• 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 "aemu/base/threads/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,std::optional<std::string> nameOpt)29 Thread::Thread(ThreadFlags flags, int stackSize, std::optional<std::string> nameOpt)
30     : mThread((pthread_t)NULL), mStackSize(stackSize), mFlags(flags), mNameOpt(std::move(nameOpt)) {}
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     // TODO: implement for mac os
71 #ifndef __APPLE__
72     if (mNameOpt.has_value()) {
73         pthread_setname_np(mThread, (*mNameOpt).c_str());
74     }
75 #endif  // __APPLE__
76 
77     if (useAttributes) {
78         pthread_attr_destroy(&attr);
79     }
80 
81     return ret;
82 }
83 
wait(intptr_t * exitStatus)84 bool Thread::wait(intptr_t* exitStatus) {
85     if (!mStarted || (mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
86         return false;
87     }
88 
89     // NOTE: Do not hold the lock when waiting for the thread to ensure
90     // it can update mFinished and mExitStatus properly in thread_main
91     // without blocking.
92     if (!mJoined && pthread_join(mThread, NULL)) {
93         return false;
94     }
95     mJoined = true;
96 
97     if (exitStatus) {
98         *exitStatus = mExitStatus;
99     }
100     return true;
101 }
102 
tryWait(intptr_t * exitStatus)103 bool Thread::tryWait(intptr_t* exitStatus) {
104     if (!mStarted || (mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
105         return false;
106     }
107 
108     {
109         AutoLock locker(mLock);
110         if (!mFinished) {
111             return false;
112         }
113     }
114 
115     if (!mJoined) {
116         if (pthread_join(mThread, NULL)) {
117             fprintf(stderr, "Thread: failed to join a finished thread, errno %d\n", errno);
118         }
119         mJoined = true;
120     }
121 
122     if (exitStatus) {
123         *exitStatus = mExitStatus;
124     }
125     return true;
126 }
127 
128 // static
thread_main(void * arg)129 void* Thread::thread_main(void* arg) {
130     intptr_t ret;
131 
132     {
133         Thread* self = reinterpret_cast<Thread*>(arg);
134         if ((self->mFlags & ThreadFlags::MaskSignals) != ThreadFlags::NoFlags) {
135             Thread::maskAllSignals();
136         }
137 
138         if ((self->mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
139             if (pthread_detach(pthread_self())) {
140                 // Failed to detach thread
141             }
142         }
143 
144         ret = self->main();
145 
146         {
147             AutoLock lock(self->mLock);
148             self->mFinished = true;
149             self->mExitStatus = ret;
150         }
151 
152         self->onExit();
153         // |self| is not valid beyond this point
154     }
155 
156     // This return value is ignored.
157     return NULL;
158 }
159 
160 // static
maskAllSignals()161 void Thread::maskAllSignals() {
162     sigset_t set;
163     sigfillset(&set);
164     pthread_sigmask(SIG_SETMASK, &set, nullptr);
165 }
166 
167 // static
sleepMs(unsigned n)168 void Thread::sleepMs(unsigned n) {
169     usleep(n * 1000);
170 }
171 
172 // static
sleepUs(unsigned n)173 void Thread::sleepUs(unsigned n) {
174     usleep(n);
175 }
176 
177 // static
yield()178 void Thread::yield() {
179     sched_yield();
180 }
181 
getCurrentThreadId()182 unsigned long getCurrentThreadId() {
183     pthread_t tid = pthread_self();
184     // POSIX doesn't require pthread_t to be a numeric type.
185     // Instead, just pick up the first sizeof(long) bytes as the "id".
186 #ifdef __QNX__
187     // the assert for sizeof(long) fails
188     static_assert(sizeof(tid) >= sizeof(int),
189                   "Expected pthread_t to be at least sizeof(int) wide");
190     return *reinterpret_cast<unsigned int*>(&tid);
191 #else
192     static_assert(sizeof(tid) >= sizeof(long),
193                   "Expected pthread_t to be at least sizeof(long) wide");
194     return *reinterpret_cast<unsigned long*>(&tid);
195 #endif
196 }
197 
198 static unsigned long sUiThreadId = 0;
199 
setUiThreadId(unsigned long id)200 void setUiThreadId(unsigned long id) {
201     sUiThreadId = id;
202 
203 }
204 
isRunningInUiThread()205 bool isRunningInUiThread() {
206     if (!sUiThreadId) return false;
207     return sUiThreadId == getCurrentThreadId();
208 }
209 
210 
211 }  // namespace base
212 }  // namespace android
213