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 "base/Thread.h"
16
17 #include <assert.h>
18
19 namespace android {
20 namespace base {
21
Thread(ThreadFlags flags,int stackSize)22 Thread::Thread(ThreadFlags flags, int stackSize)
23 : mStackSize(stackSize), mFlags(flags) {}
24
~Thread()25 Thread::~Thread() {
26 if (mThread) {
27 assert(!mStarted || mFinished);
28 CloseHandle(mThread);
29 }
30 }
31
start()32 bool Thread::start() {
33 if (mStarted) {
34 return false;
35 }
36
37 bool ret = true;
38 mStarted = true;
39 DWORD threadId = 0;
40 mThread = CreateThread(NULL, mStackSize, &Thread::thread_main, this, 0,
41 &threadId);
42 if (!mThread) {
43 // don't reset mStarted: we're artifically limiting the user's
44 // ability to retry the failed starts here.
45 ret = false;
46 mFinished = true;
47 }
48 return ret;
49 }
50
wait(intptr_t * exitStatus)51 bool Thread::wait(intptr_t* exitStatus) {
52 if (!mStarted || (mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
53 return false;
54 }
55
56 // NOTE: Do not hold lock during wait to allow thread_main to
57 // properly update mIsRunning and mFinished on thread exit.
58 if (WaitForSingleObject(mThread, INFINITE) == WAIT_FAILED) {
59 return false;
60 }
61
62 if (exitStatus) {
63 *exitStatus = mExitStatus;
64 }
65 return true;
66 }
67
tryWait(intptr_t * exitStatus)68 bool Thread::tryWait(intptr_t* exitStatus) {
69 if (!mStarted || (mFlags & ThreadFlags::Detach) != ThreadFlags::NoFlags) {
70 return false;
71 }
72
73 AutoLock locker(mLock);
74 if (!mFinished || WaitForSingleObject(mThread, 0) != WAIT_OBJECT_0) {
75 return false;
76 }
77
78 if (exitStatus) {
79 *exitStatus = mExitStatus;
80 }
81 return true;
82 }
83
84 // static
thread_main(void * arg)85 DWORD WINAPI Thread::thread_main(void* arg) {
86 {
87 // no need to call maskAllSignals() here: we know
88 // that on Windows it's a noop
89 Thread* self = reinterpret_cast<Thread*>(arg);
90 auto ret = self->main();
91
92 {
93 AutoLock lock(self->mLock);
94 self->mFinished = true;
95 self->mExitStatus = ret;
96 }
97
98 self->onExit();
99 // |self| is not valid beyond this point
100 }
101
102 // This return value is ignored.
103 return 0;
104 }
105
106 // static
maskAllSignals()107 void Thread::maskAllSignals() {
108 // no such thing as signal in Windows
109 }
110
111 // static
sleepMs(unsigned n)112 void Thread::sleepMs(unsigned n) {
113 ::Sleep(n);
114 }
115
116 // static
sleepUs(unsigned n)117 void Thread::sleepUs(unsigned n) {
118 // Hehe
119 ::Sleep(n / 1000);
120 }
121
122 // static
yield()123 void Thread::yield() {
124 if (!::SwitchToThread()) {
125 ::Sleep(0);
126 }
127 }
128
getCurrentThreadId()129 unsigned long getCurrentThreadId() {
130 return static_cast<unsigned long>(GetCurrentThreadId());
131 }
132
133 static unsigned long sUiThreadId = 0;
setUiThreadId(unsigned long id)134 void setUiThreadId(unsigned long id) {
135 sUiThreadId = id;
136
137 }
138
isRunningInUiThread()139 bool isRunningInUiThread() {
140 if (!sUiThreadId) return false;
141 return sUiThreadId == getCurrentThreadId();
142 }
143
144 } // namespace base
145 } // namespace android
146