📄 thread.cpp
字号:
{#ifdef WIN32 Thread::sleep(1); // note: on Win32, Sleep(0) is "optimized" to NOP.#else#ifdef CCXX_SIG_THREAD_CANCEL Thread* th = getThread(); sigset_t cancel, old; sigemptyset(&cancel); sigaddset(&cancel, CCXX_SIG_THREAD_CANCEL); if(th && th->_cancel != cancelDisabled && th->_cancel != cancelInitial) pthread_sigmask(SIG_UNBLOCK, &cancel, &old);#else pthread_testcancel();#endif#ifdef HAVE_PTHREAD_YIELD pthread_yield();#endif#ifdef CCXX_SIG_THREAD_CANCEL if(th && th->_cancel != cancelDisabled && th->_cancel != cancelInitial) pthread_sigmask(SIG_SETMASK, &old, NULL);#endif#endif // WIN32}void Thread::setException(Thread::Throw mode){ Thread *thread = getThread(); thread->priv->_throw = mode;}Thread::Throw Thread::getException(void){ Thread *thread = getThread(); return thread->priv->_throw;}Cancellation::Cancellation(Thread::Cancel cancel){ Thread *thread = getThread(); if(!thread) return; prior = thread->getCancel(); thread->setCancel(cancel);}Cancellation::~Cancellation(){ Thread *thread = getThread(); if(!thread) return; thread->setCancel(prior);}bool Thread::testCancel(void){#ifdef WIN32 switch(_cancel) { case cancelInitial: case cancelDisabled: break; default: if(WaitForSingleObject(priv->_cancellation, 0) == WAIT_OBJECT_0) { if (_cancel == cancelManual) THROW(InterruptException()); else exit(); } } return false;#else // WIN32#ifdef CCXX_SIG_THREAD_CANCEL sigset_t cancel, old; sigemptyset(&cancel); sigaddset(&cancel, CCXX_SIG_THREAD_CANCEL); if(_cancel != cancelDisabled && _cancel != cancelInitial) pthread_sigmask(SIG_UNBLOCK, &cancel, &old);#else pthread_testcancel();#endif #ifdef CCXX_SIG_THREAD_CANCEL if(_cancel != cancelDisabled) pthread_sigmask(SIG_SETMASK, &old, NULL);#endif return false;#endif // WIN32} #ifdef WIN32bool Thread::isCancelled(){ return waitThread(priv->_cancellation, 0) == WAIT_OBJECT_0;}DWORD Thread::waitThread(HANDLE hRef, timeout_t timeout){ Thread *th = getThread(); if(th) return th->waitHandle(hRef, timeout); else return WaitForSingleObject(hRef, timeout);}void Thread::sleep(timeout_t timeout) { Thread *th = getThread(); if(!th) { SleepEx(timeout, FALSE); return; } switch(th->_cancel) { case cancelInitial: case cancelDisabled: SleepEx(timeout, FALSE); break; default: if(WaitForSingleObject(th->priv->_cancellation, timeout) == WAIT_OBJECT_0) { if (th->_cancel == cancelManual) THROW(InterruptException()); else th->exit(); } }}DWORD Thread::waitHandle(HANDLE obj, timeout_t timeout) { HANDLE objects[2]; DWORD stat; objects[0] = priv->_cancellation; objects[1] = obj; // FIXME: what should happen if someone enable cancellation on wait?? switch(_cancel) { case cancelInitial: case cancelDisabled: return WaitForSingleObject(obj, timeout); default: switch(stat = WaitForMultipleObjects(2, objects, false, timeout)) { case WAIT_OBJECT_0: if (_cancel == cancelManual) THROW(InterruptException()); else exit(); case WAIT_OBJECT_0 + 1: return WAIT_OBJECT_0; default: return stat; } }}// Entry point linked for default disable thread call, not suitable// for threading library...BOOL WINAPI DllMain( HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved ){ switch(dwReason) { case DLL_THREAD_DETACH: DummyThread::CheckDelete(); break; } return TRUE ;}#endif // WIN32#ifndef WIN32Thread *Thread::get(void){ Thread *thread; // fix strange no-init on Solaris if(!Thread::_main) { new (&_mainthread) MainThread(); return &_mainthread; } thread = (Thread *)ThreadImpl::_self.getKey(); // class have been deleted, return NULL if (thread == DUMMY_INVALID_THREAD) return NULL; if(!thread) { // this Thread will be deleted by ccxx_thread_destruct thread = new DummyThread; ThreadImpl::_self.setKey(thread); } return thread;}#else // WIN32Thread *Thread::get(void){ Thread *th = (Thread *)_self.getKey(); if (th == DUMMY_INVALID_THREAD) return NULL; // for no common c++ thread construct a dummy thread if (!th) th = new DummyThread(); return th;}unsigned __stdcall Thread::Execute(Thread *th){ _self.setKey(th); th->yield(); if(th->_start) { th->_start->wait(); th->_start = NULL; } try { th->priv->_tid = GetCurrentThreadId(); if(!th->_name[0]) snprintf(th->_name, sizeof(th->_name), "%d", GetCurrentThreadId()); th->initial(); if(th->getCancel() == cancelInitial) th->setCancel(cancelDefault); th->run(); } // ignore cancellation exception catch(const InterruptException&) { ; } th->close(); return 0;}#endif //WIN32#if !defined(WIN32)/* * PosixThread implementation */inline void ThreadImpl::PosixThreadSigHandler(int signo){ Thread *t = getThread(); PosixThread *th = NULL;#ifdef CCXX_EXCEPTIONS if (t) th = dynamic_cast<PosixThread*>(t);#else if (t) th = (PosixThread*)(t);#endif if (!th) return; switch(signo) { case SIGHUP: if(th) th->onHangup(); break; case SIGABRT: if(th) th->onException(); break; case SIGPIPE: if(th) th->onDisconnect(); break; case SIGALRM:#ifndef CCXX_SIG_THREAD_ALARM if(PosixThread::_timer) { PosixThread::_timer->_alarm = 0; PosixThread::_timer->onTimer(); } else#endif if(th) th->onTimer(); break;#ifdef SIGPOLL case SIGPOLL:#else case SIGIO:#endif if(th) th->onPolling(); break; default: if(th) th->onSignal(signo); }}static void ccxx_sig_handler(int signo){ ThreadImpl::PosixThreadSigHandler(signo);}PosixThread::PosixThread(int pri, size_t stack): Thread(pri,stack){ SysTime::getTime(&_alarm);}void PosixThread::onTimer(void){}void PosixThread::onHangup(void){}void PosixThread::onException(void){}void PosixThread::onDisconnect(void){}void PosixThread::onPolling(void){}void PosixThread::onSignal(int sig){}void PosixThread::setTimer(timeout_t timer, bool periodic){ sigset_t sigs;#ifdef HAVE_SETITIMER struct itimerval itimer; memset(&itimer, 0, sizeof(itimer)); itimer.it_value.tv_usec = (timer * 1000) % 1000000; itimer.it_value.tv_sec = timer / 1000; if (periodic) { itimer.it_interval.tv_usec = itimer.it_value.tv_usec; itimer.it_interval.tv_sec = itimer.it_value.tv_sec; }#else timer /= 1000;#endif#ifndef CCXX_SIG_THREAD_ALARM _arm.enterMutex(); _timer = this;#endif SysTime::getTime(&_alarm); sigemptyset(&sigs); sigaddset(&sigs, SIGALRM); pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);#ifdef HAVE_SETITIMER setitimer(ITIMER_REAL, &itimer, NULL);#else alarm(timer);#endif} timeout_t PosixThread::getTimer(void) const{#ifdef HAVE_SETITIMER struct itimerval itimer;#endif if(!_alarm) return 0;#ifdef HAVE_SETITIMER getitimer(ITIMER_REAL, &itimer); return (timeout_t)(itimer.it_value.tv_sec * 1000 + itimer.it_value.tv_usec / 1000);#else time_t now = SysTime::getTime(); return (timeout_t)(((now - _alarm) * 1000) + 500);#endif}void PosixThread::endTimer(void){#ifdef HAVE_SETITIMER static const struct itimerval itimer = {{0, 0},{0,0}};#endif sigset_t sigs;#ifndef CCXX_SIG_THREAD_ALARM if(_timer != this) return;#endif#ifdef HAVE_SETITIMER setitimer(ITIMER_REAL, (struct itimerval *)&itimer, NULL);#else alarm(0);#endif sigemptyset(&sigs); sigaddset(&sigs, SIGALRM); pthread_sigmask(SIG_BLOCK, &sigs, NULL);#ifndef CCXX_SIG_THREAD_ALARM _arm.leaveMutex(); _timer = NULL;#endif}#if defined(HAVE_SIGWAIT) || defined(HAVE_SIGWAIT2)void PosixThread::waitSignal(signo_t signo){ sigset_t mask; sigemptyset(&mask); sigaddset(&mask, signo);#ifndef HAVE_SIGWAIT2 signo = sigwait(&mask);#else sigwait(&mask, &signo);#endif}#endif // ifdef HAVE_SIGWAITvoid PosixThread::setSignal(int signo, bool mode){ sigset_t sigs; sigemptyset(&sigs); sigaddset(&sigs, signo); if(mode) pthread_sigmask(SIG_UNBLOCK, &sigs, NULL); else pthread_sigmask(SIG_BLOCK, &sigs, NULL);} void PosixThread::signalThread(Thread* th,signo_t signo){ pthread_kill(th->priv->_tid, signo);}pthread_attr_t * PosixThread::getPthreadAttrPtr(void){ return &priv->_attr;}pthread_t PosixThread::getPthreadId(void){ return priv->_tid;}void PosixThread::sigInstall(int signo){ struct sigaction act; act.sa_handler = (signalexec_t)&ccxx_sig_handler; sigemptyset(&act.sa_mask);#ifdef SA_INTERRUPT act.sa_flags = SA_INTERRUPT;#else act.sa_flags = 0;#endif sigaction(signo, &act, NULL);}#endif#ifdef USE_POLLPoller::Poller(){ nufds = 0; ufds = NULL;}Poller::~Poller(){ if(ufds) { delete[] ufds; ufds = NULL; }}pollfd *Poller::getList(int cnt){ if(nufds < cnt) { if(ufds) delete[] ufds; ufds = new pollfd[cnt]; nufds = cnt; } return ufds;}#endifMutex SysTime::timeLock;time_t SysTime::getTime(time_t *tloc) { time_t ret; lock(); time_t temp;#ifdef WIN32 ::time(&temp);#else std::time(&temp);#endif memcpy(&ret, &temp, sizeof(time_t)); if (tloc != NULL) memcpy(tloc, &ret, sizeof(time_t)); unlock(); return ret; }int SysTime::getTimeOfDay(struct timeval *tp) { struct timeval temp; int ret(0); lock();#ifdef WIN32 // We could use _ftime(), but it is not available on WinCE. // (WinCE also lacks time.h) // Note also that the average error of _ftime is around 20 ms :) time(&temp.tv_sec); temp.tv_usec = (GetTickCount() % 1000) * 1000; memcpy(tp, &temp, sizeof(struct timeval));#else ret = ::gettimeofday(&temp, NULL); if (ret == 0) memcpy(tp, &temp, sizeof(struct timeval));#endif unlock(); return ret;}struct tm *SysTime::getLocalTime(const time_t *clock, struct tm* result) { lock();#ifdef WIN32 struct tm *temp = ::localtime(clock);#else struct tm *temp = std::localtime(clock);#endif memcpy(result, temp, sizeof(struct tm)); unlock(); return result;}struct tm *SysTime::getGMTTime(const time_t *clock, struct tm* result) { lock();#ifdef WIN32 struct tm *temp = ::gmtime(clock);#else struct tm *temp = std::gmtime(clock);#endif memcpy(result, temp, sizeof(struct tm)); unlock(); return result;}// C stuff// this function must declared as extern "C" for some compiler#ifdef CCXX_NAMESPACES}#endif /** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -