VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

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

© 2023 Oracle
ContactPrivacy policyTerms of Use