blob: bb5999f9c8bc1e8936d105fae6384ac2346ba4f8 [file] [log] [blame]
#include "aos/util/thread.h"
#include <pthread.h>
#include <signal.h>
#include "glog/logging.h"
namespace aos {
namespace util {
Thread::Thread() : started_(false), joined_(false), should_terminate_(false) {}
Thread::~Thread() {
CHECK(!(started_ && !joined_));
}
void Thread::Start() {
CHECK(!started_);
started_ = true;
CHECK(pthread_create(&thread_, NULL, &Thread::StaticRun, this) == 0);
}
void Thread::Join() {
CHECK(!joined_ && started_);
joined_ = true;
should_terminate_.store(true);
CHECK(pthread_join(thread_, NULL) == 0);
}
bool Thread::TryJoin() {
CHECK(!joined_ && started_);
#ifdef AOS_SANITIZER_thread
// ThreadSanitizer misses the tryjoin and then complains about leaking the
// thread. Instead, we'll just check if the thread is still around and then
// do a regular Join() iff it isn't.
// TODO(brians): Remove this once tsan learns about pthread_tryjoin_np.
const int kill_ret = pthread_kill(thread_, 0);
// If it's still around.
if (kill_ret == 0) return false;
// If it died, we'll get ESRCH. Otherwise, something went wrong.
if (kill_ret != ESRCH) {
errno = kill_ret;
PLOG(FATAL) << "pthread_kill(thread_, 0) failed";
}
Join();
return true;
#else
const int ret = pthread_tryjoin_np(thread_, nullptr);
if (ret == 0) {
joined_ = true;
return true;
} else if (ret == EBUSY) {
return false;
} else {
errno = ret;
PLOG(FATAL) << "pthread_tryjoin_np(thread_, nullptr) failed";
return false;
}
#endif
}
void Thread::RequestStop() {
CHECK(!joined_ && started_);
should_terminate_.store(true);
}
void Thread::WaitUntilDone() {
CHECK(!joined_ && started_);
joined_ = true;
CHECK(pthread_join(thread_, NULL) == 0);
}
void *Thread::StaticRun(void *self) {
static_cast<Thread *>(self)->Run();
return NULL;
}
} // namespace util
} // namespace aos