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