• 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 <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