/** 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;
}
Exemple #5
0
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;
}
Exemple #6
0
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;
}
Exemple #7
0
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;
}
Exemple #9
0
/**
 * 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;
}
Exemple #13
0
/** 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;
}
Exemple #15
0
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;
}
Exemple #21
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;
}
Exemple #22
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;
}
Exemple #25
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;
}
Exemple #26
0
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;
}