VirtualBox

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

Last change on this file since 39078 was 39078, checked in by vboxsync, 13 years ago

VMM: -Wunused-parameter

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