VirtualBox

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

Last change on this file since 61072 was 59261, checked in by vboxsync, 9 years ago

PDMAsyncCompletion: Don't return an already existing endpoint handle when a file is opened multiple times but create a new handle everytime, fixes a crash when an ISO images is attached multiple times to the same VM

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 66.1 KB
Line 
1/* $Id: PDMAsyncCompletion.cpp 59261 2016-01-06 11:32:38Z vboxsync $ */
2/** @file
3 * PDM Async I/O - Transport data asynchronous in R3 using EMT.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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/vmm/pdm.h>
25#include <VBox/vmm/mm.h>
26#ifdef VBOX_WITH_REM
27# include <VBox/vmm/rem.h>
28#endif
29#include <VBox/vmm/vm.h>
30#include <VBox/vmm/uvm.h>
31#include <VBox/err.h>
32
33#include <VBox/log.h>
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/thread.h>
37#include <iprt/mem.h>
38#include <iprt/critsect.h>
39#include <iprt/tcp.h>
40#include <iprt/path.h>
41#include <iprt/string.h>
42
43#include <VBox/vmm/pdmasynccompletion.h>
44#include "PDMAsyncCompletionInternal.h"
45
46
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50/**
51 * Async I/O type.
52 */
53typedef enum PDMASYNCCOMPLETIONTEMPLATETYPE
54{
55 /** Device . */
56 PDMASYNCCOMPLETIONTEMPLATETYPE_DEV = 1,
57 /** Driver consumer. */
58 PDMASYNCCOMPLETIONTEMPLATETYPE_DRV,
59 /** Internal consumer. */
60 PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL,
61 /** Usb consumer. */
62 PDMASYNCCOMPLETIONTEMPLATETYPE_USB
63} PDMASYNCTEMPLATETYPE;
64
65/**
66 * PDM Async I/O template.
67 */
68typedef struct PDMASYNCCOMPLETIONTEMPLATE
69{
70 /** Pointer to the next template in the list. */
71 R3PTRTYPE(PPDMASYNCCOMPLETIONTEMPLATE) pNext;
72 /** Pointer to the previous template in the list. */
73 R3PTRTYPE(PPDMASYNCCOMPLETIONTEMPLATE) pPrev;
74 /** Type specific data. */
75 union
76 {
77 /** PDMASYNCCOMPLETIONTEMPLATETYPE_DEV */
78 struct
79 {
80 /** Pointer to consumer function. */
81 R3PTRTYPE(PFNPDMASYNCCOMPLETEDEV) pfnCompleted;
82 /** Pointer to the device instance owning the template. */
83 R3PTRTYPE(PPDMDEVINS) pDevIns;
84 } Dev;
85 /** PDMASYNCCOMPLETIONTEMPLATETYPE_DRV */
86 struct
87 {
88 /** Pointer to consumer function. */
89 R3PTRTYPE(PFNPDMASYNCCOMPLETEDRV) pfnCompleted;
90 /** Pointer to the driver instance owning the template. */
91 R3PTRTYPE(PPDMDRVINS) pDrvIns;
92 /** User argument given during template creation.
93 * This is only here to make things much easier
94 * for DrVVD. */
95 void *pvTemplateUser;
96 } Drv;
97 /** PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL */
98 struct
99 {
100 /** Pointer to consumer function. */
101 R3PTRTYPE(PFNPDMASYNCCOMPLETEINT) pfnCompleted;
102 /** Pointer to user data. */
103 R3PTRTYPE(void *) pvUser;
104 } Int;
105 /** PDMASYNCCOMPLETIONTEMPLATETYPE_USB */
106 struct
107 {
108 /** Pointer to consumer function. */
109 R3PTRTYPE(PFNPDMASYNCCOMPLETEUSB) pfnCompleted;
110 /** Pointer to the usb instance owning the template. */
111 R3PTRTYPE(PPDMUSBINS) pUsbIns;
112 } Usb;
113 } u;
114 /** Template type. */
115 PDMASYNCCOMPLETIONTEMPLATETYPE enmType;
116 /** Pointer to the VM. */
117 R3PTRTYPE(PVM) pVM;
118 /** Use count of the template. */
119 volatile uint32_t cUsed;
120} PDMASYNCCOMPLETIONTEMPLATE;
121
122/**
123 * Bandwidth control manager instance data
124 */
125typedef struct PDMACBWMGR
126{
127 /** Pointer to the next manager in the list. */
128 struct PDMACBWMGR *pNext;
129 /** Pointer to the shared UVM structure. */
130 PPDMASYNCCOMPLETIONEPCLASS pEpClass;
131 /** Identifier of the manager. */
132 char *pszId;
133 /** Maximum number of bytes the endpoints are allowed to transfer (Max is 4GB/s currently) */
134 volatile uint32_t cbTransferPerSecMax;
135 /** Number of bytes we start with */
136 volatile uint32_t cbTransferPerSecStart;
137 /** Step after each update */
138 volatile uint32_t cbTransferPerSecStep;
139 /** Number of bytes we are allowed to transfer till the next update.
140 * Reset by the refresh timer. */
141 volatile uint32_t cbTransferAllowed;
142 /** Timestamp of the last update */
143 volatile uint64_t tsUpdatedLast;
144 /** Reference counter - How many endpoints are associated with this manager. */
145 volatile uint32_t cRefs;
146} PDMACBWMGR;
147/** Pointer to a bandwidth control manager pointer. */
148typedef PPDMACBWMGR *PPPDMACBWMGR;
149
150
151/*********************************************************************************************************************************
152* Internal Functions *
153*********************************************************************************************************************************/
154static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask);
155
156
157/**
158 * Internal worker for the creation apis
159 *
160 * @returns VBox status code.
161 * @param pVM The cross context VM structure.
162 * @param ppTemplate Where to store the template handle.
163 * @param enmType Async completion template type (dev, drv, usb, int).
164 */
165static int pdmR3AsyncCompletionTemplateCreate(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
166 PDMASYNCCOMPLETIONTEMPLATETYPE enmType)
167{
168 PUVM pUVM = pVM->pUVM;
169
170 AssertPtrReturn(ppTemplate, VERR_INVALID_POINTER);
171
172 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
173 int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION, sizeof(PDMASYNCCOMPLETIONTEMPLATE), (void **)&pTemplate);
174 if (RT_FAILURE(rc))
175 return rc;
176
177 /*
178 * Initialize fields.
179 */
180 pTemplate->pVM = pVM;
181 pTemplate->cUsed = 0;
182 pTemplate->enmType = enmType;
183
184 /*
185 * Add template to the global VM template list.
186 */
187 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
188 pTemplate->pNext = pUVM->pdm.s.pAsyncCompletionTemplates;
189 if (pUVM->pdm.s.pAsyncCompletionTemplates)
190 pUVM->pdm.s.pAsyncCompletionTemplates->pPrev = pTemplate;
191 pUVM->pdm.s.pAsyncCompletionTemplates = pTemplate;
192 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
193
194 *ppTemplate = pTemplate;
195 return VINF_SUCCESS;
196}
197
198
199#ifdef SOME_UNUSED_FUNCTION
200/**
201 * Creates a async completion template for a device instance.
202 *
203 * The template is used when creating new completion tasks.
204 *
205 * @returns VBox status code.
206 * @param pVM The cross context VM structure.
207 * @param pDevIns The device instance.
208 * @param ppTemplate Where to store the template pointer on success.
209 * @param pfnCompleted The completion callback routine.
210 * @param pszDesc Description.
211 */
212int pdmR3AsyncCompletionTemplateCreateDevice(PVM pVM, PPDMDEVINS pDevIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
213 PFNPDMASYNCCOMPLETEDEV pfnCompleted, const char *pszDesc)
214{
215 LogFlow(("%s: pDevIns=%p ppTemplate=%p pfnCompleted=%p pszDesc=%s\n",
216 __FUNCTION__, pDevIns, ppTemplate, pfnCompleted, pszDesc));
217
218 /*
219 * Validate input.
220 */
221 VM_ASSERT_EMT(pVM);
222 AssertPtrReturn(pfnCompleted, VERR_INVALID_POINTER);
223 AssertPtrReturn(ppTemplate, VERR_INVALID_POINTER);
224
225 /*
226 * Create the template.
227 */
228 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
229 int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_DEV);
230 if (RT_SUCCESS(rc))
231 {
232 pTemplate->u.Dev.pDevIns = pDevIns;
233 pTemplate->u.Dev.pfnCompleted = pfnCompleted;
234
235 *ppTemplate = pTemplate;
236 Log(("PDM: Created device template %p: pfnCompleted=%p pDevIns=%p\n",
237 pTemplate, pfnCompleted, pDevIns));
238 }
239
240 return rc;
241}
242#endif /* SOME_UNUSED_FUNCTION */
243
244
245/**
246 * Creates a async completion template for a driver instance.
247 *
248 * The template is used when creating new completion tasks.
249 *
250 * @returns VBox status code.
251 * @param pVM The cross context VM structure.
252 * @param pDrvIns The driver instance.
253 * @param ppTemplate Where to store the template pointer on success.
254 * @param pfnCompleted The completion callback routine.
255 * @param pvTemplateUser Template user argument
256 * @param pszDesc Description.
257 */
258int pdmR3AsyncCompletionTemplateCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
259 PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser,
260 const char *pszDesc)
261{
262 LogFlow(("PDMR3AsyncCompletionTemplateCreateDriver: pDrvIns=%p ppTemplate=%p pfnCompleted=%p pszDesc=%s\n", pDrvIns, ppTemplate, pfnCompleted, pszDesc));
263
264 /*
265 * Validate input.
266 */
267 AssertPtrReturn(pfnCompleted, VERR_INVALID_POINTER);
268 AssertPtrReturn(ppTemplate, VERR_INVALID_POINTER);
269
270 /*
271 * Create the template.
272 */
273 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
274 int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_DRV);
275 if (RT_SUCCESS(rc))
276 {
277 pTemplate->u.Drv.pDrvIns = pDrvIns;
278 pTemplate->u.Drv.pfnCompleted = pfnCompleted;
279 pTemplate->u.Drv.pvTemplateUser = pvTemplateUser;
280
281 *ppTemplate = pTemplate;
282 Log(("PDM: Created driver template %p: pfnCompleted=%p pDrvIns=%p\n",
283 pTemplate, pfnCompleted, pDrvIns));
284 }
285
286 return rc;
287}
288
289
290#ifdef SOME_UNUSED_FUNCTION
291/**
292 * Creates a async completion template for a USB device instance.
293 *
294 * The template is used when creating new completion tasks.
295 *
296 * @returns VBox status code.
297 * @param pVM The cross context VM structure.
298 * @param pUsbIns The USB device instance.
299 * @param ppTemplate Where to store the template pointer on success.
300 * @param pfnCompleted The completion callback routine.
301 * @param pszDesc Description.
302 */
303int pdmR3AsyncCompletionTemplateCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
304 PFNPDMASYNCCOMPLETEUSB pfnCompleted, const char *pszDesc)
305{
306 LogFlow(("pdmR3AsyncCompletionTemplateCreateUsb: pUsbIns=%p ppTemplate=%p pfnCompleted=%p pszDesc=%s\n", pUsbIns, ppTemplate, pfnCompleted, pszDesc));
307
308 /*
309 * Validate input.
310 */
311 VM_ASSERT_EMT(pVM);
312 AssertPtrReturn(pfnCompleted, VERR_INVALID_POINTER);
313 AssertPtrReturn(ppTemplate, VERR_INVALID_POINTER);
314
315 /*
316 * Create the template.
317 */
318 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
319 int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_USB);
320 if (RT_SUCCESS(rc))
321 {
322 pTemplate->u.Usb.pUsbIns = pUsbIns;
323 pTemplate->u.Usb.pfnCompleted = pfnCompleted;
324
325 *ppTemplate = pTemplate;
326 Log(("PDM: Created usb template %p: pfnCompleted=%p pDevIns=%p\n",
327 pTemplate, pfnCompleted, pUsbIns));
328 }
329
330 return rc;
331}
332#endif
333
334
335/**
336 * Creates a async completion template for internally by the VMM.
337 *
338 * The template is used when creating new completion tasks.
339 *
340 * @returns VBox status code.
341 * @param pVM The cross context VM structure.
342 * @param ppTemplate Where to store the template pointer on success.
343 * @param pfnCompleted The completion callback routine.
344 * @param pvUser2 The 2nd user argument for the callback.
345 * @param pszDesc Description.
346 * @internal
347 */
348VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateInternal(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEINT pfnCompleted, void *pvUser2, const char *pszDesc)
349{
350 LogFlow(("%s: ppTemplate=%p pfnCompleted=%p pvUser2=%p pszDesc=%s\n",
351 __FUNCTION__, ppTemplate, pfnCompleted, pvUser2, pszDesc));
352
353 /*
354 * Validate input.
355 */
356 VM_ASSERT_EMT(pVM);
357 AssertPtrReturn(pfnCompleted, VERR_INVALID_POINTER);
358 AssertPtrReturn(ppTemplate, VERR_INVALID_POINTER);
359
360 /*
361 * Create the template.
362 */
363 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
364 int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL);
365 if (RT_SUCCESS(rc))
366 {
367 pTemplate->u.Int.pvUser = pvUser2;
368 pTemplate->u.Int.pfnCompleted = pfnCompleted;
369
370 *ppTemplate = pTemplate;
371 Log(("PDM: Created internal template %p: pfnCompleted=%p pvUser2=%p\n",
372 pTemplate, pfnCompleted, pvUser2));
373 }
374
375 return rc;
376}
377
378
379/**
380 * Destroys the specified async completion template.
381 *
382 * @returns VBox status codes:
383 * @retval VINF_SUCCESS on success.
384 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if the template is still in use.
385 *
386 * @param pTemplate The template in question.
387 */
388VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroy(PPDMASYNCCOMPLETIONTEMPLATE pTemplate)
389{
390 LogFlow(("%s: pTemplate=%p\n", __FUNCTION__, pTemplate));
391
392 if (!pTemplate)
393 {
394 AssertMsgFailed(("pTemplate is NULL!\n"));
395 return VERR_INVALID_PARAMETER;
396 }
397
398 /*
399 * Check if the template is still used.
400 */
401 if (pTemplate->cUsed > 0)
402 {
403 AssertMsgFailed(("Template is still in use\n"));
404 return VERR_PDM_ASYNC_TEMPLATE_BUSY;
405 }
406
407 /*
408 * Unlink the template from the list.
409 */
410 PUVM pUVM = pTemplate->pVM->pUVM;
411 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
412
413 PPDMASYNCCOMPLETIONTEMPLATE pPrev = pTemplate->pPrev;
414 PPDMASYNCCOMPLETIONTEMPLATE pNext = pTemplate->pNext;
415
416 if (pPrev)
417 pPrev->pNext = pNext;
418 else
419 pUVM->pdm.s.pAsyncCompletionTemplates = pNext;
420
421 if (pNext)
422 pNext->pPrev = pPrev;
423
424 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
425
426 /*
427 * Free the template.
428 */
429 MMR3HeapFree(pTemplate);
430
431 return VINF_SUCCESS;
432}
433
434
435/**
436 * Destroys all the specified async completion templates for the given device instance.
437 *
438 * @returns VBox status codes:
439 * @retval VINF_SUCCESS on success.
440 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
441 *
442 * @param pVM The cross context VM structure.
443 * @param pDevIns The device instance.
444 */
445int pdmR3AsyncCompletionTemplateDestroyDevice(PVM pVM, PPDMDEVINS pDevIns)
446{
447 LogFlow(("pdmR3AsyncCompletionTemplateDestroyDevice: pDevIns=%p\n", pDevIns));
448
449 /*
450 * Validate input.
451 */
452 if (!pDevIns)
453 return VERR_INVALID_PARAMETER;
454 VM_ASSERT_EMT(pVM);
455
456 /*
457 * Unlink it.
458 */
459 PUVM pUVM = pVM->pUVM;
460 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
461 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pUVM->pdm.s.pAsyncCompletionTemplates;
462 while (pTemplate)
463 {
464 if ( pTemplate->enmType == PDMASYNCCOMPLETIONTEMPLATETYPE_DEV
465 && pTemplate->u.Dev.pDevIns == pDevIns)
466 {
467 PPDMASYNCCOMPLETIONTEMPLATE pTemplateDestroy = pTemplate;
468 pTemplate = pTemplate->pNext;
469 int rc = PDMR3AsyncCompletionTemplateDestroy(pTemplateDestroy);
470 if (RT_FAILURE(rc))
471 {
472 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
473 return rc;
474 }
475 }
476 else
477 pTemplate = pTemplate->pNext;
478 }
479
480 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
481 return VINF_SUCCESS;
482}
483
484
485/**
486 * Destroys all the specified async completion templates for the given driver instance.
487 *
488 * @returns VBox status codes:
489 * @retval VINF_SUCCESS on success.
490 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
491 *
492 * @param pVM The cross context VM structure.
493 * @param pDrvIns The driver instance.
494 */
495int pdmR3AsyncCompletionTemplateDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns)
496{
497 LogFlow(("pdmR3AsyncCompletionTemplateDestroyDriver: pDevIns=%p\n", pDrvIns));
498
499 /*
500 * Validate input.
501 */
502 if (!pDrvIns)
503 return VERR_INVALID_PARAMETER;
504 VM_ASSERT_EMT(pVM);
505
506 /*
507 * Unlink it.
508 */
509 PUVM pUVM = pVM->pUVM;
510 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
511 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pUVM->pdm.s.pAsyncCompletionTemplates;
512 while (pTemplate)
513 {
514 if ( pTemplate->enmType == PDMASYNCCOMPLETIONTEMPLATETYPE_DRV
515 && pTemplate->u.Drv.pDrvIns == pDrvIns)
516 {
517 PPDMASYNCCOMPLETIONTEMPLATE pTemplateDestroy = pTemplate;
518 pTemplate = pTemplate->pNext;
519 int rc = PDMR3AsyncCompletionTemplateDestroy(pTemplateDestroy);
520 if (RT_FAILURE(rc))
521 {
522 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
523 return rc;
524 }
525 }
526 else
527 pTemplate = pTemplate->pNext;
528 }
529
530 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
531 return VINF_SUCCESS;
532}
533
534
535/**
536 * Destroys all the specified async completion templates for the given USB device instance.
537 *
538 * @returns VBox status codes:
539 * @retval VINF_SUCCESS on success.
540 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
541 *
542 * @param pVM The cross context VM structure.
543 * @param pUsbIns The USB device instance.
544 */
545int pdmR3AsyncCompletionTemplateDestroyUsb(PVM pVM, PPDMUSBINS pUsbIns)
546{
547 LogFlow(("pdmR3AsyncCompletionTemplateDestroyUsb: pUsbIns=%p\n", pUsbIns));
548
549 /*
550 * Validate input.
551 */
552 if (!pUsbIns)
553 return VERR_INVALID_PARAMETER;
554 VM_ASSERT_EMT(pVM);
555
556 /*
557 * Unlink it.
558 */
559 PUVM pUVM = pVM->pUVM;
560 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
561 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pUVM->pdm.s.pAsyncCompletionTemplates;
562 while (pTemplate)
563 {
564 if ( pTemplate->enmType == PDMASYNCCOMPLETIONTEMPLATETYPE_USB
565 && pTemplate->u.Usb.pUsbIns == pUsbIns)
566 {
567 PPDMASYNCCOMPLETIONTEMPLATE pTemplateDestroy = pTemplate;
568 pTemplate = pTemplate->pNext;
569 int rc = PDMR3AsyncCompletionTemplateDestroy(pTemplateDestroy);
570 if (RT_FAILURE(rc))
571 {
572 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
573 return rc;
574 }
575 }
576 else
577 pTemplate = pTemplate->pNext;
578 }
579
580 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
581 return VINF_SUCCESS;
582}
583
584
585/** Lazy coder. */
586static PPDMACBWMGR pdmacBwMgrFindById(PPDMASYNCCOMPLETIONEPCLASS pEpClass, const char *pszId)
587{
588 PPDMACBWMGR pBwMgr = NULL;
589
590 if (pszId)
591 {
592 int rc = RTCritSectEnter(&pEpClass->CritSect); AssertRC(rc);
593
594 pBwMgr = pEpClass->pBwMgrsHead;
595 while ( pBwMgr
596 && RTStrCmp(pBwMgr->pszId, pszId))
597 pBwMgr = pBwMgr->pNext;
598
599 rc = RTCritSectLeave(&pEpClass->CritSect); AssertRC(rc);
600 }
601
602 return pBwMgr;
603}
604
605
606/** Lazy coder. */
607static void pdmacBwMgrLink(PPDMACBWMGR pBwMgr)
608{
609 PPDMASYNCCOMPLETIONEPCLASS pEpClass = pBwMgr->pEpClass;
610 int rc = RTCritSectEnter(&pEpClass->CritSect); AssertRC(rc);
611
612 pBwMgr->pNext = pEpClass->pBwMgrsHead;
613 pEpClass->pBwMgrsHead = pBwMgr;
614
615 rc = RTCritSectLeave(&pEpClass->CritSect); AssertRC(rc);
616}
617
618
619#ifdef SOME_UNUSED_FUNCTION
620/** Lazy coder. */
621static void pdmacBwMgrUnlink(PPDMACBWMGR pBwMgr)
622{
623 PPDMASYNCCOMPLETIONEPCLASS pEpClass = pBwMgr->pEpClass;
624 int rc = RTCritSectEnter(&pEpClass->CritSect); AssertRC(rc);
625
626 if (pBwMgr == pEpClass->pBwMgrsHead)
627 pEpClass->pBwMgrsHead = pBwMgr->pNext;
628 else
629 {
630 PPDMACBWMGR pPrev = pEpClass->pBwMgrsHead;
631 while ( pPrev
632 && pPrev->pNext != pBwMgr)
633 pPrev = pPrev->pNext;
634
635 AssertPtr(pPrev);
636 pPrev->pNext = pBwMgr->pNext;
637 }
638
639 rc = RTCritSectLeave(&pEpClass->CritSect); AssertRC(rc);
640}
641#endif /* SOME_UNUSED_FUNCTION */
642
643
644/** Lazy coder. */
645static int pdmacAsyncCompletionBwMgrCreate(PPDMASYNCCOMPLETIONEPCLASS pEpClass, const char *pszBwMgr, uint32_t cbTransferPerSecMax,
646 uint32_t cbTransferPerSecStart, uint32_t cbTransferPerSecStep)
647{
648 LogFlowFunc(("pEpClass=%#p pszBwMgr=%#p{%s} cbTransferPerSecMax=%u cbTransferPerSecStart=%u cbTransferPerSecStep=%u\n",
649 pEpClass, pszBwMgr, pszBwMgr, cbTransferPerSecMax, cbTransferPerSecStart, cbTransferPerSecStep));
650
651 AssertPtrReturn(pEpClass, VERR_INVALID_POINTER);
652 AssertPtrReturn(pszBwMgr, VERR_INVALID_POINTER);
653 AssertReturn(*pszBwMgr != '\0', VERR_INVALID_PARAMETER);
654
655 int rc;
656 PPDMACBWMGR pBwMgr = pdmacBwMgrFindById(pEpClass, pszBwMgr);
657 if (!pBwMgr)
658 {
659 rc = MMR3HeapAllocZEx(pEpClass->pVM, MM_TAG_PDM_ASYNC_COMPLETION,
660 sizeof(PDMACBWMGR),
661 (void **)&pBwMgr);
662 if (RT_SUCCESS(rc))
663 {
664 pBwMgr->pszId = RTStrDup(pszBwMgr);
665 if (pBwMgr->pszId)
666 {
667 pBwMgr->pEpClass = pEpClass;
668 pBwMgr->cRefs = 0;
669
670 /* Init I/O flow control. */
671 pBwMgr->cbTransferPerSecMax = cbTransferPerSecMax;
672 pBwMgr->cbTransferPerSecStart = cbTransferPerSecStart;
673 pBwMgr->cbTransferPerSecStep = cbTransferPerSecStep;
674
675 pBwMgr->cbTransferAllowed = pBwMgr->cbTransferPerSecStart;
676 pBwMgr->tsUpdatedLast = RTTimeSystemNanoTS();
677
678 pdmacBwMgrLink(pBwMgr);
679 rc = VINF_SUCCESS;
680 }
681 else
682 {
683 rc = VERR_NO_MEMORY;
684 MMR3HeapFree(pBwMgr);
685 }
686 }
687 }
688 else
689 rc = VERR_ALREADY_EXISTS;
690
691 LogFlowFunc(("returns rc=%Rrc\n", rc));
692 return rc;
693}
694
695
696/** Lazy coder. */
697DECLINLINE(void) pdmacBwMgrRetain(PPDMACBWMGR pBwMgr)
698{
699 ASMAtomicIncU32(&pBwMgr->cRefs);
700}
701
702
703/** Lazy coder. */
704DECLINLINE(void) pdmacBwMgrRelease(PPDMACBWMGR pBwMgr)
705{
706 Assert(pBwMgr->cRefs > 0);
707 ASMAtomicDecU32(&pBwMgr->cRefs);
708}
709
710
711/**
712 * Checks if the endpoint is allowed to transfer the given amount of bytes.
713 *
714 * @returns true if the endpoint is allowed to transfer the data.
715 * false otherwise
716 * @param pEndpoint The endpoint.
717 * @param cbTransfer The number of bytes to transfer.
718 * @param pmsWhenNext Where to store the number of milliseconds
719 * until the bandwidth is refreshed.
720 * Only set if false is returned.
721 */
722bool pdmacEpIsTransferAllowed(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint32_t cbTransfer, RTMSINTERVAL *pmsWhenNext)
723{
724 bool fAllowed = true;
725 PPDMACBWMGR pBwMgr = ASMAtomicReadPtrT(&pEndpoint->pBwMgr, PPDMACBWMGR);
726
727 LogFlowFunc(("pEndpoint=%p pBwMgr=%p cbTransfer=%u\n", pEndpoint, pBwMgr, cbTransfer));
728
729 if (pBwMgr)
730 {
731 uint32_t cbOld = ASMAtomicSubU32(&pBwMgr->cbTransferAllowed, cbTransfer);
732 if (RT_LIKELY(cbOld >= cbTransfer))
733 fAllowed = true;
734 else
735 {
736 fAllowed = false;
737
738 /* We are out of resources Check if we can update again. */
739 uint64_t tsNow = RTTimeSystemNanoTS();
740 uint64_t tsUpdatedLast = ASMAtomicUoReadU64(&pBwMgr->tsUpdatedLast);
741
742 if (tsNow - tsUpdatedLast >= (1000*1000*1000))
743 {
744 if (ASMAtomicCmpXchgU64(&pBwMgr->tsUpdatedLast, tsNow, tsUpdatedLast))
745 {
746 if (pBwMgr->cbTransferPerSecStart < pBwMgr->cbTransferPerSecMax)
747 {
748 pBwMgr->cbTransferPerSecStart = RT_MIN(pBwMgr->cbTransferPerSecMax, pBwMgr->cbTransferPerSecStart + pBwMgr->cbTransferPerSecStep);
749 LogFlow(("AIOMgr: Increasing maximum bandwidth to %u bytes/sec\n", pBwMgr->cbTransferPerSecStart));
750 }
751
752 /* Update */
753 ASMAtomicWriteU32(&pBwMgr->cbTransferAllowed, pBwMgr->cbTransferPerSecStart - cbTransfer);
754 fAllowed = true;
755 LogFlow(("AIOMgr: Refreshed bandwidth\n"));
756 }
757 }
758 else
759 {
760 ASMAtomicAddU32(&pBwMgr->cbTransferAllowed, cbTransfer);
761 *pmsWhenNext = ((1000*1000*1000) - (tsNow - tsUpdatedLast)) / (1000*1000);
762 }
763 }
764 }
765
766 LogFlowFunc(("fAllowed=%RTbool\n", fAllowed));
767 return fAllowed;
768}
769
770
771/**
772 * Called by the endpoint if a task has finished.
773 *
774 * @returns nothing
775 * @param pTask Pointer to the finished task.
776 * @param rc Status code of the completed request.
777 * @param fCallCompletionHandler Flag whether the completion handler should be called to
778 * inform the owner of the task that it has completed.
779 */
780void pdmR3AsyncCompletionCompleteTask(PPDMASYNCCOMPLETIONTASK pTask, int rc, bool fCallCompletionHandler)
781{
782 LogFlow(("%s: pTask=%#p fCallCompletionHandler=%RTbool\n", __FUNCTION__, pTask, fCallCompletionHandler));
783
784 if (fCallCompletionHandler)
785 {
786 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pTask->pEndpoint->pTemplate;
787
788 switch (pTemplate->enmType)
789 {
790 case PDMASYNCCOMPLETIONTEMPLATETYPE_DEV:
791 pTemplate->u.Dev.pfnCompleted(pTemplate->u.Dev.pDevIns, pTask->pvUser, rc);
792 break;
793
794 case PDMASYNCCOMPLETIONTEMPLATETYPE_DRV:
795 pTemplate->u.Drv.pfnCompleted(pTemplate->u.Drv.pDrvIns, pTemplate->u.Drv.pvTemplateUser, pTask->pvUser, rc);
796 break;
797
798 case PDMASYNCCOMPLETIONTEMPLATETYPE_USB:
799 pTemplate->u.Usb.pfnCompleted(pTemplate->u.Usb.pUsbIns, pTask->pvUser, rc);
800 break;
801
802 case PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL:
803 pTemplate->u.Int.pfnCompleted(pTemplate->pVM, pTask->pvUser, pTemplate->u.Int.pvUser, rc);
804 break;
805
806 default:
807 AssertMsgFailed(("Unknown template type!\n"));
808 }
809 }
810
811 pdmR3AsyncCompletionPutTask(pTask->pEndpoint, pTask);
812}
813
814
815/**
816 * Worker initializing a endpoint class.
817 *
818 * @returns VBox status code.
819 * @param pVM The cross context VM structure.
820 * @param pEpClassOps Pointer to the endpoint class structure.
821 * @param pCfgHandle Pointer to the CFGM tree.
822 */
823int pdmR3AsyncCompletionEpClassInit(PVM pVM, PCPDMASYNCCOMPLETIONEPCLASSOPS pEpClassOps, PCFGMNODE pCfgHandle)
824{
825 /* Validate input. */
826 AssertPtrReturn(pEpClassOps, VERR_INVALID_POINTER);
827 AssertReturn(pEpClassOps->u32Version == PDMAC_EPCLASS_OPS_VERSION, VERR_VERSION_MISMATCH);
828 AssertReturn(pEpClassOps->u32VersionEnd == PDMAC_EPCLASS_OPS_VERSION, VERR_VERSION_MISMATCH);
829
830 LogFlow(("pdmR3AsyncCompletionEpClassInit: pVM=%p pEpClassOps=%p{%s}\n", pVM, pEpClassOps, pEpClassOps->pszName));
831
832 /* Allocate global class data. */
833 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = NULL;
834
835 int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION,
836 pEpClassOps->cbEndpointClassGlobal,
837 (void **)&pEndpointClass);
838 if (RT_SUCCESS(rc))
839 {
840 /* Initialize common data. */
841 pEndpointClass->pVM = pVM;
842 pEndpointClass->pEndpointOps = pEpClassOps;
843
844 rc = RTCritSectInit(&pEndpointClass->CritSect);
845 if (RT_SUCCESS(rc))
846 {
847 PCFGMNODE pCfgNodeClass = CFGMR3GetChild(pCfgHandle, pEpClassOps->pszName);
848
849 /* Create task cache */
850 rc = RTMemCacheCreate(&pEndpointClass->hMemCacheTasks, pEpClassOps->cbTask,
851 0, UINT32_MAX, NULL, NULL, NULL, 0);
852 if (RT_SUCCESS(rc))
853 {
854 /* Call the specific endpoint class initializer. */
855 rc = pEpClassOps->pfnInitialize(pEndpointClass, pCfgNodeClass);
856 if (RT_SUCCESS(rc))
857 {
858 /* Create all bandwidth groups for resource control. */
859 PCFGMNODE pCfgBwGrp = CFGMR3GetChild(pCfgNodeClass, "BwGroups");
860
861 if (pCfgBwGrp)
862 {
863 for (PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgBwGrp); pCur; pCur = CFGMR3GetNextChild(pCur))
864 {
865 uint32_t cbMax, cbStart, cbStep;
866 size_t cchName = CFGMR3GetNameLen(pCur) + 1;
867 char *pszBwGrpId = (char *)RTMemAllocZ(cchName);
868
869 if (!pszBwGrpId)
870 {
871 rc = VERR_NO_MEMORY;
872 break;
873 }
874
875 rc = CFGMR3GetName(pCur, pszBwGrpId, cchName);
876 AssertRC(rc);
877
878 if (RT_SUCCESS(rc))
879 rc = CFGMR3QueryU32(pCur, "Max", &cbMax);
880 if (RT_SUCCESS(rc))
881 rc = CFGMR3QueryU32Def(pCur, "Start", &cbStart, cbMax);
882 if (RT_SUCCESS(rc))
883 rc = CFGMR3QueryU32Def(pCur, "Step", &cbStep, 0);
884 if (RT_SUCCESS(rc))
885 rc = pdmacAsyncCompletionBwMgrCreate(pEndpointClass, pszBwGrpId, cbMax, cbStart, cbStep);
886
887 RTMemFree(pszBwGrpId);
888
889 if (RT_FAILURE(rc))
890 break;
891 }
892 }
893
894 if (RT_SUCCESS(rc))
895 {
896 PUVM pUVM = pVM->pUVM;
897 AssertMsg(!pUVM->pdm.s.apAsyncCompletionEndpointClass[pEpClassOps->enmClassType],
898 ("Endpoint class was already initialized\n"));
899
900#ifdef VBOX_WITH_STATISTICS
901 CFGMR3QueryBoolDef(pCfgNodeClass, "AdvancedStatistics", &pEndpointClass->fGatherAdvancedStatistics, true);
902#else
903 CFGMR3QueryBoolDef(pCfgNodeClass, "AdvancedStatistics", &pEndpointClass->fGatherAdvancedStatistics, false);
904#endif
905
906 pUVM->pdm.s.apAsyncCompletionEndpointClass[pEpClassOps->enmClassType] = pEndpointClass;
907 LogFlowFunc((": Initialized endpoint class \"%s\" rc=%Rrc\n", pEpClassOps->pszName, rc));
908 return VINF_SUCCESS;
909 }
910 }
911 RTMemCacheDestroy(pEndpointClass->hMemCacheTasks);
912 }
913 RTCritSectDelete(&pEndpointClass->CritSect);
914 }
915 MMR3HeapFree(pEndpointClass);
916 }
917
918 LogFlowFunc((": Failed to initialize endpoint class rc=%Rrc\n", rc));
919
920 return rc;
921}
922
923
924/**
925 * Worker terminating all endpoint classes.
926 *
927 * @returns nothing
928 * @param pEndpointClass Pointer to the endpoint class to terminate.
929 *
930 * @remarks This method ensures that any still open endpoint is closed.
931 */
932static void pdmR3AsyncCompletionEpClassTerminate(PPDMASYNCCOMPLETIONEPCLASS pEndpointClass)
933{
934 PVM pVM = pEndpointClass->pVM;
935
936 /* Close all still open endpoints. */
937 while (pEndpointClass->pEndpointsHead)
938 PDMR3AsyncCompletionEpClose(pEndpointClass->pEndpointsHead);
939
940 /* Destroy the bandwidth managers. */
941 PPDMACBWMGR pBwMgr = pEndpointClass->pBwMgrsHead;
942 while (pBwMgr)
943 {
944 PPDMACBWMGR pFree = pBwMgr;
945 pBwMgr = pBwMgr->pNext;
946 MMR3HeapFree(pFree);
947 }
948
949 /* Call the termination callback of the class. */
950 pEndpointClass->pEndpointOps->pfnTerminate(pEndpointClass);
951
952 RTMemCacheDestroy(pEndpointClass->hMemCacheTasks);
953 RTCritSectDelete(&pEndpointClass->CritSect);
954
955 /* Free the memory of the class finally and clear the entry in the class array. */
956 pVM->pUVM->pdm.s.apAsyncCompletionEndpointClass[pEndpointClass->pEndpointOps->enmClassType] = NULL;
957 MMR3HeapFree(pEndpointClass);
958}
959
960
961/**
962 * Records the size of the request in the statistics.
963 *
964 * @returns nothing.
965 * @param pEndpoint The endpoint to register the request size for.
966 * @param cbReq Size of the request.
967 */
968static void pdmR3AsyncCompletionStatisticsRecordSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, size_t cbReq)
969{
970 if (cbReq < 512)
971 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSizeSmaller512);
972 else if (cbReq < _1K)
973 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize512To1K);
974 else if (cbReq < _2K)
975 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize1KTo2K);
976 else if (cbReq < _4K)
977 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize2KTo4K);
978 else if (cbReq < _8K)
979 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize4KTo8K);
980 else if (cbReq < _16K)
981 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize8KTo16K);
982 else if (cbReq < _32K)
983 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize16KTo32K);
984 else if (cbReq < _64K)
985 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize32KTo64K);
986 else if (cbReq < _128K)
987 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize64KTo128K);
988 else if (cbReq < _256K)
989 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize128KTo256K);
990 else if (cbReq < _512K)
991 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize256KTo512K);
992 else
993 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSizeOver512K);
994
995 if (cbReq & ((size_t)512 - 1))
996 STAM_REL_COUNTER_INC(&pEndpoint->StatReqsUnaligned512);
997 else if (cbReq & ((size_t)_4K - 1))
998 STAM_REL_COUNTER_INC(&pEndpoint->StatReqsUnaligned4K);
999 else if (cbReq & ((size_t)_8K - 1))
1000 STAM_REL_COUNTER_INC(&pEndpoint->StatReqsUnaligned8K);
1001}
1002
1003
1004/**
1005 * Records the required processing time of a request.
1006 *
1007 * @returns nothing.
1008 * @param pEndpoint The endpoint.
1009 * @param cNsRun The request time in nanoseconds.
1010 */
1011static void pdmR3AsyncCompletionStatisticsRecordCompletionTime(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cNsRun)
1012{
1013 PSTAMCOUNTER pStatCounter;
1014 if (cNsRun < RT_NS_1US)
1015 pStatCounter = &pEndpoint->StatTaskRunTimesNs[cNsRun / (RT_NS_1US / 10)];
1016 else if (cNsRun < RT_NS_1MS)
1017 pStatCounter = &pEndpoint->StatTaskRunTimesUs[cNsRun / (RT_NS_1MS / 10)];
1018 else if (cNsRun < RT_NS_1SEC)
1019 pStatCounter = &pEndpoint->StatTaskRunTimesMs[cNsRun / (RT_NS_1SEC / 10)];
1020 else if (cNsRun < RT_NS_1SEC_64*100)
1021 pStatCounter = &pEndpoint->StatTaskRunTimesSec[cNsRun / (RT_NS_1SEC_64*100 / 10)];
1022 else
1023 pStatCounter = &pEndpoint->StatTaskRunOver100Sec;
1024 STAM_REL_COUNTER_INC(pStatCounter);
1025
1026 STAM_REL_COUNTER_INC(&pEndpoint->StatIoOpsCompleted);
1027 pEndpoint->cIoOpsCompleted++;
1028 uint64_t tsMsCur = RTTimeMilliTS();
1029 uint64_t tsInterval = tsMsCur - pEndpoint->tsIntervalStartMs;
1030 if (tsInterval >= 1000)
1031 {
1032 pEndpoint->StatIoOpsPerSec.c = pEndpoint->cIoOpsCompleted / (tsInterval / 1000);
1033 pEndpoint->tsIntervalStartMs = tsMsCur;
1034 pEndpoint->cIoOpsCompleted = 0;
1035 }
1036}
1037
1038
1039/**
1040 * Registers advanced statistics for the given endpoint.
1041 *
1042 * @returns VBox status code.
1043 * @param pEndpoint The endpoint to register the advanced statistics for.
1044 */
1045static int pdmR3AsyncCompletionStatisticsRegister(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
1046{
1047 int rc = VINF_SUCCESS;
1048 PVM pVM = pEndpoint->pEpClass->pVM;
1049
1050 pEndpoint->tsIntervalStartMs = RTTimeMilliTS();
1051
1052 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesNs) && RT_SUCCESS(rc); i++)
1053 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesNs[i], STAMTYPE_COUNTER,
1054 STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1055 "Nanosecond resolution runtime statistics",
1056 "/PDM/AsyncCompletion/File/%s/%d/TaskRun1Ns-%u-%u",
1057 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId, i*100, i*100+100-1);
1058
1059 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesUs) && RT_SUCCESS(rc); i++)
1060 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesUs[i], STAMTYPE_COUNTER,
1061 STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1062 "Microsecond resolution runtime statistics",
1063 "/PDM/AsyncCompletion/File/%s/%d/TaskRun2MicroSec-%u-%u",
1064 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId, i*100, i*100+100-1);
1065
1066 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs) && RT_SUCCESS(rc); i++)
1067 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesMs[i], STAMTYPE_COUNTER,
1068 STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1069 "Milliseconds resolution runtime statistics",
1070 "/PDM/AsyncCompletion/File/%s/%d/TaskRun3Ms-%u-%u",
1071 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId, i*100, i*100+100-1);
1072
1073 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs) && RT_SUCCESS(rc); i++)
1074 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesSec[i], STAMTYPE_COUNTER,
1075 STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1076 "Second resolution runtime statistics",
1077 "/PDM/AsyncCompletion/File/%s/%d/TaskRun4Sec-%u-%u",
1078 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId, i*10, i*10+10-1);
1079
1080 if (RT_SUCCESS(rc))
1081 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunOver100Sec, STAMTYPE_COUNTER,
1082 STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1083 "Tasks which ran more than 100sec",
1084 "/PDM/AsyncCompletion/File/%s/%d/TaskRunSecGreater100Sec",
1085 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1086
1087 if (RT_SUCCESS(rc))
1088 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsPerSec, STAMTYPE_COUNTER,
1089 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1090 "Processed I/O operations per second",
1091 "/PDM/AsyncCompletion/File/%s/%d/IoOpsPerSec",
1092 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1093
1094 if (RT_SUCCESS(rc))
1095 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsStarted, STAMTYPE_COUNTER,
1096 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1097 "Started I/O operations for this endpoint",
1098 "/PDM/AsyncCompletion/File/%s/%d/IoOpsStarted",
1099 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1100
1101 if (RT_SUCCESS(rc))
1102 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsCompleted, STAMTYPE_COUNTER,
1103 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1104 "Completed I/O operations for this endpoint",
1105 "/PDM/AsyncCompletion/File/%s/%d/IoOpsCompleted",
1106 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1107
1108 if (RT_SUCCESS(rc))
1109 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSizeSmaller512, STAMTYPE_COUNTER,
1110 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1111 "Number of requests with a size smaller than 512 bytes",
1112 "/PDM/AsyncCompletion/File/%s/%d/ReqSizeSmaller512",
1113 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1114
1115 if (RT_SUCCESS(rc))
1116 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize512To1K, STAMTYPE_COUNTER,
1117 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1118 "Number of requests with a size between 512 bytes and 1KB",
1119 "/PDM/AsyncCompletion/File/%s/%d/ReqSize512To1K",
1120 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1121
1122 if (RT_SUCCESS(rc))
1123 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize1KTo2K, STAMTYPE_COUNTER,
1124 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1125 "Number of requests with a size between 1KB and 2KB",
1126 "/PDM/AsyncCompletion/File/%s/%d/ReqSize1KTo2K",
1127 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1128
1129 if (RT_SUCCESS(rc))
1130 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize2KTo4K, STAMTYPE_COUNTER,
1131 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1132 "Number of requests with a size between 2KB and 4KB",
1133 "/PDM/AsyncCompletion/File/%s/%d/ReqSize2KTo4K",
1134 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1135
1136 if (RT_SUCCESS(rc))
1137 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize4KTo8K, STAMTYPE_COUNTER,
1138 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1139 "Number of requests with a size between 4KB and 8KB",
1140 "/PDM/AsyncCompletion/File/%s/%d/ReqSize4KTo8K",
1141 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1142
1143 if (RT_SUCCESS(rc))
1144 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize8KTo16K, STAMTYPE_COUNTER,
1145 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1146 "Number of requests with a size between 8KB and 16KB",
1147 "/PDM/AsyncCompletion/File/%s/%d/ReqSize8KTo16K",
1148 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1149
1150 if (RT_SUCCESS(rc))
1151 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize16KTo32K, STAMTYPE_COUNTER,
1152 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1153 "Number of requests with a size between 16KB and 32KB",
1154 "/PDM/AsyncCompletion/File/%s/%d/ReqSize16KTo32K",
1155 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1156
1157 if (RT_SUCCESS(rc))
1158 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize32KTo64K, STAMTYPE_COUNTER,
1159 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1160 "Number of requests with a size between 32KB and 64KB",
1161 "/PDM/AsyncCompletion/File/%s/%d/ReqSize32KTo64K",
1162 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1163
1164 if (RT_SUCCESS(rc))
1165 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize64KTo128K, STAMTYPE_COUNTER,
1166 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1167 "Number of requests with a size between 64KB and 128KB",
1168 "/PDM/AsyncCompletion/File/%s/%d/ReqSize64KTo128K",
1169 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1170
1171 if (RT_SUCCESS(rc))
1172 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize128KTo256K, STAMTYPE_COUNTER,
1173 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1174 "Number of requests with a size between 128KB and 256KB",
1175 "/PDM/AsyncCompletion/File/%s/%d/ReqSize128KTo256K",
1176 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1177
1178 if (RT_SUCCESS(rc))
1179 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize256KTo512K, STAMTYPE_COUNTER,
1180 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1181 "Number of requests with a size between 256KB and 512KB",
1182 "/PDM/AsyncCompletion/File/%s/%d/ReqSize256KTo512K",
1183 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1184
1185 if (RT_SUCCESS(rc))
1186 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSizeOver512K, STAMTYPE_COUNTER,
1187 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1188 "Number of requests with a size over 512KB",
1189 "/PDM/AsyncCompletion/File/%s/%d/ReqSizeOver512K",
1190 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1191
1192 if (RT_SUCCESS(rc))
1193 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqsUnaligned512, STAMTYPE_COUNTER,
1194 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1195 "Number of requests which size is not aligned to 512 bytes",
1196 "/PDM/AsyncCompletion/File/%s/%d/ReqsUnaligned512",
1197 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1198
1199 if (RT_SUCCESS(rc))
1200 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqsUnaligned4K, STAMTYPE_COUNTER,
1201 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1202 "Number of requests which size is not aligned to 4KB",
1203 "/PDM/AsyncCompletion/File/%s/%d/ReqsUnaligned4K",
1204 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1205
1206 if (RT_SUCCESS(rc))
1207 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqsUnaligned8K, STAMTYPE_COUNTER,
1208 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1209 "Number of requests which size is not aligned to 8KB",
1210 "/PDM/AsyncCompletion/File/%s/%d/ReqsUnaligned8K",
1211 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1212
1213 return rc;
1214}
1215
1216
1217/**
1218 * Deregisters advanced statistics for one endpoint.
1219 *
1220 * @returns nothing.
1221 * @param pEndpoint The endpoint to deregister the advanced statistics for.
1222 */
1223static void pdmR3AsyncCompletionStatisticsDeregister(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
1224{
1225 /* I hope this doesn't remove too much... */
1226 STAMR3DeregisterF(pEndpoint->pEpClass->pVM->pUVM, "/PDM/AsyncCompletion/File/%s/*", RTPathFilename(pEndpoint->pszUri));
1227}
1228
1229
1230/**
1231 * Initialize the async completion manager.
1232 *
1233 * @returns VBox status code
1234 * @param pVM The cross context VM structure.
1235 */
1236int pdmR3AsyncCompletionInit(PVM pVM)
1237{
1238 LogFlowFunc((": pVM=%p\n", pVM));
1239
1240 VM_ASSERT_EMT(pVM);
1241
1242 PCFGMNODE pCfgRoot = CFGMR3GetRoot(pVM);
1243 PCFGMNODE pCfgAsyncCompletion = CFGMR3GetChild(CFGMR3GetChild(pCfgRoot, "PDM"), "AsyncCompletion");
1244
1245 int rc = pdmR3AsyncCompletionEpClassInit(pVM, &g_PDMAsyncCompletionEndpointClassFile, pCfgAsyncCompletion);
1246 LogFlowFunc((": pVM=%p rc=%Rrc\n", pVM, rc));
1247 return rc;
1248}
1249
1250
1251/**
1252 * Terminates the async completion manager.
1253 *
1254 * @returns VBox status code
1255 * @param pVM The cross context VM structure.
1256 */
1257int pdmR3AsyncCompletionTerm(PVM pVM)
1258{
1259 LogFlowFunc((": pVM=%p\n", pVM));
1260 PUVM pUVM = pVM->pUVM;
1261
1262 for (size_t i = 0; i < RT_ELEMENTS(pUVM->pdm.s.apAsyncCompletionEndpointClass); i++)
1263 if (pUVM->pdm.s.apAsyncCompletionEndpointClass[i])
1264 pdmR3AsyncCompletionEpClassTerminate(pUVM->pdm.s.apAsyncCompletionEndpointClass[i]);
1265
1266 return VINF_SUCCESS;
1267}
1268
1269
1270/**
1271 * Resume worker for the async completion manager.
1272 *
1273 * @returns nothing.
1274 * @param pVM The cross context VM structure.
1275 */
1276void pdmR3AsyncCompletionResume(PVM pVM)
1277{
1278 LogFlowFunc((": pVM=%p\n", pVM));
1279 PUVM pUVM = pVM->pUVM;
1280
1281 /* Log the bandwidth groups and all assigned endpoints. */
1282 for (size_t i = 0; i < RT_ELEMENTS(pUVM->pdm.s.apAsyncCompletionEndpointClass); i++)
1283 if (pUVM->pdm.s.apAsyncCompletionEndpointClass[i])
1284 {
1285 PPDMASYNCCOMPLETIONEPCLASS pEpClass = pUVM->pdm.s.apAsyncCompletionEndpointClass[i];
1286 PPDMACBWMGR pBwMgr = pEpClass->pBwMgrsHead;
1287 PPDMASYNCCOMPLETIONENDPOINT pEp;
1288
1289 if (pBwMgr)
1290 LogRel(("AIOMgr: Bandwidth groups for class '%s'\n", i == PDMASYNCCOMPLETIONEPCLASSTYPE_FILE
1291 ? "File" : "<Unknown>"));
1292
1293 while (pBwMgr)
1294 {
1295 LogRel(("AIOMgr: Id: %s\n", pBwMgr->pszId));
1296 LogRel(("AIOMgr: Max: %u B/s\n", pBwMgr->cbTransferPerSecMax));
1297 LogRel(("AIOMgr: Start: %u B/s\n", pBwMgr->cbTransferPerSecStart));
1298 LogRel(("AIOMgr: Step: %u B/s\n", pBwMgr->cbTransferPerSecStep));
1299 LogRel(("AIOMgr: Endpoints:\n"));
1300
1301 pEp = pEpClass->pEndpointsHead;
1302 while (pEp)
1303 {
1304 if (pEp->pBwMgr == pBwMgr)
1305 LogRel(("AIOMgr: %s\n", pEp->pszUri));
1306
1307 pEp = pEp->pNext;
1308 }
1309
1310 pBwMgr = pBwMgr->pNext;
1311 }
1312
1313 /* Print all endpoints without assigned bandwidth groups. */
1314 pEp = pEpClass->pEndpointsHead;
1315 if (pEp)
1316 LogRel(("AIOMgr: Endpoints without assigned bandwidth groups:\n"));
1317
1318 while (pEp)
1319 {
1320 if (!pEp->pBwMgr)
1321 LogRel(("AIOMgr: %s\n", pEp->pszUri));
1322
1323 pEp = pEp->pNext;
1324 }
1325 }
1326}
1327
1328
1329/**
1330 * Tries to get a free task from the endpoint or class cache
1331 * allocating the task if it fails.
1332 *
1333 * @returns Pointer to a new and initialized task or NULL
1334 * @param pEndpoint The endpoint the task is for.
1335 * @param pvUser Opaque user data for the task.
1336 */
1337static PPDMASYNCCOMPLETIONTASK pdmR3AsyncCompletionGetTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser)
1338{
1339 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
1340 PPDMASYNCCOMPLETIONTASK pTask = (PPDMASYNCCOMPLETIONTASK)RTMemCacheAlloc(pEndpointClass->hMemCacheTasks);
1341 if (RT_LIKELY(pTask))
1342 {
1343 /* Initialize common parts. */
1344 pTask->pvUser = pvUser;
1345 pTask->pEndpoint = pEndpoint;
1346 /* Clear list pointers for safety. */
1347 pTask->pPrev = NULL;
1348 pTask->pNext = NULL;
1349 pTask->tsNsStart = RTTimeNanoTS();
1350 STAM_REL_COUNTER_INC(&pEndpoint->StatIoOpsStarted);
1351 }
1352
1353 return pTask;
1354}
1355
1356
1357/**
1358 * Puts a task in one of the caches.
1359 *
1360 * @returns nothing.
1361 * @param pEndpoint The endpoint the task belongs to.
1362 * @param pTask The task to cache.
1363 */
1364static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask)
1365{
1366 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
1367 uint64_t cNsRun = RTTimeNanoTS() - pTask->tsNsStart;
1368
1369 if (RT_UNLIKELY(cNsRun >= RT_NS_10SEC))
1370 LogRel(("AsyncCompletion: Task %#p completed after %llu seconds\n", pTask, cNsRun / RT_NS_1SEC));
1371
1372 if (pEndpointClass->fGatherAdvancedStatistics)
1373 pdmR3AsyncCompletionStatisticsRecordCompletionTime(pEndpoint, cNsRun);
1374
1375 RTMemCacheFree(pEndpointClass->hMemCacheTasks, pTask);
1376}
1377
1378
1379static unsigned
1380pdmR3AsyncCompletionGetStatId(PPDMASYNCCOMPLETIONEPCLASS pEndpointClass, const char *pszUri)
1381{
1382 PPDMASYNCCOMPLETIONENDPOINT pEndpoint = pEndpointClass->pEndpointsHead;
1383 const char *pszFilename = RTPathFilename(pszUri);
1384 unsigned iStatId = 0;
1385
1386 while (pEndpoint)
1387 {
1388 if ( !RTStrCmp(RTPathFilename(pEndpoint->pszUri), pszFilename)
1389 && pEndpoint->iStatId >= iStatId)
1390 iStatId = pEndpoint->iStatId + 1;
1391
1392 pEndpoint = pEndpoint->pNext;
1393 }
1394
1395 return iStatId;
1396}
1397
1398/**
1399 * Opens a file as an async completion endpoint.
1400 *
1401 * @returns VBox status code.
1402 * @param ppEndpoint Where to store the opaque endpoint handle on success.
1403 * @param pszFilename Path to the file which is to be opened. (UTF-8)
1404 * @param fFlags Open flags, see grp_pdmacep_file_flags.
1405 * @param pTemplate Handle to the completion callback template to use
1406 * for this end point.
1407 */
1408VMMR3DECL(int) PDMR3AsyncCompletionEpCreateForFile(PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint,
1409 const char *pszFilename, uint32_t fFlags,
1410 PPDMASYNCCOMPLETIONTEMPLATE pTemplate)
1411{
1412 LogFlowFunc((": ppEndpoint=%p pszFilename=%p{%s} fFlags=%u pTemplate=%p\n",
1413 ppEndpoint, pszFilename, pszFilename, fFlags, pTemplate));
1414
1415 /* Sanity checks. */
1416 AssertPtrReturn(ppEndpoint, VERR_INVALID_POINTER);
1417 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1418 AssertPtrReturn(pTemplate, VERR_INVALID_POINTER);
1419
1420 /* Check that the flags are valid. */
1421 AssertReturn(((~(PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_DONT_LOCK | PDMACEP_FILE_FLAGS_HOST_CACHE_ENABLED) & fFlags) == 0),
1422 VERR_INVALID_PARAMETER);
1423
1424 PVM pVM = pTemplate->pVM;
1425 PUVM pUVM = pVM->pUVM;
1426 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pUVM->pdm.s.apAsyncCompletionEndpointClass[PDMASYNCCOMPLETIONEPCLASSTYPE_FILE];
1427 PPDMASYNCCOMPLETIONENDPOINT pEndpoint = NULL;
1428
1429 AssertMsg(pEndpointClass, ("File endpoint class was not initialized\n"));
1430
1431 /* Create an endpoint. */
1432 int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION,
1433 pEndpointClass->pEndpointOps->cbEndpoint,
1434 (void **)&pEndpoint);
1435 if (RT_SUCCESS(rc))
1436 {
1437 /* Initialize common parts. */
1438 pEndpoint->pNext = NULL;
1439 pEndpoint->pPrev = NULL;
1440 pEndpoint->pEpClass = pEndpointClass;
1441 pEndpoint->pTemplate = pTemplate;
1442 pEndpoint->pszUri = RTStrDup(pszFilename);
1443 pEndpoint->iStatId = pdmR3AsyncCompletionGetStatId(pEndpointClass, pszFilename);
1444 pEndpoint->pBwMgr = NULL;
1445
1446 if ( pEndpoint->pszUri
1447 && RT_SUCCESS(rc))
1448 {
1449 /* Call the initializer for the endpoint. */
1450 rc = pEndpointClass->pEndpointOps->pfnEpInitialize(pEndpoint, pszFilename, fFlags);
1451 if (RT_SUCCESS(rc))
1452 {
1453 if (pEndpointClass->fGatherAdvancedStatistics)
1454 rc = pdmR3AsyncCompletionStatisticsRegister(pEndpoint);
1455
1456 if (RT_SUCCESS(rc))
1457 {
1458 /* Link it into the list of endpoints. */
1459 rc = RTCritSectEnter(&pEndpointClass->CritSect);
1460 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1461
1462 pEndpoint->pNext = pEndpointClass->pEndpointsHead;
1463 if (pEndpointClass->pEndpointsHead)
1464 pEndpointClass->pEndpointsHead->pPrev = pEndpoint;
1465
1466 pEndpointClass->pEndpointsHead = pEndpoint;
1467 pEndpointClass->cEndpoints++;
1468
1469 rc = RTCritSectLeave(&pEndpointClass->CritSect);
1470 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1471
1472 /* Reference the template. */
1473 ASMAtomicIncU32(&pTemplate->cUsed);
1474
1475 *ppEndpoint = pEndpoint;
1476 LogFlowFunc((": Created endpoint for %s\n", pszFilename));
1477 return VINF_SUCCESS;
1478 }
1479 else
1480 pEndpointClass->pEndpointOps->pfnEpClose(pEndpoint);
1481
1482 if (pEndpointClass->fGatherAdvancedStatistics)
1483 pdmR3AsyncCompletionStatisticsDeregister(pEndpoint);
1484 }
1485 RTStrFree(pEndpoint->pszUri);
1486 }
1487 MMR3HeapFree(pEndpoint);
1488 }
1489
1490 LogFlowFunc((": Creation of endpoint for %s failed: rc=%Rrc\n", pszFilename, rc));
1491 return rc;
1492}
1493
1494
1495/**
1496 * Closes a endpoint waiting for any pending tasks to finish.
1497 *
1498 * @returns nothing.
1499 * @param pEndpoint Handle of the endpoint.
1500 */
1501VMMR3DECL(void) PDMR3AsyncCompletionEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
1502{
1503 LogFlowFunc((": pEndpoint=%p\n", pEndpoint));
1504
1505 /* Sanity checks. */
1506 AssertReturnVoid(VALID_PTR(pEndpoint));
1507
1508 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
1509 PVM pVM = pEndpointClass->pVM;
1510
1511 pEndpointClass->pEndpointOps->pfnEpClose(pEndpoint);
1512
1513 /* Drop reference from the template. */
1514 ASMAtomicDecU32(&pEndpoint->pTemplate->cUsed);
1515
1516 /* Unlink the endpoint from the list. */
1517 int rc = RTCritSectEnter(&pEndpointClass->CritSect);
1518 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1519
1520 PPDMASYNCCOMPLETIONENDPOINT pEndpointNext = pEndpoint->pNext;
1521 PPDMASYNCCOMPLETIONENDPOINT pEndpointPrev = pEndpoint->pPrev;
1522
1523 if (pEndpointPrev)
1524 pEndpointPrev->pNext = pEndpointNext;
1525 else
1526 pEndpointClass->pEndpointsHead = pEndpointNext;
1527 if (pEndpointNext)
1528 pEndpointNext->pPrev = pEndpointPrev;
1529
1530 pEndpointClass->cEndpoints--;
1531
1532 rc = RTCritSectLeave(&pEndpointClass->CritSect);
1533 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1534
1535 if (pEndpointClass->fGatherAdvancedStatistics)
1536 pdmR3AsyncCompletionStatisticsDeregister(pEndpoint);
1537
1538 RTStrFree(pEndpoint->pszUri);
1539 MMR3HeapFree(pEndpoint);
1540}
1541
1542
1543/**
1544 * Creates a read task on the given endpoint.
1545 *
1546 * @returns VBox status code.
1547 * @param pEndpoint The file endpoint to read from.
1548 * @param off Where to start reading from.
1549 * @param paSegments Scatter gather list to store the data in.
1550 * @param cSegments Number of segments in the list.
1551 * @param cbRead The overall number of bytes to read.
1552 * @param pvUser Opaque user data returned in the completion callback
1553 * upon completion of the task.
1554 * @param ppTask Where to store the task handle on success.
1555 */
1556VMMR3DECL(int) PDMR3AsyncCompletionEpRead(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
1557 PCRTSGSEG paSegments, unsigned cSegments,
1558 size_t cbRead, void *pvUser,
1559 PPPDMASYNCCOMPLETIONTASK ppTask)
1560{
1561 AssertPtrReturn(pEndpoint, VERR_INVALID_POINTER);
1562 AssertPtrReturn(paSegments, VERR_INVALID_POINTER);
1563 AssertPtrReturn(ppTask, VERR_INVALID_POINTER);
1564 AssertReturn(cSegments > 0, VERR_INVALID_PARAMETER);
1565 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
1566 AssertReturn(off >= 0, VERR_INVALID_PARAMETER);
1567
1568 PPDMASYNCCOMPLETIONTASK pTask;
1569
1570 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1571 if (!pTask)
1572 return VERR_NO_MEMORY;
1573
1574 int rc = pEndpoint->pEpClass->pEndpointOps->pfnEpRead(pTask, pEndpoint, off,
1575 paSegments, cSegments, cbRead);
1576 if (RT_SUCCESS(rc))
1577 {
1578 if (pEndpoint->pEpClass->fGatherAdvancedStatistics)
1579 pdmR3AsyncCompletionStatisticsRecordSize(pEndpoint, cbRead);
1580
1581 *ppTask = pTask;
1582 }
1583 else
1584 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1585
1586 return rc;
1587}
1588
1589
1590/**
1591 * Creates a write task on the given endpoint.
1592 *
1593 * @returns VBox status code.
1594 * @param pEndpoint The file endpoint to write to.
1595 * @param off Where to start writing at.
1596 * @param paSegments Scatter gather list of the data to write.
1597 * @param cSegments Number of segments in the list.
1598 * @param cbWrite The overall number of bytes to write.
1599 * @param pvUser Opaque user data returned in the completion callback
1600 * upon completion of the task.
1601 * @param ppTask Where to store the task handle on success.
1602 */
1603VMMR3DECL(int) PDMR3AsyncCompletionEpWrite(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
1604 PCRTSGSEG paSegments, unsigned cSegments,
1605 size_t cbWrite, void *pvUser,
1606 PPPDMASYNCCOMPLETIONTASK ppTask)
1607{
1608 AssertPtrReturn(pEndpoint, VERR_INVALID_POINTER);
1609 AssertPtrReturn(paSegments, VERR_INVALID_POINTER);
1610 AssertPtrReturn(ppTask, VERR_INVALID_POINTER);
1611 AssertReturn(cSegments > 0, VERR_INVALID_PARAMETER);
1612 AssertReturn(cbWrite > 0, VERR_INVALID_PARAMETER);
1613 AssertReturn(off >= 0, VERR_INVALID_PARAMETER);
1614
1615 PPDMASYNCCOMPLETIONTASK pTask;
1616
1617 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1618 if (!pTask)
1619 return VERR_NO_MEMORY;
1620
1621 int rc = pEndpoint->pEpClass->pEndpointOps->pfnEpWrite(pTask, pEndpoint, off,
1622 paSegments, cSegments, cbWrite);
1623 if (RT_SUCCESS(rc))
1624 {
1625 if (pEndpoint->pEpClass->fGatherAdvancedStatistics)
1626 pdmR3AsyncCompletionStatisticsRecordSize(pEndpoint, cbWrite);
1627
1628 *ppTask = pTask;
1629 }
1630 else
1631 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1632
1633 return rc;
1634}
1635
1636
1637/**
1638 * Creates a flush task on the given endpoint.
1639 *
1640 * Every read and write task initiated before the flush task is
1641 * finished upon completion of this task.
1642 *
1643 * @returns VBox status code.
1644 * @param pEndpoint The file endpoint to flush.
1645 * @param pvUser Opaque user data returned in the completion callback
1646 * upon completion of the task.
1647 * @param ppTask Where to store the task handle on success.
1648 */
1649VMMR3DECL(int) PDMR3AsyncCompletionEpFlush(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser, PPPDMASYNCCOMPLETIONTASK ppTask)
1650{
1651 AssertPtrReturn(pEndpoint, VERR_INVALID_POINTER);
1652 AssertPtrReturn(ppTask, VERR_INVALID_POINTER);
1653
1654 PPDMASYNCCOMPLETIONTASK pTask;
1655
1656 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1657 if (!pTask)
1658 return VERR_NO_MEMORY;
1659
1660 int rc = pEndpoint->pEpClass->pEndpointOps->pfnEpFlush(pTask, pEndpoint);
1661 if (RT_SUCCESS(rc))
1662 *ppTask = pTask;
1663 else
1664 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1665
1666 return rc;
1667}
1668
1669
1670/**
1671 * Queries the size of an endpoint.
1672 *
1673 * Not that some endpoints may not support this and will return an error
1674 * (sockets for example).
1675 *
1676 * @returns VBox status code.
1677 * @retval VERR_NOT_SUPPORTED if the endpoint does not support this operation.
1678 * @param pEndpoint The file endpoint.
1679 * @param pcbSize Where to store the size of the endpoint.
1680 */
1681VMMR3DECL(int) PDMR3AsyncCompletionEpGetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1682 uint64_t *pcbSize)
1683{
1684 AssertPtrReturn(pEndpoint, VERR_INVALID_POINTER);
1685 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1686
1687 if (pEndpoint->pEpClass->pEndpointOps->pfnEpGetSize)
1688 return pEndpoint->pEpClass->pEndpointOps->pfnEpGetSize(pEndpoint, pcbSize);
1689 return VERR_NOT_SUPPORTED;
1690}
1691
1692
1693/**
1694 * Sets the size of an endpoint.
1695 *
1696 * Not that some endpoints may not support this and will return an error
1697 * (sockets for example).
1698 *
1699 * @returns VBox status code.
1700 * @retval VERR_NOT_SUPPORTED if the endpoint does not support this operation.
1701 * @param pEndpoint The file endpoint.
1702 * @param cbSize The size to set.
1703 *
1704 * @note PDMR3AsyncCompletionEpFlush should be called before this operation is executed.
1705 */
1706VMMR3DECL(int) PDMR3AsyncCompletionEpSetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize)
1707{
1708 AssertPtrReturn(pEndpoint, VERR_INVALID_POINTER);
1709
1710 if (pEndpoint->pEpClass->pEndpointOps->pfnEpSetSize)
1711 return pEndpoint->pEpClass->pEndpointOps->pfnEpSetSize(pEndpoint, cbSize);
1712 return VERR_NOT_SUPPORTED;
1713}
1714
1715
1716/**
1717 * Assigns or removes a bandwidth control manager to/from the endpoint.
1718 *
1719 * @returns VBox status code.
1720 * @param pEndpoint The endpoint.
1721 * @param pszBwMgr The identifer of the new bandwidth manager to assign
1722 * or NULL to remove the current one.
1723 */
1724VMMR3DECL(int) PDMR3AsyncCompletionEpSetBwMgr(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr)
1725{
1726 AssertPtrReturn(pEndpoint, VERR_INVALID_POINTER);
1727 PPDMACBWMGR pBwMgrOld = NULL;
1728 PPDMACBWMGR pBwMgrNew = NULL;
1729
1730 int rc = VINF_SUCCESS;
1731 if (pszBwMgr)
1732 {
1733 pBwMgrNew = pdmacBwMgrFindById(pEndpoint->pEpClass, pszBwMgr);
1734 if (pBwMgrNew)
1735 pdmacBwMgrRetain(pBwMgrNew);
1736 else
1737 rc = VERR_NOT_FOUND;
1738 }
1739
1740 if (RT_SUCCESS(rc))
1741 {
1742 pBwMgrOld = ASMAtomicXchgPtrT(&pEndpoint->pBwMgr, pBwMgrNew, PPDMACBWMGR);
1743 if (pBwMgrOld)
1744 pdmacBwMgrRelease(pBwMgrOld);
1745 }
1746
1747 return rc;
1748}
1749
1750
1751/**
1752 * Cancels an async completion task.
1753 *
1754 * If you want to use this method, you have to take great create to make sure
1755 * you will never attempt cancel a task which has been completed. Since there is
1756 * no reference counting or anything on the task it self, you have to serialize
1757 * the cancelation and completion paths such that the aren't racing one another.
1758 *
1759 * @returns VBox status code
1760 * @param pTask The Task to cancel.
1761 */
1762VMMR3DECL(int) PDMR3AsyncCompletionTaskCancel(PPDMASYNCCOMPLETIONTASK pTask)
1763{
1764 NOREF(pTask);
1765 return VERR_NOT_IMPLEMENTED;
1766}
1767
1768
1769/**
1770 * Changes the limit of a bandwidth manager for file endpoints to the given value.
1771 *
1772 * @returns VBox status code.
1773 * @param pUVM The user mode VM handle.
1774 * @param pszBwMgr The identifer of the bandwidth manager to change.
1775 * @param cbMaxNew The new maximum for the bandwidth manager in bytes/sec.
1776 */
1777VMMR3DECL(int) PDMR3AsyncCompletionBwMgrSetMaxForFile(PUVM pUVM, const char *pszBwMgr, uint32_t cbMaxNew)
1778{
1779 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1780 PVM pVM = pUVM->pVM;
1781 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1782 AssertPtrReturn(pszBwMgr, VERR_INVALID_POINTER);
1783
1784 int rc = VINF_SUCCESS;
1785 PPDMASYNCCOMPLETIONEPCLASS pEpClass = pVM->pUVM->pdm.s.apAsyncCompletionEndpointClass[PDMASYNCCOMPLETIONEPCLASSTYPE_FILE];
1786 PPDMACBWMGR pBwMgr = pdmacBwMgrFindById(pEpClass, pszBwMgr);
1787 if (pBwMgr)
1788 {
1789 /*
1790 * Set the new value for the start and max value to let the manager pick up
1791 * the new limit immediately.
1792 */
1793 ASMAtomicWriteU32(&pBwMgr->cbTransferPerSecMax, cbMaxNew);
1794 ASMAtomicWriteU32(&pBwMgr->cbTransferPerSecStart, cbMaxNew);
1795 }
1796 else
1797 rc = VERR_NOT_FOUND;
1798
1799 return rc;
1800}
1801
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