VirtualBox

source: vbox/trunk/src/VBox/VMM/VMEmt.cpp@ 2965

Last change on this file since 2965 was 2965, checked in by vboxsync, 18 years ago

Forgot to commit this the other day...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 20.1 KB
Line 
1/* $Id: VMEmt.cpp 2965 2007-05-31 17:22:32Z vboxsync $ */
2/** @file
3 * VM - Virtual Machine, The Emulation Thread.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_VM
27#include <VBox/tm.h>
28#include <VBox/dbgf.h>
29#include <VBox/em.h>
30#include <VBox/pdm.h>
31#include <VBox/rem.h>
32#include "VMInternal.h"
33#include <VBox/vm.h>
34
35#include <VBox/err.h>
36#include <VBox/log.h>
37#include <iprt/assert.h>
38#include <iprt/asm.h>
39#include <iprt/semaphore.h>
40#include <iprt/thread.h>
41#include <iprt/time.h>
42
43
44
45/**
46 * The emulation thread.
47 *
48 * @returns Thread exit code.
49 * @param ThreadSelf The handle to the executing thread.
50 * @param pvArgs Pointer to a VMEMULATIONTHREADARGS structure.
51 */
52DECLCALLBACK(int) vmR3EmulationThread(RTTHREAD ThreadSelf, void *pvArgs)
53{
54 PVMEMULATIONTHREADARGS pArgs = (PVMEMULATIONTHREADARGS)pvArgs;
55 AssertReleaseMsg(pArgs && pArgs->pVM, ("Invalid arguments to the emulation thread!\n"));
56
57 /*
58 * Init the native thread member.
59 */
60 PVM pVM = pArgs->pVM;
61 pVM->NativeThreadEMT = RTThreadGetNative(ThreadSelf);
62
63 /*
64 * The request loop.
65 */
66 VMSTATE enmBefore;
67 int rc;
68 Log(("vmR3EmulationThread: Emulation thread starting the days work... Thread=%#x pVM=%p\n", ThreadSelf, pVM));
69 for (;;)
70 {
71 /* Requested to exit the EMT thread out of sync? (currently only VMR3WaitForResume) */
72 if (setjmp(pVM->vm.s.emtJumpEnv) != 0)
73 {
74 rc = VINF_SUCCESS;
75 break;
76 }
77
78 /*
79 * Pending requests which needs servicing?
80 *
81 * We check for state changes in addition to status codes when
82 * servicing requests. (Look after the ifs.)
83 */
84 enmBefore = pVM->enmVMState;
85 if (VM_FF_ISSET(pVM, VM_FF_TERMINATE))
86 {
87 rc = VINF_EM_TERMINATE;
88 break;
89 }
90 else if (pVM->vm.s.pReqs)
91 {
92 /*
93 * Service execute in EMT request.
94 */
95 rc = VMR3ReqProcess(pVM);
96 Log(("vmR3EmulationThread: Req rc=%Vrc, VM state %d -> %d\n", rc, enmBefore, pVM->enmVMState));
97 }
98 else if (VM_FF_ISSET(pVM, VM_FF_DBGF))
99 {
100 /*
101 * Service the debugger request.
102 */
103 rc = DBGFR3VMMForcedAction(pVM);
104 Log(("vmR3EmulationThread: Dbg rc=%Vrc, VM state %d -> %d\n", rc, enmBefore, pVM->enmVMState));
105 }
106 else if (VM_FF_ISSET(pVM, VM_FF_RESET))
107 {
108 /*
109 * Service a delay reset request.
110 */
111 rc = VMR3Reset(pVM);
112 VM_FF_CLEAR(pVM, VM_FF_RESET);
113 Log(("vmR3EmulationThread: Reset rc=%Vrc, VM state %d -> %d\n", rc, enmBefore, pVM->enmVMState));
114 }
115 else
116 {
117 /*
118 * Nothing important is pending, so wait for something.
119 */
120 rc = VMR3Wait(pVM);
121 if (VBOX_FAILURE(rc))
122 break;
123 }
124
125 /*
126 * Check for termination requests, these are extremely high priority.
127 */
128 if ( rc == VINF_EM_TERMINATE
129 || VM_FF_ISSET(pVM, VM_FF_TERMINATE))
130 break;
131
132 /*
133 * Some requests (both VMR3Req* and the DBGF) can potentially
134 * resume or start the VM, in that case we'll get a change in
135 * VM status indicating that we're now running.
136 */
137 if ( VBOX_SUCCESS(rc)
138 && enmBefore != pVM->enmVMState
139 && (pVM->enmVMState == VMSTATE_RUNNING))
140 {
141 rc = EMR3ExecuteVM(pVM);
142 Log(("vmR3EmulationThread: EMR3ExecuteVM() -> rc=%Vrc, enmVMState=%d\n", rc, pVM->enmVMState));
143 }
144
145 } /* forever */
146
147
148 /*
149 * Exiting.
150 */
151 Log(("vmR3EmulationThread: Terminating emulation thread! Thread=%#x pVM=%p rc=%Vrc enmBefore=%d enmVMState=%d\n",
152 ThreadSelf, pVM, rc, enmBefore, pVM->enmVMState));
153 if (pVM->vm.s.fEMTDoesTheCleanup)
154 {
155 Log(("vmR3EmulationThread: executing delayed Destroy\n"));
156 vmR3Destroy(pVM);
157 vmR3DestroyFinalBit(pVM);
158 Log(("vmR3EmulationThread: EMT is terminated.\n"));
159 }
160 else
161 {
162 /* we don't reset ThreadEMT here because it's used in waiting. */
163 pVM->NativeThreadEMT = NIL_RTNATIVETHREAD;
164 }
165 return rc;
166}
167
168/**
169 * Wait for VM to be resumed. Handle events like vmR3EmulationThread does.
170 * In case the VM is stopped, clean up and long jump to the main EMT loop.
171 *
172 * @returns VINF_SUCCESS or doesn't return
173 * @param pVM VM handle.
174 */
175VMR3DECL(int) VMR3WaitForResume(PVM pVM)
176{
177 /*
178 * The request loop.
179 */
180 VMSTATE enmBefore;
181 int rc;
182 for (;;)
183 {
184
185 /*
186 * Pending requests which needs servicing?
187 *
188 * We check for state changes in addition to status codes when
189 * servicing requests. (Look after the ifs.)
190 */
191 enmBefore = pVM->enmVMState;
192 if (VM_FF_ISSET(pVM, VM_FF_TERMINATE))
193 {
194 rc = VINF_EM_TERMINATE;
195 break;
196 }
197 else if (pVM->vm.s.pReqs)
198 {
199 /*
200 * Service execute in EMT request.
201 */
202 rc = VMR3ReqProcess(pVM);
203 Log(("vmR3EmulationThread: Req rc=%Vrc, VM state %d -> %d\n", rc, enmBefore, pVM->enmVMState));
204 }
205 else if (VM_FF_ISSET(pVM, VM_FF_DBGF))
206 {
207 /*
208 * Service the debugger request.
209 */
210 rc = DBGFR3VMMForcedAction(pVM);
211 Log(("vmR3EmulationThread: Dbg rc=%Vrc, VM state %d -> %d\n", rc, enmBefore, pVM->enmVMState));
212 }
213 else if (VM_FF_ISSET(pVM, VM_FF_RESET))
214 {
215 /*
216 * Service a delay reset request.
217 */
218 rc = VMR3Reset(pVM);
219 VM_FF_CLEAR(pVM, VM_FF_RESET);
220 Log(("vmR3EmulationThread: Reset rc=%Vrc, VM state %d -> %d\n", rc, enmBefore, pVM->enmVMState));
221 }
222 else
223 {
224 /*
225 * Nothing important is pending, so wait for something.
226 */
227 rc = VMR3Wait(pVM);
228 if (VBOX_FAILURE(rc))
229 break;
230 }
231
232 /*
233 * Check for termination requests, these are extremely high priority.
234 */
235 if ( rc == VINF_EM_TERMINATE
236 || VM_FF_ISSET(pVM, VM_FF_TERMINATE))
237 break;
238
239 /*
240 * Some requests (both VMR3Req* and the DBGF) can potentially
241 * resume or start the VM, in that case we'll get a change in
242 * VM status indicating that we're now running.
243 */
244 if ( VBOX_SUCCESS(rc)
245 && enmBefore != pVM->enmVMState
246 && (pVM->enmVMState == VMSTATE_RUNNING))
247 {
248 /* Only valid exit reason. */
249 return VINF_SUCCESS;
250 }
251
252 } /* forever */
253
254 /* Return to the main loop in vmR3EmulationThread, which will clean up for us. */
255 longjmp(pVM->vm.s.emtJumpEnv, 1);
256}
257
258/**
259 * Notify the emulation thread (EMT) about pending Forced Action (FF).
260 *
261 * This function is called by thread other than EMT to make
262 * sure EMT wakes up and promptly service an FF request.
263 *
264 * @param pVM VM handle.
265 * @param fNotifiedREM Set if REM have already been notified. If clear the
266 * generic REMR3NotifyFF() method is called.
267 */
268VMR3DECL(void) VMR3NotifyFF(PVM pVM, bool fNotifiedREM)
269{
270 LogFlow(("VMR3NotifyFF:\n"));
271 if (pVM->vm.s.fWait)
272 {
273 int rc = RTSemEventSignal(pVM->vm.s.EventSemWait);
274 AssertRC(rc);
275 }
276 else if (!fNotifiedREM)
277 REMR3NotifyFF(pVM);
278}
279
280
281/**
282 * The old halt loop.
283 */
284DECLCALLBACK(int) vmR3WaitHaltedOld(PVM pVM, const uint32_t fMask)
285{
286 /*
287 * Halt loop.
288 */
289 int rc = VINF_SUCCESS;
290 ASMAtomicXchgU32(&pVM->vm.s.fWait, 1);
291 //unsigned cLoops = 0;
292 for (;;)
293 {
294 /*
295 * Work the timers and check if we can exit.
296 * The poll call gives us the ticks left to the next event in
297 * addition to perhaps set an FF.
298 */
299 STAM_REL_PROFILE_START(&pVM->vm.s.StatHaltPoll, a);
300 PDMR3Poll(pVM);
301 STAM_REL_PROFILE_STOP(&pVM->vm.s.StatHaltPoll, a);
302 STAM_REL_PROFILE_START(&pVM->vm.s.StatHaltTimers, b);
303 TMR3TimerQueuesDo(pVM);
304 STAM_REL_PROFILE_STOP(&pVM->vm.s.StatHaltTimers, b);
305 if (VM_FF_ISPENDING(pVM, fMask))
306 break;
307 uint64_t u64NanoTS = TMVirtualToNano(pVM, TMTimerPoll(pVM));
308 if (VM_FF_ISPENDING(pVM, fMask))
309 break;
310
311 /*
312 * Wait for a while. Someone will wake us up or interrupt the call if
313 * anything needs our attention.
314 */
315 if (u64NanoTS < 50000)
316 {
317 //RTLogPrintf("u64NanoTS=%RI64 cLoops=%d spin\n", u64NanoTS, cLoops++);
318 /* spin */;
319 }
320 else
321 {
322 VMMR3YieldStop(pVM);
323 //uint64_t u64Start = RTTimeNanoTS();
324 if (u64NanoTS < 870000) /* this is a bit speculative... works fine on linux. */
325 {
326 //RTLogPrintf("u64NanoTS=%RI64 cLoops=%d yield", u64NanoTS, cLoops++);
327 STAM_REL_PROFILE_START(&pVM->vm.s.StatHaltYield, a);
328 RTThreadYield(); /* this is the best we can do here */
329 STAM_REL_PROFILE_STOP(&pVM->vm.s.StatHaltYield, a);
330 }
331 else if (u64NanoTS < 2000000)
332 {
333 //RTLogPrintf("u64NanoTS=%RI64 cLoops=%d sleep 1ms", u64NanoTS, cLoops++);
334 STAM_REL_PROFILE_START(&pVM->vm.s.StatHaltBlock, a);
335 rc = RTSemEventWait(pVM->vm.s.EventSemWait, 1);
336 STAM_REL_PROFILE_STOP(&pVM->vm.s.StatHaltBlock, a);
337 }
338 else
339 {
340 //RTLogPrintf("u64NanoTS=%RI64 cLoops=%d sleep %dms", u64NanoTS, cLoops++, (uint32_t)RT_MIN((u64NanoTS - 500000) / 1000000, 15));
341 STAM_REL_PROFILE_START(&pVM->vm.s.StatHaltBlock, a);
342 rc = RTSemEventWait(pVM->vm.s.EventSemWait, RT_MIN((u64NanoTS - 1000000) / 1000000, 15));
343 STAM_REL_PROFILE_STOP(&pVM->vm.s.StatHaltBlock, a);
344 }
345 //uint64_t u64Slept = RTTimeNanoTS() - u64Start;
346 //RTLogPrintf(" -> rc=%Vrc in %RU64 ns / %RI64 ns delta\n", rc, u64Slept, u64NanoTS - u64Slept);
347 }
348 if (rc == VERR_TIMEOUT)
349 rc = VINF_SUCCESS;
350 else if (VBOX_FAILURE(rc))
351 {
352 AssertRC(rc != VERR_INTERRUPTED);
353 AssertMsgFailed(("RTSemEventWait->%Vrc\n", rc));
354 VM_FF_SET(pVM, VM_FF_TERMINATE);
355 rc = VERR_INTERNAL_ERROR;
356 break;
357 }
358 }
359
360 return rc;
361}
362
363
364/**
365 * Method 1 - Block whenever possible, and when lagging behind
366 * switch to spinning for 10-30ms with occational blocking until
367 * the lag has been eliminated.
368 */
369DECLCALLBACK(int) vmR3WaitHaltedMethod1(PVM pVM, const uint32_t fMask, uint64_t u64Now)
370{
371 /*
372 * To simplify things, we decide up-front whether we should switch
373 * to spinning or not. This makes some assumptions about the cause
374 * of the spinning (PIT/RTC/PCNet) and that it will generate interrupts
375 * or other events that means we should exit the halt loop.
376 */
377 bool fBlockOnce = false;
378 bool fSpinning = false;
379 uint32_t u32CatchUpPct = TMVirtualSyncGetCatchUpPct(pVM);
380 if (u32CatchUpPct /* non-zero if catching up */)
381 {
382 if (pVM->vm.s.Halt.Method12.u64StartSpinTS)
383 {
384 fSpinning = TMVirtualSyncGetLag(pVM) >= 2*1000000;
385 if (fSpinning)
386 {
387 uint64_t u64Lag = TMVirtualSyncGetLag(pVM);
388 fBlockOnce = u64Now - pVM->vm.s.Halt.Method12.u64LastBlockTS
389 > RT_MAX(5*1000000, RT_MIN(u64Lag / 4, 200*1000000));
390 }
391 else
392 {
393RTLogRelPrintf("Stopped spinning (%u ms)\n", (u64Now - pVM->vm.s.Halt.Method12.u64StartSpinTS) / 1000000);
394 pVM->vm.s.Halt.Method12.u64StartSpinTS = 0;
395 }
396 }
397 else
398 {
399 fSpinning = TMVirtualSyncGetLag(pVM) >= 20*1000000;
400 if (fSpinning)
401 pVM->vm.s.Halt.Method12.u64StartSpinTS = u64Now;
402 }
403 }
404 else if (pVM->vm.s.Halt.Method12.u64StartSpinTS)
405 {
406RTLogRelPrintf("Stopped spinning (%u ms)\n", (u64Now - pVM->vm.s.Halt.Method12.u64StartSpinTS) / 1000000);
407 pVM->vm.s.Halt.Method12.u64StartSpinTS = 0;
408 }
409
410 /*
411 * Halt loop.
412 */
413 int rc = VINF_SUCCESS;
414 ASMAtomicXchgU32(&pVM->vm.s.fWait, 1);
415 unsigned cLoops = 0;
416 for (;; cLoops++)
417 {
418 /*
419 * Work the timers and check if we can exit.
420 */
421 STAM_REL_PROFILE_START(&pVM->vm.s.StatHaltPoll, a);
422 PDMR3Poll(pVM);
423 STAM_REL_PROFILE_STOP(&pVM->vm.s.StatHaltPoll, a);
424 STAM_REL_PROFILE_START(&pVM->vm.s.StatHaltTimers, b);
425 TMR3TimerQueuesDo(pVM);
426 STAM_REL_PROFILE_STOP(&pVM->vm.s.StatHaltTimers, b);
427 if (VM_FF_ISPENDING(pVM, fMask))
428 break;
429
430 /*
431 * Estimate time left to the next event.
432 */
433 uint64_t u64NanoTS = TMVirtualToNano(pVM, TMTimerPoll(pVM));
434 if (VM_FF_ISPENDING(pVM, fMask))
435 break;
436
437 /*
438 * Block if we're not spinning and the interval isn't all that small.
439 */
440 if ( ( !fSpinning
441 || fBlockOnce)
442 && u64NanoTS >= 250000) /* 0.250 ms */
443 {
444 const uint64_t Start = pVM->vm.s.Halt.Method12.u64LastBlockTS = RTTimeNanoTS();
445 VMMR3YieldStop(pVM);
446
447 uint32_t cMilliSecs = RT_MIN(u64NanoTS / 1000000, 15);
448 if (cMilliSecs <= pVM->vm.s.Halt.Method12.cNSBlockedTooLongAvg)
449 cMilliSecs = 1;
450 else
451 cMilliSecs -= pVM->vm.s.Halt.Method12.cNSBlockedTooLongAvg;
452RTLogRelPrintf("u64NanoTS=%RI64 cLoops=%3d sleep %02dms (%7RU64) ", u64NanoTS, cLoops, cMilliSecs, u64NanoTS);
453 STAM_REL_PROFILE_START(&pVM->vm.s.StatHaltBlock, a);
454 rc = RTSemEventWait(pVM->vm.s.EventSemWait, cMilliSecs);
455 STAM_REL_PROFILE_STOP(&pVM->vm.s.StatHaltBlock, a);
456 if (rc == VERR_TIMEOUT)
457 rc = VINF_SUCCESS;
458 else if (VBOX_FAILURE(rc))
459 {
460 AssertRC(rc != VERR_INTERRUPTED);
461 AssertMsgFailed(("RTSemEventWait->%Vrc\n", rc));
462 VM_FF_SET(pVM, VM_FF_TERMINATE);
463 rc = VERR_INTERNAL_ERROR;
464 break;
465 }
466
467 /*
468 * Calc the statistics.
469 * Update averages every 16th time, and flush parts of the history every 64th time.
470 */
471 const uint64_t Elapsed = RTTimeNanoTS() - Start;
472 pVM->vm.s.Halt.Method12.cNSBlocked += Elapsed;
473 if (Elapsed > u64NanoTS)
474 pVM->vm.s.Halt.Method12.cNSBlockedTooLong += Elapsed - u64NanoTS;
475 pVM->vm.s.Halt.Method12.cBlocks++;
476 if (!(pVM->vm.s.Halt.Method12.cBlocks & 0xf))
477 {
478 pVM->vm.s.Halt.Method12.cNSBlockedTooLongAvg = pVM->vm.s.Halt.Method12.cNSBlockedTooLong / pVM->vm.s.Halt.Method12.cBlocks;
479 if (!(pVM->vm.s.Halt.Method12.cBlocks & 0x3f))
480 {
481 pVM->vm.s.Halt.Method12.cNSBlockedTooLong = pVM->vm.s.Halt.Method12.cNSBlockedTooLongAvg * 0x40;
482 pVM->vm.s.Halt.Method12.cBlocks = 0x40;
483 }
484 }
485RTLogRelPrintf(" -> %7RU64 ns / %7RI64 ns delta%s\n", Elapsed, Elapsed - u64NanoTS, fBlockOnce ? " (block once)" : "");
486
487 /*
488 * Clear the block once flag if we actually blocked.
489 */
490 if ( fBlockOnce
491 && Elapsed > 100000 /* 0.1 ms */)
492 fBlockOnce = false;
493 }
494 }
495if (fSpinning) RTLogRelPrintf("spun for %RU64 ns %u loops; lag=%RU64 pct=%d\n", RTTimeNanoTS() - u64Now, cLoops, TMVirtualSyncGetLag(pVM), u32CatchUpPct);
496
497 return rc;
498}
499
500
501/**
502 * Halted VM Wait.
503 * Any external event will unblock the thread.
504 *
505 * @returns VINF_SUCCESS unless a fatal error occured. In the latter
506 * case an appropriate status code is returned.
507 * @param pVM VM handle.
508 * @param fIgnoreInterrupts If set the VM_FF_INTERRUPT flags is ignored.
509 * @thread The emulation thread.
510 */
511VMR3DECL(int) VMR3WaitHalted(PVM pVM, bool fIgnoreInterrupts)
512{
513 LogFlow(("VMR3WaitHalted: fIgnoreInterrupts=%d\n", fIgnoreInterrupts));
514
515 /*
516 * Check Relevant FFs.
517 */
518 const uint32_t fMask = !fIgnoreInterrupts
519 ? VM_FF_EXTERNAL_HALTED_MASK
520 : VM_FF_EXTERNAL_HALTED_MASK & ~(VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC);
521 if (VM_FF_ISPENDING(pVM, fMask))
522 {
523 LogFlow(("VMR3WaitHalted: returns VINF_SUCCESS (FF %#x)\n", pVM->fForcedActions));
524 return VINF_SUCCESS;
525 }
526
527 /*
528 * The yielder is suspended while we're halting.
529 */
530 VMMR3YieldSuspend(pVM);
531
532 /*
533 * Record halt averages for the last second.
534 */
535 uint64_t u64Now = RTTimeNanoTS();
536 int64_t off = u64Now - pVM->vm.s.u64HaltsStartTS;
537 if (off > 1000000000)
538 {
539 if (off > _4G || !pVM->vm.s.cHalts)
540 {
541 pVM->vm.s.HaltInterval = 1000000000 /* 1 sec */;
542 pVM->vm.s.HaltFrequency = 1;
543 }
544 else
545 {
546 pVM->vm.s.HaltInterval = (uint32_t)off / pVM->vm.s.cHalts;
547 pVM->vm.s.HaltFrequency = ASMMultU64ByU32DivByU32(pVM->vm.s.cHalts, 1000000000, (uint32_t)off);
548 }
549 pVM->vm.s.u64HaltsStartTS = u64Now;
550 pVM->vm.s.cHalts = 0;
551 }
552 pVM->vm.s.cHalts++;
553
554 /*
555 * Do the halt.
556 */
557#if 1
558 int rc = vmR3WaitHaltedOld(pVM, fMask);
559#elif 0 /* work in progress */
560 int rc = vmR3WaitHaltedMethod1(pVM, fMask, u64Now);
561#else
562# error "misconfigured halt"
563#endif
564
565 /*
566 * Resume the yielder and tell the world we're not blocking.
567 */
568 ASMAtomicXchgU32(&pVM->vm.s.fWait, 0);
569 VMMR3YieldResume(pVM);
570
571 LogFlow(("VMR3WaitHalted: returns %Vrc (FF %#x)\n", rc, pVM->fForcedActions));
572 return rc;
573}
574
575
576/**
577 * Suspended VM Wait.
578 * Only a handful of forced actions will cause the function to
579 * return to the caller.
580 *
581 * @returns VINF_SUCCESS unless a fatal error occured. In the latter
582 * case an appropriate status code is returned.
583 * @param pVM VM handle.
584 * @thread The emulation thread.
585 */
586VMR3DECL(int) VMR3Wait(PVM pVM)
587{
588 LogFlow(("VMR3Wait:\n"));
589
590 /*
591 * Check Relevant FFs.
592 */
593 if (VM_FF_ISPENDING(pVM, VM_FF_EXTERNAL_SUSPENDED_MASK))
594 {
595 LogFlow(("VMR3Wait: returns VINF_SUCCESS (FF %#x)\n", pVM->fForcedActions));
596 return VINF_SUCCESS;
597 }
598
599 int rc = VINF_SUCCESS;
600 ASMAtomicXchgU32(&pVM->vm.s.fWait, 1);
601 for (;;)
602 {
603 /*
604 * Check Relevant FFs.
605 */
606 if (VM_FF_ISPENDING(pVM, VM_FF_EXTERNAL_SUSPENDED_MASK))
607 break;
608
609 /*
610 * Wait for a while. Someone will wake us up or interrupt the call if
611 * anything needs our attention.
612 */
613 rc = RTSemEventWait(pVM->vm.s.EventSemWait, 1000);
614 if (rc == VERR_TIMEOUT)
615 rc = VINF_SUCCESS;
616 else if (VBOX_FAILURE(rc))
617 {
618 AssertMsgFailed(("RTSemEventWait->%Vrc\n", rc));
619 VM_FF_SET(pVM, VM_FF_TERMINATE);
620 rc = VERR_INTERNAL_ERROR;
621 break;
622 }
623
624 }
625 ASMAtomicXchgU32(&pVM->vm.s.fWait, 0);
626
627 LogFlow(("VMR3Wait: returns %Vrc (FF %#x)\n", rc, pVM->fForcedActions));
628 return rc;
629}
630
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