VirtualBox

source: vbox/trunk/src/VBox/VMM/PDMQueue.cpp@ 16560

Last change on this file since 16560 was 14074, checked in by vboxsync, 16 years ago

PDMQueue: The 64-bit MSC warning hunt continues.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.1 KB
Line 
1/* $Id: PDMQueue.cpp 14074 2008-11-11 00:02:26Z vboxsync $ */
2/** @file
3 * PDM Queue - Transport data and tasks to EMT and R3.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_PDM_QUEUE
27#include "PDMInternal.h"
28#include <VBox/pdm.h>
29#include <VBox/mm.h>
30#include <VBox/rem.h>
31#include <VBox/vm.h>
32#include <VBox/err.h>
33
34#include <VBox/log.h>
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/thread.h>
38
39
40/*******************************************************************************
41* Internal Functions *
42*******************************************************************************/
43DECLINLINE(void) pdmR3QueueFree(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem);
44static bool pdmR3QueueFlush(PPDMQUEUE pQueue);
45static DECLCALLBACK(void) pdmR3QueueTimer(PVM pVM, PTMTIMER pTimer, void *pvUser);
46
47
48
49/**
50 * Internal worker for the queue creation apis.
51 *
52 * @returns VBox status.
53 * @param pVM VM handle.
54 * @param cbItem Item size.
55 * @param cItems Number of items.
56 * @param cMilliesInterval Number of milliseconds between polling the queue.
57 * If 0 then the emulation thread will be notified whenever an item arrives.
58 * @param fRZEnabled Set if the queue will be used from RC/R0 and need to be allocated from the hyper heap.
59 * @param ppQueue Where to store the queue handle.
60 */
61static int pdmR3QueueCreate(PVM pVM, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval, bool fRZEnabled, PPDMQUEUE *ppQueue)
62{
63 /*
64 * Validate input.
65 */
66 if (cbItem < sizeof(PDMQUEUEITEMCORE))
67 {
68 AssertMsgFailed(("cbItem=%d\n", cbItem));
69 return VERR_INVALID_PARAMETER;
70 }
71 if (cItems < 1 || cItems >= 0x10000)
72 {
73 AssertMsgFailed(("cItems=%d valid:[1-65535]\n", cItems));
74 return VERR_INVALID_PARAMETER;
75 }
76
77 /*
78 * Align the item size and calculate the structure size.
79 */
80 cbItem = RT_ALIGN(cbItem, sizeof(RTUINTPTR));
81 size_t cb = cbItem * cItems + RT_ALIGN_Z(RT_OFFSETOF(PDMQUEUE, aFreeItems[cItems + PDMQUEUE_FREE_SLACK]), 16);
82 PPDMQUEUE pQueue;
83 int rc;
84 if (fRZEnabled)
85 rc = MMHyperAlloc(pVM, cb, 0, MM_TAG_PDM_QUEUE, (void **)&pQueue );
86 else
87 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_QUEUE, cb, (void **)&pQueue);
88 if (RT_FAILURE(rc))
89 return rc;
90
91 /*
92 * Initialize the data fields.
93 */
94 pQueue->pVMR3 = pVM;
95 pQueue->pVMR0 = fRZEnabled ? pVM->pVMR0 : NIL_RTR0PTR;
96 pQueue->pVMRC = fRZEnabled ? pVM->pVMRC : NIL_RTRCPTR;
97 pQueue->cMilliesInterval = cMilliesInterval;
98 //pQueue->pTimer = NULL;
99 pQueue->cbItem = cbItem;
100 pQueue->cItems = cItems;
101 //pQueue->pPendingR3 = NULL;
102 //pQueue->pPendingR0 = NULL;
103 //pQueue->pPendingRC = NULL;
104 pQueue->iFreeHead = cItems;
105 //pQueue->iFreeTail = 0;
106 PPDMQUEUEITEMCORE pItem = (PPDMQUEUEITEMCORE)((char *)pQueue + RT_ALIGN_Z(RT_OFFSETOF(PDMQUEUE, aFreeItems[cItems + PDMQUEUE_FREE_SLACK]), 16));
107 for (unsigned i = 0; i < cItems; i++, pItem = (PPDMQUEUEITEMCORE)((char *)pItem + cbItem))
108 {
109 pQueue->aFreeItems[i].pItemR3 = pItem;
110 if (fRZEnabled)
111 {
112 pQueue->aFreeItems[i].pItemR0 = MMHyperR3ToR0(pVM, pItem);
113 pQueue->aFreeItems[i].pItemRC = MMHyperR3ToRC(pVM, pItem);
114 }
115 }
116
117 /*
118 * Create timer?
119 */
120 if (cMilliesInterval)
121 {
122 int rc = TMR3TimerCreateInternal(pVM, TMCLOCK_REAL, pdmR3QueueTimer, pQueue, "Queue timer", &pQueue->pTimer);
123 if (RT_SUCCESS(rc))
124 {
125 rc = TMTimerSetMillies(pQueue->pTimer, cMilliesInterval);
126 if (RT_FAILURE(rc))
127 {
128 AssertMsgFailed(("TMTimerSetMillies failed rc=%Rrc\n", rc));
129 int rc2 = TMTimerDestroy(pQueue->pTimer); AssertRC(rc2);
130 }
131 }
132 else
133 AssertMsgFailed(("TMR3TimerCreateInternal failed rc=%Rrc\n", rc));
134 if (RT_FAILURE(rc))
135 {
136 if (fRZEnabled)
137 MMHyperFree(pVM, pQueue);
138 else
139 MMR3HeapFree(pQueue);
140 return rc;
141 }
142
143 /*
144 * Insert into the queue list for timer driven queues.
145 */
146 pQueue->pNext = pVM->pdm.s.pQueuesTimer;
147 pVM->pdm.s.pQueuesTimer = pQueue;
148 }
149 else
150 {
151 /*
152 * Insert into the queue list for forced action driven queues.
153 * This is a FIFO, so insert at the end.
154 */
155 /** @todo we should add a priority priority to the queues so we don't have to rely on
156 * the initialization order to deal with problems like #1605 (pgm/pcnet deadlock
157 * caused by the critsect queue to be last in the chain).
158 * - Update, the critical sections are no longer using queues, so this isn't a real
159 * problem any longer. The priority might be a nice feature for later though.
160 */
161 if (!pVM->pdm.s.pQueuesForced)
162 pVM->pdm.s.pQueuesForced = pQueue;
163 else
164 {
165 PPDMQUEUE pPrev = pVM->pdm.s.pQueuesForced;
166 while (pPrev->pNext)
167 pPrev = pPrev->pNext;
168 pPrev->pNext = pQueue;
169 }
170 }
171
172 *ppQueue = pQueue;
173 return VINF_SUCCESS;
174}
175
176
177/**
178 * Create a queue with a device owner.
179 *
180 * @returns VBox status code.
181 * @param pVM VM handle.
182 * @param pDevIns Device instance.
183 * @param cbItem Size a queue item.
184 * @param cItems Number of items in the queue.
185 * @param cMilliesInterval Number of milliseconds between polling the queue.
186 * If 0 then the emulation thread will be notified whenever an item arrives.
187 * @param pfnCallback The consumer function.
188 * @param fRZEnabled Set if the queue must be usable from RC/R0.
189 * @param ppQueue Where to store the queue handle on success.
190 * @thread Emulation thread only.
191 */
192VMMR3DECL(int) PDMR3QueueCreateDevice(PVM pVM, PPDMDEVINS pDevIns, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval,
193 PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, PPDMQUEUE *ppQueue)
194{
195 LogFlow(("PDMR3QueueCreateDevice: pDevIns=%p cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p fRZEnabled=%RTbool\n",
196 pDevIns, cbItem, cItems, cMilliesInterval, pfnCallback, fRZEnabled));
197
198 /*
199 * Validate input.
200 */
201 VM_ASSERT_EMT(pVM);
202 if (!pfnCallback)
203 {
204 AssertMsgFailed(("No consumer callback!\n"));
205 return VERR_INVALID_PARAMETER;
206 }
207
208 /*
209 * Create the queue.
210 */
211 PPDMQUEUE pQueue;
212 int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, fRZEnabled, &pQueue);
213 if (RT_SUCCESS(rc))
214 {
215 pQueue->enmType = PDMQUEUETYPE_DEV;
216 pQueue->u.Dev.pDevIns = pDevIns;
217 pQueue->u.Dev.pfnCallback = pfnCallback;
218
219 *ppQueue = pQueue;
220 Log(("PDM: Created device queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p pDevIns=%p\n",
221 cbItem, cItems, cMilliesInterval, pfnCallback, pDevIns));
222 }
223 return rc;
224}
225
226
227/**
228 * Create a queue with a driver owner.
229 *
230 * @returns VBox status code.
231 * @param pVM VM handle.
232 * @param pDrvIns Driver instance.
233 * @param cbItem Size a queue item.
234 * @param cItems Number of items in the queue.
235 * @param cMilliesInterval Number of milliseconds between polling the queue.
236 * If 0 then the emulation thread will be notified whenever an item arrives.
237 * @param pfnCallback The consumer function.
238 * @param ppQueue Where to store the queue handle on success.
239 * @thread Emulation thread only.
240 */
241VMMR3DECL(int) PDMR3QueueCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval,
242 PFNPDMQUEUEDRV pfnCallback, PPDMQUEUE *ppQueue)
243{
244 LogFlow(("PDMR3QueueCreateDriver: pDrvIns=%p cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p\n",
245 pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback));
246
247 /*
248 * Validate input.
249 */
250 VM_ASSERT_EMT(pVM);
251 if (!pfnCallback)
252 {
253 AssertMsgFailed(("No consumer callback!\n"));
254 return VERR_INVALID_PARAMETER;
255 }
256
257 /*
258 * Create the queue.
259 */
260 PPDMQUEUE pQueue;
261 int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, false, &pQueue);
262 if (RT_SUCCESS(rc))
263 {
264 pQueue->enmType = PDMQUEUETYPE_DRV;
265 pQueue->u.Drv.pDrvIns = pDrvIns;
266 pQueue->u.Drv.pfnCallback = pfnCallback;
267
268 *ppQueue = pQueue;
269 Log(("PDM: Created driver queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p pDrvIns=%p\n",
270 cbItem, cItems, cMilliesInterval, pfnCallback, pDrvIns));
271 }
272 return rc;
273}
274
275
276/**
277 * Create a queue with an internal owner.
278 *
279 * @returns VBox status code.
280 * @param pVM VM handle.
281 * @param cbItem Size a queue item.
282 * @param cItems Number of items in the queue.
283 * @param cMilliesInterval Number of milliseconds between polling the queue.
284 * If 0 then the emulation thread will be notified whenever an item arrives.
285 * @param pfnCallback The consumer function.
286 * @param fRZEnabled Set if the queue must be usable from RC/R0.
287 * @param ppQueue Where to store the queue handle on success.
288 * @thread Emulation thread only.
289 */
290VMMR3DECL(int) PDMR3QueueCreateInternal(PVM pVM, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval,
291 PFNPDMQUEUEINT pfnCallback, bool fRZEnabled, PPDMQUEUE *ppQueue)
292{
293 LogFlow(("PDMR3QueueCreateInternal: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p fRZEnabled=%RTbool\n",
294 cbItem, cItems, cMilliesInterval, pfnCallback, fRZEnabled));
295
296 /*
297 * Validate input.
298 */
299 VM_ASSERT_EMT(pVM);
300 if (!pfnCallback)
301 {
302 AssertMsgFailed(("No consumer callback!\n"));
303 return VERR_INVALID_PARAMETER;
304 }
305
306 /*
307 * Create the queue.
308 */
309 PPDMQUEUE pQueue;
310 int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, fRZEnabled, &pQueue);
311 if (RT_SUCCESS(rc))
312 {
313 pQueue->enmType = PDMQUEUETYPE_INTERNAL;
314 pQueue->u.Int.pfnCallback = pfnCallback;
315
316 *ppQueue = pQueue;
317 Log(("PDM: Created internal queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p\n",
318 cbItem, cItems, cMilliesInterval, pfnCallback));
319 }
320 return rc;
321}
322
323
324/**
325 * Create a queue with an external owner.
326 *
327 * @returns VBox status code.
328 * @param pVM VM handle.
329 * @param cbItem Size a queue item.
330 * @param cItems Number of items in the queue.
331 * @param cMilliesInterval Number of milliseconds between polling the queue.
332 * If 0 then the emulation thread will be notified whenever an item arrives.
333 * @param pfnCallback The consumer function.
334 * @param pvUser The user argument to the consumer function.
335 * @param ppQueue Where to store the queue handle on success.
336 * @thread Emulation thread only.
337 */
338VMMR3DECL(int) PDMR3QueueCreateExternal(PVM pVM, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval, PFNPDMQUEUEEXT pfnCallback, void *pvUser, PPDMQUEUE *ppQueue)
339{
340 LogFlow(("PDMR3QueueCreateExternal: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p\n", cbItem, cItems, cMilliesInterval, pfnCallback));
341
342 /*
343 * Validate input.
344 */
345 VM_ASSERT_EMT(pVM);
346 if (!pfnCallback)
347 {
348 AssertMsgFailed(("No consumer callback!\n"));
349 return VERR_INVALID_PARAMETER;
350 }
351
352 /*
353 * Create the queue.
354 */
355 PPDMQUEUE pQueue;
356 int rc = pdmR3QueueCreate(pVM, cbItem, cItems, cMilliesInterval, false, &pQueue);
357 if (RT_SUCCESS(rc))
358 {
359 pQueue->enmType = PDMQUEUETYPE_EXTERNAL;
360 pQueue->u.Ext.pvUser = pvUser;
361 pQueue->u.Ext.pfnCallback = pfnCallback;
362
363 *ppQueue = pQueue;
364 Log(("PDM: Created external queue %p; cbItem=%d cItems=%d cMillies=%d pfnCallback=%p pvUser=%p\n",
365 cbItem, cItems, cMilliesInterval, pfnCallback, pvUser));
366 }
367 return rc;
368}
369
370
371/**
372 * Destroy a queue.
373 *
374 * @returns VBox status code.
375 * @param pQueue Queue to destroy.
376 * @thread Emulation thread only.
377 */
378VMMR3DECL(int) PDMR3QueueDestroy(PPDMQUEUE pQueue)
379{
380 LogFlow(("PDMR3QueueDestroy: pQueue=%p\n", pQueue));
381
382 /*
383 * Validate input.
384 */
385 if (!pQueue)
386 return VERR_INVALID_PARAMETER;
387 Assert(pQueue && pQueue->pVMR3);
388 PVM pVM = pQueue->pVMR3;
389 VM_ASSERT_EMT(pVM);
390
391 /*
392 * Unlink it.
393 */
394 if (pQueue->pTimer)
395 {
396 if (pVM->pdm.s.pQueuesTimer != pQueue)
397 {
398 PPDMQUEUE pCur = pVM->pdm.s.pQueuesTimer;
399 while (pCur)
400 {
401 if (pCur->pNext == pQueue)
402 {
403 pCur->pNext = pQueue->pNext;
404 break;
405 }
406 pCur = pCur->pNext;
407 }
408 AssertMsg(pCur, ("Didn't find the queue!\n"));
409 }
410 else
411 pVM->pdm.s.pQueuesTimer = pQueue->pNext;
412 }
413 else
414 {
415 if (pVM->pdm.s.pQueuesForced != pQueue)
416 {
417 PPDMQUEUE pCur = pVM->pdm.s.pQueuesForced;
418 while (pCur)
419 {
420 if (pCur->pNext == pQueue)
421 {
422 pCur->pNext = pQueue->pNext;
423 break;
424 }
425 pCur = pCur->pNext;
426 }
427 AssertMsg(pCur, ("Didn't find the queue!\n"));
428 }
429 else
430 pVM->pdm.s.pQueuesForced = pQueue->pNext;
431 }
432 pQueue->pNext = NULL;
433 pQueue->pVMR3 = NULL;
434
435 /*
436 * Destroy the timer and free it.
437 */
438 if (pQueue->pTimer)
439 {
440 TMTimerDestroy(pQueue->pTimer);
441 pQueue->pTimer = NULL;
442 }
443 if (pQueue->pVMRC)
444 {
445 pQueue->pVMRC = NIL_RTRCPTR;
446 pQueue->pVMR0 = NIL_RTR0PTR;
447 MMHyperFree(pVM, pQueue);
448 }
449 else
450 MMR3HeapFree(pQueue);
451
452 return VINF_SUCCESS;
453}
454
455
456/**
457 * Destroy a all queues owned by the specified device.
458 *
459 * @returns VBox status code.
460 * @param pVM VM handle.
461 * @param pDevIns Device instance.
462 * @thread Emulation thread only.
463 */
464VMMR3DECL(int) PDMR3QueueDestroyDevice(PVM pVM, PPDMDEVINS pDevIns)
465{
466 LogFlow(("PDMR3QueueDestroyDevice: pDevIns=%p\n", pDevIns));
467
468 /*
469 * Validate input.
470 */
471 if (!pDevIns)
472 return VERR_INVALID_PARAMETER;
473 VM_ASSERT_EMT(pVM);
474
475 /*
476 * Unlink it.
477 */
478 PPDMQUEUE pQueueNext = pVM->pdm.s.pQueuesTimer;
479 PPDMQUEUE pQueue = pVM->pdm.s.pQueuesForced;
480 do
481 {
482 while (pQueue)
483 {
484 if ( pQueue->enmType == PDMQUEUETYPE_DEV
485 && pQueue->u.Dev.pDevIns == pDevIns)
486 {
487 PPDMQUEUE pQueueDestroy = pQueue;
488 pQueue = pQueue->pNext;
489 int rc = PDMR3QueueDestroy(pQueueDestroy);
490 AssertRC(rc);
491 }
492 else
493 pQueue = pQueue->pNext;
494 }
495
496 /* next queue list */
497 pQueue = pQueueNext;
498 pQueueNext = NULL;
499 } while (pQueue);
500
501 return VINF_SUCCESS;
502}
503
504
505/**
506 * Destroy a all queues owned by the specified driver.
507 *
508 * @returns VBox status code.
509 * @param pVM VM handle.
510 * @param pDrvIns Driver instance.
511 * @thread Emulation thread only.
512 */
513VMMR3DECL(int) PDMR3QueueDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns)
514{
515 LogFlow(("PDMR3QueueDestroyDriver: pDrvIns=%p\n", pDrvIns));
516
517 /*
518 * Validate input.
519 */
520 if (!pDrvIns)
521 return VERR_INVALID_PARAMETER;
522 VM_ASSERT_EMT(pVM);
523
524 /*
525 * Unlink it.
526 */
527 PPDMQUEUE pQueueNext = pVM->pdm.s.pQueuesTimer;
528 PPDMQUEUE pQueue = pVM->pdm.s.pQueuesForced;
529 do
530 {
531 while (pQueue)
532 {
533 if ( pQueue->enmType == PDMQUEUETYPE_DRV
534 && pQueue->u.Drv.pDrvIns == pDrvIns)
535 {
536 PPDMQUEUE pQueueDestroy = pQueue;
537 pQueue = pQueue->pNext;
538 int rc = PDMR3QueueDestroy(pQueueDestroy);
539 AssertRC(rc);
540 }
541 else
542 pQueue = pQueue->pNext;
543 }
544
545 /* next queue list */
546 pQueue = pQueueNext;
547 pQueueNext = NULL;
548 } while (pQueue);
549
550 return VINF_SUCCESS;
551}
552
553
554/**
555 * Relocate the queues.
556 *
557 * @param pVM The VM handle.
558 * @param offDelta The relocation delta.
559 */
560void pdmR3QueueRelocate(PVM pVM, RTGCINTPTR offDelta)
561{
562 /*
563 * Process the queues.
564 */
565 PPDMQUEUE pQueueNext = pVM->pdm.s.pQueuesTimer;
566 PPDMQUEUE pQueue = pVM->pdm.s.pQueuesForced;
567 do
568 {
569 while (pQueue)
570 {
571 if (pQueue->pVMRC)
572 {
573 pQueue->pVMRC = pVM->pVMRC;
574
575 /* Pending RC items. */
576 if (pQueue->pPendingRC)
577 {
578 pQueue->pPendingRC += offDelta;
579 PPDMQUEUEITEMCORE pCur = (PPDMQUEUEITEMCORE)MMHyperRCToR3(pVM, pQueue->pPendingRC);
580 while (pCur->pNextRC)
581 {
582 pCur->pNextRC += offDelta;
583 pCur = (PPDMQUEUEITEMCORE)MMHyperRCToR3(pVM, pCur->pNextRC);
584 }
585 }
586
587 /* The free items. */
588 uint32_t i = pQueue->iFreeTail;
589 while (i != pQueue->iFreeHead)
590 {
591 pQueue->aFreeItems[i].pItemRC = MMHyperR3ToRC(pVM, pQueue->aFreeItems[i].pItemR3);
592 i = (i + 1) % (pQueue->cItems + PDMQUEUE_FREE_SLACK);
593 }
594 }
595
596 /* next queue */
597 pQueue = pQueue->pNext;
598 }
599
600 /* next queue list */
601 pQueue = pQueueNext;
602 pQueueNext = NULL;
603 } while (pQueue);
604}
605
606
607/**
608 * Flush pending queues.
609 * This is a forced action callback.
610 *
611 * @param pVM VM handle.
612 * @thread Emulation thread only.
613 */
614VMMR3DECL(void) PDMR3QueueFlushAll(PVM pVM)
615{
616 VM_ASSERT_EMT(pVM);
617 LogFlow(("PDMR3QueuesFlush:\n"));
618
619 VM_FF_CLEAR(pVM, VM_FF_PDM_QUEUES);
620 for (PPDMQUEUE pCur = pVM->pdm.s.pQueuesForced; pCur; pCur = pCur->pNext)
621 {
622 if ( pCur->pPendingR3
623 || pCur->pPendingR0
624 || pCur->pPendingRC)
625 {
626 if ( pdmR3QueueFlush(pCur)
627 && pCur->pPendingR3)
628 /* new items arrived while flushing. */
629 pdmR3QueueFlush(pCur);
630 }
631 }
632}
633
634
635/**
636 * Process pending items in one queue.
637 *
638 * @returns Success indicator.
639 * If false the item the consumer said "enough!".
640 * @param pQueue The queue.
641 */
642static bool pdmR3QueueFlush(PPDMQUEUE pQueue)
643{
644 /*
645 * Get the lists.
646 */
647 PPDMQUEUEITEMCORE pItems = (PPDMQUEUEITEMCORE)ASMAtomicXchgPtr((void * volatile *)&pQueue->pPendingR3, NULL);
648 RTRCPTR pItemsRC = ASMAtomicXchgRCPtr(&pQueue->pPendingRC, NIL_RTRCPTR);
649 RTR0PTR pItemsR0 = ASMAtomicXchgR0Ptr(&pQueue->pPendingR0, NIL_RTR0PTR);
650
651 AssertMsg(pItems || pItemsRC || pItemsR0, ("ERROR: can't all be NULL now!\n"));
652
653
654 /*
655 * Reverse the list (it's inserted in LIFO order to avoid semaphores, remember).
656 */
657 PPDMQUEUEITEMCORE pCur = pItems;
658 pItems = NULL;
659 while (pCur)
660 {
661 PPDMQUEUEITEMCORE pInsert = pCur;
662 pCur = pCur->pNextR3;
663 pInsert->pNextR3 = pItems;
664 pItems = pInsert;
665 }
666
667 /*
668 * Do the same for any pending RC items.
669 */
670 while (pItemsRC)
671 {
672 PPDMQUEUEITEMCORE pInsert = (PPDMQUEUEITEMCORE)MMHyperRCToR3(pQueue->pVMR3, pItemsRC);
673 pItemsRC = pInsert->pNextRC;
674 pInsert->pNextRC = NIL_RTRCPTR;
675 pInsert->pNextR3 = pItems;
676 pItems = pInsert;
677 }
678
679 /*
680 * Do the same for any pending R0 items.
681 */
682 while (pItemsR0)
683 {
684 PPDMQUEUEITEMCORE pInsert = (PPDMQUEUEITEMCORE)MMHyperR0ToR3(pQueue->pVMR3, pItemsR0);
685 pItemsR0 = pInsert->pNextR0;
686 pInsert->pNextR0 = NIL_RTR0PTR;
687 pInsert->pNextR3 = pItems;
688 pItems = pInsert;
689 }
690
691 /*
692 * Feed the items to the consumer function.
693 */
694 Log2(("pdmR3QueueFlush: pQueue=%p enmType=%d pItems=%p\n", pQueue, pQueue->enmType, pItems));
695 switch (pQueue->enmType)
696 {
697 case PDMQUEUETYPE_DEV:
698 while (pItems)
699 {
700 pCur = pItems;
701 pItems = pItems->pNextR3;
702 if (!pQueue->u.Dev.pfnCallback(pQueue->u.Dev.pDevIns, pCur))
703 break;
704 pdmR3QueueFree(pQueue, pCur);
705 }
706 break;
707
708 case PDMQUEUETYPE_DRV:
709 while (pItems)
710 {
711 pCur = pItems;
712 pItems = pItems->pNextR3;
713 if (!pQueue->u.Drv.pfnCallback(pQueue->u.Drv.pDrvIns, pCur))
714 break;
715 pdmR3QueueFree(pQueue, pCur);
716 }
717 break;
718
719 case PDMQUEUETYPE_INTERNAL:
720 while (pItems)
721 {
722 pCur = pItems;
723 pItems = pItems->pNextR3;
724 if (!pQueue->u.Int.pfnCallback(pQueue->pVMR3, pCur))
725 break;
726 pdmR3QueueFree(pQueue, pCur);
727 }
728 break;
729
730 case PDMQUEUETYPE_EXTERNAL:
731 while (pItems)
732 {
733 pCur = pItems;
734 pItems = pItems->pNextR3;
735 if (!pQueue->u.Ext.pfnCallback(pQueue->u.Ext.pvUser, pCur))
736 break;
737 pdmR3QueueFree(pQueue, pCur);
738 }
739 break;
740
741 default:
742 AssertMsgFailed(("Invalid queue type %d\n", pQueue->enmType));
743 break;
744 }
745
746 /*
747 * Success?
748 */
749 if (pItems)
750 {
751 /*
752 * Shit, no!
753 * 1. Insert pCur.
754 * 2. Reverse the list.
755 * 3. Insert the LIFO at the tail of the pending list.
756 */
757 pCur->pNextR3 = pItems;
758 pItems = pCur;
759
760 //pCur = pItems;
761 pItems = NULL;
762 while (pCur)
763 {
764 PPDMQUEUEITEMCORE pInsert = pCur;
765 pCur = pCur->pNextR3;
766 pInsert->pNextR3 = pItems;
767 pItems = pInsert;
768 }
769
770 if (!ASMAtomicCmpXchgPtr((void * volatile *)&pQueue->pPendingR3, pItems, NULL))
771 {
772 pCur = pQueue->pPendingR3;
773 while (pCur->pNextR3)
774 pCur = pCur->pNextR3;
775 pCur->pNextR3 = pItems;
776 }
777 return false;
778 }
779
780 return true;
781}
782
783
784/**
785 * This is a worker function used by PDMQueueFlush to perform the
786 * flush in ring-3.
787 *
788 * The queue which should be flushed is pointed to by either pQueueFlushRC,
789 * pQueueFlushR0, or pQueue. This function will flush that queue and recalc
790 * the queue FF.
791 *
792 * @param pVM The VM handle.
793 * @param pQueue The queue to flush. Only used in Ring-3.
794 */
795VMMR3DECL(void) PDMR3QueueFlushWorker(PVM pVM, PPDMQUEUE pQueue)
796{
797 Assert(pVM->pdm.s.pQueueFlushR0 || pVM->pdm.s.pQueueFlushRC || pQueue);
798 VM_ASSERT_EMT(pVM);
799
800 /*
801 * Flush the queue.
802 */
803 if (!pQueue && pVM->pdm.s.pQueueFlushRC)
804 {
805 pQueue = (PPDMQUEUE)MMHyperRCToR3(pVM, pVM->pdm.s.pQueueFlushRC);
806 pVM->pdm.s.pQueueFlushRC = NIL_RTRCPTR;
807 }
808 else if (!pQueue && pVM->pdm.s.pQueueFlushR0)
809 {
810 pQueue = (PPDMQUEUE)MMHyperR0ToR3(pVM, pVM->pdm.s.pQueueFlushR0);
811 pVM->pdm.s.pQueueFlushR0 = NIL_RTR0PTR;
812 }
813 Assert(!pVM->pdm.s.pQueueFlushR0 && !pVM->pdm.s.pQueueFlushRC);
814
815 if ( !pQueue
816 || pdmR3QueueFlush(pQueue))
817 {
818 /*
819 * Recalc the FF (for the queues using force action).
820 */
821 VM_FF_CLEAR(pVM, VM_FF_PDM_QUEUES);
822 for (pQueue = pVM->pdm.s.pQueuesForced; pQueue; pQueue = pQueue->pNext)
823 if ( pQueue->pPendingRC
824 || pQueue->pPendingR0
825 || pQueue->pPendingR3)
826 {
827 VM_FF_SET(pVM, VM_FF_PDM_QUEUES);
828 break;
829 }
830 }
831}
832
833
834/**
835 * Free an item.
836 *
837 * @param pQueue The queue.
838 * @param pItem The item.
839 */
840DECLINLINE(void) pdmR3QueueFree(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem)
841{
842 VM_ASSERT_EMT(pQueue->pVMR3);
843
844 int i = pQueue->iFreeHead;
845 int iNext = (i + 1) % (pQueue->cItems + PDMQUEUE_FREE_SLACK);
846
847 pQueue->aFreeItems[i].pItemR3 = pItem;
848 if (pQueue->pVMRC)
849 {
850 pQueue->aFreeItems[i].pItemRC = MMHyperR3ToRC(pQueue->pVMR3, pItem);
851 pQueue->aFreeItems[i].pItemR0 = MMHyperR3ToR0(pQueue->pVMR3, pItem);
852 }
853
854 if (!ASMAtomicCmpXchgU32(&pQueue->iFreeHead, iNext, i))
855 AssertMsgFailed(("huh? i=%d iNext=%d iFreeHead=%d iFreeTail=%d\n", i, iNext, pQueue->iFreeHead, pQueue->iFreeTail));
856}
857
858
859/**
860 * Timer handler for PDM queues.
861 * This is called by for a single queue.
862 *
863 * @param pVM VM handle.
864 * @param pTimer Pointer to timer.
865 * @param pvUser Pointer to the queue.
866 */
867static DECLCALLBACK(void) pdmR3QueueTimer(PVM pVM, PTMTIMER pTimer, void *pvUser)
868{
869 PPDMQUEUE pQueue = (PPDMQUEUE)pvUser;
870 Assert(pTimer == pQueue->pTimer); NOREF(pTimer);
871
872 if ( pQueue->pPendingR3
873 || pQueue->pPendingR0
874 || pQueue->pPendingRC)
875 pdmR3QueueFlush(pQueue);
876 int rc = TMTimerSetMillies(pQueue->pTimer, pQueue->cMilliesInterval);
877 AssertRC(rc);
878}
879
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use