blob: bb5999f9c8bc1e8936d105fae6384ac2346ba4f8 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/util/thread.h"
Brian Silverman798c7782013-03-28 16:48:02 -07002
3#include <pthread.h>
Brian Silverman325c5972014-09-04 16:12:09 -04004#include <signal.h>
Brian Silverman653491d2014-05-13 16:53:29 -07005
Alex Perrycb7da4b2019-08-28 19:35:56 -07006#include "glog/logging.h"
Brian Silverman798c7782013-03-28 16:48:02 -07007
8namespace aos {
9namespace util {
10
11Thread::Thread() : started_(false), joined_(false), should_terminate_(false) {}
12
13Thread::~Thread() {
Alex Perrycb7da4b2019-08-28 19:35:56 -070014 CHECK(!(started_ && !joined_));
Brian Silverman798c7782013-03-28 16:48:02 -070015}
16
17void Thread::Start() {
Alex Perrycb7da4b2019-08-28 19:35:56 -070018 CHECK(!started_);
Brian Silverman798c7782013-03-28 16:48:02 -070019 started_ = true;
Alex Perrycb7da4b2019-08-28 19:35:56 -070020 CHECK(pthread_create(&thread_, NULL, &Thread::StaticRun, this) == 0);
Brian Silverman798c7782013-03-28 16:48:02 -070021}
22
23void Thread::Join() {
Alex Perrycb7da4b2019-08-28 19:35:56 -070024 CHECK(!joined_ && started_);
Brian Silverman798c7782013-03-28 16:48:02 -070025 joined_ = true;
Brian Silvermand4c48322014-09-06 21:17:29 -040026 should_terminate_.store(true);
Alex Perrycb7da4b2019-08-28 19:35:56 -070027 CHECK(pthread_join(thread_, NULL) == 0);
Brian Silverman653491d2014-05-13 16:53:29 -070028}
29
Brian Silverman325c5972014-09-04 16:12:09 -040030bool Thread::TryJoin() {
Alex Perrycb7da4b2019-08-28 19:35:56 -070031 CHECK(!joined_ && started_);
Brian Silverman325c5972014-09-04 16:12:09 -040032#ifdef AOS_SANITIZER_thread
33 // ThreadSanitizer misses the tryjoin and then complains about leaking the
34 // thread. Instead, we'll just check if the thread is still around and then
35 // do a regular Join() iff it isn't.
36 // TODO(brians): Remove this once tsan learns about pthread_tryjoin_np.
37 const int kill_ret = pthread_kill(thread_, 0);
38 // If it's still around.
39 if (kill_ret == 0) return false;
40 // If it died, we'll get ESRCH. Otherwise, something went wrong.
41 if (kill_ret != ESRCH) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070042 errno = kill_ret;
43 PLOG(FATAL) << "pthread_kill(thread_, 0) failed";
Brian Silverman325c5972014-09-04 16:12:09 -040044 }
45 Join();
46 return true;
47#else
48 const int ret = pthread_tryjoin_np(thread_, nullptr);
49 if (ret == 0) {
50 joined_ = true;
51 return true;
52 } else if (ret == EBUSY) {
53 return false;
54 } else {
Alex Perrycb7da4b2019-08-28 19:35:56 -070055 errno = ret;
56 PLOG(FATAL) << "pthread_tryjoin_np(thread_, nullptr) failed";
57 return false;
Brian Silverman325c5972014-09-04 16:12:09 -040058 }
59#endif
60}
61
62void Thread::RequestStop() {
Alex Perrycb7da4b2019-08-28 19:35:56 -070063 CHECK(!joined_ && started_);
Brian Silverman325c5972014-09-04 16:12:09 -040064 should_terminate_.store(true);
65}
66
Brian Silverman653491d2014-05-13 16:53:29 -070067void Thread::WaitUntilDone() {
Alex Perrycb7da4b2019-08-28 19:35:56 -070068 CHECK(!joined_ && started_);
Brian Silverman653491d2014-05-13 16:53:29 -070069 joined_ = true;
Alex Perrycb7da4b2019-08-28 19:35:56 -070070 CHECK(pthread_join(thread_, NULL) == 0);
Brian Silverman798c7782013-03-28 16:48:02 -070071}
72
73void *Thread::StaticRun(void *self) {
74 static_cast<Thread *>(self)->Run();
75 return NULL;
76}
77
78} // namespace util
79} // namespace aos