DLL_EXPORT void FishHang_LeaveCriticalSection ( const char* pszFileReleasing, // source file that attempted it const int nLineReleasing, // line number of source file LPCRITICAL_SECTION lpCriticalSection // address of critical section object ) { FISH_THREAD* pFISH_THREAD; FISH_LOCK* pFISH_LOCK; FIXFILENAME(pszFileReleasing); LockFishHang(); if (!GetThreadAndLockPtrs(&pFISH_THREAD,&pFISH_LOCK,lpCriticalSection)) FishHangAbort(pszFileReleasing,nLineReleasing); if (!bFishHangAtExit && pFISH_LOCK->pOwningThread != pFISH_THREAD) { logmsg( "\n** ERROR ** FISH_THREAD %8.8X " "releasing FISH_LOCK %8.8X " "owned by FISH_THREAD %8.8X!\n" "** Here's the culprit! --> %s(%d)\n", (int)pFISH_THREAD, (int)pFISH_LOCK, (int)pFISH_LOCK->pOwningThread, pszFileReleasing,nLineReleasing ); RemoveListEntry(&pFISH_THREAD->ThreadListLink); InsertListHead(&ThreadsListHead,&pFISH_THREAD->ThreadListLink); PrintAllFISH_THREADs(); if (pFISH_LOCK->pOwningThread) { RemoveListEntry(&pFISH_LOCK->ThreadLockListLink); InsertListHead(&pFISH_LOCK->pOwningThread->ThreadLockListHead,&pFISH_LOCK->ThreadLockListLink); } PrintAllFISH_LOCKs(); FishHangAbort(pszFileReleasing,nLineReleasing); } else { pFISH_LOCK->nLockedDepth--; } if (pFISH_LOCK->nLockedDepth <= 0) { if (pFISH_LOCK->nLockedDepth < 0) { logmsg( "\n** ERROR ** FISH_THREAD %8.8X " "attempted to release FISH_LOCK %8.8X " "one too many times!?!\n" "** Here's the culprit! --> %s(%d)\n", (int)pFISH_THREAD, (int)pFISH_LOCK, pszFileReleasing,nLineReleasing ); RemoveListEntry(&pFISH_THREAD->ThreadListLink); InsertListHead(&ThreadsListHead,&pFISH_THREAD->ThreadListLink); PrintAllFISH_THREADs(); if (pFISH_LOCK->pOwningThread) { RemoveListEntry(&pFISH_LOCK->ThreadLockListLink); InsertListHead(&pFISH_LOCK->pOwningThread->ThreadLockListHead,&pFISH_LOCK->ThreadLockListLink); } PrintAllFISH_LOCKs(); FishHangAbort(pszFileReleasing,nLineReleasing); } pFISH_LOCK->pOwningThread = NULL; RemoveListEntry(&pFISH_LOCK->ThreadLockListLink); InitializeListLink(&pFISH_LOCK->ThreadLockListLink); } UnlockFishHang(); LeaveCriticalSection(lpCriticalSection); }
int ScheduleIORequest(void* pDevBlk, unsigned short wDevNum, int* pnDevPrio) { ///////////////////////////////////////////////////////////////// // PROGRAMMING NOTE: The various errors that can occur in this // function should probably be reported by returning cc1 with // 'channel control check' set (or something similar), but until // I can work out the details, I'm going to be lazy and just // return cc2 (subchannel busy) for now to allow the system to // retry the i/o request if it so desires. Hopefully the problem // was only intermittent and will work the second time around. ///////////////////////////////////////////////////////////////// DEVIOREQUEST* pIORequest; // ptr to i/o request DEVTHREADPARMS* pThreadParms; // ptr to device_thread parameters // Create an i/o request queue entry for this i/o request pIORequest = (DEVIOREQUEST*) malloc(sizeof(DEVIOREQUEST)); if (!pIORequest) { WRMSG ( HHC04111, "E", 0, wDevNum, "malloc(DEVIOREQUEST)", errno, strerror(errno) ); return 2; } InitializeListLink(&pIORequest->IORequestListLinkingListEntry); pIORequest->pDevBlk = pDevBlk; pIORequest->wDevNum = wDevNum; pIORequest->pnDevPrio = pnDevPrio; // Schedule a device_thread to process this i/o request LockScheduler(); // (lock scheduler vars) if (ios_devtmax < 0) { // Create new "one time only" thread each time... // (Note: the device thread's parms will automatically // be locked upon return if creation was successful.) RemoveDeadThreadsFromList(); // (prevent runaway list) if (!(pThreadParms = CreateDeviceThread(wDevNum))) { UnlockScheduler(); // (unlock scheduler vars) free(pIORequest); // (discard i/o request) return 2; // (return device busy) } } else { // Select a non-busy device thread to handle this i/o request... // (Note: the device thread's parms will automatically // be locked upon return if selection was successful.) if (!(pThreadParms = SelectDeviceThread())) { // All threads are currently busy or no threads exist yet. // Since the possibility of a deadlock[1] can easily occur if we schedule // an i/o request to a currently busy device thread[2], we have no choice // but to create another device thread. // [1] Not an actual programmatic deadlock of course, but nonetheless // a deadlock from the guest operating system's point of view. // [2] A curently busy device thread could easily have its channel program // suspended and thus would never see the queued request until such time // its suspended channel program was resumed and allowed to complete, and // if the request we queued (that would end up waiting to be processed // by the currently suspended device thread) just so happens to be one // that the operating system needs to have completed before it can resume // the currently suspended channel program, then the operating system will // obviously hang. (It would end up waiting for an i/o to complete that // would never complete until the currently suspended channel program was // resumed, which would never be resumed until the queued i/o completes, // which would never even be processed until the currently suspended // channel program is resumed ..... etc.) if (ios_devtmax && ios_devtnbr >= ios_devtmax) // max threads already created? { WRMSG ( HHC04110, "W", ios_devtmax, ( ios_devtnbr - ios_devtmax ) + 1 ); ios_devtunavail++; // (count occurrences) } // Create a new device thread for this i/o request... // (Note: the device thread's parms will automatically // be locked upon return if creation was successful.) if (!(pThreadParms = CreateDeviceThread(wDevNum))) { UnlockScheduler(); // (unlock scheduler vars) free(pIORequest); // (discard i/o request) return 2; // (return device busy) } } } // (Note: the thread parms lock should still be held at this point) // Queue the i/o request to the selected device_thread's i/o request queue... InsertListTail(&pThreadParms->IORequestListHeadListEntry,&pIORequest->IORequestListLinkingListEntry); // Tell device_thread it has work (must do this while its request list is still // locked to prevent it from prematurely exiting in case it's just about to die) MySetEvent(pThreadParms->hRequestQueuedEvent); // Now unlock its request queue so it can process the request we just gave it UnlockThreadParms(pThreadParms); // (let it proceed) // We're done, so unlock the scheduler vars so another cpu thread // in the configuration can schedule and i/o request and then exit // back the the startio function... UnlockScheduler(); // (unlock vars and exit; we're done) return 0; // (success) }
DEVTHREADPARMS* CreateDeviceThread(unsigned short wDevNum) { DEVTHREADPARMS* pThreadParms; // ptr to returned device_thread parameters DWORD dwThreadID; // (work) pThreadParms = malloc(sizeof(DEVTHREADPARMS)); // (allocate structure) if (!pThreadParms) { logmsg(_("HHCCP086E malloc(DEVTHREADPARMS) failed; device=%4.4X, strerror=\"%s\"\n"), wDevNum,strerror(errno)); return NULL; // (error) } pThreadParms->hShutdownEvent = MyCreateEvent(NULL,TRUE,FALSE,NULL); if (!pThreadParms->hShutdownEvent) { logmsg(_("HHCCP087E CreateEvent(hShutdownEvent) failed; device=%4.4X, strerror=\"%s\"\n"), wDevNum,strerror(errno)); free(pThreadParms); return NULL; // (error) } pThreadParms->hRequestQueuedEvent = MyCreateEvent(NULL,TRUE,FALSE,NULL); if (!pThreadParms->hRequestQueuedEvent) { logmsg(_("HHCCP088E CreateEvent(hRequestQueuedEvent) failed; device=%4.4X, strerror=\"%s\"\n"), wDevNum,strerror(errno)); MyCloseHandle(pThreadParms->hShutdownEvent); free(pThreadParms); return NULL; // (error) } MyInitializeCriticalSection(&pThreadParms->IORequestListLock); InitializeListLink(&pThreadParms->ThreadListLinkingListEntry); InitializeListHead(&pThreadParms->IORequestListHeadListEntry); pThreadParms->bThreadIsDead = FALSE; pThreadParms->dwThreadID = 0; if (fthread_create(&dwThreadID,NULL,DeviceThread,pThreadParms,"DeviceThread") != 0) { logmsg(_("HHCCP089E fthread_create(DeviceThread) failed; device=%4.4X, strerror=\"%s\"\n"), wDevNum,strerror(errno)); MyCloseHandle(pThreadParms->hShutdownEvent); MyCloseHandle(pThreadParms->hRequestQueuedEvent); MyDeleteCriticalSection(&pThreadParms->IORequestListLock); free(pThreadParms); return NULL; // (error) } // Add the newly created device_thread to the end of our list of managed threads. InsertListTail(&ThreadListHeadListEntry,&pThreadParms->ThreadListLinkingListEntry); if (++ios_devtnbr > ios_devthwm) ios_devthwm = ios_devtnbr; LockThreadParms(pThreadParms); // (lock thread parms before using) return pThreadParms; // (success) }