VirtualBox

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

Last change on this file since 28800 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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

© 2023 Oracle
ContactPrivacy policyTerms of Use