VirtualBox

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

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

AsyncCompletion: Alignment assertions and remove a bit of unused code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 53.1 KB
Line 
1/* $Id: PDMAsyncCompletion.cpp 33840 2010-11-08 13:44:38Z 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 argument 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 /** Identifier 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 resources 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 status 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 /* Initialize common parts. */
1070 pTask->pvUser = pvUser;
1071 pTask->pEndpoint = pEndpoint;
1072 /* Clear list pointers for safety. */
1073 pTask->pPrev = NULL;
1074 pTask->pNext = NULL;
1075 pTask->tsNsStart = RTTimeNanoTS();
1076#ifdef VBOX_WITH_STATISTICS
1077 STAM_COUNTER_INC(&pEndpoint->StatIoOpsStarted);
1078#endif
1079 }
1080
1081 return pTask;
1082}
1083
1084/**
1085 * Puts a task in one of the caches.
1086 *
1087 * @returns nothing.
1088 * @param pEndpoint The endpoint the task belongs to.
1089 * @param pTask The task to cache.
1090 */
1091static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask)
1092{
1093 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
1094 uint64_t tsRun = RTTimeNanoTS() - pTask->tsNsStart;
1095
1096 if (RT_UNLIKELY(tsRun >= (uint64_t)10*1000*1000*1000))
1097 {
1098 LogRel(("AsyncCompletion: Task %#p completed after %llu seconds\n", pTask, tsRun / ((uint64_t)1000*1000*1000)));
1099 }
1100
1101#ifdef VBOX_WITH_STATISTICS
1102 uint64_t iStatIdx;
1103
1104 if (tsRun < 1000)
1105 {
1106 /* Update nanoseconds statistics */
1107 iStatIdx = tsRun / 100;
1108 STAM_COUNTER_INC(&pEndpoint->StatTaskRunTimesNs[iStatIdx]);
1109 }
1110 else
1111 {
1112 tsRun /= 1000;
1113
1114 if (tsRun < 1000)
1115 {
1116 /* Update microsecnds statistics */
1117 iStatIdx = tsRun / 100;
1118 STAM_COUNTER_INC(&pEndpoint->StatTaskRunTimesMicroSec[iStatIdx]);
1119 }
1120 else
1121 {
1122 tsRun /= 1000;
1123
1124 if (tsRun < 1000)
1125 {
1126 /* Update milliseconds statistics */
1127 iStatIdx = tsRun / 100;
1128 STAM_COUNTER_INC(&pEndpoint->StatTaskRunTimesMs[iStatIdx]);
1129 }
1130 else
1131 {
1132 tsRun /= 1000;
1133
1134 if (tsRun < 1000)
1135 {
1136 /* Update seconds statistics */
1137 iStatIdx = tsRun / 10;
1138 STAM_COUNTER_INC(&pEndpoint->StatTaskRunTimesSec[iStatIdx]);
1139 }
1140 else
1141 STAM_COUNTER_INC(&pEndpoint->StatTaskRunOver100Sec);
1142 }
1143 }
1144 }
1145
1146 STAM_COUNTER_INC(&pEndpoint->StatIoOpsCompleted);
1147 pEndpoint->cIoOpsCompleted++;
1148 uint64_t tsMsCur = RTTimeMilliTS();
1149 uint64_t tsInterval = tsMsCur - pEndpoint->tsIntervalStartMs;
1150
1151 if (tsInterval >= 1000)
1152 {
1153 pEndpoint->StatIoOpsPerSec.c = pEndpoint->cIoOpsCompleted / (tsInterval / 1000);
1154 pEndpoint->tsIntervalStartMs = tsMsCur;
1155 pEndpoint->cIoOpsCompleted = 0;
1156 }
1157#endif
1158
1159 RTMemCacheFree(pEndpointClass->hMemCacheTasks, pTask);
1160}
1161
1162static PPDMASYNCCOMPLETIONENDPOINT pdmR3AsyncCompletionFindEndpointWithUri(PPDMASYNCCOMPLETIONEPCLASS pEndpointClass,
1163 const char *pszUri)
1164{
1165 PPDMASYNCCOMPLETIONENDPOINT pEndpoint = pEndpointClass->pEndpointsHead;
1166
1167 while (pEndpoint)
1168 {
1169 if (!RTStrCmp(pEndpoint->pszUri, pszUri))
1170 return pEndpoint;
1171
1172 pEndpoint = pEndpoint->pNext;
1173 }
1174
1175 return NULL;
1176}
1177
1178VMMR3DECL(int) PDMR3AsyncCompletionEpCreateForFile(PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint,
1179 const char *pszFilename, uint32_t fFlags,
1180 PPDMASYNCCOMPLETIONTEMPLATE pTemplate)
1181{
1182 int rc = VINF_SUCCESS;
1183
1184 LogFlowFunc((": ppEndpoint=%p pszFilename=%p{%s} fFlags=%u pTemplate=%p\n",
1185 ppEndpoint, pszFilename, pszFilename, fFlags, pTemplate));
1186
1187 /* Sanity checks. */
1188 AssertReturn(VALID_PTR(ppEndpoint), VERR_INVALID_POINTER);
1189 AssertReturn(VALID_PTR(pszFilename), VERR_INVALID_POINTER);
1190 AssertReturn(VALID_PTR(pTemplate), VERR_INVALID_POINTER);
1191
1192 /* Check that the flags are valid. */
1193 AssertReturn(((~(PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_CACHING | PDMACEP_FILE_FLAGS_DONT_LOCK) & fFlags) == 0),
1194 VERR_INVALID_PARAMETER);
1195
1196 PVM pVM = pTemplate->pVM;
1197 PUVM pUVM = pVM->pUVM;
1198 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pUVM->pdm.s.apAsyncCompletionEndpointClass[PDMASYNCCOMPLETIONEPCLASSTYPE_FILE];
1199 PPDMASYNCCOMPLETIONENDPOINT pEndpoint = NULL;
1200
1201 AssertMsg(pEndpointClass, ("File endpoint class was not initialized\n"));
1202
1203 /* Search for a already opened endpoint for this file. */
1204 pEndpoint = pdmR3AsyncCompletionFindEndpointWithUri(pEndpointClass, pszFilename);
1205
1206 if(!pEndpoint)
1207 {
1208 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION,
1209 pEndpointClass->pEndpointOps->cbEndpoint,
1210 (void **)&pEndpoint);
1211 if (RT_SUCCESS(rc))
1212 {
1213
1214 /* Initialize common parts. */
1215 pEndpoint->pNext = NULL;
1216 pEndpoint->pPrev = NULL;
1217 pEndpoint->pEpClass = pEndpointClass;
1218 pEndpoint->pTemplate = pTemplate;
1219 pEndpoint->pszUri = RTStrDup(pszFilename);
1220 pEndpoint->cUsers = 1;
1221 pEndpoint->pBwMgr = NULL;
1222
1223#ifdef VBOX_WITH_STATISTICS
1224 /* Init the statistics part */
1225 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesNs); i++)
1226 {
1227 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesNs[i], STAMTYPE_COUNTER,
1228 STAMVISIBILITY_USED,
1229 STAMUNIT_OCCURENCES,
1230 "Nanosecond resolution runtime statistics",
1231 "/PDM/AsyncCompletion/File/%s/TaskRun1Ns-%u-%u",
1232 RTPathFilename(pEndpoint->pszUri),
1233 i*100, i*100+100-1);
1234 if (RT_FAILURE(rc))
1235 break;
1236 }
1237
1238 if (RT_SUCCESS(rc))
1239 {
1240 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMicroSec); i++)
1241 {
1242 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesMicroSec[i], STAMTYPE_COUNTER,
1243 STAMVISIBILITY_USED,
1244 STAMUNIT_OCCURENCES,
1245 "Microsecond resolution runtime statistics",
1246 "/PDM/AsyncCompletion/File/%s/TaskRun2MicroSec-%u-%u",
1247 RTPathFilename(pEndpoint->pszUri),
1248 i*100, i*100+100-1);
1249 if (RT_FAILURE(rc))
1250 break;
1251 }
1252 }
1253
1254 if (RT_SUCCESS(rc))
1255 {
1256 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs); i++)
1257 {
1258 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesMs[i], STAMTYPE_COUNTER,
1259 STAMVISIBILITY_USED,
1260 STAMUNIT_OCCURENCES,
1261 "Milliseconds resolution runtime statistics",
1262 "/PDM/AsyncCompletion/File/%s/TaskRun3Ms-%u-%u",
1263 RTPathFilename(pEndpoint->pszUri),
1264 i*100, i*100+100-1);
1265 if (RT_FAILURE(rc))
1266 break;
1267 }
1268 }
1269
1270 if (RT_SUCCESS(rc))
1271 {
1272 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs); i++)
1273 {
1274 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunTimesSec[i], STAMTYPE_COUNTER,
1275 STAMVISIBILITY_USED,
1276 STAMUNIT_OCCURENCES,
1277 "Second resolution runtime statistics",
1278 "/PDM/AsyncCompletion/File/%s/TaskRun4Sec-%u-%u",
1279 RTPathFilename(pEndpoint->pszUri),
1280 i*10, i*10+10-1);
1281 if (RT_FAILURE(rc))
1282 break;
1283 }
1284 }
1285
1286 if (RT_SUCCESS(rc))
1287 {
1288 rc = STAMR3RegisterF(pVM, &pEndpoint->StatTaskRunOver100Sec, STAMTYPE_COUNTER,
1289 STAMVISIBILITY_USED,
1290 STAMUNIT_OCCURENCES,
1291 "Tasks which ran more than 100sec",
1292 "/PDM/AsyncCompletion/File/%s/TaskRunSecGreater100Sec",
1293 RTPathFilename(pEndpoint->pszUri));
1294 }
1295
1296 if (RT_SUCCESS(rc))
1297 {
1298 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsPerSec, STAMTYPE_COUNTER,
1299 STAMVISIBILITY_ALWAYS,
1300 STAMUNIT_OCCURENCES,
1301 "Processed I/O operations per second",
1302 "/PDM/AsyncCompletion/File/%s/IoOpsPerSec",
1303 RTPathFilename(pEndpoint->pszUri));
1304 }
1305
1306 if (RT_SUCCESS(rc))
1307 {
1308 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsStarted, STAMTYPE_COUNTER,
1309 STAMVISIBILITY_ALWAYS,
1310 STAMUNIT_OCCURENCES,
1311 "Started I/O operations for this endpoint",
1312 "/PDM/AsyncCompletion/File/%s/IoOpsStarted",
1313 RTPathFilename(pEndpoint->pszUri));
1314 }
1315
1316 if (RT_SUCCESS(rc))
1317 {
1318 rc = STAMR3RegisterF(pVM, &pEndpoint->StatIoOpsCompleted, STAMTYPE_COUNTER,
1319 STAMVISIBILITY_ALWAYS,
1320 STAMUNIT_OCCURENCES,
1321 "Completed I/O operations for this endpoint",
1322 "/PDM/AsyncCompletion/File/%s/IoOpsCompleted",
1323 RTPathFilename(pEndpoint->pszUri));
1324 }
1325
1326 pEndpoint->tsIntervalStartMs = RTTimeMilliTS();
1327#endif
1328
1329 if ( pEndpoint->pszUri
1330 && RT_SUCCESS(rc))
1331 {
1332 /* Call the initializer for the endpoint. */
1333 rc = pEndpointClass->pEndpointOps->pfnEpInitialize(pEndpoint, pszFilename, fFlags);
1334 if (RT_SUCCESS(rc))
1335 {
1336 /* Link it into the list of endpoints. */
1337 rc = RTCritSectEnter(&pEndpointClass->CritSect);
1338 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1339
1340 pEndpoint->pNext = pEndpointClass->pEndpointsHead;
1341 if (pEndpointClass->pEndpointsHead)
1342 pEndpointClass->pEndpointsHead->pPrev = pEndpoint;
1343
1344 pEndpointClass->pEndpointsHead = pEndpoint;
1345 pEndpointClass->cEndpoints++;
1346
1347 rc = RTCritSectLeave(&pEndpointClass->CritSect);
1348 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1349
1350 /* Reference the template. */
1351 ASMAtomicIncU32(&pTemplate->cUsed);
1352
1353 *ppEndpoint = pEndpoint;
1354
1355 LogFlowFunc((": Created endpoint for %s: rc=%Rrc\n", pszFilename, rc));
1356 return VINF_SUCCESS;
1357 }
1358 RTStrFree(pEndpoint->pszUri);
1359 }
1360 MMR3HeapFree(pEndpoint);
1361 }
1362 }
1363 else
1364 {
1365 /* Endpoint found. */
1366 pEndpoint->cUsers++;
1367
1368 *ppEndpoint = pEndpoint;
1369 return VINF_SUCCESS;
1370 }
1371
1372 LogFlowFunc((": Creation of endpoint for %s failed: rc=%Rrc\n", pszFilename, rc));
1373
1374 return rc;
1375}
1376
1377VMMR3DECL(void) PDMR3AsyncCompletionEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
1378{
1379 LogFlowFunc((": pEndpoint=%p\n", pEndpoint));
1380
1381 /* Sanity checks. */
1382 AssertReturnVoid(VALID_PTR(pEndpoint));
1383
1384 pEndpoint->cUsers--;
1385
1386 /* If the last user closed the endpoint we will free it. */
1387 if (!pEndpoint->cUsers)
1388 {
1389 PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pEndpoint->pEpClass;
1390 pEndpointClass->pEndpointOps->pfnEpClose(pEndpoint);
1391
1392 /* Drop reference from the template. */
1393 ASMAtomicDecU32(&pEndpoint->pTemplate->cUsed);
1394
1395 /* Unlink the endpoint from the list. */
1396 int rc = RTCritSectEnter(&pEndpointClass->CritSect);
1397 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1398
1399 PPDMASYNCCOMPLETIONENDPOINT pEndpointNext = pEndpoint->pNext;
1400 PPDMASYNCCOMPLETIONENDPOINT pEndpointPrev = pEndpoint->pPrev;
1401
1402 if (pEndpointPrev)
1403 pEndpointPrev->pNext = pEndpointNext;
1404 else
1405 pEndpointClass->pEndpointsHead = pEndpointNext;
1406 if (pEndpointNext)
1407 pEndpointNext->pPrev = pEndpointPrev;
1408
1409 pEndpointClass->cEndpoints--;
1410
1411 rc = RTCritSectLeave(&pEndpointClass->CritSect);
1412 AssertMsg(RT_SUCCESS(rc), ("Failed to enter critical section rc=%Rrc\n", rc));
1413
1414#ifdef VBOX_WITH_STATISTICS
1415 /* Deregister the statistics part */
1416 PVM pVM = pEndpointClass->pVM;
1417
1418 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesNs); i++)
1419 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunTimesNs[i]);
1420 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMicroSec); i++)
1421 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunTimesMicroSec[i]);
1422 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs); i++)
1423 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunTimesMs[i]);
1424 for (unsigned i = 0; i < RT_ELEMENTS(pEndpoint->StatTaskRunTimesMs); i++)
1425 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunTimesSec[i]);
1426
1427 STAMR3Deregister(pVM, &pEndpoint->StatTaskRunOver100Sec);
1428 STAMR3Deregister(pVM, &pEndpoint->StatIoOpsPerSec);
1429 STAMR3Deregister(pVM, &pEndpoint->StatIoOpsStarted);
1430 STAMR3Deregister(pVM, &pEndpoint->StatIoOpsCompleted);
1431#endif
1432
1433 RTStrFree(pEndpoint->pszUri);
1434 MMR3HeapFree(pEndpoint);
1435 }
1436}
1437
1438VMMR3DECL(int) PDMR3AsyncCompletionEpRead(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
1439 PCRTSGSEG paSegments, unsigned cSegments,
1440 size_t cbRead, void *pvUser,
1441 PPPDMASYNCCOMPLETIONTASK ppTask)
1442{
1443 int rc = VINF_SUCCESS;
1444
1445 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1446 AssertReturn(VALID_PTR(paSegments), VERR_INVALID_POINTER);
1447 AssertReturn(VALID_PTR(ppTask), VERR_INVALID_POINTER);
1448 AssertReturn(cSegments > 0, VERR_INVALID_PARAMETER);
1449 AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
1450 AssertReturn(off >= 0, VERR_INVALID_PARAMETER);
1451
1452 PPDMASYNCCOMPLETIONTASK pTask;
1453
1454 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1455 if (!pTask)
1456 return VERR_NO_MEMORY;
1457
1458 rc = pEndpoint->pEpClass->pEndpointOps->pfnEpRead(pTask, pEndpoint, off,
1459 paSegments, cSegments, cbRead);
1460 if (RT_SUCCESS(rc))
1461 {
1462 *ppTask = pTask;
1463 }
1464 else
1465 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1466
1467 return rc;
1468}
1469
1470VMMR3DECL(int) PDMR3AsyncCompletionEpWrite(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
1471 PCRTSGSEG paSegments, unsigned cSegments,
1472 size_t cbWrite, void *pvUser,
1473 PPPDMASYNCCOMPLETIONTASK ppTask)
1474{
1475 int rc = VINF_SUCCESS;
1476
1477 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1478 AssertReturn(VALID_PTR(paSegments), VERR_INVALID_POINTER);
1479 AssertReturn(VALID_PTR(ppTask), VERR_INVALID_POINTER);
1480 AssertReturn(cSegments > 0, VERR_INVALID_PARAMETER);
1481 AssertReturn(cbWrite > 0, VERR_INVALID_PARAMETER);
1482 AssertReturn(off >= 0, VERR_INVALID_PARAMETER);
1483
1484 PPDMASYNCCOMPLETIONTASK pTask;
1485
1486 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1487 if (!pTask)
1488 return VERR_NO_MEMORY;
1489
1490 rc = pEndpoint->pEpClass->pEndpointOps->pfnEpWrite(pTask, pEndpoint, off,
1491 paSegments, cSegments, cbWrite);
1492 if (RT_SUCCESS(rc))
1493 {
1494 *ppTask = pTask;
1495 }
1496 else
1497 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1498
1499 return rc;
1500}
1501
1502VMMR3DECL(int) PDMR3AsyncCompletionEpFlush(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1503 void *pvUser,
1504 PPPDMASYNCCOMPLETIONTASK ppTask)
1505{
1506 int rc = VINF_SUCCESS;
1507
1508 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1509 AssertReturn(VALID_PTR(ppTask), VERR_INVALID_POINTER);
1510
1511 PPDMASYNCCOMPLETIONTASK pTask;
1512
1513 pTask = pdmR3AsyncCompletionGetTask(pEndpoint, pvUser);
1514 if (!pTask)
1515 return VERR_NO_MEMORY;
1516
1517 rc = pEndpoint->pEpClass->pEndpointOps->pfnEpFlush(pTask, pEndpoint);
1518 if (RT_SUCCESS(rc))
1519 {
1520 *ppTask = pTask;
1521 }
1522 else
1523 pdmR3AsyncCompletionPutTask(pEndpoint, pTask);
1524
1525 return rc;
1526}
1527
1528VMMR3DECL(int) PDMR3AsyncCompletionEpGetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1529 uint64_t *pcbSize)
1530{
1531 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1532 AssertReturn(VALID_PTR(pcbSize), VERR_INVALID_POINTER);
1533
1534 if (pEndpoint->pEpClass->pEndpointOps->pfnEpGetSize)
1535 return pEndpoint->pEpClass->pEndpointOps->pfnEpGetSize(pEndpoint, pcbSize);
1536 else
1537 return VERR_NOT_SUPPORTED;
1538}
1539
1540VMMR3DECL(int) PDMR3AsyncCompletionEpSetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1541 uint64_t cbSize)
1542{
1543 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1544
1545 if (pEndpoint->pEpClass->pEndpointOps->pfnEpSetSize)
1546 return pEndpoint->pEpClass->pEndpointOps->pfnEpSetSize(pEndpoint, cbSize);
1547 else
1548 return VERR_NOT_SUPPORTED;
1549}
1550
1551VMMR3DECL(int) PDMR3AsyncCompletionEpSetBwMgr(PPDMASYNCCOMPLETIONENDPOINT pEndpoint,
1552 const char *pcszBwMgr)
1553{
1554 int rc = VINF_SUCCESS;
1555 AssertReturn(VALID_PTR(pEndpoint), VERR_INVALID_POINTER);
1556 PPDMACBWMGR pBwMgrOld = NULL;
1557 PPDMACBWMGR pBwMgrNew = NULL;
1558
1559 if (pcszBwMgr)
1560 {
1561 pBwMgrNew = pdmacBwMgrFindById(pEndpoint->pEpClass, pcszBwMgr);
1562
1563 if (pBwMgrNew)
1564 pdmacBwMgrRef(pBwMgrNew);
1565 else
1566 rc = VERR_NOT_FOUND;
1567 }
1568
1569 if (RT_SUCCESS(rc))
1570 {
1571 pBwMgrOld = ASMAtomicXchgPtrT(&pEndpoint->pBwMgr, pBwMgrNew, PPDMACBWMGR);
1572
1573 if (pBwMgrOld)
1574 pdmacBwMgrUnref(pBwMgrOld);
1575 }
1576
1577 return rc;
1578}
1579
1580VMMR3DECL(int) PDMR3AsyncCompletionTaskCancel(PPDMASYNCCOMPLETIONTASK pTask)
1581{
1582 return VERR_NOT_IMPLEMENTED;
1583}
1584
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