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