1cd139dc7SShuo Chen// excerpts from http://code.google.com/p/muduo/
2cd139dc7SShuo Chen//
3cd139dc7SShuo Chen// Use of this source code is governed by a BSD-style license
4cd139dc7SShuo Chen// that can be found in the License file.
5cd139dc7SShuo Chen//
6cd139dc7SShuo Chen// Author: Shuo Chen (giantchen at gmail dot com)
7cd139dc7SShuo Chen
8cd139dc7SShuo Chen#include "Thread.h"
9cd139dc7SShuo Chen
102b2bf878SShuo Chen#include <boost/weak_ptr.hpp>
112b2bf878SShuo Chen
12cd139dc7SShuo Chen#include <unistd.h>
13cd139dc7SShuo Chen#include <sys/syscall.h>
14cd139dc7SShuo Chen#include <sys/types.h>
15b9b67c9bSShuo Chen
16b9b67c9bSShuo Chen#if __FreeBSD__
17b9b67c9bSShuo Chen#include <pthread_np.h>
18b9b67c9bSShuo Chen#else
19b9b67c9bSShuo Chen#include <sys/prctl.h>
20cd139dc7SShuo Chen#include <linux/unistd.h>
21b9b67c9bSShuo Chen#endif
22cd139dc7SShuo Chen
23cd139dc7SShuo Chennamespace muduo
24cd139dc7SShuo Chen{
25cd139dc7SShuo Chennamespace CurrentThread
26cd139dc7SShuo Chen{
27b9b67c9bSShuo Chen  __thread const char* t_threadName = "unnamedThread";
28cd139dc7SShuo Chen}
29cd139dc7SShuo Chen}
30cd139dc7SShuo Chen
31cd139dc7SShuo Chennamespace
32cd139dc7SShuo Chen{
33cd139dc7SShuo Chen__thread pid_t t_cachedTid = 0;
34cd139dc7SShuo Chen
35b9b67c9bSShuo Chen#if __FreeBSD__
36b9b67c9bSShuo Chenpid_t gettid()
37b9b67c9bSShuo Chen{
38b9b67c9bSShuo Chen  return pthread_getthreadid_np();
39b9b67c9bSShuo Chen}
40b9b67c9bSShuo Chen#else
41cc4062ffSShuo Chen#if !__GLIBC_PREREQ(2,30)
42cd139dc7SShuo Chenpid_t gettid()
43cd139dc7SShuo Chen{
44cd139dc7SShuo Chen  return static_cast<pid_t>(::syscall(SYS_gettid));
45cd139dc7SShuo Chen}
46cc4062ffSShuo Chen#endif
47b9b67c9bSShuo Chen#endif
48cd139dc7SShuo Chen
4950da4f87SShuo Chenvoid afterFork()
5050da4f87SShuo Chen{
5150da4f87SShuo Chen  t_cachedTid = gettid();
5250da4f87SShuo Chen  muduo::CurrentThread::t_threadName = "main";
5350da4f87SShuo Chen  // no need to call pthread_atfork(NULL, NULL, &afterFork);
5450da4f87SShuo Chen}
5550da4f87SShuo Chen
56cd139dc7SShuo Chenclass ThreadNameInitializer
57cd139dc7SShuo Chen{
58cd139dc7SShuo Chen public:
59cd139dc7SShuo Chen  ThreadNameInitializer()
60cd139dc7SShuo Chen  {
61cd139dc7SShuo Chen    muduo::CurrentThread::t_threadName = "main";
6250da4f87SShuo Chen    pthread_atfork(NULL, NULL, &afterFork);
63cd139dc7SShuo Chen  }
64cd139dc7SShuo Chen};
65cd139dc7SShuo Chen
66cd139dc7SShuo ChenThreadNameInitializer init;
672b2bf878SShuo Chen
682b2bf878SShuo Chenstruct ThreadData
692b2bf878SShuo Chen{
702b2bf878SShuo Chen  typedef muduo::Thread::ThreadFunc ThreadFunc;
712b2bf878SShuo Chen  ThreadFunc func_;
722b2bf878SShuo Chen  std::string name_;
732b2bf878SShuo Chen  boost::weak_ptr<pid_t> wkTid_;
742b2bf878SShuo Chen
752b2bf878SShuo Chen  ThreadData(const ThreadFunc& func,
762b2bf878SShuo Chen             const std::string& name,
772b2bf878SShuo Chen             const boost::shared_ptr<pid_t>& tid)
782b2bf878SShuo Chen    : func_(func),
792b2bf878SShuo Chen      name_(name),
802b2bf878SShuo Chen      wkTid_(tid)
812b2bf878SShuo Chen  { }
822b2bf878SShuo Chen
832b2bf878SShuo Chen  void runInThread()
842b2bf878SShuo Chen  {
85ac2f0106SShuo Chen    pid_t tid = muduo::CurrentThread::tid();
86ac2f0106SShuo Chen    boost::shared_ptr<pid_t> ptid = wkTid_.lock();
87ac2f0106SShuo Chen
88ac2f0106SShuo Chen    if (ptid)
892b2bf878SShuo Chen    {
90ac2f0106SShuo Chen      *ptid = tid;
91ac2f0106SShuo Chen      ptid.reset();
922b2bf878SShuo Chen    }
932b2bf878SShuo Chen
94b9b67c9bSShuo Chen    if (!name_.empty())
95b9b67c9bSShuo Chen      muduo::CurrentThread::t_threadName =  name_.c_str();
96b9b67c9bSShuo Chen#if __FreeBSD__
97b9b67c9bSShuo Chen    // setname_np() costs as much as creating a thread on FreeBSD 13.
98b9b67c9bSShuo Chen    pthread_setname_np(pthread_self(), muduo::CurrentThread::t_threadName);
99b9b67c9bSShuo Chen#else
100926c960eSShuo Chen    ::prctl(PR_SET_NAME, muduo::CurrentThread::t_threadName);
101b9b67c9bSShuo Chen#endif
1022b2bf878SShuo Chen    func_(); // FIXME: surround with try-catch, see muduo
1032b2bf878SShuo Chen    muduo::CurrentThread::t_threadName = "finished";
1042b2bf878SShuo Chen  }
1052b2bf878SShuo Chen};
1062b2bf878SShuo Chen
1072b2bf878SShuo Chenvoid* startThread(void* obj)
1082b2bf878SShuo Chen{
1092b2bf878SShuo Chen  ThreadData* data = static_cast<ThreadData*>(obj);
1102b2bf878SShuo Chen  data->runInThread();
1112b2bf878SShuo Chen  delete data;
1122b2bf878SShuo Chen  return NULL;
1132b2bf878SShuo Chen}
1142b2bf878SShuo Chen
115cd139dc7SShuo Chen}
116cd139dc7SShuo Chen
117cd139dc7SShuo Chenusing namespace muduo;
118cd139dc7SShuo Chen
119cd139dc7SShuo Chenpid_t CurrentThread::tid()
120cd139dc7SShuo Chen{
121cd139dc7SShuo Chen  if (t_cachedTid == 0)
122cd139dc7SShuo Chen  {
123cd139dc7SShuo Chen    t_cachedTid = gettid();
124cd139dc7SShuo Chen  }
125cd139dc7SShuo Chen  return t_cachedTid;
126cd139dc7SShuo Chen}
127cd139dc7SShuo Chen
128cd139dc7SShuo Chenconst char* CurrentThread::name()
129cd139dc7SShuo Chen{
130cd139dc7SShuo Chen  return t_threadName;
131cd139dc7SShuo Chen}
132cd139dc7SShuo Chen
133cd139dc7SShuo Chenbool CurrentThread::isMainThread()
134cd139dc7SShuo Chen{
135cd139dc7SShuo Chen  return tid() == ::getpid();
136cd139dc7SShuo Chen}
137cd139dc7SShuo Chen
138cd139dc7SShuo ChenAtomicInt32 Thread::numCreated_;
139cd139dc7SShuo Chen
140cd139dc7SShuo ChenThread::Thread(const ThreadFunc& func, const std::string& n)
141cd139dc7SShuo Chen  : started_(false),
1422b2bf878SShuo Chen    joined_(false),
143cd139dc7SShuo Chen    pthreadId_(0),
1442b2bf878SShuo Chen    tid_(new pid_t(0)),
145cd139dc7SShuo Chen    func_(func),
146cd139dc7SShuo Chen    name_(n)
147cd139dc7SShuo Chen{
148cd139dc7SShuo Chen  numCreated_.increment();
149cd139dc7SShuo Chen}
150cd139dc7SShuo Chen
151cd139dc7SShuo ChenThread::~Thread()
152cd139dc7SShuo Chen{
1532b2bf878SShuo Chen  if (started_ && !joined_)
1542b2bf878SShuo Chen  {
1552b2bf878SShuo Chen    pthread_detach(pthreadId_);
1562b2bf878SShuo Chen  }
157cd139dc7SShuo Chen}
158cd139dc7SShuo Chen
159cd139dc7SShuo Chenvoid Thread::start()
160cd139dc7SShuo Chen{
161cd139dc7SShuo Chen  assert(!started_);
162cd139dc7SShuo Chen  started_ = true;
1632b2bf878SShuo Chen
1642b2bf878SShuo Chen  ThreadData* data = new ThreadData(func_, name_, tid_);
1652b2bf878SShuo Chen  if (pthread_create(&pthreadId_, NULL, &startThread, data))
1662b2bf878SShuo Chen  {
1672b2bf878SShuo Chen    started_ = false;
1682b2bf878SShuo Chen    delete data;
1692b2bf878SShuo Chen    abort();
1702b2bf878SShuo Chen  }
171cd139dc7SShuo Chen}
172cd139dc7SShuo Chen
173cd139dc7SShuo Chenvoid Thread::join()
174cd139dc7SShuo Chen{
175cd139dc7SShuo Chen  assert(started_);
1762b2bf878SShuo Chen  assert(!joined_);
1772b2bf878SShuo Chen  joined_ = true;
178cd139dc7SShuo Chen  pthread_join(pthreadId_, NULL);
179cd139dc7SShuo Chen}
180