• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2014 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "base/Thread.h"
16 
17 #include <cerrno>
18 
19 #include <assert.h>
20 #include <signal.h>
21 #include <stdio.h>
22 #ifndef _MSC_VER
23 #include <unistd.h>
24 #endif
25 
26 namespace android {
27 namespace base {
28 
Thread(ThreadFlags flags,int stackSize)29 Thread::Thread(ThreadFlags flags, int stackSize)
30     : mThread((pthread_t)NULL), mStackSize(stackSize), mFlags(flags) {}
31 
~Thread()32 Thread::~Thread() {
33     assert(!mStarted || mFinished);
34     if ((mFlags & ThreadFlags::Detach) == ThreadFlags::NoFlags && mStarted &&
35         !mJoined) {
36         // Make sure we reclaim the OS resources.
37         pthread_join(mThread, nullptr);
38     }
39 }
40 
start()41 bool Thread::start() {
42     if (mStarted) {
43         return false;
44     }
45 
46     bool ret = true;
47     mStarted = true;
48 
49     const auto useAttributes = mStackSize != 0;
50 
51     pthread_attr_t attr;
52     if (useAttributes) {
53         pthread_attr_init(&attr);
54         pthread_attr_setstacksize(&attr, mStackSize);
55     }
56 
57     if (pthread_create(&mThread, mStackSize ? &attr : nullptr, thread_main,
58                        this)) {
59         fprintf(stderr, "Thread: failed to create a thread, errno %d\n", errno);
60         ret = false;
61         // We _do not_ need to guard this access to |mFinished| because we're
62         // sure that the launched thread failed, so there can't be parallel
63         // access.
64         mFinished = true;
65         mExitStatus = -errno;
66         // Nothing to join, so technically it's joined.
67         mJoined = true;
68     }
69 
70     if (useAttributes) {
71         pthread_attr_destroy(&attr);
72     }
73 
74     return ret;
75 }
76 
wait(intptr_t * exitStatus)77 bool Thread::wait(intptr_t* exitStatus) {
78     if (!mStarted || (mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
79         return false;
80     }
81 
82     // NOTE: Do not hold the lock when waiting for the thread to ensure
83     // it can update mFinished and mExitStatus properly in thread_main
84     // without blocking.
85     if (!mJoined && pthread_join(mThread, NULL)) {
86         return false;
87     }
88     mJoined = true;
89 
90     if (exitStatus) {
91         *exitStatus = mExitStatus;
92     }
93     return true;
94 }
95 
tryWait(intptr_t * exitStatus)96 bool Thread::tryWait(intptr_t* exitStatus) {
97     if (!mStarted || (mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
98         return false;
99     }
100 
101     {
102         AutoLock locker(mLock);
103         if (!mFinished) {
104             return false;
105         }
106     }
107 
108     if (!mJoined) {
109         if (pthread_join(mThread, NULL)) {
110             fprintf(stderr, "Thread: failed to join a finished thread, errno %d\n", errno);
111         }
112         mJoined = true;
113     }
114 
115     if (exitStatus) {
116         *exitStatus = mExitStatus;
117     }
118     return true;
119 }
120 
121 // static
thread_main(void * arg)122 void* Thread::thread_main(void* arg) {
123     intptr_t ret;
124 
125     {
126         Thread* self = reinterpret_cast<Thread*>(arg);
127         if ((self->mFlags & ThreadFlags::MaskSignals) != ThreadFlags::NoFlags) {
128             Thread::maskAllSignals();
129         }
130 
131         if ((self->mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
132             if (pthread_detach(pthread_self())) {
133                 // Failed to detach thread
134             }
135         }
136 
137         ret = self->main();
138 
139         {
140             AutoLock lock(self->mLock);
141             self->mFinished = true;
142             self->mExitStatus = ret;
143         }
144 
145         self->onExit();
146         // |self| is not valid beyond this point
147     }
148 
149     // This return value is ignored.
150     return NULL;
151 }
152 
153 // static
maskAllSignals()154 void Thread::maskAllSignals() {
155     sigset_t set;
156     sigfillset(&set);
157     pthread_sigmask(SIG_SETMASK, &set, nullptr);
158 }
159 
160 // static
sleepMs(unsigned n)161 void Thread::sleepMs(unsigned n) {
162     usleep(n * 1000);
163 }
164 
165 // static
sleepUs(unsigned n)166 void Thread::sleepUs(unsigned n) {
167     usleep(n);
168 }
169 
170 // static
yield()171 void Thread::yield() {
172     sched_yield();
173 }
174 
getCurrentThreadId()175 unsigned long getCurrentThreadId() {
176     pthread_t tid = pthread_self();
177     // POSIX doesn't require pthread_t to be a numeric type.
178     // Instead, just pick up the first sizeof(long) bytes as the "id".
179     static_assert(sizeof(tid) >= sizeof(long),
180                   "Expected pthread_t to be at least sizeof(long) wide");
181     return *reinterpret_cast<unsigned long*>(&tid);
182 }
183 
184 static unsigned long sUiThreadId = 0;
185 
setUiThreadId(unsigned long id)186 void setUiThreadId(unsigned long id) {
187     sUiThreadId = id;
188 
189 }
190 
isRunningInUiThread()191 bool isRunningInUiThread() {
192     if (!sUiThreadId) return false;
193     return sUiThreadId == getCurrentThreadId();
194 }
195 
196 
197 }  // namespace base
198 }  // namespace android
199