1// excerpts from http://code.google.com/p/muduo/ 2// 3// Use of this source code is governed by a BSD-style license 4// that can be found in the License file. 5// 6// Author: Shuo Chen (giantchen at gmail dot com) 7 8#include "Thread.h" 9 10#include <boost/weak_ptr.hpp> 11 12#include <unistd.h> 13#include <sys/syscall.h> 14#include <sys/types.h> 15 16#if __FreeBSD__ 17#include <pthread_np.h> 18#else 19#include <sys/prctl.h> 20#include <linux/unistd.h> 21#endif 22 23namespace muduo 24{ 25namespace CurrentThread 26{ 27 __thread const char* t_threadName = "unnamedThread"; 28} 29} 30 31namespace 32{ 33__thread pid_t t_cachedTid = 0; 34 35#if __FreeBSD__ 36pid_t gettid() 37{ 38 return pthread_getthreadid_np(); 39} 40#else 41#if !__GLIBC_PREREQ(2,30) 42pid_t gettid() 43{ 44 return static_cast<pid_t>(::syscall(SYS_gettid)); 45} 46#endif 47#endif 48 49void afterFork() 50{ 51 t_cachedTid = gettid(); 52 muduo::CurrentThread::t_threadName = "main"; 53 // no need to call pthread_atfork(NULL, NULL, &afterFork); 54} 55 56class ThreadNameInitializer 57{ 58 public: 59 ThreadNameInitializer() 60 { 61 muduo::CurrentThread::t_threadName = "main"; 62 pthread_atfork(NULL, NULL, &afterFork); 63 } 64}; 65 66ThreadNameInitializer init; 67 68struct ThreadData 69{ 70 typedef muduo::Thread::ThreadFunc ThreadFunc; 71 ThreadFunc func_; 72 std::string name_; 73 boost::weak_ptr<pid_t> wkTid_; 74 75 ThreadData(const ThreadFunc& func, 76 const std::string& name, 77 const boost::shared_ptr<pid_t>& tid) 78 : func_(func), 79 name_(name), 80 wkTid_(tid) 81 { } 82 83 void runInThread() 84 { 85 pid_t tid = muduo::CurrentThread::tid(); 86 boost::shared_ptr<pid_t> ptid = wkTid_.lock(); 87 88 if (ptid) 89 { 90 *ptid = tid; 91 ptid.reset(); 92 } 93 94 if (!name_.empty()) 95 muduo::CurrentThread::t_threadName = name_.c_str(); 96#if __FreeBSD__ 97 // setname_np() costs as much as creating a thread on FreeBSD 13. 98 pthread_setname_np(pthread_self(), muduo::CurrentThread::t_threadName); 99#else 100 ::prctl(PR_SET_NAME, muduo::CurrentThread::t_threadName); 101#endif 102 func_(); // FIXME: surround with try-catch, see muduo 103 muduo::CurrentThread::t_threadName = "finished"; 104 } 105}; 106 107void* startThread(void* obj) 108{ 109 ThreadData* data = static_cast<ThreadData*>(obj); 110 data->runInThread(); 111 delete data; 112 return NULL; 113} 114 115} 116 117using namespace muduo; 118 119pid_t CurrentThread::tid() 120{ 121 if (t_cachedTid == 0) 122 { 123 t_cachedTid = gettid(); 124 } 125 return t_cachedTid; 126} 127 128const char* CurrentThread::name() 129{ 130 return t_threadName; 131} 132 133bool CurrentThread::isMainThread() 134{ 135 return tid() == ::getpid(); 136} 137 138AtomicInt32 Thread::numCreated_; 139 140Thread::Thread(const ThreadFunc& func, const std::string& n) 141 : started_(false), 142 joined_(false), 143 pthreadId_(0), 144 tid_(new pid_t(0)), 145 func_(func), 146 name_(n) 147{ 148 numCreated_.increment(); 149} 150 151Thread::~Thread() 152{ 153 if (started_ && !joined_) 154 { 155 pthread_detach(pthreadId_); 156 } 157} 158 159void Thread::start() 160{ 161 assert(!started_); 162 started_ = true; 163 164 ThreadData* data = new ThreadData(func_, name_, tid_); 165 if (pthread_create(&pthreadId_, NULL, &startThread, data)) 166 { 167 started_ = false; 168 delete data; 169 abort(); 170 } 171} 172 173void Thread::join() 174{ 175 assert(started_); 176 assert(!joined_); 177 joined_ = true; 178 pthread_join(pthreadId_, NULL); 179} 180