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