BOOL AcquireReadLock(RWLock *pLock)
{
    BOOL result = TRUE;

    if (!MyWaitForSingleObject(pLock->hMutex))
        return FALSE;
 
    if(++pLock->nReaderCount == 1)
        result = MyWaitForSingleObject(pLock->hDataLock);

    ReleaseMutex(pLock->hMutex);
    return result;
}
BOOL ReleaseReadLock(RWLock *pLock)
{
    int result;
    LONG lPrevCount;

    if (!MyWaitForSingleObject(pLock->hMutex))
        return FALSE;

    if (--pLock->nReaderCount == 0)
        result = ReleaseSemaphore(pLock->hDataLock, 1, &lPrevCount);

    ReleaseMutex(pLock->hMutex);
    return result;
}
Beispiel #3
0
void*  DeviceThread (void* pArg)
{
    DEVTHREADPARMS*  pThreadParms;      // ptr to thread parms
    LIST_ENTRY*      pListEntry;        // (work)
    DEVIOREQUEST*    pIORequest;        // ptr to i/o request
    void*            pDevBlk;           // ptr to device block
    int*             pnDevPrio;         // ptr to device i/o priority
    int              nCurPrio;          // current thread priority

    pThreadParms = (DEVTHREADPARMS*) pArg;

    pThreadParms->dwThreadID = GetCurrentThreadId();

    nCurPrio = getpriority(PRIO_PROCESS, 0);
    AdjustThreadPriority(&nCurPrio,ios_devthread_prio);

    for (;;)
    {
        // Wait for an i/o request to be queued...

        InterlockedIncrement(&ios_devtwait);
        MyWaitForSingleObject(pThreadParms->hRequestQueuedEvent,ios_devthread_timeout * 1000);
        InterlockedDecrement(&ios_devtwait);


        if (IsEventSet(pThreadParms->hShutdownEvent)) break;

        // Lock our queue so it doesn't change while we take a look at it...

        LockThreadParms(pThreadParms);      // (freeze moving target)

        // Check to see if we have any work...

        if (IsListEmpty(&pThreadParms->IORequestListHeadListEntry))
        {
            // We've waited long enough...

            pThreadParms->bThreadIsDead = TRUE;     // (keep scheduler informed)
            UnlockThreadParms(pThreadParms);        // (let go of our parms block)
            return NULL;                            // (return, NOT break!)
        }

        // Remove the i/o request from our queue...

        // It's important that we remove the request from our queue but
        // NOT reset our flag (if the list is now empty) until AFTER we've
        // processed the request (see further below for details as to why).

        pListEntry = RemoveListHead(&pThreadParms->IORequestListHeadListEntry);

        UnlockThreadParms(pThreadParms);    // (done with thread parms for now)

        pIORequest = CONTAINING_RECORD(pListEntry,DEVIOREQUEST,IORequestListLinkingListEntry);
        pDevBlk   = pIORequest->pDevBlk;    // (need ptr to devblk)
        pnDevPrio = pIORequest->pnDevPrio;  // (need ptr to devprio)
        free(pIORequest);                   // (not needed anymore)

        // Process the i/o request by calling the proper 'execute_ccw_chain'
        // function (based on architectural mode) in source module channel.c

        // Set thread priority to requested device level
        AdjustThreadPriority(&nCurPrio,pnDevPrio);

        call_execute_ccw_chain(ios_arch_mode, pDevBlk); // (process i/o request)

        // Reset thread priority, if necessary
        if (nCurPrio > *ios_devthread_prio)
            AdjustThreadPriority(&nCurPrio,ios_devthread_prio);


        ////////////////////////////////////////////////////////////////////////////
        //
        //                  * * *   I M P O R T A N T   * * *
        //
        // It's important that we reset our flag AFTER we're done with our request
        // in order to prevent the scheduler from trying to give us more work while
        // we're still busy processing the current i/o request (in case the channel
        // program we're processing gets suspended). If the channel program we're
        // processing gets suspended and the scheduler places another request in our
        // queue, it won't ever get processed until our suspended channel program is
        // resumed, and if the request that was placed in our queue was a request
        // for an i/o to another device that the operating system needs to complete
        // in order to obtain the information needed to resume our suspended channel
        // program, a deadlock will occur! (i.e. if the operating system needs to
        // read data from another device before it can resume our channel program,
        // then the i/o request to read from that device better not be given to us
        // because we're suspended and will never get around to executing it until
        // we're resumed, which will never happen until the i/o request waiting in
        // our queue is completed, which will never happend until we're resumed,
        // etc...)
        //
        ////////////////////////////////////////////////////////////////////////////

        // Now that we're done this i/o, reset our flag.

        LockThreadParms(pThreadParms);      // (freeze moving target)

        if (IsListEmpty(&pThreadParms->IORequestListHeadListEntry))
            MyResetEvent(pThreadParms->hRequestQueuedEvent);

        UnlockThreadParms(pThreadParms);    // (thaw moving target)

        if (IsEventSet(pThreadParms->hShutdownEvent)) break;

        // If we're a "one time only" thread, then we're done.

        if (ios_devtmax < 0)
        {
            // Note: no need to lock our thread parms before setting 'dead' flag
            // since the scheduler should never queue us another request anyway
            // because we're a "one-time-only" thread.

            pThreadParms->bThreadIsDead = TRUE;     // (let garbage collector discard us)
            return NULL;                            // (return, NOT break!)
        }
    }

    // The only time we reach here is if the shutdown event was signalled (i.e. we
    // were manually "cancelled" or asked to stop processing; i.e. the i/o subsystem
    // was reset). Discard all i/o requests that may still be remaining in our queue.

    TRACE("** DeviceThread %8.8X: shutdown detected\n",
        (unsigned int)pThreadParms->dwThreadID);

    LockThreadParms(pThreadParms);          // (freeze moving target)

    // Discard all queued i/o requests...

    while (!IsListEmpty(&pThreadParms->IORequestListHeadListEntry))
    {
        pListEntry = RemoveListHead(&pThreadParms->IORequestListHeadListEntry);

        pIORequest = CONTAINING_RECORD(pListEntry,DEVIOREQUEST,IORequestListLinkingListEntry);

        TRACE("** DeviceThread %8.8X: discarding i/o request for device %4.4X\n",
            (unsigned int)pThreadParms->dwThreadID,pIORequest->wDevNum);

        free(pIORequest);
    }

    pThreadParms->bThreadIsDead = TRUE;     // (tell scheduler we've died)

    TRACE("** DeviceThread %8.8X: shutdown complete\n",
        (unsigned int)pThreadParms->dwThreadID);

    UnlockThreadParms(pThreadParms);        // (thaw moving target)

    return NULL;
}
BOOL AcquireWriteLock(RWLock *pLock)
{
    return MyWaitForSingleObject(pLock->hDataLock);
}