VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PDMR3Task.cpp@ 84044

Last change on this file since 84044 was 82968, checked in by vboxsync, 4 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.4 KB
Line 
1/* $Id: PDMR3Task.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * PDM Task - Asynchronous user mode tasks.
4 */
5
6/*
7 * Copyright (C) 2019-2020 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_TASK
23#include "PDMInternal.h"
24#include <VBox/vmm/pdmtask.h>
25#include <VBox/vmm/mm.h>
26#include <VBox/vmm/vm.h>
27#include <VBox/err.h>
28
29#include <VBox/log.h>
30#include <VBox/sup.h>
31#include <iprt/asm.h>
32#include <iprt/assert.h>
33#include <iprt/semaphore.h>
34#include <iprt/thread.h>
35
36
37/**
38 * @callback_method_impl{FNDBGFINFOARGVINT}
39 */
40static DECLCALLBACK(void) pdmR3TaskInfo(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
41{
42 RT_NOREF(cArgs, papszArgs); /* for now. */
43
44 uint32_t cSetsDisplayed = 0;
45 for (size_t i = 0; i < RT_ELEMENTS(pVM->pdm.s.apTaskSets); i++)
46 {
47 PPDMTASKSET pTaskSet = pVM->pdm.s.apTaskSets[i];
48 if ( pTaskSet
49 && ( pTaskSet->cAllocated > 0
50 || ASMAtomicReadU64(&pTaskSet->fTriggered)))
51 {
52 if (cSetsDisplayed > 0)
53 pHlp->pfnPrintf(pHlp, "\n");
54 pHlp->pfnPrintf(pHlp,
55 "Task set #%u - handle base %u, pending %#RX64%s%s, running %d, %u of %u allocated:\n"
56 /* 123: triggered internal 0123456789abcdef 0123456789abcdef 0x0000 SomeFunctionName */
57 " Hnd: State Type pfnCallback pvUser Flags Name\n",
58 i, pTaskSet->uHandleBase, ASMAtomicReadU64(&pTaskSet->fTriggered),
59 pTaskSet->fRZEnabled ? " RZ-enabled" : "", pTaskSet->hThread != NIL_RTTHREAD ? "" : " no-thread",
60 (int)ASMAtomicReadU32(&pTaskSet->idxRunning), pTaskSet->cAllocated, RT_ELEMENTS(pTaskSet->aTasks));
61 for (unsigned j = 0; j < RT_ELEMENTS(pTaskSet->aTasks); j++)
62 {
63 PPDMTASK pTask = &pTaskSet->aTasks[j];
64 if (pTask->pvOwner)
65 {
66 const char *pszType;
67 switch (pTask->enmType)
68 {
69 case PDMTASKTYPE_DEV: pszType = " device "; break;
70 case PDMTASKTYPE_DRV: pszType = " driver "; break;
71 case PDMTASKTYPE_USB: pszType = " usbdev "; break;
72 case PDMTASKTYPE_INTERNAL: pszType = "internal"; break;
73 default: pszType = "unknown "; break;
74 }
75 pHlp->pfnPrintf(pHlp, " %3u: %s %s %p %p %#06x %s\n", pTaskSet->uHandleBase + j,
76 ASMBitTest(&pTaskSet->fTriggered, j) ? "triggered"
77 : ASMAtomicReadU32(&pTaskSet->idxRunning) == j ? " running " : " idle ",
78 pszType, pTask->pfnCallback, pTask->pvUser, pTask->fFlags, pTask->pszName);
79 }
80 }
81
82 cSetsDisplayed++;
83 }
84 }
85}
86
87
88/**
89 * Initializes the ring-0 capable tasks during VM construction.
90 *
91 * @returns VBox status code.
92 * @param pVM The cross context VM structure.
93 */
94int pdmR3TaskInit(PVM pVM)
95{
96 for (size_t i = 0; i < RT_ELEMENTS(pVM->pdm.s.aTaskSets); i++)
97 {
98 PPDMTASKSET pTaskSet = &pVM->pdm.s.aTaskSets[i];
99
100 pTaskSet->u32Magic = PDMTASKSET_MAGIC;
101 pTaskSet->fRZEnabled = true;
102 //pTaskSet->cAllocated = 0;
103 pTaskSet->uHandleBase = (uint16_t)(i * RT_ELEMENTS(pTaskSet->aTasks));
104 pTaskSet->hThread = NIL_RTTHREAD;
105 int rc = SUPSemEventCreate(pVM->pSession, &pTaskSet->hEventR0);
106 AssertRCReturn(rc, rc);
107 pTaskSet->hEventR3 = NIL_RTSEMEVENT;
108 //pTaskSet->fTriggered = 0;
109 pTaskSet->idxRunning = UINT8_MAX;
110 //pTaskSet->fShutdown = false;
111 pTaskSet->pVM = pVM;
112
113 pVM->pdm.s.apTaskSets[i] = pTaskSet;
114 }
115
116 int rc = DBGFR3InfoRegisterInternalArgv(pVM, "tasks", "PDM tasks", pdmR3TaskInfo, 0 /*fFlags*/);
117 AssertRC(rc);
118
119 return VINF_SUCCESS;
120}
121
122
123/**
124 * Terminates task threads when the VM is destroyed.
125 *
126 * @param pVM The cross context VM structure.
127 */
128void pdmR3TaskTerm(PVM pVM)
129{
130 /*
131 * Signal all the threads first.
132 */
133 for (size_t i = 0; i < RT_ELEMENTS(pVM->pdm.s.apTaskSets); i++)
134 {
135 PPDMTASKSET pTaskSet = pVM->pdm.s.apTaskSets[i];
136 if (pTaskSet)
137 {
138 /*
139 * Set the shutdown indicator and signal the thread.
140 */
141 ASMAtomicWriteBool(&pTaskSet->fShutdown, true);
142
143 if (pTaskSet->hEventR0 != NIL_SUPSEMEVENT)
144 {
145 int rc = SUPSemEventSignal(pVM->pSession, pTaskSet->hEventR0);
146 AssertRC(rc);
147 }
148
149 if (pTaskSet->hEventR3 != NIL_RTSEMEVENT)
150 {
151 int rc = RTSemEventSignal(pTaskSet->hEventR3);
152 AssertRC(rc);
153 }
154 }
155 }
156
157 /*
158 * Wait for them to terminate and clean up semaphores.
159 */
160 for (size_t i = 0; i < RT_ELEMENTS(pVM->pdm.s.apTaskSets); i++)
161 {
162 PPDMTASKSET pTaskSet = pVM->pdm.s.apTaskSets[i];
163 if (pTaskSet)
164 {
165 /*
166 * Wait for the thread to terminate.
167 */
168 if (pTaskSet->hThread != NIL_RTTHREAD)
169 {
170 int rc = RTThreadWait(pTaskSet->hThread, RT_MS_30SEC, NULL);
171 AssertLogRelMsg(RT_SUCCESS(rc), ("pTaskSet %u: thread wait failed: %Rrc\n", i, rc));
172 if (RT_SUCCESS(rc))
173 pTaskSet->hThread = NIL_RTTHREAD;
174 }
175
176 /*
177 * Destroy the semaphore.
178 */
179 if (pTaskSet->hEventR0 != NIL_SUPSEMEVENT)
180 {
181 int rc = SUPSemEventClose(pVM->pSession, pTaskSet->hEventR0);
182 AssertRC(rc);
183 pTaskSet->hEventR0 = NIL_SUPSEMEVENT;
184 }
185
186 if (pTaskSet->hEventR3 != NIL_RTSEMEVENT)
187 {
188 int rc = RTSemEventDestroy(pTaskSet->hEventR3);
189 AssertRC(rc);
190 pTaskSet->hEventR3 = NIL_RTSEMEVENT;
191 }
192 }
193 }
194}
195
196
197/**
198 * @callback_method_impl{FNRTTHREAD,
199 * PDM Asynchronous Task Executor Thread}
200 */
201static DECLCALLBACK(int) pdmR3TaskThread(RTTHREAD ThreadSelf, void *pvUser)
202{
203 PPDMTASKSET const pTaskSet = (PPDMTASKSET)pvUser;
204 AssertPtr(pTaskSet);
205 Assert(pTaskSet->u32Magic == PDMTASKSET_MAGIC);
206 RT_NOREF(ThreadSelf);
207
208 /*
209 * Process stuff until we're told to terminate.
210 */
211 while (!ASMAtomicReadBool(&pTaskSet->fShutdown))
212 {
213 /*
214 * Process pending tasks.
215 *
216 * The outer loop runs till there are no more pending tasks.
217 *
218 * The inner loop takes one snapshot of fTriggered and processes all
219 * pending bits in the snaphot. This ensure fairness.
220 */
221 for (;;)
222 {
223 uint64_t fTriggered = ASMAtomicReadU64(&pTaskSet->fTriggered);
224 unsigned iTask = ASMBitFirstSetU64(fTriggered);
225 if (iTask == 0)
226 break;
227 uint32_t cShutdown = 3;
228 do
229 {
230 iTask--;
231 AssertBreak(iTask < RT_ELEMENTS(pTaskSet->aTasks));
232
233 if (ASMAtomicBitTestAndClear(&pTaskSet->fTriggered, iTask))
234 {
235 PPDMTASK pTask = &pTaskSet->aTasks[iTask];
236
237 /* Copy out the data we need here to try avoid destruction race trouble. */
238 PDMTASKTYPE const enmType = pTask->enmType;
239 PFNRT const pfnCallback = pTask->pfnCallback;
240 void * const pvOwner = pTask->pvOwner;
241 void * const pvTaskUser = pTask->pvUser;
242
243 ASMAtomicWriteU32(&pTaskSet->idxRunning, iTask);
244
245 if ( pvOwner
246 && pfnCallback
247 && pvOwner == pTask->pvOwner
248 && pfnCallback == pTask->pfnCallback
249 && pvTaskUser == pTask->pvUser
250 && enmType == pTask->enmType)
251 {
252 pTask->cRuns += 1;
253 switch (pTask->enmType)
254 {
255 case PDMTASKTYPE_DEV:
256 Log2(("pdmR3TaskThread: Runs dev task %s (%#x)\n", pTask->pszName, iTask + pTaskSet->uHandleBase));
257 ((PFNPDMTASKDEV)(pfnCallback))((PPDMDEVINS)pvOwner, pvTaskUser);
258 break;
259 case PDMTASKTYPE_DRV:
260 Log2(("pdmR3TaskThread: Runs drv task %s (%#x)\n", pTask->pszName, iTask + pTaskSet->uHandleBase));
261 ((PFNPDMTASKDRV)(pfnCallback))((PPDMDRVINS)pvOwner, pvTaskUser);
262 break;
263 case PDMTASKTYPE_USB:
264 Log2(("pdmR3TaskThread: Runs USB task %s (%#x)\n", pTask->pszName, iTask + pTaskSet->uHandleBase));
265 ((PFNPDMTASKUSB)(pfnCallback))((PPDMUSBINS)pvOwner, pvTaskUser);
266 break;
267 case PDMTASKTYPE_INTERNAL:
268 Log2(("pdmR3TaskThread: Runs int task %s (%#x)\n", pTask->pszName, iTask + pTaskSet->uHandleBase));
269 ((PFNPDMTASKINT)(pfnCallback))((PVM)pvOwner, pvTaskUser);
270 break;
271 default:
272 AssertFailed();
273 }
274 }
275 else /* Note! There might be a race here during destruction. */
276 AssertMsgFailed(("%d %p %p %p\n", enmType, pvOwner, pfnCallback, pvTaskUser));
277
278 ASMAtomicWriteU32(&pTaskSet->idxRunning, UINT32_MAX);
279 }
280
281 /* Next pending task. */
282 fTriggered &= ~RT_BIT_64(iTask);
283 iTask = ASMBitFirstSetU64(fTriggered);
284 } while (iTask != 0);
285
286 /*
287 * If we're shutting down, we'll try drain the pending tasks by
288 * looping three more times before just quitting. We don't want
289 * to get stuck here if some stuff is misbehaving.
290 */
291 if (!ASMAtomicReadBool(&pTaskSet->fShutdown))
292 { /* likely */ }
293 else if (--cShutdown == 0)
294 break;
295 }
296
297 /*
298 * Wait unless we're shutting down.
299 */
300 if (!ASMAtomicReadBool(&pTaskSet->fShutdown))
301 {
302 if (pTaskSet->fRZEnabled)
303 SUPSemEventWaitNoResume(pTaskSet->pVM->pSession, pTaskSet->hEventR0, RT_MS_15SEC);
304 else
305 RTSemEventWaitNoResume(pTaskSet->hEventR3, RT_MS_15SEC);
306 }
307 }
308
309 /*
310 * Complain about pending tasks.
311 */
312 uint64_t const fTriggered = ASMAtomicReadU64(&pTaskSet->fTriggered);
313 AssertLogRelMsg(fTriggered == 0, ("fTriggered=%#RX64 - %u %s\n", fTriggered, ASMBitFirstSetU64(fTriggered) - 1,
314 pTaskSet->aTasks[ASMBitFirstSetU64(fTriggered) - 1].pszName));
315
316 return VINF_SUCCESS;
317}
318
319
320/**
321 * Worker for PDMR3TaskCreate().
322 */
323DECLINLINE(PPDMTASK) pdmR3TaskAllocInSet(PPDMTASKSET pTaskSet)
324{
325 if (pTaskSet->cAllocated < RT_ELEMENTS(pTaskSet->aTasks))
326 {
327 for (size_t j = 0; j < RT_ELEMENTS(pTaskSet->aTasks); j++)
328 if (pTaskSet->aTasks[j].pvOwner == NULL)
329 return &pTaskSet->aTasks[j];
330 AssertFailed();
331 }
332 return NULL;
333}
334
335/**
336 * Creates a task.
337 *
338 * @returns VBox status code.
339 * @param pVM The cross context VM structure.
340 * @param fFlags PDMTASK_F_XXX.
341 * @param pszName The task name (function name ++).
342 * @param enmType The task owner type.
343 * @param pvOwner The task owner pointer.
344 * @param pfnCallback The task callback.
345 * @param pvUser The user argument for the callback.
346 * @param phTask Where to return the task handle.
347 * @thread EMT(0)
348 */
349VMMR3_INT_DECL(int) PDMR3TaskCreate(PVM pVM, uint32_t fFlags, const char *pszName, PDMTASKTYPE enmType, void *pvOwner,
350 PFNRT pfnCallback, void *pvUser, PDMTASKHANDLE *phTask)
351{
352 /*
353 * Validate input.
354 */
355 AssertReturn(!(fFlags & ~PDMTASK_F_VALID_MASK), VERR_INVALID_FLAGS);
356 AssertPtrReturn(pvOwner, VERR_INVALID_POINTER);
357 AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
358 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
359 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
360 VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT); /* implicit serialization by requiring EMT(0) */
361 switch (enmType)
362 {
363 case PDMTASKTYPE_DEV:
364 case PDMTASKTYPE_DRV:
365 case PDMTASKTYPE_USB:
366 break;
367 case PDMTASKTYPE_INTERNAL:
368 AssertReturn(pvOwner == (void *)pVM, VERR_INVALID_PARAMETER);
369 break;
370 default:
371 AssertFailedReturn(VERR_INVALID_PARAMETER);
372 }
373
374 /*
375 * If the callback must be ring-0 triggerable, we are restricted to the
376 * task sets living the VM structure. Otherwise, pick from the dynamically
377 * allocated sets living on ring-3 heap.
378 */
379 PPDMTASKSET pTaskSet = NULL;
380 PPDMTASK pTask = NULL;
381 if (fFlags & PDMTASK_F_RZ)
382 {
383 for (size_t i = 0; i < RT_ELEMENTS(pVM->pdm.s.aTaskSets); i++)
384 {
385 pTaskSet = &pVM->pdm.s.aTaskSets[i];
386 pTask = pdmR3TaskAllocInSet(pTaskSet);
387 if (pTask)
388 break;
389 }
390 }
391 else
392 {
393 for (size_t i = RT_ELEMENTS(pVM->pdm.s.aTaskSets); i < RT_ELEMENTS(pVM->pdm.s.apTaskSets); i++)
394 {
395 pTaskSet = pVM->pdm.s.apTaskSets[i];
396 if (pTaskSet)
397 {
398 pTask = pdmR3TaskAllocInSet(pTaskSet);
399 if (pTask)
400 break;
401 }
402 else
403 {
404 /*
405 * Try allocate a new set.
406 */
407 LogFlow(("PDMR3TaskCreate: Allocating new task set (%#u)...\n", i));
408 pTaskSet = (PPDMTASKSET)MMR3HeapAllocZ(pVM, MM_TAG_PDM, sizeof(*pTaskSet));
409 AssertReturn(pTaskSet, VERR_NO_MEMORY);
410
411 pTaskSet->u32Magic = PDMTASKSET_MAGIC;
412 //pTaskSet->fRZEnabled = false;
413 //pTaskSet->cAllocated = 0;
414 pTaskSet->uHandleBase = (uint16_t)(i * RT_ELEMENTS(pTaskSet->aTasks));
415 pTaskSet->hThread = NIL_RTTHREAD;
416 pTaskSet->hEventR0 = NIL_SUPSEMEVENT;
417 int rc = RTSemEventCreate(&pTaskSet->hEventR3);
418 AssertRCReturnStmt(rc, MMR3HeapFree(pTaskSet), rc);
419 //pTaskSet->fTriggered = 0;
420 pTaskSet->idxRunning = UINT8_MAX;
421 //pTaskSet->fShutdown = false;
422 pTaskSet->pVM = pVM;
423
424 pVM->pdm.s.apTaskSets[i] = pTaskSet;
425 pTask = &pTaskSet->aTasks[0];
426 break;
427 }
428 }
429 }
430 AssertLogRelReturn(pTask, VERR_OUT_OF_RESOURCES);
431
432 /*
433 * Do we need to start a worker thread? Do this first as it can fail.
434 */
435 if (pTaskSet->hThread == NIL_RTTHREAD)
436 {
437 int rc = RTThreadCreateF(&pTaskSet->hThread, pdmR3TaskThread, pTaskSet, 0 /*cbStack*/, RTTHREADTYPE_IO,
438 RTTHREADFLAGS_WAITABLE, "TaskSet%u", pTaskSet->uHandleBase / RT_ELEMENTS(pTaskSet->aTasks));
439 AssertLogRelRCReturn(rc, rc);
440 }
441
442 /*
443 * Complete the allocation.
444 */
445 pTask->enmType = enmType;
446 pTask->fFlags = fFlags;
447 pTask->pvUser = pvUser;
448 pTask->pfnCallback = pfnCallback;
449 pTask->pszName = pszName;
450 ASMAtomicWritePtr(&pTask->pvOwner, pvOwner);
451 pTaskSet->cAllocated += 1;
452
453 uint32_t const hTask = pTaskSet->uHandleBase + (uint32_t)(pTask - &pTaskSet->aTasks[0]);
454 *phTask = hTask;
455
456 STAMR3RegisterF(pVM, &pTask->cRuns, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
457 "Number of times the task has been executed.", "/PDM/Tasks/%03u-%s-runs", hTask, pszName);
458 STAMR3RegisterF(pVM, (void *)&pTask->cAlreadyTrigged, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
459 "Number of times the task was re-triggered.", "/PDM/Tasks/%03u-%s-retriggered", hTask, pszName);
460
461 LogFlow(("PDMR3TaskCreate: Allocated %u for %s\n", hTask, pszName));
462 return VINF_SUCCESS;
463}
464
465
466/**
467 * Creates an internal task.
468 *
469 * @returns VBox status code.
470 * @param pVM The cross context VM structure.
471 * @param fFlags PDMTASK_F_XXX.
472 * @param pszName The task name (function name ++).
473 * @param pfnCallback The task callback.
474 * @param pvUser The user argument for the callback.
475 * @param phTask Where to return the task handle.
476 * @thread EMT(0)
477 */
478VMMR3_INT_DECL(int) PDMR3TaskCreateInternal(PVM pVM, uint32_t fFlags, const char *pszName,
479 PFNPDMTASKINT pfnCallback, void *pvUser, PDMTASKHANDLE *phTask)
480{
481 return PDMR3TaskCreate(pVM, fFlags, pszName, PDMTASKTYPE_INTERNAL, pVM, (PFNRT)pfnCallback, pvUser, phTask);
482}
483
484
485/**
486 * Worker for PDMR3TaskDestroyAllByOwner() and PDMR3TaskDestroySpecific().
487 */
488static void pdmR3TaskDestroyOne(PVM pVM, PPDMTASKSET pTaskSet, PPDMTASK pTask, size_t iTask)
489{
490 AssertPtr(pTask->pvOwner);
491
492 /*
493 * Delay if busy.
494 */
495 uint32_t cYields = 64;
496 while ( ASMAtomicReadU32(&pTaskSet->idxRunning) == iTask
497 && cYields > 0
498 && pTaskSet->hThread != NIL_RTTHREAD)
499 {
500 ASMNopPause();
501 RTThreadYield();
502 }
503
504 /*
505 * Zap it (very noisy, but whatever).
506 */
507 LogFlow(("pdmR3TaskDestroyOne: Destroying %zu %s\n", iTask + pTaskSet->uHandleBase, pTask->pszName));
508 AssertPtr(pTask->pvOwner);
509
510 char szPrefix[64];
511 RTStrPrintf(szPrefix, sizeof(szPrefix), "/PDM/Tasks/%03zu-", iTask + pTaskSet->uHandleBase);
512 STAMR3DeregisterByPrefix(pVM->pUVM, szPrefix);
513
514 AssertPtr(pTask->pvOwner);
515 ASMAtomicWriteNullPtr(&pTask->pvOwner);
516 pTask->enmType = (PDMTASKTYPE)0;
517 pTask->fFlags = 0;
518 ASMAtomicWriteNullPtr(&pTask->pfnCallback);
519 ASMAtomicWriteNullPtr(&pTask->pvUser);
520 ASMAtomicWriteNullPtr(&pTask->pszName);
521
522 AssertReturnVoid(pTaskSet->cAllocated > 0);
523 pTaskSet->cAllocated -= 1;
524}
525
526
527/**
528 * Destroys all tasks belonging to @a pvOwner.
529 *
530 * @returns VBox status code.
531 * @param pVM The cross context VM structure.
532 * @param enmType The owner type.
533 * @param pvOwner The owner.
534 */
535VMMR3_INT_DECL(int) PDMR3TaskDestroyAllByOwner(PVM pVM, PDMTASKTYPE enmType, void *pvOwner)
536{
537 /*
538 * Validate input.
539 */
540 AssertReturn(enmType >= PDMTASKTYPE_DEV && enmType < PDMTASKTYPE_INTERNAL, VERR_INVALID_PARAMETER);
541 AssertPtrReturn(pvOwner, VERR_INVALID_POINTER);
542 VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT); /* implicit serialization by requiring EMT(0) */
543
544 /*
545 * Scan all the task sets.
546 */
547 for (size_t i = 0; i < RT_ELEMENTS(pVM->pdm.s.apTaskSets); i++)
548 {
549 PPDMTASKSET pTaskSet = pVM->pdm.s.apTaskSets[i];
550 if (pTaskSet)
551 {
552 ssize_t cLeft = pTaskSet->cAllocated;
553 for (size_t j = 0; j < RT_ELEMENTS(pTaskSet->aTasks) && cLeft > 0; j++)
554 {
555 PPDMTASK pTask = &pTaskSet->aTasks[j];
556 void * const pvTaskOwner = pTask->pvOwner;
557 if (pvTaskOwner)
558 {
559 if ( pvTaskOwner == pvOwner
560 && pTask->enmType == enmType)
561 pdmR3TaskDestroyOne(pVM, pTaskSet, pTask, j);
562 else
563 Assert(pvTaskOwner != pvOwner);
564 cLeft--;
565 }
566 }
567 }
568 else
569 break;
570 }
571
572 return VINF_SUCCESS;
573}
574
575
576/**
577 * Destroys the task @a hTask.
578 *
579 * @returns VBox status code.
580 * @param pVM The cross context VM structure.
581 * @param enmType The owner type.
582 * @param pvOwner The owner.
583 * @param hTask Handle to the task to destroy.
584 */
585VMMR3_INT_DECL(int) PDMR3TaskDestroySpecific(PVM pVM, PDMTASKTYPE enmType, void *pvOwner, PDMTASKHANDLE hTask)
586{
587 /*
588 * Validate the input.
589 */
590 AssertReturn(enmType >= PDMTASKTYPE_DEV && enmType <= PDMTASKTYPE_INTERNAL, VERR_INVALID_PARAMETER);
591 AssertPtrReturn(pvOwner, VERR_INVALID_POINTER);
592
593 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
594
595 size_t const iTask = hTask % RT_ELEMENTS(pVM->pdm.s.apTaskSets[0]->aTasks);
596 size_t const iTaskSet = hTask / RT_ELEMENTS(pVM->pdm.s.apTaskSets[0]->aTasks);
597 AssertReturn(iTaskSet < RT_ELEMENTS(pVM->pdm.s.apTaskSets), VERR_INVALID_HANDLE);
598 PPDMTASKSET const pTaskSet = pVM->pdm.s.apTaskSets[iTaskSet];
599 AssertPtrReturn(pTaskSet, VERR_INVALID_HANDLE);
600 AssertPtrReturn(pTaskSet->u32Magic == PDMTASKSET_MAGIC, VERR_INVALID_MAGIC);
601 PPDMTASK const pTask = &pTaskSet->aTasks[iTask];
602
603 VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT); /* implicit serialization by requiring EMT(0) */
604
605 AssertPtrReturn(pTask->pvOwner == pvOwner, VERR_NOT_OWNER);
606 AssertPtrReturn(pTask->enmType == enmType, VERR_NOT_OWNER);
607
608 /*
609 * Do the job.
610 */
611 pdmR3TaskDestroyOne(pVM, pTaskSet, pTask, iTask);
612
613 return VINF_SUCCESS;
614}
615
616
617/**
618 * Destroys the internal task @a hTask.
619 *
620 * @returns VBox status code.
621 * @param pVM The cross context VM structure.
622 * @param hTask Handle to the task to destroy.
623 */
624VMMR3_INT_DECL(int) PDMR3TaskDestroyInternal(PVM pVM, PDMTASKHANDLE hTask)
625{
626 return PDMR3TaskDestroySpecific(pVM, PDMTASKTYPE_INTERNAL, pVM, hTask);
627}
628
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use