VirtualBox

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

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