VirtualBox

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

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

PDM: Put pAsyncCompletionTemplates under the ListCritSect.

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