void ThreadPrivate::destroyFunc(void* arg) { #ifdef DEBUG Debugger debug("ThreadPrivate::destroyFunc","(%p)",arg); #endif ThreadPrivate *t = reinterpret_cast<ThreadPrivate *>(arg); if (t) t->destroy(); }
void* ThreadPrivate::startFunc(void* arg) #endif { DDebug(DebugAll,"ThreadPrivate::startFunc(%p)",arg); ThreadPrivate *t = reinterpret_cast<ThreadPrivate *>(arg); t->run(); #ifdef _WINDOWS t->m_running = false; if (t->m_updest) t->destroy(); #else return 0; #endif }
void Thread::exit() { DDebug(DebugAll,"Thread::exit()"); ThreadPrivate* t = ThreadPrivate::current(); if (t && t->m_thread && t->m_thread->locked()) Alarm("engine","bug",DebugFail,"Thread::exit() in '%s' with mutex locks (%d held) [%p]", t->m_name,t->m_thread->locks(),t->m_thread); #ifdef _WINDOWS if (t) { t->m_running = false; t->destroy(); } ::_endthread(); #else ::pthread_exit(0); #endif }
void ThreadPrivate::killall() { Debugger debug("ThreadPrivate::killall()"); ThreadPrivate *t; bool sledgehammer = false; s_tmutex.lock(); ThreadPrivate* crt = ThreadPrivate::current(); int c = s_threads.count(); if (crt) Debug(DebugNote,"Thread '%s' is soft cancelling other %d running threads",crt->m_name,c-1); else Debug(DebugNote,"Soft cancelling %d running threads",c); ObjList* l = &s_threads; while (l && (t = static_cast<ThreadPrivate *>(l->get())) != 0) { if (t != crt) { Debug(DebugInfo,"Stopping ThreadPrivate '%s' [%p]",t->m_name,t); t->cancel(false); } l = l->next(); } for (int w = 0; w < SOFT_WAITS; w++) { s_tmutex.unlock(); Thread::idle(); s_tmutex.lock(); c = s_threads.count(); // ignore the current thread if we have one if (crt && c) c--; if (!c) { s_tmutex.unlock(); return; } } Debug(DebugMild,"Hard cancelling %d remaining threads",c); l = &s_threads; c = 1; while (l && (t = static_cast<ThreadPrivate *>(l->get())) != 0) { if (t == crt) { l = l->next(); continue; } Debug(DebugInfo,"Trying to kill ThreadPrivate '%s' [%p], attempt %d",t->m_name,t,c); bool ok = t->cancel(true); if (ok) { int d = 0; // delay a little (exponentially) so threads have a chance to clean up for (int i=1; i<=KILL_WAIT; i<<=1) { s_tmutex.unlock(); Thread::msleep(i-d); d = i; s_tmutex.lock(); if (t != l->get()) break; } } if (t != l->get()) c = 1; else { if (ok) { #ifdef _WINDOWS Debug(DebugGoOn,"Could not kill %p but seems OK to delete it (library bug?)",t); s_tmutex.unlock(); t->destroy(); s_tmutex.lock(); if (t != l->get()) c = 1; #else Debug(DebugGoOn,"Could not kill cancelled %p so we'll abandon it (library bug?)",t); l->remove(t,false); c = 1; #endif continue; } Thread::msleep(1); if (++c >= HARD_KILLS) { Debug(DebugGoOn,"Could not kill %p, will use sledgehammer later.",t); sledgehammer = true; t->m_thread = 0; l = l->next(); c = 1; } } } s_tmutex.unlock(); // last solution - a REALLY BIG tool! // usually too big since many libraries have threads of their own... if (sledgehammer) { #ifdef THREAD_KILL Debug(DebugGoOn,"Brutally killing remaining threads!"); ::pthread_kill_other_threads_np(); #else Debug(DebugGoOn,"Aargh! I cannot kill remaining threads on this platform!"); #endif } }
ThreadPrivate* ThreadPrivate::create(Thread* t,const char* name,Thread::Priority prio) { ThreadPrivate *p = new ThreadPrivate(t,name); int e = 0; #ifndef _WINDOWS // Set a decent (256K) stack size that won't eat all virtual memory pthread_attr_t attr; ::pthread_attr_init(&attr); ::pthread_attr_setstacksize(&attr, 16*PTHREAD_STACK_MIN); if (prio > Thread::Normal) { struct sched_param param; param.sched_priority = 0; int policy = SCHED_OTHER; switch (prio) { case Thread::High: policy = SCHED_RR; param.sched_priority = 1; break; case Thread::Highest: policy = SCHED_FIFO; param.sched_priority = 99; break; default: break; } int err = ::pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED); if (!err) err = ::pthread_attr_setschedpolicy(&attr,policy); if (!err) err = ::pthread_attr_setschedparam(&attr,¶m); if (err) Debug( #ifdef DEBUG DebugWarn, #else DebugNote, #endif "Could not set thread scheduling parameters: %s (%d)", strerror(err),err); #ifdef XDEBUG else Debug(DebugInfo,"Successfully set high thread priority %d",prio); #endif } #endif /* _WINDOWS */ for (int i=0; i<5; i++) { #ifdef _WINDOWS HTHREAD t = ::_beginthread(startFunc,16*PTHREAD_STACK_MIN,p); e = (t == (HTHREAD)-1) ? errno : 0; if (!e) { p->thread = t; int pr = THREAD_PRIORITY_NORMAL; switch (prio) { case Thread::Lowest: pr = THREAD_PRIORITY_LOWEST; break; case Thread::Low: pr = THREAD_PRIORITY_BELOW_NORMAL; break; case Thread::High: pr = THREAD_PRIORITY_ABOVE_NORMAL; break; case Thread::Highest: pr = THREAD_PRIORITY_HIGHEST; break; default: break; } if (pr != THREAD_PRIORITY_NORMAL) ::SetThreadPriority(reinterpret_cast<HANDLE>(t),pr); } #else /* _WINDOWS */ e = ::pthread_create(&p->thread,&attr,startFunc,p); #ifdef PTHREAD_INHERIT_SCHED if ((0 == i) && (EPERM == e) && (prio > Thread::Normal)) { Debug(DebugWarn,"Failed to create thread with priority %d, trying with inherited",prio); ::pthread_attr_setinheritsched(&attr,PTHREAD_INHERIT_SCHED); e = EAGAIN; } #endif #endif /* _WINDOWS */ if (e != EAGAIN) break; Thread::usleep(20); } #ifndef _WINDOWS ::pthread_attr_destroy(&attr); #endif if (e) { Alarm("engine","system",DebugGoOn,"Error %d while creating pthread in '%s' [%p]",e,name,p); p->m_thread = 0; p->destroy(); return 0; } p->m_running = true; return p; }