We ran into this while chasing an interface binding error (for some reason tftpd32 is starting the tftp server thread when the interface is unavailable on our Windows 7 boxes). When we started the tftpd32 service with the network jack disconnected, the service would use up a full core's CPU at real time priority, making the keyboard very slow to respond among other problems. On a single core cpu, this could really be bad. It turns out that the "scheduler" thread would continuously loop if a thread it was monitoring ended unexpectedly.
I ended up putting several patches into the scheduler thread while I was tracking this down, adding some error handling on the thread monitoring, reducing the thread priority from real time, and possibly fixing a gui update bug.
in start_threads.c:
void Scheduler (void *param) { unsigned int Ark; unsigned int Rc; int waitIndex; HANDLE tHdle[TH_NUMBER]; unsigned int nCount; int nTime=1000; // Increase thread priority in order to return asap in the Wait function SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); tThreads [TH_SCHEDULER].bInit = TRUE; // inits OK do { tHdle[0] = tThreads [TH_SCHEDULER].hEv; for ( Ark=0, nCount=1 ; Ark<TH_NUMBER ; Ark++ ) if (tThreads [Ark].gRunning) tHdle[nCount++] = tThreads [Ark].tTh; // wake up every 30 seconds waitIndex = -1; Rc = WaitForMultipleObjects (nCount, tHdle, FALSE, 30000); if (Rc == WAIT_TIMEOUT) PoolNetworkInterfaces (); // so not trigger messages to GUI else if (Rc == WAIT_FAILED) LogToMonitor ("Scheduler wait returns %d (error %d - %s)\n", Rc, GetLastError (), LastErrorText()); else if ( Rc - WAIT_OBJECT_0 < nCount && Rc - WAIT_OBJECT_0 >= 0 ) waitIndex = Rc - WAIT_OBJECT_0; else LogToMonitor ("Scheduler wait returns invalid index %d\n", Rc); // a process has terminated if ( waitIndex >= 0 ) { struct S_Chg_Service chgmsg; // thread itself is signalled, since the number of service has changed if (waitIndex == 0) { LogToMonitor ("Scheduler signal received"); ResetEvent (tThreads[TH_SCHEDULER].hEv); // was tThreads[Ark].hEv; this should work better PoolNetworkInterfaces (); // GUI has waked up this thread, send it fresh info continue; } for ( Ark=0 ; Ark<SizeOfTab(tThreads) && tHdle[waitIndex]!=tThreads [Ark].tTh ; Ark++ ); if (Ark>=SizeOfTab(tThreads)) continue; LogToMonitor ("process %s has terminated\n", tThreadsConfig[Ark].name); // free resources allocated by StartSingleWorkerThread FreeThreadResources (Ark); if (tThreadsConfig [Ark].gui) { // change display : ie add its tab in the GUI chgmsg.service = tThreadsConfig [Ark].serv_mask; chgmsg.status = SERVICE_STOPPED; SendMsgRequest (C_CHG_SERVICE,& chgmsg, sizeof chgmsg, FALSE, FALSE ); } // wait since uServices may be changed by Console thread !! if ( tThreadsConfig [Ark].restart && sSettings.uServices & tThreadsConfig [Ark].serv_mask && tThreads [Ark].gRunning ) StartSingleWorkerThread (Ark); else tThreads[Ark].gRunning = FALSE; } // WAitMultipleObject else Sleep(1000); } while ( tThreads[TH_SCHEDULER].gRunning ); LogToMonitor ("end of ip pooling thread\n"); _endthread (); } // ListIPInterfaces