VirtualBox

source: vbox/trunk/src/VBox/VMM/PDMAsyncCompletion.cpp@ 28112

Last change on this file since 28112 was 28065, checked in by vboxsync, 15 years ago

Storage: Convert from PDMDATASEG to RTSGSEG to avoid casting between those two in VBoxHDD and more async I/O updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.5 KB
Line 
1/* $Id: PDMAsyncCompletion.cpp 28065 2010-04-07 20:54:34Z 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* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_PDM_ASYNC_COMPLETION
27#include "PDMInternal.h"
28#include <VBox/pdm.h>
29#include <VBox/mm.h>
30#include <VBox/rem.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/tcp.h>
41#include <iprt/path.h>
42
43#include <VBox/pdmasynccompletion.h>
44#include "PDMAsyncCompletionInternal.h"
45
46/**
47 * Async I/O type.
48 */
49typedef enum PDMASYNCCOMPLETIONTEMPLATETYPE
50{
51 /** Device . */
52 PDMASYNCCOMPLETIONTEMPLATETYPE_DEV = 1,
53 /** Driver consumer. */
54 PDMASYNCCOMPLETIONTEMPLATETYPE_DRV,
55 /** Internal consumer. */
56 PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL,
57 /** Usb consumer. */
58 PDMASYNCCOMPLETIONTEMPLATETYPE_USB
59} PDMASYNCTEMPLATETYPE;
60
61/**
62 * PDM Async I/O template.
63 */
64typedef struct PDMASYNCCOMPLETIONTEMPLATE
65{
66 /** Pointer to the next template in the list. */
67 R3PTRTYPE(PPDMASYNCCOMPLETIONTEMPLATE) pNext;
68 /** Pointer to the previous template in the list. */
69 R3PTRTYPE(PPDMASYNCCOMPLETIONTEMPLATE) pPrev;
70 /** Type specific data. */
71 union
72 {
73 /** PDMASYNCCOMPLETIONTEMPLATETYPE_DEV */
74 struct
75 {
76 /** Pointer to consumer function. */
77 R3PTRTYPE(PFNPDMASYNCCOMPLETEDEV) pfnCompleted;
78 /** Pointer to the device instance owning the template. */
79 R3PTRTYPE(PPDMDEVINS) pDevIns;
80 } Dev;
81 /** PDMASYNCCOMPLETIONTEMPLATETYPE_DRV */
82 struct
83 {
84 /** Pointer to consumer function. */
85 R3PTRTYPE(PFNPDMASYNCCOMPLETEDRV) pfnCompleted;
86 /** Pointer to the driver instance owning the template. */
87 R3PTRTYPE(PPDMDRVINS) pDrvIns;
88 /** User agument given during template creation.
89 * This is only here to make things much easier
90 * for DrVVD. */
91 void *pvTemplateUser;
92 } Drv;
93 /** PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL */
94 struct
95 {
96 /** Pointer to consumer function. */
97 R3PTRTYPE(PFNPDMASYNCCOMPLETEINT) pfnCompleted;
98 /** Pointer to user data. */
99 R3PTRTYPE(void *) pvUser;
100 } Int;
101 /** PDMASYNCCOMPLETIONTEMPLATETYPE_USB */
102 struct
103 {
104 /** Pointer to consumer function. */
105 R3PTRTYPE(PFNPDMASYNCCOMPLETEUSB) pfnCompleted;
106 /** Pointer to the usb instance owning the template. */
107 R3PTRTYPE(PPDMUSBINS) pUsbIns;
108 } Usb;
109 } u;
110 /** Template type. */
111 PDMASYNCCOMPLETIONTEMPLATETYPE enmType;
112 /** Pointer to the VM. */
113 R3PTRTYPE(PVM) pVM;
114 /** Use count of the template. */
115 volatile uint32_t cUsed;
116} PDMASYNCCOMPLETIONTEMPLATE;
117
118static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask);
119
120/**
121 * Internal worker for the creation apis
122 *
123 * @returns VBox status.
124 * @param pVM VM handle.
125 * @param ppTemplate Where to store the template handle.
126 */
127static int pdmR3AsyncCompletionTemplateCreate(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE enmType)
128{
129 int rc = VINF_SUCCESS;
130
131 if (ppTemplate == NULL)
132 {
133 AssertMsgFailed(("ppTemplate is NULL\n"));
134 return VERR_INVALID_PARAMETER;
135 }
136
137 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
138 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION, sizeof(PDMASYNCCOMPLETIONTEMPLATE), (void **)&pTemplate);
139 if (RT_FAILURE(rc))
140 return rc;
141
142 /*
143 * Initialize fields.
144 */
145 pTemplate->pVM = pVM;
146 pTemplate->cUsed = 0;
147 pTemplate->enmType = enmType;
148
149 /*
150 * Add template to the global VM template list.
151 */
152 pTemplate->pNext = pVM->pdm.s.pAsyncCompletionTemplates;
153 if (pVM->pdm.s.pAsyncCompletionTemplates)
154 pVM->pdm.s.pAsyncCompletionTemplates->pPrev = pTemplate;
155 pVM->pdm.s.pAsyncCompletionTemplates = pTemplate;
156
157 *ppTemplate = pTemplate;
158 return VINF_SUCCESS;
159}
160
161/**
162 * Creates a async completion template for a device instance.
163 *
164 * The template is used when creating new completion tasks.
165 *
166 * @returns VBox status code.
167 * @param pVM Pointer to the shared VM structure.
168 * @param pDevIns The device instance.
169 * @param ppTemplate Where to store the template pointer on success.
170 * @param pfnCompleted The completion callback routine.
171 * @param pszDesc Description.
172 */
173VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateDevice(PVM pVM, PPDMDEVINS pDevIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEDEV pfnCompleted, const char *pszDesc)
174{
175 LogFlow(("%s: pDevIns=%p ppTemplate=%p pfnCompleted=%p pszDesc=%s\n",
176 __FUNCTION__, pDevIns, ppTemplate, pfnCompleted, pszDesc));
177
178 /*
179 * Validate input.
180 */
181 VM_ASSERT_EMT(pVM);
182 if (!pfnCompleted)
183 {
184 AssertMsgFailed(("No completion callback!\n"));
185 return VERR_INVALID_PARAMETER;
186 }
187
188 if (!ppTemplate)
189 {
190 AssertMsgFailed(("Template pointer is NULL!\n"));
191 return VERR_INVALID_PARAMETER;
192 }
193
194 /*
195 * Create the template.
196 */
197 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
198 int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_DEV);
199 if (RT_SUCCESS(rc))
200 {
201 pTemplate->u.Dev.pDevIns = pDevIns;
202 pTemplate->u.Dev.pfnCompleted = pfnCompleted;
203
204 *ppTemplate = pTemplate;
205 Log(("PDM: Created device template %p: pfnCompleted=%p pDevIns=%p\n",
206 pTemplate, pfnCompleted, pDevIns));
207 }
208
209 return rc;
210}
211
212/**
213 * Creates a async completion template for a driver instance.
214 *
215 * The template is used when creating new completion tasks.
216 *
217 * @returns VBox status code.
218 * @param pVM Pointer to the shared VM structure.
219 * @param pDrvIns The driver instance.
220 * @param ppTemplate Where to store the template pointer on success.
221 * @param pfnCompleted The completion callback routine.
222 * @param pvTemplateUser Template user argument
223 * @param pszDesc Description.
224 */
225VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser, const char *pszDesc)
226{
227 LogFlow(("%s: pDrvIns=%p ppTemplate=%p pfnCompleted=%p pszDesc=%s\n",
228 __FUNCTION__, pDrvIns, ppTemplate, pfnCompleted, pszDesc));
229
230 /*
231 * Validate input.
232 */
233 VM_ASSERT_EMT(pVM);
234 if (!pfnCompleted)
235 {
236 AssertMsgFailed(("No completion callback!\n"));
237 return VERR_INVALID_PARAMETER;
238 }
239
240 if (!ppTemplate)
241 {
242 AssertMsgFailed(("Template pointer is NULL!\n"));
243 return VERR_INVALID_PARAMETER;
244 }
245
246 /*
247 * Create the template.
248 */
249 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
250 int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_DRV);
251 if (RT_SUCCESS(rc))
252 {
253 pTemplate->u.Drv.pDrvIns = pDrvIns;
254 pTemplate->u.Drv.pfnCompleted = pfnCompleted;
255 pTemplate->u.Drv.pvTemplateUser = pvTemplateUser;
256
257 *ppTemplate = pTemplate;
258 Log(("PDM: Created driver template %p: pfnCompleted=%p pDrvIns=%p\n",
259 pTemplate, pfnCompleted, pDrvIns));
260 }
261
262 return rc;
263}
264
265/**
266 * Creates a async completion template for a USB device instance.
267 *
268 * The template is used when creating new completion tasks.
269 *
270 * @returns VBox status code.
271 * @param pVM Pointer to the shared VM structure.
272 * @param pUsbIns The USB device instance.
273 * @param ppTemplate Where to store the template pointer on success.
274 * @param pfnCompleted The completion callback routine.
275 * @param pszDesc Description.
276 */
277VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEUSB pfnCompleted, const char *pszDesc)
278{
279 LogFlow(("%s: pUsbIns=%p ppTemplate=%p pfnCompleted=%p pszDesc=%s\n",
280 __FUNCTION__, pUsbIns, ppTemplate, pfnCompleted, pszDesc));
281
282 /*
283 * Validate input.
284 */
285 VM_ASSERT_EMT(pVM);
286 if (!pfnCompleted)
287 {
288 AssertMsgFailed(("No completion callback!\n"));
289 return VERR_INVALID_PARAMETER;
290 }
291
292 if (!ppTemplate)
293 {
294 AssertMsgFailed(("Template pointer is NULL!\n"));
295 return VERR_INVALID_PARAMETER;
296 }
297
298 /*
299 * Create the template.
300 */
301 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
302 int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_USB);
303 if (RT_SUCCESS(rc))
304 {
305 pTemplate->u.Usb.pUsbIns = pUsbIns;
306 pTemplate->u.Usb.pfnCompleted = pfnCompleted;
307
308 *ppTemplate = pTemplate;
309 Log(("PDM: Created usb template %p: pfnCompleted=%p pDevIns=%p\n",
310 pTemplate, pfnCompleted, pUsbIns));
311 }
312
313 return rc;
314}
315
316/**
317 * Creates a async completion template for internally by the VMM.
318 *
319 * The template is used when creating new completion tasks.
320 *
321 * @returns VBox status code.
322 * @param pVM Pointer to the shared VM structure.
323 * @param ppTemplate Where to store the template pointer on success.
324 * @param pfnCompleted The completion callback routine.
325 * @param pvUser2 The 2nd user argument for the callback.
326 * @param pszDesc Description.
327 */
328VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateInternal(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEINT pfnCompleted, void *pvUser2, const char *pszDesc)
329{
330 LogFlow(("%s: ppTemplate=%p pfnCompleted=%p pvUser2=%p pszDesc=%s\n",
331 __FUNCTION__, ppTemplate, pfnCompleted, pvUser2, pszDesc));
332
333 /*
334 * Validate input.
335 */
336 VM_ASSERT_EMT(pVM);
337 if (!pfnCompleted)
338 {
339 AssertMsgFailed(("No completion callback!\n"));
340 return VERR_INVALID_PARAMETER;
341 }
342
343 if (!ppTemplate)
344 {
345 AssertMsgFailed(("Template pointer is NULL!\n"));
346 return VERR_INVALID_PARAMETER;
347 }
348
349 /*
350 * Create the template.
351 */
352 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
353 int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL);
354 if (RT_SUCCESS(rc))
355 {
356 pTemplate->u.Int.pvUser = pvUser2;
357 pTemplate->u.Int.pfnCompleted = pfnCompleted;
358
359 *ppTemplate = pTemplate;
360 Log(("PDM: Created internal template %p: pfnCompleted=%p pvUser2=%p\n",
361 pTemplate, pfnCompleted, pvUser2));
362 }
363
364 return rc;
365}
366
367/**
368 * Destroys the specified async completion template.
369 *
370 * @returns VBox status codes:
371 * @retval VINF_SUCCESS on success.
372 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if the template is still in use.
373 *
374 * @param pTemplate The template in question.
375 */
376VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroy(PPDMASYNCCOMPLETIONTEMPLATE pTemplate)
377{
378 LogFlow(("%s: pTemplate=%p\n", __FUNCTION__, pTemplate));
379
380 if (!pTemplate)
381 {
382 AssertMsgFailed(("pTemplate is NULL!\n"));
383 return VERR_INVALID_PARAMETER;
384 }
385
386 /*
387 * Check if the template is still used.
388 */
389 if (pTemplate->cUsed > 0)
390 {
391 AssertMsgFailed(("Template is still in use\n"));
392 return VERR_PDM_ASYNC_TEMPLATE_BUSY;
393 }
394
395 /*
396 * Unlink the template from the list.
397 */
398 PVM pVM = pTemplate->pVM;
399 PPDMASYNCCOMPLETIONTEMPLATE pPrev = pTemplate->pPrev;
400 PPDMASYNCCOMPLETIONTEMPLATE pNext = pTemplate->pNext;
401
402 if (pPrev)
403 pPrev->pNext = pNext;
404 else
405 pVM->pdm.s.pAsyncCompletionTemplates = pNext;
406
407 if (pNext)
408 pNext->pPrev = pPrev;
409
410 /*
411 * Free the template.
412 */
413 MMR3HeapFree(pTemplate);
414
415 return VINF_SUCCESS;
416}
417
418/**
419 * Destroys all the specified async completion templates for the given device instance.
420 *
421 * @returns VBox status codes:
422 * @retval VINF_SUCCESS on success.
423 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
424 *
425 * @param pVM Pointer to the shared VM structure.
426 * @param pDevIns The device instance.
427 */
428VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyDevice(PVM pVM, PPDMDEVINS pDevIns)
429{
430 LogFlow(("%s: pDevIns=%p\n", __FUNCTION__, pDevIns));
431
432 /*
433 * Validate input.
434 */
435 if (!pDevIns)
436 return VERR_INVALID_PARAMETER;
437 VM_ASSERT_EMT(pVM);
438
439 /*
440 * Unlink it.
441 */
442 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pVM->pdm.s.pAsyncCompletionTemplates;
443 while (pTemplate)
444 {
445 if ( pTemplate->enmType == PDMASYNCCOMPLETIONTEMPLATETYPE_DEV
446 && pTemplate->u.Dev.pDevIns == pDevIns)
447 {
448 PPDMASYNCCOMPLETIONTEMPLATE pTemplateDestroy = pTemplate;
449 pTemplate = pTemplate->pNext;
450 int rc = PDMR3AsyncCompletionTemplateDestroy(pTemplateDestroy);
451 if (RT_FAILURE(rc))
452 return rc;
453 }
454 else
455 pTemplate = pTemplate->pNext;
456 }
457
458 return VINF_SUCCESS;
459}
460
461/**
462 * Destroys all the specified async completion templates for the given driver instance.
463 *
464 * @returns VBox status codes:
465 * @retval VINF_SUCCESS on success.
466 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
467 *
468 * @param pVM Pointer to the shared VM structure.
469 * @param pDrvIns The driver instance.
470 */
471VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns)
472{
473 LogFlow(("%s: pDevIns=%p\n", __FUNCTION__, pDrvIns));
474
475 /*
476 * Validate input.
477 */
478 if (!pDrvIns)
479 return VERR_INVALID_PARAMETER;
480 VM_ASSERT_EMT(pVM);
481
482 /*
483 * Unlink it.
484 */
485 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pVM->pdm.s.pAsyncCompletionTemplates;
486 while (pTemplate)
487 {
488 if ( pTemplate->enmType == PDMASYNCCOMPLETIONTEMPLATETYPE_DRV
489 && pTemplate->u.Drv.pDrvIns == pDrvIns)
490 {
491 PPDMASYNCCOMPLETIONTEMPLATE pTemplateDestroy = pTemplate;
492 pTemplate = pTemplate->pNext;
493 int rc = PDMR3AsyncCompletionTemplateDestroy(pTemplateDestroy);
494 if (RT_FAILURE(rc))
495 return rc;
496 }
497 else
498 pTemplate = pTemplate->pNext;
499 }
500
501 return VINF_SUCCESS;
502}
503
504/**
505 * Destroys all the specified async completion templates for the given USB device instance.
506 *
507 * @returns VBox status codes:
508 * @retval VINF_SUCCESS on success.
509 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
510 *
511 * @param pVM Pointer to the shared VM structure.
512 * @param pUsbIns The USB device instance.
513 */
514VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyUsb(PVM pVM, PPDMUSBINS pUsbIns)
515{
516 LogFlow(("%s: pUsbIns=%p\n", __FUNCTION__, pUsbIns));
517
518 /*
519 * Validate input.
520 */
521 if (!pUsbIns)
522 return VERR_INVALID_PARAMETER;
523 VM_ASSERT_EMT(pVM);
524
525 /*
526 * Unlink it.
527 */
528 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pVM->pdm.s.pAsyncCompletionTemplates;
529 while (pTemplate)
530 {
531 if ( pTemplate->enmType == PDMASYNCCOMPLETIONTEMPLATETYPE_USB
532 && pTemplate->u.Usb.pUsbIns == pUsbIns)
533 {
534 PPDMASYNCCOMPLETIONTEMPLATE pTemplateDestroy = pTemplate;
535 pTemplate = pTemplate->pNext;
536 int rc = PDMR3AsyncCompletionTemplateDestroy(pTemplateDestroy);
537 if (RT_FAILURE(rc))
538 return rc;
539 }
540 else
541 pTemplate = pTemplate->pNext;
542 }
543
544 return VINF_SUCCESS;
545}
546
547void pdmR3AsyncCompletionCompleteTask(PPDMASYNCCOMPLETIONTASK pTask, int rc, bool fCallCompletionHandler)
548{
549 LogFlow(("%s: pTask=%#p fCallCompletionHandler=%RTbool\n", __FUNCTION__, pTask, fCallCompletionHandler));
550
551 if (fCallCompletionHandler)
552 {
553 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pTask->pEndpoint->pTemplate;
554
555 switch (pTemplate->enmType)
556 {
557 case PDMASYNCCOMPLETIONTEMPLATETYPE_DEV:
558 {
559 pTemplate->u.Dev.pfnCompleted(pTemplate->u.Dev.pDevIns, pTask->pvUser, rc);
560 break;
561 }
562 case PDMASYNCCOMPLETIONTEMPLATETYPE_DRV:
563 {
564 pTemplate->u.Drv.pfnCompleted(pTemplate->u.Drv.pDrvIns, pTemplate->u.Drv.pvTemplateUser, pTask->pvUser, rc);
565 break;
566 }
567 case PDMASYNCCOMPLETIONTEMPLATETYPE_USB:
568 {
569 pTemplate->u.Usb.pfnCompleted(pTemplate->u.Usb.pUsbIns, pTask->pvUser, rc);
570 break;
571 }
572 case PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL:
573 {
574 pTemplate->u.Int.pfnCompleted(pTemplate->pVM, pTask->pvUser, pTemplate->u.Int.pvUser, rc);
575 break;
576 }
577 default:
578 AssertMsgFailed(("Unknown template type!\n"));
579 }
580 }
581
582 pdmR3AsyncCompletionPutTask(pTask->pEndpoint, pTask);
583}
584
585/**
586 * Worker initializing a endpoint class.
587 *
588 * @returns VBox statis code.
589 * @param pVM Pointer to the shared VM instance data.
590 * @param pEpClass Pointer to the endpoint class structure.
591 * @param pCfgHandle Pointer to the the CFGM tree.
592 */
593int pdmR3AsyncCompletionEpClassInit(PVM pVM, PCPDMASYNCCOMPLETIONEPCLASSOPS pEpClassOps, PCFGMNODE pCfgHandle)
594{
595 int rc = VINF_SUCCESS;
596
597 /* Validate input. */
598 if ( !pEpClassOps
599 || (pEpClassOps->u32Version != PDMAC_EPCLASS_OPS_VERSION)
600 || (pEpClassOps->u32VersionEnd != PDMAC_EPCLASS_OPS_VERSION))
601 AssertMsgFailedReturn(("Invalid endpoint class data\n"), VERR_VERSION_MISMATCH);
602
603 LogFlowFunc((": pVM=%p pEpClassOps=%p{%s}\n", pVM, pEpClassOps, pEpClassOps->pcszName));
604
605 /* Allocate global class data. */
606 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = NULL;
607
608 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION,
609 pEpClassOps->cbEndpointClassGlobal,
610 (void **)&pEndpointClass);
611 if (RT_SUCCESS(rc))
612 {
613 /* Initialize common data. */
614 pEndpointClass->pVM = pVM;
615 pEndpointClass->pEndpointOps = pEpClassOps;
616
617 rc = RTCritSectInit(&pEndpointClass->CritSect);
618 if (RT_SUCCESS(rc))
619 {
620 PCFGMNODE pCfgNodeClass = CFGMR3GetChild(pCfgHandle, pEpClassOps->pcszName);
621
622 /* Create task cache */
623 rc = RTMemCacheCreate(&pEndpointClass->hMemCacheTasks, pEpClassOps->cbTask,
624 0, UINT32_MAX, NULL, NULL, NULL, 0);
625 if (RT_SUCCESS(rc))
626 {
627 /* Call the specific endpoint class initializer. */
628 rc = pEpClassOps->pfnInitialize(pEndpointClass, pCfgNodeClass);
629 if (RT_SUCCESS(rc))
630 {
631 AssertMsg(!pVM->pdm.s.papAsyncCompletionEndpointClass[pEpClassOps->enmClassType],
632 ("Endpoint class was already initialized\n"));
633
634 pVM->pdm.s.papAsyncCompletionEndpointClass[pEpClassOps->enmClassType] = pEndpointClass;
635 LogFlowFunc((": Initialized endpoint class \"%s\" rc=%Rrc\n", pEpClassOps->pcszName, rc));
636 return VINF_SUCCESS;
637 }
638 RTMemCacheDestroy(pEndpointClass->hMemCacheTasks);
639 }
640 RTCritSectDelete(&pEndpointClass->CritSect);
641 }
642 MMR3HeapFree(pEndpointClass);
643 }
644
645 LogFlowFunc((": Failed to initialize endpoint class rc=%Rrc\n", rc));
646
647 return rc;
648}
649
650/**
651 * Worker terminating all endpoint classes.
652 *
653 * @returns nothing
654 * @param pEndpointClass Pointer to the endpoint class to terminate.
655 *
656 * @remarks This method ensures that any still open endpoint is closed.
657 */
658static void pdmR3AsyncCompletionEpClassTerminate(PPDMASYNCCOMPLETIONEPCLASS pEndpointClass)
659{
660 int rc = VINF_SUCCESS;
661 PVM pVM = pEndpointClass->pVM;
662
663 /* Close all still open endpoints. */
664 while (pEndpointClass->pEndpointsHead)
665 PDMR3AsyncCompletionEpClose(pEndpointClass->pEndpointsHead);
666
667 /* Call the termination callback of the class. */
668 pEndpointClass->pEndpointOps->pfnTerminate(pEndpointClass);
669
670 RTMemCacheDestroy(pEndpointClass->hMemCacheTasks);
671 RTCritSectDelete(&pEndpointClass->CritSect);
672
673 /* Free the memory of the class finally and clear the entry in the class array. */
674 pVM->pdm.s.papAsyncCompletionEndpointClass[pEndpointClass->pEndpointOps->enmClassType] = NULL;
675 MMR3HeapFree(pEndpointClass);
676}
677
678/**
679 * Initialize the async completion manager.
680 *
681 * @returns VBox status code
682 * @param pVM Pointer to the shared VM structure.
683 */
684int pdmR3AsyncCompletionInit(PVM pVM)
685{
686 int rc = VINF_SUCCESS;
687
688 LogFlowFunc((": pVM=%p\n", pVM));
689
690 VM_ASSERT_EMT(pVM);
691
692 do
693 {
694 /* Allocate array for global class data. */
695 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION,
696 sizeof(PPDMASYNCCOMPLETIONEPCLASS) * PDMASYNCCOMPLETIONEPCLASSTYPE_MAX,
697 (void **)&pVM->pdm.s.papAsyncCompletionEndpointClass);
698 if (RT_FAILURE(rc))
699 break;
700
701 PCFGMNODE pCfgRoot = CFGMR3GetRoot(pVM);
702 PCFGMNODE pCfgAsyncCompletion = CFGMR3GetChild(CFGMR3GetChild(pCfgRoot, "PDM"), "AsyncCompletion");
703
704 rc = pdmR3AsyncCompletionEpClassInit(pVM, &g_PDMAsyncCompletionEndpointClassFile, pCfgAsyncCompletion);
705 if (RT_FAILURE(rc))
706 break;
707
708 /* Put other classes here. */
709 } while (0);
710
711 LogFlowFunc((": pVM=%p rc=%Rrc\n", pVM, rc));
712
713 return rc;
714}
715
716/**
717 * Terminates the async completion manager.
718 *
719 * @returns VBox status code
720 * @param pVM Pointer to the shared VM structure.
721 */
722int pdmR3AsyncCompletionTerm(PVM pVM)
723{
724 LogFlowFunc((": pVM=%p\n", pVM));
725
726 if (pVM->pdm.s.papAsyncCompletionEndpointClass)
727 {
728 pdmR3AsyncCompletionEpClassTerminate(pVM->pdm.s.papAsyncCompletionEndpointClass[PDMASYNCCOMPLETIONEPCLASSTYPE_FILE]);
729 MMR3HeapFree(pVM->pdm.s.papAsyncCompletionEndpointClass);
730 }
731 return VINF_SUCCESS;
732}
733
734/**
735 * Tries to get a free task from the endpoint or class cache
736 * allocating the task if it fails.
737 *
738 * @returns Pointer to a new and initialized task or NULL
739 * @param pEndpoint The endpoint the task is for.
740 * @param pvUser Opaque user data for the task.
741 */
742static PPDMASYNCCOMPLETIONTASK pdmR3AsyncCompletionGetTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser)
743{
744 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
745 PPDMASYNCCOMPLETIONTASK pTask = NULL;
746
747 pTask = (PPDMASYNCCOMPLETIONTASK)RTMemCacheAlloc(pEndpointClass->hMemCacheTasks);
748
749 if (RT_LIKELY(pTask))
750 {
751 /* Get ID of the task. */
752 pTask->uTaskId = ASMAtomicIncU32(&pEndpoint->uTaskIdNext);
753
754 /* Initialize common parts. */
755 pTask->pvUser = pvUser;
756 pTask->pEndpoint = pEndpoint;
757 /* Clear list pointers for safety. */
758 pTask->pPrev = NULL;
759 pTask->pNext = NULL;
760#ifdef VBOX_WITH_STATISTICS
761 pTask->tsNsStart = RTTimeNanoTS();
762 STAM_COUNTER_INC(&pEndpoint->StatIoOpsStarted);
763#endif
764 }
765
766 return pTask;
767}
768
769/**
770 * Puts a task in one of the caches.
771 *
772 * @returns nothing.
773 * @param pEndpoint The endpoint the task belongs to.
774 * @param pTask The task to cache.
775 */
776static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask)
777{
778 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
779
780#ifdef VBOX_WITH_STATISTICS
781 uint64_t tsRun = RTTimeNanoTS() - pTask->tsNsStart;
782 uint64_t iStatIdx;
783
784 if (tsRun < 1000)
785 {
786 /* Update nanoseconds statistics */
787 iStatIdx = tsRun / 100;
788 STAM_COUNTER_INC(&pEndpoint->StatTaskRunTimesNs[iStatIdx]);
789 }
790 else
791 {
792 tsRun /= 1000;
793
794 if (tsRun < 1000)
795 {
796 /* Update microsecnds statistics */
797 iStatIdx = tsRun / 100;
798 STAM_COUNTER_INC(&pEndpoint->StatTaskRunTimesMicroSec[iStatIdx]);
799 }
800 else
801 {
802 tsRun /= 1000;
803
804 if (tsRun < 1000)
805 {
806 /* Update milliseconds statistics */
807 iStatIdx = tsRun / 100;
808 STAM_COUNTER_INC(&pEndpoint->StatTaskRunTimesMs[iStatIdx]);
809 }
810 else
811 {
812 tsRun /= 1000;
813
814 if (tsRun < 1000)
815 {
816 /* Update seconds statistics */
817 iStatIdx = tsRun / 10;
818 STAM_COUNTER_INC(&pEndpoint->StatTaskRunTimesSec[iStatIdx]);
819 }
820 else
821 STAM_COUNTER_INC(&pEndpoint->StatTaskRunOver100Sec);
822 }
823 }
824 }
825
826 STAM_COUNTER_INC(&pEndpoint->StatIoOpsCompleted);
827 pEndpoint->cIoOpsCompleted++;
828 uint64_t tsMsCur = RTTimeMilliTS();
829 uint64_t tsInterval = tsMsCur - pEndpoint->tsIntervalStartMs;
830
831 if (tsInterval >= 1000)
832 {
833 pEndpoint->StatIoOpsPerSec.c = pEndpoint->cIoOpsCompleted / (tsInterval / 1000);
834 pEndpoint->tsIntervalStartMs = tsMsCur;
835 pEndpoint->cIoOpsCompleted = 0;
836 }
837#endif
838
839 RTMemCacheFree(pEndpointClass->hMemCacheTasks, pTask);
840}
841
842static PPDMASYNCCOMPLETIONENDPOINT pdmR3AsyncCompletionFindEndpointWithUri(PPDMASYNCCOMPLETIONEPCLASS pEndpointClass,
843 const char *pszUri)
844{
845 PPDMASYNCCOMPLETIONENDPOINT pEndpoint = pEndpointClass->pEndpointsHead;
846
847 while (pEndpoint)
848 {
849 if (!RTStrCmp(pEndpoint->pszUri, pszUri))
850 return pEndpoint;
851
852 pEndpoint = pEndpoint->pNext;
853 }
854
855 return NULL;
856}
857
858VMMR3DECL(int) PDMR3AsyncCompletionEpCreateForFile(PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint,
859 const char *pszFilename, uint32_t fFlags,
860 PPDMASYNCCOMPLETIONTEMPLATE pTemplate)
861{
862 int rc = VINF_SUCCESS;
863
864 LogFlowFunc((": ppEndpoint=%p pszFilename=%p{%s} fFlags=%u pTemplate=%p\n",
865 ppEndpoint, pszFilename, pszFilename, fFlags, pTemplate));
866
867 /* Sanity checks. */
868 AssertReturn(VALID_PTR(ppEndpoint), VERR_INVALID_POINTER);
869 AssertReturn(VALID_PTR(pszFilename), VERR_INVALID_POINTER);
870 AssertReturn(VALID_PTR(pTemplate), VERR_INVALID_POINTER);
871
872 /* Check that the flags are valid. */
873 AssertReturn(((~(PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_CACHING) & fFlags) == 0),
874 VERR_INVALID_PARAMETER);
875
876 PVM pVM = pTemplate->pVM;
877 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pVM->pdm.s.papAsyncCompletionEndpointClass[PDMASYNCCOMPLETIONEPCLASSTYPE_FILE];
878 PPDMASYNCCOMPLETIONENDPOINT pEndpoint = NULL;
879
880 AssertMsg(pEndpointClass, ("File endpoint class was not initialized\n"));
881
882 /* Search for a already opened endpoint for this file. */
883 pEndpoint = pdmR3AsyncCompletionFindEndpointWithUri(pEndpointClass, pszFilename);
884
885 if(!pEndpoint)
886 {
887 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION,
888 pEndpointClass->pEndpointOps->cbEndpoint,
889 (void **)&pEndpoint);
890 if (RT_SUCCESS(rc))
891 {
892
893 /* Initialize common parts. */
894 pEndpoint->pNext = NULL;
895 pEndpoint->pPrev = NULL;
896 pEndpoint->pEpClass = pEndpointClass;
897 pEndpoint->uTaskIdNext = 0;
898 pEndpoint->fTaskIdWraparound = false;
899 pEndpoint->pTemplate = pTemplate;
900 pEndpoint->pszUri = RTStrDup(pszFilename);
901 pEndpoint->cUsers = 1;
902
903#ifdef VBOX_WITH_STATISTICS
904 /* Init the statistics part */
905 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesNs); i++)
906 {
907 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesNs[i], STAMTYPE_COUNTER,
908 STAMVISIBILITY_USED,
909 STAMUNIT_OCCURENCES,
910 "Nanosecond resolution runtime statistics",
911 "/PDM/AsyncCompletion/File/%s/TaskRun1Ns-%u-%u",
912 RTPathFilename(pEndpoint->pszUri),
913 i*100, i*100+100-1);
914 if (RT_FAILURE(rc))
915 break;
916 }
917
918 if (RT_SUCCESS(rc))
919 {
920 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMicroSec); i++)
921 {
922 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesMicroSec[i], STAMTYPE_COUNTER,
923 STAMVISIBILITY_USED,
924 STAMUNIT_OCCURENCES,
925 "Microsecond resolution runtime statistics",
926 "/PDM/AsyncCompletion/File/%s/TaskRun2MicroSec-%u-%u",
927 RTPathFilename(pEndpoint->pszUri),
928 i*100, i*100+100-1);
929 if (RT_FAILURE(rc))
930 break;
931 }
932 }
933
934 if (RT_SUCCESS(rc))
935 {
936 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs); i++)
937 {
938 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesMs[i], STAMTYPE_COUNTER,
939 STAMVISIBILITY_USED,
940 STAMUNIT_OCCURENCES,
941 "Milliseconds resolution runtime statistics",
942 "/PDM/AsyncCompletion/File/%s/TaskRun3Ms-%u-%u",
943 RTPathFilename(pEndpoint->pszUri),
944 i*100, i*100+100-1);
945 if (RT_FAILURE(rc))
946 break;
947 }
948 }
949
950 if (RT_SUCCESS(rc))
951 {
952 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs); i++)
953 {
954 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesSec[i], STAMTYPE_COUNTER,
955 STAMVISIBILITY_USED,
956 STAMUNIT_OCCURENCES,
957 "Second resolution runtime statistics",
958 "/PDM/AsyncCompletion/File/%s/TaskRun4Sec-%u-%u",
959 RTPathFilename(pEndpoint->pszUri),
960 i*10, i*10+10-1);
961 if (RT_FAILURE(rc))
962 break;
963 }
964 }
965
966 if (RT_SUCCESS(rc))
967 {
968 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunOver100Sec, STAMTYPE_COUNTER,
969 STAMVISIBILITY_USED,
970 STAMUNIT_OCCURENCES,
971 "Tasks which ran more than 100sec",
972 "/PDM/AsyncCompletion/File/%s/TaskRunSecGreater100Sec",
973 RTPathFilename(pEndpoint->pszUri));
974 }
975
976 if (RT_SUCCESS(rc))
977 {
978 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsPerSec, STAMTYPE_COUNTER,
979 STAMVISIBILITY_ALWAYS,
980 STAMUNIT_OCCURENCES,
981 "Processed I/O operations per second",
982 "/PDM/AsyncCompletion/File/%s/IoOpsPerSec",
983 RTPathFilename(pEndpoint->pszUri));
984 }
985
986 if (RT_SUCCESS(rc))
987 {
988 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsStarted, STAMTYPE_COUNTER,
989 STAMVISIBILITY_ALWAYS,
990 STAMUNIT_OCCURENCES,
991 "Started I/O operations for this endpoint",
992 "/PDM/AsyncCompletion/File/%s/IoOpsStarted",
993 RTPathFilename(pEndpoint->pszUri));
994 }
995
996 if (RT_SUCCESS(rc))
997 {
998 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsCompleted, STAMTYPE_COUNTER,
999 STAMVISIBILITY_ALWAYS,
1000 STAMUNIT_OCCURENCES,
1001 "Completed I/O operations for this endpoint",
1002 "/PDM/AsyncCompletion/File/%s/IoOpsCompleted",
1003 RTPathFilename(pEndpoint->pszUri));
1004 }
1005
1006 pEndpoint->tsIntervalStartMs = RTTimeMilliTS();
1007#endif
1008
1009 if ( pEndpoint->pszUri
1010 && RT_SUCCESS(rc))
1011 {
1012 /* Call the initializer for the endpoint. */
1013 rc = pEndpointClass->pEndpointOps->pfnEpInitialize(pEndpoint, pszFilename, fFlags);
1014 if (RT_SUCCESS(rc))
1015 {
1016 /* Link it into the list of endpoints. */
1017 rc = RTCritSectEnter(&pEndpointClass->CritSect);
1018 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1019
1020 pEndpoint->pNext = pEndpointClass->pEndpointsHead;
1021 if (pEndpointClass->pEndpointsHead)
1022 pEndpointClass->pEndpointsHead->pPrev = pEndpoint;
1023
1024 pEndpointClass->pEndpointsHead = pEndpoint;
1025 pEndpointClass->cEndpoints++;
1026
1027 rc = RTCritSectLeave(&pEndpointClass->CritSect);
1028 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1029
1030 /* Reference the template. */
1031 ASMAtomicIncU32(&pTemplate->cUsed);
1032
1033 *ppEndpoint = pEndpoint;
1034
1035 LogFlowFunc((": Created endpoint for %s: rc=%Rrc\n", pszFilename, rc));
1036 return VINF_SUCCESS;
1037 }
1038 RTStrFree(pEndpoint->pszUri);
1039 }
1040 MMR3HeapFree(pEndpoint);
1041 }
1042 }
1043 else
1044 {
1045 /* Endpoint found. */
1046 pEndpoint->cUsers++;
1047
1048 *ppEndpoint = pEndpoint;
1049 return VINF_SUCCESS;
1050 }
1051
1052 LogFlowFunc((": Creation of endpoint for %s failed: rc=%Rrc\n", pszFilename, rc));
1053
1054 return rc;
1055}
1056
1057VMMR3DECL(void) PDMR3AsyncCompletionEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
1058{
1059 LogFlowFunc((": pEndpoint=%p\n", pEndpoint));
1060
1061 /* Sanity checks. */
1062 AssertReturnVoid(VALID_PTR(pEndpoint));
1063
1064 pEndpoint->cUsers--;
1065
1066 /* If the last user closed the endpoint we will free it. */
1067 if (!pEndpoint->cUsers)
1068 {
1069 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
1070 pEndpointClass->pEndpointOps->pfnEpClose(pEndpoint);
1071
1072 /* Drop reference from the template. */
1073 ASMAtomicDecU32(&pEndpoint->pTemplate->cUsed);
1074
1075 /* Unlink the endpoint from the list. */
1076 int rc = RTCritSectEnter(&pEndpointClass->CritSect);
1077 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1078
1079 PPDMASYNCCOMPLETIONENDPOINT pEndpointNext = pEndpoint->pNext;
1080 PPDMASYNCCOMPLETIONENDPOINT pEndpointPrev = pEndpoint->pPrev;
1081
1082 if (pEndpointPrev)
1083 pEndpointPrev->pNext = pEndpointNext;
1084 else
1085 pEndpointClass->pEndpointsHead = pEndpointNext;
1086 if (pEndpointNext)
1087 pEndpointNext->pPrev = pEndpointPrev;
1088
1089 pEndpointClass->cEndpoints--;
1090
1091 rc = RTCritSectLeave(&pEndpointClass->CritSect);
1092 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1093
1094#ifdef VBOX_WITH_STATISTICS
1095 /* Deregister the statistics part */
1096 PVM pVM = pEndpointClass->pVM;
1097
1098 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesNs); i++)
1099 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunTimesNs[i]);
1100 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMicroSec); i++)
1101 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunTimesMicroSec[i]);
1102 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs); i++)
1103 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunTimesMs[i]);
1104 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs); i++)
1105 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunTimesSec[i]);
1106
1107 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunOver100Sec);
1108 STAMR3Deregister(pVM, &pEndpoint->StatIoOpsPerSec);
1109 STAMR3Deregister(pVM, &pEndpoint->StatIoOpsStarted);
1110 STAMR3Deregister(pVM, &pEndpoint->StatIoOpsCompleted);
1111#endif
1112
1113 RTStrFree(pEndpoint->pszUri);
1114 MMR3HeapFree(pEndpoint);
1115 }
1116}
1117
1118VMMR3DECL(int) PDMR3AsyncCompletionEpRead(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
1119 PCRTSGSEG paSegments, unsigned cSegments,
1120 size_t cbRead, void *pvUser,
1121 PPPDMASYNCCOMPLETIONTASK ppTask)
1122{
1123 int rc = VINF_SUCCESS;
1124
1125 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1126 AssertReturn(VALID_PTR(paSegments), VERR_INVALID_POINTER);
1127 AssertReturn(VALID_PTR(ppTask), VERR_INVALID_POINTER);
1128 AssertReturn(cSegments > 0, VERR_INVALID_PARAMETER);
1129 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
1130 AssertReturn(off >= 0, VERR_INVALID_PARAMETER);
1131
1132 PPDMASYNCCOMPLETIONTASK pTask;
1133
1134 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1135 if (!pTask)
1136 return VERR_NO_MEMORY;
1137
1138 rc = pEndpoint->pEpClass->pEndpointOps->pfnEpRead(pTask, pEndpoint, off,
1139 paSegments, cSegments, cbRead);
1140 if (RT_SUCCESS(rc))
1141 {
1142 *ppTask = pTask;
1143 }
1144 else
1145 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1146
1147 return rc;
1148}
1149
1150VMMR3DECL(int) PDMR3AsyncCompletionEpWrite(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
1151 PCRTSGSEG paSegments, unsigned cSegments,
1152 size_t cbWrite, void *pvUser,
1153 PPPDMASYNCCOMPLETIONTASK ppTask)
1154{
1155 int rc = VINF_SUCCESS;
1156
1157 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1158 AssertReturn(VALID_PTR(paSegments), VERR_INVALID_POINTER);
1159 AssertReturn(VALID_PTR(ppTask), VERR_INVALID_POINTER);
1160 AssertReturn(cSegments > 0, VERR_INVALID_PARAMETER);
1161 AssertReturn(cbWrite > 0, VERR_INVALID_PARAMETER);
1162 AssertReturn(off >= 0, VERR_INVALID_PARAMETER);
1163
1164 PPDMASYNCCOMPLETIONTASK pTask;
1165
1166 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1167 if (!pTask)
1168 return VERR_NO_MEMORY;
1169
1170 rc = pEndpoint->pEpClass->pEndpointOps->pfnEpWrite(pTask, pEndpoint, off,
1171 paSegments, cSegments, cbWrite);
1172 if (RT_SUCCESS(rc))
1173 {
1174 *ppTask = pTask;
1175 }
1176 else
1177 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1178
1179 return rc;
1180}
1181
1182VMMR3DECL(int) PDMR3AsyncCompletionEpFlush(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1183 void *pvUser,
1184 PPPDMASYNCCOMPLETIONTASK ppTask)
1185{
1186 int rc = VINF_SUCCESS;
1187
1188 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1189 AssertReturn(VALID_PTR(ppTask), VERR_INVALID_POINTER);
1190
1191 PPDMASYNCCOMPLETIONTASK pTask;
1192
1193 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1194 if (!pTask)
1195 return VERR_NO_MEMORY;
1196
1197 rc = pEndpoint->pEpClass->pEndpointOps->pfnEpFlush(pTask, pEndpoint);
1198 if (RT_SUCCESS(rc))
1199 {
1200 *ppTask = pTask;
1201 }
1202 else
1203 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1204
1205 return rc;
1206}
1207
1208VMMR3DECL(int) PDMR3AsyncCompletionEpGetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1209 uint64_t *pcbSize)
1210{
1211 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1212 AssertReturn(VALID_PTR(pcbSize), VERR_INVALID_POINTER);
1213
1214 if (pEndpoint->pEpClass->pEndpointOps->pfnEpGetSize)
1215 return pEndpoint->pEpClass->pEndpointOps->pfnEpGetSize(pEndpoint, pcbSize);
1216 else
1217 return VERR_NOT_SUPPORTED;
1218}
1219
1220VMMR3DECL(int) PDMR3AsyncCompletionEpSetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1221 uint64_t cbSize)
1222{
1223 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1224
1225 if (pEndpoint->pEpClass->pEndpointOps->pfnEpSetSize)
1226 return pEndpoint->pEpClass->pEndpointOps->pfnEpSetSize(pEndpoint, cbSize);
1227 else
1228 return VERR_NOT_SUPPORTED;
1229}
1230
1231VMMR3DECL(int) PDMR3AsyncCompletionTaskCancel(PPDMASYNCCOMPLETIONTASK pTask)
1232{
1233 return VERR_NOT_IMPLEMENTED;
1234}
1235
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