VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 8 weeks ago

Copyright year updates by scm.

  • 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 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * PDM Async I/O - Transport data asynchronous in R3 using EMT.
4 */
5
6/*
7 * Copyright (C) 2006-2024 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.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette