#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SYNC
#include "src/core/lib/gprpp/thd.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd_id.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/fork.h"
#include "src/core/lib/gprpp/memory.h"
namespace grpc_core {
namespace {
class ThreadInternalsPosix;
struct thd_arg {
ThreadInternalsPosix* thread;
void (*body)(void* arg);
void* arg;
const char* name;
};
class ThreadInternalsPosix
: public grpc_core::internal::ThreadInternalsInterface {
public:
ThreadInternalsPosix(const char* thd_name, void (*thd_body)(void* arg),
void* arg, bool* success)
: started_(false) {
gpr_mu_init(&mu_);
gpr_cv_init(&ready_);
pthread_attr_t attr;
thd_arg* info = static_cast<thd_arg*>(malloc(sizeof(*info)));
GPR_ASSERT(info != nullptr);
info->thread = this;
info->body = thd_body;
info->arg = arg;
info->name = thd_name;
grpc_core::Fork::IncThreadCount();
GPR_ASSERT(pthread_attr_init(&attr) == 0);
GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
0);
*success =
(pthread_create(&pthread_id_, &attr,
[](void* v) -> void* {
thd_arg arg = *static_cast<thd_arg*>(v);
free(v);
if (arg.name != nullptr) {
#if GPR_APPLE_PTHREAD_NAME
pthread_setname_np(arg.name);
#elif GPR_LINUX_PTHREAD_NAME
char buf[16];
size_t buf_len = GPR_ARRAY_SIZE(buf) - 1;
strncpy(buf, arg.name, buf_len);
buf[buf_len] = '\0';
pthread_setname_np(pthread_self(), buf);
#endif }
gpr_mu_lock(&arg.thread->mu_);
while (!arg.thread->started_) {
gpr_cv_wait(&arg.thread->ready_, &arg.thread->mu_,
gpr_inf_future(GPR_CLOCK_MONOTONIC));
}
gpr_mu_unlock(&arg.thread->mu_);
(*arg.body)(arg.arg);
grpc_core::Fork::DecThreadCount();
return nullptr;
},
info) == 0);
GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
if (!(*success)) {
free(info);
grpc_core::Fork::DecThreadCount();
}
};
~ThreadInternalsPosix() override {
gpr_mu_destroy(&mu_);
gpr_cv_destroy(&ready_);
}
void Start() override {
gpr_mu_lock(&mu_);
started_ = true;
gpr_cv_signal(&ready_);
gpr_mu_unlock(&mu_);
}
void Join() override { pthread_join(pthread_id_, nullptr); }
private:
gpr_mu mu_;
gpr_cv ready_;
bool started_;
pthread_t pthread_id_;
};
}
Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
bool* success) {
bool outcome = false;
impl_ =
grpc_core::New<ThreadInternalsPosix>(thd_name, thd_body, arg, &outcome);
if (outcome) {
state_ = ALIVE;
} else {
state_ = FAILED;
grpc_core::Delete(impl_);
impl_ = nullptr;
}
if (success != nullptr) {
*success = outcome;
}
}
}
gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }
#endif