VirtualBox

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

Last change on this file since 33218 was 33218, checked in by vboxsync, 14 years ago

AsyncCompletion: Move bandwidth groups to the generic code and support arbitrary grouping of endpoints into bandwidth groups.

To add a new bandwidth group use setextradata (this adds a group called Test and sets the maximum to 2 MB/s):

VBoxInternal/PDM/AsyncCompletion/File/BwGroups/Test/Max 2097152
VBoxInternal/PDM/AsyncCompletion/File/BwGroups/Test/Start 2097152
VBoxInternal/PDM/AsyncCompletion/File/BwGroups/Test/Step 0

To assign a disk to the group add:

VBoxInternal/Devices/ahci/0/LUN#0/AttachedDriver/Config/BwGroup Test

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 53.3 KB
Line 
1/* $Id: PDMAsyncCompletion.cpp 33218 2010-10-18 19:54:10Z vboxsync $ */
2/** @file
3 * PDM Async I/O - Transport data asynchronous in R3 using EMT.
4 */
5
6/*
7 * Copyright (C) 2006-2008 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/pdm.h>
25#include <VBox/mm.h>
26#include <VBox/rem.h>
27#include <VBox/vm.h>
28#include <VBox/uvm.h>
29#include <VBox/err.h>
30
31#include <VBox/log.h>
32#include <iprt/asm.h>
33#include <iprt/assert.h>
34#include <iprt/thread.h>
35#include <iprt/mem.h>
36#include <iprt/critsect.h>
37#include <iprt/tcp.h>
38#include <iprt/path.h>
39#include <iprt/string.h>
40
41#include <VBox/pdmasynccompletion.h>
42#include "PDMAsyncCompletionInternal.h"
43
44/**
45 * Async I/O type.
46 */
47typedef enum PDMASYNCCOMPLETIONTEMPLATETYPE
48{
49 /** Device . */
50 PDMASYNCCOMPLETIONTEMPLATETYPE_DEV = 1,
51 /** Driver consumer. */
52 PDMASYNCCOMPLETIONTEMPLATETYPE_DRV,
53 /** Internal consumer. */
54 PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL,
55 /** Usb consumer. */
56 PDMASYNCCOMPLETIONTEMPLATETYPE_USB
57} PDMASYNCTEMPLATETYPE;
58
59/**
60 * PDM Async I/O template.
61 */
62typedef struct PDMASYNCCOMPLETIONTEMPLATE
63{
64 /** Pointer to the next template in the list. */
65 R3PTRTYPE(PPDMASYNCCOMPLETIONTEMPLATE) pNext;
66 /** Pointer to the previous template in the list. */
67 R3PTRTYPE(PPDMASYNCCOMPLETIONTEMPLATE) pPrev;
68 /** Type specific data. */
69 union
70 {
71 /** PDMASYNCCOMPLETIONTEMPLATETYPE_DEV */
72 struct
73 {
74 /** Pointer to consumer function. */
75 R3PTRTYPE(PFNPDMASYNCCOMPLETEDEV) pfnCompleted;
76 /** Pointer to the device instance owning the template. */
77 R3PTRTYPE(PPDMDEVINS) pDevIns;
78 } Dev;
79 /** PDMASYNCCOMPLETIONTEMPLATETYPE_DRV */
80 struct
81 {
82 /** Pointer to consumer function. */
83 R3PTRTYPE(PFNPDMASYNCCOMPLETEDRV) pfnCompleted;
84 /** Pointer to the driver instance owning the template. */
85 R3PTRTYPE(PPDMDRVINS) pDrvIns;
86 /** User agument given during template creation.
87 * This is only here to make things much easier
88 * for DrVVD. */
89 void *pvTemplateUser;
90 } Drv;
91 /** PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL */
92 struct
93 {
94 /** Pointer to consumer function. */
95 R3PTRTYPE(PFNPDMASYNCCOMPLETEINT) pfnCompleted;
96 /** Pointer to user data. */
97 R3PTRTYPE(void *) pvUser;
98 } Int;
99 /** PDMASYNCCOMPLETIONTEMPLATETYPE_USB */
100 struct
101 {
102 /** Pointer to consumer function. */
103 R3PTRTYPE(PFNPDMASYNCCOMPLETEUSB) pfnCompleted;
104 /** Pointer to the usb instance owning the template. */
105 R3PTRTYPE(PPDMUSBINS) pUsbIns;
106 } Usb;
107 } u;
108 /** Template type. */
109 PDMASYNCCOMPLETIONTEMPLATETYPE enmType;
110 /** Pointer to the VM. */
111 R3PTRTYPE(PVM) pVM;
112 /** Use count of the template. */
113 volatile uint32_t cUsed;
114} PDMASYNCCOMPLETIONTEMPLATE;
115
116/**
117 * Bandwidth control manager instance data
118 */
119typedef struct PDMACBWMGR
120{
121 /** Pointer to the next manager in the list. */
122 struct PDMACBWMGR *pNext;
123 /** Pointer to the shared UVM structure. */
124 PPDMASYNCCOMPLETIONEPCLASS pEpClass;
125 /** Identifer of the manager. */
126 char *pszId;
127 /** Maximum number of bytes the endpoints are allowed to transfer (Max is 4GB/s currently) */
128 volatile uint32_t cbTransferPerSecMax;
129 /** Number of bytes we start with */
130 volatile uint32_t cbTransferPerSecStart;
131 /** Step after each update */
132 volatile uint32_t cbTransferPerSecStep;
133 /** Number of bytes we are allowed to transfer till the next update.
134 * Reset by the refresh timer. */
135 volatile uint32_t cbTransferAllowed;
136 /** Timestamp of the last update */
137 volatile uint64_t tsUpdatedLast;
138 /** Reference counter - How many endpoints are associated with this manager. */
139 volatile uint32_t cRefs;
140} PDMACBWMGR;
141/** Pointer to a bandwidth control manager pointer. */
142typedef PPDMACBWMGR *PPPDMACBWMGR;
143
144static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask);
145
146/**
147 * Internal worker for the creation apis
148 *
149 * @returns VBox status.
150 * @param pVM VM handle.
151 * @param ppTemplate Where to store the template handle.
152 */
153static int pdmR3AsyncCompletionTemplateCreate(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE enmType)
154{
155 PUVM pUVM = pVM->pUVM;
156
157 if (ppTemplate == NULL)
158 {
159 AssertMsgFailed(("ppTemplate is NULL\n"));
160 return VERR_INVALID_PARAMETER;
161 }
162
163 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
164 int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION, sizeof(PDMASYNCCOMPLETIONTEMPLATE), (void **)&pTemplate);
165 if (RT_FAILURE(rc))
166 return rc;
167
168 /*
169 * Initialize fields.
170 */
171 pTemplate->pVM = pVM;
172 pTemplate->cUsed = 0;
173 pTemplate->enmType = enmType;
174
175 /*
176 * Add template to the global VM template list.
177 */
178 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
179 pTemplate->pNext = pUVM->pdm.s.pAsyncCompletionTemplates;
180 if (pUVM->pdm.s.pAsyncCompletionTemplates)
181 pUVM->pdm.s.pAsyncCompletionTemplates->pPrev = pTemplate;
182 pUVM->pdm.s.pAsyncCompletionTemplates = pTemplate;
183 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
184
185 *ppTemplate = pTemplate;
186 return VINF_SUCCESS;
187}
188
189/**
190 * Creates a async completion template for a device instance.
191 *
192 * The template is used when creating new completion tasks.
193 *
194 * @returns VBox status code.
195 * @param pVM Pointer to the shared VM structure.
196 * @param pDevIns The device instance.
197 * @param ppTemplate Where to store the template pointer on success.
198 * @param pfnCompleted The completion callback routine.
199 * @param pszDesc Description.
200 */
201VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateDevice(PVM pVM, PPDMDEVINS pDevIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEDEV pfnCompleted, const char *pszDesc)
202{
203 LogFlow(("%s: pDevIns=%p ppTemplate=%p pfnCompleted=%p pszDesc=%s\n",
204 __FUNCTION__, pDevIns, ppTemplate, pfnCompleted, pszDesc));
205
206 /*
207 * Validate input.
208 */
209 VM_ASSERT_EMT(pVM);
210 if (!pfnCompleted)
211 {
212 AssertMsgFailed(("No completion callback!\n"));
213 return VERR_INVALID_PARAMETER;
214 }
215
216 if (!ppTemplate)
217 {
218 AssertMsgFailed(("Template pointer is NULL!\n"));
219 return VERR_INVALID_PARAMETER;
220 }
221
222 /*
223 * Create the template.
224 */
225 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
226 int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_DEV);
227 if (RT_SUCCESS(rc))
228 {
229 pTemplate->u.Dev.pDevIns = pDevIns;
230 pTemplate->u.Dev.pfnCompleted = pfnCompleted;
231
232 *ppTemplate = pTemplate;
233 Log(("PDM: Created device template %p: pfnCompleted=%p pDevIns=%p\n",
234 pTemplate, pfnCompleted, pDevIns));
235 }
236
237 return rc;
238}
239
240/**
241 * Creates a async completion template for a driver instance.
242 *
243 * The template is used when creating new completion tasks.
244 *
245 * @returns VBox status code.
246 * @param pVM Pointer to the shared VM structure.
247 * @param pDrvIns The driver instance.
248 * @param ppTemplate Where to store the template pointer on success.
249 * @param pfnCompleted The completion callback routine.
250 * @param pvTemplateUser Template user argument
251 * @param pszDesc Description.
252 */
253VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser, const char *pszDesc)
254{
255 LogFlow(("%s: pDrvIns=%p ppTemplate=%p pfnCompleted=%p pszDesc=%s\n",
256 __FUNCTION__, pDrvIns, ppTemplate, pfnCompleted, pszDesc));
257
258 /*
259 * Validate input.
260 */
261 if (!pfnCompleted)
262 {
263 AssertMsgFailed(("No completion callback!\n"));
264 return VERR_INVALID_PARAMETER;
265 }
266
267 if (!ppTemplate)
268 {
269 AssertMsgFailed(("Template pointer is NULL!\n"));
270 return VERR_INVALID_PARAMETER;
271 }
272
273 /*
274 * Create the template.
275 */
276 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
277 int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_DRV);
278 if (RT_SUCCESS(rc))
279 {
280 pTemplate->u.Drv.pDrvIns = pDrvIns;
281 pTemplate->u.Drv.pfnCompleted = pfnCompleted;
282 pTemplate->u.Drv.pvTemplateUser = pvTemplateUser;
283
284 *ppTemplate = pTemplate;
285 Log(("PDM: Created driver template %p: pfnCompleted=%p pDrvIns=%p\n",
286 pTemplate, pfnCompleted, pDrvIns));
287 }
288
289 return rc;
290}
291
292/**
293 * Creates a async completion template for a USB device instance.
294 *
295 * The template is used when creating new completion tasks.
296 *
297 * @returns VBox status code.
298 * @param pVM Pointer to the shared VM structure.
299 * @param pUsbIns The USB device instance.
300 * @param ppTemplate Where to store the template pointer on success.
301 * @param pfnCompleted The completion callback routine.
302 * @param pszDesc Description.
303 */
304VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEUSB pfnCompleted, const char *pszDesc)
305{
306 LogFlow(("%s: pUsbIns=%p ppTemplate=%p pfnCompleted=%p pszDesc=%s\n",
307 __FUNCTION__, pUsbIns, ppTemplate, pfnCompleted, pszDesc));
308
309 /*
310 * Validate input.
311 */
312 VM_ASSERT_EMT(pVM);
313 if (!pfnCompleted)
314 {
315 AssertMsgFailed(("No completion callback!\n"));
316 return VERR_INVALID_PARAMETER;
317 }
318
319 if (!ppTemplate)
320 {
321 AssertMsgFailed(("Template pointer is NULL!\n"));
322 return VERR_INVALID_PARAMETER;
323 }
324
325 /*
326 * Create the template.
327 */
328 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
329 int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_USB);
330 if (RT_SUCCESS(rc))
331 {
332 pTemplate->u.Usb.pUsbIns = pUsbIns;
333 pTemplate->u.Usb.pfnCompleted = pfnCompleted;
334
335 *ppTemplate = pTemplate;
336 Log(("PDM: Created usb template %p: pfnCompleted=%p pDevIns=%p\n",
337 pTemplate, pfnCompleted, pUsbIns));
338 }
339
340 return rc;
341}
342
343/**
344 * Creates a async completion template for internally by the VMM.
345 *
346 * The template is used when creating new completion tasks.
347 *
348 * @returns VBox status code.
349 * @param pVM Pointer to the shared VM structure.
350 * @param ppTemplate Where to store the template pointer on success.
351 * @param pfnCompleted The completion callback routine.
352 * @param pvUser2 The 2nd user argument for the callback.
353 * @param pszDesc Description.
354 */
355VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateInternal(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEINT pfnCompleted, void *pvUser2, const char *pszDesc)
356{
357 LogFlow(("%s: ppTemplate=%p pfnCompleted=%p pvUser2=%p pszDesc=%s\n",
358 __FUNCTION__, ppTemplate, pfnCompleted, pvUser2, pszDesc));
359
360 /*
361 * Validate input.
362 */
363 VM_ASSERT_EMT(pVM);
364 if (!pfnCompleted)
365 {
366 AssertMsgFailed(("No completion callback!\n"));
367 return VERR_INVALID_PARAMETER;
368 }
369
370 if (!ppTemplate)
371 {
372 AssertMsgFailed(("Template pointer is NULL!\n"));
373 return VERR_INVALID_PARAMETER;
374 }
375
376 /*
377 * Create the template.
378 */
379 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
380 int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL);
381 if (RT_SUCCESS(rc))
382 {
383 pTemplate->u.Int.pvUser = pvUser2;
384 pTemplate->u.Int.pfnCompleted = pfnCompleted;
385
386 *ppTemplate = pTemplate;
387 Log(("PDM: Created internal template %p: pfnCompleted=%p pvUser2=%p\n",
388 pTemplate, pfnCompleted, pvUser2));
389 }
390
391 return rc;
392}
393
394/**
395 * Destroys the specified async completion template.
396 *
397 * @returns VBox status codes:
398 * @retval VINF_SUCCESS on success.
399 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if the template is still in use.
400 *
401 * @param pTemplate The template in question.
402 */
403VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroy(PPDMASYNCCOMPLETIONTEMPLATE pTemplate)
404{
405 LogFlow(("%s: pTemplate=%p\n", __FUNCTION__, pTemplate));
406
407 if (!pTemplate)
408 {
409 AssertMsgFailed(("pTemplate is NULL!\n"));
410 return VERR_INVALID_PARAMETER;
411 }
412
413 /*
414 * Check if the template is still used.
415 */
416 if (pTemplate->cUsed > 0)
417 {
418 AssertMsgFailed(("Template is still in use\n"));
419 return VERR_PDM_ASYNC_TEMPLATE_BUSY;
420 }
421
422 /*
423 * Unlink the template from the list.
424 */
425 PUVM pUVM = pTemplate->pVM->pUVM;
426 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
427
428 PPDMASYNCCOMPLETIONTEMPLATE pPrev = pTemplate->pPrev;
429 PPDMASYNCCOMPLETIONTEMPLATE pNext = pTemplate->pNext;
430
431 if (pPrev)
432 pPrev->pNext = pNext;
433 else
434 pUVM->pdm.s.pAsyncCompletionTemplates = pNext;
435
436 if (pNext)
437 pNext->pPrev = pPrev;
438
439 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
440
441 /*
442 * Free the template.
443 */
444 MMR3HeapFree(pTemplate);
445
446 return VINF_SUCCESS;
447}
448
449/**
450 * Destroys all the specified async completion templates for the given device instance.
451 *
452 * @returns VBox status codes:
453 * @retval VINF_SUCCESS on success.
454 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
455 *
456 * @param pVM Pointer to the shared VM structure.
457 * @param pDevIns The device instance.
458 */
459VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyDevice(PVM pVM, PPDMDEVINS pDevIns)
460{
461 LogFlow(("%s: pDevIns=%p\n", __FUNCTION__, pDevIns));
462
463 /*
464 * Validate input.
465 */
466 if (!pDevIns)
467 return VERR_INVALID_PARAMETER;
468 VM_ASSERT_EMT(pVM);
469
470 /*
471 * Unlink it.
472 */
473 PUVM pUVM = pVM->pUVM;
474 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
475 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pUVM->pdm.s.pAsyncCompletionTemplates;
476 while (pTemplate)
477 {
478 if ( pTemplate->enmType == PDMASYNCCOMPLETIONTEMPLATETYPE_DEV
479 && pTemplate->u.Dev.pDevIns == pDevIns)
480 {
481 PPDMASYNCCOMPLETIONTEMPLATE pTemplateDestroy = pTemplate;
482 pTemplate = pTemplate->pNext;
483 int rc = PDMR3AsyncCompletionTemplateDestroy(pTemplateDestroy);
484 if (RT_FAILURE(rc))
485 {
486 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
487 return rc;
488 }
489 }
490 else
491 pTemplate = pTemplate->pNext;
492 }
493
494 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
495 return VINF_SUCCESS;
496}
497
498/**
499 * Destroys all the specified async completion templates for the given driver instance.
500 *
501 * @returns VBox status codes:
502 * @retval VINF_SUCCESS on success.
503 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
504 *
505 * @param pVM Pointer to the shared VM structure.
506 * @param pDrvIns The driver instance.
507 */
508VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns)
509{
510 LogFlow(("%s: pDevIns=%p\n", __FUNCTION__, pDrvIns));
511
512 /*
513 * Validate input.
514 */
515 if (!pDrvIns)
516 return VERR_INVALID_PARAMETER;
517 VM_ASSERT_EMT(pVM);
518
519 /*
520 * Unlink it.
521 */
522 PUVM pUVM = pVM->pUVM;
523 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
524 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pUVM->pdm.s.pAsyncCompletionTemplates;
525 while (pTemplate)
526 {
527 if ( pTemplate->enmType == PDMASYNCCOMPLETIONTEMPLATETYPE_DRV
528 && pTemplate->u.Drv.pDrvIns == pDrvIns)
529 {
530 PPDMASYNCCOMPLETIONTEMPLATE pTemplateDestroy = pTemplate;
531 pTemplate = pTemplate->pNext;
532 int rc = PDMR3AsyncCompletionTemplateDestroy(pTemplateDestroy);
533 if (RT_FAILURE(rc))
534 {
535 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
536 return rc;
537 }
538 }
539 else
540 pTemplate = pTemplate->pNext;
541 }
542
543 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
544 return VINF_SUCCESS;
545}
546
547/**
548 * Destroys all the specified async completion templates for the given USB device instance.
549 *
550 * @returns VBox status codes:
551 * @retval VINF_SUCCESS on success.
552 * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
553 *
554 * @param pVM Pointer to the shared VM structure.
555 * @param pUsbIns The USB device instance.
556 */
557VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyUsb(PVM pVM, PPDMUSBINS pUsbIns)
558{
559 LogFlow(("%s: pUsbIns=%p\n", __FUNCTION__, pUsbIns));
560
561 /*
562 * Validate input.
563 */
564 if (!pUsbIns)
565 return VERR_INVALID_PARAMETER;
566 VM_ASSERT_EMT(pVM);
567
568 /*
569 * Unlink it.
570 */
571 PUVM pUVM = pVM->pUVM;
572 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
573 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pUVM->pdm.s.pAsyncCompletionTemplates;
574 while (pTemplate)
575 {
576 if ( pTemplate->enmType == PDMASYNCCOMPLETIONTEMPLATETYPE_USB
577 && pTemplate->u.Usb.pUsbIns == pUsbIns)
578 {
579 PPDMASYNCCOMPLETIONTEMPLATE pTemplateDestroy = pTemplate;
580 pTemplate = pTemplate->pNext;
581 int rc = PDMR3AsyncCompletionTemplateDestroy(pTemplateDestroy);
582 if (RT_FAILURE(rc))
583 {
584 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
585 return rc;
586 }
587 }
588 else
589 pTemplate = pTemplate->pNext;
590 }
591
592 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
593 return VINF_SUCCESS;
594}
595
596
597static PPDMACBWMGR pdmacBwMgrFindById(PPDMASYNCCOMPLETIONEPCLASS pEpClass, const char *pcszId)
598{
599 PPDMACBWMGR pBwMgr = NULL;
600
601 if (VALID_PTR(pcszId))
602 {
603 int rc;
604 rc = RTCritSectEnter(&pEpClass->CritSect);
605 AssertRC(rc);
606
607 pBwMgr = pEpClass->pBwMgrsHead;
608 while ( pBwMgr
609 && RTStrCmp(pBwMgr->pszId, pcszId))
610 pBwMgr = pBwMgr->pNext;
611
612 rc = RTCritSectLeave(&pEpClass->CritSect);
613 AssertRC(rc);
614 }
615
616 return pBwMgr;
617}
618
619static void pdmacBwMgrLink(PPDMACBWMGR pBwMgr)
620{
621 PPDMASYNCCOMPLETIONEPCLASS pEpClass = pBwMgr->pEpClass;
622 int rc;
623
624 rc = RTCritSectEnter(&pEpClass->CritSect);
625 AssertRC(rc);
626
627 pBwMgr->pNext = pEpClass->pBwMgrsHead;
628 pEpClass->pBwMgrsHead = pBwMgr;
629
630 rc = RTCritSectLeave(&pEpClass->CritSect);
631 AssertRC(rc);
632}
633
634static void pdmacBwMgrUnlink(PPDMACBWMGR pBwMgr)
635{
636 int rc;
637 PPDMASYNCCOMPLETIONEPCLASS pEpClass = pBwMgr->pEpClass;
638
639 rc = RTCritSectEnter(&pEpClass->CritSect);
640 AssertRC(rc);
641
642 if (pBwMgr == pEpClass->pBwMgrsHead)
643 pEpClass->pBwMgrsHead = pBwMgr->pNext;
644 else
645 {
646 PPDMACBWMGR pPrev = pEpClass->pBwMgrsHead;
647 while ( pPrev
648 && pPrev->pNext != pBwMgr)
649 pPrev = pPrev->pNext;
650
651 AssertPtr(pPrev);
652 pPrev->pNext = pBwMgr->pNext;
653 }
654
655 rc = RTCritSectLeave(&pEpClass->CritSect);
656 AssertRC(rc);
657}
658
659static int pdmacAsyncCompletionBwMgrCreate(PPDMASYNCCOMPLETIONEPCLASS pEpClass, const char *pcszBwMgr, uint32_t cbTransferPerSecMax,
660 uint32_t cbTransferPerSecStart, uint32_t cbTransferPerSecStep)
661{
662 int rc = VINF_SUCCESS;
663 PPDMACBWMGR pBwMgr;
664
665 LogFlowFunc(("pEpClass=%#p pcszBwMgr=%#p{%s} cbTransferPerSecMax=%u cbTransferPerSecStart=%u cbTransferPerSecStep=%u\n",
666 pEpClass, pcszBwMgr, cbTransferPerSecMax, cbTransferPerSecStart, cbTransferPerSecStep));
667
668 AssertPtrReturn(pEpClass, VERR_INVALID_POINTER);
669 AssertPtrReturn(pcszBwMgr, VERR_INVALID_POINTER);
670 AssertReturn(*pcszBwMgr != '\0', VERR_INVALID_PARAMETER);
671
672 pBwMgr = pdmacBwMgrFindById(pEpClass, pcszBwMgr);
673 if (!pBwMgr)
674 {
675 rc = MMR3HeapAllocZEx(pEpClass->pVM, MM_TAG_PDM_ASYNC_COMPLETION,
676 sizeof(PDMACBWMGR),
677 (void **)&pBwMgr);
678 if (RT_SUCCESS(rc))
679 {
680 pBwMgr->pszId = RTStrDup(pcszBwMgr);
681 if (pBwMgr->pszId)
682 {
683 pBwMgr->pEpClass = pEpClass;
684 pBwMgr->cRefs = 0;
685
686 /* Init I/O flow control. */
687 pBwMgr->cbTransferPerSecMax = cbTransferPerSecMax;
688 pBwMgr->cbTransferPerSecStart = cbTransferPerSecStart;
689 pBwMgr->cbTransferPerSecStep = cbTransferPerSecStep;
690
691 pBwMgr->cbTransferAllowed = pBwMgr->cbTransferPerSecStart;
692 pBwMgr->tsUpdatedLast = RTTimeSystemNanoTS();
693
694 pdmacBwMgrLink(pBwMgr);
695 rc = VINF_SUCCESS;
696 }
697 else
698 {
699 rc = VERR_NO_MEMORY;
700 MMR3HeapFree(pBwMgr);
701 }
702 }
703 }
704 else
705 rc = VERR_ALREADY_EXISTS;
706
707 LogFlowFunc(("returns rc=%Rc\n", rc));
708 return rc;
709}
710
711DECLINLINE(void) pdmacBwMgrRef(PPDMACBWMGR pBwMgr)
712{
713 ASMAtomicIncU32(&pBwMgr->cRefs);
714}
715
716DECLINLINE(void) pdmacBwMgrUnref(PPDMACBWMGR pBwMgr)
717{
718 Assert(pBwMgr->cRefs > 0);
719 ASMAtomicDecU32(&pBwMgr->cRefs);
720}
721
722bool pdmacEpIsTransferAllowed(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint32_t cbTransfer, RTMSINTERVAL *pmsWhenNext)
723{
724 bool fAllowed = true;
725 PPDMACBWMGR pBwMgr = ASMAtomicReadPtrT(&pEndpoint->pBwMgr, PPDMACBWMGR);
726
727 LogFlowFunc(("pEndpoint=%p pBwMgr=%p cbTransfer=%u\n", pEndpoint, pBwMgr, cbTransfer));
728
729 if (pBwMgr)
730 {
731 uint32_t cbOld = ASMAtomicSubU32(&pBwMgr->cbTransferAllowed, cbTransfer);
732 if (RT_LIKELY(cbOld >= cbTransfer))
733 fAllowed = true;
734 else
735 {
736 fAllowed = false;
737
738 /* We are out of ressources Check if we can update again. */
739 uint64_t tsNow = RTTimeSystemNanoTS();
740 uint64_t tsUpdatedLast = ASMAtomicUoReadU64(&pBwMgr->tsUpdatedLast);
741
742 if (tsNow - tsUpdatedLast >= (1000*1000*1000))
743 {
744 if (ASMAtomicCmpXchgU64(&pBwMgr->tsUpdatedLast, tsNow, tsUpdatedLast))
745 {
746 if (pBwMgr->cbTransferPerSecStart < pBwMgr->cbTransferPerSecMax)
747 {
748 pBwMgr->cbTransferPerSecStart = RT_MIN(pBwMgr->cbTransferPerSecMax, pBwMgr->cbTransferPerSecStart + pBwMgr->cbTransferPerSecStep);
749 LogFlow(("AIOMgr: Increasing maximum bandwidth to %u bytes/sec\n", pBwMgr->cbTransferPerSecStart));
750 }
751
752 /* Update */
753 ASMAtomicWriteU32(&pBwMgr->cbTransferAllowed, pBwMgr->cbTransferPerSecStart - cbTransfer);
754 fAllowed = true;
755 LogFlow(("AIOMgr: Refreshed bandwidth\n"));
756 }
757 }
758 else
759 {
760 ASMAtomicAddU32(&pBwMgr->cbTransferAllowed, cbTransfer);
761 *pmsWhenNext = ((1000*1000*1000) - (tsNow - tsUpdatedLast)) / (1000*1000);
762 }
763 }
764 }
765
766 LogFlowFunc(("fAllowed=%RTbool\n", fAllowed));
767
768 return fAllowed;
769}
770
771void pdmR3AsyncCompletionCompleteTask(PPDMASYNCCOMPLETIONTASK pTask, int rc, bool fCallCompletionHandler)
772{
773 LogFlow(("%s: pTask=%#p fCallCompletionHandler=%RTbool\n", __FUNCTION__, pTask, fCallCompletionHandler));
774
775 if (fCallCompletionHandler)
776 {
777 PPDMASYNCCOMPLETIONTEMPLATE pTemplate = pTask->pEndpoint->pTemplate;
778
779 switch (pTemplate->enmType)
780 {
781 case PDMASYNCCOMPLETIONTEMPLATETYPE_DEV:
782 {
783 pTemplate->u.Dev.pfnCompleted(pTemplate->u.Dev.pDevIns, pTask->pvUser, rc);
784 break;
785 }
786 case PDMASYNCCOMPLETIONTEMPLATETYPE_DRV:
787 {
788 pTemplate->u.Drv.pfnCompleted(pTemplate->u.Drv.pDrvIns, pTemplate->u.Drv.pvTemplateUser, pTask->pvUser, rc);
789 break;
790 }
791 case PDMASYNCCOMPLETIONTEMPLATETYPE_USB:
792 {
793 pTemplate->u.Usb.pfnCompleted(pTemplate->u.Usb.pUsbIns, pTask->pvUser, rc);
794 break;
795 }
796 case PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL:
797 {
798 pTemplate->u.Int.pfnCompleted(pTemplate->pVM, pTask->pvUser, pTemplate->u.Int.pvUser, rc);
799 break;
800 }
801 default:
802 AssertMsgFailed(("Unknown template type!\n"));
803 }
804 }
805
806 pdmR3AsyncCompletionPutTask(pTask->pEndpoint, pTask);
807}
808
809/**
810 * Worker initializing a endpoint class.
811 *
812 * @returns VBox statis code.
813 * @param pVM Pointer to the shared VM instance data.
814 * @param pEpClass Pointer to the endpoint class structure.
815 * @param pCfgHandle Pointer to the the CFGM tree.
816 */
817int pdmR3AsyncCompletionEpClassInit(PVM pVM, PCPDMASYNCCOMPLETIONEPCLASSOPS pEpClassOps, PCFGMNODE pCfgHandle)
818{
819 int rc = VINF_SUCCESS;
820
821 /* Validate input. */
822 if ( !pEpClassOps
823 || (pEpClassOps->u32Version != PDMAC_EPCLASS_OPS_VERSION)
824 || (pEpClassOps->u32VersionEnd != PDMAC_EPCLASS_OPS_VERSION))
825 AssertMsgFailedReturn(("Invalid endpoint class data\n"), VERR_VERSION_MISMATCH);
826
827 LogFlowFunc((": pVM=%p pEpClassOps=%p{%s}\n", pVM, pEpClassOps, pEpClassOps->pcszName));
828
829 /* Allocate global class data. */
830 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = NULL;
831
832 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION,
833 pEpClassOps->cbEndpointClassGlobal,
834 (void **)&pEndpointClass);
835 if (RT_SUCCESS(rc))
836 {
837 /* Initialize common data. */
838 pEndpointClass->pVM = pVM;
839 pEndpointClass->pEndpointOps = pEpClassOps;
840
841 rc = RTCritSectInit(&pEndpointClass->CritSect);
842 if (RT_SUCCESS(rc))
843 {
844 PCFGMNODE pCfgNodeClass = CFGMR3GetChild(pCfgHandle, pEpClassOps->pcszName);
845
846 /* Create task cache */
847 rc = RTMemCacheCreate(&pEndpointClass->hMemCacheTasks, pEpClassOps->cbTask,
848 0, UINT32_MAX, NULL, NULL, NULL, 0);
849 if (RT_SUCCESS(rc))
850 {
851 /* Call the specific endpoint class initializer. */
852 rc = pEpClassOps->pfnInitialize(pEndpointClass, pCfgNodeClass);
853 if (RT_SUCCESS(rc))
854 {
855 /* Create all bandwidth groups for resource control. */
856 PCFGMNODE pCfgBwGrp = CFGMR3GetChild(pCfgNodeClass, "BwGroups");
857
858 if (pCfgBwGrp)
859 {
860 for (PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgBwGrp); pCur; pCur = CFGMR3GetNextChild(pCur))
861 {
862 uint32_t cbMax, cbStart, cbStep;
863 size_t cchName = CFGMR3GetNameLen(pCur) + 1;
864 char *pszBwGrpId = (char *)RTMemAllocZ(cchName);
865
866 if (!pszBwGrpId)
867 {
868 rc = VERR_NO_MEMORY;
869 break;
870 }
871
872 rc = CFGMR3GetName(pCur, pszBwGrpId, cchName);
873 AssertRC(rc);
874
875 if (RT_SUCCESS(rc))
876 rc = CFGMR3QueryU32(pCur, "Start", &cbStart);
877 if (RT_SUCCESS(rc))
878 rc = CFGMR3QueryU32(pCur, "Max", &cbMax);
879 if (RT_SUCCESS(rc))
880 rc = CFGMR3QueryU32(pCur, "Step", &cbStep);
881 if (RT_SUCCESS(rc))
882 rc = pdmacAsyncCompletionBwMgrCreate(pEndpointClass, pszBwGrpId, cbMax, cbStart, cbStep);
883
884 RTMemFree(pszBwGrpId);
885
886 if (RT_FAILURE(rc))
887 break;
888 }
889 }
890
891 if (RT_SUCCESS(rc))
892 {
893 PUVM pUVM = pVM->pUVM;
894 AssertMsg(!pUVM->pdm.s.apAsyncCompletionEndpointClass[pEpClassOps->enmClassType],
895 ("Endpoint class was already initialized\n"));
896
897 pUVM->pdm.s.apAsyncCompletionEndpointClass[pEpClassOps->enmClassType] = pEndpointClass;
898 LogFlowFunc((": Initialized endpoint class \"%s\" rc=%Rrc\n", pEpClassOps->pcszName, rc));
899 return VINF_SUCCESS;
900 }
901 }
902 RTMemCacheDestroy(pEndpointClass->hMemCacheTasks);
903 }
904 RTCritSectDelete(&pEndpointClass->CritSect);
905 }
906 MMR3HeapFree(pEndpointClass);
907 }
908
909 LogFlowFunc((": Failed to initialize endpoint class rc=%Rrc\n", rc));
910
911 return rc;
912}
913
914/**
915 * Worker terminating all endpoint classes.
916 *
917 * @returns nothing
918 * @param pEndpointClass Pointer to the endpoint class to terminate.
919 *
920 * @remarks This method ensures that any still open endpoint is closed.
921 */
922static void pdmR3AsyncCompletionEpClassTerminate(PPDMASYNCCOMPLETIONEPCLASS pEndpointClass)
923{
924 int rc = VINF_SUCCESS;
925 PVM pVM = pEndpointClass->pVM;
926
927 /* Close all still open endpoints. */
928 while (pEndpointClass->pEndpointsHead)
929 PDMR3AsyncCompletionEpClose(pEndpointClass->pEndpointsHead);
930
931 /* Destroy the bandwidth managers. */
932 PPDMACBWMGR pBwMgr = pEndpointClass->pBwMgrsHead;
933 while (pBwMgr)
934 {
935 PPDMACBWMGR pFree = pBwMgr;
936 pBwMgr = pBwMgr->pNext;
937 MMR3HeapFree(pFree);
938 }
939
940 /* Call the termination callback of the class. */
941 pEndpointClass->pEndpointOps->pfnTerminate(pEndpointClass);
942
943 RTMemCacheDestroy(pEndpointClass->hMemCacheTasks);
944 RTCritSectDelete(&pEndpointClass->CritSect);
945
946 /* Free the memory of the class finally and clear the entry in the class array. */
947 pVM->pUVM->pdm.s.apAsyncCompletionEndpointClass[pEndpointClass->pEndpointOps->enmClassType] = NULL;
948 MMR3HeapFree(pEndpointClass);
949}
950
951/**
952 * Initialize the async completion manager.
953 *
954 * @returns VBox status code
955 * @param pVM Pointer to the shared VM structure.
956 */
957int pdmR3AsyncCompletionInit(PVM pVM)
958{
959 int rc = VINF_SUCCESS;
960 PUVM pUVM = pVM->pUVM;
961
962 LogFlowFunc((": pVM=%p\n", pVM));
963
964 VM_ASSERT_EMT(pVM);
965
966 PCFGMNODE pCfgRoot = CFGMR3GetRoot(pVM);
967 PCFGMNODE pCfgAsyncCompletion = CFGMR3GetChild(CFGMR3GetChild(pCfgRoot, "PDM"), "AsyncCompletion");
968
969 rc = pdmR3AsyncCompletionEpClassInit(pVM, &g_PDMAsyncCompletionEndpointClassFile, pCfgAsyncCompletion);
970
971 LogFlowFunc((": pVM=%p rc=%Rrc\n", pVM, rc));
972
973 return rc;
974}
975
976/**
977 * Terminates the async completion manager.
978 *
979 * @returns VBox status code
980 * @param pVM Pointer to the shared VM structure.
981 */
982int pdmR3AsyncCompletionTerm(PVM pVM)
983{
984 LogFlowFunc((": pVM=%p\n", pVM));
985 PUVM pUVM = pVM->pUVM;
986
987 for (size_t i = 0; i < RT_ELEMENTS(pUVM->pdm.s.apAsyncCompletionEndpointClass); i++)
988 if (pUVM->pdm.s.apAsyncCompletionEndpointClass[i])
989 pdmR3AsyncCompletionEpClassTerminate(pUVM->pdm.s.apAsyncCompletionEndpointClass[i]);
990
991 return VINF_SUCCESS;
992}
993
994/**
995 * Resume worker for the async completion manager.
996 *
997 * @returns nothing.
998 * @param pVM Pointer to the shared VM structure.
999 */
1000void pdmR3AsyncCompletionResume(PVM pVM)
1001{
1002 LogFlowFunc((": pVM=%p\n", pVM));
1003 PUVM pUVM = pVM->pUVM;
1004
1005 /* Log the bandwidth groups and all assigned endpoints. */
1006 for (size_t i = 0; i < RT_ELEMENTS(pUVM->pdm.s.apAsyncCompletionEndpointClass); i++)
1007 if (pUVM->pdm.s.apAsyncCompletionEndpointClass[i])
1008 {
1009 PPDMASYNCCOMPLETIONEPCLASS pEpClass = pUVM->pdm.s.apAsyncCompletionEndpointClass[i];
1010 PPDMASYNCCOMPLETIONENDPOINT pEp;
1011 PPDMACBWMGR pBwMgr = pEpClass->pBwMgrsHead;
1012
1013 if (pBwMgr)
1014 LogRel(("AIOMgr: Bandwidth groups for class '%s'\n", i == PDMASYNCCOMPLETIONEPCLASSTYPE_FILE
1015 ? "File" : "<Unknown>"));
1016
1017 while (pBwMgr)
1018 {
1019 LogRel(("AIOMgr: Id: %s\n", pBwMgr->pszId));
1020 LogRel(("AIOMgr: Max: %u B/s\n", pBwMgr->cbTransferPerSecMax));
1021 LogRel(("AIOMgr: Start: %u B/s\n", pBwMgr->cbTransferPerSecStart));
1022 LogRel(("AIOMgr: Step: %u B/s\n", pBwMgr->cbTransferPerSecStep));
1023 LogRel(("AIOMgr: Endpoints:\n"));
1024
1025 pEp = pEpClass->pEndpointsHead;
1026 while (pEp)
1027 {
1028 if (pEp->pBwMgr == pBwMgr)
1029 LogRel(("AIOMgr: %s\n", pEp->pszUri));
1030
1031 pEp = pEp->pNext;
1032 }
1033
1034 pBwMgr = pBwMgr->pNext;
1035 }
1036
1037 /* Print all endpoints without assigned bandwidth groups. */
1038 pEp = pEpClass->pEndpointsHead;
1039 if (pEp)
1040 LogRel(("AIOMgr: Endpoints without assigned bandwidth groups:\n"));
1041
1042 while (pEp)
1043 {
1044 if (!pEp->pBwMgr)
1045 LogRel(("AIOMgr: %s\n", pEp->pszUri));
1046
1047 pEp = pEp->pNext;
1048 }
1049 }
1050}
1051
1052/**
1053 * Tries to get a free task from the endpoint or class cache
1054 * allocating the task if it fails.
1055 *
1056 * @returns Pointer to a new and initialized task or NULL
1057 * @param pEndpoint The endpoint the task is for.
1058 * @param pvUser Opaque user data for the task.
1059 */
1060static PPDMASYNCCOMPLETIONTASK pdmR3AsyncCompletionGetTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser)
1061{
1062 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
1063 PPDMASYNCCOMPLETIONTASK pTask = NULL;
1064
1065 pTask = (PPDMASYNCCOMPLETIONTASK)RTMemCacheAlloc(pEndpointClass->hMemCacheTasks);
1066
1067 if (RT_LIKELY(pTask))
1068 {
1069 /* Get ID of the task. */
1070 pTask->uTaskId = ASMAtomicIncU32(&pEndpoint->uTaskIdNext);
1071
1072 /* Initialize common parts. */
1073 pTask->pvUser = pvUser;
1074 pTask->pEndpoint = pEndpoint;
1075 /* Clear list pointers for safety. */
1076 pTask->pPrev = NULL;
1077 pTask->pNext = NULL;
1078 pTask->tsNsStart = RTTimeNanoTS();
1079#ifdef VBOX_WITH_STATISTICS
1080 STAM_COUNTER_INC(&pEndpoint->StatIoOpsStarted);
1081#endif
1082 }
1083
1084 return pTask;
1085}
1086
1087/**
1088 * Puts a task in one of the caches.
1089 *
1090 * @returns nothing.
1091 * @param pEndpoint The endpoint the task belongs to.
1092 * @param pTask The task to cache.
1093 */
1094static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask)
1095{
1096 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
1097 uint64_t tsRun = RTTimeNanoTS() - pTask->tsNsStart;
1098
1099 if (RT_UNLIKELY(tsRun >= (uint64_t)10*1000*1000*1000))
1100 {
1101 LogRel(("AsyncCompletion: Task %#p completed after %llu seconds\n", pTask, tsRun / ((uint64_t)1000*1000*1000)));
1102 }
1103
1104#ifdef VBOX_WITH_STATISTICS
1105 uint64_t iStatIdx;
1106
1107 if (tsRun < 1000)
1108 {
1109 /* Update nanoseconds statistics */
1110 iStatIdx = tsRun / 100;
1111 STAM_COUNTER_INC(&pEndpoint->StatTaskRunTimesNs[iStatIdx]);
1112 }
1113 else
1114 {
1115 tsRun /= 1000;
1116
1117 if (tsRun < 1000)
1118 {
1119 /* Update microsecnds statistics */
1120 iStatIdx = tsRun / 100;
1121 STAM_COUNTER_INC(&pEndpoint->StatTaskRunTimesMicroSec[iStatIdx]);
1122 }
1123 else
1124 {
1125 tsRun /= 1000;
1126
1127 if (tsRun < 1000)
1128 {
1129 /* Update milliseconds statistics */
1130 iStatIdx = tsRun / 100;
1131 STAM_COUNTER_INC(&pEndpoint->StatTaskRunTimesMs[iStatIdx]);
1132 }
1133 else
1134 {
1135 tsRun /= 1000;
1136
1137 if (tsRun < 1000)
1138 {
1139 /* Update seconds statistics */
1140 iStatIdx = tsRun / 10;
1141 STAM_COUNTER_INC(&pEndpoint->StatTaskRunTimesSec[iStatIdx]);
1142 }
1143 else
1144 STAM_COUNTER_INC(&pEndpoint->StatTaskRunOver100Sec);
1145 }
1146 }
1147 }
1148
1149 STAM_COUNTER_INC(&pEndpoint->StatIoOpsCompleted);
1150 pEndpoint->cIoOpsCompleted++;
1151 uint64_t tsMsCur = RTTimeMilliTS();
1152 uint64_t tsInterval = tsMsCur - pEndpoint->tsIntervalStartMs;
1153
1154 if (tsInterval >= 1000)
1155 {
1156 pEndpoint->StatIoOpsPerSec.c = pEndpoint->cIoOpsCompleted / (tsInterval / 1000);
1157 pEndpoint->tsIntervalStartMs = tsMsCur;
1158 pEndpoint->cIoOpsCompleted = 0;
1159 }
1160#endif
1161
1162 RTMemCacheFree(pEndpointClass->hMemCacheTasks, pTask);
1163}
1164
1165static PPDMASYNCCOMPLETIONENDPOINT pdmR3AsyncCompletionFindEndpointWithUri(PPDMASYNCCOMPLETIONEPCLASS pEndpointClass,
1166 const char *pszUri)
1167{
1168 PPDMASYNCCOMPLETIONENDPOINT pEndpoint = pEndpointClass->pEndpointsHead;
1169
1170 while (pEndpoint)
1171 {
1172 if (!RTStrCmp(pEndpoint->pszUri, pszUri))
1173 return pEndpoint;
1174
1175 pEndpoint = pEndpoint->pNext;
1176 }
1177
1178 return NULL;
1179}
1180
1181VMMR3DECL(int) PDMR3AsyncCompletionEpCreateForFile(PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint,
1182 const char *pszFilename, uint32_t fFlags,
1183 PPDMASYNCCOMPLETIONTEMPLATE pTemplate)
1184{
1185 int rc = VINF_SUCCESS;
1186
1187 LogFlowFunc((": ppEndpoint=%p pszFilename=%p{%s} fFlags=%u pTemplate=%p\n",
1188 ppEndpoint, pszFilename, pszFilename, fFlags, pTemplate));
1189
1190 /* Sanity checks. */
1191 AssertReturn(VALID_PTR(ppEndpoint), VERR_INVALID_POINTER);
1192 AssertReturn(VALID_PTR(pszFilename), VERR_INVALID_POINTER);
1193 AssertReturn(VALID_PTR(pTemplate), VERR_INVALID_POINTER);
1194
1195 /* Check that the flags are valid. */
1196 AssertReturn(((~(PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_CACHING | PDMACEP_FILE_FLAGS_DONT_LOCK) & fFlags) == 0),
1197 VERR_INVALID_PARAMETER);
1198
1199 PVM pVM = pTemplate->pVM;
1200 PUVM pUVM = pVM->pUVM;
1201 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pUVM->pdm.s.apAsyncCompletionEndpointClass[PDMASYNCCOMPLETIONEPCLASSTYPE_FILE];
1202 PPDMASYNCCOMPLETIONENDPOINT pEndpoint = NULL;
1203
1204 AssertMsg(pEndpointClass, ("File endpoint class was not initialized\n"));
1205
1206 /* Search for a already opened endpoint for this file. */
1207 pEndpoint = pdmR3AsyncCompletionFindEndpointWithUri(pEndpointClass, pszFilename);
1208
1209 if(!pEndpoint)
1210 {
1211 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION,
1212 pEndpointClass->pEndpointOps->cbEndpoint,
1213 (void **)&pEndpoint);
1214 if (RT_SUCCESS(rc))
1215 {
1216
1217 /* Initialize common parts. */
1218 pEndpoint->pNext = NULL;
1219 pEndpoint->pPrev = NULL;
1220 pEndpoint->pEpClass = pEndpointClass;
1221 pEndpoint->uTaskIdNext = 0;
1222 pEndpoint->fTaskIdWraparound = false;
1223 pEndpoint->pTemplate = pTemplate;
1224 pEndpoint->pszUri = RTStrDup(pszFilename);
1225 pEndpoint->cUsers = 1;
1226 pEndpoint->pBwMgr = NULL;
1227
1228#ifdef VBOX_WITH_STATISTICS
1229 /* Init the statistics part */
1230 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesNs); i++)
1231 {
1232 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesNs[i], STAMTYPE_COUNTER,
1233 STAMVISIBILITY_USED,
1234 STAMUNIT_OCCURENCES,
1235 "Nanosecond resolution runtime statistics",
1236 "/PDM/AsyncCompletion/File/%s/TaskRun1Ns-%u-%u",
1237 RTPathFilename(pEndpoint->pszUri),
1238 i*100, i*100+100-1);
1239 if (RT_FAILURE(rc))
1240 break;
1241 }
1242
1243 if (RT_SUCCESS(rc))
1244 {
1245 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMicroSec); i++)
1246 {
1247 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesMicroSec[i], STAMTYPE_COUNTER,
1248 STAMVISIBILITY_USED,
1249 STAMUNIT_OCCURENCES,
1250 "Microsecond resolution runtime statistics",
1251 "/PDM/AsyncCompletion/File/%s/TaskRun2MicroSec-%u-%u",
1252 RTPathFilename(pEndpoint->pszUri),
1253 i*100, i*100+100-1);
1254 if (RT_FAILURE(rc))
1255 break;
1256 }
1257 }
1258
1259 if (RT_SUCCESS(rc))
1260 {
1261 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs); i++)
1262 {
1263 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesMs[i], STAMTYPE_COUNTER,
1264 STAMVISIBILITY_USED,
1265 STAMUNIT_OCCURENCES,
1266 "Milliseconds resolution runtime statistics",
1267 "/PDM/AsyncCompletion/File/%s/TaskRun3Ms-%u-%u",
1268 RTPathFilename(pEndpoint->pszUri),
1269 i*100, i*100+100-1);
1270 if (RT_FAILURE(rc))
1271 break;
1272 }
1273 }
1274
1275 if (RT_SUCCESS(rc))
1276 {
1277 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs); i++)
1278 {
1279 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesSec[i], STAMTYPE_COUNTER,
1280 STAMVISIBILITY_USED,
1281 STAMUNIT_OCCURENCES,
1282 "Second resolution runtime statistics",
1283 "/PDM/AsyncCompletion/File/%s/TaskRun4Sec-%u-%u",
1284 RTPathFilename(pEndpoint->pszUri),
1285 i*10, i*10+10-1);
1286 if (RT_FAILURE(rc))
1287 break;
1288 }
1289 }
1290
1291 if (RT_SUCCESS(rc))
1292 {
1293 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunOver100Sec, STAMTYPE_COUNTER,
1294 STAMVISIBILITY_USED,
1295 STAMUNIT_OCCURENCES,
1296 "Tasks which ran more than 100sec",
1297 "/PDM/AsyncCompletion/File/%s/TaskRunSecGreater100Sec",
1298 RTPathFilename(pEndpoint->pszUri));
1299 }
1300
1301 if (RT_SUCCESS(rc))
1302 {
1303 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsPerSec, STAMTYPE_COUNTER,
1304 STAMVISIBILITY_ALWAYS,
1305 STAMUNIT_OCCURENCES,
1306 "Processed I/O operations per second",
1307 "/PDM/AsyncCompletion/File/%s/IoOpsPerSec",
1308 RTPathFilename(pEndpoint->pszUri));
1309 }
1310
1311 if (RT_SUCCESS(rc))
1312 {
1313 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsStarted, STAMTYPE_COUNTER,
1314 STAMVISIBILITY_ALWAYS,
1315 STAMUNIT_OCCURENCES,
1316 "Started I/O operations for this endpoint",
1317 "/PDM/AsyncCompletion/File/%s/IoOpsStarted",
1318 RTPathFilename(pEndpoint->pszUri));
1319 }
1320
1321 if (RT_SUCCESS(rc))
1322 {
1323 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsCompleted, STAMTYPE_COUNTER,
1324 STAMVISIBILITY_ALWAYS,
1325 STAMUNIT_OCCURENCES,
1326 "Completed I/O operations for this endpoint",
1327 "/PDM/AsyncCompletion/File/%s/IoOpsCompleted",
1328 RTPathFilename(pEndpoint->pszUri));
1329 }
1330
1331 pEndpoint->tsIntervalStartMs = RTTimeMilliTS();
1332#endif
1333
1334 if ( pEndpoint->pszUri
1335 && RT_SUCCESS(rc))
1336 {
1337 /* Call the initializer for the endpoint. */
1338 rc = pEndpointClass->pEndpointOps->pfnEpInitialize(pEndpoint, pszFilename, fFlags);
1339 if (RT_SUCCESS(rc))
1340 {
1341 /* Link it into the list of endpoints. */
1342 rc = RTCritSectEnter(&pEndpointClass->CritSect);
1343 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1344
1345 pEndpoint->pNext = pEndpointClass->pEndpointsHead;
1346 if (pEndpointClass->pEndpointsHead)
1347 pEndpointClass->pEndpointsHead->pPrev = pEndpoint;
1348
1349 pEndpointClass->pEndpointsHead = pEndpoint;
1350 pEndpointClass->cEndpoints++;
1351
1352 rc = RTCritSectLeave(&pEndpointClass->CritSect);
1353 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1354
1355 /* Reference the template. */
1356 ASMAtomicIncU32(&pTemplate->cUsed);
1357
1358 *ppEndpoint = pEndpoint;
1359
1360 LogFlowFunc((": Created endpoint for %s: rc=%Rrc\n", pszFilename, rc));
1361 return VINF_SUCCESS;
1362 }
1363 RTStrFree(pEndpoint->pszUri);
1364 }
1365 MMR3HeapFree(pEndpoint);
1366 }
1367 }
1368 else
1369 {
1370 /* Endpoint found. */
1371 pEndpoint->cUsers++;
1372
1373 *ppEndpoint = pEndpoint;
1374 return VINF_SUCCESS;
1375 }
1376
1377 LogFlowFunc((": Creation of endpoint for %s failed: rc=%Rrc\n", pszFilename, rc));
1378
1379 return rc;
1380}
1381
1382VMMR3DECL(void) PDMR3AsyncCompletionEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
1383{
1384 LogFlowFunc((": pEndpoint=%p\n", pEndpoint));
1385
1386 /* Sanity checks. */
1387 AssertReturnVoid(VALID_PTR(pEndpoint));
1388
1389 pEndpoint->cUsers--;
1390
1391 /* If the last user closed the endpoint we will free it. */
1392 if (!pEndpoint->cUsers)
1393 {
1394 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
1395 pEndpointClass->pEndpointOps->pfnEpClose(pEndpoint);
1396
1397 /* Drop reference from the template. */
1398 ASMAtomicDecU32(&pEndpoint->pTemplate->cUsed);
1399
1400 /* Unlink the endpoint from the list. */
1401 int rc = RTCritSectEnter(&pEndpointClass->CritSect);
1402 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1403
1404 PPDMASYNCCOMPLETIONENDPOINT pEndpointNext = pEndpoint->pNext;
1405 PPDMASYNCCOMPLETIONENDPOINT pEndpointPrev = pEndpoint->pPrev;
1406
1407 if (pEndpointPrev)
1408 pEndpointPrev->pNext = pEndpointNext;
1409 else
1410 pEndpointClass->pEndpointsHead = pEndpointNext;
1411 if (pEndpointNext)
1412 pEndpointNext->pPrev = pEndpointPrev;
1413
1414 pEndpointClass->cEndpoints--;
1415
1416 rc = RTCritSectLeave(&pEndpointClass->CritSect);
1417 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1418
1419#ifdef VBOX_WITH_STATISTICS
1420 /* Deregister the statistics part */
1421 PVM pVM = pEndpointClass->pVM;
1422
1423 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesNs); i++)
1424 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunTimesNs[i]);
1425 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMicroSec); i++)
1426 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunTimesMicroSec[i]);
1427 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs); i++)
1428 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunTimesMs[i]);
1429 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs); i++)
1430 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunTimesSec[i]);
1431
1432 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunOver100Sec);
1433 STAMR3Deregister(pVM, &pEndpoint->StatIoOpsPerSec);
1434 STAMR3Deregister(pVM, &pEndpoint->StatIoOpsStarted);
1435 STAMR3Deregister(pVM, &pEndpoint->StatIoOpsCompleted);
1436#endif
1437
1438 RTStrFree(pEndpoint->pszUri);
1439 MMR3HeapFree(pEndpoint);
1440 }
1441}
1442
1443VMMR3DECL(int) PDMR3AsyncCompletionEpRead(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
1444 PCRTSGSEG paSegments, unsigned cSegments,
1445 size_t cbRead, void *pvUser,
1446 PPPDMASYNCCOMPLETIONTASK ppTask)
1447{
1448 int rc = VINF_SUCCESS;
1449
1450 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1451 AssertReturn(VALID_PTR(paSegments), VERR_INVALID_POINTER);
1452 AssertReturn(VALID_PTR(ppTask), VERR_INVALID_POINTER);
1453 AssertReturn(cSegments > 0, VERR_INVALID_PARAMETER);
1454 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
1455 AssertReturn(off >= 0, VERR_INVALID_PARAMETER);
1456
1457 PPDMASYNCCOMPLETIONTASK pTask;
1458
1459 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1460 if (!pTask)
1461 return VERR_NO_MEMORY;
1462
1463 rc = pEndpoint->pEpClass->pEndpointOps->pfnEpRead(pTask, pEndpoint, off,
1464 paSegments, cSegments, cbRead);
1465 if (RT_SUCCESS(rc))
1466 {
1467 *ppTask = pTask;
1468 }
1469 else
1470 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1471
1472 return rc;
1473}
1474
1475VMMR3DECL(int) PDMR3AsyncCompletionEpWrite(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
1476 PCRTSGSEG paSegments, unsigned cSegments,
1477 size_t cbWrite, void *pvUser,
1478 PPPDMASYNCCOMPLETIONTASK ppTask)
1479{
1480 int rc = VINF_SUCCESS;
1481
1482 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1483 AssertReturn(VALID_PTR(paSegments), VERR_INVALID_POINTER);
1484 AssertReturn(VALID_PTR(ppTask), VERR_INVALID_POINTER);
1485 AssertReturn(cSegments > 0, VERR_INVALID_PARAMETER);
1486 AssertReturn(cbWrite > 0, VERR_INVALID_PARAMETER);
1487 AssertReturn(off >= 0, VERR_INVALID_PARAMETER);
1488
1489 PPDMASYNCCOMPLETIONTASK pTask;
1490
1491 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1492 if (!pTask)
1493 return VERR_NO_MEMORY;
1494
1495 rc = pEndpoint->pEpClass->pEndpointOps->pfnEpWrite(pTask, pEndpoint, off,
1496 paSegments, cSegments, cbWrite);
1497 if (RT_SUCCESS(rc))
1498 {
1499 *ppTask = pTask;
1500 }
1501 else
1502 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1503
1504 return rc;
1505}
1506
1507VMMR3DECL(int) PDMR3AsyncCompletionEpFlush(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1508 void *pvUser,
1509 PPPDMASYNCCOMPLETIONTASK ppTask)
1510{
1511 int rc = VINF_SUCCESS;
1512
1513 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1514 AssertReturn(VALID_PTR(ppTask), VERR_INVALID_POINTER);
1515
1516 PPDMASYNCCOMPLETIONTASK pTask;
1517
1518 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1519 if (!pTask)
1520 return VERR_NO_MEMORY;
1521
1522 rc = pEndpoint->pEpClass->pEndpointOps->pfnEpFlush(pTask, pEndpoint);
1523 if (RT_SUCCESS(rc))
1524 {
1525 *ppTask = pTask;
1526 }
1527 else
1528 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1529
1530 return rc;
1531}
1532
1533VMMR3DECL(int) PDMR3AsyncCompletionEpGetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1534 uint64_t *pcbSize)
1535{
1536 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1537 AssertReturn(VALID_PTR(pcbSize), VERR_INVALID_POINTER);
1538
1539 if (pEndpoint->pEpClass->pEndpointOps->pfnEpGetSize)
1540 return pEndpoint->pEpClass->pEndpointOps->pfnEpGetSize(pEndpoint, pcbSize);
1541 else
1542 return VERR_NOT_SUPPORTED;
1543}
1544
1545VMMR3DECL(int) PDMR3AsyncCompletionEpSetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1546 uint64_t cbSize)
1547{
1548 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1549
1550 if (pEndpoint->pEpClass->pEndpointOps->pfnEpSetSize)
1551 return pEndpoint->pEpClass->pEndpointOps->pfnEpSetSize(pEndpoint, cbSize);
1552 else
1553 return VERR_NOT_SUPPORTED;
1554}
1555
1556VMMR3DECL(int) PDMR3AsyncCompletionEpSetBwMgr(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1557 const char *pcszBwMgr)
1558{
1559 int rc = VINF_SUCCESS;
1560 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1561 PPDMACBWMGR pBwMgrOld = NULL;
1562 PPDMACBWMGR pBwMgrNew = NULL;
1563
1564 if (pcszBwMgr)
1565 {
1566 pBwMgrNew = pdmacBwMgrFindById(pEndpoint->pEpClass, pcszBwMgr);
1567
1568 if (pBwMgrNew)
1569 pdmacBwMgrRef(pBwMgrNew);
1570 else
1571 rc = VERR_NOT_FOUND;
1572 }
1573
1574 if (RT_SUCCESS(rc))
1575 {
1576 pBwMgrOld = ASMAtomicXchgPtrT(&pEndpoint->pBwMgr, pBwMgrNew, PPDMACBWMGR);
1577
1578 if (pBwMgrOld)
1579 pdmacBwMgrUnref(pBwMgrOld);
1580 }
1581
1582 return rc;
1583}
1584
1585VMMR3DECL(int) PDMR3AsyncCompletionTaskCancel(PPDMASYNCCOMPLETIONTASK pTask)
1586{
1587 return VERR_NOT_IMPLEMENTED;
1588}
1589
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