blob: 6b3ef76d3c9ae3d6c300ed442150b06dfc2b49b9 [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
John Park33858a32018-09-28 23:05:48 -07006#include "aos/logging/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() {
Brian Silverman325c5972014-09-04 16:12:09 -040014 CHECK(!(started_ && !joined_));
Brian Silverman798c7782013-03-28 16:48:02 -070015}
16
17void Thread::Start() {
Brian Silverman653491d2014-05-13 16:53:29 -070018 CHECK(!started_);
Brian Silverman798c7782013-03-28 16:48:02 -070019 started_ = true;
Brian Silverman653491d2014-05-13 16:53:29 -070020 CHECK(pthread_create(&thread_, NULL, &Thread::StaticRun, this) == 0);
Brian Silverman798c7782013-03-28 16:48:02 -070021}
22
23void Thread::Join() {
Brian Silverman653491d2014-05-13 16:53:29 -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);
Brian Silverman653491d2014-05-13 16:53:29 -070027 CHECK(pthread_join(thread_, NULL) == 0);
28}
29
Brian Silverman325c5972014-09-04 16:12:09 -040030bool Thread::TryJoin() {
31 CHECK(!joined_ && started_);
32#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) {
42 PELOG(FATAL, kill_ret, "pthread_kill(thread_, 0) failed");
43 }
44 Join();
45 return true;
46#else
47 const int ret = pthread_tryjoin_np(thread_, nullptr);
48 if (ret == 0) {
49 joined_ = true;
50 return true;
51 } else if (ret == EBUSY) {
52 return false;
53 } else {
54 PELOG(FATAL, ret, "pthread_tryjoin_np(thread_, nullptr) failed");
55 }
56#endif
57}
58
59void Thread::RequestStop() {
60 CHECK(!joined_ && started_);
61 should_terminate_.store(true);
62}
63
Brian Silverman653491d2014-05-13 16:53:29 -070064void Thread::WaitUntilDone() {
65 CHECK(!joined_ && started_);
66 joined_ = true;
67 CHECK(pthread_join(thread_, NULL) == 0);
Brian Silverman798c7782013-03-28 16:48:02 -070068}
69
70void *Thread::StaticRun(void *self) {
71 static_cast<Thread *>(self)->Run();
72 return NULL;
73}
74
75} // namespace util
76} // namespace aos