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 <assert.h>
16 #include <comdef.h>
17
18 #include <sstream>
19
20 #include "aemu/base/threads/Thread.h"
21 #include "aemu/base/system/Win32UnicodeString.h"
22 #include "host-common/logging.h"
23
24 namespace android {
25 namespace base {
26
Thread(ThreadFlags flags,int stackSize,std::optional<std::string> nameOpt)27 Thread::Thread(ThreadFlags flags, int stackSize, std::optional<std::string> nameOpt)
28 : mStackSize(stackSize), mFlags(flags), mNameOpt(std::move(nameOpt)) {}
29
~Thread()30 Thread::~Thread() {
31 if (mThread) {
32 assert(!mStarted || mFinished);
33 CloseHandle(mThread);
34 }
35 }
36
start()37 bool Thread::start() {
38 if (mStarted) {
39 return false;
40 }
41
42 bool ret = true;
43 mStarted = true;
44 DWORD threadId = 0;
45 mThread = CreateThread(NULL, mStackSize, &Thread::thread_main, this, 0,
46 &threadId);
47 if (!mThread) {
48 // don't reset mStarted: we're artifically limiting the user's
49 // ability to retry the failed starts here.
50 ret = false;
51 mFinished = true;
52 }
53
54 if (mNameOpt.has_value()) {
55 Win32UnicodeString name(mNameOpt->c_str());
56 if (!mNameOpt->empty() && name.size() == 0) {
57 ERR("Invalid thread name.");
58 return ret;
59 }
60 HRESULT res = SetThreadDescription(mThread, name.c_str());
61 if (FAILED(res)) {
62 std::stringstream ss;
63 ss << "Failed to set the thread name " << name.toString();
64 DWORD threadId = GetThreadId(mThread);
65 if (threadId != 0) {
66 ss << " for thread " << threadId;
67 }
68 ss << ": ";
69 _com_error e(res);
70 Win32UnicodeString errorMessage(e.ErrorMessage());
71 if (errorMessage.size() != 0) {
72 ss << errorMessage.toString().c_str() << "(" << res << ")";
73 } else {
74 ss << res;
75 }
76 ss << ".";
77 ERR("%s", ss.str().c_str());
78 }
79 }
80 return ret;
81 }
82
wait(intptr_t * exitStatus)83 bool Thread::wait(intptr_t* exitStatus) {
84 if (!mStarted || (mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
85 return false;
86 }
87
88 // NOTE: Do not hold lock during wait to allow thread_main to
89 // properly update mIsRunning and mFinished on thread exit.
90 if (WaitForSingleObject(mThread, INFINITE) == WAIT_FAILED) {
91 return false;
92 }
93
94 if (exitStatus) {
95 *exitStatus = mExitStatus;
96 }
97 return true;
98 }
99
tryWait(intptr_t * exitStatus)100 bool Thread::tryWait(intptr_t* exitStatus) {
101 if (!mStarted || (mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
102 return false;
103 }
104
105 AutoLock locker(mLock);
106 if (!mFinished || WaitForSingleObject(mThread, 0) != WAIT_OBJECT_0) {
107 return false;
108 }
109
110 if (exitStatus) {
111 *exitStatus = mExitStatus;
112 }
113 return true;
114 }
115
116 // static
thread_main(void * arg)117 DWORD WINAPI Thread::thread_main(void* arg) {
118 {
119 // no need to call maskAllSignals() here: we know
120 // that on Windows it's a noop
121 Thread* self = reinterpret_cast<Thread*>(arg);
122 auto ret = self->main();
123
124 {
125 AutoLock lock(self->mLock);
126 self->mFinished = true;
127 self->mExitStatus = ret;
128 }
129
130 self->onExit();
131 // |self| is not valid beyond this point
132 }
133
134 // This return value is ignored.
135 return 0;
136 }
137
138 // static
maskAllSignals()139 void Thread::maskAllSignals() {
140 // no such thing as signal in Windows
141 }
142
143 // static
sleepMs(unsigned n)144 void Thread::sleepMs(unsigned n) {
145 ::Sleep(n);
146 }
147
148 // static
sleepUs(unsigned n)149 void Thread::sleepUs(unsigned n) {
150 // Hehe
151 ::Sleep(n / 1000);
152 }
153
154 // static
yield()155 void Thread::yield() {
156 if (!::SwitchToThread()) {
157 ::Sleep(0);
158 }
159 }
160
getCurrentThreadId()161 unsigned long getCurrentThreadId() {
162 return static_cast<unsigned long>(GetCurrentThreadId());
163 }
164
165 static unsigned long sUiThreadId = 0;
setUiThreadId(unsigned long id)166 void setUiThreadId(unsigned long id) {
167 sUiThreadId = id;
168
169 }
170
isRunningInUiThread()171 bool isRunningInUiThread() {
172 if (!sUiThreadId) return false;
173 return sUiThreadId == getCurrentThreadId();
174 }
175
176 } // namespace base
177 } // namespace android
178