VirtualBox

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

Last change on this file since 84044 was 82968, checked in by vboxsync, 4 years ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use