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/AndroidThread.h"
16
17 #include "aemu/base/threads/AndroidThreadStore.h"
18
19 #include <log/log.h>
20 #include <assert.h>
21 #include <errno.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #ifndef _MSC_VER
25 #include <unistd.h>
26 #endif
27 #ifdef __linux__
28 #include <sys/syscall.h>
29 #include <sys/types.h>
30 #endif
31
32 #ifdef __Fuchsia__
33 #include <zircon/process.h>
34 #endif
35
36 namespace gfxstream {
37 namespace guest {
38
Thread(ThreadFlags flags,int stackSize)39 Thread::Thread(ThreadFlags flags, int stackSize)
40 : mThread((pthread_t)NULL), mStackSize(stackSize), mFlags(flags) {}
41
~Thread()42 Thread::~Thread() {
43 assert(!mStarted || mFinished);
44 if ((mFlags & ThreadFlags::Detach) == ThreadFlags::NoFlags && mStarted &&
45 !mJoined) {
46 // Make sure we reclaim the OS resources.
47 pthread_join(mThread, nullptr);
48 }
49 }
50
start()51 bool Thread::start() {
52 if (mStarted) {
53 return false;
54 }
55
56 bool ret = true;
57 mStarted = true;
58
59 const auto useAttributes = mStackSize != 0;
60
61 pthread_attr_t attr;
62 if (useAttributes) {
63 pthread_attr_init(&attr);
64 pthread_attr_setstacksize(&attr, mStackSize);
65 }
66
67 if (pthread_create(&mThread, mStackSize ? &attr : nullptr, thread_main,
68 this)) {
69 ALOGE("Thread: failed to create a thread, errno %d\n", errno);
70 ret = false;
71 // We _do not_ need to guard this access to |mFinished| because we're
72 // sure that the launched thread failed, so there can't be parallel
73 // access.
74 mFinished = true;
75 mExitStatus = -errno;
76 // Nothing to join, so technically it's joined.
77 mJoined = true;
78 }
79
80 if (useAttributes) {
81 pthread_attr_destroy(&attr);
82 }
83
84 return ret;
85 }
86
wait(intptr_t * exitStatus)87 bool Thread::wait(intptr_t* exitStatus) {
88 if (!mStarted || (mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
89 return false;
90 }
91
92 // NOTE: Do not hold the lock when waiting for the thread to ensure
93 // it can update mFinished and mExitStatus properly in thread_main
94 // without blocking.
95 if (!mJoined && pthread_join(mThread, NULL)) {
96 return false;
97 }
98 mJoined = true;
99
100 if (exitStatus) {
101 *exitStatus = mExitStatus;
102 }
103 return true;
104 }
105
tryWait(intptr_t * exitStatus)106 bool Thread::tryWait(intptr_t* exitStatus) {
107 if (!mStarted || (mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
108 return false;
109 }
110
111 {
112 AutoLock<Lock> locker(mLock);
113 if (!mFinished) {
114 return false;
115 }
116 }
117
118 if (!mJoined) {
119 if (pthread_join(mThread, NULL)) {
120 ALOGW("Thread: failed to join a finished thread, errno %d\n", errno);
121 }
122 mJoined = true;
123 }
124
125 if (exitStatus) {
126 *exitStatus = mExitStatus;
127 }
128 return true;
129 }
130
131 // static
thread_main(void * arg)132 void* Thread::thread_main(void* arg) {
133 intptr_t ret;
134
135 {
136 Thread* self = reinterpret_cast<Thread*>(arg);
137 if ((self->mFlags & ThreadFlags::MaskSignals) != ThreadFlags::NoFlags) {
138 Thread::maskAllSignals();
139 }
140
141 if ((self->mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
142 if (pthread_detach(pthread_self())) {
143 // This only means a slow memory leak, so use VERBOSE.
144 ALOGV("Failed to set thread to detach mode\n");
145 }
146 }
147
148 ret = self->main();
149
150 {
151 AutoLock<Lock> lock(self->mLock);
152 self->mFinished = true;
153 self->mExitStatus = ret;
154 }
155
156 self->onExit();
157 // |self| is not valid beyond this point
158 }
159
160 gfxstream::guest::ThreadStoreBase::OnThreadExit();
161
162 // This return value is ignored.
163 return NULL;
164 }
165
166 // static
maskAllSignals()167 void Thread::maskAllSignals() {
168 sigset_t set;
169 sigfillset(&set);
170 pthread_sigmask(SIG_SETMASK, &set, nullptr);
171 }
172
173 // static
sleepMs(unsigned n)174 void Thread::sleepMs(unsigned n) {
175 usleep(n * 1000);
176 }
177
178 // static
sleepUs(unsigned n)179 void Thread::sleepUs(unsigned n) {
180 usleep(n);
181 }
182
183 // static
yield()184 void Thread::yield() {
185 sched_yield();
186 }
187
getCurrentThreadId()188 unsigned long getCurrentThreadId() {
189 #ifdef __ANDROID__
190 // bionic has an efficient implementation for gettid.
191 pid_t tid = gettid();
192 #elif defined(__linux__)
193 // Linux doesn't always include an implementation of gettid, so we use syscall.
194 thread_local pid_t tid = -1;
195 if (tid == -1) {
196 tid = syscall(__NR_gettid);
197 }
198 #elif defined(__Fuchsia__)
199 zx_handle_t tid = zx_thread_self();
200 #else
201 pthread_t thread = pthread_self();
202 // POSIX doesn't require pthread_t to be a numeric type.
203 // Instead, just pick up the first sizeof(long) bytes as the "id".
204 static_assert(sizeof(thread) >= sizeof(long),
205 "Expected pthread_t to be at least sizeof(long) wide");
206 unsigned long tid = *reinterpret_cast<unsigned long*>(&tid);
207 #endif
208 static_assert(sizeof(tid) <= sizeof(long),
209 "Expected thread handle to be at most sizeof(long) wide");
210 return static_cast<unsigned long>(tid);
211 }
212
213 } // namespace guest
214 } // namespace gfxstream
215