VirtualBox

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

Last change on this file since 37950 was 37596, checked in by vboxsync, 13 years ago

*: RTFILE becomes a pointer, RTFileOpen++ expands it's flags paramter from uint32_t to uint64_t.

  • 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 37596 2011-06-22 19:30:06Z 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/**
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 */
154int pdmacFileAioMgrFailsafe(RTTHREAD ThreadSelf, void *pvUser)
155{
156 int rc = VINF_SUCCESS;
157 PPDMACEPFILEMGR pAioMgr = (PPDMACEPFILEMGR)pvUser;
158
159 while ( (pAioMgr->enmState == PDMACEPFILEMGRSTATE_RUNNING)
160 || (pAioMgr->enmState == PDMACEPFILEMGRSTATE_SUSPENDING))
161 {
162 ASMAtomicWriteBool(&pAioMgr->fWaitingEventSem, true);
163 if (!ASMAtomicReadBool(&pAioMgr->fWokenUp))
164 rc = RTSemEventWait(pAioMgr->EventSem, pAioMgr->msBwLimitExpired);
165 ASMAtomicWriteBool(&pAioMgr->fWaitingEventSem, false);
166 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
167
168 LogFlow(("Got woken up\n"));
169 ASMAtomicWriteBool(&pAioMgr->fWokenUp, false);
170
171 /* Process endpoint events first. */
172 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint = pAioMgr->pEndpointsHead;
173 while (pEndpoint)
174 {
175 pAioMgr->msBwLimitExpired = RT_INDEFINITE_WAIT;
176 rc = pdmacFileAioMgrFailsafeProcessEndpoint(pAioMgr, pEndpoint);
177 AssertRC(rc);
178 pEndpoint = pEndpoint->AioMgr.pEndpointNext;
179 }
180
181 /* Now check for an external blocking event. */
182 if (pAioMgr->fBlockingEventPending)
183 {
184 switch (pAioMgr->enmBlockingEvent)
185 {
186 case PDMACEPFILEAIOMGRBLOCKINGEVENT_ADD_ENDPOINT:
187 {
188 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointNew = pAioMgr->BlockingEventData.AddEndpoint.pEndpoint;
189 AssertMsg(VALID_PTR(pEndpointNew), ("Adding endpoint event without a endpoint to add\n"));
190
191 pEndpointNew->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE;
192
193 pEndpointNew->AioMgr.pEndpointNext = pAioMgr->pEndpointsHead;
194 pEndpointNew->AioMgr.pEndpointPrev = NULL;
195 if (pAioMgr->pEndpointsHead)
196 pAioMgr->pEndpointsHead->AioMgr.pEndpointPrev = pEndpointNew;
197 pAioMgr->pEndpointsHead = pEndpointNew;
198
199 pAioMgr->cEndpoints++;
200
201 /*
202 * Process the task list the first time. There might be pending requests
203 * if the endpoint was migrated from another endpoint.
204 */
205 rc = pdmacFileAioMgrFailsafeProcessEndpoint(pAioMgr, pEndpointNew);
206 AssertRC(rc);
207 break;
208 }
209 case PDMACEPFILEAIOMGRBLOCKINGEVENT_REMOVE_ENDPOINT:
210 {
211 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointRemove = pAioMgr->BlockingEventData.RemoveEndpoint.pEndpoint;
212 AssertMsg(VALID_PTR(pEndpointRemove), ("Removing endpoint event without a endpoint to remove\n"));
213
214 pEndpointRemove->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_REMOVING;
215
216 PPDMASYNCCOMPLETIONENDPOINTFILE pPrev = pEndpointRemove->AioMgr.pEndpointPrev;
217 PPDMASYNCCOMPLETIONENDPOINTFILE pNext = pEndpointRemove->AioMgr.pEndpointNext;
218
219 if (pPrev)
220 pPrev->AioMgr.pEndpointNext = pNext;
221 else
222 pAioMgr->pEndpointsHead = pNext;
223
224 if (pNext)
225 pNext->AioMgr.pEndpointPrev = pPrev;
226
227 pAioMgr->cEndpoints--;
228 break;
229 }
230 case PDMACEPFILEAIOMGRBLOCKINGEVENT_CLOSE_ENDPOINT:
231 {
232 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointClose = pAioMgr->BlockingEventData.CloseEndpoint.pEndpoint;
233 AssertMsg(VALID_PTR(pEndpointClose), ("Close endpoint event without a endpoint to Close\n"));
234
235 pEndpointClose->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_CLOSING;
236
237 /* Make sure all tasks finished. */
238 rc = pdmacFileAioMgrFailsafeProcessEndpoint(pAioMgr, pEndpointClose);
239 AssertRC(rc);
240 break;
241 }
242 case PDMACEPFILEAIOMGRBLOCKINGEVENT_SHUTDOWN:
243 pAioMgr->enmState = PDMACEPFILEMGRSTATE_SHUTDOWN;
244 break;
245 case PDMACEPFILEAIOMGRBLOCKINGEVENT_SUSPEND:
246 pAioMgr->enmState = PDMACEPFILEMGRSTATE_SUSPENDING;
247 break;
248 case PDMACEPFILEAIOMGRBLOCKINGEVENT_RESUME:
249 pAioMgr->enmState = PDMACEPFILEMGRSTATE_RUNNING;
250 break;
251 default:
252 AssertMsgFailed(("Invalid event type %d\n", pAioMgr->enmBlockingEvent));
253 }
254
255 ASMAtomicWriteBool(&pAioMgr->fBlockingEventPending, false);
256 pAioMgr->enmBlockingEvent = PDMACEPFILEAIOMGRBLOCKINGEVENT_INVALID;
257
258 /* Release the waiting thread. */
259 rc = RTSemEventSignal(pAioMgr->EventSemBlock);
260 AssertRC(rc);
261 }
262 }
263
264 return rc;
265}
266
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