VirtualBox

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

Last change on this file since 74795 was 69111, checked in by vboxsync, 7 years ago

(C) year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use