VirtualBox

source: vbox/trunk/src/VBox/VMM/VMReq.cpp@ 10700

Last change on this file since 10700 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 34.7 KB
Line 
1/* $Id: VMReq.cpp 8155 2008-04-18 15:16:47Z vboxsync $ */
2/** @file
3 * VM - Virtual Machine
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_VM
27#include <VBox/mm.h>
28#include <VBox/vmm.h>
29#include "VMInternal.h"
30#include <VBox/vm.h>
31#include <VBox/uvm.h>
32
33#include <VBox/err.h>
34#include <VBox/param.h>
35#include <VBox/log.h>
36#include <iprt/assert.h>
37#include <iprt/asm.h>
38#include <iprt/string.h>
39#include <iprt/time.h>
40#include <iprt/semaphore.h>
41#include <iprt/thread.h>
42
43
44/*******************************************************************************
45* Internal Functions *
46*******************************************************************************/
47static int vmR3ReqProcessOneU(PUVM pUVM, PVMREQ pReq);
48
49
50/**
51 * Allocate and queue a call request.
52 *
53 * If it's desired to poll on the completion of the request set cMillies
54 * to 0 and use VMR3ReqWait() to check for completation. In the other case
55 * use RT_INDEFINITE_WAIT.
56 * The returned request packet must be freed using VMR3ReqFree().
57 *
58 * @returns VBox status code.
59 * Will not return VERR_INTERRUPTED.
60 * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
61 *
62 * @param pVM The VM handle.
63 * @param ppReq Where to store the pointer to the request.
64 * This will be NULL or a valid request pointer not matter what happends.
65 * @param cMillies Number of milliseconds to wait for the request to
66 * be completed. Use RT_INDEFINITE_WAIT to only
67 * wait till it's completed.
68 * @param pfnFunction Pointer to the function to call.
69 * @param cArgs Number of arguments following in the ellipsis.
70 * Not possible to pass 64-bit arguments!
71 * @param ... Function arguments.
72 */
73VMR3DECL(int) VMR3ReqCall(PVM pVM, PVMREQ *ppReq, unsigned cMillies, PFNRT pfnFunction, unsigned cArgs, ...)
74{
75 va_list va;
76 va_start(va, cArgs);
77 int rc = VMR3ReqCallVU(pVM->pUVM, ppReq, cMillies, VMREQFLAGS_VBOX_STATUS, pfnFunction, cArgs, va);
78 va_end(va);
79 return rc;
80}
81
82
83/**
84 * Allocate and queue a call request to a void function.
85 *
86 * If it's desired to poll on the completion of the request set cMillies
87 * to 0 and use VMR3ReqWait() to check for completation. In the other case
88 * use RT_INDEFINITE_WAIT.
89 * The returned request packet must be freed using VMR3ReqFree().
90 *
91 * @returns VBox status code.
92 * Will not return VERR_INTERRUPTED.
93 * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
94 *
95 * @param pUVM Pointer to the user mode VM structure.
96 * @param ppReq Where to store the pointer to the request.
97 * This will be NULL or a valid request pointer not matter what happends.
98 * @param cMillies Number of milliseconds to wait for the request to
99 * be completed. Use RT_INDEFINITE_WAIT to only
100 * wait till it's completed.
101 * @param pfnFunction Pointer to the function to call.
102 * @param cArgs Number of arguments following in the ellipsis.
103 * Not possible to pass 64-bit arguments!
104 * @param ... Function arguments.
105 */
106VMR3DECL(int) VMR3ReqCallVoidU(PUVM pUVM, PVMREQ *ppReq, unsigned cMillies, PFNRT pfnFunction, unsigned cArgs, ...)
107{
108 va_list va;
109 va_start(va, cArgs);
110 int rc = VMR3ReqCallVU(pUVM, ppReq, cMillies, VMREQFLAGS_VOID, pfnFunction, cArgs, va);
111 va_end(va);
112 return rc;
113}
114
115
116/**
117 * Allocate and queue a call request to a void function.
118 *
119 * If it's desired to poll on the completion of the request set cMillies
120 * to 0 and use VMR3ReqWait() to check for completation. In the other case
121 * use RT_INDEFINITE_WAIT.
122 * The returned request packet must be freed using VMR3ReqFree().
123 *
124 * @returns VBox status code.
125 * Will not return VERR_INTERRUPTED.
126 * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
127 *
128 * @param pVM The VM handle.
129 * @param ppReq Where to store the pointer to the request.
130 * This will be NULL or a valid request pointer not matter what happends.
131 * @param cMillies Number of milliseconds to wait for the request to
132 * be completed. Use RT_INDEFINITE_WAIT to only
133 * wait till it's completed.
134 * @param pfnFunction Pointer to the function to call.
135 * @param cArgs Number of arguments following in the ellipsis.
136 * Not possible to pass 64-bit arguments!
137 * @param ... Function arguments.
138 */
139VMR3DECL(int) VMR3ReqCallVoid(PVM pVM, PVMREQ *ppReq, unsigned cMillies, PFNRT pfnFunction, unsigned cArgs, ...)
140{
141 va_list va;
142 va_start(va, cArgs);
143 int rc = VMR3ReqCallVU(pVM->pUVM, ppReq, cMillies, VMREQFLAGS_VOID, pfnFunction, cArgs, va);
144 va_end(va);
145 return rc;
146}
147
148
149/**
150 * Allocate and queue a call request to a void function.
151 *
152 * If it's desired to poll on the completion of the request set cMillies
153 * to 0 and use VMR3ReqWait() to check for completation. In the other case
154 * use RT_INDEFINITE_WAIT.
155 * The returned request packet must be freed using VMR3ReqFree().
156 *
157 * @returns VBox status code.
158 * Will not return VERR_INTERRUPTED.
159 * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
160 *
161 * @param pVM The VM handle.
162 * @param ppReq Where to store the pointer to the request.
163 * This will be NULL or a valid request pointer not matter what happends, unless fFlags
164 * contains VMREQFLAGS_NO_WAIT when it will be optional and always NULL.
165 * @param cMillies Number of milliseconds to wait for the request to
166 * be completed. Use RT_INDEFINITE_WAIT to only
167 * wait till it's completed.
168 * @param fFlags A combination of the VMREQFLAGS values.
169 * @param pfnFunction Pointer to the function to call.
170 * @param cArgs Number of arguments following in the ellipsis.
171 * Not possible to pass 64-bit arguments!
172 * @param ... Function arguments.
173 */
174VMR3DECL(int) VMR3ReqCallEx(PVM pVM, PVMREQ *ppReq, unsigned cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, ...)
175{
176 va_list va;
177 va_start(va, cArgs);
178 int rc = VMR3ReqCallVU(pVM->pUVM, ppReq, cMillies, fFlags, pfnFunction, cArgs, va);
179 va_end(va);
180 return rc;
181}
182
183
184/**
185 * Allocate and queue a call request to a void function.
186 *
187 * If it's desired to poll on the completion of the request set cMillies
188 * to 0 and use VMR3ReqWait() to check for completation. In the other case
189 * use RT_INDEFINITE_WAIT.
190 * The returned request packet must be freed using VMR3ReqFree().
191 *
192 * @returns VBox status code.
193 * Will not return VERR_INTERRUPTED.
194 * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
195 *
196 * @param pUVM Pointer to the user mode VM structure.
197 * @param ppReq Where to store the pointer to the request.
198 * This will be NULL or a valid request pointer not matter what happends, unless fFlags
199 * contains VMREQFLAGS_NO_WAIT when it will be optional and always NULL.
200 * @param cMillies Number of milliseconds to wait for the request to
201 * be completed. Use RT_INDEFINITE_WAIT to only
202 * wait till it's completed.
203 * @param fFlags A combination of the VMREQFLAGS values.
204 * @param pfnFunction Pointer to the function to call.
205 * @param cArgs Number of arguments following in the ellipsis.
206 * Not possible to pass 64-bit arguments!
207 * @param ... Function arguments.
208 */
209VMR3DECL(int) VMR3ReqCallU(PUVM pUVM, PVMREQ *ppReq, unsigned cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, ...)
210{
211 va_list va;
212 va_start(va, cArgs);
213 int rc = VMR3ReqCallVU(pUVM, ppReq, cMillies, fFlags, pfnFunction, cArgs, va);
214 va_end(va);
215 return rc;
216}
217
218
219/**
220 * Allocate and queue a call request.
221 *
222 * If it's desired to poll on the completion of the request set cMillies
223 * to 0 and use VMR3ReqWait() to check for completation. In the other case
224 * use RT_INDEFINITE_WAIT.
225 * The returned request packet must be freed using VMR3ReqFree().
226 *
227 * @returns VBox status code.
228 * Will not return VERR_INTERRUPTED.
229 * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
230 *
231 * @param pUVM Pointer to the user mode VM structure.
232 * @param ppReq Where to store the pointer to the request.
233 * This will be NULL or a valid request pointer not matter what happends, unless fFlags
234 * contains VMREQFLAGS_NO_WAIT when it will be optional and always NULL.
235 * @param cMillies Number of milliseconds to wait for the request to
236 * be completed. Use RT_INDEFINITE_WAIT to only
237 * wait till it's completed.
238 * @param pfnFunction Pointer to the function to call.
239 * @param fFlags A combination of the VMREQFLAGS values.
240 * @param cArgs Number of arguments following in the ellipsis.
241 * Stuff which differs in size from uintptr_t is gonna make trouble, so don't try!
242 * @param Args Argument vector.
243 */
244VMR3DECL(int) VMR3ReqCallVU(PUVM pUVM, PVMREQ *ppReq, unsigned cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args)
245{
246 LogFlow(("VMR3ReqCallV: cMillies=%d fFlags=%#x pfnFunction=%p cArgs=%d\n", cMillies, fFlags, pfnFunction, cArgs));
247
248 /*
249 * Validate input.
250 */
251 AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER);
252 AssertPtrReturn(pUVM, VERR_INVALID_POINTER);
253 AssertReturn(!(fFlags & ~(VMREQFLAGS_RETURN_MASK | VMREQFLAGS_NO_WAIT)), VERR_INVALID_PARAMETER);
254 if (!(fFlags & VMREQFLAGS_NO_WAIT) || ppReq)
255 {
256 AssertPtrReturn(ppReq, VERR_INVALID_POINTER);
257 *ppReq = NULL;
258 }
259 PVMREQ pReq = NULL;
260 AssertMsgReturn(cArgs * sizeof(uintptr_t) <= sizeof(pReq->u.Internal.aArgs),
261 ("cArg=%d\n", cArgs),
262 VERR_TOO_MUCH_DATA);
263
264 /*
265 * Allocate request
266 */
267 int rc = VMR3ReqAllocU(pUVM, &pReq, VMREQTYPE_INTERNAL);
268 if (VBOX_FAILURE(rc))
269 return rc;
270
271 /*
272 * Initialize the request data.
273 */
274 pReq->fFlags = fFlags;
275 pReq->u.Internal.pfn = pfnFunction;
276 pReq->u.Internal.cArgs = cArgs;
277 for (unsigned iArg = 0; iArg < cArgs; iArg++)
278 pReq->u.Internal.aArgs[iArg] = va_arg(Args, uintptr_t);
279
280 /*
281 * Queue the request and return.
282 */
283 rc = VMR3ReqQueue(pReq, cMillies);
284 if ( VBOX_FAILURE(rc)
285 && rc != VERR_TIMEOUT)
286 {
287 VMR3ReqFree(pReq);
288 pReq = NULL;
289 }
290 if (!(fFlags & VMREQFLAGS_NO_WAIT))
291 {
292 *ppReq = pReq;
293 LogFlow(("VMR3ReqCallV: returns %Vrc *ppReq=%p\n", rc, pReq));
294 }
295 else
296 LogFlow(("VMR3ReqCallV: returns %Vrc\n", rc));
297 Assert(rc != VERR_INTERRUPTED);
298 return rc;
299}
300
301
302/**
303 * Joins the list pList with whatever is linked up at *pHead.
304 */
305static void vmr3ReqJoinFreeSub(volatile PVMREQ *ppHead, PVMREQ pList)
306{
307 for (unsigned cIterations = 0;; cIterations++)
308 {
309 PVMREQ pHead = (PVMREQ)ASMAtomicXchgPtr((void * volatile *)ppHead, pList);
310 if (!pHead)
311 return;
312 PVMREQ pTail = pHead;
313 while (pTail->pNext)
314 pTail = pTail->pNext;
315 pTail->pNext = pList;
316 if (ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (void *)pHead, pList))
317 return;
318 pTail->pNext = NULL;
319 if (ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (void *)pHead, NULL))
320 return;
321 pList = pHead;
322 Assert(cIterations != 32);
323 Assert(cIterations != 64);
324 }
325}
326
327
328/**
329 * Joins the list pList with whatever is linked up at *pHead.
330 */
331static void vmr3ReqJoinFree(PVMINTUSERPERVM pVMInt, PVMREQ pList)
332{
333 /*
334 * Split the list if it's too long.
335 */
336 unsigned cReqs = 1;
337 PVMREQ pTail = pList;
338 while (pTail->pNext)
339 {
340 if (cReqs++ > 25)
341 {
342 const uint32_t i = pVMInt->iReqFree;
343 vmr3ReqJoinFreeSub(&pVMInt->apReqFree[(i + 2) % RT_ELEMENTS(pVMInt->apReqFree)], pTail->pNext);
344
345 pTail->pNext = NULL;
346 vmr3ReqJoinFreeSub(&pVMInt->apReqFree[(i + 2 + (i == pVMInt->iReqFree)) % RT_ELEMENTS(pVMInt->apReqFree)], pTail->pNext);
347 return;
348 }
349 pTail = pTail->pNext;
350 }
351 vmr3ReqJoinFreeSub(&pVMInt->apReqFree[(pVMInt->iReqFree + 2) % RT_ELEMENTS(pVMInt->apReqFree)], pList);
352}
353
354
355/**
356 * Allocates a request packet.
357 *
358 * The caller allocates a request packet, fills in the request data
359 * union and queues the request.
360 *
361 * @returns VBox status code.
362 *
363 * @param pVM VM handle.
364 * @param ppReq Where to store the pointer to the allocated packet.
365 * @param enmType Package type.
366 */
367VMR3DECL(int) VMR3ReqAlloc(PVM pVM, PVMREQ *ppReq, VMREQTYPE enmType)
368{
369 return VMR3ReqAllocU(pVM->pUVM, ppReq, enmType);
370}
371
372
373/**
374 * Allocates a request packet.
375 *
376 * The caller allocates a request packet, fills in the request data
377 * union and queues the request.
378 *
379 * @returns VBox status code.
380 *
381 * @param pUVM Pointer to the user mode VM structure.
382 * @param ppReq Where to store the pointer to the allocated packet.
383 * @param enmType Package type.
384 */
385VMR3DECL(int) VMR3ReqAllocU(PUVM pUVM, PVMREQ *ppReq, VMREQTYPE enmType)
386{
387 /*
388 * Validate input.
389 */
390 AssertMsgReturn(enmType > VMREQTYPE_INVALID && enmType < VMREQTYPE_MAX,
391 ("Invalid package type %d valid range %d-%d inclusivly.\n",
392 enmType, VMREQTYPE_INVALID + 1, VMREQTYPE_MAX - 1),
393 VERR_VM_REQUEST_INVALID_TYPE);
394 AssertPtrReturn(ppReq, VERR_INVALID_POINTER);
395
396 /*
397 * Try get a recycled packet.
398 * While this could all be solved with a single list with a lock, it's a sport
399 * of mine to avoid locks.
400 */
401 int cTries = RT_ELEMENTS(pUVM->vm.s.apReqFree) * 2;
402 while (--cTries >= 0)
403 {
404 PVMREQ volatile *ppHead = &pUVM->vm.s.apReqFree[ASMAtomicIncU32(&pUVM->vm.s.iReqFree) % RT_ELEMENTS(pUVM->vm.s.apReqFree)];
405#if 0 /* sad, but this won't work safely because the reading of pReq->pNext. */
406 PVMREQ pNext = NULL;
407 PVMREQ pReq = *ppHead;
408 if ( pReq
409 && !ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (pNext = pReq->pNext), pReq)
410 && (pReq = *ppHead)
411 && !ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (pNext = pReq->pNext), pReq))
412 pReq = NULL;
413 if (pReq)
414 {
415 Assert(pReq->pNext == pNext); NOREF(pReq);
416#else
417 PVMREQ pReq = (PVMREQ)ASMAtomicXchgPtr((void * volatile *)ppHead, NULL);
418 if (pReq)
419 {
420 PVMREQ pNext = pReq->pNext;
421 if ( pNext
422 && !ASMAtomicCmpXchgPtr((void * volatile *)ppHead, pNext, NULL))
423 {
424 STAM_COUNTER_INC(&pUVM->vm.s.StatReqAllocRaces);
425 vmr3ReqJoinFree(&pUVM->vm.s, pReq->pNext);
426 }
427#endif
428 ASMAtomicDecU32(&pUVM->vm.s.cReqFree);
429
430 /*
431 * Make sure the event sem is not signaled.
432 */
433 if (!pReq->fEventSemClear)
434 {
435 int rc = RTSemEventWait(pReq->EventSem, 0);
436 if (rc != VINF_SUCCESS && rc != VERR_TIMEOUT)
437 {
438 /*
439 * This shall not happen, but if it does we'll just destroy
440 * the semaphore and create a new one.
441 */
442 AssertMsgFailed(("rc=%Vrc from RTSemEventWait(%#x).\n", rc, pReq->EventSem));
443 RTSemEventDestroy(pReq->EventSem);
444 rc = RTSemEventCreate(&pReq->EventSem);
445 AssertRC(rc);
446 if (VBOX_FAILURE(rc))
447 return rc;
448 }
449 pReq->fEventSemClear = true;
450 }
451 else
452 Assert(RTSemEventWait(pReq->EventSem, 0) == VERR_TIMEOUT);
453
454 /*
455 * Initialize the packet and return it.
456 */
457 Assert(pReq->enmType == VMREQTYPE_INVALID);
458 Assert(pReq->enmState == VMREQSTATE_FREE);
459 Assert(pReq->pUVM == pUVM);
460 ASMAtomicXchgSize(&pReq->pNext, NULL);
461 pReq->enmState = VMREQSTATE_ALLOCATED;
462 pReq->iStatus = VERR_VM_REQUEST_STATUS_STILL_PENDING;
463 pReq->fFlags = VMREQFLAGS_VBOX_STATUS;
464 pReq->enmType = enmType;
465
466 *ppReq = pReq;
467 STAM_COUNTER_INC(&pUVM->vm.s.StatReqAllocRecycled);
468 LogFlow(("VMR3ReqAlloc: returns VINF_SUCCESS *ppReq=%p recycled\n", pReq));
469 return VINF_SUCCESS;
470 }
471 }
472
473 /*
474 * Ok allocate one.
475 */
476 PVMREQ pReq = (PVMREQ)MMR3HeapAllocU(pUVM, MM_TAG_VM_REQ, sizeof(*pReq));
477 if (!pReq)
478 return VERR_NO_MEMORY;
479
480 /*
481 * Create the semaphore.
482 */
483 int rc = RTSemEventCreate(&pReq->EventSem);
484 AssertRC(rc);
485 if (VBOX_FAILURE(rc))
486 {
487 MMR3HeapFree(pReq);
488 return rc;
489 }
490
491 /*
492 * Initialize the packet and return it.
493 */
494 pReq->pNext = NULL;
495 pReq->pUVM = pUVM;
496 pReq->enmState = VMREQSTATE_ALLOCATED;
497 pReq->iStatus = VERR_VM_REQUEST_STATUS_STILL_PENDING;
498 pReq->fEventSemClear = true;
499 pReq->fFlags = VMREQFLAGS_VBOX_STATUS;
500 pReq->enmType = enmType;
501
502 *ppReq = pReq;
503 STAM_COUNTER_INC(&pUVM->vm.s.StatReqAllocNew);
504 LogFlow(("VMR3ReqAlloc: returns VINF_SUCCESS *ppReq=%p new\n", pReq));
505 return VINF_SUCCESS;
506}
507
508
509/**
510 * Free a request packet.
511 *
512 * @returns VBox status code.
513 *
514 * @param pReq Package to free.
515 * @remark The request packet must be in allocated or completed state!
516 */
517VMR3DECL(int) VMR3ReqFree(PVMREQ pReq)
518{
519 /*
520 * Ignore NULL (all free functions should do this imho).
521 */
522 if (!pReq)
523 return VINF_SUCCESS;
524
525 /*
526 * Check packet state.
527 */
528 switch (pReq->enmState)
529 {
530 case VMREQSTATE_ALLOCATED:
531 case VMREQSTATE_COMPLETED:
532 break;
533 default:
534 AssertMsgFailed(("Invalid state %d!\n", pReq->enmState));
535 return VERR_VM_REQUEST_STATE;
536 }
537
538 /*
539 * Make it a free packet and put it into one of the free packet lists.
540 */
541 pReq->enmState = VMREQSTATE_FREE;
542 pReq->iStatus = VERR_VM_REQUEST_STATUS_FREED;
543 pReq->enmType = VMREQTYPE_INVALID;
544
545 PUVM pUVM = pReq->pUVM;
546 STAM_COUNTER_INC(&pUVM->vm.s.StatReqFree);
547
548 if (pUVM->vm.s.cReqFree < 128)
549 {
550 ASMAtomicIncU32(&pUVM->vm.s.cReqFree);
551 PVMREQ volatile *ppHead = &pUVM->vm.s.apReqFree[ASMAtomicIncU32(&pUVM->vm.s.iReqFree) % RT_ELEMENTS(pUVM->vm.s.apReqFree)];
552 PVMREQ pNext;
553 do
554 {
555 pNext = *ppHead;
556 ASMAtomicXchgPtr((void * volatile *)&pReq->pNext, pNext);
557 } while (!ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (void *)pReq, (void *)pNext));
558 }
559 else
560 {
561 STAM_COUNTER_INC(&pReq->pUVM->vm.s.StatReqFreeOverflow);
562 RTSemEventDestroy(pReq->EventSem);
563 MMR3HeapFree(pReq);
564 }
565 return VINF_SUCCESS;
566}
567
568
569/**
570 * Queue a request.
571 *
572 * The quest must be allocated using VMR3ReqAlloc() and contain
573 * all the required data.
574 * If it's desired to poll on the completion of the request set cMillies
575 * to 0 and use VMR3ReqWait() to check for completation. In the other case
576 * use RT_INDEFINITE_WAIT.
577 *
578 * @returns VBox status code.
579 * Will not return VERR_INTERRUPTED.
580 * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
581 *
582 * @param pReq The request to queue.
583 * @param cMillies Number of milliseconds to wait for the request to
584 * be completed. Use RT_INDEFINITE_WAIT to only
585 * wait till it's completed.
586 */
587VMR3DECL(int) VMR3ReqQueue(PVMREQ pReq, unsigned cMillies)
588{
589 LogFlow(("VMR3ReqQueue: pReq=%p cMillies=%d\n", pReq, cMillies));
590 /*
591 * Verify the supplied package.
592 */
593 AssertMsgReturn(pReq->enmState == VMREQSTATE_ALLOCATED, ("%d\n", pReq->enmState), VERR_VM_REQUEST_STATE);
594 AssertMsgReturn( VALID_PTR(pReq->pUVM)
595 && !pReq->pNext
596 && pReq->EventSem != NIL_RTSEMEVENT,
597 ("Invalid request package! Anyone cooking their own packages???\n"),
598 VERR_VM_REQUEST_INVALID_PACKAGE);
599 AssertMsgReturn( pReq->enmType > VMREQTYPE_INVALID
600 && pReq->enmType < VMREQTYPE_MAX,
601 ("Invalid package type %d valid range %d-%d inclusivly. This was verified on alloc too...\n",
602 pReq->enmType, VMREQTYPE_INVALID + 1, VMREQTYPE_MAX - 1),
603 VERR_VM_REQUEST_INVALID_TYPE);
604
605 /*
606 * Are we the EMT or not?
607 * Also, store pVM (and fFlags) locally since pReq may be invalid after queuing it.
608 */
609 int rc = VINF_SUCCESS;
610 PUVM pUVM = ((VMREQ volatile *)pReq)->pUVM; /* volatile paranoia */
611 if (pUVM->vm.s.NativeThreadEMT != RTThreadNativeSelf())
612 {
613 unsigned fFlags = ((VMREQ volatile *)pReq)->fFlags; /* volatile paranoia */
614
615 /*
616 * Insert it.
617 */
618 pReq->enmState = VMREQSTATE_QUEUED;
619 PVMREQ pNext;
620 do
621 {
622 pNext = pUVM->vm.s.pReqs;
623 pReq->pNext = pNext;
624 } while (!ASMAtomicCmpXchgPtr((void * volatile *)&pUVM->vm.s.pReqs, (void *)pReq, (void *)pNext));
625
626 /*
627 * Notify EMT.
628 */
629 if (pUVM->pVM)
630 VM_FF_SET(pUVM->pVM, VM_FF_REQUEST);
631 VMR3NotifyFFU(pUVM, false);
632
633 /*
634 * Wait and return.
635 */
636 if (!(fFlags & VMREQFLAGS_NO_WAIT))
637 rc = VMR3ReqWait(pReq, cMillies);
638 LogFlow(("VMR3ReqQueue: returns %Vrc\n", rc));
639 }
640 else
641 {
642 /*
643 * The requester was EMT, just execute it.
644 */
645 pReq->enmState = VMREQSTATE_QUEUED;
646 rc = vmR3ReqProcessOneU(pUVM, pReq);
647 LogFlow(("VMR3ReqQueue: returns %Vrc (processed)\n", rc));
648 }
649 return rc;
650}
651
652
653/**
654 * Wait for a request to be completed.
655 *
656 * @returns VBox status code.
657 * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
658 *
659 * @param pReq The request to wait for.
660 * @param cMillies Number of milliseconds to wait.
661 * Use RT_INDEFINITE_WAIT to only wait till it's completed.
662 */
663VMR3DECL(int) VMR3ReqWait(PVMREQ pReq, unsigned cMillies)
664{
665 LogFlow(("VMR3ReqWait: pReq=%p cMillies=%d\n", pReq, cMillies));
666
667 /*
668 * Verify the supplied package.
669 */
670 AssertMsgReturn( pReq->enmState == VMREQSTATE_QUEUED
671 || pReq->enmState == VMREQSTATE_PROCESSING
672 || pReq->enmState == VMREQSTATE_COMPLETED,
673 ("Invalid state %d\n", pReq->enmState),
674 VERR_VM_REQUEST_STATE);
675 AssertMsgReturn( VALID_PTR(pReq->pUVM)
676 && pReq->EventSem != NIL_RTSEMEVENT,
677 ("Invalid request package! Anyone cooking their own packages???\n"),
678 VERR_VM_REQUEST_INVALID_PACKAGE);
679 AssertMsgReturn( pReq->enmType > VMREQTYPE_INVALID
680 && pReq->enmType < VMREQTYPE_MAX,
681 ("Invalid package type %d valid range %d-%d inclusivly. This was verified on alloc too...\n",
682 pReq->enmType, VMREQTYPE_INVALID + 1, VMREQTYPE_MAX - 1),
683 VERR_VM_REQUEST_INVALID_TYPE);
684
685 /*
686 * Check for deadlock condition
687 */
688 PUVM pUVM = pReq->pUVM;
689 NOREF(pUVM);
690 AssertMsg(!pUVM->pVM || !VMMR3LockIsOwner(pUVM->pVM),
691 ("Waiting for EMT to process a request, but we own the global VM lock!?!?!?!\n"));
692
693 /*
694 * Wait on the package.
695 */
696 int rc;
697 if (cMillies != RT_INDEFINITE_WAIT)
698 rc = RTSemEventWait(pReq->EventSem, cMillies);
699 else
700 {
701 do
702 {
703 rc = RTSemEventWait(pReq->EventSem, RT_INDEFINITE_WAIT);
704 Assert(rc != VERR_TIMEOUT);
705 } while ( pReq->enmState != VMREQSTATE_COMPLETED
706 && pReq->enmState != VMREQSTATE_INVALID);
707 }
708 if (VBOX_SUCCESS(rc))
709 ASMAtomicXchgSize(&pReq->fEventSemClear, true);
710 if (pReq->enmState == VMREQSTATE_COMPLETED)
711 rc = VINF_SUCCESS;
712 LogFlow(("VMR3ReqWait: returns %Vrc\n", rc));
713 Assert(rc != VERR_INTERRUPTED);
714 return rc;
715}
716
717
718/**
719 * Process pending request(s).
720 *
721 * This function is called from a forced action handler in the EMT
722 * or from one of the EMT loops.
723 *
724 * @returns VBox status code.
725 *
726 * @param pUVM Pointer to the user mode VM structure.
727 */
728VMR3DECL(int) VMR3ReqProcessU(PUVM pUVM)
729{
730 LogFlow(("VMR3ReqProcessU: (enmVMState=%d)\n", pUVM->pVM ? pUVM->pVM->enmVMState : VMSTATE_CREATING));
731
732 /*
733 * Process loop.
734 *
735 * We do not repeat the outer loop if we've got an informationtional status code
736 * since that code needs processing by our caller.
737 */
738 int rc = VINF_SUCCESS;
739 while (rc <= VINF_SUCCESS)
740 {
741 /*
742 * Get pending requests.
743 */
744 if (RT_LIKELY(pUVM->pVM))
745 VM_FF_CLEAR(pUVM->pVM, VM_FF_REQUEST);
746 PVMREQ pReqs = (PVMREQ)ASMAtomicXchgPtr((void * volatile *)&pUVM->vm.s.pReqs, NULL);
747 if (!pReqs)
748 break;
749
750 /*
751 * Reverse the list to process it in FIFO order.
752 */
753 PVMREQ pReq = pReqs;
754 if (pReq->pNext)
755 Log2(("VMR3ReqProcess: 2+ requests: %p %p %p\n", pReq, pReq->pNext, pReq->pNext->pNext));
756 pReqs = NULL;
757 while (pReq)
758 {
759 Assert(pReq->enmState == VMREQSTATE_QUEUED);
760 Assert(pReq->pUVM == pUVM);
761 PVMREQ pCur = pReq;
762 pReq = pReq->pNext;
763 pCur->pNext = pReqs;
764 pReqs = pCur;
765 }
766
767
768 /*
769 * Process the requests.
770 *
771 * Since this is a FF worker certain rules applies to the
772 * status codes. See the EM section in VBox/err.h and EM.cpp for details.
773 */
774 while (pReqs)
775 {
776 /* Unchain the first request and advance the list. */
777 pReq = pReqs;
778 pReqs = pReqs->pNext;
779 pReq->pNext = NULL;
780
781 /* Process the request */
782 int rc2 = vmR3ReqProcessOneU(pUVM, pReq);
783
784 /*
785 * The status code handling extremely important yet very fragile. Should probably
786 * look for a better way of communicating status changes to EM...
787 */
788 if ( rc2 >= VINF_EM_FIRST
789 && rc2 <= VINF_EM_LAST
790 && ( rc == VINF_SUCCESS
791 || rc2 < rc) )
792 rc = rc2;
793 }
794 }
795
796 LogFlow(("VMR3ReqProcess: returns %Vrc (enmVMState=%d)\n", rc, pUVM->pVM ? pUVM->pVM->enmVMState : VMSTATE_CREATING));
797 return rc;
798}
799
800
801/**
802 * Process one request.
803 *
804 * @returns VBox status code.
805 *
806 * @param pVM VM handle.
807 * @param pReq Request packet to process.
808 */
809static int vmR3ReqProcessOneU(PUVM pUVM, PVMREQ pReq)
810{
811 LogFlow(("vmR3ReqProcessOne: pReq=%p type=%d fFlags=%#x\n", pReq, pReq->enmType, pReq->fFlags));
812
813 /*
814 * Process the request.
815 */
816 Assert(pReq->enmState == VMREQSTATE_QUEUED);
817 pReq->enmState = VMREQSTATE_PROCESSING;
818 int rcRet = VINF_SUCCESS; /* the return code of this function. */
819 int rcReq = VERR_NOT_IMPLEMENTED; /* the request status. */
820 switch (pReq->enmType)
821 {
822 /*
823 * A packed down call frame.
824 */
825 case VMREQTYPE_INTERNAL:
826 {
827 uintptr_t *pauArgs = &pReq->u.Internal.aArgs[0];
828 union
829 {
830 PFNRT pfn;
831 DECLCALLBACKMEMBER(int, pfn00)(void);
832 DECLCALLBACKMEMBER(int, pfn01)(uintptr_t);
833 DECLCALLBACKMEMBER(int, pfn02)(uintptr_t, uintptr_t);
834 DECLCALLBACKMEMBER(int, pfn03)(uintptr_t, uintptr_t, uintptr_t);
835 DECLCALLBACKMEMBER(int, pfn04)(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
836 DECLCALLBACKMEMBER(int, pfn05)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
837 DECLCALLBACKMEMBER(int, pfn06)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
838 DECLCALLBACKMEMBER(int, pfn07)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
839 DECLCALLBACKMEMBER(int, pfn08)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
840 DECLCALLBACKMEMBER(int, pfn09)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
841 DECLCALLBACKMEMBER(int, pfn10)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
842 DECLCALLBACKMEMBER(int, pfn11)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
843 DECLCALLBACKMEMBER(int, pfn12)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
844 } u;
845 u.pfn = pReq->u.Internal.pfn;
846#ifdef RT_ARCH_AMD64
847 switch (pReq->u.Internal.cArgs)
848 {
849 case 0: rcRet = u.pfn00(); break;
850 case 1: rcRet = u.pfn01(pauArgs[0]); break;
851 case 2: rcRet = u.pfn02(pauArgs[0], pauArgs[1]); break;
852 case 3: rcRet = u.pfn03(pauArgs[0], pauArgs[1], pauArgs[2]); break;
853 case 4: rcRet = u.pfn04(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3]); break;
854 case 5: rcRet = u.pfn05(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4]); break;
855 case 6: rcRet = u.pfn06(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5]); break;
856 case 7: rcRet = u.pfn07(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6]); break;
857 case 8: rcRet = u.pfn08(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7]); break;
858 case 9: rcRet = u.pfn09(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8]); break;
859 case 10: rcRet = u.pfn10(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9]); break;
860 case 11: rcRet = u.pfn11(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9], pauArgs[10]); break;
861 case 12: rcRet = u.pfn12(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9], pauArgs[10], pauArgs[11]); break;
862 default:
863 AssertReleaseMsgFailed(("cArgs=%d\n", pReq->u.Internal.cArgs));
864 rcRet = rcReq = VERR_INTERNAL_ERROR;
865 break;
866 }
867#else /* x86: */
868 size_t cbArgs = pReq->u.Internal.cArgs * sizeof(uintptr_t);
869# ifdef __GNUC__
870 __asm__ __volatile__("movl %%esp, %%edx\n\t"
871 "subl %2, %%esp\n\t"
872 "andl $0xfffffff0, %%esp\n\t"
873 "shrl $2, %2\n\t"
874 "movl %%esp, %%edi\n\t"
875 "rep movsl\n\t"
876 "movl %%edx, %%edi\n\t"
877 "call *%%eax\n\t"
878 "mov %%edi, %%esp\n\t"
879 : "=a" (rcRet),
880 "=S" (pauArgs),
881 "=c" (cbArgs)
882 : "0" (u.pfn),
883 "1" (pauArgs),
884 "2" (cbArgs)
885 : "edi", "edx");
886# else
887 __asm
888 {
889 xor edx, edx /* just mess it up. */
890 mov eax, u.pfn
891 mov ecx, cbArgs
892 shr ecx, 2
893 mov esi, pauArgs
894 mov ebx, esp
895 sub esp, cbArgs
896 and esp, 0xfffffff0
897 mov edi, esp
898 rep movsd
899 call eax
900 mov esp, ebx
901 mov rcRet, eax
902 }
903# endif
904#endif /* x86 */
905 if ((pReq->fFlags & (VMREQFLAGS_RETURN_MASK)) == VMREQFLAGS_VOID)
906 rcRet = VINF_SUCCESS;
907 rcReq = rcRet;
908 break;
909 }
910
911 default:
912 AssertMsgFailed(("pReq->enmType=%d\n", pReq->enmType));
913 rcReq = VERR_NOT_IMPLEMENTED;
914 break;
915 }
916
917 /*
918 * Complete the request.
919 */
920 pReq->iStatus = rcReq;
921 pReq->enmState = VMREQSTATE_COMPLETED;
922 if (pReq->fFlags & VMREQFLAGS_NO_WAIT)
923 {
924 /* Free the packet, nobody is waiting. */
925 LogFlow(("vmR3ReqProcessOne: Completed request %p: rcReq=%Vrc rcRet=%Vrc - freeing it\n",
926 pReq, rcReq, rcRet));
927 VMR3ReqFree(pReq);
928 }
929 else
930 {
931 /* Notify the waiter and him free up the packet. */
932 LogFlow(("vmR3ReqProcessOne: Completed request %p: rcReq=%Vrc rcRet=%Vrc - notifying waiting thread\n",
933 pReq, rcReq, rcRet));
934 ASMAtomicXchgSize(&pReq->fEventSemClear, false);
935 int rc2 = RTSemEventSignal(pReq->EventSem);
936 if (VBOX_FAILURE(rc2))
937 {
938 AssertRC(rc2);
939 rcRet = rc2;
940 }
941 }
942 return rcRet;
943}
944
945
946
947
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