/* : set sw=8 ai fdm=marker fmr={,} :*/ #include #include #include #include #include #include "thread.h" #include "memcheck.h" #include "log.h" #include __attribute__((__weak__)) volatile extern int stop; CThread::thread_map_t CThread::_thread_map; pthread_mutex_t CThread::_thread_map_lock = PTHREAD_MUTEX_INITIALIZER; CThread * CThread::FindThreadByName(const char *name) { CThread::LOCK_THREAD_MAP(); thread_map_t::const_iterator i = _thread_map.find(name); CThread *ret = i == _thread_map.end() ? NULL : i->second; CThread::UNLOCK_THREAD_MAP(); return ret; } __attribute__((__weak__)) void DaemonCrashed(int); #if HAS_TLS static __thread CThread *currentThread __TLS_MODEL; extern "C" void CrashHook(int signo) { if(currentThread != NULL) currentThread->CrashHook(signo); } #endif void *CThread::Entry (void *thread) { CThread *my = (CThread *)thread; my->PrepareInternal(); void *ret = my->Process(); my->Cleanup(); return ret; } CThread::CThread (const char *name, int type) { tid = 0; pid = 0; tasktype = type; taskname = STRDUP(name); stacksize = 0; cpumask = 0; stopped = 0; stopPtr = &stopped; pthread_mutex_init (&runlock, NULL); CThread::LOCK_THREAD_MAP(); _thread_map[taskname] = this; CThread::UNLOCK_THREAD_MAP(); } CThread::~CThread () { pthread_mutex_destroy (&runlock); FREE_IF(taskname); } void CThread::SetStackSize(int size) { if(size < 0) // default size size = 0; else if(size > 64<<20) // max 64M size = 64<<20; // round to 64K if((size & 0xFFFF) != 0) size = (size & ~0xFFFF) + 0x10000; stacksize = size; } CAutoConfig *CThread::g_autoconf = NULL; void CThread::AutoConfigStackSize(void) { unsigned long long size = g_autoconf->GetSizeVal("ThreadStackSize", taskname, stacksize, 'M'); if(size > (1<<30)) size = 1<<30; SetStackSize((int)size); log_debug("autoconf thread %s ThreadStackSize %d", taskname, stacksize); } void CThread::AutoConfigCPUMask(void) { #ifdef CPU_ZERO const char *val = g_autoconf->GetStrVal("ThreadCPUMask", taskname); if(val != NULL) { cpumask = strtoll(val, NULL, 16); } log_debug("autoconf thread %s ThreadCPUMask %llx", taskname, (unsigned long long)cpumask); #endif } void CThread::AutoConfig(void) { if(g_autoconf) { switch(tasktype) { case ThreadTypeSync: case ThreadTypeAsync: AutoConfigStackSize(); break; default: break; } AutoConfigCPUMask(); //AutoConfigRemoteLog(); } } int CThread::InitializeThread (void) { int ret = Initialize(); if(ret < 0) return -1; switch(tasktype) { case 0: // main tid = pthread_self (); AutoConfig(); #ifdef CPU_ZERO if(cpumask != 0) { uint64_t temp[2] = {cpumask, 0}; sched_setaffinity(pid, sizeof(temp), (cpu_set_t *)&temp); } #endif break; case -1: // world class tid = 0; break; case 1: // async case 2: // sync AutoConfig(); pthread_mutex_lock (&runlock); pthread_attr_t attr; pthread_attr_init(&attr); if(stacksize) { pthread_attr_setstacksize(&attr, stacksize); } pthread_create (&tid, &attr, Entry, this); break; } return 0; } void CThread::RunningThread () { switch(tasktype) { case -1: // error return; case 0: stopPtr = &stop; PrepareInternal(); Process(); Cleanup(); break; case 1: case 2: pthread_mutex_unlock (&runlock); break; } } void CThread::PrepareInternal (void) { pid = gettid(); log_info("thread %s[%d] started", taskname, pid); sigset_t sset; sigemptyset(&sset); sigaddset(&sset, SIGTERM); pthread_sigmask(SIG_BLOCK, &sset, &sset); #ifdef CPU_ZERO if(cpumask != 0) { uint64_t temp[2] = {cpumask, 0}; sched_setaffinity(pid, sizeof(temp), (cpu_set_t *)&temp); } #endif Prepare(); pthread_mutex_lock (&runlock); #if HAS_TLS currentThread = this; #endif } void CThread::interrupt (void) { if(this==NULL || stopped || !tid) return; int ret; stopped = 1; if (tasktype > 0) { //pthread_kill (tid, SIGINT); pthread_mutex_unlock (&runlock); if ((ret=pthread_join(tid, 0)) != 0) { log_warning("Thread [%s] join failed %d.", Name(), ret); } else { log_info("Thread [%s] stopped.", Name()); } } } int CThread::Initialize (void) { return 0; } void CThread::Prepare (void) { } void * CThread::Process (void) { while(!Stopping()) pause(); return NULL; } void CThread::Cleanup (void) { } void CThread::CrashHook (int signo) { // mark mine is stopped this->stopped = 1; // global stopping if(&DaemonCrashed != 0) { DaemonCrashed(signo); } log_crit("Ouch......, I crashed, hang and stopping server"); pthread_exit(NULL); while(1) pause(); } CThread CThread::TheWorldThread("world", CThread::ThreadTypeWorld);