/** VM IPC mutex holder thread */ DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser) { LogFlowFuncEnter(); Assert (pvUser); void **data = (void **) pvUser; Utf8Str ipcId = (BSTR)data[0]; RTSEMEVENT finishSem = (RTSEMEVENT)data[1]; LogFlowFunc (("ipcId='%s', finishSem=%p\n", ipcId.raw(), finishSem)); HMTX ipcMutex = NULLHANDLE; APIRET arc = ::DosOpenMutexSem ((PSZ) ipcId.raw(), &ipcMutex); AssertMsg (arc == NO_ERROR, ("cannot open IPC mutex, arc=%ld\n", arc)); if (arc == NO_ERROR) { /* grab the mutex */ LogFlowFunc (("grabbing IPC mutex...\n")); arc = ::DosRequestMutexSem (ipcMutex, SEM_IMMEDIATE_RETURN); AssertMsg (arc == NO_ERROR, ("cannot grab IPC mutex, arc=%ld\n", arc)); if (arc == NO_ERROR) { /* store the answer */ data[2] = (void*)true; /* signal we're done */ int vrc = RTThreadUserSignal (Thread); AssertRC(vrc); /* wait until we're signaled to release the IPC mutex */ LogFlowFunc (("waiting for termination signal..\n")); vrc = RTSemEventWait (finishSem, RT_INDEFINITE_WAIT); Assert (arc == ERROR_INTERRUPT || ERROR_TIMEOUT); /* release the IPC mutex */ LogFlowFunc (("releasing IPC mutex...\n")); arc = ::DosReleaseMutexSem (ipcMutex); AssertMsg (arc == NO_ERROR, ("cannot release mutex, arc=%ld\n", arc)); } ::DosCloseMutexSem (ipcMutex); } /* store the answer */ data[1] = (void*)false; /* signal we're done */ int vrc = RTThreadUserSignal (Thread); AssertRC(vrc); LogFlowFuncLeave(); return 0; }
/** * Called by the PDM thread in response to a wakeup call with * suspending as the new state. * * The thread will block in side this call until the state is changed in * response to a VM state change or to the device/driver/whatever calling the * PDMR3ThreadResume API. * * @returns VBox status code. * On failure, terminate the thread. * @param pThread The PDM thread. */ VMMR3DECL(int) PDMR3ThreadIAmSuspending(PPDMTHREAD pThread) { /* * Assert sanity. */ AssertPtr(pThread); AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC); Assert(pThread->Thread == RTThreadSelf() || pThread->enmState == PDMTHREADSTATE_INITIALIZING); PDMTHREADSTATE enmState = pThread->enmState; Assert( enmState == PDMTHREADSTATE_SUSPENDING || enmState == PDMTHREADSTATE_INITIALIZING); /* * Update the state, notify the control thread (the API caller) and go to sleep. */ int rc = VERR_WRONG_ORDER; if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_SUSPENDED, enmState)) { rc = RTThreadUserSignal(pThread->Thread); if (RT_SUCCESS(rc)) { rc = RTSemEventMultiWait(pThread->Internal.s.BlockEvent, RT_INDEFINITE_WAIT); if ( RT_SUCCESS(rc) && pThread->enmState != PDMTHREADSTATE_SUSPENDED) return rc; if (RT_SUCCESS(rc)) rc = VERR_PDM_THREAD_IPE_2; } } AssertMsgFailed(("rc=%d enmState=%d\n", rc, pThread->enmState)); pdmR3ThreadBailMeOut(pThread); return rc; }
/** * @interface_method_impl{TXSTRANSPORT,pfnTerm} */ static DECLCALLBACK(void) txsTcpTerm(void) { /* Signal thread */ if (RTCritSectIsInitialized(&g_TcpCritSect)) { RTCritSectEnter(&g_TcpCritSect); g_fTcpStopConnecting = true; RTCritSectLeave(&g_TcpCritSect); } if (g_hThreadTcpConnect != NIL_RTTHREAD) { RTThreadUserSignal(g_hThreadTcpConnect); RTTcpClientCancelConnect(&g_pTcpConnectCancelCookie); } /* Shut down the server (will wake up thread). */ if (g_pTcpServer) { Log(("txsTcpTerm: Destroying server...\n")); int rc = RTTcpServerDestroy(g_pTcpServer); if (RT_FAILURE(rc)) RTMsgInfo("RTTcpServerDestroy failed in txsTcpTerm: %Rrc", rc); g_pTcpServer = NULL; } /* Shut down client */ if (g_hTcpClient != NIL_RTSOCKET) { if (g_fTcpClientFromServer) { Log(("txsTcpTerm: Disconnecting client...\n")); int rc = RTTcpServerDisconnectClient2(g_hTcpClient); if (RT_FAILURE(rc)) RTMsgInfo("RTTcpServerDisconnectClient2(%RTsock) failed in txsTcpTerm: %Rrc", g_hTcpClient, rc); } else { int rc = RTTcpClientClose(g_hTcpClient); if (RT_FAILURE(rc)) RTMsgInfo("RTTcpClientClose(%RTsock) failed in txsTcpTerm: %Rrc", g_hTcpClient, rc); } g_hTcpClient = NIL_RTSOCKET; } /* Clean up stashing. */ RTMemFree(g_pbTcpStashed); g_pbTcpStashed = NULL; g_cbTcpStashed = 0; g_cbTcpStashedAlloced = 0; /* Wait for the thread (they should've had some time to quit by now). */ txsTcpConnectWaitOnThreads(15000); /* Finally, clean up the critical section. */ if (RTCritSectIsInitialized(&g_TcpCritSect)) RTCritSectDelete(&g_TcpCritSect); Log(("txsTcpTerm: done\n")); }
int VBoxCredProvPoller::Shutdown(void) { VBoxCredProvVerbose(0, "VBoxCredProvPoller: Shutdown\n"); if (m_hThreadPoller == NIL_RTTHREAD) return VINF_SUCCESS; /* Post termination event semaphore. */ int rc = RTThreadUserSignal(m_hThreadPoller); if (RT_SUCCESS(rc)) { VBoxCredProvVerbose(0, "VBoxCredProvPoller: Waiting for thread to terminate\n"); /* Wait until the thread has terminated. */ rc = RTThreadWait(m_hThreadPoller, RT_INDEFINITE_WAIT, NULL); if (RT_FAILURE(rc)) VBoxCredProvVerbose(0, "VBoxCredProvPoller: Wait returned error rc=%Rrc\n", rc); } else VBoxCredProvVerbose(0, "VBoxCredProvPoller: Error waiting for thread shutdown, rc=%Rrc\n", rc); m_pProv = NULL; m_hThreadPoller = NIL_RTTHREAD; VBoxCredProvVerbose(0, "VBoxCredProvPoller: Shutdown returned with rc=%Rrc\n", rc); return rc; }
int VBoxGINACredentialsPollerTerminate(void) { if (gThreadPoller == NIL_RTTHREAD) return VINF_SUCCESS; VBoxGINAVerbose(0, "VBoxGINA::credentialsPollerTerminate\n"); /* post termination event semaphore */ int rc = RTThreadUserSignal(gThreadPoller); if (RT_SUCCESS(rc)) { VBoxGINAVerbose(0, "VBoxGINA::credentialsPollerTerminate: waiting for thread to terminate\n"); rc = RTThreadWait(gThreadPoller, RT_INDEFINITE_WAIT, NULL); } else VBoxGINAVerbose(0, "VBoxGINA::credentialsPollerTerminate: thread has terminated? wait rc = %Rrc\n", rc); if (RT_SUCCESS(rc)) { gThreadPoller = NIL_RTTHREAD; } VBoxGINAVerbose(0, "VBoxGINA::credentialsPollerTerminate: returned with rc=%Rrc)\n", rc); return rc; }
static DECLCALLBACK(int) tstSupSemMREInf(RTTHREAD hSelf, void *pvUser) { SUPSEMEVENTMULTI hEventMulti = (SUPSEMEVENTMULTI)pvUser; RTThreadUserSignal(hSelf); int rc = SUPSemEventMultiWaitNoResume(g_pSession, hEventMulti, RT_INDEFINITE_WAIT); AssertReleaseMsgFailed(("%Rrc\n", rc)); return rc; }
static DECLCALLBACK(int) tstSupSemSRETimed(RTTHREAD hSelf, void *pvUser) { SUPSEMEVENT hEvent = (SUPSEMEVENT)pvUser; RTThreadUserSignal(hSelf); int rc = SUPSemEventWaitNoResume(g_pSession, hEvent, 120*1000); AssertReleaseMsgFailed(("%Rrc\n", rc)); return rc; }
/** * Sets the current client socket in a safe manner. * * @returns NIL_RTSOCKET if consumed, other wise hTcpClient. * @param hTcpClient The client socket. * @param fFromServer Set if server type connection. */ static RTSOCKET txsTcpSetClient(RTSOCKET hTcpClient, bool fFromServer) { RTCritSectEnter(&g_TcpCritSect); if ( g_hTcpClient == NIL_RTSOCKET && !g_fTcpStopConnecting && g_hThreadMain != NIL_RTTHREAD ) { g_fTcpClientFromServer = true; g_hTcpClient = hTcpClient; int rc = RTThreadUserSignal(g_hThreadMain); AssertRC(rc); hTcpClient = NIL_RTSOCKET; } RTCritSectLeave(&g_TcpCritSect); return hTcpClient; }
/** * The service thread. * * @returns Whatever the worker function returns. * @param ThreadSelf My thread handle. * @param pvUser The service index. */ static DECLCALLBACK(int) vboxServiceThread(RTTHREAD ThreadSelf, void *pvUser) { const unsigned i = (uintptr_t)pvUser; #ifndef RT_OS_WINDOWS /* * Block all signals for this thread. Only the main thread will handle signals. */ sigset_t signalMask; sigfillset(&signalMask); pthread_sigmask(SIG_BLOCK, &signalMask, NULL); #endif int rc = g_aServices[i].pDesc->pfnWorker(&g_aServices[i].fShutdown); ASMAtomicXchgBool(&g_aServices[i].fShutdown, true); RTThreadUserSignal(ThreadSelf); return rc; }
/** Terminate the host side of the shared clipboard - called by the hgcm layer. */ void vboxClipboardDestroy(void) { Log(("vboxClipboardDestroy\n")); /* * Signal the termination of the polling thread and wait for it to respond. */ ASMAtomicWriteBool(&g_ctx.fTerminate, true); int rc = RTThreadUserSignal(g_ctx.thread); AssertRC(rc); rc = RTThreadWait(g_ctx.thread, RT_INDEFINITE_WAIT, NULL); AssertRC(rc); /* * Destroy the pasteboard and uninitialize the global context record. */ destroyPasteboard(&g_ctx.pasteboard); g_ctx.thread = NIL_RTTHREAD; g_ctx.pClient = NULL; }
/** * Does the waiting on a section of the handle array. * * @param pSubworker Pointer to the calling thread's data. * @param cMsWait Number of milliseconds to wait. */ void VirtualBox::ClientWatcher::subworkerWait(VirtualBox::ClientWatcher::PerSubworker *pSubworker, uint32_t cMsWait) { /* * Figure out what section to wait on and do the waiting. */ uint32_t idxHandle = pSubworker->iSubworker * CW_MAX_HANDLES_PER_THREAD; uint32_t cHandles = CW_MAX_HANDLES_PER_THREAD; if (idxHandle + cHandles > mcWaitHandles) { cHandles = mcWaitHandles - idxHandle; AssertStmt(idxHandle < mcWaitHandles, cHandles = 1); } Assert(mahWaitHandles[idxHandle] == mUpdateReq); DWORD dwWait = ::WaitForMultipleObjects(cHandles, &mahWaitHandles[idxHandle], FALSE /*fWaitAll*/, cMsWait); pSubworker->dwWait = dwWait; /* * If we didn't wake up because of the UpdateReq handle, signal it to make * sure everyone else wakes up too. */ if (dwWait != WAIT_OBJECT_0) { BOOL fRc = SetEvent(mUpdateReq); Assert(fRc); NOREF(fRc); } /* * Last one signals the main thread. */ if (ASMAtomicDecU32(&mcActiveSubworkers) == 0) { int vrc = RTThreadUserSignal(maSubworkers[0].hThread); AssertLogRelMsg(RT_SUCCESS(vrc), ("RTThreadUserSignal -> %Rrc\n", vrc)); } }
bool VBoxCredPoller::Shutdown(void) { Log(("VBoxCredPoller::Shutdown\n")); if (m_hThreadPoller == NIL_RTTHREAD) { Log(("VBoxCredPoller::Shutdown: Either thread or exit sem is NULL!\n")); return false; } /* Post termination event semaphore. */ int rc = RTThreadUserSignal(m_hThreadPoller); if (RT_SUCCESS(rc)) { Log(("VBoxCredPoller::Shutdown: Waiting for thread to terminate\n")); /* Wait until the thread has terminated. */ rc = RTThreadWait(m_hThreadPoller, RT_INDEFINITE_WAIT, NULL); Log(("VBoxCredPoller::Shutdown: Thread has (probably) terminated (rc = %Rrc)\n", rc)); } else { /* Failed to signal the thread - very unlikely - so no point in waiting long. */ Log(("VBoxCredPoller::Shutdown: Failed to signal semaphore, rc = %Rrc\n", rc)); rc = RTThreadWait(m_hThreadPoller, 100, NULL); Log(("VBoxCredPoller::Shutdown: Thread has terminated? wait rc = %Rrc\n", rc)); } if (m_pProv != NULL) { m_pProv->Release(); m_pProv = NULL; } credentialsReset(); RTCritSectDelete(&m_csCredUpate); m_hThreadPoller = NIL_RTTHREAD; return true; }
/** sub test */ static void tst4Sub(uint32_t cThreads) { RTTestISubF("Serialization - %u threads", cThreads); RTMEMPOOL hMemPool; RTTESTI_CHECK_RC_RETV(RTMemPoolCreate(&hMemPool, "test 2a"), VINF_SUCCESS); g_hMemPool4 = hMemPool; PRTTHREAD pahThreads = (PRTTHREAD)RTMemPoolAlloc(hMemPool, cThreads * sizeof(RTTHREAD)); RTTESTI_CHECK(pahThreads); if (pahThreads) { /* start them. */ for (uint32_t i = 0; i < cThreads; i++) { int rc = RTThreadCreateF(&pahThreads[i], tst4Thread, (void *)(uintptr_t)i, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tst4-%u/%u", i, cThreads); RTTESTI_CHECK_RC_OK(rc); if (RT_FAILURE(rc)) pahThreads[i] = NIL_RTTHREAD; } RTThreadYield(); /* kick them off. */ for (uint32_t i = 0; i < cThreads; i++) if (pahThreads[i] != NIL_RTTHREAD) RTTESTI_CHECK_RC_OK(RTThreadUserSignal(pahThreads[i])); /* wait for them. */ for (uint32_t i = 0; i < cThreads; i++) if (pahThreads[i] != NIL_RTTHREAD) { int rc = RTThreadWait(pahThreads[i], 2*60*1000, NULL); RTTESTI_CHECK_RC_OK(rc); } } RTTESTI_CHECK_RC(RTMemPoolDestroy(hMemPool), VINF_SUCCESS); }
/** * Called by the PDM thread in response to a resuming state. * * The purpose of this API is to tell the PDMR3ThreadResume caller that * the PDM thread has successfully resumed. It will also do the * state transition from the resuming to the running state. * * @returns VBox status code. * On failure, terminate the thread. * @param pThread The PDM thread. */ VMMR3DECL(int) PDMR3ThreadIAmRunning(PPDMTHREAD pThread) { /* * Assert sanity. */ Assert(pThread->enmState == PDMTHREADSTATE_RESUMING); Assert(pThread->Thread == RTThreadSelf()); /* * Update the state and tell the control thread (the guy calling the resume API). */ int rc = VERR_WRONG_ORDER; if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_RUNNING, PDMTHREADSTATE_RESUMING)) { rc = RTThreadUserSignal(pThread->Thread); if (RT_SUCCESS(rc)) return rc; } AssertMsgFailed(("rc=%d enmState=%d\n", rc, pThread->enmState)); pdmR3ThreadBailMeOut(pThread); return rc; }
static DECLCALLBACK(int) tstSupSemInterruptibleMRE(RTTHREAD hSelf, void *pvUser) { SUPSEMEVENTMULTI hEventMulti = (SUPSEMEVENTMULTI)pvUser; RTThreadUserSignal(hSelf); return SUPSemEventMultiWaitNoResume(g_pSession, hEventMulti, g_cMillies); }
/** * @interface_method_impl{VBOXSERVICE,pfnWorker} */ DECLCALLBACK(int) vgsvcTimeSyncWorker(bool volatile *pfShutdown) { RTTIME Time; char sz[64]; int rc = VINF_SUCCESS; /* * Tell the control thread that it can continue spawning services. */ RTThreadUserSignal(RTThreadSelf()); /* * The Work Loop. */ for (;;) { /* * Try get a reliable time reading. */ int cTries = 3; do { /* query it. */ RTTIMESPEC GuestNow0, GuestNow, HostNow; RTTimeNow(&GuestNow0); int rc2 = VbglR3GetHostTime(&HostNow); if (RT_FAILURE(rc2)) { if (g_cTimeSyncErrors++ < 10) VGSvcError("vgsvcTimeSyncWorker: VbglR3GetHostTime failed; rc2=%Rrc\n", rc2); break; } RTTimeNow(&GuestNow); /* calc latency and check if it's ok. */ RTTIMESPEC GuestElapsed = GuestNow; RTTimeSpecSub(&GuestElapsed, &GuestNow0); if ((uint32_t)RTTimeSpecGetMilli(&GuestElapsed) < g_TimeSyncMaxLatency) { /* * Set the time once after we were restored. * (Of course only if the drift is bigger than MinAdjust) */ uint32_t TimeSyncSetThreshold = g_TimeSyncSetThreshold; if (g_fTimeSyncSetOnRestore) { uint64_t idNewSession = g_idTimeSyncSession; VbglR3GetSessionId(&idNewSession); if (idNewSession != g_idTimeSyncSession) { VGSvcVerbose(3, "vgsvcTimeSyncWorker: The VM session ID changed, forcing resync.\n"); TimeSyncSetThreshold = 0; g_idTimeSyncSession = idNewSession; } } /* * Calculate the adjustment threshold and the current drift. */ uint32_t MinAdjust = RTTimeSpecGetMilli(&GuestElapsed) * g_TimeSyncLatencyFactor; if (MinAdjust < g_TimeSyncMinAdjust) MinAdjust = g_TimeSyncMinAdjust; RTTIMESPEC Drift = HostNow; RTTimeSpecSub(&Drift, &GuestNow); if (RTTimeSpecGetMilli(&Drift) < 0) MinAdjust += g_TimeSyncMinAdjust; /* extra buffer against moving time backwards. */ RTTIMESPEC AbsDrift = Drift; RTTimeSpecAbsolute(&AbsDrift); if (g_cVerbosity >= 3) { VGSvcVerbose(3, "vgsvcTimeSyncWorker: Host: %s (MinAdjust: %RU32 ms)\n", RTTimeToString(RTTimeExplode(&Time, &HostNow), sz, sizeof(sz)), MinAdjust); VGSvcVerbose(3, "vgsvcTimeSyncWorker: Guest: - %s => %RDtimespec drift\n", RTTimeToString(RTTimeExplode(&Time, &GuestNow), sz, sizeof(sz)), &Drift); } uint32_t AbsDriftMilli = RTTimeSpecGetMilli(&AbsDrift); if (AbsDriftMilli > MinAdjust) { /* * Ok, the drift is above the threshold. * * Try a gradual adjustment first, if that fails or the drift is * too big, fall back on just setting the time. */ if ( AbsDriftMilli > TimeSyncSetThreshold || g_fTimeSyncSetNext || !vgsvcTimeSyncAdjust(&Drift)) { vgsvcTimeSyncCancelAdjust(); vgsvcTimeSyncSet(&Drift); } } else vgsvcTimeSyncCancelAdjust(); break; } VGSvcVerbose(3, "vgsvcTimeSyncWorker: %RDtimespec: latency too high (%RDtimespec) sleeping 1s\n", GuestElapsed); RTThreadSleep(1000); } while (--cTries > 0); /* Clear the set-next/set-start flag. */ g_fTimeSyncSetNext = false; /* * Block for a while. * * The event semaphore takes care of ignoring interruptions and it * allows us to implement service wakeup later. */ if (*pfShutdown) break; int rc2 = RTSemEventMultiWait(g_TimeSyncEvent, g_TimeSyncInterval); if (*pfShutdown) break; if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2)) { VGSvcError("vgsvcTimeSyncWorker: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2); rc = rc2; break; } } vgsvcTimeSyncCancelAdjust(); RTSemEventMultiDestroy(g_TimeSyncEvent); g_TimeSyncEvent = NIL_RTSEMEVENTMULTI; return rc; }
DECLCALLBACK(int) VBoxClipboardWorker(void *pInstance, bool volatile *pfShutdown) { AssertPtr(pInstance); LogFlowFunc(("pInstance=%p\n", pInstance)); /* * Tell the control thread that it can continue * spawning services. */ RTThreadUserSignal(RTThreadSelf()); PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance; AssertPtr(pCtx); int rc; /* The thread waits for incoming messages from the host. */ for (;;) { uint32_t u32Msg; uint32_t u32Formats; rc = VbglR3ClipboardGetHostMsg(pCtx->u32ClientID, &u32Msg, &u32Formats); if (RT_FAILURE(rc)) { if (rc == VERR_INTERRUPTED) break; LogFlowFunc(("Error getting host message, rc=%Rrc\n", rc)); if (*pfShutdown) break; /* Wait a bit before retrying. */ RTThreadSleep(1000); continue; } else { LogFlowFunc(("u32Msg=%RU32, u32Formats=0x%x\n", u32Msg, u32Formats)); switch (u32Msg) { /** @todo r=andy: Use a \#define for WM_USER (+1). */ case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS: { /* The host has announced available clipboard formats. * Forward the information to the window, so it can later * respond to WM_RENDERFORMAT message. */ ::PostMessage(pCtx->hwnd, WM_USER, 0, u32Formats); } break; case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA: { /* The host needs data in the specified format. */ ::PostMessage(pCtx->hwnd, WM_USER + 1, 0, u32Formats); } break; case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT: { /* The host is terminating. */ LogRel(("Clipboard: Terminating ...\n")); ASMAtomicXchgBool(pfShutdown, true); } break; default: { LogFlowFunc(("Unsupported message from host, message=%RU32\n", u32Msg)); /* Wait a bit before retrying. */ RTThreadSleep(1000); } break; } } if (*pfShutdown) break; } LogFlowFuncLeaveRC(rc); return rc; }
/** @copydoc VBOXSERVICE::pfnWorker */ DECLCALLBACK(int) VBoxServiceVMInfoWorker(bool volatile *pfShutdown) { int rc; /* * Tell the control thread that it can continue * spawning services. */ RTThreadUserSignal(RTThreadSelf()); #ifdef RT_OS_WINDOWS /* Required for network information (must be called per thread). */ WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData)) VBoxServiceError("VMInfo/Network: WSAStartup failed! Error: %Rrc\n", RTErrConvertFromWin32(WSAGetLastError())); #endif /* RT_OS_WINDOWS */ /* * Write the fixed properties first. */ vboxserviceVMInfoWriteFixedProperties(); /* * Now enter the loop retrieving runtime data continuously. */ for (;;) { rc = vboxserviceVMInfoWriteUsers(); if (RT_FAILURE(rc)) break; rc = vboxserviceVMInfoWriteNetwork(); if (RT_FAILURE(rc)) break; /* * Flush all properties if we were restored. */ uint64_t idNewSession = g_idVMInfoSession; VbglR3GetSessionId(&idNewSession); if (idNewSession != g_idVMInfoSession) { VBoxServiceVerbose(3, "VMInfo: The VM session ID changed, flushing all properties\n"); vboxserviceVMInfoWriteFixedProperties(); VBoxServicePropCacheFlush(&g_VMInfoPropCache); g_idVMInfoSession = idNewSession; } /* * Block for a while. * * The event semaphore takes care of ignoring interruptions and it * allows us to implement service wakeup later. */ if (*pfShutdown) break; int rc2 = RTSemEventMultiWait(g_hVMInfoEvent, g_cMsVMInfoInterval); if (*pfShutdown) break; if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2)) { VBoxServiceError("VMInfo: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2); rc = rc2; break; } else if (RT_LIKELY(RT_SUCCESS(rc2))) { /* Reset event semaphore if it got triggered. */ rc2 = RTSemEventMultiReset(g_hVMInfoEvent); if (RT_FAILURE(rc2)) rc2 = VBoxServiceError("VMInfo: RTSemEventMultiReset failed; rc2=%Rrc\n", rc2); } } #ifdef RT_OS_WINDOWS WSACleanup(); #endif return rc; }
/** @copydoc VBOXSERVICE::pfnWorker */ DECLCALLBACK(int) VBoxServiceCpuHotPlugWorker(bool volatile *pfShutdown) { /* * Tell the control thread that it can continue spawning services. */ RTThreadUserSignal(RTThreadSelf()); /* * Enable the CPU hotplug notifier. */ int rc = VbglR3CpuHotPlugInit(); if (RT_FAILURE(rc)) return rc; /* * The Work Loop. */ for (;;) { /* Wait for CPU hot plugging event. */ uint32_t idCpuCore; uint32_t idCpuPackage; VMMDevCpuEventType enmEventType; rc = VbglR3CpuHotPlugWaitForEvent(&enmEventType, &idCpuCore, &idCpuPackage); if (RT_SUCCESS(rc)) { VBoxServiceVerbose(3, "CpuHotPlug: Event happened idCpuCore=%u idCpuPackage=%u enmEventType=%d\n", idCpuCore, idCpuPackage, enmEventType); switch (enmEventType) { case VMMDevCpuEventType_Plug: VBoxServiceCpuHotPlugHandlePlugEvent(idCpuCore, idCpuPackage); break; case VMMDevCpuEventType_Unplug: VBoxServiceCpuHotPlugHandleUnplugEvent(idCpuCore, idCpuPackage); break; default: { static uint32_t s_iErrors = 0; if (s_iErrors++ < 10) VBoxServiceError("CpuHotPlug: Unknown event: idCpuCore=%u idCpuPackage=%u enmEventType=%d\n", idCpuCore, idCpuPackage, enmEventType); break; } } } else if (rc != VERR_INTERRUPTED && rc != VERR_TRY_AGAIN) { VBoxServiceError("CpuHotPlug: VbglR3CpuHotPlugWaitForEvent returned %Rrc\n", rc); break; } if (*pfShutdown) break; } VbglR3CpuHotPlugTerm(); return rc; }
/*static*/ DECLCALLBACK(int) VirtualBox::ClientWatcher::worker(RTTHREAD hThreadSelf, void *pvUser) { LogFlowFuncEnter(); NOREF(hThreadSelf); VirtualBox::ClientWatcher *that = (VirtualBox::ClientWatcher *)pvUser; Assert(that); typedef std::vector<ComObjPtr<Machine> > MachineVector; typedef std::vector<ComObjPtr<SessionMachine> > SessionMachineVector; SessionMachineVector machines; MachineVector spawnedMachines; size_t cnt = 0; size_t cntSpawned = 0; VirtualBoxBase::initializeComForThread(); #if defined(RT_OS_WINDOWS) int vrc; /* Initialize all the subworker data. */ that->maSubworkers[0].hThread = hThreadSelf; for (uint32_t iSubworker = 1; iSubworker < RT_ELEMENTS(that->maSubworkers); iSubworker++) that->maSubworkers[iSubworker].hThread = NIL_RTTHREAD; for (uint32_t iSubworker = 0; iSubworker < RT_ELEMENTS(that->maSubworkers); iSubworker++) { that->maSubworkers[iSubworker].pSelf = that; that->maSubworkers[iSubworker].iSubworker = iSubworker; } do { /* VirtualBox has been early uninitialized, terminate. */ AutoCaller autoCaller(that->mVirtualBox); if (!autoCaller.isOk()) break; bool fPidRace = false; /* We poll if the PID of a spawning session hasn't been established yet. */ bool fRecentDeath = false; /* We slowly poll if a session has recently been closed to do reaping. */ for (;;) { /* release the caller to let uninit() ever proceed */ autoCaller.release(); /* Kick of the waiting. */ uint32_t const cSubworkers = (that->mcWaitHandles + CW_MAX_HANDLES_PER_THREAD - 1) / CW_MAX_HANDLES_PER_THREAD; uint32_t const cMsWait = fPidRace ? 500 : fRecentDeath ? 5000 : INFINITE; LogFlowFunc(("UPDATE: Waiting. %u handles, %u subworkers, %u ms wait\n", that->mcWaitHandles, cSubworkers, cMsWait)); that->mcMsWait = cMsWait; ASMAtomicWriteU32(&that->mcActiveSubworkers, cSubworkers); RTThreadUserReset(hThreadSelf); for (uint32_t iSubworker = 1; iSubworker < cSubworkers; iSubworker++) { if (that->maSubworkers[iSubworker].hThread != NIL_RTTHREAD) { vrc = RTThreadUserSignal(that->maSubworkers[iSubworker].hThread); AssertLogRelMsg(RT_SUCCESS(vrc), ("RTThreadUserSignal -> %Rrc\n", vrc)); } else { vrc = RTThreadCreateF(&that->maSubworkers[iSubworker].hThread, VirtualBox::ClientWatcher::subworkerThread, &that->maSubworkers[iSubworker], _128K, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "Watcher%u", iSubworker); AssertLogRelMsgStmt(RT_SUCCESS(vrc), ("%Rrc iSubworker=%u\n", vrc, iSubworker), that->maSubworkers[iSubworker].hThread = NIL_RTTHREAD); } if (RT_FAILURE(vrc)) that->subworkerWait(&that->maSubworkers[iSubworker], 1); } /* Wait ourselves. */ that->subworkerWait(&that->maSubworkers[0], cMsWait); /* Make sure all waiters are done waiting. */ BOOL fRc = SetEvent(that->mUpdateReq); Assert(fRc); NOREF(fRc); vrc = RTThreadUserWait(hThreadSelf, RT_INDEFINITE_WAIT); AssertLogRelMsg(RT_SUCCESS(vrc), ("RTThreadUserWait -> %Rrc\n", vrc)); Assert(that->mcActiveSubworkers == 0); /* Consume pending update request before proceeding with processing the wait results. */ fRc = ResetEvent(that->mUpdateReq); Assert(fRc); bool update = ASMAtomicXchgBool(&that->mfUpdateReq, false); if (update) LogFlowFunc(("UPDATE: Update request pending\n")); update |= fPidRace; /* Process the wait results. */ autoCaller.add(); if (!autoCaller.isOk()) break; fRecentDeath = false; for (uint32_t iSubworker = 0; iSubworker < cSubworkers; iSubworker++) { DWORD dwWait = that->maSubworkers[iSubworker].dwWait; LogFlowFunc(("UPDATE: subworker #%u: dwWait=%#x\n", iSubworker, dwWait)); if ( (dwWait > WAIT_OBJECT_0 && dwWait < WAIT_OBJECT_0 + CW_MAX_HANDLES_PER_THREAD) || (dwWait > WAIT_ABANDONED_0 && dwWait < WAIT_ABANDONED_0 + CW_MAX_HANDLES_PER_THREAD) ) { uint32_t idxHandle = iSubworker * CW_MAX_HANDLES_PER_THREAD; if (dwWait > WAIT_OBJECT_0 && dwWait < WAIT_OBJECT_0 + CW_MAX_HANDLES_PER_THREAD) idxHandle += dwWait - WAIT_OBJECT_0; else idxHandle += dwWait - WAIT_ABANDONED_0; uint32_t const idxMachine = idxHandle - (iSubworker + 1); if (idxMachine < cnt) { /* Machine mutex is released or abandond due to client process termination. */ LogFlowFunc(("UPDATE: Calling i_checkForDeath on idxMachine=%u (idxHandle=%u) dwWait=%#x\n", idxMachine, idxHandle, dwWait)); fRecentDeath |= (machines[idxMachine])->i_checkForDeath(); } else if (idxMachine < cnt + cntSpawned) { /* Spawned VM process has terminated normally. */ Assert(dwWait < WAIT_ABANDONED_0); LogFlowFunc(("UPDATE: Calling i_checkForSpawnFailure on idxMachine=%u/%u idxHandle=%u dwWait=%#x\n", idxMachine, idxMachine - cnt, idxHandle, dwWait)); fRecentDeath |= (spawnedMachines[idxMachine - cnt])->i_checkForSpawnFailure(); } else AssertFailed(); update = true; } else Assert(dwWait == WAIT_OBJECT_0 || dwWait == WAIT_TIMEOUT); } if (update) { LogFlowFunc(("UPDATE: Update pending (cnt=%u cntSpawned=%u)...\n", cnt, cntSpawned)); /* close old process handles */ that->winResetHandleArray((uint32_t)cntSpawned); // get reference to the machines list in VirtualBox VirtualBox::MachinesOList &allMachines = that->mVirtualBox->i_getMachinesList(); // lock the machines list for reading AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS); /* obtain a new set of opened machines */ cnt = 0; machines.clear(); uint32_t idxHandle = 0; for (MachinesOList::iterator it = allMachines.begin(); it != allMachines.end(); ++it) { AssertMsgBreak(idxHandle < CW_MAX_CLIENTS, ("CW_MAX_CLIENTS reached")); ComObjPtr<SessionMachine> sm; if ((*it)->i_isSessionOpenOrClosing(sm)) { AutoCaller smCaller(sm); if (smCaller.isOk()) { AutoReadLock smLock(sm COMMA_LOCKVAL_SRC_POS); Machine::ClientToken *ct = sm->i_getClientToken(); if (ct) { HANDLE ipcSem = ct->getToken(); machines.push_back(sm); if (!(idxHandle % CW_MAX_HANDLES_PER_THREAD)) idxHandle++; that->mahWaitHandles[idxHandle++] = ipcSem; ++cnt; } } } } LogFlowFunc(("UPDATE: direct session count = %d\n", cnt)); /* obtain a new set of spawned machines */ fPidRace = false; cntSpawned = 0; spawnedMachines.clear(); for (MachinesOList::iterator it = allMachines.begin(); it != allMachines.end(); ++it) { AssertMsgBreak(idxHandle < CW_MAX_CLIENTS, ("CW_MAX_CLIENTS reached")); if ((*it)->i_isSessionSpawning()) { ULONG pid; HRESULT hrc = (*it)->COMGETTER(SessionPID)(&pid); if (SUCCEEDED(hrc)) { if (pid != NIL_RTPROCESS) { HANDLE hProc = OpenProcess(SYNCHRONIZE, FALSE, pid); AssertMsg(hProc != NULL, ("OpenProcess (pid=%d) failed with %d\n", pid, GetLastError())); if (hProc != NULL) { spawnedMachines.push_back(*it); if (!(idxHandle % CW_MAX_HANDLES_PER_THREAD)) idxHandle++; that->mahWaitHandles[idxHandle++] = hProc; ++cntSpawned; } } else fPidRace = true; } } } LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned)); /* Update mcWaitHandles and make sure there is at least one handle to wait on. */ that->mcWaitHandles = RT_MAX(idxHandle, 1); // machines lock unwinds here } else LogFlowFunc(("UPDATE: No update pending.\n")); /* reap child processes */ that->reapProcesses(); } /* for ever (well, till autoCaller fails). */ } while (0); /* Terminate subworker threads. */ ASMAtomicWriteBool(&that->mfTerminate, true); for (uint32_t iSubworker = 1; iSubworker < RT_ELEMENTS(that->maSubworkers); iSubworker++) if (that->maSubworkers[iSubworker].hThread != NIL_RTTHREAD) RTThreadUserSignal(that->maSubworkers[iSubworker].hThread); for (uint32_t iSubworker = 1; iSubworker < RT_ELEMENTS(that->maSubworkers); iSubworker++) if (that->maSubworkers[iSubworker].hThread != NIL_RTTHREAD) { vrc = RTThreadWait(that->maSubworkers[iSubworker].hThread, RT_MS_1MIN, NULL /*prc*/); if (RT_SUCCESS(vrc)) that->maSubworkers[iSubworker].hThread = NIL_RTTHREAD; else AssertLogRelMsgFailed(("RTThreadWait -> %Rrc\n", vrc)); } /* close old process handles */ that->winResetHandleArray((uint32_t)cntSpawned); /* release sets of machines if any */ machines.clear(); spawnedMachines.clear(); ::CoUninitialize(); #elif defined(RT_OS_OS2) /* according to PMREF, 64 is the maximum for the muxwait list */ SEMRECORD handles[64]; HMUX muxSem = NULLHANDLE; do { AutoCaller autoCaller(that->mVirtualBox); /* VirtualBox has been early uninitialized, terminate */ if (!autoCaller.isOk()) break; for (;;) { /* release the caller to let uninit() ever proceed */ autoCaller.release(); int vrc = RTSemEventWait(that->mUpdateReq, 500); /* Restore the caller before using VirtualBox. If it fails, this * means VirtualBox is being uninitialized and we must terminate. */ autoCaller.add(); if (!autoCaller.isOk()) break; bool update = false; bool updateSpawned = false; if (RT_SUCCESS(vrc)) { /* update event is signaled */ update = true; updateSpawned = true; } else { AssertMsg(vrc == VERR_TIMEOUT || vrc == VERR_INTERRUPTED, ("RTSemEventWait returned %Rrc\n", vrc)); /* are there any mutexes? */ if (cnt > 0) { /* figure out what's going on with machines */ unsigned long semId = 0; APIRET arc = ::DosWaitMuxWaitSem(muxSem, SEM_IMMEDIATE_RETURN, &semId); if (arc == NO_ERROR) { /* machine mutex is normally released */ Assert(semId >= 0 && semId < cnt); if (semId >= 0 && semId < cnt) { #if 0//def DEBUG { AutoReadLock machineLock(machines[semId] COMMA_LOCKVAL_SRC_POS); LogFlowFunc(("released mutex: machine='%ls'\n", machines[semId]->name().raw())); } #endif machines[semId]->i_checkForDeath(); } update = true; } else if (arc == ERROR_SEM_OWNER_DIED) { /* machine mutex is abandoned due to client process * termination; find which mutex is in the Owner Died * state */ for (size_t i = 0; i < cnt; ++i) { PID pid; TID tid; unsigned long reqCnt; arc = DosQueryMutexSem((HMTX)handles[i].hsemCur, &pid, &tid, &reqCnt); if (arc == ERROR_SEM_OWNER_DIED) { /* close the dead mutex as asked by PMREF */ ::DosCloseMutexSem((HMTX)handles[i].hsemCur); Assert(i >= 0 && i < cnt); if (i >= 0 && i < cnt) { #if 0//def DEBUG { AutoReadLock machineLock(machines[semId] COMMA_LOCKVAL_SRC_POS); LogFlowFunc(("mutex owner dead: machine='%ls'\n", machines[i]->name().raw())); } #endif machines[i]->i_checkForDeath(); } } } update = true; } else AssertMsg(arc == ERROR_INTERRUPT || arc == ERROR_TIMEOUT, ("DosWaitMuxWaitSem returned %d\n", arc)); } /* are there any spawning sessions? */ if (cntSpawned > 0) { for (size_t i = 0; i < cntSpawned; ++i) updateSpawned |= (spawnedMachines[i])-> i_checkForSpawnFailure(); } } if (update || updateSpawned) { // get reference to the machines list in VirtualBox VirtualBox::MachinesOList &allMachines = that->mVirtualBox->i_getMachinesList(); // lock the machines list for reading AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS); if (update) { /* close the old muxsem */ if (muxSem != NULLHANDLE) ::DosCloseMuxWaitSem(muxSem); /* obtain a new set of opened machines */ cnt = 0; machines.clear(); for (MachinesOList::iterator it = allMachines.begin(); it != allMachines.end(); ++it) { /// @todo handle situations with more than 64 objects AssertMsg(cnt <= 64 /* according to PMREF */, ("maximum of 64 mutex semaphores reached (%d)", cnt)); ComObjPtr<SessionMachine> sm; if ((*it)->i_isSessionOpenOrClosing(sm)) { AutoCaller smCaller(sm); if (smCaller.isOk()) { AutoReadLock smLock(sm COMMA_LOCKVAL_SRC_POS); ClientToken *ct = sm->i_getClientToken(); if (ct) { HMTX ipcSem = ct->getToken(); machines.push_back(sm); handles[cnt].hsemCur = (HSEM)ipcSem; handles[cnt].ulUser = cnt; ++cnt; } } } } LogFlowFunc(("UPDATE: direct session count = %d\n", cnt)); if (cnt > 0) { /* create a new muxsem */ APIRET arc = ::DosCreateMuxWaitSem(NULL, &muxSem, cnt, handles, DCMW_WAIT_ANY); AssertMsg(arc == NO_ERROR, ("DosCreateMuxWaitSem returned %d\n", arc)); NOREF(arc); } } if (updateSpawned) { /* obtain a new set of spawned machines */ spawnedMachines.clear(); for (MachinesOList::iterator it = allMachines.begin(); it != allMachines.end(); ++it) { if ((*it)->i_isSessionSpawning()) spawnedMachines.push_back(*it); } cntSpawned = spawnedMachines.size(); LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned)); } } /* reap child processes */ that->reapProcesses(); } /* for ever (well, till autoCaller fails). */ } while (0); /* close the muxsem */ if (muxSem != NULLHANDLE) ::DosCloseMuxWaitSem(muxSem); /* release sets of machines if any */ machines.clear(); spawnedMachines.clear(); #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) bool update = false; bool updateSpawned = false; do { AutoCaller autoCaller(that->mVirtualBox); if (!autoCaller.isOk()) break; do { /* release the caller to let uninit() ever proceed */ autoCaller.release(); /* determine wait timeout adaptively: after updating information * relevant to the client watcher, check a few times more * frequently. This ensures good reaction time when the signalling * has to be done a bit before the actual change for technical * reasons, and saves CPU cycles when no activities are expected. */ RTMSINTERVAL cMillies; { uint8_t uOld, uNew; do { uOld = ASMAtomicUoReadU8(&that->mUpdateAdaptCtr); uNew = uOld ? uOld - 1 : uOld; } while (!ASMAtomicCmpXchgU8(&that->mUpdateAdaptCtr, uNew, uOld)); Assert(uOld <= RT_ELEMENTS(s_aUpdateTimeoutSteps) - 1); cMillies = s_aUpdateTimeoutSteps[uOld]; } int rc = RTSemEventWait(that->mUpdateReq, cMillies); /* * Restore the caller before using VirtualBox. If it fails, this * means VirtualBox is being uninitialized and we must terminate. */ autoCaller.add(); if (!autoCaller.isOk()) break; if (RT_SUCCESS(rc) || update || updateSpawned) { /* RT_SUCCESS(rc) means an update event is signaled */ // get reference to the machines list in VirtualBox VirtualBox::MachinesOList &allMachines = that->mVirtualBox->i_getMachinesList(); // lock the machines list for reading AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS); if (RT_SUCCESS(rc) || update) { /* obtain a new set of opened machines */ machines.clear(); for (MachinesOList::iterator it = allMachines.begin(); it != allMachines.end(); ++it) { ComObjPtr<SessionMachine> sm; if ((*it)->i_isSessionOpenOrClosing(sm)) machines.push_back(sm); } cnt = machines.size(); LogFlowFunc(("UPDATE: direct session count = %d\n", cnt)); } if (RT_SUCCESS(rc) || updateSpawned) { /* obtain a new set of spawned machines */ spawnedMachines.clear(); for (MachinesOList::iterator it = allMachines.begin(); it != allMachines.end(); ++it) { if ((*it)->i_isSessionSpawning()) spawnedMachines.push_back(*it); } cntSpawned = spawnedMachines.size(); LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned)); } // machines lock unwinds here } update = false; for (size_t i = 0; i < cnt; ++i) update |= (machines[i])->i_checkForDeath(); updateSpawned = false; for (size_t i = 0; i < cntSpawned; ++i) updateSpawned |= (spawnedMachines[i])->i_checkForSpawnFailure(); /* reap child processes */ that->reapProcesses(); } while (true); } while (0); /* release sets of machines if any */ machines.clear(); spawnedMachines.clear(); #elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER) bool updateSpawned = false; do { AutoCaller autoCaller(that->mVirtualBox); if (!autoCaller.isOk()) break; do { /* release the caller to let uninit() ever proceed */ autoCaller.release(); /* determine wait timeout adaptively: after updating information * relevant to the client watcher, check a few times more * frequently. This ensures good reaction time when the signalling * has to be done a bit before the actual change for technical * reasons, and saves CPU cycles when no activities are expected. */ RTMSINTERVAL cMillies; { uint8_t uOld, uNew; do { uOld = ASMAtomicUoReadU8(&that->mUpdateAdaptCtr); uNew = uOld ? (uint8_t)(uOld - 1) : uOld; } while (!ASMAtomicCmpXchgU8(&that->mUpdateAdaptCtr, uNew, uOld)); Assert(uOld <= RT_ELEMENTS(s_aUpdateTimeoutSteps) - 1); cMillies = s_aUpdateTimeoutSteps[uOld]; } int rc = RTSemEventWait(that->mUpdateReq, cMillies); /* * Restore the caller before using VirtualBox. If it fails, this * means VirtualBox is being uninitialized and we must terminate. */ autoCaller.add(); if (!autoCaller.isOk()) break; /** @todo this quite big effort for catching machines in spawning * state which can't be caught by the token mechanism (as the token * can't be in the other process yet) could be eliminated if the * reaping is made smarter, having cross-reference information * from the pid to the corresponding machine object. Both cases do * more or less the same thing anyway. */ if (RT_SUCCESS(rc) || updateSpawned) { /* RT_SUCCESS(rc) means an update event is signaled */ // get reference to the machines list in VirtualBox VirtualBox::MachinesOList &allMachines = that->mVirtualBox->i_getMachinesList(); // lock the machines list for reading AutoReadLock thatLock(allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS); if (RT_SUCCESS(rc) || updateSpawned) { /* obtain a new set of spawned machines */ spawnedMachines.clear(); for (MachinesOList::iterator it = allMachines.begin(); it != allMachines.end(); ++it) { if ((*it)->i_isSessionSpawning()) spawnedMachines.push_back(*it); } cntSpawned = spawnedMachines.size(); LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned)); } NOREF(cnt); // machines lock unwinds here } updateSpawned = false; for (size_t i = 0; i < cntSpawned; ++i) updateSpawned |= (spawnedMachines[i])->i_checkForSpawnFailure(); /* reap child processes */ that->reapProcesses(); } while (true); } while (0); /* release sets of machines if any */ machines.clear(); spawnedMachines.clear(); #else # error "Port me!" #endif VirtualBoxBase::uninitializeComForThread(); LogFlowFuncLeave(); return 0; }
static DECLCALLBACK(int) stubSyncThreadProc(RTTHREAD ThreadSelf, void *pvUser) { #ifdef WINDOWS MSG msg; # ifdef VBOX_WITH_WDDM static VBOXDISPMP_CALLBACKS VBoxDispMpTstCallbacks = {NULL, NULL, NULL}; HMODULE hVBoxD3D = NULL; VBOXCR_UPDATEWNDCB RegionsData; HRESULT hr; GLint spuConnection = 0; # endif #endif (void) pvUser; crDebug("Sync thread started"); #ifdef WINDOWS PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); # ifdef VBOX_WITH_WDDM hVBoxD3D = GetModuleHandle(VBOX_MODNAME_DISPD3D); if (hVBoxD3D) { hVBoxD3D = LoadLibrary(VBOX_MODNAME_DISPD3D); } if (hVBoxD3D) { PFNVBOXDISPMP_GETCALLBACKS pfnVBoxDispMpGetCallbacks; pfnVBoxDispMpGetCallbacks = (PFNVBOXDISPMP_GETCALLBACKS)GetProcAddress(hVBoxD3D, TEXT("VBoxDispMpGetCallbacks")); if (pfnVBoxDispMpGetCallbacks) { hr = pfnVBoxDispMpGetCallbacks(VBOXDISPMP_VERSION, &VBoxDispMpTstCallbacks); if (S_OK==hr) { CRASSERT(VBoxDispMpTstCallbacks.pfnEnableEvents); CRASSERT(VBoxDispMpTstCallbacks.pfnDisableEvents); CRASSERT(VBoxDispMpTstCallbacks.pfnGetRegions); hr = VBoxDispMpTstCallbacks.pfnEnableEvents(); if (hr != S_OK) { crWarning("VBoxDispMpTstCallbacks.pfnEnableEvents failed"); } else { crDebug("running with " VBOX_MODNAME_DISPD3D); stub.trackWindowVisibleRgn = 0; stub.bRunningUnderWDDM = true; #ifdef VBOX_WDDM_MINIPORT_WITH_VISIBLE_RECTS crError("should not be here, visible rects should be processed in miniport!"); #endif } } else { crWarning("VBoxDispMpGetCallbacks failed"); } } } # endif /* VBOX_WITH_WDDM */ #endif /* WINDOWS */ crLockMutex(&stub.mutex); #if defined(WINDOWS) && defined(VBOX_WITH_WDDM) spuConnection = #endif stub.spu->dispatch_table.VBoxPackSetInjectThread(NULL); #if defined(WINDOWS) && defined(VBOX_WITH_WDDM) if (stub.bRunningUnderWDDM && !spuConnection) { crError("VBoxPackSetInjectThread failed!"); } #endif crUnlockMutex(&stub.mutex); RTThreadUserSignal(ThreadSelf); while(!stub.bShutdownSyncThread) { #ifdef WINDOWS if (!PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { # ifdef VBOX_WITH_WDDM if (VBoxDispMpTstCallbacks.pfnGetRegions) { hr = VBoxDispMpTstCallbacks.pfnGetRegions(&RegionsData.Regions, 50); if (S_OK==hr) { RegionsData.fSendUpdateMsg = false; # if 0 uint32_t i; crDebug(">>>Regions for HWND(0x%x)>>>", RegionsData.Regions.hWnd); crDebug("Flags(0x%x)", RegionsData.Regions.pRegions->fFlags.Value); for (i = 0; i < RegionsData.Regions.pRegions->RectsInfo.cRects; ++i) { RECT *pRect = &RegionsData.Regions.pRegions->RectsInfo.aRects[i]; crDebug("Rect(%d): left(%d), top(%d), right(%d), bottom(%d)", i, pRect->left, pRect->top, pRect->right, pRect->bottom); } crDebug("<<<<<"); # endif /*hacky way to make sure window wouldn't be deleted in another thread as we hold hashtable lock here*/ crHashtableWalk(stub.windowTable, stubSyncTrUpdateWindowCB, &RegionsData); if (RegionsData.fSendUpdateMsg) { SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0, SMTO_NORMAL, 1000, NULL); } } else { if (WAIT_TIMEOUT!=hr) { crWarning("VBoxDispMpTstCallbacks.pfnGetRegions failed with 0x%x", hr); } crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL); } } else # endif { crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL); RTThreadSleep(50); } } else { if (WM_QUIT==msg.message) { crDebug("Sync thread got WM_QUIT"); break; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } #else crLockMutex(&stub.mutex); crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL); crUnlockMutex(&stub.mutex); RTThreadSleep(50); #endif } #ifdef VBOX_WITH_WDDM if (VBoxDispMpTstCallbacks.pfnDisableEvents) { VBoxDispMpTstCallbacks.pfnDisableEvents(); } if (spuConnection) { stub.spu->dispatch_table.VBoxConDestroy(spuConnection); } if (hVBoxD3D) { FreeLibrary(hVBoxD3D); } #endif crDebug("Sync thread stopped"); return 0; }
/** * Timer thread. */ static DECLCALLBACK(int) rttimerCallback(RTTHREAD Thread, void *pvArg) { PRTTIMER pTimer = (PRTTIMER)(void *)pvArg; Assert(pTimer->u32Magic == RTTIMER_MAGIC); /* * Bounce our priority up quite a bit. */ if ( !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) /*&& !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)*/) { int rc = GetLastError(); AssertMsgFailed(("Failed to set priority class lasterror %d.\n", rc)); pTimer->iError = RTErrConvertFromWin32(rc); return rc; } /* * Start the waitable timer. */ #ifdef USE_CATCH_UP const int64_t NSInterval = (int64_t)pTimer->uMilliesInterval * 1000000; pTimer->llNext.QuadPart = RTTimeNanoTS() + NSInterval; #else pTimer->llNext.QuadPart = -(int64_t)pTimer->uMilliesInterval * 10000; #endif LARGE_INTEGER ll; ll.QuadPart = -(int64_t)pTimer->uMilliesInterval * 10000; #ifdef USE_APC if (!SetWaitableTimer(pTimer->hTimer, &ll, 0, rttimerAPCProc, pTimer, FALSE)) #else if (!SetWaitableTimer(pTimer->hTimer, &ll, 0, NULL, NULL, FALSE)) #endif { int rc = GetLastError(); AssertMsgFailed(("Failed to set timer, lasterr %d.\n", rc)); pTimer->iError = RTErrConvertFromWin32(rc); RTThreadUserSignal(Thread); return rc; } /* * Wait for the semaphore to be posted. */ RTThreadUserSignal(Thread); for (;pTimer->u32Magic == RTTIMER_MAGIC;) { #ifdef USE_APC int rc = WaitForSingleObjectEx(pTimer->hevWait, INFINITE, TRUE); if (rc != WAIT_OBJECT_0 && rc != WAIT_IO_COMPLETION) #else int rc = WaitForSingleObjectEx(pTimer->hTimer, INFINITE, FALSE); if (pTimer->u32Magic != RTTIMER_MAGIC) break; if (rc == WAIT_OBJECT_0) { /* * Callback the handler. */ pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pTimer->iTick); /* * Rearm the timer handler. */ # ifdef USE_CATCH_UP pTimer->llNext.QuadPart += NSInterval; LARGE_INTEGER ll; ll.QuadPart = RTTimeNanoTS() - pTimer->llNext.QuadPart; if (ll.QuadPart < -500000) ll.QuadPart = ll.QuadPart / 100; else ll.QuadPart = -500000 / 100; /* need to catch up, do a minimum wait of 0.5ms. */ # else LARGE_INTEGER ll = pTimer->llNext; # endif BOOL fRc = SetWaitableTimer(pTimer->hTimer, &ll, 0, NULL, NULL, FALSE); AssertMsg(fRc || pTimer->u32Magic != RTTIMER_MAGIC, ("last error %d\n", GetLastError())); NOREF(fRc); } else #endif { /* * We failed during wait, so just signal the destructor and exit. */ int rc2 = GetLastError(); RTThreadUserSignal(Thread); AssertMsgFailed(("Wait on hTimer failed, rc=%d lasterr=%d\n", rc, rc2)); NOREF(rc2); return -1; } } /* * Exit. */ RTThreadUserSignal(Thread); return 0; }
/** @copydoc VBOXSERVICE::pfnWorker */ DECLCALLBACK(int) VBoxServiceAutoMountWorker(bool volatile *pfShutdown) { /* * Tell the control thread that it can continue * spawning services. */ RTThreadUserSignal(RTThreadSelf()); uint32_t cMappings; PVBGLR3SHAREDFOLDERMAPPING paMappings; int rc = VbglR3SharedFolderGetMappings(g_SharedFoldersSvcClientID, true /* Only process auto-mounted folders */, &paMappings, &cMappings); if ( RT_SUCCESS(rc) && cMappings) { char *pszMountDir; rc = VbglR3SharedFolderGetMountDir(&pszMountDir); if (rc == VERR_NOT_FOUND) rc = RTStrDupEx(&pszMountDir, VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR); if (RT_SUCCESS(rc)) { VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder mount dir set to \"%s\"\n", pszMountDir); char *pszSharePrefix; rc = VbglR3SharedFolderGetMountPrefix(&pszSharePrefix); if (RT_SUCCESS(rc)) { VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder mount prefix set to \"%s\"\n", pszSharePrefix); #ifdef USE_VIRTUAL_SHARES /* Check for a fixed/virtual auto-mount share. */ if (VbglR3SharedFolderExists(g_SharedFoldersSvcClientID, "vbsfAutoMount")) { VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Host supports auto-mount root\n"); } else { #endif VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Got %u shared folder mappings\n", cMappings); rc = VBoxServiceAutoMountProcessMappings(paMappings, cMappings, pszMountDir, pszSharePrefix, g_SharedFoldersSvcClientID); #ifdef USE_VIRTUAL_SHARES } #endif RTStrFree(pszSharePrefix); } /* Mount share prefix. */ else VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mount prefix, rc = %Rrc\n", rc); RTStrFree(pszMountDir); } else VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder directory, rc = %Rrc\n", rc); VbglR3SharedFolderFreeMappings(paMappings); } else if (RT_FAILURE(rc)) VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mappings, rc = %Rrc\n", rc); else VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: No shared folder mappings found\n"); /* * Because this thread is a one-timer at the moment we don't want to break/change * the semantics of the main thread's start/stop sub-threads handling. * * This thread exits so fast while doing its own startup in VBoxServiceStartServices() * that this->fShutdown flag is set to true in VBoxServiceThread() before we have the * chance to check for a service failure in VBoxServiceStartServices() to indicate * a VBoxService startup error. * * Therefore *no* service threads are allowed to quit themselves and need to wait * for the pfShutdown flag to be set by the main thread. */ for (;;) { /* Do we need to shutdown? */ if (*pfShutdown) break; /* Let's sleep for a bit and let others run ... */ RTThreadSleep(500); } RTSemEventMultiDestroy(g_AutoMountEvent); g_AutoMountEvent = NIL_RTSEMEVENTMULTI; VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Finished with rc=%Rrc\n", rc); return VINF_SUCCESS; }
/** @copydoc VBOXSERVICE::pfnWorker */ DECLCALLBACK(int) VBoxServiceVMStatsWorker(bool volatile *pfShutdown) { int rc = VINF_SUCCESS; /* Start monitoring of the stat event change event. */ rc = VbglR3CtlFilterMask(VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST, 0); if (RT_FAILURE(rc)) { VBoxServiceVerbose(3, "VBoxServiceVMStatsWorker: VbglR3CtlFilterMask failed with %d\n", rc); return rc; } /* * Tell the control thread that it can continue * spawning services. */ RTThreadUserSignal(RTThreadSelf()); /* * Now enter the loop retrieving runtime data continuously. */ for (;;) { uint32_t fEvents = 0; RTMSINTERVAL cWaitMillies; /* Check if an update interval change is pending. */ rc = VbglR3WaitEvent(VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST, 0 /* no wait */, &fEvents); if ( RT_SUCCESS(rc) && (fEvents & VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)) { VbglR3StatQueryInterval(&gCtx.cMsStatInterval); } if (gCtx.cMsStatInterval) { VBoxServiceVMStatsReport(); cWaitMillies = gCtx.cMsStatInterval; } else cWaitMillies = 3000; /* * Block for a while. * * The event semaphore takes care of ignoring interruptions and it * allows us to implement service wakeup later. */ if (*pfShutdown) break; int rc2 = RTSemEventMultiWait(g_VMStatEvent, cWaitMillies); if (*pfShutdown) break; if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2)) { VBoxServiceError("VBoxServiceVMStatsWorker: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2); rc = rc2; break; } } /* Cancel monitoring of the stat event change event. */ rc = VbglR3CtlFilterMask(0, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST); if (RT_FAILURE(rc)) VBoxServiceVerbose(3, "VBoxServiceVMStatsWorker: VbglR3CtlFilterMask failed with %d\n", rc); RTSemEventMultiDestroy(g_VMStatEvent); g_VMStatEvent = NIL_RTSEMEVENTMULTI; VBoxServiceVerbose(3, "VBoxStatsThread: finished statistics change request thread\n"); return 0; }
/** * Thread function to wait for and process seamless mode change * requests */ static DECLCALLBACK(int) VBoxSeamlessWorker(void *pInstance, bool volatile *pfShutdown) { AssertPtrReturn(pInstance, VERR_INVALID_POINTER); LogFlowFunc(("pInstance=%p\n", pInstance)); /* * Tell the control thread that it can continue * spawning services. */ RTThreadUserSignal(RTThreadSelf()); PVBOXSEAMLESSCONTEXT pCtx = (PVBOXSEAMLESSCONTEXT)pInstance; HANDLE gVBoxDriver = pCtx->pEnv->hDriver; VBoxGuestFilterMaskInfo maskInfo; DWORD cbReturned; BOOL fWasScreenSaverActive = FALSE, fRet; maskInfo.u32OrMask = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; maskInfo.u32NotMask = 0; if (!DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL)) { DWORD dwErr = GetLastError(); LogRel(("Seamless: DeviceIOControl(CtlMask) failed with %ld, exiting ...\n", dwErr)); return RTErrConvertFromWin32(dwErr); } int rc = VINF_SUCCESS; for (;;) { /* wait for a seamless change event */ VBoxGuestWaitEventInfo waitEvent; waitEvent.u32TimeoutIn = 5000; waitEvent.u32EventMaskIn = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL)) { /* are we supposed to stop? */ if (*pfShutdown) break; /* did we get the right event? */ if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST) { /* We got at least one event. Read the requested resolution * and try to set it until success. New events will not be seen * but a new resolution will be read in this poll loop. */ for (;;) { /* get the seamless change request */ VMMDevSeamlessChangeRequest seamlessChangeRequest = {0}; vmmdevInitRequest((VMMDevRequestHeader*)&seamlessChangeRequest, VMMDevReq_GetSeamlessChangeRequest); seamlessChangeRequest.eventAck = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; BOOL fSeamlessChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(seamlessChangeRequest)), &seamlessChangeRequest, sizeof(seamlessChangeRequest), &seamlessChangeRequest, sizeof(seamlessChangeRequest), &cbReturned, NULL); if (fSeamlessChangeQueried) { LogFlowFunc(("Mode changed to %d\n", seamlessChangeRequest.mode)); switch(seamlessChangeRequest.mode) { case VMMDev_Seamless_Disabled: if (fWasScreenSaverActive) { LogRel(("Seamless: Re-enabling the screensaver\n")); fRet = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, TRUE, NULL, 0); if (!fRet) LogRel(("Seamless: SystemParametersInfo SPI_SETSCREENSAVEACTIVE failed with %ld\n", GetLastError())); } PostMessage(g_hwndToolWindow, WM_VBOX_SEAMLESS_DISABLE, 0, 0); break; case VMMDev_Seamless_Visible_Region: fRet = SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &fWasScreenSaverActive, 0); if (!fRet) LogRel(("Seamless: SystemParametersInfo SPI_GETSCREENSAVEACTIVE failed with %ld\n", GetLastError())); if (fWasScreenSaverActive) LogRel(("Seamless: Disabling the screensaver\n")); fRet = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0); if (!fRet) LogRel(("Seamless: SystemParametersInfo SPI_SETSCREENSAVEACTIVE failed with %ld\n", GetLastError())); PostMessage(g_hwndToolWindow, WM_VBOX_SEAMLESS_ENABLE, 0, 0); break; case VMMDev_Seamless_Host_Window: break; default: AssertFailed(); break; } break; } else LogRel(("Seamless: DeviceIoControl(ChangeReq) failed with %ld\n", GetLastError())); if (*pfShutdown) break; /* sleep a bit to not eat too much CPU while retrying */ RTThreadSleep(10); } } } else { /* sleep a bit to not eat too much CPU in case the above call always fails */ RTThreadSleep(10); } if (*pfShutdown) break; } maskInfo.u32OrMask = 0; maskInfo.u32NotMask = VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST; if (!DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL)) LogRel(("Seamless: DeviceIOControl(CtlMask) failed with %ld\n", GetLastError())); LogFlowFuncLeaveRC(rc); return rc; }
static DECLCALLBACK(int) stubSyncThreadProc(RTTHREAD ThreadSelf, void *pvUser) { #ifdef WINDOWS MSG msg; # ifdef VBOX_WITH_WDDM HMODULE hVBoxD3D = NULL; GLint spuConnection = 0; # endif #endif (void) pvUser; crDebug("Sync thread started"); #ifdef WINDOWS PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); # ifdef VBOX_WITH_WDDM hVBoxD3D = NULL; if (!GetModuleHandleEx(0, VBOX_MODNAME_DISPD3D, &hVBoxD3D)) { crDebug("GetModuleHandleEx failed err %d", GetLastError()); hVBoxD3D = NULL; } if (hVBoxD3D) { crDebug("running with " VBOX_MODNAME_DISPD3D); stub.trackWindowVisibleRgn = 0; stub.bRunningUnderWDDM = true; } # endif /* VBOX_WITH_WDDM */ #endif /* WINDOWS */ crLockMutex(&stub.mutex); #if defined(WINDOWS) && defined(VBOX_WITH_WDDM) spuConnection = #endif stub.spu->dispatch_table.VBoxPackSetInjectThread(NULL); #if defined(WINDOWS) && defined(VBOX_WITH_WDDM) if (stub.bRunningUnderWDDM && !spuConnection) { crError("VBoxPackSetInjectThread failed!"); } #endif crUnlockMutex(&stub.mutex); RTThreadUserSignal(ThreadSelf); while(!stub.bShutdownSyncThread) { #ifdef WINDOWS if (!PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { # ifdef VBOX_WITH_WDDM if (stub.bRunningUnderWDDM) { } else # endif { crHashtableWalk(stub.windowTable, stubSyncTrCheckWindowsCB, NULL); RTThreadSleep(50); } } else { if (WM_QUIT==msg.message) { crDebug("Sync thread got WM_QUIT"); break; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } #else /* Try to keep a consistent locking order. */ crHashtableLock(stub.windowTable); crLockMutex(&stub.mutex); crHashtableWalkUnlocked(stub.windowTable, stubSyncTrCheckWindowsCB, NULL); crUnlockMutex(&stub.mutex); crHashtableUnlock(stub.windowTable); RTThreadSleep(50); #endif } #ifdef VBOX_WITH_WDDM if (spuConnection) { stub.spu->dispatch_table.VBoxConDestroy(spuConnection); } if (hVBoxD3D) { FreeLibrary(hVBoxD3D); } #endif crDebug("Sync thread stopped"); return 0; }
/** * Thread function waiting for credentials to arrive. * * @return IPRT status code. * @param hThreadSelf Thread handle. * @param pvUser Pointer to a PAMVBOXTHREAD structure providing * required data used / set by the thread. */ static DECLCALLBACK(int) pam_vbox_wait_thread(RTTHREAD hThreadSelf, void *pvUser) { RT_NOREF1(hThreadSelf); PPAMVBOXTHREAD pUserData = (PPAMVBOXTHREAD)pvUser; AssertPtr(pUserData); int rc = VINF_SUCCESS; /* Get current time stamp to later calculate rest of timeout left. */ uint64_t u64StartMS = RTTimeMilliTS(); #ifdef VBOX_WITH_GUEST_PROPS uint32_t uClientID = 0; rc = VbglR3GuestPropConnect(&uClientID); if (RT_FAILURE(rc)) { pam_vbox_error(pUserData->hPAM, "pam_vbox_wait_thread: Unable to connect to guest property service, rc=%Rrc\n", rc); } else { pam_vbox_log(pUserData->hPAM, "pam_vbox_wait_thread: clientID=%u\n", uClientID); #endif for (;;) { #ifdef VBOX_WITH_GUEST_PROPS if (uClientID) { rc = pam_vbox_wait_prop(pUserData->hPAM, uClientID, "/VirtualBox/GuestAdd/PAM/CredsWaitAbort", 500 /* Wait 500ms, same as VBoxGINA/VBoxCredProv. */); switch (rc) { case VINF_SUCCESS: /* Somebody (guest/host) wants to abort waiting for credentials. */ break; case VERR_INTERRUPTED: pam_vbox_error(pUserData->hPAM, "pam_vbox_wait_thread: The abort notification request timed out or was interrupted\n"); break; case VERR_TIMEOUT: /* We did not receive an abort message within time. */ break; case VERR_TOO_MUCH_DATA: pam_vbox_error(pUserData->hPAM, "pam_vbox_wait_thread: Temporarily unable to get abort notification\n"); break; default: pam_vbox_error(pUserData->hPAM, "pam_vbox_wait_thread: The abort notification request failed with rc=%Rrc\n", rc); break; } if (RT_SUCCESS(rc)) /* Abort waiting. */ { pam_vbox_log(pUserData->hPAM, "pam_vbox_wait_thread: Got notification to abort waiting\n"); rc = VERR_CANCELLED; break; } } #endif if ( RT_SUCCESS(rc) || rc == VERR_TIMEOUT) { rc = pam_vbox_check_creds(pUserData->hPAM); if (RT_SUCCESS(rc)) { /* Credentials retrieved. */ break; /* Thread no longer is required, bail out. */ } else if (rc == VERR_NOT_FOUND) { /* No credentials found, but try next round (if there's * time left for) ... */ #ifndef VBOX_WITH_GUEST_PROPS RTThreadSleep(500); /* Wait 500 ms. */ #endif } else break; /* Something bad happend ... */ } else break; /* Calculate timeout value left after process has been started. */ uint64_t u64Elapsed = RTTimeMilliTS() - u64StartMS; /* Is it time to bail out? */ if (pUserData->uTimeoutMS < u64Elapsed) { pam_vbox_log(pUserData->hPAM, "pam_vbox_wait_thread: Waiting thread has reached timeout (%dms), exiting ...\n", pUserData->uTimeoutMS); rc = VERR_TIMEOUT; break; } } #ifdef VBOX_WITH_GUEST_PROPS } VbglR3GuestPropDisconnect(uClientID); #endif /* Save result. */ pUserData->rc = rc; /** @todo Use ASMAtomicXXX? */ int rc2 = RTThreadUserSignal(RTThreadSelf()); AssertRC(rc2); pam_vbox_log(pUserData->hPAM, "pam_vbox_wait_thread: Waiting thread returned with rc=%Rrc\n", rc); return rc; }
/** * The PDM thread function. * * @returns return from pfnThread. * * @param Thread The thread handle. * @param pvUser Pointer to the PDMTHREAD structure. */ static DECLCALLBACK(int) pdmR3ThreadMain(RTTHREAD Thread, void *pvUser) { PPDMTHREAD pThread = (PPDMTHREAD)pvUser; Log(("PDMThread: Initializing thread %RTthrd / %p / '%s'...\n", Thread, pThread, RTThreadGetName(Thread))); pThread->Thread = Thread; PUVM pUVM = pThread->Internal.s.pVM->pUVM; if ( pUVM->pVmm2UserMethods && pUVM->pVmm2UserMethods->pfnNotifyPdmtInit) pUVM->pVmm2UserMethods->pfnNotifyPdmtInit(pUVM->pVmm2UserMethods, pUVM); /* * The run loop. * * It handles simple thread functions which returns when they see a suspending * request and leaves the PDMR3ThreadIAmSuspending and PDMR3ThreadIAmRunning * parts to us. */ int rc; for (;;) { switch (pThread->Internal.s.enmType) { case PDMTHREADTYPE_DEVICE: rc = pThread->u.Dev.pfnThread(pThread->u.Dev.pDevIns, pThread); break; case PDMTHREADTYPE_USB: rc = pThread->u.Usb.pfnThread(pThread->u.Usb.pUsbIns, pThread); break; case PDMTHREADTYPE_DRIVER: rc = pThread->u.Drv.pfnThread(pThread->u.Drv.pDrvIns, pThread); break; case PDMTHREADTYPE_INTERNAL: rc = pThread->u.Int.pfnThread(pThread->Internal.s.pVM, pThread); break; case PDMTHREADTYPE_EXTERNAL: rc = pThread->u.Ext.pfnThread(pThread); break; default: AssertMsgFailed(("%d\n", pThread->Internal.s.enmType)); rc = VERR_PDM_THREAD_IPE_1; break; } if (RT_FAILURE(rc)) break; /* * If this is a simple thread function, the state will be suspending * or initializing now. If it isn't we're supposed to terminate. */ if ( pThread->enmState != PDMTHREADSTATE_SUSPENDING && pThread->enmState != PDMTHREADSTATE_INITIALIZING) { Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING); break; } rc = PDMR3ThreadIAmSuspending(pThread); if (RT_FAILURE(rc)) break; if (pThread->enmState != PDMTHREADSTATE_RESUMING) { Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING); break; } rc = PDMR3ThreadIAmRunning(pThread); if (RT_FAILURE(rc)) break; } if (RT_FAILURE(rc)) LogRel(("PDMThread: Thread '%s' (%RTthrd) quit unexpectedly with rc=%Rrc.\n", RTThreadGetName(Thread), Thread, rc)); /* * Advance the state to terminating and then on to terminated. */ for (;;) { PDMTHREADSTATE enmState = pThread->enmState; if ( enmState == PDMTHREADSTATE_TERMINATING || pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState)) break; } ASMAtomicXchgSize(&pThread->enmState, PDMTHREADSTATE_TERMINATED); int rc2 = RTThreadUserSignal(Thread); AssertRC(rc2); if ( pUVM->pVmm2UserMethods && pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm) pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm(pUVM->pVmm2UserMethods, pUVM); Log(("PDMThread: Terminating thread %RTthrd / %p / '%s': %Rrc\n", Thread, pThread, RTThreadGetName(Thread), rc)); return rc; }