VirtualBox

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

Last change on this file since 26550 was 26147, checked in by vboxsync, 15 years ago

AsyncCompletion: Fix incorrect count of outstanding write tasks. Fixes hangs during flush requests. Return VINF_AIO_TASK_PENDING if data needs to be read from the file

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