DLL_EXPORT void FishHang_DeleteCriticalSection ( const char* pszFileDeleting, // source file that's deleting it const int nLineDeleting, // line number of source file LPCRITICAL_SECTION lpCriticalSection // address of critical section object ) { FISH_THREAD* pFISH_THREAD; FISH_LOCK* pFISH_LOCK; FIXFILENAME(pszFileDeleting); LockFishHang(); if (!GetThreadAndLockPtrs(&pFISH_THREAD,&pFISH_LOCK,lpCriticalSection)) FishHangAbort(pszFileDeleting,nLineDeleting); if (!bFishHangAtExit && pFISH_LOCK->nLockedDepth) { logmsg( "\n** ERROR ** FISH_THREAD %8.8X " "deleting still-locked FISH_LOCK %8.8X!\n", (int)pFISH_THREAD, (int)pFISH_LOCK ); if (pFISH_LOCK->pOwningThread != pFISH_THREAD) { logmsg( "** ERROR ** FISH_LOCK %8.8X " "owned by FISH_THREAD %8.8X!\n", (int)pFISH_LOCK, (int)pFISH_LOCK->pOwningThread ); } logmsg("%s(%d)\n\n",pszFileDeleting,nLineDeleting); logmsg("%s\n",PrintFISH_THREAD(pFISH_THREAD)); logmsg("%s\n",PrintFISH_LOCK(pFISH_LOCK)); } RemoveListEntry(&pFISH_LOCK->LockListLink); if (pFISH_LOCK->ThreadLockListLink.Flink) { RemoveListEntry(&pFISH_LOCK->ThreadLockListLink); } free(pFISH_LOCK); UnlockFishHang(); DeleteCriticalSection(lpCriticalSection); }
DEVTHREADPARMS* SelectDeviceThread() { DEVTHREADPARMS* pThreadParms; // ptr to selected device thread LIST_ENTRY* pListEntry; // (work) pListEntry = ThreadListHeadListEntry.Flink; while (pListEntry != &ThreadListHeadListEntry) { pThreadParms = CONTAINING_RECORD(pListEntry,DEVTHREADPARMS,ThreadListLinkingListEntry); LockThreadParms(pThreadParms); // (freeze moving target) if (pThreadParms->bThreadIsDead) { UnlockThreadParms(pThreadParms); RemoveThisThreadFromOurList(pThreadParms); pListEntry = ThreadListHeadListEntry.Flink; continue; } if (!IsEventSet(pThreadParms->hRequestQueuedEvent)) { RemoveListEntry(pListEntry); InsertListTail(&ThreadListHeadListEntry,pListEntry); return pThreadParms; } UnlockThreadParms(pThreadParms); // (can't use this one) pListEntry = pListEntry->Flink; } return NULL; // (all of them are busy) }
void RemoveThisThreadFromOurList(DEVTHREADPARMS* pThreadParms) { RemoveListEntry(&pThreadParms->ThreadListLinkingListEntry); MyCloseHandle(pThreadParms->hShutdownEvent); MyCloseHandle(pThreadParms->hRequestQueuedEvent); MyDeleteCriticalSection(&pThreadParms->IORequestListLock); free(pThreadParms); ios_devtnbr--; // (track number of active device_thread) }
DLL_EXPORT BOOL FishHang_CloseHandle // ** NOTE: only events for right now ** ( const char* pszFileClosed, // source file that closed it const int nLineClosed, // line number of source file HANDLE hEvent // handle to event object ) { FISH_THREAD* pThisFISH_THREAD; FISH_EVENT* pFISH_EVENT; LIST_ENTRY* pListEntry; FISH_THREAD* pWaitingFISH_THREAD; FIXFILENAME(pszFileClosed); LockFishHang(); if (!GetThreadAndEventPtrs(&pThisFISH_THREAD,&pFISH_EVENT,hEvent)) FishHangAbort(pszFileClosed,nLineClosed); pListEntry = ThreadsListHead.Flink; while (pListEntry != &ThreadsListHead) { pWaitingFISH_THREAD = CONTAINING_RECORD(pListEntry,FISH_THREAD,ThreadListLink); pListEntry = pListEntry->Flink; if (!pWaitingFISH_THREAD->bWaitingForEvent || pWaitingFISH_THREAD->pWhatWaiting != pFISH_EVENT) continue; logmsg( "\n** ERROR ** %s(%d); FISH_THREAD %8.8X " "is closing FISH_EVENT %8.8X " "that FISH_THREAD %8.8X is still waiting on!\n", pszFileClosed,nLineClosed,(int)pThisFISH_THREAD, (int)pFISH_EVENT, (int)pWaitingFISH_THREAD ); logmsg("\n%s\n%s\n%s\n", PrintFISH_THREAD(pThisFISH_THREAD), PrintFISH_EVENT(pFISH_EVENT), PrintFISH_THREAD(pWaitingFISH_THREAD) ); FishHangAbort(pszFileClosed,nLineClosed); } RemoveListEntry(&pFISH_EVENT->EventsListLink); free(pFISH_EVENT); UnlockFishHang(); return CloseHandle(hEvent); }
/*-------------------------------------------------------------------*/ DLL_EXPORT int hthread_destroy_rwlock( RWLOCK* plk, const char* location ) { int rc; ILOCK* ilk; UNREFERENCED( location ); ilk = (ILOCK*) plk->ilk; rc = hthread_rwlock_destroy( &ilk->rwlock ); LockLocksList(); RemoveListEntry( &ilk->locklink ); lockcount--; UnlockLocksList(); free_aligned( ilk ); plk->ilk = NULL; return rc; }
DLL_EXPORT void FishHang_ExitThread ( DWORD dwExitCode // exit code for this thread ) { FISH_THREAD* pFISH_THREAD; LIST_ENTRY* pListEntry; FISH_LOCK* pFISH_LOCK; LockFishHang(); if (!(pFISH_THREAD = FindFISH_THREAD(GetCurrentThreadId()))) { UnlockFishHang(); logmsg("** FishHang_ExitThread: FindFISH_THREAD failed!\n"); if (bFishHangAtExit) _endthreadex(dwExitCode); exit(-1); } // "If a thread terminates while it has ownership of a critical // section, the state of the critical section is undefined." if (!bFishHangAtExit && !IsListEmpty(&pFISH_THREAD->ThreadLockListHead)) { logmsg( "\n** ERROR ** FISH_THREAD %8.8X " "exiting with locks still owned!\n\n", (int)pFISH_THREAD); RemoveListEntry(&pFISH_THREAD->ThreadListLink); InsertListHead(&ThreadsListHead,&pFISH_THREAD->ThreadListLink); logmsg("%s\n",PrintFISH_THREAD(pFISH_THREAD)); pListEntry = pFISH_THREAD->ThreadLockListHead.Flink; while (pListEntry != &pFISH_THREAD->ThreadLockListHead) { pFISH_LOCK = CONTAINING_RECORD(pListEntry,FISH_LOCK,ThreadLockListLink); pListEntry = pListEntry->Flink; logmsg("%s\n",PrintFISH_LOCK(pFISH_LOCK)); } } UnlockFishHang(); _endthreadex(dwExitCode); }
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 unbind_device_ex (DEVBLK* dev, int forced) { bind_struct* bs; logdebug("unbind_device(%4.4X)\n", dev->devnum); /* Error if device not bound */ if (!(bs = dev->bs)) { logmsg (_("HHCSD005E Device %4.4X not bound to any socket\n"), dev->devnum); return 0; /* (failure) */ } /* Is anyone still connected? */ if (dev->fd != -1) { /* Yes. Should we forcibly disconnect them? */ if (forced) { /* Yes. Then do so... */ close_socket( dev->fd ); dev->fd = -1; logmsg (_("HHCSD025I Client %s (%s) disconnected from device %4.4X (%s)\n"), dev->bs->clientip, dev->bs->clientname, dev->devnum, dev->bs->spec); } else { /* No. Then fail the request. */ logmsg (_("HHCSD006E Client %s (%s) still connected to device %4.4X (%s)\n"), dev->bs->clientip, dev->bs->clientname, dev->devnum, dev->bs->spec); return 0; /* (failure) */ } } /* Remove the entry from our list */ obtain_lock( &bind_lock ); RemoveListEntry( &bs->bind_link ); SIGNAL_SOCKDEV_THREAD(); release_lock( &bind_lock ); logmsg (_("HHCSD007I Device %4.4X unbound from socket %s\n"), dev->devnum, bs->spec); if (bs->sd != -1) close_socket (bs->sd); /* Unchain device and bind_struct from each another */ dev->bs = NULL; bs->dev = NULL; /* Discard the entry */ if ( bs->clientname ) free( bs->clientname ); if ( bs->clientip ) free( bs->clientip ); bs->clientname = NULL; bs->clientip = NULL; free ( bs->spec ); free ( bs ); return 1; /* (success) */ }
/*-------------------------------------------------------------------*/ int bind_device_ex (DEVBLK* dev, char* spec, ONCONNECT fn, void* arg ) { bind_struct* bs; int was_list_empty; if (!init_done) init_sockdev(); if (sysblk.shutdown) return 0; logdebug("bind_device (%4.4X, %s)\n", dev->devnum, spec); /* Error if device already bound */ if (dev->bs) { logmsg (_("HHCSD001E Device %4.4X already bound to socket %s\n"), dev->devnum, dev->bs->spec); return 0; /* (failure) */ } /* Create a new bind_struct entry */ bs = malloc(sizeof(bind_struct)); if (!bs) { logmsg (_("HHCSD002E bind_device malloc() failed for device %4.4X\n"), dev->devnum); return 0; /* (failure) */ } memset(bs,0,sizeof(bind_struct)); bs->fn = fn; bs->arg = arg; if (!(bs->spec = strdup(spec))) { logmsg (_("HHCSD003E bind_device strdup() failed for device %4.4X\n"), dev->devnum); free (bs); return 0; /* (failure) */ } /* Create a listening socket */ if (bs->spec[0] == '/') bs->sd = unix_socket (bs->spec); else bs->sd = inet_socket (bs->spec); if (bs->sd == -1) { /* (error message already issued) */ free( bs->spec ); free( bs ); return 0; /* (failure) */ } /* Chain device and bind_struct to each other */ dev->bs = bs; bs->dev = dev; /* Add the new entry to our list of bound devices and create the socket thread that will listen for connections (if it doesn't already exist) */ obtain_lock( &bind_lock ); was_list_empty = IsListEmpty( &bind_head ); InsertListTail( &bind_head, &bs->bind_link ); if ( was_list_empty ) { if ( create_thread( &sysblk.socktid, JOINABLE, socket_thread, NULL, "socket_thread" ) ) { logmsg( _( "HHCSD023E Cannot create socketdevice thread: errno=%d: %s\n" ), errno, strerror( errno ) ); RemoveListEntry( &bs->bind_link ); close_socket(bs->sd); free( bs->spec ); free( bs ); release_lock( &bind_lock ); return 0; /* (failure) */ } } SIGNAL_SOCKDEV_THREAD(); release_lock( &bind_lock ); logmsg (_("HHCSD004I Device %4.4X bound to socket %s\n"), dev->devnum, dev->bs->spec); return 1; /* (success) */ }
/*-------------------------------------------------------------------*/ int unbind_device_ex (DEVBLK* dev, int forced) { bind_struct* bs; logdebug("unbind_device(%4.4X)\n", dev->devnum); /* Error if device not bound */ if (!(bs = dev->bs)) { WRMSG (HHC01043, "E", SSID_TO_LCSS(dev->ssid), dev->devnum); return 0; /* (failure) */ } /* Is anyone still connected? */ if (dev->fd != -1) { /* Yes. Should we forcibly disconnect them? */ if (forced) { /* Yes. Then do so... */ close_socket( dev->fd ); dev->fd = -1; WRMSG (HHC01044, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->bs->clientip, dev->bs->clientname, dev->bs->spec); } else { /* No. Then fail the request. */ WRMSG (HHC01045, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->bs->clientip, dev->bs->clientname, dev->bs->spec); return 0; /* (failure) */ } } /* Remove the entry from our list */ obtain_lock( &bind_lock ); RemoveListEntry( &bs->bind_link ); SIGNAL_SOCKDEV_THREAD(); release_lock( &bind_lock ); WRMSG (HHC01046, "I",SSID_TO_LCSS(dev->ssid), dev->devnum, bs->spec); if (bs->sd != -1) close_socket (bs->sd); /* Unchain device and bind_struct from each another */ dev->bs = NULL; bs->dev = NULL; /* Discard the entry */ if ( bs->clientname ) free( bs->clientname ); if ( bs->clientip ) free( bs->clientip ); bs->clientname = NULL; bs->clientip = NULL; free ( bs->spec ); free ( bs ); return 1; /* (success) */ }
/*-------------------------------------------------------------------*/ int bind_device_ex (DEVBLK* dev, char* spec, ONCONNECT fn, void* arg ) { bind_struct* bs; int was_list_empty; int rc; if (!init_done) init_sockdev(); if (sysblk.shutdown) return 0; logdebug("bind_device (%4.4X, %s)\n", dev->devnum, spec); /* Error if device already bound */ if (dev->bs) { WRMSG (HHC01041, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->bs->spec); return 0; /* (failure) */ } /* Create a new bind_struct entry */ bs = malloc(sizeof(bind_struct)); if (!bs) { char buf[40]; MSGBUF( buf, "malloc(%d)", (int)sizeof(bind_struct)); WRMSG (HHC01000, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, buf, strerror(errno)); return 0; /* (failure) */ } memset(bs, 0, sizeof(bind_struct)); bs->fn = fn; bs->arg = arg; if (!(bs->spec = strdup(spec))) { WRMSG (HHC01000, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "strdup()", strerror(errno) ); free (bs); return 0; /* (failure) */ } /* Create a listening socket */ if (bs->spec[0] == '/') bs->sd = unix_socket (bs->spec); else bs->sd = inet_socket (bs->spec); if (bs->sd == -1) { /* (error message already issued) */ free( bs->spec ); free( bs ); return 0; /* (failure) */ } /* Chain device and bind_struct to each other */ dev->bs = bs; bs->dev = dev; /* Add the new entry to our list of bound devices and create the socket thread that will listen for connections (if it doesn't already exist) */ obtain_lock( &bind_lock ); was_list_empty = IsListEmpty( &bind_head ); InsertListTail( &bind_head, &bs->bind_link ); if ( was_list_empty ) { rc = create_thread( &sysblk.socktid, JOINABLE, socket_thread, NULL, "socket_thread" ); if (rc) { WRMSG(HHC00102, "E", strerror( rc ) ); RemoveListEntry( &bs->bind_link ); close_socket(bs->sd); free( bs->spec ); free( bs ); release_lock( &bind_lock ); return 0; /* (failure) */ } } SIGNAL_SOCKDEV_THREAD(); release_lock( &bind_lock ); WRMSG (HHC01042, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->bs->spec); return 1; /* (success) */ }