edd1f6a91ef97c2351f748f71c306771b9d2af96
[iec.git] / src / type3_AndroidCloud / anbox-master / external / android-emugl / shared / emugl / common / thread_pthread.cpp
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 "emugl/common/thread.h"
16
17 #include "emugl/common/thread_store.h"
18
19 #include <assert.h>
20 #include <stdio.h>
21
22 namespace emugl {
23
24 namespace {
25
26 class ScopedLocker {
27 public:
28     ScopedLocker(pthread_mutex_t* mutex) : mMutex(mutex) {
29         pthread_mutex_lock(mMutex);
30     }
31
32     ~ScopedLocker() {
33         pthread_mutex_unlock(mMutex);
34     }
35 private:
36     pthread_mutex_t* mMutex;
37 };
38
39 }  // namespace
40
41 Thread::Thread() :
42     mThread((pthread_t)NULL),
43     mLock(),
44     mJoined(false),
45     mExitStatus(0),
46     mIsRunning(false) {
47     pthread_mutex_init(&mLock, NULL);
48 }
49
50 Thread::~Thread() {
51     assert(!mIsRunning);
52     assert(mJoined);
53     pthread_mutex_destroy(&mLock);
54 }
55
56 bool Thread::start() {
57     bool ret = true;
58     pthread_mutex_lock(&mLock);
59     mIsRunning = true;
60     if (pthread_create(&mThread, NULL, thread_main, this)) {
61         ret = false;
62         mIsRunning = false;
63     }
64     pthread_mutex_unlock(&mLock);
65     return ret;
66 }
67
68 bool Thread::wait(intptr_t *exitStatus) {
69     {
70         ScopedLocker locker(&mLock);
71         if (!mIsRunning) {
72             // Thread already stopped.
73             if (exitStatus) {
74                 *exitStatus = mExitStatus;
75             }
76             if (!mJoined) {
77                 // reclaim thread stack
78                 pthread_join(mThread, NULL);
79                 mJoined = true;
80             }
81             return true;
82         }
83     }
84
85     // NOTE: Do not hold the lock when waiting for the thread to ensure
86     // it can update mIsRunning and mExitStatus properly in thread_main
87     // without blocking.
88     void *retval;
89     if (pthread_join(mThread, &retval)) {
90         return false;
91     }
92     if (exitStatus) {
93         *exitStatus = (intptr_t)retval;
94     }
95     // Note: Updating mJoined must be performed inside the lock to avoid
96     //       race conditions between two threads waiting for the same thread
97     //       that just completed its execution.
98     {
99         ScopedLocker locker(&mLock);
100         mJoined = true;
101     }
102     return true;
103 }
104
105 bool Thread::tryWait(intptr_t *exitStatus) {
106     ScopedLocker locker(&mLock);
107     if (mIsRunning) {
108         return false;
109     }
110     if (!mJoined) {
111         // Reclaim stack.
112         pthread_join(mThread, NULL);
113         mJoined = true;
114     }
115     if (exitStatus) {
116         *exitStatus = mExitStatus;
117     }
118     return true;
119 }
120
121 // static
122 void* Thread::thread_main(void *arg) {
123     Thread* self = reinterpret_cast<Thread*>(arg);
124     intptr_t ret = self->main();
125
126     pthread_mutex_lock(&self->mLock);
127     self->mIsRunning = false;
128     self->mExitStatus = ret;
129     pthread_mutex_unlock(&self->mLock);
130
131     ::emugl::ThreadStore::OnThreadExit();
132
133     return (void*)ret;
134 }
135
136 }  // namespace emugl