VirtualBox

source: vbox/trunk/src/VBox/VMM/PDMAsyncCompletionFileNormal.cpp@ 22346

Last change on this file since 22346 was 22309, checked in by vboxsync, 15 years ago

PDMAsyncCompletion: Add first part of the cache for file I/O

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.4 KB
Line 
1/* $Id: PDMAsyncCompletionFileNormal.cpp 22309 2009-08-17 20:59:28Z vboxsync $ */
2/** @file
3 * PDM Async I/O - Transport data asynchronous in R3 using EMT.
4 * Async 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/file.h>
25#include <iprt/mem.h>
26#include <iprt/string.h>
27#include <VBox/log.h>
28
29#include "PDMAsyncCompletionFileInternal.h"
30
31/** The update period for the I/O load statistics in ms. */
32#define PDMACEPFILEMGR_LOAD_UPDATE_PERIOD 1000
33/** Maximum number of requests a manager will handle. */
34#define PDMACEPFILEMGR_REQS_MAX 512 /* @todo: Find better solution wrt. the request number*/
35
36int pdmacFileAioMgrNormalInit(PPDMACEPFILEMGR pAioMgr)
37{
38 int rc = VINF_SUCCESS;
39
40 rc = RTFileAioCtxCreate(&pAioMgr->hAioCtx, RTFILEAIO_UNLIMITED_REQS);
41 if (rc == VERR_OUT_OF_RANGE)
42 rc = RTFileAioCtxCreate(&pAioMgr->hAioCtx, PDMACEPFILEMGR_REQS_MAX);
43
44 if (RT_SUCCESS(rc))
45 {
46 /* Initialize request handle array. */
47 pAioMgr->iFreeEntryNext = 0;
48 pAioMgr->iFreeReqNext = 0;
49 pAioMgr->cReqEntries = PDMACEPFILEMGR_REQS_MAX + 1;
50 pAioMgr->pahReqsFree = (RTFILEAIOREQ *)RTMemAllocZ(pAioMgr->cReqEntries * sizeof(RTFILEAIOREQ));
51
52 if (pAioMgr->pahReqsFree)
53 {
54 return VINF_SUCCESS;
55 }
56 else
57 {
58 RTFileAioCtxDestroy(pAioMgr->hAioCtx);
59 rc = VERR_NO_MEMORY;
60 }
61 }
62
63 return rc;
64}
65
66void pdmacFileAioMgrNormalDestroy(PPDMACEPFILEMGR pAioMgr)
67{
68 RTFileAioCtxDestroy(pAioMgr->hAioCtx);
69
70 while (pAioMgr->iFreeReqNext != pAioMgr->iFreeEntryNext)
71 {
72 RTFileAioReqDestroy(pAioMgr->pahReqsFree[pAioMgr->iFreeReqNext]);
73 pAioMgr->iFreeReqNext = (pAioMgr->iFreeReqNext + 1) % pAioMgr->cReqEntries;
74 }
75
76 RTMemFree(pAioMgr->pahReqsFree);
77}
78
79/**
80 * Error handler which will create the failsafe managers and destroy the failed I/O manager.
81 *
82 * @returns VBox status code
83 * @param pAioMgr The I/O manager the error ocurred on.
84 * @param rc The error code.
85 */
86static int pdmacFileAioMgrNormalErrorHandler(PPDMACEPFILEMGR pAioMgr, int rc, RT_SRC_POS_DECL)
87{
88 LogRel(("AIOMgr: I/O manager %#p encountered a critical error (rc=%Rrc) during operation. Falling back to failsafe mode. Expect reduced performance\n",
89 pAioMgr, rc));
90 LogRel(("AIOMgr: Error happened in %s:(%u){%s}\n", RT_SRC_POS_ARGS));
91 LogRel(("AIOMgr: Please contact the product vendor\n"));
92
93 PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pAioMgr->pEndpointsHead->Core.pEpClass;
94
95 pAioMgr->enmState = PDMACEPFILEMGRSTATE_FAULT;
96 ASMAtomicWriteBool(&pEpClassFile->fFailsafe, true);
97
98 AssertMsgFailed(("Implement\n"));
99 return VINF_SUCCESS;
100}
101
102static int pdmacFileAioMgrNormalProcessTaskList(PPDMACTASKFILE pTaskHead,
103 PPDMACEPFILEMGR pAioMgr,
104 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
105{
106 RTFILEAIOREQ apReqs[20];
107 unsigned cRequests = 0;
108 int rc = VINF_SUCCESS;
109 PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->Core.pEpClass;
110
111 AssertMsg(pEndpoint->enmState == PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE,
112 ("Trying to process request lists of a non active endpoint!\n"));
113
114 /* Go through the list and queue the requests until we get a flush request */
115 while (pTaskHead && !pEndpoint->pFlushReq)
116 {
117 PPDMACTASKFILE pCurr = pTaskHead;
118
119 pTaskHead = pTaskHead->pNext;
120
121 AssertMsg(VALID_PTR(pCurr->pEndpoint) && (pCurr->pEndpoint == pEndpoint),
122 ("Endpoints do not match\n"));
123
124 switch (pCurr->enmTransferType)
125 {
126 case PDMACTASKFILETRANSFER_FLUSH:
127 {
128 /* If there is no data transfer request this flush request finished immediately. */
129 if (!pEndpoint->AioMgr.cRequestsActive)
130 {
131 pCurr->pfnCompleted(pCurr, pCurr->pvUser);
132 pdmacFileTaskFree(pEndpoint, pCurr);
133 }
134 else
135 {
136 pEndpoint->pFlushReq = pCurr;
137
138 if (pTaskHead)
139 {
140 /* Add the rest of the tasks to the pending list */
141 if (!pEndpoint->AioMgr.pReqsPendingHead)
142 {
143 Assert(!pEndpoint->AioMgr.pReqsPendingTail);
144 pEndpoint->AioMgr.pReqsPendingHead = pTaskHead;
145 }
146 else
147 {
148 Assert(pEndpoint->AioMgr.pReqsPendingTail);
149 pEndpoint->AioMgr.pReqsPendingTail->pNext = pTaskHead;
150 }
151
152 /* Update the tail. */
153 while (pTaskHead->pNext)
154 pTaskHead = pTaskHead->pNext;
155
156 pEndpoint->AioMgr.pReqsPendingTail = pTaskHead;
157 }
158 }
159 break;
160 }
161 case PDMACTASKFILETRANSFER_READ:
162 case PDMACTASKFILETRANSFER_WRITE:
163 {
164 RTFILEAIOREQ hReq = NIL_RTFILEAIOREQ;
165 void *pvBuf = pCurr->DataSeg.pvSeg;
166
167 /* Get a request handle. */
168 if (pAioMgr->iFreeReqNext != pAioMgr->iFreeEntryNext)
169 {
170 hReq = pAioMgr->pahReqsFree[pAioMgr->iFreeReqNext];
171 pAioMgr->pahReqsFree[pAioMgr->iFreeReqNext] = NIL_RTFILEAIOREQ;
172 pAioMgr->iFreeReqNext = (pAioMgr->iFreeReqNext + 1) % pAioMgr->cReqEntries;
173 }
174 else
175 {
176 rc = RTFileAioReqCreate(&hReq);
177 AssertRC(rc);
178 }
179
180 AssertMsg(hReq != NIL_RTFILEAIOREQ, ("Out of request handles\n"));
181
182 /* Check if the alignment requirements are met. */
183 if ((pEpClassFile->uBitmaskAlignment & (RTR3UINTPTR)pvBuf) != (RTR3UINTPTR)pvBuf)
184 {
185 /* Create bounce buffer. */
186 pCurr->fBounceBuffer = true;
187
188 /** @todo: I think we need something like a RTMemAllocAligned method here.
189 * Current assumption is that the maximum alignment is 4096byte
190 * (GPT disk on Windows)
191 * so we can use RTMemPageAlloc here.
192 */
193 pCurr->pvBounceBuffer = RTMemPageAlloc(pCurr->DataSeg.cbSeg);
194 AssertPtr(pCurr->pvBounceBuffer);
195 pvBuf = pCurr->pvBounceBuffer;
196
197 if (pCurr->enmTransferType == PDMACTASKFILETRANSFER_WRITE)
198 memcpy(pvBuf, pCurr->DataSeg.pvSeg, pCurr->DataSeg.cbSeg);
199 }
200 else
201 pCurr->fBounceBuffer = false;
202
203 AssertMsg((pEpClassFile->uBitmaskAlignment & (RTR3UINTPTR)pvBuf) == (RTR3UINTPTR)pvBuf,
204 ("AIO: Alignment restrictions not met!\n"));
205
206 if (pCurr->enmTransferType == PDMACTASKFILETRANSFER_WRITE)
207 rc = RTFileAioReqPrepareWrite(hReq, pEndpoint->File,
208 pCurr->Off, pvBuf, pCurr->DataSeg.cbSeg, pCurr);
209 else
210 rc = RTFileAioReqPrepareRead(hReq, pEndpoint->File,
211 pCurr->Off, pvBuf, pCurr->DataSeg.cbSeg, pCurr);
212 AssertRC(rc);
213
214 apReqs[cRequests] = hReq;
215 pEndpoint->AioMgr.cReqsProcessed++;
216 cRequests++;
217 if (cRequests == RT_ELEMENTS(apReqs))
218 {
219 pAioMgr->cRequestsActive += cRequests;
220 rc = RTFileAioCtxSubmit(pAioMgr->hAioCtx, apReqs, cRequests);
221 if (RT_FAILURE(rc))
222 {
223 /* @todo implement */
224 AssertMsgFailed(("Implement\n"));
225 }
226
227 cRequests = 0;
228 }
229 break;
230 }
231 default:
232 AssertMsgFailed(("Invalid transfer type %d\n", pCurr->enmTransferType));
233 }
234 }
235
236 if (cRequests)
237 {
238 pAioMgr->cRequestsActive += cRequests;
239 rc = RTFileAioCtxSubmit(pAioMgr->hAioCtx, apReqs, cRequests);
240 if (RT_FAILURE(rc))
241 {
242 /* Not enough ressources on this context anymore. */
243 /* @todo implement */
244 AssertMsgFailed(("Implement\n"));
245 }
246 }
247
248 return rc;
249}
250
251/**
252 * Adds all pending requests for the given endpoint
253 * until a flush request is encountered or there is no
254 * request anymore.
255 *
256 * @returns VBox status code.
257 * @param pAioMgr The async I/O manager for the endpoint
258 * @param pEndpoint The endpoint to get the requests from.
259 */
260static int pdmacFileAioMgrNormalQueueReqs(PPDMACEPFILEMGR pAioMgr,
261 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
262{
263 int rc = VINF_SUCCESS;
264 PPDMACTASKFILE pTasksHead = NULL;
265
266 AssertMsg(pEndpoint->enmState == PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE,
267 ("Trying to process request lists of a non active endpoint!\n"));
268
269 Assert(!pEndpoint->pFlushReq);
270
271 /* Check the pending list first */
272 if (pEndpoint->AioMgr.pReqsPendingHead)
273 {
274 pTasksHead = pEndpoint->AioMgr.pReqsPendingHead;
275 /*
276 * Clear the list as the processing routine will insert them into the list
277 * again if it gets a flush request.
278 */
279 pEndpoint->AioMgr.pReqsPendingHead = NULL;
280 pEndpoint->AioMgr.pReqsPendingTail = NULL;
281 rc = pdmacFileAioMgrNormalProcessTaskList(pTasksHead, pAioMgr, pEndpoint);
282 AssertRC(rc);
283 }
284
285 if (!pEndpoint->pFlushReq)
286 {
287 /* Now the request queue. */
288 pTasksHead = pdmacFileEpGetNewTasks(pEndpoint);
289 if (pTasksHead)
290 {
291 rc = pdmacFileAioMgrNormalProcessTaskList(pTasksHead, pAioMgr, pEndpoint);
292 AssertRC(rc);
293 }
294 }
295
296 return rc;
297}
298
299static int pdmacFileAioMgrNormalProcessBlockingEvent(PPDMACEPFILEMGR pAioMgr)
300{
301 int rc = VINF_SUCCESS;
302 bool fNotifyWaiter = false;
303
304 Assert(pAioMgr->fBlockingEventPending);
305
306 switch (pAioMgr->enmBlockingEvent)
307 {
308 case PDMACEPFILEAIOMGRBLOCKINGEVENT_ADD_ENDPOINT:
309 {
310 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointNew = (PPDMASYNCCOMPLETIONENDPOINTFILE)ASMAtomicReadPtr((void * volatile *)&pAioMgr->BlockingEventData.AddEndpoint.pEndpoint);
311 AssertMsg(VALID_PTR(pEndpointNew), ("Adding endpoint event without a endpoint to add\n"));
312
313 pEndpointNew->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE;
314
315 pEndpointNew->AioMgr.pEndpointNext = pAioMgr->pEndpointsHead;
316 pEndpointNew->AioMgr.pEndpointPrev = NULL;
317 if (pAioMgr->pEndpointsHead)
318 pAioMgr->pEndpointsHead->AioMgr.pEndpointPrev = pEndpointNew;
319 pAioMgr->pEndpointsHead = pEndpointNew;
320
321 /* Assign the completion point to this file. */
322 rc = RTFileAioCtxAssociateWithFile(pAioMgr->hAioCtx, pEndpointNew->File);
323 fNotifyWaiter = true;
324 break;
325 }
326 case PDMACEPFILEAIOMGRBLOCKINGEVENT_REMOVE_ENDPOINT:
327 {
328 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointRemove = (PPDMASYNCCOMPLETIONENDPOINTFILE)ASMAtomicReadPtr((void * volatile *)&pAioMgr->BlockingEventData.RemoveEndpoint.pEndpoint);
329 AssertMsg(VALID_PTR(pEndpointRemove), ("Removing endpoint event without a endpoint to remove\n"));
330
331 PPDMASYNCCOMPLETIONENDPOINTFILE pPrev = pEndpointRemove->AioMgr.pEndpointPrev;
332 PPDMASYNCCOMPLETIONENDPOINTFILE pNext = pEndpointRemove->AioMgr.pEndpointNext;
333
334 pEndpointRemove->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_REMOVING;
335
336 if (pPrev)
337 pPrev->AioMgr.pEndpointNext = pNext;
338 else
339 pAioMgr->pEndpointsHead = pNext;
340
341 if (pNext)
342 pNext->AioMgr.pEndpointPrev = pPrev;
343
344 /* Make sure that there is no request pending on this manager for the endpoint. */
345 if (!pEndpointRemove->AioMgr.cRequestsActive)
346 {
347 Assert(!pEndpointRemove->pFlushReq);
348
349 /* Reopen the file so that the new endpoint can reassociate with the file */
350 RTFileClose(pEndpointRemove->File);
351 rc = RTFileOpen(&pEndpointRemove->File, pEndpointRemove->Core.pszUri, pEndpointRemove->fFlags);
352 AssertRC(rc);
353 }
354 break;
355 }
356 case PDMACEPFILEAIOMGRBLOCKINGEVENT_CLOSE_ENDPOINT:
357 {
358 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointClose = (PPDMASYNCCOMPLETIONENDPOINTFILE)ASMAtomicReadPtr((void * volatile *)&pAioMgr->BlockingEventData.CloseEndpoint.pEndpoint);
359 AssertMsg(VALID_PTR(pEndpointClose), ("Close endpoint event without a endpoint to close\n"));
360
361 /* Make sure all tasks finished. Process the queues a last time first. */
362 rc = pdmacFileAioMgrNormalQueueReqs(pAioMgr, pEndpointClose);
363 AssertRC(rc);
364
365 pEndpointClose->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_CLOSING;
366
367 PPDMASYNCCOMPLETIONENDPOINTFILE pPrev = pEndpointClose->AioMgr.pEndpointPrev;
368 PPDMASYNCCOMPLETIONENDPOINTFILE pNext = pEndpointClose->AioMgr.pEndpointNext;
369
370 if (pPrev)
371 pPrev->AioMgr.pEndpointNext = pNext;
372 else
373 pAioMgr->pEndpointsHead = pNext;
374
375 if (pNext)
376 pNext->AioMgr.pEndpointPrev = pPrev;
377
378 if (!pEndpointClose->AioMgr.cRequestsActive)
379 {
380 Assert(!pEndpointClose->pFlushReq);
381
382 /* Reopen the file to deassociate it from the endpoint. */
383 RTFileClose(pEndpointClose->File);
384 rc = RTFileOpen(&pEndpointClose->File, pEndpointClose->Core.pszUri, pEndpointClose->fFlags);
385 AssertRC(rc);
386 fNotifyWaiter = true;
387 }
388 break;
389 }
390 case PDMACEPFILEAIOMGRBLOCKINGEVENT_SHUTDOWN:
391 {
392 pAioMgr->enmState = PDMACEPFILEMGRSTATE_SHUTDOWN;
393 if (!pAioMgr->cRequestsActive)
394 fNotifyWaiter = true;
395 break;
396 }
397 case PDMACEPFILEAIOMGRBLOCKINGEVENT_SUSPEND:
398 {
399 pAioMgr->enmState = PDMACEPFILEMGRSTATE_SUSPENDING;
400 break;
401 }
402 case PDMACEPFILEAIOMGRBLOCKINGEVENT_RESUME:
403 {
404 pAioMgr->enmState = PDMACEPFILEMGRSTATE_RUNNING;
405 fNotifyWaiter = true;
406 break;
407 }
408 default:
409 AssertReleaseMsgFailed(("Invalid event type %d\n", pAioMgr->enmBlockingEvent));
410 }
411
412 if (fNotifyWaiter)
413 {
414 ASMAtomicWriteBool(&pAioMgr->fBlockingEventPending, false);
415 pAioMgr->enmBlockingEvent = PDMACEPFILEAIOMGRBLOCKINGEVENT_INVALID;
416
417 /* Release the waiting thread. */
418 rc = RTSemEventSignal(pAioMgr->EventSemBlock);
419 AssertRC(rc);
420 }
421
422 return rc;
423}
424
425/** Helper macro for checking for error codes. */
426#define CHECK_RC(pAioMgr, rc) \
427 if (RT_FAILURE(rc)) \
428 {\
429 int rc2 = pdmacFileAioMgrNormalErrorHandler(pAioMgr, rc, RT_SRC_POS);\
430 return rc2;\
431 }
432
433/**
434 * The normal I/O manager using the RTFileAio* API
435 *
436 * @returns VBox status code.
437 * @param ThreadSelf Handle of the thread.
438 * @param pvUser Opaque user data.
439 */
440int pdmacFileAioMgrNormal(RTTHREAD ThreadSelf, void *pvUser)
441{
442 int rc = VINF_SUCCESS;
443 PPDMACEPFILEMGR pAioMgr = (PPDMACEPFILEMGR)pvUser;
444 uint64_t uMillisEnd = RTTimeMilliTS() + PDMACEPFILEMGR_LOAD_UPDATE_PERIOD;
445
446 while ( (pAioMgr->enmState == PDMACEPFILEMGRSTATE_RUNNING)
447 || (pAioMgr->enmState == PDMACEPFILEMGRSTATE_SUSPENDING))
448 {
449 ASMAtomicWriteBool(&pAioMgr->fWaitingEventSem, true);
450 if (!ASMAtomicReadBool(&pAioMgr->fWokenUp))
451 rc = RTSemEventWait(pAioMgr->EventSem, RT_INDEFINITE_WAIT);
452 ASMAtomicWriteBool(&pAioMgr->fWaitingEventSem, false);
453 AssertRC(rc);
454
455 LogFlow(("Got woken up\n"));
456 ASMAtomicWriteBool(&pAioMgr->fWokenUp, false);
457
458 /* Check for an external blocking event first. */
459 if (pAioMgr->fBlockingEventPending)
460 {
461 rc = pdmacFileAioMgrNormalProcessBlockingEvent(pAioMgr);
462 CHECK_RC(pAioMgr, rc);
463 }
464
465 if (RT_LIKELY(pAioMgr->enmState == PDMACEPFILEMGRSTATE_RUNNING))
466 {
467 /* Check the assigned endpoints for new tasks if there isn't a flush request active at the moment. */
468 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint = pAioMgr->pEndpointsHead;
469
470 while (pEndpoint)
471 {
472 if (!pEndpoint->pFlushReq && (pEndpoint->enmState == PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE))
473 {
474 rc = pdmacFileAioMgrNormalQueueReqs(pAioMgr, pEndpoint);
475 CHECK_RC(pAioMgr, rc);
476 }
477
478 pEndpoint = pEndpoint->AioMgr.pEndpointNext;
479 }
480
481 while (pAioMgr->cRequestsActive)
482 {
483 RTFILEAIOREQ apReqs[20];
484 uint32_t cReqsCompleted = 0;
485
486 rc = RTFileAioCtxWait(pAioMgr->hAioCtx, 1, RT_INDEFINITE_WAIT, apReqs,
487 RT_ELEMENTS(apReqs), &cReqsCompleted);
488 CHECK_RC(pAioMgr, rc);
489
490 for (uint32_t i = 0; i < cReqsCompleted; i++)
491 {
492 size_t cbTransfered = 0;
493 int rcReq = RTFileAioReqGetRC(apReqs[i], &cbTransfered);
494 PPDMACTASKFILE pTask = (PPDMACTASKFILE)RTFileAioReqGetUser(apReqs[i]);
495
496 pEndpoint = pTask->pEndpoint;
497
498 AssertMsg( RT_SUCCESS(rcReq)
499 && (cbTransfered == pTask->DataSeg.cbSeg),
500 ("Task didn't completed successfully (rc=%Rrc) or was incomplete (cbTransfered=%u)\n", rc, cbTransfered));
501
502 if (pTask->fBounceBuffer)
503 {
504 if (pTask->enmTransferType == PDMACTASKFILETRANSFER_READ)
505 memcpy(pTask->DataSeg.pvSeg, pTask->pvBounceBuffer, pTask->DataSeg.cbSeg);
506
507 RTMemPageFree(pTask->pvBounceBuffer);
508 }
509
510 /* Put the entry on the free array */
511 pAioMgr->pahReqsFree[pAioMgr->iFreeEntryNext] = apReqs[i];
512 pAioMgr->iFreeEntryNext = (pAioMgr->iFreeEntryNext + 1) %pAioMgr->cReqEntries;
513
514 pAioMgr->cRequestsActive--;
515 pEndpoint->AioMgr.cReqsProcessed++;
516
517 /* Call completion callback */
518 pTask->pfnCompleted(pTask, pTask->pvUser);
519 pdmacFileTaskFree(pEndpoint, pTask);
520
521 /*
522 * If there is no request left on the endpoint but a flush request is set
523 * it completed now and we notify the owner.
524 * Furthermore we look for new requests and continue.
525 */
526 if (!pEndpoint->AioMgr.cRequestsActive && pEndpoint->pFlushReq)
527 {
528 /* Call completion callback */
529 pTask = pEndpoint->pFlushReq;
530 pEndpoint->pFlushReq = NULL;
531
532 AssertMsg(pTask->pEndpoint == pEndpoint, ("Endpoint of the flush request does not match assigned one\n"));
533
534 pTask->pfnCompleted(pTask, pTask->pvUser);
535 pdmacFileTaskFree(pEndpoint, pTask);
536 }
537
538 if (pEndpoint->enmState == PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE)
539 {
540 if (!pEndpoint->pFlushReq)
541 {
542 /* Check if there are events on the endpoint. */
543 rc = pdmacFileAioMgrNormalQueueReqs(pAioMgr, pEndpoint);
544 CHECK_RC(pAioMgr, rc);
545 }
546 }
547 else if (!pEndpoint->AioMgr.cRequestsActive)
548 {
549 Assert(pAioMgr->fBlockingEventPending);
550 ASMAtomicWriteBool(&pAioMgr->fBlockingEventPending, false);
551
552 /* Release the waiting thread. */
553 rc = RTSemEventSignal(pAioMgr->EventSemBlock);
554 AssertRC(rc);
555 }
556 }
557
558 /* Check for an external blocking event before we go to sleep again. */
559 if (pAioMgr->fBlockingEventPending)
560 {
561 rc = pdmacFileAioMgrNormalProcessBlockingEvent(pAioMgr);
562 CHECK_RC(pAioMgr, rc);
563 }
564
565 /* Update load statistics. */
566 uint64_t uMillisCurr = RTTimeMilliTS();
567 if (uMillisCurr > uMillisEnd)
568 {
569 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointCurr = pAioMgr->pEndpointsHead;
570
571 /* Calculate timespan. */
572 uMillisCurr -= uMillisEnd;
573
574 while (pEndpointCurr)
575 {
576 pEndpointCurr->AioMgr.cReqsPerSec = pEndpointCurr->AioMgr.cReqsProcessed / (uMillisCurr + PDMACEPFILEMGR_LOAD_UPDATE_PERIOD);
577 pEndpointCurr->AioMgr.cReqsProcessed = 0;
578 pEndpointCurr = pEndpointCurr->AioMgr.pEndpointNext;
579 }
580
581 /* Set new update interval */
582 uMillisEnd = RTTimeMilliTS() + PDMACEPFILEMGR_LOAD_UPDATE_PERIOD;
583 }
584 }
585 }
586 }
587
588 return rc;
589}
590
591#undef CHECK_RC
592
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