VirtualBox

source: vbox/trunk/src/VBox/VMM/PDMAsyncCompletionFileFailsafe.cpp@ 30690

Last change on this file since 30690 was 30147, checked in by vboxsync, 14 years ago

AsyncCompletion: Fix race in the failsafe manager when checking the woken up flag before going to sleep. The order matters here

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.4 KB
Line 
1/* $Id: PDMAsyncCompletionFileFailsafe.cpp 30147 2010-06-10 12:11:24Z vboxsync $ */
2/** @file
3 * PDM Async I/O - Transport data asynchronous in R3 using EMT.
4 * Simple File I/O manager.
5 */
6
7/*
8 * Copyright (C) 2006-2008 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_PDM_ASYNC_COMPLETION
23#include <iprt/asm.h>
24#include <iprt/assert.h>
25#include <VBox/log.h>
26
27#include "PDMAsyncCompletionFileInternal.h"
28
29
30static int pdmacFileAioMgrFailsafeProcessEndpointTaskList(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint,
31 PPDMACTASKFILE pTasks)
32{
33 int rc = VINF_SUCCESS;
34
35 while (pTasks)
36 {
37 PPDMACTASKFILE pCurr = pTasks;
38
39 pTasks = pTasks->pNext;
40
41 switch (pCurr->enmTransferType)
42 {
43 case PDMACTASKFILETRANSFER_FLUSH:
44 {
45 rc = RTFileFlush(pEndpoint->File);
46 break;
47 }
48 case PDMACTASKFILETRANSFER_READ:
49 case PDMACTASKFILETRANSFER_WRITE:
50 {
51 if (pCurr->enmTransferType == PDMACTASKFILETRANSFER_READ)
52 {
53 rc = RTFileReadAt(pEndpoint->File, pCurr->Off,
54 pCurr->DataSeg.pvSeg,
55 pCurr->DataSeg.cbSeg,
56 NULL);
57 }
58 else
59 {
60 if (RT_UNLIKELY((uint64_t)pCurr->Off + pCurr->DataSeg.cbSeg > pEndpoint->cbFile))
61 {
62 ASMAtomicWriteU64(&pEndpoint->cbFile, pCurr->Off + pCurr->DataSeg.cbSeg);
63 RTFileSetSize(pEndpoint->File, pCurr->Off + pCurr->DataSeg.cbSeg);
64 }
65
66 rc = RTFileWriteAt(pEndpoint->File, pCurr->Off,
67 pCurr->DataSeg.pvSeg,
68 pCurr->DataSeg.cbSeg,
69 NULL);
70 }
71
72 break;
73 }
74 default:
75 AssertMsgFailed(("Invalid transfer type %d\n", pTasks->enmTransferType));
76 }
77
78 pCurr->pfnCompleted(pCurr, pCurr->pvUser, rc);
79 pdmacFileTaskFree(pEndpoint, pCurr);
80 }
81
82 return VINF_SUCCESS;
83}
84
85static int pdmacFileAioMgrFailsafeProcessEndpoint(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
86{
87 int rc = VINF_SUCCESS;
88 PPDMACTASKFILE pTasks = pEndpoint->AioMgr.pReqsPendingHead;
89
90 pEndpoint->AioMgr.pReqsPendingHead = NULL;
91 pEndpoint->AioMgr.pReqsPendingTail = NULL;
92
93 /* Process the request pending list first in case the endpoint was migrated due to an error. */
94 if (pTasks)
95 rc = pdmacFileAioMgrFailsafeProcessEndpointTaskList(pEndpoint, pTasks);
96
97 if (RT_SUCCESS(rc))
98 {
99 pTasks = pdmacFileEpGetNewTasks(pEndpoint);
100
101 if (pTasks)
102 rc = pdmacFileAioMgrFailsafeProcessEndpointTaskList(pEndpoint, pTasks);
103 }
104
105 return rc;
106}
107
108/**
109 * A fallback method in case something goes wrong with the normal
110 * I/O manager.
111 */
112int pdmacFileAioMgrFailsafe(RTTHREAD ThreadSelf, void *pvUser)
113{
114 int rc = VINF_SUCCESS;
115 PPDMACEPFILEMGR pAioMgr = (PPDMACEPFILEMGR)pvUser;
116
117 while ( (pAioMgr->enmState == PDMACEPFILEMGRSTATE_RUNNING)
118 || (pAioMgr->enmState == PDMACEPFILEMGRSTATE_SUSPENDING))
119 {
120 ASMAtomicWriteBool(&pAioMgr->fWaitingEventSem, true);
121 if (!ASMAtomicReadBool(&pAioMgr->fWokenUp))
122 rc = RTSemEventWait(pAioMgr->EventSem, RT_INDEFINITE_WAIT);
123 ASMAtomicWriteBool(&pAioMgr->fWaitingEventSem, false);
124 AssertRC(rc);
125
126 LogFlow(("Got woken up\n"));
127 ASMAtomicWriteBool(&pAioMgr->fWokenUp, false);
128
129 /* Process endpoint events first. */
130 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint = pAioMgr->pEndpointsHead;
131 while (pEndpoint)
132 {
133 rc = pdmacFileAioMgrFailsafeProcessEndpoint(pEndpoint);
134 AssertRC(rc);
135 pEndpoint = pEndpoint->AioMgr.pEndpointNext;
136 }
137
138 /* Now check for an external blocking event. */
139 if (pAioMgr->fBlockingEventPending)
140 {
141 switch (pAioMgr->enmBlockingEvent)
142 {
143 case PDMACEPFILEAIOMGRBLOCKINGEVENT_ADD_ENDPOINT:
144 {
145 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointNew = pAioMgr->BlockingEventData.AddEndpoint.pEndpoint;
146 AssertMsg(VALID_PTR(pEndpointNew), ("Adding endpoint event without a endpoint to add\n"));
147
148 pEndpointNew->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE;
149
150 pEndpointNew->AioMgr.pEndpointNext = pAioMgr->pEndpointsHead;
151 pEndpointNew->AioMgr.pEndpointPrev = NULL;
152 if (pAioMgr->pEndpointsHead)
153 pAioMgr->pEndpointsHead->AioMgr.pEndpointPrev = pEndpointNew;
154 pAioMgr->pEndpointsHead = pEndpointNew;
155
156 pAioMgr->cEndpoints++;
157
158 /*
159 * Process the task list the first time. There might be pending requests
160 * if the endpoint was migrated from another endpoint.
161 */
162 rc = pdmacFileAioMgrFailsafeProcessEndpoint(pEndpointNew);
163 AssertRC(rc);
164 break;
165 }
166 case PDMACEPFILEAIOMGRBLOCKINGEVENT_REMOVE_ENDPOINT:
167 {
168 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointRemove = pAioMgr->BlockingEventData.RemoveEndpoint.pEndpoint;
169 AssertMsg(VALID_PTR(pEndpointRemove), ("Removing endpoint event without a endpoint to remove\n"));
170
171 pEndpointRemove->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_REMOVING;
172
173 PPDMASYNCCOMPLETIONENDPOINTFILE pPrev = pEndpointRemove->AioMgr.pEndpointPrev;
174 PPDMASYNCCOMPLETIONENDPOINTFILE pNext = pEndpointRemove->AioMgr.pEndpointNext;
175
176 if (pPrev)
177 pPrev->AioMgr.pEndpointNext = pNext;
178 else
179 pAioMgr->pEndpointsHead = pNext;
180
181 if (pNext)
182 pNext->AioMgr.pEndpointPrev = pPrev;
183
184 pAioMgr->cEndpoints--;
185 break;
186 }
187 case PDMACEPFILEAIOMGRBLOCKINGEVENT_CLOSE_ENDPOINT:
188 {
189 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointClose = pAioMgr->BlockingEventData.CloseEndpoint.pEndpoint;
190 AssertMsg(VALID_PTR(pEndpointClose), ("Close endpoint event without a endpoint to Close\n"));
191
192 pEndpointClose->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_CLOSING;
193
194 /* Make sure all tasks finished. */
195 rc = pdmacFileAioMgrFailsafeProcessEndpoint(pEndpointClose);
196 AssertRC(rc);
197 break;
198 }
199 case PDMACEPFILEAIOMGRBLOCKINGEVENT_SHUTDOWN:
200 pAioMgr->enmState = PDMACEPFILEMGRSTATE_SHUTDOWN;
201 break;
202 case PDMACEPFILEAIOMGRBLOCKINGEVENT_SUSPEND:
203 pAioMgr->enmState = PDMACEPFILEMGRSTATE_SUSPENDING;
204 break;
205 case PDMACEPFILEAIOMGRBLOCKINGEVENT_RESUME:
206 pAioMgr->enmState = PDMACEPFILEMGRSTATE_RUNNING;
207 break;
208 default:
209 AssertMsgFailed(("Invalid event type %d\n", pAioMgr->enmBlockingEvent));
210 }
211
212 ASMAtomicWriteBool(&pAioMgr->fBlockingEventPending, false);
213 pAioMgr->enmBlockingEvent = PDMACEPFILEAIOMGRBLOCKINGEVENT_INVALID;
214
215 /* Release the waiting thread. */
216 rc = RTSemEventSignal(pAioMgr->EventSemBlock);
217 AssertRC(rc);
218 }
219 }
220
221 return rc;
222}
223
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette