VirtualBox

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

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

AsyncCompletion: Log requests which take longer than 10 seconds

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.9 KB
Line 
1/* $Id: PDMAsyncCompletion.cpp 29496 2010-05-14 19:09:40Z 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 pTask->tsNsStart = RTTimeNanoTS();
769#ifdef VBOX_WITH_STATISTICS
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 uint64_t tsRun = RTTimeNanoTS() - pTask->tsNsStart;
788
789 if (RT_UNLIKELY(tsRun >= (uint64_t)10*1000*1000*1000))
790 {
791 LogRel(("AsyncCompletion: Task completed after %llu seconds\n", tsRun / ((uint64_t)1000*1000*1000)));
792 }
793
794#ifdef VBOX_WITH_STATISTICS
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.

© 2023 Oracle
ContactPrivacy policyTerms of Use