/** * Client mode connection thread. * * @returns iprt status code. * @param hSelf Thread handle. Use to sleep on. The main thread will * signal it to speed up thread shutdown. * @param pvUser Ignored. */ static DECLCALLBACK(int) txsTcpClientConnectThread(RTTHREAD hSelf, void *pvUser) { for (;;) { /* Stop? */ RTCritSectEnter(&g_TcpCritSect); bool fStop = g_fTcpStopConnecting; RTCritSectLeave(&g_TcpCritSect); if (fStop) return VINF_SUCCESS; /* Try connect. */ /** @todo make cancelable! */ RTSOCKET hTcpClient; Log2(("Calling RTTcpClientConnect(%s, %u,)...\n", g_szTcpConnectAddr, g_uTcpConnectPort)); int rc = RTTcpClientConnectEx(g_szTcpConnectAddr, g_uTcpConnectPort, &hTcpClient, RT_SOCKETCONNECT_DEFAULT_WAIT, &g_pTcpConnectCancelCookie); Log(("txsTcpRecvPkt: RTTcpClientConnect -> %Rrc\n", rc)); if (RT_SUCCESS(rc)) { hTcpClient = txsTcpSetClient(hTcpClient, true /*fFromServer*/); RTTcpClientCloseEx(hTcpClient, true /* fGracefulShutdown*/); break; } if (txsTcpIsFatalClientConnectStatus(rc)) return rc; /* Delay a wee bit before retrying. */ RTThreadUserWait(hSelf, 1536); } return VINF_SUCCESS; }
/** * Waits for credentials to arrive by creating and waiting for a thread. * * @return IPRT status code. * @param hPAM PAM handle. * @param uClientID Guest property service client ID. * @param uTimeoutMS Timeout (in ms) to wait for the change. Specify * RT_INDEFINITE_WAIT to wait indefinitly. */ static int pam_vbox_wait_for_creds(pam_handle_t *hPAM, uint32_t uClientID, uint32_t uTimeoutMS) { RT_NOREF1(uClientID); PAMVBOXTHREAD threadData; threadData.hPAM = hPAM; threadData.uTimeoutMS = uTimeoutMS; RTTHREAD threadWait; int rc = RTThreadCreate(&threadWait, pam_vbox_wait_thread, (void *)&threadData, 0, RTTHREADTYPE_DEFAULT, 0 /* Flags */, "pam_vbox"); if (RT_SUCCESS(rc)) { pam_vbox_log(hPAM, "pam_vbox_wait_for_creds: Waiting for credentials (%dms) ...\n", uTimeoutMS); /* Wait for thread to initialize. */ /** @todo We can do something else here in the meantime later. */ rc = RTThreadUserWait(threadWait, RT_INDEFINITE_WAIT); if (RT_SUCCESS(rc)) rc = threadData.rc; /* Get back thread result to take further actions. */ } else pam_vbox_error(hPAM, "pam_vbox_wait_for_creds: Creating thread failed with rc=%Rrc\n", rc); pam_vbox_log(hPAM, "pam_vbox_wait_for_creds: Waiting for credentials returned with rc=%Rrc\n", rc); return rc; }
/** Thread function for tst4. */ static DECLCALLBACK(int) tst4Thread(RTTHREAD hSelf, void *pvArg) { // uint32_t iThread = (uint32_t)(uintptr_t)pvArg; RTMEMPOOL hMemPool = g_hMemPool4; /* setup. */ RTTestSetDefault(g_hTest, NULL); /* wait for the kick-off */ RTThreadUserWait(hSelf, RT_INDEFINITE_WAIT); /* do the work. */ for (uint32_t i = 0; i < 1024; i++) { void *apvHistory[256]; RT_ZERO(apvHistory); uint32_t j; for (j = 0; j < RT_ELEMENTS(apvHistory) - (i % 200); j++) RTTESTI_CHECK_RET(apvHistory[j] = RTMemPoolAlloc(hMemPool, (i & 15) + (j & 63)), VERR_NO_MEMORY); for (uint32_t k = i & 7; k < j; k += 3) { RTTESTI_CHECK_RET(RTMemPoolRelease(hMemPool, apvHistory[k]) == 0, VERR_INTERNAL_ERROR); apvHistory[k] = NULL; } while (j-- > 0) RTTESTI_CHECK_RET(RTMemPoolRelease(hMemPool, apvHistory[j]) == 0, VERR_INTERNAL_ERROR); } return VINF_SUCCESS; }
DECLCALLBACK(int) VBoxCredPoller::threadPoller(RTTHREAD ThreadSelf, void *pvUser) { Log(("VBoxCredPoller::threadPoller\n")); VBoxCredPoller *pThis = (VBoxCredPoller *)pvUser; do { int rc; rc = VbglR3CredentialsQueryAvailability(); if (RT_FAILURE(rc)) { if (rc != VERR_NOT_FOUND) Log(("VBoxCredPoller::threadPoller: Could not retrieve credentials! rc = %Rc\n", rc)); } else { Log(("VBoxCredPoller::threadPoller: Credentials available.\n")); Assert(pThis); rc = pThis->credentialsRetrieve(); } /* Wait a bit. */ if (RTThreadUserWait(ThreadSelf, 500) == VINF_SUCCESS) { Log(("VBoxCredPoller::threadPoller: Terminating\n")); /* We were asked to terminate, do that instantly! */ return 0; } } while (1); return 0; }
VBoxCredProvPoller::threadPoller(RTTHREAD hThreadSelf, void *pvUser) { VBoxCredProvVerbose(0, "VBoxCredProvPoller: Starting, pvUser=0x%p\n", pvUser); VBoxCredProvPoller *pThis = (VBoxCredProvPoller*)pvUser; AssertPtr(pThis); for (;;) { int rc; rc = VbglR3CredentialsQueryAvailability(); if (RT_FAILURE(rc)) { if (rc != VERR_NOT_FOUND) VBoxCredProvVerbose(0, "VBoxCredProvPoller: Could not retrieve credentials! rc=%Rc\n", rc); } else { VBoxCredProvVerbose(0, "VBoxCredProvPoller: Credentials available, notifying provider\n"); if (pThis->m_pProv) pThis->m_pProv->OnCredentialsProvided(); } /* Wait a bit. */ if (RTThreadUserWait(hThreadSelf, 500) == VINF_SUCCESS) { VBoxCredProvVerbose(0, "VBoxCredProvPoller: Terminating\n"); break; } } return VINF_SUCCESS; }
/** @note To be called only from #close() */ void Session::releaseIPCSemaphore() { /* release the IPC semaphore */ #if defined(RT_OS_WINDOWS) if (mIPCSem && mIPCThreadSem) { /* * tell the thread holding the IPC mutex to release it; * it will close mIPCSem handle */ ::SetEvent (mIPCSem); /* wait for the thread to finish */ ::WaitForSingleObject (mIPCThreadSem, INFINITE); ::CloseHandle (mIPCThreadSem); mIPCThreadSem = NULL; mIPCSem = NULL; } #elif defined(RT_OS_OS2) if (mIPCThread != NIL_RTTHREAD) { Assert (mIPCThreadSem != NIL_RTSEMEVENT); /* tell the thread holding the IPC mutex to release it */ int vrc = RTSemEventSignal (mIPCThreadSem); AssertRC(vrc == NO_ERROR); /* wait for the thread to finish */ vrc = RTThreadUserWait (mIPCThread, RT_INDEFINITE_WAIT); Assert (RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED); mIPCThread = NIL_RTTHREAD; } if (mIPCThreadSem != NIL_RTSEMEVENT) { RTSemEventDestroy (mIPCThreadSem); mIPCThreadSem = NIL_RTSEMEVENT; } #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) if (mIPCSem >= 0) { ::sembuf sop = { 0, 1, SEM_UNDO }; ::semop (mIPCSem, &sop, 1); mIPCSem = -1; } #else # error "Port me!" #endif }
/** * Suspends the thread. * * This can be called at the power off / suspend notifications to suspend the * PDM thread a bit early. The thread will be automatically suspend upon * completion of the device/driver notification cycle. * * The caller is responsible for serializing the control operations on the * thread. That basically means, always do these calls from the EMT. * * @returns VBox status code. * @param pThread The PDM thread. */ VMMR3DECL(int) PDMR3ThreadSuspend(PPDMTHREAD pThread) { /* * Assert sanity. */ AssertPtrReturn(pThread, VERR_INVALID_POINTER); AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC); Assert(pThread->Thread != RTThreadSelf()); /* * This is a noop if the thread is already suspended. */ if (pThread->enmState == PDMTHREADSTATE_SUSPENDED) return VINF_SUCCESS; /* * Change the state to resuming and kick the thread. */ int rc = RTSemEventMultiReset(pThread->Internal.s.BlockEvent); if (RT_SUCCESS(rc)) { rc = RTThreadUserReset(pThread->Thread); if (RT_SUCCESS(rc)) { rc = VERR_WRONG_ORDER; if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_SUSPENDING, PDMTHREADSTATE_RUNNING)) { rc = pdmR3ThreadWakeUp(pThread); if (RT_SUCCESS(rc)) { /* * Wait for the thread to reach the suspended state. */ if (pThread->enmState != PDMTHREADSTATE_SUSPENDED) rc = RTThreadUserWait(pThread->Thread, 60*1000); if ( RT_SUCCESS(rc) && pThread->enmState != PDMTHREADSTATE_SUSPENDED) rc = VERR_PDM_THREAD_IPE_2; if (RT_SUCCESS(rc)) return rc; } } } } /* * Something failed, initialize termination. */ AssertMsgFailed(("PDMR3ThreadSuspend -> rc=%Rrc enmState=%d suspending '%s'\n", rc, pThread->enmState, RTThreadGetName(pThread->Thread))); pdmR3ThreadBailOut(pThread); return rc; }
/** * Resumes the thread. * * This can be called the power on / resume notifications to resume the * PDM thread a bit early. The thread will be automatically resumed upon * return from these two notification callbacks (devices/drivers). * * The caller is responsible for serializing the control operations on the * thread. That basically means, always do these calls from the EMT. * * @returns VBox status code. * @param pThread The PDM thread. */ VMMR3DECL(int) PDMR3ThreadResume(PPDMTHREAD pThread) { /* * Assert sanity. */ AssertPtrReturn(pThread, VERR_INVALID_POINTER); AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC); Assert(pThread->Thread != RTThreadSelf()); /* * Change the state to resuming and kick the thread. */ int rc = RTThreadUserReset(pThread->Thread); if (RT_SUCCESS(rc)) { rc = VERR_WRONG_ORDER; if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_RESUMING, PDMTHREADSTATE_SUSPENDED)) { rc = RTSemEventMultiSignal(pThread->Internal.s.BlockEvent); if (RT_SUCCESS(rc)) { /* * Wait for the thread to reach the running state. */ rc = RTThreadUserWait(pThread->Thread, 60*1000); if ( RT_SUCCESS(rc) && pThread->enmState != PDMTHREADSTATE_RUNNING) rc = VERR_PDM_THREAD_IPE_2; if (RT_SUCCESS(rc)) return rc; } } } /* * Something failed, initialize termination. */ AssertMsgFailed(("PDMR3ThreadResume -> rc=%Rrc enmState=%d\n", rc, pThread->enmState)); pdmR3ThreadBailOut(pThread); return rc; }
/** * The poller thread. * * This thread will check for the arrival of new data on the clipboard. * * @returns VINF_SUCCESS (not used). * @param ThreadSelf Our thread handle. * @param pvUser Pointer to the VBOXCLIPBOARDCONTEXT structure. * */ static int vboxClipboardThread(RTTHREAD ThreadSelf, void *pvUser) { Log(("vboxClipboardThread: starting clipboard thread\n")); AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER); VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *)pvUser; while (!pCtx->fTerminate) { /* call this behind the lock because we don't know if the api is thread safe and in any case we're calling several methods. */ VBoxSvcClipboardLock(); vboxClipboardChanged(pCtx); VBoxSvcClipboardUnlock(); /* Sleep for 200 msecs before next poll */ RTThreadUserWait(ThreadSelf, 200); } Log(("vboxClipboardThread: clipboard thread terminated successfully with return code %Rrc\n", VINF_SUCCESS)); return VINF_SUCCESS; }
/** * Poller thread. Checks periodically whether there are credentials. */ static DECLCALLBACK(int) credentialsPoller(RTTHREAD ThreadSelf, void *pvUser) { RT_NOREF(pvUser); VBoxGINAVerbose(0, "VBoxGINA::credentialsPoller\n"); do { int rc = VbglR3CredentialsQueryAvailability(); if (RT_SUCCESS(rc)) { VBoxGINAVerbose(0, "VBoxGINA::credentialsPoller: got credentials, simulating C-A-D\n"); /* tell WinLogon to start the attestation process */ pWlxFuncs->WlxSasNotify(hGinaWlx, WLX_SAS_TYPE_CTRL_ALT_DEL); /* time to say goodbye */ return 0; } if ( RT_FAILURE(rc) && rc != VERR_NOT_FOUND) { static int s_cBitchedQueryAvail = 0; if (s_cBitchedQueryAvail++ < 5) VBoxGINAVerbose(0, "VBoxGINA::credentialsPoller: querying for credentials failed with rc=%Rrc\n", rc); } /* wait a bit */ if (RTThreadUserWait(ThreadSelf, 500) == VINF_SUCCESS) { VBoxGINAVerbose(0, "VBoxGINA::credentialsPoller: we were asked to terminate\n"); /* we were asked to terminate, do that instantly! */ return 0; } } while (1); return 0; }
/** * Starts the service. * * @returns VBox status code, errors are fully bitched. */ int VBoxServiceStartServices(void) { int rc; VBoxServiceReportStatus(VBoxGuestFacilityStatus_Init); /* * Initialize the services. */ VBoxServiceVerbose(2, "Initializing services ...\n"); for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) if (g_aServices[j].fEnabled) { rc = g_aServices[j].pDesc->pfnInit(); if (RT_FAILURE(rc)) { if (rc != VERR_SERVICE_DISABLED) { VBoxServiceError("Service '%s' failed to initialize: %Rrc\n", g_aServices[j].pDesc->pszName, rc); VBoxServiceReportStatus(VBoxGuestFacilityStatus_Failed); return rc; } g_aServices[j].fEnabled = false; VBoxServiceVerbose(0, "Service '%s' was disabled because of missing functionality\n", g_aServices[j].pDesc->pszName); } } /* * Start the service(s). */ VBoxServiceVerbose(2, "Starting services ...\n"); rc = VINF_SUCCESS; for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) { if (!g_aServices[j].fEnabled) continue; VBoxServiceVerbose(2, "Starting service '%s' ...\n", g_aServices[j].pDesc->pszName); rc = RTThreadCreate(&g_aServices[j].Thread, vboxServiceThread, (void *)(uintptr_t)j, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, g_aServices[j].pDesc->pszName); if (RT_FAILURE(rc)) { VBoxServiceError("RTThreadCreate failed, rc=%Rrc\n", rc); break; } g_aServices[j].fStarted = true; /* Wait for the thread to initialize. */ /** @todo There is a race between waiting and checking * the fShutdown flag of a thread here and processing * the thread's actual worker loop. If the thread decides * to exit the loop before we skipped the fShutdown check * below the service will fail to start! */ RTThreadUserWait(g_aServices[j].Thread, 60 * 1000); if (g_aServices[j].fShutdown) { VBoxServiceError("Service '%s' failed to start!\n", g_aServices[j].pDesc->pszName); rc = VERR_GENERAL_FAILURE; } } if (RT_SUCCESS(rc)) VBoxServiceVerbose(1, "All services started.\n"); else { VBoxServiceError("An error occcurred while the services!\n"); VBoxServiceReportStatus(VBoxGuestFacilityStatus_Failed); } return rc; }
/** * Do one-time initializations for the faker. * Returns TRUE on success, FALSE otherwise. */ static bool stubInitLocked(void) { /* Here is where we contact the mothership to find out what we're supposed * to be doing. Networking code in a DLL initializer. I sure hope this * works :) * * HOW can I pass the mothership address to this if I already know it? */ CRConnection *conn = NULL; char response[1024]; char **spuchain; int num_spus; int *spu_ids; char **spu_names; const char *app_id; int i; int disable_sync = 0; stubInitVars(); crGetProcName(response, 1024); crDebug("Stub launched for %s", response); #if defined(CR_NEWWINTRACK) && !defined(WINDOWS) /*@todo when vm boots with compiz turned on, new code causes hang in xcb_wait_for_reply in the sync thread * as at the start compiz runs our code under XGrabServer. */ if (!crStrcmp(response, "compiz") || !crStrcmp(response, "compiz_real") || !crStrcmp(response, "compiz.real") || !crStrcmp(response, "compiz-bin")) { disable_sync = 1; } #elif defined(WINDOWS) && defined(VBOX_WITH_WDDM) && defined(VBOX_WDDM_MINIPORT_WITH_VISIBLE_RECTS) if (GetModuleHandle(VBOX_MODNAME_DISPD3D)) { disable_sync = 1; crDebug("running with " VBOX_MODNAME_DISPD3D); stub.trackWindowVisibleRgn = 0; stub.bRunningUnderWDDM = true; } #endif /* @todo check if it'd be of any use on other than guests, no use for windows */ app_id = crGetenv( "CR_APPLICATION_ID_NUMBER" ); crNetInit( NULL, NULL ); #ifndef WINDOWS { CRNetServer ns; ns.name = "vboxhgcm://host:0"; ns.buffer_size = 1024; crNetServerConnect(&ns #if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST) , NULL #endif ); if (!ns.conn) { crWarning("Failed to connect to host. Make sure 3D acceleration is enabled for this VM."); return false; } else { crNetFreeConnection(ns.conn); } #if 0 && defined(CR_NEWWINTRACK) { Status st = XInitThreads(); if (st==0) { crWarning("XInitThreads returned %i", (int)st); } } #endif } #endif strcpy(response, "2 0 feedback 1 pack"); spuchain = crStrSplit( response, " " ); num_spus = crStrToInt( spuchain[0] ); spu_ids = (int *) crAlloc( num_spus * sizeof( *spu_ids ) ); spu_names = (char **) crAlloc( num_spus * sizeof( *spu_names ) ); for (i = 0 ; i < num_spus ; i++) { spu_ids[i] = crStrToInt( spuchain[2*i+1] ); spu_names[i] = crStrdup( spuchain[2*i+2] ); crDebug( "SPU %d/%d: (%d) \"%s\"", i+1, num_spus, spu_ids[i], spu_names[i] ); } stubSetDefaultConfigurationOptions(); stub.spu = crSPULoadChain( num_spus, spu_ids, spu_names, stub.spu_dir, NULL ); crFree( spuchain ); crFree( spu_ids ); for (i = 0; i < num_spus; ++i) crFree(spu_names[i]); crFree( spu_names ); // spu chain load failed somewhere if (!stub.spu) { return false; } crSPUInitDispatchTable( &glim ); /* This is unlikely to change -- We still want to initialize our dispatch * table with the functions of the first SPU in the chain. */ stubInitSPUDispatch( stub.spu ); /* we need to plug one special stub function into the dispatch table */ glim.GetChromiumParametervCR = stub_GetChromiumParametervCR; #if !defined(VBOX_NO_NATIVEGL) /* Load pointers to native OpenGL functions into stub.nativeDispatch */ stubInitNativeDispatch(); #endif /*crDebug("stub init"); raise(SIGINT);*/ #ifdef WINDOWS # ifndef CR_NEWWINTRACK stubInstallWindowMessageHook(); # endif #endif #ifdef CR_NEWWINTRACK { int rc; RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); if (!disable_sync) { crDebug("Starting sync thread"); rc = RTThreadCreate(&stub.hSyncThread, stubSyncThreadProc, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "Sync"); if (RT_FAILURE(rc)) { crError("Failed to start sync thread! (%x)", rc); } RTThreadUserWait(stub.hSyncThread, 60 * 1000); RTThreadUserReset(stub.hSyncThread); crDebug("Going on"); } } #endif #ifdef GLX stub.xshmSI.shmid = -1; stub.bShmInitFailed = GL_FALSE; stub.pGLXPixmapsHash = crAllocHashtable(); stub.bXExtensionsChecked = GL_FALSE; stub.bHaveXComposite = GL_FALSE; stub.bHaveXFixes = GL_FALSE; #endif return true; }
/** @note To be called only from #AssignMachine() */ HRESULT Session::grabIPCSemaphore() { HRESULT rc = E_FAIL; /* open the IPC semaphore based on the sessionId and try to grab it */ Bstr ipcId; rc = mControl->GetIPCId(ipcId.asOutParam()); AssertComRCReturnRC(rc); LogFlowThisFunc(("ipcId='%ls'\n", ipcId.raw())); #if defined(RT_OS_WINDOWS) /* * Since Session is an MTA object, this method can be executed on * any thread, and this thread will not necessarily match the thread on * which close() will be called later. Therefore, we need a separate * thread to hold the IPC mutex and then release it in close(). */ mIPCThreadSem = ::CreateEvent(NULL, FALSE, FALSE, NULL); AssertMsgReturn(mIPCThreadSem, ("Cannot create an event sem, err=%d", ::GetLastError()), E_FAIL); void *data[3]; data[0] = (void*)(BSTR)ipcId.raw(); data[1] = (void*)mIPCThreadSem; data[2] = 0; /* will get an output from the thread */ /* create a thread to hold the IPC mutex until signalled to release it */ RTTHREAD tid; int vrc = RTThreadCreate(&tid, IPCMutexHolderThread, (void*)data, 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder"); AssertRCReturn(vrc, E_FAIL); /* wait until thread init is completed */ DWORD wrc = ::WaitForSingleObject(mIPCThreadSem, INFINITE); AssertMsg(wrc == WAIT_OBJECT_0, ("Wait failed, err=%d\n", ::GetLastError())); Assert(data[2]); if (wrc == WAIT_OBJECT_0 && data[2]) { /* memorize the event sem we should signal in close() */ mIPCSem = (HANDLE)data[2]; rc = S_OK; } else { ::CloseHandle(mIPCThreadSem); mIPCThreadSem = NULL; rc = E_FAIL; } #elif defined(RT_OS_OS2) /* We use XPCOM where any message (including close()) can arrive on any * worker thread (which will not necessarily match this thread that opens * the mutex). Therefore, we need a separate thread to hold the IPC mutex * and then release it in close(). */ int vrc = RTSemEventCreate(&mIPCThreadSem); AssertRCReturn(vrc, E_FAIL); void *data[3]; data[0] = (void*)ipcId.raw(); data[1] = (void*)mIPCThreadSem; data[2] = (void*)false; /* will get the thread result here */ /* create a thread to hold the IPC mutex until signalled to release it */ vrc = RTThreadCreate(&mIPCThread, IPCMutexHolderThread, (void *) data, 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder"); AssertRCReturn(vrc, E_FAIL); /* wait until thread init is completed */ vrc = RTThreadUserWait (mIPCThread, RT_INDEFINITE_WAIT); AssertReturn(RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED, E_FAIL); /* the thread must succeed */ AssertReturn((bool)data[2], E_FAIL); #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER) # ifdef VBOX_WITH_NEW_SYS_V_KEYGEN Utf8Str ipcKey = ipcId; key_t key = RTStrToUInt32(ipcKey.c_str()); AssertMsgReturn (key != 0, ("Key value of 0 is not valid for IPC semaphore"), E_FAIL); # else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ Utf8Str semName = ipcId; char *pszSemName = NULL; RTStrUtf8ToCurrentCP (&pszSemName, semName); key_t key = ::ftok (pszSemName, 'V'); RTStrFree (pszSemName); # endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ mIPCSem = ::semget (key, 0, 0); AssertMsgReturn (mIPCSem >= 0, ("Cannot open IPC semaphore, errno=%d", errno), E_FAIL); /* grab the semaphore */ ::sembuf sop = { 0, -1, SEM_UNDO }; int rv = ::semop (mIPCSem, &sop, 1); AssertMsgReturn (rv == 0, ("Cannot grab IPC semaphore, errno=%d", errno), E_FAIL); #else # error "Port me!" #endif return rc; }
RTDECL(int) RTTimerCreate(PRTTIMER *ppTimer, unsigned uMilliesInterval, PFNRTTIMER pfnTimer, void *pvUser) { #ifndef USE_WINMM /* * On windows we'll have to set the timer resolution before * we start the timer. */ ULONG ulMax = UINT32_MAX; ULONG ulMin = UINT32_MAX; ULONG ulCur = UINT32_MAX; NtQueryTimerResolution(&ulMax, &ulMin, &ulCur); Log(("NtQueryTimerResolution -> ulMax=%lu00ns ulMin=%lu00ns ulCur=%lu00ns\n", ulMax, ulMin, ulCur)); if (ulCur > ulMin && ulCur > 10000 /* = 1ms */) { if (NtSetTimerResolution(10000, TRUE, &ulCur) >= 0) Log(("Changed timer resolution to 1ms.\n")); else if (NtSetTimerResolution(20000, TRUE, &ulCur) >= 0) Log(("Changed timer resolution to 2ms.\n")); else if (NtSetTimerResolution(40000, TRUE, &ulCur) >= 0) Log(("Changed timer resolution to 4ms.\n")); else if (ulMin <= 50000 && NtSetTimerResolution(ulMin, TRUE, &ulCur) >= 0) Log(("Changed timer resolution to %lu *100ns.\n", ulMin)); else { AssertMsgFailed(("Failed to configure timer resolution!\n")); return VERR_INTERNAL_ERROR; } } #endif /* !USE_WINN */ /* * Create new timer. */ int rc = VERR_IPE_UNINITIALIZED_STATUS; PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer)); if (pTimer) { pTimer->u32Magic = RTTIMER_MAGIC; pTimer->pvUser = pvUser; pTimer->pfnTimer = pfnTimer; pTimer->iTick = 0; pTimer->uMilliesInterval = uMilliesInterval; #ifdef USE_WINMM /* sync kill doesn't work. */ pTimer->TimerId = timeSetEvent(uMilliesInterval, 0, rttimerCallback, (DWORD_PTR)pTimer, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); if (pTimer->TimerId) { ULONG ulMax = UINT32_MAX; ULONG ulMin = UINT32_MAX; ULONG ulCur = UINT32_MAX; NtQueryTimerResolution(&ulMax, &ulMin, &ulCur); Log(("NtQueryTimerResolution -> ulMax=%lu00ns ulMin=%lu00ns ulCur=%lu00ns\n", ulMax, ulMin, ulCur)); *ppTimer = pTimer; return VINF_SUCCESS; } rc = VERR_INVALID_PARAMETER; #else /* !USE_WINMM */ /* * Create Win32 event semaphore. */ pTimer->iError = 0; pTimer->hTimer = CreateWaitableTimer(NULL, TRUE, NULL); if (pTimer->hTimer) { #ifdef USE_APC /* * Create wait semaphore. */ pTimer->hevWait = CreateEvent(NULL, FALSE, FALSE, NULL); if (pTimer->hevWait) #endif { /* * Kick off the timer thread. */ rc = RTThreadCreate(&pTimer->Thread, rttimerCallback, pTimer, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "Timer"); if (RT_SUCCESS(rc)) { /* * Wait for the timer to successfully create the timer * If we don't get a response in 10 secs, then we assume we're screwed. */ rc = RTThreadUserWait(pTimer->Thread, 10000); if (RT_SUCCESS(rc)) { rc = pTimer->iError; if (RT_SUCCESS(rc)) { *ppTimer = pTimer; return VINF_SUCCESS; } } ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1); RTThreadWait(pTimer->Thread, 250, NULL); CancelWaitableTimer(pTimer->hTimer); } #ifdef USE_APC CloseHandle(pTimer->hevWait); #endif } CloseHandle(pTimer->hTimer); } #endif /* !USE_WINMM */ AssertMsgFailed(("Failed to create timer uMilliesInterval=%d. rc=%d\n", uMilliesInterval, rc)); RTMemFree(pTimer); } else rc = VERR_NO_MEMORY; return rc; }
int main(int argc, char **argv) { bool fSys = true; bool fGip = false; #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) fGip = true; #endif /* * Init. */ int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB); if (RT_FAILURE(rc)) return RTMsgInitFailure(rc); if (argc == 2 && !strcmp(argv[1], "child")) { RTThreadSleep(300); return 0; } RTTEST hTest; rc = RTTestCreate("tstSupSem", &hTest); if (RT_FAILURE(rc)) { RTPrintf("tstSupSem: fatal error: RTTestCreate failed with rc=%Rrc\n", rc); return 1; } g_hTest = hTest; PSUPDRVSESSION pSession; rc = SUPR3Init(&pSession); if (RT_FAILURE(rc)) { RTTestFailed(hTest, "SUPR3Init failed with rc=%Rrc\n", rc); return RTTestSummaryAndDestroy(hTest); } g_pSession = pSession; RTTestBanner(hTest); /* * Basic API checks. */ RTTestSub(hTest, "Single Release Event (SRE) API"); SUPSEMEVENT hEvent = NIL_SUPSEMEVENT; RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 0), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 1), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 2), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 8), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent,20), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 0), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 1), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 2), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 8), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 20), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent,1000),VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 0), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 0), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 1), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 2), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 8), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent,20), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VERR_INVALID_HANDLE); RTTESTI_CHECK_RC(SUPSemEventClose(pSession, NIL_SUPSEMEVENT), VINF_SUCCESS); RTTestSub(hTest, "Multiple Release Event (MRE) API"); SUPSEMEVENTMULTI hEventMulti = NIL_SUPSEMEVENT; RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEventMulti), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 1), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 2), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 8), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,20), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEventMulti), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 1), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 2), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 8), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,20), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,1000), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEventMulti), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEventMulti), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiReset(pSession, hEventMulti), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 1), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 2), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 8), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,20), VERR_TIMEOUT); RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEventMulti), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 1), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 2), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 8), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 20), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,1000), VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEventMulti), VINF_OBJECT_DESTROYED); RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEventMulti), VERR_INVALID_HANDLE); RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, NIL_SUPSEMEVENTMULTI), VINF_SUCCESS); #if !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS) RTTestSub(hTest, "SRE Interruptibility"); RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); g_cMillies = RT_INDEFINITE_WAIT; RTTHREAD hThread = NIL_RTTHREAD; RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleSRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS); RTTESTI_CHECK_RC(RTThreadUserWait(hThread, 60*1000), VINF_SUCCESS); RTThreadSleep(120); RTThreadPoke(hThread); int rcThread = VINF_SUCCESS; RTTESTI_CHECK_RC(RTThreadWait(hThread, 60*1000, &rcThread), VINF_SUCCESS); RTTESTI_CHECK_RC(rcThread, VERR_INTERRUPTED); RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); g_cMillies = 120*1000; hThread = NIL_RTTHREAD; RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleSRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS); RTTESTI_CHECK_RC(RTThreadUserWait(hThread, 60*1000), VINF_SUCCESS); RTThreadSleep(120); RTThreadPoke(hThread); rcThread = VINF_SUCCESS; RTTESTI_CHECK_RC(RTThreadWait(hThread, 60*1000, &rcThread), VINF_SUCCESS); RTTESTI_CHECK_RC(rcThread, VERR_INTERRUPTED); RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); RTTestSub(hTest, "MRE Interruptibility"); RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEventMulti), VINF_SUCCESS); g_cMillies = RT_INDEFINITE_WAIT; hThread = NIL_RTTHREAD; RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleMRE, (void *)hEventMulti, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntMRE"), VINF_SUCCESS); RTTESTI_CHECK_RC(RTThreadUserWait(hThread, 60*1000), VINF_SUCCESS); RTThreadSleep(120); RTThreadPoke(hThread); rcThread = VINF_SUCCESS; RTTESTI_CHECK_RC(RTThreadWait(hThread, 60*1000, &rcThread), VINF_SUCCESS); RTTESTI_CHECK_RC(rcThread, VERR_INTERRUPTED); RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEventMulti), VINF_OBJECT_DESTROYED); RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEventMulti), VINF_SUCCESS); g_cMillies = 120*1000; hThread = NIL_RTTHREAD; RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleMRE, (void *)hEventMulti, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntMRE"), VINF_SUCCESS); RTTESTI_CHECK_RC(RTThreadUserWait(hThread, 60*1000), VINF_SUCCESS); RTThreadSleep(120); RTThreadPoke(hThread); rcThread = VINF_SUCCESS; RTTESTI_CHECK_RC(RTThreadWait(hThread, 60*1000, &rcThread), VINF_SUCCESS); RTTESTI_CHECK_RC(rcThread, VERR_INTERRUPTED); RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEventMulti), VINF_OBJECT_DESTROYED); /* * Fork test. * Spawn a thread waiting for an event, then spawn a new child process (of * ourselves) and make sure that this does not alter the intended behaviour * of our event semaphore implementation (see @bugref{5090}). */ RTTestSub(hTest, "SRE Process Spawn"); hThread = NIL_RTTHREAD; g_cMillies = 120*1000; RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleSRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS); const char *apszArgs[3] = { argv[0], "child", NULL }; RTPROCESS Process = NIL_RTPROCESS; RTThreadSleep(250); RTTESTI_CHECK_RC(RTProcCreate(apszArgs[0], apszArgs, RTENV_DEFAULT, 0, &Process), VINF_SUCCESS); RTThreadSleep(250); RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); rcThread = VERR_GENERAL_FAILURE; RTTESTI_CHECK_RC(RTThreadWait(hThread, 120*1000, &rcThread), VINF_SUCCESS); RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); RTTestSub(hTest, "MRE Process Spawn"); hThread = NIL_RTTHREAD; g_cMillies = 120*1000; RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEvent), VINF_SUCCESS); RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleMRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS); RTTHREAD hThread2 = NIL_RTTHREAD; RTTESTI_CHECK_RC(RTThreadCreate(&hThread2, tstSupSemInterruptibleMRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS); Process = NIL_RTPROCESS; RTThreadSleep(250); RTTESTI_CHECK_RC(RTProcCreate(apszArgs[0], apszArgs, RTENV_DEFAULT, 0, &Process), VINF_SUCCESS); RTThreadSleep(250); RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEvent), VINF_SUCCESS); rcThread = VERR_GENERAL_FAILURE; RTTESTI_CHECK_RC(RTThreadWait(hThread, 120*1000, &rcThread), VINF_SUCCESS); RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS); int rcThread2 = VERR_GENERAL_FAILURE; RTTESTI_CHECK_RC(RTThreadWait(hThread2, 120*1000, &rcThread2), VINF_SUCCESS); RTTESTI_CHECK_RC(rcThread2, VINF_SUCCESS); RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEvent), VINF_OBJECT_DESTROYED); #endif /* !OS2 && !WINDOWS */ { #define LOOP_COUNT 20 static unsigned const s_acMsIntervals[] = { 0, 1, 2, 3, 4, 8, 10, 16, 32 }; if (RTTestErrorCount(hTest) == 0) { RTTestSub(hTest, "SRE Timeout Accuracy (ms)"); RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); uint32_t cInterrupted = 0; for (unsigned i = 0; i < RT_ELEMENTS(s_acMsIntervals); i++) { uint64_t cMs = s_acMsIntervals[i]; uint64_t cNsMinSys = UINT64_MAX; uint64_t cNsMin = UINT64_MAX; uint64_t cNsTotalSys= 0; uint64_t cNsTotal = 0; unsigned cLoops = 0; while (cLoops < LOOP_COUNT) { uint64_t u64StartSys = RTTimeSystemNanoTS(); uint64_t u64Start = RTTimeNanoTS(); int rcX = SUPSemEventWaitNoResume(pSession, hEvent, cMs); uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys; uint64_t cNsElapsed = RTTimeNanoTS() - u64Start; if (rcX == VERR_INTERRUPTED) { cInterrupted++; continue; /* retry */ } if (rcX != VERR_TIMEOUT) RTTestFailed(hTest, "%Rrc cLoops=%u cMs=%u", rcX, cLoops, cMs); if (cNsElapsedSys < cNsMinSys) cNsMinSys = cNsElapsedSys; if (cNsElapsed < cNsMin) cNsMin = cNsElapsed; cNsTotalSys += cNsElapsedSys; cNsTotal += cNsElapsed; cLoops++; } if (fSys) { RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS, "%u ms min (clock=sys)", cMs); RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%u ms avg (clock=sys)", cMs); } if (fGip) { RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS, "%u ms min (clock=gip)", cMs); RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS, "%u ms avg (clock=gip)", cMs); } } RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned"); } if (RTTestErrorCount(hTest) == 0) { RTTestSub(hTest, "MRE Timeout Accuracy (ms)"); RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEvent), VINF_SUCCESS); uint32_t cInterrupted = 0; for (unsigned i = 0; i < RT_ELEMENTS(s_acMsIntervals); i++) { uint64_t cMs = s_acMsIntervals[i]; uint64_t cNsMinSys = UINT64_MAX; uint64_t cNsMin = UINT64_MAX; uint64_t cNsTotalSys= 0; uint64_t cNsTotal = 0; unsigned cLoops = 0; while (cLoops < LOOP_COUNT) { uint64_t u64StartSys = RTTimeSystemNanoTS(); uint64_t u64Start = RTTimeNanoTS(); int rcX = SUPSemEventMultiWaitNoResume(pSession, hEvent, cMs); uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys; uint64_t cNsElapsed = RTTimeNanoTS() - u64Start; if (rcX == VERR_INTERRUPTED) { cInterrupted++; continue; /* retry */ } if (rcX != VERR_TIMEOUT) RTTestFailed(hTest, "%Rrc cLoops=%u cMs=%u", rcX, cLoops, cMs); if (cNsElapsedSys < cNsMinSys) cNsMinSys = cNsElapsedSys; if (cNsElapsed < cNsMin) cNsMin = cNsElapsed; cNsTotalSys += cNsElapsedSys; cNsTotal += cNsElapsed; cLoops++; } if (fSys) { RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS, "%u ms min (clock=sys)", cMs); RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%u ms avg (clock=sys)", cMs); } if (fGip) { RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS, "%u ms min (clock=gip)", cMs); RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS, "%u ms avg (clock=gip)", cMs); } } RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEvent), VINF_OBJECT_DESTROYED); RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned"); } } { static uint32_t const s_acNsIntervals[] = { 0, 1000, 5000, 15000, 30000, 50000, 100000, 250000, 500000, 750000, 900000, 1500000, 2200000 }; if (RTTestErrorCount(hTest) == 0) { RTTestSub(hTest, "SUPSemEventWaitNsRelIntr Accuracy"); RTTestValueF(hTest, SUPSemEventGetResolution(pSession), RTTESTUNIT_NS, "SRE resolution"); RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); uint32_t cInterrupted = 0; for (unsigned i = 0; i < RT_ELEMENTS(s_acNsIntervals); i++) { uint64_t cNs = s_acNsIntervals[i]; uint64_t cNsMinSys = UINT64_MAX; uint64_t cNsMin = UINT64_MAX; uint64_t cNsTotalSys= 0; uint64_t cNsTotal = 0; unsigned cLoops = 0; while (cLoops < LOOP_COUNT) { uint64_t u64StartSys = RTTimeSystemNanoTS(); uint64_t u64Start = RTTimeNanoTS(); int rcX = SUPSemEventWaitNsRelIntr(pSession, hEvent, cNs); uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys; uint64_t cNsElapsed = RTTimeNanoTS() - u64Start; if (rcX == VERR_INTERRUPTED) { cInterrupted++; continue; /* retry */ } if (rcX != VERR_TIMEOUT) RTTestFailed(hTest, "%Rrc cLoops=%u cNs=%u", rcX, cLoops, cNs); if (cNsElapsedSys < cNsMinSys) cNsMinSys = cNsElapsedSys; if (cNsElapsed < cNsMin) cNsMin = cNsElapsed; cNsTotalSys += cNsElapsedSys; cNsTotal += cNsElapsed; cLoops++; } if (fSys) { RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS, "%'u ns min (clock=sys)", cNs); RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=sys)", cNs); } if (fGip) { RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS, "%'u ns min (clock=gip)", cNs); RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=gip)", cNs); } } RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned"); } if (RTTestErrorCount(hTest) == 0) { RTTestSub(hTest, "SUPSemEventMultiWaitNsRelIntr Accuracy"); RTTestValueF(hTest, SUPSemEventMultiGetResolution(pSession), RTTESTUNIT_NS, "MRE resolution"); RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEvent), VINF_SUCCESS); uint32_t cInterrupted = 0; for (unsigned i = 0; i < RT_ELEMENTS(s_acNsIntervals); i++) { uint64_t cNs = s_acNsIntervals[i]; uint64_t cNsMinSys = UINT64_MAX; uint64_t cNsMin = UINT64_MAX; uint64_t cNsTotalSys= 0; uint64_t cNsTotal = 0; unsigned cLoops = 0; while (cLoops < LOOP_COUNT) { uint64_t u64StartSys = RTTimeSystemNanoTS(); uint64_t u64Start = RTTimeNanoTS(); int rcX = SUPSemEventMultiWaitNsRelIntr(pSession, hEvent, cNs); uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys; uint64_t cNsElapsed = RTTimeNanoTS() - u64Start; if (rcX == VERR_INTERRUPTED) { cInterrupted++; continue; /* retry */ } if (rcX != VERR_TIMEOUT) RTTestFailed(hTest, "%Rrc cLoops=%u cNs=%u", rcX, cLoops, cNs); if (cNsElapsedSys < cNsMinSys) cNsMinSys = cNsElapsedSys; if (cNsElapsed < cNsMin) cNsMin = cNsElapsed; cNsTotalSys += cNsElapsedSys; cNsTotal += cNsElapsed; cLoops++; } if (fSys) { RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS, "%'u ns min (clock=sys)", cNs); RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=sys)", cNs); } if (fGip) { RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS, "%'u ns min (clock=gip)", cNs); RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=gip)", cNs); } } RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEvent), VINF_OBJECT_DESTROYED); RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned"); } if (RTTestErrorCount(hTest) == 0) { RTTestSub(hTest, "SUPSemEventWaitNsAbsIntr Accuracy"); RTTestValueF(hTest, SUPSemEventGetResolution(pSession), RTTESTUNIT_NS, "MRE resolution"); RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); uint32_t cInterrupted = 0; for (unsigned i = 0; i < RT_ELEMENTS(s_acNsIntervals); i++) { uint64_t cNs = s_acNsIntervals[i]; uint64_t cNsMinSys = UINT64_MAX; uint64_t cNsMin = UINT64_MAX; uint64_t cNsTotalSys= 0; uint64_t cNsTotal = 0; unsigned cLoops = 0; while (cLoops < LOOP_COUNT) { uint64_t u64StartSys = RTTimeSystemNanoTS(); uint64_t u64Start = RTTimeNanoTS(); uint64_t uAbsDeadline = (fGip ? u64Start : u64StartSys) + cNs; int rcX = SUPSemEventWaitNsAbsIntr(pSession, hEvent, uAbsDeadline); uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys; uint64_t cNsElapsed = RTTimeNanoTS() - u64Start; if (rcX == VERR_INTERRUPTED) { cInterrupted++; continue; /* retry */ } if (rcX != VERR_TIMEOUT) RTTestFailed(hTest, "%Rrc cLoops=%u cNs=%u", rcX, cLoops, cNs); if (cNsElapsedSys < cNsMinSys) cNsMinSys = cNsElapsedSys; if (cNsElapsed < cNsMin) cNsMin = cNsElapsed; cNsTotalSys += cNsElapsedSys; cNsTotal += cNsElapsed; cLoops++; } if (fSys) { RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS, "%'u ns min (clock=sys)", cNs); RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=sys)", cNs); } if (fGip) { RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS, "%'u ns min (clock=gip)", cNs); RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=gip)", cNs); } } RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned"); } if (RTTestErrorCount(hTest) == 0) { RTTestSub(hTest, "SUPSemEventMultiWaitNsAbsIntr Accuracy"); RTTestValueF(hTest, SUPSemEventMultiGetResolution(pSession), RTTESTUNIT_NS, "MRE resolution"); RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEvent), VINF_SUCCESS); uint32_t cInterrupted = 0; for (unsigned i = 0; i < RT_ELEMENTS(s_acNsIntervals); i++) { uint64_t cNs = s_acNsIntervals[i]; uint64_t cNsMinSys = UINT64_MAX; uint64_t cNsMin = UINT64_MAX; uint64_t cNsTotalSys= 0; uint64_t cNsTotal = 0; unsigned cLoops = 0; while (cLoops < LOOP_COUNT) { uint64_t u64StartSys = RTTimeSystemNanoTS(); uint64_t u64Start = RTTimeNanoTS(); uint64_t uAbsDeadline = (fGip ? u64Start : u64StartSys) + cNs; int rcX = SUPSemEventMultiWaitNsAbsIntr(pSession, hEvent, uAbsDeadline); uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys; uint64_t cNsElapsed = RTTimeNanoTS() - u64Start; if (rcX == VERR_INTERRUPTED) { cInterrupted++; continue; /* retry */ } if (rcX != VERR_TIMEOUT) RTTestFailed(hTest, "%Rrc cLoops=%u cNs=%u", rcX, cLoops, cNs); if (cNsElapsedSys < cNsMinSys) cNsMinSys = cNsElapsedSys; if (cNsElapsed < cNsMin) cNsMin = cNsElapsed; cNsTotalSys += cNsElapsedSys; cNsTotal += cNsElapsed; cLoops++; } if (fSys) { RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS, "%'u ns min (clock=sys)", cNs); RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=sys)", cNs); } if (fGip) { RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS, "%'u ns min (clock=gip)", cNs); RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=gip)", cNs); } } RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEvent), VINF_OBJECT_DESTROYED); RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned"); } } /* * Done. */ return RTTestSummaryAndDestroy(hTest); }
/** * Starts the service. * * @returns VBox status code, errors are fully bitched. * * @remarks Also called from VBoxService-win.cpp, thus not static. */ int VGSvcStartServices(void) { int rc; VGSvcReportStatus(VBoxGuestFacilityStatus_Init); /* * Initialize the services. */ VGSvcVerbose(2, "Initializing services ...\n"); for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) if (g_aServices[j].fEnabled) { rc = g_aServices[j].pDesc->pfnInit(); if (RT_FAILURE(rc)) { if (rc != VERR_SERVICE_DISABLED) { VGSvcError("Service '%s' failed to initialize: %Rrc\n", g_aServices[j].pDesc->pszName, rc); VGSvcReportStatus(VBoxGuestFacilityStatus_Failed); return rc; } g_aServices[j].fEnabled = false; VGSvcVerbose(0, "Service '%s' was disabled because of missing functionality\n", g_aServices[j].pDesc->pszName); } } /* * Start the service(s). */ VGSvcVerbose(2, "Starting services ...\n"); rc = VINF_SUCCESS; for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) { if (!g_aServices[j].fEnabled) continue; VGSvcVerbose(2, "Starting service '%s' ...\n", g_aServices[j].pDesc->pszName); rc = RTThreadCreate(&g_aServices[j].Thread, vgsvcThread, (void *)(uintptr_t)j, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, g_aServices[j].pDesc->pszName); if (RT_FAILURE(rc)) { VGSvcError("RTThreadCreate failed, rc=%Rrc\n", rc); break; } g_aServices[j].fStarted = true; /* Wait for the thread to initialize. */ /** @todo There is a race between waiting and checking * the fShutdown flag of a thread here and processing * the thread's actual worker loop. If the thread decides * to exit the loop before we skipped the fShutdown check * below the service will fail to start! */ /** @todo This presumably means either a one-shot service or that * something has gone wrong. In the second case treating it as failure * to start is probably right, so we need a way to signal the first * rather than leaving the idle thread hanging around. A flag in the * service description? */ RTThreadUserWait(g_aServices[j].Thread, 60 * 1000); if (g_aServices[j].fShutdown) { VGSvcError("Service '%s' failed to start!\n", g_aServices[j].pDesc->pszName); rc = VERR_GENERAL_FAILURE; } } if (RT_SUCCESS(rc)) VGSvcVerbose(1, "All services started.\n"); else { VGSvcError("An error occcurred while the services!\n"); VGSvcReportStatus(VBoxGuestFacilityStatus_Failed); } return rc; }
/** * Initialize a new thread, this actually creates the thread. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param ppThread Where the thread instance data handle is. * @param cbStack The stack size, see RTThreadCreate(). * @param enmType The thread type, see RTThreadCreate(). * @param pszName The thread name, see RTThreadCreate(). */ static int pdmR3ThreadInit(PVM pVM, PPPDMTHREAD ppThread, size_t cbStack, RTTHREADTYPE enmType, const char *pszName) { PPDMTHREAD pThread = *ppThread; PUVM pUVM = pVM->pUVM; /* * Initialize the remainder of the structure. */ pThread->Internal.s.pVM = pVM; int rc = RTSemEventMultiCreate(&pThread->Internal.s.BlockEvent); if (RT_SUCCESS(rc)) { rc = RTSemEventMultiCreate(&pThread->Internal.s.SleepEvent); if (RT_SUCCESS(rc)) { /* * Create the thread and wait for it to initialize. * The newly created thread will set the PDMTHREAD::Thread member. */ RTTHREAD Thread; rc = RTThreadCreate(&Thread, pdmR3ThreadMain, pThread, cbStack, enmType, RTTHREADFLAGS_WAITABLE, pszName); if (RT_SUCCESS(rc)) { rc = RTThreadUserWait(Thread, 60*1000); if ( RT_SUCCESS(rc) && pThread->enmState != PDMTHREADSTATE_SUSPENDED) rc = VERR_PDM_THREAD_IPE_2; if (RT_SUCCESS(rc)) { /* * Insert it into the thread list. */ RTCritSectEnter(&pUVM->pdm.s.ListCritSect); pThread->Internal.s.pNext = NULL; if (pUVM->pdm.s.pThreadsTail) pUVM->pdm.s.pThreadsTail->Internal.s.pNext = pThread; else pUVM->pdm.s.pThreads = pThread; pUVM->pdm.s.pThreadsTail = pThread; RTCritSectLeave(&pUVM->pdm.s.ListCritSect); rc = RTThreadUserReset(Thread); AssertRC(rc); return rc; } /* bailout */ RTThreadWait(Thread, 60*1000, NULL); } RTSemEventMultiDestroy(pThread->Internal.s.SleepEvent); pThread->Internal.s.SleepEvent = NIL_RTSEMEVENTMULTI; } RTSemEventMultiDestroy(pThread->Internal.s.BlockEvent); pThread->Internal.s.BlockEvent = NIL_RTSEMEVENTMULTI; } MMHyperFree(pVM, pThread); *ppThread = NULL; return rc; }
/** * Connects to the peer. * * @returns VBox status code. Updates g_hTcpClient and g_fTcpClientFromServer on * success */ static int txsTcpConnect(void) { int rc; if (g_enmTcpMode == TXSTCPMODE_SERVER) { g_fTcpClientFromServer = true; rc = RTTcpServerListen2(g_pTcpServer, &g_hTcpClient); Log(("txsTcpRecvPkt: RTTcpServerListen2 -> %Rrc\n", rc)); } else if (g_enmTcpMode == TXSTCPMODE_CLIENT) { g_fTcpClientFromServer = false; for (;;) { Log2(("Calling RTTcpClientConnect(%s, %u,)...\n", g_szTcpConnectAddr, g_uTcpConnectPort)); rc = RTTcpClientConnect(g_szTcpConnectAddr, g_uTcpConnectPort, &g_hTcpClient); Log(("txsTcpRecvPkt: RTTcpClientConnect -> %Rrc\n", rc)); if (RT_SUCCESS(rc) || txsTcpIsFatalClientConnectStatus(rc)) break; /* Delay a wee bit before retrying. */ RTThreadSleep(1536); } } else { Assert(g_enmTcpMode == TXSTCPMODE_BOTH); RTTHREAD hSelf = RTThreadSelf(); /* * Create client threads. */ RTCritSectEnter(&g_TcpCritSect); RTThreadUserReset(hSelf); g_hThreadMain = hSelf; g_fTcpStopConnecting = false; RTCritSectLeave(&g_TcpCritSect); txsTcpConnectWaitOnThreads(32); rc = VINF_SUCCESS; if (g_hThreadTcpConnect == NIL_RTTHREAD) { g_pTcpConnectCancelCookie = NULL; rc = RTThreadCreate(&g_hThreadTcpConnect, txsTcpClientConnectThread, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tcpconn"); } if (g_hThreadTcpServer == NIL_RTTHREAD && RT_SUCCESS(rc)) rc = RTThreadCreate(&g_hThreadTcpServer, txsTcpServerConnectThread, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tcpserv"); RTCritSectEnter(&g_TcpCritSect); /* * Wait for connection to be established. */ while ( RT_SUCCESS(rc) && g_hTcpClient == NIL_RTSOCKET) { RTCritSectLeave(&g_TcpCritSect); RTThreadUserWait(hSelf, 1536); rc = txsTcpConnectWaitOnThreads(0); RTCritSectEnter(&g_TcpCritSect); } /* * Cancel the threads. */ g_hThreadMain = NIL_RTTHREAD; g_fTcpStopConnecting = true; RTCritSectLeave(&g_TcpCritSect); RTTcpClientCancelConnect(&g_pTcpConnectCancelCookie); } AssertMsg(RT_SUCCESS(rc) ? g_hTcpClient != NIL_RTSOCKET : g_hTcpClient == NIL_RTSOCKET, ("%Rrc %p\n", rc, g_hTcpClient)); g_cbTcpStashed = 0; 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; }