VirtualBox

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

Last change on this file was 99775, checked in by vboxsync, 12 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.1 KB
Line 
1/* $Id: PDMAsyncCompletion.cpp 99775 2023-05-12 12:21:58Z vboxsync $ */
2/** @file
3 * PDM Async I/O - Transport data asynchronous in R3 using EMT.
4 */
5
6/*
7 * Copyright (C) 2006-2023 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 * @param pTask Pointer to the finished task.
790 * @param rc Status code of the completed request.
791 * @param fCallCompletionHandler Flag whether the completion handler should be called to
792 * inform the owner of the task that it has completed.
793 */
794void pdmR3AsyncCompletionCompleteTask(PPDMASYNCCOMPLETIONTASK pTask, int rc, bool fCallCompletionHandler)
795{
796 LogFlow(("%s: pTask=%#p fCallCompletionHandler=%RTbool\n", __FUNCTION__, pTask, fCallCompletionHandler));
797
798 if (fCallCompletionHandler)
799 {
800 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pTask->pEndpoint->pTemplate;
801
802 switch (pTemplate->enmType)
803 {
804 case PDMASYNCCOMPLETIONTEMPLATETYPE_DEV:
805 pTemplate->u.Dev.pfnCompleted(pTemplate->u.Dev.pDevIns, pTask->pvUser, rc);
806 break;
807
808 case PDMASYNCCOMPLETIONTEMPLATETYPE_DRV:
809 pTemplate->u.Drv.pfnCompleted(pTemplate->u.Drv.pDrvIns, pTemplate->u.Drv.pvTemplateUser, pTask->pvUser, rc);
810 break;
811
812 case PDMASYNCCOMPLETIONTEMPLATETYPE_USB:
813 pTemplate->u.Usb.pfnCompleted(pTemplate->u.Usb.pUsbIns, pTask->pvUser, rc);
814 break;
815
816 case PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL:
817 pTemplate->u.Int.pfnCompleted(pTemplate->pVM, pTask->pvUser, pTemplate->u.Int.pvUser, rc);
818 break;
819
820 default:
821 AssertMsgFailed(("Unknown template type!\n"));
822 }
823 }
824
825 pdmR3AsyncCompletionPutTask(pTask->pEndpoint, pTask);
826}
827
828
829/**
830 * Worker initializing a endpoint class.
831 *
832 * @returns VBox status code.
833 * @param pVM The cross context VM structure.
834 * @param pEpClassOps Pointer to the endpoint class structure.
835 * @param pCfgHandle Pointer to the CFGM tree.
836 */
837static int pdmR3AsyncCompletionEpClassInit(PVM pVM, PCPDMASYNCCOMPLETIONEPCLASSOPS pEpClassOps, PCFGMNODE pCfgHandle)
838{
839 /* Validate input. */
840 AssertPtrReturn(pEpClassOps, VERR_INVALID_POINTER);
841 AssertReturn(pEpClassOps->u32Version == PDMAC_EPCLASS_OPS_VERSION, VERR_VERSION_MISMATCH);
842 AssertReturn(pEpClassOps->u32VersionEnd == PDMAC_EPCLASS_OPS_VERSION, VERR_VERSION_MISMATCH);
843
844 LogFlow(("pdmR3AsyncCompletionEpClassInit: pVM=%p pEpClassOps=%p{%s}\n", pVM, pEpClassOps, pEpClassOps->pszName));
845
846 /* Allocate global class data. */
847 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = NULL;
848
849 int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION,
850 pEpClassOps->cbEndpointClassGlobal,
851 (void **)&pEndpointClass);
852 if (RT_SUCCESS(rc))
853 {
854 /* Initialize common data. */
855 pEndpointClass->pVM = pVM;
856 pEndpointClass->pEndpointOps = pEpClassOps;
857
858 rc = RTCritSectInit(&pEndpointClass->CritSect);
859 if (RT_SUCCESS(rc))
860 {
861 PCFGMNODE pCfgNodeClass = CFGMR3GetChild(pCfgHandle, pEpClassOps->pszName);
862
863 /* Create task cache */
864 rc = RTMemCacheCreate(&pEndpointClass->hMemCacheTasks, pEpClassOps->cbTask,
865 0, UINT32_MAX, NULL, NULL, NULL, 0);
866 if (RT_SUCCESS(rc))
867 {
868 /* Call the specific endpoint class initializer. */
869 rc = pEpClassOps->pfnInitialize(pEndpointClass, pCfgNodeClass);
870 if (RT_SUCCESS(rc))
871 {
872 /* Create all bandwidth groups for resource control. */
873 PCFGMNODE pCfgBwGrp = CFGMR3GetChild(pCfgNodeClass, "BwGroups");
874 if (pCfgBwGrp)
875 {
876 for (PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgBwGrp); pCur; pCur = CFGMR3GetNextChild(pCur))
877 {
878 size_t cbName = CFGMR3GetNameLen(pCur) + 1;
879 char *pszBwGrpId = (char *)RTMemAllocZ(cbName);
880 if (pszBwGrpId)
881 {
882 rc = CFGMR3GetName(pCur, pszBwGrpId, cbName);
883 if (RT_SUCCESS(rc))
884 {
885 uint32_t cbMax;
886 rc = CFGMR3QueryU32(pCur, "Max", &cbMax);
887 if (RT_SUCCESS(rc))
888 {
889 uint32_t cbStart;
890 rc = CFGMR3QueryU32Def(pCur, "Start", &cbStart, cbMax);
891 if (RT_SUCCESS(rc))
892 {
893 uint32_t cbStep;
894 rc = CFGMR3QueryU32Def(pCur, "Step", &cbStep, 0);
895 if (RT_SUCCESS(rc))
896 rc = pdmacAsyncCompletionBwMgrCreate(pEndpointClass, pszBwGrpId,
897 cbMax, cbStart, cbStep);
898 }
899 }
900 }
901 RTMemFree(pszBwGrpId);
902 }
903 else
904 rc = VERR_NO_MEMORY;
905 if (RT_FAILURE(rc))
906 break;
907 }
908 }
909 if (RT_SUCCESS(rc))
910 {
911 PUVM pUVM = pVM->pUVM;
912 AssertMsg(!pUVM->pdm.s.apAsyncCompletionEndpointClass[pEpClassOps->enmClassType],
913 ("Endpoint class was already initialized\n"));
914
915#ifdef VBOX_WITH_STATISTICS
916 CFGMR3QueryBoolDef(pCfgNodeClass, "AdvancedStatistics", &pEndpointClass->fGatherAdvancedStatistics, true);
917#else
918 CFGMR3QueryBoolDef(pCfgNodeClass, "AdvancedStatistics", &pEndpointClass->fGatherAdvancedStatistics, false);
919#endif
920
921 pUVM->pdm.s.apAsyncCompletionEndpointClass[pEpClassOps->enmClassType] = pEndpointClass;
922 LogFlowFunc((": Initialized endpoint class \"%s\" rc=%Rrc\n", pEpClassOps->pszName, rc));
923 return VINF_SUCCESS;
924 }
925 }
926 RTMemCacheDestroy(pEndpointClass->hMemCacheTasks);
927 }
928 RTCritSectDelete(&pEndpointClass->CritSect);
929 }
930 MMR3HeapFree(pEndpointClass);
931 }
932
933 LogFlowFunc((": Failed to initialize endpoint class rc=%Rrc\n", rc));
934
935 return rc;
936}
937
938
939/**
940 * Worker terminating all endpoint classes.
941 *
942 * @param pEndpointClass Pointer to the endpoint class to terminate.
943 *
944 * @remarks This method ensures that any still open endpoint is closed.
945 */
946static void pdmR3AsyncCompletionEpClassTerminate(PPDMASYNCCOMPLETIONEPCLASS pEndpointClass)
947{
948 PVM pVM = pEndpointClass->pVM;
949
950 /* Close all still open endpoints. */
951 while (pEndpointClass->pEndpointsHead)
952 PDMR3AsyncCompletionEpClose(pEndpointClass->pEndpointsHead);
953
954 /* Destroy the bandwidth managers. */
955 PPDMACBWMGR pBwMgr = pEndpointClass->pBwMgrsHead;
956 while (pBwMgr)
957 {
958 PPDMACBWMGR pFree = pBwMgr;
959 pBwMgr = pBwMgr->pNext;
960 MMR3HeapFree(pFree);
961 }
962
963 /* Call the termination callback of the class. */
964 pEndpointClass->pEndpointOps->pfnTerminate(pEndpointClass);
965
966 RTMemCacheDestroy(pEndpointClass->hMemCacheTasks);
967 RTCritSectDelete(&pEndpointClass->CritSect);
968
969 /* Free the memory of the class finally and clear the entry in the class array. */
970 pVM->pUVM->pdm.s.apAsyncCompletionEndpointClass[pEndpointClass->pEndpointOps->enmClassType] = NULL;
971 MMR3HeapFree(pEndpointClass);
972}
973
974
975/**
976 * Records the size of the request in the statistics.
977 *
978 * @param pEndpoint The endpoint to register the request size for.
979 * @param cbReq Size of the request.
980 */
981static void pdmR3AsyncCompletionStatisticsRecordSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, size_t cbReq)
982{
983 if (cbReq < 512)
984 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSizeSmaller512);
985 else if (cbReq < _1K)
986 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize512To1K);
987 else if (cbReq < _2K)
988 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize1KTo2K);
989 else if (cbReq < _4K)
990 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize2KTo4K);
991 else if (cbReq < _8K)
992 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize4KTo8K);
993 else if (cbReq < _16K)
994 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize8KTo16K);
995 else if (cbReq < _32K)
996 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize16KTo32K);
997 else if (cbReq < _64K)
998 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize32KTo64K);
999 else if (cbReq < _128K)
1000 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize64KTo128K);
1001 else if (cbReq < _256K)
1002 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize128KTo256K);
1003 else if (cbReq < _512K)
1004 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSize256KTo512K);
1005 else
1006 STAM_REL_COUNTER_INC(&pEndpoint->StatReqSizeOver512K);
1007
1008 if (cbReq & ((size_t)512 - 1))
1009 STAM_REL_COUNTER_INC(&pEndpoint->StatReqsUnaligned512);
1010 else if (cbReq & ((size_t)_4K - 1))
1011 STAM_REL_COUNTER_INC(&pEndpoint->StatReqsUnaligned4K);
1012 else if (cbReq & ((size_t)_8K - 1))
1013 STAM_REL_COUNTER_INC(&pEndpoint->StatReqsUnaligned8K);
1014}
1015
1016
1017/**
1018 * Records the required processing time of a request.
1019 *
1020 * @param pEndpoint The endpoint.
1021 * @param cNsRun The request time in nanoseconds.
1022 */
1023static void pdmR3AsyncCompletionStatisticsRecordCompletionTime(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cNsRun)
1024{
1025 PSTAMCOUNTER pStatCounter;
1026 if (cNsRun < RT_NS_1US)
1027 pStatCounter = &pEndpoint->StatTaskRunTimesNs[cNsRun / (RT_NS_1US / 10)];
1028 else if (cNsRun < RT_NS_1MS)
1029 pStatCounter = &pEndpoint->StatTaskRunTimesUs[cNsRun / (RT_NS_1MS / 10)];
1030 else if (cNsRun < RT_NS_1SEC)
1031 pStatCounter = &pEndpoint->StatTaskRunTimesMs[cNsRun / (RT_NS_1SEC / 10)];
1032 else if (cNsRun < RT_NS_1SEC_64*100)
1033 pStatCounter = &pEndpoint->StatTaskRunTimesSec[cNsRun / (RT_NS_1SEC_64*100 / 10)];
1034 else
1035 pStatCounter = &pEndpoint->StatTaskRunOver100Sec;
1036 STAM_REL_COUNTER_INC(pStatCounter);
1037
1038 STAM_REL_COUNTER_INC(&pEndpoint->StatIoOpsCompleted);
1039 pEndpoint->cIoOpsCompleted++;
1040 uint64_t tsMsCur = RTTimeMilliTS();
1041 uint64_t tsInterval = tsMsCur - pEndpoint->tsIntervalStartMs;
1042 if (tsInterval >= 1000)
1043 {
1044 pEndpoint->StatIoOpsPerSec.c = pEndpoint->cIoOpsCompleted / (tsInterval / 1000);
1045 pEndpoint->tsIntervalStartMs = tsMsCur;
1046 pEndpoint->cIoOpsCompleted = 0;
1047 }
1048}
1049
1050
1051/**
1052 * Registers advanced statistics for the given endpoint.
1053 *
1054 * @returns VBox status code.
1055 * @param pEndpoint The endpoint to register the advanced statistics for.
1056 */
1057static int pdmR3AsyncCompletionStatisticsRegister(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
1058{
1059 int rc = VINF_SUCCESS;
1060 PVM pVM = pEndpoint->pEpClass->pVM;
1061
1062 pEndpoint->tsIntervalStartMs = RTTimeMilliTS();
1063
1064 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesNs) && RT_SUCCESS(rc); i++)
1065 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesNs[i], STAMTYPE_COUNTER,
1066 STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1067 "Nanosecond resolution runtime statistics",
1068 "/PDM/AsyncCompletion/File/%s/%d/TaskRun1Ns-%u-%u",
1069 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId, i*100, i*100+100-1);
1070
1071 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesUs) && RT_SUCCESS(rc); i++)
1072 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesUs[i], STAMTYPE_COUNTER,
1073 STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1074 "Microsecond resolution runtime statistics",
1075 "/PDM/AsyncCompletion/File/%s/%d/TaskRun2MicroSec-%u-%u",
1076 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId, i*100, i*100+100-1);
1077
1078 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs) && RT_SUCCESS(rc); i++)
1079 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesMs[i], STAMTYPE_COUNTER,
1080 STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1081 "Milliseconds resolution runtime statistics",
1082 "/PDM/AsyncCompletion/File/%s/%d/TaskRun3Ms-%u-%u",
1083 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId, i*100, i*100+100-1);
1084
1085 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs) && RT_SUCCESS(rc); i++)
1086 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesSec[i], STAMTYPE_COUNTER,
1087 STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1088 "Second resolution runtime statistics",
1089 "/PDM/AsyncCompletion/File/%s/%d/TaskRun4Sec-%u-%u",
1090 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId, i*10, i*10+10-1);
1091
1092 if (RT_SUCCESS(rc))
1093 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunOver100Sec, STAMTYPE_COUNTER,
1094 STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1095 "Tasks which ran more than 100sec",
1096 "/PDM/AsyncCompletion/File/%s/%d/TaskRunSecGreater100Sec",
1097 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1098
1099 if (RT_SUCCESS(rc))
1100 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsPerSec, STAMTYPE_COUNTER,
1101 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1102 "Processed I/O operations per second",
1103 "/PDM/AsyncCompletion/File/%s/%d/IoOpsPerSec",
1104 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1105
1106 if (RT_SUCCESS(rc))
1107 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsStarted, STAMTYPE_COUNTER,
1108 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1109 "Started I/O operations for this endpoint",
1110 "/PDM/AsyncCompletion/File/%s/%d/IoOpsStarted",
1111 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1112
1113 if (RT_SUCCESS(rc))
1114 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsCompleted, STAMTYPE_COUNTER,
1115 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1116 "Completed I/O operations for this endpoint",
1117 "/PDM/AsyncCompletion/File/%s/%d/IoOpsCompleted",
1118 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1119
1120 if (RT_SUCCESS(rc))
1121 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSizeSmaller512, STAMTYPE_COUNTER,
1122 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1123 "Number of requests with a size smaller than 512 bytes",
1124 "/PDM/AsyncCompletion/File/%s/%d/ReqSizeSmaller512",
1125 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1126
1127 if (RT_SUCCESS(rc))
1128 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize512To1K, STAMTYPE_COUNTER,
1129 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1130 "Number of requests with a size between 512 bytes and 1KB",
1131 "/PDM/AsyncCompletion/File/%s/%d/ReqSize512To1K",
1132 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1133
1134 if (RT_SUCCESS(rc))
1135 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize1KTo2K, STAMTYPE_COUNTER,
1136 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1137 "Number of requests with a size between 1KB and 2KB",
1138 "/PDM/AsyncCompletion/File/%s/%d/ReqSize1KTo2K",
1139 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1140
1141 if (RT_SUCCESS(rc))
1142 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize2KTo4K, STAMTYPE_COUNTER,
1143 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1144 "Number of requests with a size between 2KB and 4KB",
1145 "/PDM/AsyncCompletion/File/%s/%d/ReqSize2KTo4K",
1146 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1147
1148 if (RT_SUCCESS(rc))
1149 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize4KTo8K, STAMTYPE_COUNTER,
1150 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1151 "Number of requests with a size between 4KB and 8KB",
1152 "/PDM/AsyncCompletion/File/%s/%d/ReqSize4KTo8K",
1153 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1154
1155 if (RT_SUCCESS(rc))
1156 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize8KTo16K, STAMTYPE_COUNTER,
1157 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1158 "Number of requests with a size between 8KB and 16KB",
1159 "/PDM/AsyncCompletion/File/%s/%d/ReqSize8KTo16K",
1160 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1161
1162 if (RT_SUCCESS(rc))
1163 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize16KTo32K, STAMTYPE_COUNTER,
1164 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1165 "Number of requests with a size between 16KB and 32KB",
1166 "/PDM/AsyncCompletion/File/%s/%d/ReqSize16KTo32K",
1167 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1168
1169 if (RT_SUCCESS(rc))
1170 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize32KTo64K, STAMTYPE_COUNTER,
1171 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1172 "Number of requests with a size between 32KB and 64KB",
1173 "/PDM/AsyncCompletion/File/%s/%d/ReqSize32KTo64K",
1174 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1175
1176 if (RT_SUCCESS(rc))
1177 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize64KTo128K, STAMTYPE_COUNTER,
1178 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1179 "Number of requests with a size between 64KB and 128KB",
1180 "/PDM/AsyncCompletion/File/%s/%d/ReqSize64KTo128K",
1181 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1182
1183 if (RT_SUCCESS(rc))
1184 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize128KTo256K, STAMTYPE_COUNTER,
1185 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1186 "Number of requests with a size between 128KB and 256KB",
1187 "/PDM/AsyncCompletion/File/%s/%d/ReqSize128KTo256K",
1188 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1189
1190 if (RT_SUCCESS(rc))
1191 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSize256KTo512K, STAMTYPE_COUNTER,
1192 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1193 "Number of requests with a size between 256KB and 512KB",
1194 "/PDM/AsyncCompletion/File/%s/%d/ReqSize256KTo512K",
1195 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1196
1197 if (RT_SUCCESS(rc))
1198 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqSizeOver512K, STAMTYPE_COUNTER,
1199 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1200 "Number of requests with a size over 512KB",
1201 "/PDM/AsyncCompletion/File/%s/%d/ReqSizeOver512K",
1202 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1203
1204 if (RT_SUCCESS(rc))
1205 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqsUnaligned512, STAMTYPE_COUNTER,
1206 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1207 "Number of requests which size is not aligned to 512 bytes",
1208 "/PDM/AsyncCompletion/File/%s/%d/ReqsUnaligned512",
1209 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1210
1211 if (RT_SUCCESS(rc))
1212 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqsUnaligned4K, STAMTYPE_COUNTER,
1213 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1214 "Number of requests which size is not aligned to 4KB",
1215 "/PDM/AsyncCompletion/File/%s/%d/ReqsUnaligned4K",
1216 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1217
1218 if (RT_SUCCESS(rc))
1219 rc = STAMR3RegisterF(pVM, &pEndpoint->StatReqsUnaligned8K, STAMTYPE_COUNTER,
1220 STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1221 "Number of requests which size is not aligned to 8KB",
1222 "/PDM/AsyncCompletion/File/%s/%d/ReqsUnaligned8K",
1223 RTPathFilename(pEndpoint->pszUri), pEndpoint->iStatId);
1224
1225 return rc;
1226}
1227
1228
1229/**
1230 * Deregisters advanced statistics for one endpoint.
1231 *
1232 * @param pEndpoint The endpoint to deregister the advanced statistics for.
1233 */
1234static void pdmR3AsyncCompletionStatisticsDeregister(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
1235{
1236 /* I hope this doesn't remove too much... */
1237 STAMR3DeregisterF(pEndpoint->pEpClass->pVM->pUVM, "/PDM/AsyncCompletion/File/%s/*", RTPathFilename(pEndpoint->pszUri));
1238}
1239
1240
1241/**
1242 * Initialize the async completion manager.
1243 *
1244 * @returns VBox status code
1245 * @param pVM The cross context VM structure.
1246 */
1247int pdmR3AsyncCompletionInit(PVM pVM)
1248{
1249 LogFlowFunc((": pVM=%p\n", pVM));
1250
1251 VM_ASSERT_EMT(pVM);
1252
1253 PCFGMNODE pCfgRoot = CFGMR3GetRoot(pVM);
1254 PCFGMNODE pCfgAsyncCompletion = CFGMR3GetChild(CFGMR3GetChild(pCfgRoot, "PDM"), "AsyncCompletion");
1255
1256 int rc = pdmR3AsyncCompletionEpClassInit(pVM, &g_PDMAsyncCompletionEndpointClassFile, pCfgAsyncCompletion);
1257 LogFlowFunc((": pVM=%p rc=%Rrc\n", pVM, rc));
1258 return rc;
1259}
1260
1261
1262/**
1263 * Terminates the async completion manager.
1264 *
1265 * @returns VBox status code
1266 * @param pVM The cross context VM structure.
1267 */
1268int pdmR3AsyncCompletionTerm(PVM pVM)
1269{
1270 LogFlowFunc((": pVM=%p\n", pVM));
1271 PUVM pUVM = pVM->pUVM;
1272
1273 for (size_t i = 0; i < RT_ELEMENTS(pUVM->pdm.s.apAsyncCompletionEndpointClass); i++)
1274 if (pUVM->pdm.s.apAsyncCompletionEndpointClass[i])
1275 pdmR3AsyncCompletionEpClassTerminate(pUVM->pdm.s.apAsyncCompletionEndpointClass[i]);
1276
1277 return VINF_SUCCESS;
1278}
1279
1280
1281/**
1282 * Resume worker for the async completion manager.
1283 *
1284 * @param pVM The cross context VM structure.
1285 */
1286void pdmR3AsyncCompletionResume(PVM pVM)
1287{
1288 LogFlowFunc((": pVM=%p\n", pVM));
1289 PUVM pUVM = pVM->pUVM;
1290
1291 /* Log the bandwidth groups and all assigned endpoints. */
1292 for (size_t i = 0; i < RT_ELEMENTS(pUVM->pdm.s.apAsyncCompletionEndpointClass); i++)
1293 if (pUVM->pdm.s.apAsyncCompletionEndpointClass[i])
1294 {
1295 PPDMASYNCCOMPLETIONEPCLASS pEpClass = pUVM->pdm.s.apAsyncCompletionEndpointClass[i];
1296 PPDMACBWMGR pBwMgr = pEpClass->pBwMgrsHead;
1297 PPDMASYNCCOMPLETIONENDPOINT pEp;
1298
1299 if (pBwMgr)
1300 LogRel(("AIOMgr: Bandwidth groups for class '%s'\n", i == PDMASYNCCOMPLETIONEPCLASSTYPE_FILE
1301 ? "File" : "<Unknown>"));
1302
1303 while (pBwMgr)
1304 {
1305 LogRel(("AIOMgr: Id: %s\n", pBwMgr->pszId));
1306 LogRel(("AIOMgr: Max: %u B/s\n", pBwMgr->cbTransferPerSecMax));
1307 LogRel(("AIOMgr: Start: %u B/s\n", pBwMgr->cbTransferPerSecStart));
1308 LogRel(("AIOMgr: Step: %u B/s\n", pBwMgr->cbTransferPerSecStep));
1309 LogRel(("AIOMgr: Endpoints:\n"));
1310
1311 pEp = pEpClass->pEndpointsHead;
1312 while (pEp)
1313 {
1314 if (pEp->pBwMgr == pBwMgr)
1315 LogRel(("AIOMgr: %s\n", pEp->pszUri));
1316
1317 pEp = pEp->pNext;
1318 }
1319
1320 pBwMgr = pBwMgr->pNext;
1321 }
1322
1323 /* Print all endpoints without assigned bandwidth groups. */
1324 pEp = pEpClass->pEndpointsHead;
1325 if (pEp)
1326 LogRel(("AIOMgr: Endpoints without assigned bandwidth groups:\n"));
1327
1328 while (pEp)
1329 {
1330 if (!pEp->pBwMgr)
1331 LogRel(("AIOMgr: %s\n", pEp->pszUri));
1332
1333 pEp = pEp->pNext;
1334 }
1335 }
1336}
1337
1338
1339/**
1340 * Tries to get a free task from the endpoint or class cache
1341 * allocating the task if it fails.
1342 *
1343 * @returns Pointer to a new and initialized task or NULL
1344 * @param pEndpoint The endpoint the task is for.
1345 * @param pvUser Opaque user data for the task.
1346 */
1347static PPDMASYNCCOMPLETIONTASK pdmR3AsyncCompletionGetTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser)
1348{
1349 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
1350 PPDMASYNCCOMPLETIONTASK pTask = (PPDMASYNCCOMPLETIONTASK)RTMemCacheAlloc(pEndpointClass->hMemCacheTasks);
1351 if (RT_LIKELY(pTask))
1352 {
1353 /* Initialize common parts. */
1354 pTask->pvUser = pvUser;
1355 pTask->pEndpoint = pEndpoint;
1356 /* Clear list pointers for safety. */
1357 pTask->pPrev = NULL;
1358 pTask->pNext = NULL;
1359 pTask->tsNsStart = RTTimeNanoTS();
1360 STAM_REL_COUNTER_INC(&pEndpoint->StatIoOpsStarted);
1361 }
1362
1363 return pTask;
1364}
1365
1366
1367/**
1368 * Puts a task in one of the caches.
1369 *
1370 * @param pEndpoint The endpoint the task belongs to.
1371 * @param pTask The task to cache.
1372 */
1373static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask)
1374{
1375 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
1376 uint64_t cNsRun = RTTimeNanoTS() - pTask->tsNsStart;
1377
1378 if (RT_UNLIKELY(cNsRun >= RT_NS_10SEC))
1379 LogRel(("AsyncCompletion: Task %#p completed after %llu seconds\n", pTask, cNsRun / RT_NS_1SEC));
1380
1381 if (pEndpointClass->fGatherAdvancedStatistics)
1382 pdmR3AsyncCompletionStatisticsRecordCompletionTime(pEndpoint, cNsRun);
1383
1384 RTMemCacheFree(pEndpointClass->hMemCacheTasks, pTask);
1385}
1386
1387
1388static unsigned
1389pdmR3AsyncCompletionGetStatId(PPDMASYNCCOMPLETIONEPCLASS pEndpointClass, const char *pszUri)
1390{
1391 PPDMASYNCCOMPLETIONENDPOINT pEndpoint = pEndpointClass->pEndpointsHead;
1392 const char *pszFilename = RTPathFilename(pszUri);
1393 unsigned iStatId = 0;
1394
1395 while (pEndpoint)
1396 {
1397 if ( !RTStrCmp(RTPathFilename(pEndpoint->pszUri), pszFilename)
1398 && pEndpoint->iStatId >= iStatId)
1399 iStatId = pEndpoint->iStatId + 1;
1400
1401 pEndpoint = pEndpoint->pNext;
1402 }
1403
1404 return iStatId;
1405}
1406
1407/**
1408 * Opens a file as an async completion endpoint.
1409 *
1410 * @returns VBox status code.
1411 * @param ppEndpoint Where to store the opaque endpoint handle on success.
1412 * @param pszFilename Path to the file which is to be opened. (UTF-8)
1413 * @param fFlags Open flags, see grp_pdmacep_file_flags.
1414 * @param pTemplate Handle to the completion callback template to use
1415 * for this end point.
1416 */
1417VMMR3DECL(int) PDMR3AsyncCompletionEpCreateForFile(PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint,
1418 const char *pszFilename, uint32_t fFlags,
1419 PPDMASYNCCOMPLETIONTEMPLATE pTemplate)
1420{
1421 LogFlowFunc((": ppEndpoint=%p pszFilename=%p{%s} fFlags=%u pTemplate=%p\n",
1422 ppEndpoint, pszFilename, pszFilename, fFlags, pTemplate));
1423
1424 /* Sanity checks. */
1425 AssertPtrReturn(ppEndpoint, VERR_INVALID_POINTER);
1426 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1427 AssertPtrReturn(pTemplate, VERR_INVALID_POINTER);
1428
1429 /* Check that the flags are valid. */
1430 AssertReturn(((~(PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_DONT_LOCK | PDMACEP_FILE_FLAGS_HOST_CACHE_ENABLED) & fFlags) == 0),
1431 VERR_INVALID_PARAMETER);
1432
1433 PVM pVM = pTemplate->pVM;
1434 PUVM pUVM = pVM->pUVM;
1435 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pUVM->pdm.s.apAsyncCompletionEndpointClass[PDMASYNCCOMPLETIONEPCLASSTYPE_FILE];
1436 PPDMASYNCCOMPLETIONENDPOINT pEndpoint = NULL;
1437
1438 AssertMsg(pEndpointClass, ("File endpoint class was not initialized\n"));
1439
1440 /* Create an endpoint. */
1441 int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION,
1442 pEndpointClass->pEndpointOps->cbEndpoint,
1443 (void **)&pEndpoint);
1444 if (RT_SUCCESS(rc))
1445 {
1446 /* Initialize common parts. */
1447 pEndpoint->pNext = NULL;
1448 pEndpoint->pPrev = NULL;
1449 pEndpoint->pEpClass = pEndpointClass;
1450 pEndpoint->pTemplate = pTemplate;
1451 pEndpoint->pszUri = RTStrDup(pszFilename);
1452 pEndpoint->iStatId = pdmR3AsyncCompletionGetStatId(pEndpointClass, pszFilename);
1453 pEndpoint->pBwMgr = NULL;
1454
1455 if ( pEndpoint->pszUri
1456 && RT_SUCCESS(rc))
1457 {
1458 /* Call the initializer for the endpoint. */
1459 rc = pEndpointClass->pEndpointOps->pfnEpInitialize(pEndpoint, pszFilename, fFlags);
1460 if (RT_SUCCESS(rc))
1461 {
1462 if (pEndpointClass->fGatherAdvancedStatistics)
1463 rc = pdmR3AsyncCompletionStatisticsRegister(pEndpoint);
1464
1465 if (RT_SUCCESS(rc))
1466 {
1467 /* Link it into the list of endpoints. */
1468 rc = RTCritSectEnter(&pEndpointClass->CritSect);
1469 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1470
1471 pEndpoint->pNext = pEndpointClass->pEndpointsHead;
1472 if (pEndpointClass->pEndpointsHead)
1473 pEndpointClass->pEndpointsHead->pPrev = pEndpoint;
1474
1475 pEndpointClass->pEndpointsHead = pEndpoint;
1476 pEndpointClass->cEndpoints++;
1477
1478 rc = RTCritSectLeave(&pEndpointClass->CritSect);
1479 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1480
1481 /* Reference the template. */
1482 ASMAtomicIncU32(&pTemplate->cUsed);
1483
1484 *ppEndpoint = pEndpoint;
1485 LogFlowFunc((": Created endpoint for %s\n", pszFilename));
1486 return VINF_SUCCESS;
1487 }
1488 else
1489 pEndpointClass->pEndpointOps->pfnEpClose(pEndpoint);
1490
1491 if (pEndpointClass->fGatherAdvancedStatistics)
1492 pdmR3AsyncCompletionStatisticsDeregister(pEndpoint);
1493 }
1494 RTStrFree(pEndpoint->pszUri);
1495 }
1496 MMR3HeapFree(pEndpoint);
1497 }
1498
1499 LogFlowFunc((": Creation of endpoint for %s failed: rc=%Rrc\n", pszFilename, rc));
1500 return rc;
1501}
1502
1503
1504/**
1505 * Closes a endpoint waiting for any pending tasks to finish.
1506 *
1507 * @param pEndpoint Handle of the endpoint.
1508 */
1509VMMR3DECL(void) PDMR3AsyncCompletionEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
1510{
1511 LogFlowFunc((": pEndpoint=%p\n", pEndpoint));
1512
1513 /* Sanity checks. */
1514 AssertReturnVoid(RT_VALID_PTR(pEndpoint));
1515
1516 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
1517 pEndpointClass->pEndpointOps->pfnEpClose(pEndpoint);
1518
1519 /* Drop reference from the template. */
1520 ASMAtomicDecU32(&pEndpoint->pTemplate->cUsed);
1521
1522 /* Unlink the endpoint from the list. */
1523 int rc = RTCritSectEnter(&pEndpointClass->CritSect);
1524 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1525
1526 PPDMASYNCCOMPLETIONENDPOINT pEndpointNext = pEndpoint->pNext;
1527 PPDMASYNCCOMPLETIONENDPOINT pEndpointPrev = pEndpoint->pPrev;
1528
1529 if (pEndpointPrev)
1530 pEndpointPrev->pNext = pEndpointNext;
1531 else
1532 pEndpointClass->pEndpointsHead = pEndpointNext;
1533 if (pEndpointNext)
1534 pEndpointNext->pPrev = pEndpointPrev;
1535
1536 pEndpointClass->cEndpoints--;
1537
1538 rc = RTCritSectLeave(&pEndpointClass->CritSect);
1539 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1540
1541 if (pEndpointClass->fGatherAdvancedStatistics)
1542 pdmR3AsyncCompletionStatisticsDeregister(pEndpoint);
1543
1544 RTStrFree(pEndpoint->pszUri);
1545 MMR3HeapFree(pEndpoint);
1546}
1547
1548
1549/**
1550 * Creates a read task on the given endpoint.
1551 *
1552 * @returns VBox status code.
1553 * @param pEndpoint The file endpoint to read from.
1554 * @param off Where to start reading from.
1555 * @param paSegments Scatter gather list to store the data in.
1556 * @param cSegments Number of segments in the list.
1557 * @param cbRead The overall number of bytes to read.
1558 * @param pvUser Opaque user data returned in the completion callback
1559 * upon completion of the task.
1560 * @param ppTask Where to store the task handle on success.
1561 */
1562VMMR3DECL(int) PDMR3AsyncCompletionEpRead(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
1563 PCRTSGSEG paSegments, unsigned cSegments,
1564 size_t cbRead, void *pvUser,
1565 PPPDMASYNCCOMPLETIONTASK ppTask)
1566{
1567 AssertPtrReturn(pEndpoint, VERR_INVALID_POINTER);
1568 AssertPtrReturn(paSegments, VERR_INVALID_POINTER);
1569 AssertPtrReturn(ppTask, VERR_INVALID_POINTER);
1570 AssertReturn(cSegments > 0, VERR_INVALID_PARAMETER);
1571 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
1572 AssertReturn(off >= 0, VERR_INVALID_PARAMETER);
1573
1574 PPDMASYNCCOMPLETIONTASK pTask;
1575
1576 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1577 if (!pTask)
1578 return VERR_NO_MEMORY;
1579
1580 int rc = pEndpoint->pEpClass->pEndpointOps->pfnEpRead(pTask, pEndpoint, off,
1581 paSegments, cSegments, cbRead);
1582 if (RT_SUCCESS(rc))
1583 {
1584 if (pEndpoint->pEpClass->fGatherAdvancedStatistics)
1585 pdmR3AsyncCompletionStatisticsRecordSize(pEndpoint, cbRead);
1586
1587 *ppTask = pTask;
1588 }
1589 else
1590 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1591
1592 return rc;
1593}
1594
1595
1596/**
1597 * Creates a write task on the given endpoint.
1598 *
1599 * @returns VBox status code.
1600 * @param pEndpoint The file endpoint to write to.
1601 * @param off Where to start writing at.
1602 * @param paSegments Scatter gather list of the data to write.
1603 * @param cSegments Number of segments in the list.
1604 * @param cbWrite The overall number of bytes to write.
1605 * @param pvUser Opaque user data returned in the completion callback
1606 * upon completion of the task.
1607 * @param ppTask Where to store the task handle on success.
1608 */
1609VMMR3DECL(int) PDMR3AsyncCompletionEpWrite(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
1610 PCRTSGSEG paSegments, unsigned cSegments,
1611 size_t cbWrite, void *pvUser,
1612 PPPDMASYNCCOMPLETIONTASK ppTask)
1613{
1614 AssertPtrReturn(pEndpoint, VERR_INVALID_POINTER);
1615 AssertPtrReturn(paSegments, VERR_INVALID_POINTER);
1616 AssertPtrReturn(ppTask, VERR_INVALID_POINTER);
1617 AssertReturn(cSegments > 0, VERR_INVALID_PARAMETER);
1618 AssertReturn(cbWrite > 0, VERR_INVALID_PARAMETER);
1619 AssertReturn(off >= 0, VERR_INVALID_PARAMETER);
1620
1621 PPDMASYNCCOMPLETIONTASK pTask;
1622
1623 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1624 if (!pTask)
1625 return VERR_NO_MEMORY;
1626
1627 int rc = pEndpoint->pEpClass->pEndpointOps->pfnEpWrite(pTask, pEndpoint, off,
1628 paSegments, cSegments, cbWrite);
1629 if (RT_SUCCESS(rc))
1630 {
1631 if (pEndpoint->pEpClass->fGatherAdvancedStatistics)
1632 pdmR3AsyncCompletionStatisticsRecordSize(pEndpoint, cbWrite);
1633
1634 *ppTask = pTask;
1635 }
1636 else
1637 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1638
1639 return rc;
1640}
1641
1642
1643/**
1644 * Creates a flush task on the given endpoint.
1645 *
1646 * Every read and write task initiated before the flush task is
1647 * finished upon completion of this task.
1648 *
1649 * @returns VBox status code.
1650 * @param pEndpoint The file endpoint to flush.
1651 * @param pvUser Opaque user data returned in the completion callback
1652 * upon completion of the task.
1653 * @param ppTask Where to store the task handle on success.
1654 */
1655VMMR3DECL(int) PDMR3AsyncCompletionEpFlush(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser, PPPDMASYNCCOMPLETIONTASK ppTask)
1656{
1657 AssertPtrReturn(pEndpoint, VERR_INVALID_POINTER);
1658 AssertPtrReturn(ppTask, VERR_INVALID_POINTER);
1659
1660 PPDMASYNCCOMPLETIONTASK pTask;
1661
1662 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1663 if (!pTask)
1664 return VERR_NO_MEMORY;
1665
1666 int rc = pEndpoint->pEpClass->pEndpointOps->pfnEpFlush(pTask, pEndpoint);
1667 if (RT_SUCCESS(rc))
1668 *ppTask = pTask;
1669 else
1670 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1671
1672 return rc;
1673}
1674
1675
1676/**
1677 * Queries the size of an endpoint.
1678 *
1679 * Not that some endpoints may not support this and will return an error
1680 * (sockets for example).
1681 *
1682 * @returns VBox status code.
1683 * @retval VERR_NOT_SUPPORTED if the endpoint does not support this operation.
1684 * @param pEndpoint The file endpoint.
1685 * @param pcbSize Where to store the size of the endpoint.
1686 */
1687VMMR3DECL(int) PDMR3AsyncCompletionEpGetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1688 uint64_t *pcbSize)
1689{
1690 AssertPtrReturn(pEndpoint, VERR_INVALID_POINTER);
1691 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
1692
1693 if (pEndpoint->pEpClass->pEndpointOps->pfnEpGetSize)
1694 return pEndpoint->pEpClass->pEndpointOps->pfnEpGetSize(pEndpoint, pcbSize);
1695 return VERR_NOT_SUPPORTED;
1696}
1697
1698
1699/**
1700 * Sets the size of an endpoint.
1701 *
1702 * Not that some endpoints may not support this and will return an error
1703 * (sockets for example).
1704 *
1705 * @returns VBox status code.
1706 * @retval VERR_NOT_SUPPORTED if the endpoint does not support this operation.
1707 * @param pEndpoint The file endpoint.
1708 * @param cbSize The size to set.
1709 *
1710 * @note PDMR3AsyncCompletionEpFlush should be called before this operation is executed.
1711 */
1712VMMR3DECL(int) PDMR3AsyncCompletionEpSetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize)
1713{
1714 AssertPtrReturn(pEndpoint, VERR_INVALID_POINTER);
1715
1716 if (pEndpoint->pEpClass->pEndpointOps->pfnEpSetSize)
1717 return pEndpoint->pEpClass->pEndpointOps->pfnEpSetSize(pEndpoint, cbSize);
1718 return VERR_NOT_SUPPORTED;
1719}
1720
1721
1722/**
1723 * Assigns or removes a bandwidth control manager to/from the endpoint.
1724 *
1725 * @returns VBox status code.
1726 * @param pEndpoint The endpoint.
1727 * @param pszBwMgr The identifer of the new bandwidth manager to assign
1728 * or NULL to remove the current one.
1729 */
1730VMMR3DECL(int) PDMR3AsyncCompletionEpSetBwMgr(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr)
1731{
1732 AssertPtrReturn(pEndpoint, VERR_INVALID_POINTER);
1733 PPDMACBWMGR pBwMgrOld = NULL;
1734 PPDMACBWMGR pBwMgrNew = NULL;
1735
1736 int rc = VINF_SUCCESS;
1737 if (pszBwMgr)
1738 {
1739 pBwMgrNew = pdmacBwMgrFindById(pEndpoint->pEpClass, pszBwMgr);
1740 if (pBwMgrNew)
1741 pdmacBwMgrRetain(pBwMgrNew);
1742 else
1743 rc = VERR_NOT_FOUND;
1744 }
1745
1746 if (RT_SUCCESS(rc))
1747 {
1748 pBwMgrOld = ASMAtomicXchgPtrT(&pEndpoint->pBwMgr, pBwMgrNew, PPDMACBWMGR);
1749 if (pBwMgrOld)
1750 pdmacBwMgrRelease(pBwMgrOld);
1751 }
1752
1753 return rc;
1754}
1755
1756
1757/**
1758 * Cancels an async completion task.
1759 *
1760 * If you want to use this method, you have to take great create to make sure
1761 * you will never attempt cancel a task which has been completed. Since there is
1762 * no reference counting or anything on the task it self, you have to serialize
1763 * the cancelation and completion paths such that the aren't racing one another.
1764 *
1765 * @returns VBox status code
1766 * @param pTask The Task to cancel.
1767 */
1768VMMR3DECL(int) PDMR3AsyncCompletionTaskCancel(PPDMASYNCCOMPLETIONTASK pTask)
1769{
1770 NOREF(pTask);
1771 return VERR_NOT_IMPLEMENTED;
1772}
1773
1774
1775/**
1776 * Changes the limit of a bandwidth manager for file endpoints to the given value.
1777 *
1778 * @returns VBox status code.
1779 * @param pUVM The user mode VM handle.
1780 * @param pszBwMgr The identifer of the bandwidth manager to change.
1781 * @param cbMaxNew The new maximum for the bandwidth manager in bytes/sec.
1782 */
1783VMMR3DECL(int) PDMR3AsyncCompletionBwMgrSetMaxForFile(PUVM pUVM, const char *pszBwMgr, uint32_t cbMaxNew)
1784{
1785 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1786 PVM pVM = pUVM->pVM;
1787 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1788 AssertPtrReturn(pszBwMgr, VERR_INVALID_POINTER);
1789
1790 int rc = VINF_SUCCESS;
1791 PPDMASYNCCOMPLETIONEPCLASS pEpClass = pVM->pUVM->pdm.s.apAsyncCompletionEndpointClass[PDMASYNCCOMPLETIONEPCLASSTYPE_FILE];
1792 PPDMACBWMGR pBwMgr = pdmacBwMgrFindById(pEpClass, pszBwMgr);
1793 if (pBwMgr)
1794 {
1795 /*
1796 * Set the new value for the start and max value to let the manager pick up
1797 * the new limit immediately.
1798 */
1799 ASMAtomicWriteU32(&pBwMgr->cbTransferPerSecMax, cbMaxNew);
1800 ASMAtomicWriteU32(&pBwMgr->cbTransferPerSecStart, cbMaxNew);
1801 }
1802 else
1803 rc = VERR_NOT_FOUND;
1804
1805 return rc;
1806}
1807
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use