VirtualBox

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

Last change on this file since 43599 was 43599, checked in by vboxsync, 12 years ago

AsyncCompletion: New statistics counter to record 8KB unaligned accesses

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

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