VirtualBox

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

Last change on this file since 81561 was 81561, checked in by vboxsync, 5 years ago

PDMR3Task: The task thread (pdmR3TaskThread) should quit eventually when shutdown is signalled. Old code just keep processing tasks till nothing was pending. Will now do three loops trying to quice things and assert before exiting. bugref:9218

  • 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 81561 2019-10-28 12:44:44Z vboxsync $ */
2/** @file
3 * PDM Task - Asynchronous user mode tasks.
4 */
5
6/*
7 * Copyright (C) 2019 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.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette