VirtualBox

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

Last change on this file since 48565 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.9 KB
Line 
1/* $Id: PDMAsyncCompletionFileFailsafe.cpp 44528 2013-02-04 14:27:54Z 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-2011 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/**
30 * Put a list of tasks in the pending request list of an endpoint.
31 */
32DECLINLINE(void) pdmacFileAioMgrEpAddTaskList(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint, PPDMACTASKFILE pTaskHead)
33{
34 /* Add the rest of the tasks to the pending list */
35 if (!pEndpoint->AioMgr.pReqsPendingHead)
36 {
37 Assert(!pEndpoint->AioMgr.pReqsPendingTail);
38 pEndpoint->AioMgr.pReqsPendingHead = pTaskHead;
39 }
40 else
41 {
42 Assert(pEndpoint->AioMgr.pReqsPendingTail);
43 pEndpoint->AioMgr.pReqsPendingTail->pNext = pTaskHead;
44 }
45
46 /* Update the tail. */
47 while (pTaskHead->pNext)
48 pTaskHead = pTaskHead->pNext;
49
50 pEndpoint->AioMgr.pReqsPendingTail = pTaskHead;
51 pTaskHead->pNext = NULL;
52}
53
54/**
55 * Processes a given task list for assigned to the given endpoint.
56 */
57static int pdmacFileAioMgrFailsafeProcessEndpointTaskList(PPDMACEPFILEMGR pAioMgr,
58 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint,
59 PPDMACTASKFILE pTasks)
60{
61 int rc = VINF_SUCCESS;
62
63 while (pTasks)
64 {
65 RTMSINTERVAL msWhenNext;
66 PPDMACTASKFILE pCurr = pTasks;
67
68 if (!pdmacEpIsTransferAllowed(&pEndpoint->Core, (uint32_t)pCurr->DataSeg.cbSeg, &msWhenNext))
69 {
70 pAioMgr->msBwLimitExpired = RT_MIN(pAioMgr->msBwLimitExpired, msWhenNext);
71 break;
72 }
73
74 pTasks = pTasks->pNext;
75
76 switch (pCurr->enmTransferType)
77 {
78 case PDMACTASKFILETRANSFER_FLUSH:
79 {
80 rc = RTFileFlush(pEndpoint->hFile);
81 break;
82 }
83 case PDMACTASKFILETRANSFER_READ:
84 case PDMACTASKFILETRANSFER_WRITE:
85 {
86 if (pCurr->enmTransferType == PDMACTASKFILETRANSFER_READ)
87 {
88 rc = RTFileReadAt(pEndpoint->hFile, pCurr->Off,
89 pCurr->DataSeg.pvSeg,
90 pCurr->DataSeg.cbSeg,
91 NULL);
92 }
93 else
94 {
95 if (RT_UNLIKELY((uint64_t)pCurr->Off + pCurr->DataSeg.cbSeg > pEndpoint->cbFile))
96 {
97 ASMAtomicWriteU64(&pEndpoint->cbFile, pCurr->Off + pCurr->DataSeg.cbSeg);
98 RTFileSetSize(pEndpoint->hFile, pCurr->Off + pCurr->DataSeg.cbSeg);
99 }
100
101 rc = RTFileWriteAt(pEndpoint->hFile, pCurr->Off,
102 pCurr->DataSeg.pvSeg,
103 pCurr->DataSeg.cbSeg,
104 NULL);
105 }
106
107 break;
108 }
109 default:
110 AssertMsgFailed(("Invalid transfer type %d\n", pTasks->enmTransferType));
111 }
112
113 pCurr->pfnCompleted(pCurr, pCurr->pvUser, rc);
114 pdmacFileTaskFree(pEndpoint, pCurr);
115 }
116
117 if (pTasks)
118 {
119 /* Add the rest of the tasks to the pending list */
120 pdmacFileAioMgrEpAddTaskList(pEndpoint, pTasks);
121 }
122
123 return VINF_SUCCESS;
124}
125
126static int pdmacFileAioMgrFailsafeProcessEndpoint(PPDMACEPFILEMGR pAioMgr,
127 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
128{
129 int rc = VINF_SUCCESS;
130 PPDMACTASKFILE pTasks = pEndpoint->AioMgr.pReqsPendingHead;
131
132 pEndpoint->AioMgr.pReqsPendingHead = NULL;
133 pEndpoint->AioMgr.pReqsPendingTail = NULL;
134
135 /* Process the request pending list first in case the endpoint was migrated due to an error. */
136 if (pTasks)
137 rc = pdmacFileAioMgrFailsafeProcessEndpointTaskList(pAioMgr, pEndpoint, pTasks);
138
139 if (RT_SUCCESS(rc))
140 {
141 pTasks = pdmacFileEpGetNewTasks(pEndpoint);
142
143 if (pTasks)
144 rc = pdmacFileAioMgrFailsafeProcessEndpointTaskList(pAioMgr, pEndpoint, pTasks);
145 }
146
147 return rc;
148}
149
150/**
151 * A fallback method in case something goes wrong with the normal
152 * I/O manager.
153 */
154DECLCALLBACK(int) pdmacFileAioMgrFailsafe(RTTHREAD hThreadSelf, void *pvUser)
155{
156 int rc = VINF_SUCCESS;
157 PPDMACEPFILEMGR pAioMgr = (PPDMACEPFILEMGR)pvUser;
158 NOREF(hThreadSelf);
159
160 while ( (pAioMgr->enmState == PDMACEPFILEMGRSTATE_RUNNING)
161 || (pAioMgr->enmState == PDMACEPFILEMGRSTATE_SUSPENDING))
162 {
163 ASMAtomicWriteBool(&pAioMgr->fWaitingEventSem, true);
164 if (!ASMAtomicReadBool(&pAioMgr->fWokenUp))
165 rc = RTSemEventWait(pAioMgr->EventSem, pAioMgr->msBwLimitExpired);
166 ASMAtomicWriteBool(&pAioMgr->fWaitingEventSem, false);
167 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
168
169 LogFlow(("Got woken up\n"));
170 ASMAtomicWriteBool(&pAioMgr->fWokenUp, false);
171
172 /* Process endpoint events first. */
173 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint = pAioMgr->pEndpointsHead;
174 while (pEndpoint)
175 {
176 pAioMgr->msBwLimitExpired = RT_INDEFINITE_WAIT;
177 rc = pdmacFileAioMgrFailsafeProcessEndpoint(pAioMgr, pEndpoint);
178 AssertRC(rc);
179 pEndpoint = pEndpoint->AioMgr.pEndpointNext;
180 }
181
182 /* Now check for an external blocking event. */
183 if (pAioMgr->fBlockingEventPending)
184 {
185 switch (pAioMgr->enmBlockingEvent)
186 {
187 case PDMACEPFILEAIOMGRBLOCKINGEVENT_ADD_ENDPOINT:
188 {
189 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointNew = pAioMgr->BlockingEventData.AddEndpoint.pEndpoint;
190 AssertMsg(VALID_PTR(pEndpointNew), ("Adding endpoint event without a endpoint to add\n"));
191
192 pEndpointNew->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE;
193
194 pEndpointNew->AioMgr.pEndpointNext = pAioMgr->pEndpointsHead;
195 pEndpointNew->AioMgr.pEndpointPrev = NULL;
196 if (pAioMgr->pEndpointsHead)
197 pAioMgr->pEndpointsHead->AioMgr.pEndpointPrev = pEndpointNew;
198 pAioMgr->pEndpointsHead = pEndpointNew;
199
200 pAioMgr->cEndpoints++;
201
202 /*
203 * Process the task list the first time. There might be pending requests
204 * if the endpoint was migrated from another endpoint.
205 */
206 rc = pdmacFileAioMgrFailsafeProcessEndpoint(pAioMgr, pEndpointNew);
207 AssertRC(rc);
208 break;
209 }
210 case PDMACEPFILEAIOMGRBLOCKINGEVENT_REMOVE_ENDPOINT:
211 {
212 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointRemove = pAioMgr->BlockingEventData.RemoveEndpoint.pEndpoint;
213 AssertMsg(VALID_PTR(pEndpointRemove), ("Removing endpoint event without a endpoint to remove\n"));
214
215 pEndpointRemove->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_REMOVING;
216
217 PPDMASYNCCOMPLETIONENDPOINTFILE pPrev = pEndpointRemove->AioMgr.pEndpointPrev;
218 PPDMASYNCCOMPLETIONENDPOINTFILE pNext = pEndpointRemove->AioMgr.pEndpointNext;
219
220 if (pPrev)
221 pPrev->AioMgr.pEndpointNext = pNext;
222 else
223 pAioMgr->pEndpointsHead = pNext;
224
225 if (pNext)
226 pNext->AioMgr.pEndpointPrev = pPrev;
227
228 pAioMgr->cEndpoints--;
229 break;
230 }
231 case PDMACEPFILEAIOMGRBLOCKINGEVENT_CLOSE_ENDPOINT:
232 {
233 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointClose = pAioMgr->BlockingEventData.CloseEndpoint.pEndpoint;
234 AssertMsg(VALID_PTR(pEndpointClose), ("Close endpoint event without a endpoint to Close\n"));
235
236 pEndpointClose->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_CLOSING;
237
238 /* Make sure all tasks finished. */
239 rc = pdmacFileAioMgrFailsafeProcessEndpoint(pAioMgr, pEndpointClose);
240 AssertRC(rc);
241 break;
242 }
243 case PDMACEPFILEAIOMGRBLOCKINGEVENT_SHUTDOWN:
244 pAioMgr->enmState = PDMACEPFILEMGRSTATE_SHUTDOWN;
245 break;
246 case PDMACEPFILEAIOMGRBLOCKINGEVENT_SUSPEND:
247 pAioMgr->enmState = PDMACEPFILEMGRSTATE_SUSPENDING;
248 break;
249 case PDMACEPFILEAIOMGRBLOCKINGEVENT_RESUME:
250 pAioMgr->enmState = PDMACEPFILEMGRSTATE_RUNNING;
251 break;
252 default:
253 AssertMsgFailed(("Invalid event type %d\n", pAioMgr->enmBlockingEvent));
254 }
255
256 ASMAtomicWriteBool(&pAioMgr->fBlockingEventPending, false);
257 pAioMgr->enmBlockingEvent = PDMACEPFILEAIOMGRBLOCKINGEVENT_INVALID;
258
259 /* Release the waiting thread. */
260 rc = RTSemEventSignal(pAioMgr->EventSemBlock);
261 AssertRC(rc);
262 }
263 }
264
265 return rc;
266}
267
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