コード例 #1
0
/**
 * Sends a signal to the thread to rescan the clients/VMs having open sessions.
 */
void VirtualBox::ClientWatcher::update()
{
    AssertReturnVoid(mThread != NIL_RTTHREAD);
    LogFlowFunc(("ping!\n"));

    /* sent an update request */
#if defined(RT_OS_WINDOWS)
    ASMAtomicWriteBool(&mfUpdateReq, true);
    ::SetEvent(mUpdateReq);

#elif defined(RT_OS_OS2)
    RTSemEventSignal(mUpdateReq);

#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
    /* use short timeouts, as we expect changes */
    ASMAtomicUoWriteU8(&mUpdateAdaptCtr, RT_ELEMENTS(s_aUpdateTimeoutSteps) - 1);
    RTSemEventSignal(mUpdateReq);

#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
    RTSemEventSignal(mUpdateReq);

#else
# error "Port me!"
#endif
}
コード例 #2
0
ファイル: GuestCtrlPrivate.cpp プロジェクト: bayasist/vbox
int GuestWaitEventBase::SignalInternal(int rc, int guestRc,
                                       const GuestWaitEventPayload *pPayload)
{
    if (ASMAtomicReadBool(&mfAborted))
        return VERR_CANCELLED;

#ifdef VBOX_STRICT
    if (rc == VERR_GSTCTL_GUEST_ERROR)
        AssertMsg(RT_FAILURE(guestRc), ("Guest error indicated but no actual guest error set (%Rrc)\n", guestRc));
    else
        AssertMsg(RT_SUCCESS(guestRc), ("No guest error indicated but actual guest error set (%Rrc)\n", guestRc));
#endif

    int rc2;
    if (pPayload)
        rc2 = mPayload.CopyFromDeep(*pPayload);
    else
        rc2 = VINF_SUCCESS;
    if (RT_SUCCESS(rc2))
    {
        mRc = rc;
        mGuestRc = guestRc;

        rc2 = RTSemEventSignal(mEventSem);
    }

    return rc2;
}
RTDECL(int) RTSemSpinMutexRelease(RTSEMSPINMUTEX hSpinMtx)
{
    RTSEMSPINMUTEXINTERNAL *pThis = hSpinMtx;
    RTNATIVETHREAD          hSelf = RTThreadNativeSelf();
    uint32_t                cLockers;
    RTSEMSPINMUTEXSTATE     State;
    bool                    fRc;

    Assert(hSelf != NIL_RTNATIVETHREAD);
    RTSEMSPINMUTEX_VALIDATE_RETURN(pThis);

    /*
     * Get the saved state and try release the semaphore.
     */
    State = pThis->SavedState;
    ASMCompilerBarrier();
    ASMAtomicCmpXchgHandle(&pThis->hOwner, NIL_RTNATIVETHREAD, hSelf, fRc);
    AssertMsgReturn(fRc,
                    ("hOwner=%p hSelf=%p cLockers=%d\n", pThis->hOwner, hSelf, pThis->cLockers),
                    VERR_NOT_OWNER);

    cLockers = ASMAtomicDecS32(&pThis->cLockers);
    rtSemSpinMutexLeave(&State);
    if (cLockers > 0)
    {
        int rc = RTSemEventSignal(pThis->hEventSem);
        AssertReleaseMsg(RT_SUCCESS(rc), ("RTSemEventSignal -> %Rrc\n", rc));
    }
    return VINF_SUCCESS;
}
コード例 #4
0
/**
 * @copydoc FNPDMDRVDESTRUCT
 */
static DECLCALLBACK(void) drvdiskintDestruct(PPDMDRVINS pDrvIns)
{
    PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);

    if (pThis->pTreeSegments)
    {
        RTAvlrFileOffsetDestroy(pThis->pTreeSegments, drvdiskintTreeDestroy, NULL);
        RTMemFree(pThis->pTreeSegments);
    }

    if (pThis->fTraceRequests)
    {
        pThis->fRunning = false;
        RTSemEventSignal(pThis->SemEvent);
        RTSemEventDestroy(pThis->SemEvent);
    }

    if (pThis->fCheckDoubleCompletion)
    {
        /* Free all requests */
        while (pThis->papIoReq[pThis->iEntry])
        {
            RTMemFree(pThis->papIoReq[pThis->iEntry]);
            pThis->papIoReq[pThis->iEntry] = NULL;
            pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
        }
    }

    if (pThis->hIoLogger)
        VDDbgIoLogDestroy(pThis->hIoLogger);
}
コード例 #5
0
SUPDECL(int) SUPSemEventSignal(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent)
{
    int         rc;
    uint32_t    h32;
    PSUPDRVOBJ  pObj;

    /*
     * Input validation.
     */
    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
    h32 = (uint32_t)(uintptr_t)hEvent;
    if (h32 != (uintptr_t)hEvent)
        return VERR_INVALID_HANDLE;
    pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT);
    if (!pObj)
        return VERR_INVALID_HANDLE;

    /*
     * Do the job.
     */
    rc = RTSemEventSignal((RTSEMEVENT)pObj->pvUser1);

    SUPR0ObjRelease(pObj, pSession);
    return rc;
}
コード例 #6
0
/**
 *  Uninitializes the instance and sets the ready flag to FALSE.
 *  Called either from FinalRelease() or by the parent when it gets destroyed.
 */
void VirtualBoxClient::uninit()
{
    LogFlowThisFunc(("\n"));

    /* Enclose the state transition Ready->InUninit->NotReady */
    AutoUninitSpan autoUninitSpan(this);
    if (autoUninitSpan.uninitDone())
        return;

    if (mData.m_ThreadWatcher != NIL_RTTHREAD)
    {
        /* Signal the event semaphore and wait for the thread to terminate.
         * if it hangs for some reason exit anyway, this can cause a crash
         * though as the object will no longer be available. */
        RTSemEventSignal(mData.m_SemEvWatcher);
        RTThreadWait(mData.m_ThreadWatcher, 30000, NULL);
        mData.m_ThreadWatcher = NIL_RTTHREAD;
        RTSemEventDestroy(mData.m_SemEvWatcher);
        mData.m_SemEvWatcher = NIL_RTSEMEVENT;
    }

    mData.m_pVirtualBox.setNull();

    ASMAtomicDecU32(&g_cInstances);
}
コード例 #7
0
RTDECL(int) RTCritSectDelete(PRTCRITSECT pCritSect)
{
    /*
     * Assert free waiters and so on.
     */
    Assert(pCritSect);
    Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
    Assert(pCritSect->cNestings == 0);
    Assert(pCritSect->cLockers == -1);
    Assert(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD);

    /*
     * Invalidate the structure and free the mutex.
     * In case someone is waiting we'll signal the semaphore cLockers + 1 times.
     */
    ASMAtomicWriteU32(&pCritSect->u32Magic, ~RTCRITSECT_MAGIC);
    pCritSect->fFlags           = 0;
    pCritSect->cNestings        = 0;
    pCritSect->NativeThreadOwner= NIL_RTNATIVETHREAD;
    RTSEMEVENT EventSem = pCritSect->EventSem;
    pCritSect->EventSem         = NIL_RTSEMEVENT;

    while (pCritSect->cLockers-- >= 0)
        RTSemEventSignal(EventSem);
    ASMAtomicWriteS32(&pCritSect->cLockers, -1);
    int rc = RTSemEventDestroy(EventSem);
    AssertRC(rc);

    RTLockValidatorRecExclDestroy(&pCritSect->pValidatorRec);

    return rc;
}
コード例 #8
0
ファイル: HostDnsServiceDarwin.cpp プロジェクト: etiago/vbox
static int hostMonitoringRoutine(RTTHREAD ThreadSelf, void *pvUser)
{
    NOREF(ThreadSelf);
    NOREF(pvUser);
    g_RunLoopRef = CFRunLoopGetCurrent();
    AssertReturn(g_RunLoopRef, VERR_INTERNAL_ERROR);

    CFRetain(g_RunLoopRef);

    CFArrayRef watchingArrayRef = CFArrayCreate(NULL,
                                                (const void **)&kStateNetworkGlobalDNSKey,
                                                1, &kCFTypeArrayCallBacks);
    if (!watchingArrayRef)
    {
        CFRelease(g_DnsWatcher);
        return E_OUTOFMEMORY;
    }

    if(SCDynamicStoreSetNotificationKeys(g_store, watchingArrayRef, NULL))
        CFRunLoopAddSource(CFRunLoopGetCurrent(), g_DnsWatcher, kCFRunLoopCommonModes);

    CFRelease(watchingArrayRef);

    RTSemEventSignal(g_DnsInitEvent);

    CFRunLoopRun();

    CFRelease(g_RunLoopRef);

    return VINF_SUCCESS;
}
コード例 #9
0
int UIDnDDataObject::Signal(const QString &strFormat,
                            const void *pvData, uint32_t cbData)
{
    LogFlowFunc(("Signalling ...\n"));

    int rc;

    SetStatus(Dropped);

    mstrFormat = strFormat;
    if (cbData)
    {
        mpvData = RTMemAlloc(cbData);
        if (mpvData)
        {
            memcpy(mpvData, pvData, cbData);
            mcbData = cbData;
            rc = VINF_SUCCESS;
        }
        else
            rc = VERR_NO_MEMORY;
    }
    else
        rc = VINF_SUCCESS;

    if (RT_FAILURE(rc))
        mStatus = Aborted;

    /* Signal in any case. */
    int rc2 = RTSemEventSignal(mSemEvent);
    if (RT_SUCCESS(rc))
        rc = rc2;

    return rc;
}
コード例 #10
0
ファイル: HostDnsServiceDarwin.cpp プロジェクト: mcenirm/vbox
int HostDnsServiceDarwin::monitorWorker()
{
    m->m_RunLoopRef = CFRunLoopGetCurrent();
    AssertReturn(m->m_RunLoopRef, VERR_INTERNAL_ERROR);

    CFRetain(m->m_RunLoopRef);

    CFArrayRef watchingArrayRef = CFArrayCreate(NULL,
                                                (const void **)&kStateNetworkGlobalDNSKey,
                                                1, &kCFTypeArrayCallBacks);
    if (!watchingArrayRef)
    {
        CFRelease(m->m_DnsWatcher);
        return E_OUTOFMEMORY;
    }

    if(SCDynamicStoreSetNotificationKeys(m->m_store, watchingArrayRef, NULL))
        CFRunLoopAddSource(CFRunLoopGetCurrent(), m->m_DnsWatcher, kCFRunLoopCommonModes);

    CFRelease(watchingArrayRef);

    monitorThreadInitializationDone();

    while (!m->m_fStop)
    {
        CFRunLoopRun();
    }

    CFRelease(m->m_RunLoopRef);

    /* We're notifying stopper thread. */
    RTSemEventSignal(m->m_evtStop);

    return VINF_SUCCESS;
}
コード例 #11
0
static void vboxNetAdpDarwinDetach(ifnet_t pIface)
{
    PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
    Assert(pThis);
    Log2(("vboxNetAdpDarwinDetach: Signaling detach to vboxNetAdpUnregisterDevice.\n"));
    /* Let vboxNetAdpDarwinUnregisterDevice know that the interface has been detached. */
    RTSemEventSignal(pThis->u.s.hEvtDetached);
}
コード例 #12
0
int GuestCtrlEvent::Signal(int rc /*= VINF_SUCCESS*/)
{
    AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);

    mRC = rc;

    return RTSemEventSignal(hEventSem);
}
コード例 #13
0
ファイル: SessionImpl.cpp プロジェクト: quiquetux/jokte-ba-as
/** @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
}
コード例 #14
0
ファイル: GuestCtrlPrivate.cpp プロジェクト: bayasist/vbox
/**
 * Signals the event.
 *
 * @return  IPRT status code.
 * @param   pEvent              Public IEvent to associate.
 *                              Optional.
 */
int GuestWaitEvent::SignalExternal(IEvent *pEvent)
{
    AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);

    if (pEvent)
        mEvent = pEvent;

    return RTSemEventSignal(mEventSem);
}
コード例 #15
0
ファイル: VMEmt.cpp プロジェクト: greg100795/virtualbox
/**
 * Bootstrap VMR3NotifyFF() worker.
 *
 * @param   pUVCpu          Pointer to the user mode VMCPU structure.
 * @param   fFlags          Notification flags, VMNOTIFYFF_FLAGS_*.
 */
static DECLCALLBACK(void) vmR3BootstrapNotifyCpuFF(PUVMCPU pUVCpu, uint32_t fFlags)
{
    if (pUVCpu->vm.s.fWait)
    {
        int rc = RTSemEventSignal(pUVCpu->vm.s.EventSemWait);
        AssertRC(rc);
    }
    NOREF(fFlags);
}
コード例 #16
0
ファイル: Helper.cpp プロジェクト: svn2github/virtualbox
/**
 * Indicates to the XPCOM thread that it should terminate now.
 */
void terminateXPCOMQueueThread(void)
{
    g_fTerminateXPCOMQueueThread = true;
    if (g_EventSemXPCOMQueueThread)
    {
        RTSemEventSignal(g_EventSemXPCOMQueueThread);
        RTThreadYield();
    }
}
コード例 #17
0
int GuestWaitEvent::Signal(IEvent *pEvent)
{
    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
    AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);

    mEvent = pEvent;

    return RTSemEventSignal(mEventSem);
}
コード例 #18
0
int VMMDev::SetCredentialsJudgementResult(uint32_t u32Flags)
{
    mu32CredentialsFlags = u32Flags;

    int rc = RTSemEventSignal (mCredentialsEvent);
    AssertRC(rc);

    return rc;
}
コード例 #19
0
ファイル: GuestCtrlPrivate.cpp プロジェクト: bayasist/vbox
/**
 * Cancels the event.
 */
int GuestWaitEvent::Cancel(void)
{
    AssertReturn(!mfAborted, VERR_CANCELLED);
    ASMAtomicWriteBool(&mfAborted, true);

#ifdef DEBUG_andy
    LogFlowThisFunc(("Cancelling %p ...\n"));
#endif
    return RTSemEventSignal(mEventSem);
}
コード例 #20
0
static void pdmacFileAioMgrWakeup(PPDMACEPFILEMGR pAioMgr)
{
    bool fWokenUp = ASMAtomicXchgBool(&pAioMgr->fWokenUp, true);
    if (!fWokenUp)
    {
        bool fWaitingEventSem = ASMAtomicReadBool(&pAioMgr->fWaitingEventSem);
        if (fWaitingEventSem)
        {
            int rc = RTSemEventSignal(pAioMgr->EventSem);
            AssertRC(rc);
        }
    }
}
コード例 #21
0
static DECLCALLBACK(void) AsyncTaskCompleted(PVM pVM, void *pvUser, void *pvUser2, int rc)
{
    LogFlow((TESTCASE ": %s: pVM=%p pvUser=%p pvUser2=%p\n", __FUNCTION__, pVM, pvUser, pvUser2));
    NOREF(rc);

    uint32_t cTasksStillLeft = ASMAtomicDecU32(&g_cTasksLeft);

    if (!cTasksStillLeft)
    {
        /* All tasks processed. Wakeup main. */
        RTSemEventSignal(g_FinishedEventSem);
    }
}
コード例 #22
0
ファイル: VMEmt.cpp プロジェクト: greg100795/virtualbox
/**
 * Default VMR3NotifyFF() worker.
 *
 * @param   pUVCpu          Pointer to the user mode VMCPU structure.
 * @param   fFlags          Notification flags, VMNOTIFYFF_FLAGS_*.
 */
static DECLCALLBACK(void) vmR3DefaultNotifyCpuFF(PUVMCPU pUVCpu, uint32_t fFlags)
{
    if (pUVCpu->vm.s.fWait)
    {
        int rc = RTSemEventSignal(pUVCpu->vm.s.EventSemWait);
        AssertRC(rc);
    }
#ifdef VBOX_WITH_REM
    else if (   !(fFlags & VMNOTIFYFF_FLAGS_DONE_REM)
             && pUVCpu->pVCpu
             && pUVCpu->pVCpu->enmState == VMCPUSTATE_STARTED_EXEC_REM)
        REMR3NotifyFF(pUVCpu->pVM);
#endif
}
コード例 #23
0
ファイル: sys_arch.c プロジェクト: greg100795/virtualbox
/**
 * Create a new (binary) semaphore.
 */
sys_sem_t sys_sem_new(u8_t count)
{
    int rc;
    RTSEMEVENT sem;

    Assert(count <= 1);
    rc = RTSemEventCreate(&sem);
    AssertRC(rc);
    if (count == 1)
    {
        rc = RTSemEventSignal(sem);
        AssertRC(rc);
    }
    return sem;
}
コード例 #24
0
ファイル: reqqueue.cpp プロジェクト: miguelinux/vbox
/**
 * Submits a request to the queue.
 *
 * @param   pQueue              The queue.
 * @param   pReq                The request.
 */
DECLHIDDEN(void) rtReqQueueSubmit(PRTREQQUEUEINT pQueue, PRTREQINT pReq)
{
    PRTREQ pNext;
    do
    {
        pNext = pQueue->pReqs;
        pReq->pNext = pNext;
        ASMAtomicWriteBool(&pQueue->fBusy, true);
    } while (!ASMAtomicCmpXchgPtr(&pQueue->pReqs, pReq, pNext));

    /*
     * Notify queue thread.
     */
    RTSemEventSignal(pQueue->EventSem);
}
コード例 #25
0
ファイル: sys_arch.c プロジェクト: greg100795/virtualbox
/**
 * Initialize the port to IPRT.
 */
void sys_init(void)
{
    int rc;
    unsigned i;
#if SYS_LIGHTWEIGHT_PROT
    rc = RTCritSectInit(&g_ProtCritSect);
    AssertRC(rc);
#else
    rc = RTSemEventCreate(&g_ThreadSem);
    AssertRC(rc);
    rc = RTSemEventSignal(g_ThreadSem);
    AssertRC(rc);
#endif
    for (i = 0; i < THREADS_MAX; i++)
        g_aTLS[i].tid = NIL_RTTHREAD;
}
コード例 #26
0
ファイル: EventQueue.cpp プロジェクト: svn2github/virtualbox
/**
 *  Posts an event to this event loop asynchronously.
 *
 *  @param  event   the event to post, must be allocated using |new|
 *  @return         TRUE if successful and false otherwise
 */
BOOL EventQueue::postEvent(Event *pEvent)
{
    int rc = RTCritSectEnter(&mCritSect);
    if (RT_SUCCESS(rc))
    {
        try
        {
            if (pEvent)
            {
                pEvent->AddRef();
                mEvents.push_back(pEvent);
            }
            else /* No locking, since we're already in our crit sect. */
                mShutdown = true;

            size_t cEvents = mEvents.size();
            if (cEvents > _1K) /** @todo Make value configurable? */
            {
                static int s_cBitchedAboutLotEvents = 0;
                if (s_cBitchedAboutLotEvents < 10)
                    LogRel(("Warning: Event queue received lots of events (%zu), expect delayed event handling (%d/10)\n",
                            cEvents, ++s_cBitchedAboutLotEvents));
            }

            /* Leave critical section before signalling event. */
            rc = RTCritSectLeave(&mCritSect);
            if (RT_SUCCESS(rc))
            {
                int rc2 = RTSemEventSignal(mSemEvent);
                AssertRC(rc2);
            }
        }
        catch (std::bad_alloc &ba)
        {
            NOREF(ba);
            rc = VERR_NO_MEMORY;
        }

        if (RT_FAILURE(rc))
        {
            int rc2 = RTCritSectLeave(&mCritSect);
            AssertRC(rc2);
        }
    }

    return RT_SUCCESS(rc) ? TRUE : FALSE;
}
コード例 #27
0
ファイル: GuestCtrlPrivate.cpp プロジェクト: ryenus/vbox
int GuestCtrlEvent::Cancel(void)
{
    int rc = VINF_SUCCESS;
    if (!ASMAtomicReadBool(&fCompleted))
    {
        if (!ASMAtomicReadBool(&fCanceled))
        {
            ASMAtomicXchgBool(&fCanceled, true);

            LogFlowThisFunc(("Cancelling event ...\n"));
            rc = hEventSem != NIL_RTSEMEVENT
               ? RTSemEventSignal(hEventSem) : VINF_SUCCESS;
        }
    }

    return rc;
}
コード例 #28
0
ファイル: sys_arch.c プロジェクト: bayasist/vbox
/**
 * Create a new (binary) semaphore.
 */
err_t sys_sem_new(sys_sem_t *pSem, u8_t count)
{
    int rc;
    err_t rcLwip = ERR_ARG;

    if (!pSem)
        return ERR_ARG;
    Assert(count <= 1);
    rc = RTSemEventCreate(pSem);
    AssertRCReturn(rc, ERR_ARG);
    rcLwip = ERR_OK;
    if (count == 1)
    {
        rc = RTSemEventSignal(*pSem);
        AssertRCReturn(rc, ERR_VAL);
    }
    return rcLwip;
}
コード例 #29
0
/** @copydoc PDMICHARCONNECTOR::pfnWrite */
static DECLCALLBACK(int) drvCharWrite(PPDMICHARCONNECTOR pInterface, const void *pvBuf, size_t cbWrite)
{
    PDRVCHAR pThis = PDMICHAR_2_DRVCHAR(pInterface);
    const char *pbBuffer = (const char *)pvBuf;

    LogFlow(("%s: pvBuf=%#p cbWrite=%d\n", __FUNCTION__, pvBuf, cbWrite));

    for (uint32_t i = 0; i < cbWrite; i++)
    {
        if (ASMAtomicXchgBool(&pThis->fSending, true))
            return VERR_BUFFER_OVERFLOW;

        pThis->u8SendByte = pbBuffer[i];
        RTSemEventSignal(pThis->SendSem);
        STAM_COUNTER_INC(&pThis->StatBytesWritten);
    }
    return VINF_SUCCESS;
}
コード例 #30
0
/**
 * Destruct a char driver instance.
 *
 * Most VM resources are freed by the VM. This callback is provided so that
 * any non-VM resources can be freed correctly.
 *
 * @param   pDrvIns     The driver instance data.
 */
static DECLCALLBACK(void) drvCharDestruct(PPDMDRVINS pDrvIns)
{
    PDRVCHAR pThis = PDMINS_2_DATA(pDrvIns, PDRVCHAR);
    LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);

    /*
     * Tell the threads to shut down.
     */
    pThis->fShutdown = true;
    if (pThis->SendSem != NIL_RTSEMEVENT)
    {
        RTSemEventSignal(pThis->SendSem);
        pThis->SendSem = NIL_RTSEMEVENT;
    }

    /*
     * Wait for the threads.
     * ASSUMES that PDM destroys the driver chain from the bottom and up.
     */
    if (pThis->ReceiveThread != NIL_RTTHREAD)
    {
        int rc = RTThreadWait(pThis->ReceiveThread, 30000, NULL);
        if (RT_SUCCESS(rc))
            pThis->ReceiveThread = NIL_RTTHREAD;
        else
            LogRel(("Char%d: receive thread did not terminate (%Rrc)\n", pDrvIns->iInstance, rc));
    }

    if (pThis->SendThread != NIL_RTTHREAD)
    {
        int rc = RTThreadWait(pThis->SendThread, 30000, NULL);
        if (RT_SUCCESS(rc))
            pThis->SendThread = NIL_RTTHREAD;
        else
            LogRel(("Char%d: send thread did not terminate (%Rrc)\n", pDrvIns->iInstance, rc));
    }

    if (pThis->SendSem != NIL_RTSEMEVENT)
    {
        RTSemEventDestroy(pThis->SendSem);
        pThis->SendSem = NIL_RTSEMEVENT;
    }
}