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; }
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); }