isearch/comm/thread.cc
2021-03-19 18:38:34 +08:00

260 lines
4.7 KiB
C++

/* : set sw=8 ai fdm=marker fmr={,} :*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sched.h>
#include "thread.h"
#include "memcheck.h"
#include "log.h"
#include <sched.h>
__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);