VirtualBox

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

Last change on this file since 80309 was 80191, checked in by vboxsync, 5 years ago

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

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