VirtualBox

source: vbox/trunk/src/VBox/VMM/PDMAsyncCompletionFile.cpp@ 22037

Last change on this file since 22037 was 21496, checked in by vboxsync, 15 years ago

VMM/PDMAsyncCompletion: Add basic working manager using RTFileAio API (Only tested on Linux) yet without caching. Splitted normal and failsafe manager into separate files to make the code easier to read

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.9 KB
Line 
1/* $Id: PDMAsyncCompletionFile.cpp 21496 2009-07-10 20:16:09Z vboxsync $ */
2/** @file
3 * PDM Async I/O - Transport data asynchronous in R3 using EMT.
4 */
5
6/*
7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_PDM_ASYNC_COMPLETION
28#include "PDMInternal.h"
29#include <VBox/pdm.h>
30#include <VBox/mm.h>
31#include <VBox/vm.h>
32#include <VBox/err.h>
33
34#include <VBox/log.h>
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/thread.h>
38#include <iprt/mem.h>
39#include <iprt/critsect.h>
40#include <iprt/file.h>
41#include <iprt/semaphore.h>
42#include <iprt/string.h>
43
44#include "PDMAsyncCompletionFileInternal.h"
45
46/**
47 * Frees a task segment
48 *
49 * @returns nothing.
50 * @param pEndpoint Pointer to the endpoint the segment was for.
51 * @param pSeg The segment to free.
52 */
53void pdmacFileSegmentFree(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint,
54 PPDMACTASKFILESEG pSeg)
55{
56 PPDMASYNCCOMPLETIONEPCLASSFILE pEpClass = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->Core.pEpClass;
57
58 LogFlowFunc((": pEndpoint=%p pSeg=%p\n", pEndpoint, pSeg));
59
60 /* Try the per endpoint cache first. */
61 if (pEndpoint->cSegmentsCached < pEpClass->cSegmentsCacheMax)
62 {
63 /* Add it to the list. */
64 pSeg->pPrev = NULL;
65 pEndpoint->pSegmentsFreeTail->pNext = pSeg;
66 pEndpoint->pSegmentsFreeTail = pSeg;
67 ASMAtomicIncU32(&pEndpoint->cSegmentsCached);
68 }
69 else if (false)
70 {
71 /* Bigger class cache */
72 }
73 else
74 {
75 Log(("Freeing segment %p because all caches are full\n", pSeg));
76 MMR3HeapFree(pSeg);
77 }
78}
79
80/**
81 * Allocates a task segment
82 *
83 * @returns Pointer to the new task segment or NULL
84 * @param pEndpoint Pointer to the endpoint
85 */
86PPDMACTASKFILESEG pdmacFileSegmentAlloc(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
87{
88 PPDMACTASKFILESEG pSeg = NULL;
89
90 /* Try the small per endpoint cache first. */
91 if (pEndpoint->pSegmentsFreeHead == pEndpoint->pSegmentsFreeTail)
92 {
93 /* Try the bigger endpoint class cache. */
94 PPDMASYNCCOMPLETIONEPCLASSFILE pEndpointClass = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->Core.pEpClass;
95
96#if 0
97 /* We start with the assigned slot id to distribute the load when allocating new tasks. */
98 unsigned iSlot = pEndpoint->iSlotStart;
99 do
100 {
101 pTask = (PPDMASYNCCOMPLETIONTASK)ASMAtomicXchgPtr((void * volatile *)&pEndpointClass->apTaskCache[iSlot], NULL);
102 if (pTask)
103 break;
104
105 iSlot = (iSlot + 1) % RT_ELEMENTS(pEndpointClass->apTaskCache);
106 } while (iSlot != pEndpoint->iSlotStart);
107#endif
108 if (!pSeg)
109 {
110 /*
111 * Allocate completely new.
112 * If this fails we return NULL.
113 */
114 int rc = MMR3HeapAllocZEx(pEndpointClass->Core.pVM, MM_TAG_PDM_ASYNC_COMPLETION,
115 sizeof(PDMACTASKFILESEG),
116 (void **)&pSeg);
117 if (RT_FAILURE(rc))
118 pSeg = NULL;
119
120 LogFlow(("Allocated segment %p\n", pSeg));
121 }
122#if 0
123 else
124 {
125 /* Remove the first element and put the rest into the slot again. */
126 PPDMASYNCCOMPLETIONTASK pTaskHeadNew = pTask->pNext;
127
128 pTaskHeadNew->pPrev = NULL;
129
130 /* Put back into the list adding any new tasks. */
131 while (true)
132 {
133 bool fChanged = ASMAtomicCmpXchgPtr((void * volatile *)&pEndpointClass->apTaskCache[iSlot], pTaskHeadNew, NULL);
134
135 if (fChanged)
136 break;
137
138 PPDMASYNCCOMPLETIONTASK pTaskHead = (PPDMASYNCCOMPLETIONTASK)ASMAtomicXchgPtr((void * volatile *)&pEndpointClass->apTaskCache[iSlot], NULL);
139
140 /* The new task could be taken inbetween */
141 if (pTaskHead)
142 {
143 /* Go to the end of the probably much shorter new list. */
144 PPDMASYNCCOMPLETIONTASK pTaskTail = pTaskHead;
145 while (pTaskTail->pNext)
146 pTaskTail = pTaskTail->pNext;
147
148 /* Concatenate */
149 pTaskTail->pNext = pTaskHeadNew;
150
151 pTaskHeadNew = pTaskHead;
152 }
153 /* Another round trying to change the list. */
154 }
155 /* We got a task from the global cache so decrement the counter */
156 ASMAtomicDecU32(&pEndpointClass->cTasksCached);
157 }
158#endif
159 }
160 else
161 {
162 /* Grab a free task from the head. */
163 AssertMsg(pEndpoint->cSegmentsCached > 0, ("No segments cached but list contains more than one element\n"));
164
165 pSeg = pEndpoint->pSegmentsFreeHead;
166 pEndpoint->pSegmentsFreeHead = pSeg->pNext;
167 ASMAtomicDecU32(&pEndpoint->cSegmentsCached);
168 }
169
170 pSeg->pNext = NULL;
171 pSeg->pPrev = NULL;
172
173 return pSeg;
174}
175
176PPDMASYNCCOMPLETIONTASK pdmacFileEpGetNewTasks(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
177{
178 PPDMASYNCCOMPLETIONTASK pTasks = NULL;
179
180 /*
181 * Get pending tasks.
182 */
183 pTasks = (PPDMASYNCCOMPLETIONTASK)ASMAtomicXchgPtr((void * volatile *)&pEndpoint->pTasksNewHead, NULL);
184
185 /* Reverse the list to process in FIFO order. */
186 if (pTasks)
187 {
188 PPDMASYNCCOMPLETIONTASK pTask = pTasks;
189
190 pTasks = NULL;
191
192 while (pTask)
193 {
194 PPDMASYNCCOMPLETIONTASK pCur = pTask;
195 pTask = pTask->pNext;
196 pCur->pNext = pTasks;
197 pTasks = pCur;
198 }
199 }
200
201 return pTasks;
202}
203
204static void pdmacFileAioMgrWakeup(PPDMACEPFILEMGR pAioMgr)
205{
206 bool fWokenUp = ASMAtomicXchgBool(&pAioMgr->fWokenUp, true);
207
208 if (!fWokenUp)
209 {
210 int rc = VINF_SUCCESS;
211 bool fWaitingEventSem = ASMAtomicReadBool(&pAioMgr->fWaitingEventSem);
212
213 if (fWaitingEventSem)
214 rc = RTSemEventSignal(pAioMgr->EventSem);
215
216 AssertRC(rc);
217 }
218}
219
220static int pdmacFileAioMgrWaitForBlockingEvent(PPDMACEPFILEMGR pAioMgr, PDMACEPFILEAIOMGRBLOCKINGEVENT enmEvent)
221{
222 int rc = VINF_SUCCESS;
223
224 ASMAtomicWriteU32((volatile uint32_t *)&pAioMgr->enmBlockingEvent, enmEvent);
225 ASMAtomicXchgBool(&pAioMgr->fBlockingEventPending, true);
226
227 /* Wakeup the async I/O manager */
228 pdmacFileAioMgrWakeup(pAioMgr);
229
230 /* Wait for completion. */
231 rc = RTSemEventWait(pAioMgr->EventSemBlock, RT_INDEFINITE_WAIT);
232 AssertRC(rc);
233
234 ASMAtomicXchgBool(&pAioMgr->fBlockingEventPending, false);
235 ASMAtomicWriteU32((volatile uint32_t *)&pAioMgr->enmBlockingEvent, PDMACEPFILEAIOMGRBLOCKINGEVENT_INVALID);
236
237 return rc;
238}
239
240static int pdmacFileAioMgrAddEndpoint(PPDMACEPFILEMGR pAioMgr, PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
241{
242 int rc;
243
244 rc = RTCritSectEnter(&pAioMgr->CritSectBlockingEvent);
245 AssertRCReturn(rc, rc);
246
247 ASMAtomicWritePtr((void * volatile *)&pAioMgr->BlockingEventData.AddEndpoint.pEndpoint, pEndpoint);
248 rc = pdmacFileAioMgrWaitForBlockingEvent(pAioMgr, PDMACEPFILEAIOMGRBLOCKINGEVENT_ADD_ENDPOINT);
249
250 RTCritSectLeave(&pAioMgr->CritSectBlockingEvent);
251
252 if (RT_SUCCESS(rc))
253 ASMAtomicWritePtr((void * volatile *)&pEndpoint->pAioMgr, pAioMgr);
254
255 return rc;
256}
257
258static int pdmacFileAioMgrRemoveEndpoint(PPDMACEPFILEMGR pAioMgr, PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
259{
260 int rc;
261
262 rc = RTCritSectEnter(&pAioMgr->CritSectBlockingEvent);
263 AssertRCReturn(rc, rc);
264
265 ASMAtomicWritePtr((void * volatile *)&pAioMgr->BlockingEventData.RemoveEndpoint.pEndpoint, pEndpoint);
266 rc = pdmacFileAioMgrWaitForBlockingEvent(pAioMgr, PDMACEPFILEAIOMGRBLOCKINGEVENT_REMOVE_ENDPOINT);
267
268 RTCritSectLeave(&pAioMgr->CritSectBlockingEvent);
269
270 return rc;
271}
272
273static int pdmacFileAioMgrCloseEndpoint(PPDMACEPFILEMGR pAioMgr, PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint)
274{
275 int rc;
276
277 rc = RTCritSectEnter(&pAioMgr->CritSectBlockingEvent);
278 AssertRCReturn(rc, rc);
279
280 ASMAtomicWritePtr((void * volatile *)&pAioMgr->BlockingEventData.CloseEndpoint.pEndpoint, pEndpoint);
281 rc = pdmacFileAioMgrWaitForBlockingEvent(pAioMgr, PDMACEPFILEAIOMGRBLOCKINGEVENT_CLOSE_ENDPOINT);
282
283 RTCritSectLeave(&pAioMgr->CritSectBlockingEvent);
284
285 return rc;
286}
287
288static int pdmacFileAioMgrShutdown(PPDMACEPFILEMGR pAioMgr)
289{
290 int rc;
291
292 ASMAtomicXchgBool(&pAioMgr->fShutdown, true);
293
294 rc = RTCritSectEnter(&pAioMgr->CritSectBlockingEvent);
295 AssertRCReturn(rc, rc);
296
297 rc = pdmacFileAioMgrWaitForBlockingEvent(pAioMgr, PDMACEPFILEAIOMGRBLOCKINGEVENT_SHUTDOWN);
298
299 RTCritSectLeave(&pAioMgr->CritSectBlockingEvent);
300
301 return rc;
302}
303
304static int pdmacFileEpAddTask(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint, PPDMASYNCCOMPLETIONTASKFILE pTask)
305{
306 PPDMASYNCCOMPLETIONTASK pNext;
307 do
308 {
309 pNext = pEndpoint->pTasksNewHead;
310 pTask->Core.pNext = pNext;
311 } while (!ASMAtomicCmpXchgPtr((void * volatile *)&pEndpoint->pTasksNewHead, (void *)pTask, (void *)pNext));
312
313 pdmacFileAioMgrWakeup((PPDMACEPFILEMGR)ASMAtomicReadPtr((void * volatile *)&pEndpoint->pAioMgr));
314
315 return VINF_SUCCESS;
316}
317
318static int pdmacFileEpTaskInitiate(PPDMASYNCCOMPLETIONTASK pTask,
319 PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
320 PCPDMDATASEG paSegments, size_t cSegments,
321 size_t cbTransfer, PDMACTASKFILETRANSFER enmTransfer)
322{
323 int rc = VINF_SUCCESS;
324 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
325 PPDMASYNCCOMPLETIONTASKFILE pTaskFile = (PPDMASYNCCOMPLETIONTASKFILE)pTask;
326 PPDMACEPFILEMGR pAioMgr = pEpFile->pAioMgr;
327
328 Assert( (enmTransfer == PDMACTASKFILETRANSFER_READ)
329 || (enmTransfer == PDMACTASKFILETRANSFER_WRITE));
330
331 pTaskFile->enmTransferType = enmTransfer;
332 pTaskFile->u.DataTransfer.cSegments = cSegments;
333 pTaskFile->u.DataTransfer.pSegmentsHead = NULL;
334 pTaskFile->u.DataTransfer.off = off;
335 pTaskFile->u.DataTransfer.cbTransfer = cbTransfer;
336
337 PPDMACTASKFILESEG pSeg = pdmacFileSegmentAlloc(pEpFile);
338
339 pTaskFile->u.DataTransfer.pSegmentsHead = pSeg;
340
341 for (unsigned i = 0; i < cSegments; i++)
342 {
343 pSeg->DataSeg.cbSeg = paSegments[i].cbSeg;
344 pSeg->DataSeg.pvSeg = paSegments[i].pvSeg;
345 pSeg->pTask = pTaskFile;
346
347 if (i < (cSegments-1))
348 {
349 /* Allocate new segment. */
350 PPDMACTASKFILESEG pSegNext = pdmacFileSegmentAlloc(pEpFile);
351 AssertPtr(pSeg);
352 pSeg->pNext = pSegNext;
353 pSeg = pSegNext;
354 }
355 }
356
357 /* Send it off to the I/O manager. */
358 pdmacFileEpAddTask(pEpFile, pTaskFile);
359
360 return VINF_SUCCESS;
361}
362
363/**
364 * Creates a new async I/O manager.
365 *
366 * @returns VBox status code.
367 * @param pEpClass Pointer to the endpoint class data.
368 * @param ppAioMgr Where to store the pointer to the new async I/O manager on success.
369 */
370static int pdmacFileAioMgrCreate(PPDMASYNCCOMPLETIONEPCLASSFILE pEpClass, PPPDMACEPFILEMGR ppAioMgr)
371{
372 int rc = VINF_SUCCESS;
373 PPDMACEPFILEMGR pAioMgrNew;
374
375 LogFlowFunc((": Entered\n"));
376
377 rc = MMR3HeapAllocZEx(pEpClass->Core.pVM, MM_TAG_PDM_ASYNC_COMPLETION, sizeof(PDMACEPFILEMGR), (void **)&pAioMgrNew);
378 if (RT_SUCCESS(rc))
379 {
380 pAioMgrNew->fFailsafe = pEpClass->fFailsafe;
381
382 rc = RTSemEventCreate(&pAioMgrNew->EventSem);
383 if (RT_SUCCESS(rc))
384 {
385 rc = RTSemEventCreate(&pAioMgrNew->EventSemBlock);
386 if (RT_SUCCESS(rc))
387 {
388 rc = RTCritSectInit(&pAioMgrNew->CritSectBlockingEvent);
389 if (RT_SUCCESS(rc))
390 {
391 /* Init the rest of the manager. */
392 rc = pdmacFileAioMgrNormalInit(pAioMgrNew);
393 if (RT_SUCCESS(rc))
394 {
395 rc = RTThreadCreateF(&pAioMgrNew->Thread,
396 pAioMgrNew->fFailsafe
397 ? pdmacFileAioMgrFailsafe
398 : pdmacFileAioMgrNormal,
399 pAioMgrNew,
400 0,
401 RTTHREADTYPE_IO,
402 0,
403 "AioMgr%d-%s", pEpClass->cAioMgrs,
404 pAioMgrNew->fFailsafe
405 ? "F"
406 : "N");
407 if (RT_SUCCESS(rc))
408 {
409 /* Link it into the list. */
410 RTCritSectEnter(&pEpClass->CritSect);
411 pAioMgrNew->pNext = pEpClass->pAioMgrHead;
412 if (pEpClass->pAioMgrHead)
413 pEpClass->pAioMgrHead->pPrev = pAioMgrNew;
414 pEpClass->pAioMgrHead = pAioMgrNew;
415 pEpClass->cAioMgrs++;
416 RTCritSectLeave(&pEpClass->CritSect);
417
418 *ppAioMgr = pAioMgrNew;
419
420 Log(("PDMAC: Successfully created new file AIO Mgr {%s}\n", RTThreadGetName(pAioMgrNew->Thread)));
421 return VINF_SUCCESS;
422 }
423 pdmacFileAioMgrNormalDestroy(pAioMgrNew);
424 }
425 RTCritSectDelete(&pAioMgrNew->CritSectBlockingEvent);
426 }
427 RTSemEventDestroy(pAioMgrNew->EventSem);
428 }
429 RTSemEventDestroy(pAioMgrNew->EventSemBlock);
430 }
431 MMR3HeapFree(pAioMgrNew);
432 }
433
434 LogFlowFunc((": Leave rc=%Rrc\n", rc));
435
436 return rc;
437}
438
439/**
440 * Destroys a async I/O manager.
441 *
442 * @returns nothing.
443 * @param pAioMgr The async I/O manager to destroy.
444 */
445static void pdmacFileAioMgrDestroy(PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile, PPDMACEPFILEMGR pAioMgr)
446{
447 /* A normal manager may have still endpoints attached and has to return them. */
448 Assert(pAioMgr->fFailsafe);
449 int rc = pdmacFileAioMgrShutdown(pAioMgr);
450 AssertRC(rc);
451
452 /* Unlink from the list. */
453 rc = RTCritSectEnter(&pEpClassFile->CritSect);
454 AssertRC(rc);
455
456 PPDMACEPFILEMGR pPrev = pAioMgr->pPrev;
457 PPDMACEPFILEMGR pNext = pAioMgr->pNext;
458
459 if (pPrev)
460 pPrev->pNext = pNext;
461 else
462 pEpClassFile->pAioMgrHead = pNext;
463
464 if (pNext)
465 pNext->pPrev = pPrev;
466
467 pEpClassFile->cAioMgrs--;
468
469 rc = RTCritSectLeave(&pEpClassFile->CritSect);
470 AssertRC(rc);
471
472 /* Free the ressources. */
473 RTCritSectDelete(&pAioMgr->CritSectBlockingEvent);
474 RTSemEventDestroy(pAioMgr->EventSem);
475 if (!pAioMgr->fFailsafe)
476 pdmacFileAioMgrNormalDestroy(pAioMgr);
477
478 MMR3HeapFree(pAioMgr);
479}
480
481static int pdmacFileInitialize(PPDMASYNCCOMPLETIONEPCLASS pClassGlobals, PCFGMNODE pCfgNode)
482{
483 int rc = VINF_SUCCESS;
484 RTFILEAIOLIMITS AioLimits; /** < Async I/O limitations. */
485
486 PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pClassGlobals;
487
488 rc = RTFileAioGetLimits(&AioLimits);
489 if (RT_FAILURE(rc))
490 {
491 LogRel(("AIO: Async I/O manager not supported (rc=%Rrc). Falling back to failsafe manager\n",
492 rc));
493 pEpClassFile->fFailsafe = true;
494 }
495 else
496 {
497 pEpClassFile->uBitmaskAlignment = ~((RTR3UINTPTR)AioLimits.cbBufferAlignment - 1);
498 pEpClassFile->cReqsOutstandingMax = AioLimits.cReqsOutstandingMax;
499 pEpClassFile->fFailsafe = false;
500 }
501
502 /* Init critical section. */
503 rc = RTCritSectInit(&pEpClassFile->CritSect);
504 return rc;
505}
506
507static void pdmacFileTerminate(PPDMASYNCCOMPLETIONEPCLASS pClassGlobals)
508{
509 PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pClassGlobals;
510
511 /* All endpoints should be closed at this point. */
512 AssertMsg(!pEpClassFile->Core.pEndpointsHead, ("There are still endpoints left\n"));
513
514 /* Destroy all left async I/O managers. */
515 while (pEpClassFile->pAioMgrHead)
516 pdmacFileAioMgrDestroy(pEpClassFile, pEpClassFile->pAioMgrHead);
517
518 RTCritSectDelete(&pEpClassFile->CritSect);
519}
520
521static int pdmacFileEpInitialize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
522 const char *pszUri, uint32_t fFlags)
523{
524 int rc = VINF_SUCCESS;
525 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
526 PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->pEpClass;
527
528 AssertMsgReturn((fFlags & ~(PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_CACHING)) == 0,
529 ("PDMAsyncCompletion: Invalid flag specified\n"), VERR_INVALID_PARAMETER);
530
531 unsigned fFileFlags = fFlags & PDMACEP_FILE_FLAGS_READ_ONLY
532 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
533 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE;
534
535 if (!pEpClassFile->fFailsafe)
536 fFileFlags |= (RTFILE_O_ASYNC_IO | RTFILE_O_NO_CACHE);
537
538 pEpFile->pszFilename = RTStrDup(pszUri);
539 if (!pEpFile->pszFilename)
540 return VERR_NO_MEMORY;
541 pEpFile->fFlags = fFileFlags;
542
543 rc = RTFileOpen(&pEpFile->File, pszUri, fFileFlags);
544 if (RT_SUCCESS(rc))
545 {
546 /* Initialize the segment cache */
547 rc = MMR3HeapAllocZEx(pEpClassFile->Core.pVM, MM_TAG_PDM_ASYNC_COMPLETION,
548 sizeof(PDMACTASKFILESEG),
549 (void **)&pEpFile->pSegmentsFreeHead);
550 if (RT_SUCCESS(rc))
551 {
552 PPDMACEPFILEMGR pAioMgr = NULL;
553
554 pEpFile->pSegmentsFreeTail = pEpFile->pSegmentsFreeHead;
555 pEpFile->cSegmentsCached = 0;
556
557 if (pEpClassFile->fFailsafe)
558 {
559 /* Safe mode. Every file has its own async I/O manager. */
560 rc = pdmacFileAioMgrCreate(pEpClassFile, &pAioMgr);
561 AssertRC(rc);
562 }
563 else
564 {
565 if (fFlags & PDMACEP_FILE_FLAGS_CACHING)
566 {
567 pEpFile->fCaching = true;
568 }
569
570 /* Check for an idling one or create new if not found */
571 if (!pEpClassFile->pAioMgrHead)
572 {
573 rc = pdmacFileAioMgrCreate(pEpClassFile, &pAioMgr);
574 AssertRC(rc);
575 }
576 else
577 {
578 pAioMgr = pEpClassFile->pAioMgrHead;
579 }
580 }
581
582 /* Assign the endpoint to the thread. */
583 rc = pdmacFileAioMgrAddEndpoint(pAioMgr, pEpFile);
584 if (RT_FAILURE(rc))
585 MMR3HeapFree(pEpFile->pSegmentsFreeHead);
586 }
587
588 if (RT_FAILURE(rc))
589 RTFileClose(pEpFile->File);
590 }
591
592 if (RT_FAILURE(rc))
593 RTStrFree(pEpFile->pszFilename);
594
595 return rc;
596}
597
598static int pdmacFileEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
599{
600 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
601 PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->pEpClass;
602
603 /* Make sure that all tasks finished for this endpoint. */
604 int rc = pdmacFileAioMgrCloseEndpoint(pEpFile->pAioMgr, pEpFile);
605 AssertRC(rc);
606
607 /* Remove the endpoint from the thread. */
608 rc = pdmacFileAioMgrRemoveEndpoint(pEpFile->pAioMgr, pEpFile);
609 AssertRC(rc);
610
611 /*
612 * If the async I/O manager is in failsafe mode this is the only endpoint
613 * he processes and thus can be destroyed now.
614 */
615 if (pEpFile->pAioMgr->fFailsafe)
616 pdmacFileAioMgrDestroy(pEpClassFile, pEpFile->pAioMgr);
617
618 /* Free cached segments. */
619 PPDMACTASKFILESEG pSeg = pEpFile->pSegmentsFreeHead;
620
621 while (pSeg)
622 {
623 PPDMACTASKFILESEG pSegFree = pSeg;
624 pSeg = pSeg->pNext;
625 MMR3HeapFree(pSegFree);
626 }
627
628 /* Free the cached data. */
629 Assert(!pEpFile->fCaching);
630
631 return VINF_SUCCESS;
632}
633
634static int pdmacFileEpRead(PPDMASYNCCOMPLETIONTASK pTask,
635 PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
636 PCPDMDATASEG paSegments, size_t cSegments,
637 size_t cbRead)
638{
639 return pdmacFileEpTaskInitiate(pTask, pEndpoint, off, paSegments, cSegments, cbRead,
640 PDMACTASKFILETRANSFER_READ);
641}
642
643static int pdmacFileEpWrite(PPDMASYNCCOMPLETIONTASK pTask,
644 PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
645 PCPDMDATASEG paSegments, size_t cSegments,
646 size_t cbWrite)
647{
648 return pdmacFileEpTaskInitiate(pTask, pEndpoint, off, paSegments, cSegments, cbWrite,
649 PDMACTASKFILETRANSFER_WRITE);
650}
651
652static int pdmacFileEpFlush(PPDMASYNCCOMPLETIONTASK pTask,
653 PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
654{
655 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
656 PPDMASYNCCOMPLETIONTASKFILE pTaskFile = (PPDMASYNCCOMPLETIONTASKFILE)pTask;
657
658 pTaskFile->enmTransferType = PDMACTASKFILETRANSFER_FLUSH;
659 pdmacFileEpAddTask(pEpFile, pTaskFile);
660
661 return VINF_SUCCESS;
662}
663
664static int pdmacFileEpGetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize)
665{
666 PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEndpoint;
667
668 return RTFileGetSize(pEpFile->File, pcbSize);
669}
670
671const PDMASYNCCOMPLETIONEPCLASSOPS g_PDMAsyncCompletionEndpointClassFile =
672{
673 /* u32Version */
674 PDMAC_EPCLASS_OPS_VERSION,
675 /* pcszName */
676 "File",
677 /* enmClassType */
678 PDMASYNCCOMPLETIONEPCLASSTYPE_FILE,
679 /* cbEndpointClassGlobal */
680 sizeof(PDMASYNCCOMPLETIONEPCLASSFILE),
681 /* cbEndpoint */
682 sizeof(PDMASYNCCOMPLETIONENDPOINTFILE),
683 /* cbTask */
684 sizeof(PDMASYNCCOMPLETIONTASKFILE),
685 /* pfnInitialize */
686 pdmacFileInitialize,
687 /* pfnTerminate */
688 pdmacFileTerminate,
689 /* pfnEpInitialize. */
690 pdmacFileEpInitialize,
691 /* pfnEpClose */
692 pdmacFileEpClose,
693 /* pfnEpRead */
694 pdmacFileEpRead,
695 /* pfnEpWrite */
696 pdmacFileEpWrite,
697 /* pfnEpFlush */
698 pdmacFileEpFlush,
699 /* pfnEpGetSize */
700 pdmacFileEpGetSize,
701 /* u32VersionEnd */
702 PDMAC_EPCLASS_OPS_VERSION
703};
704
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