VirtualBox

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

Last change on this file since 44358 was 44358, checked in by vboxsync, 11 years ago

PDMAsyncCompletion: PVM -> PUVM (one instance), internalize internal APIs where possible (not all because of test cases). API docs lives where the implmentation lives, NOT in headers (IPRT is the exception).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use