VirtualBox

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

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

PDMR3AsyncCompletionTemplateCreateDriver,PDMDRVHLP::pfnAsyncCompletionTemplateCreate: Don't require EMT, the list operations are locked.

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