VirtualBox

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

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

AsyncCompletion: More statistics

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