mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
139 lines
3.9 KiB
C++
139 lines
3.9 KiB
C++
#pragma once
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <cstring>
|
|
#include <atomic>
|
|
|
|
#include "def.h"
|
|
#include "log.h"
|
|
#include "platform/detail.h"
|
|
|
|
namespace ipc {
|
|
namespace detail {
|
|
|
|
class condition {
|
|
pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
|
|
pthread_cond_t cond_ = PTHREAD_COND_INITIALIZER;
|
|
|
|
public:
|
|
bool open(char const * name) {
|
|
if (name == nullptr || name[0] == '\0') return false;
|
|
int eno;
|
|
// init mutex
|
|
pthread_mutexattr_t mutex_attr;
|
|
if ((eno = ::pthread_mutexattr_init(&mutex_attr)) != 0) {
|
|
ipc::log("fail pthread_mutexattr_init[%d]: %s\n", eno, name);
|
|
return false;
|
|
}
|
|
IPC_UNUSED_ auto guard_mutex_attr = unique_ptr(&mutex_attr, ::pthread_mutexattr_destroy);
|
|
if ((eno = ::pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED)) != 0) {
|
|
ipc::log("fail pthread_mutexattr_setpshared[%d]: %s\n", eno, name);
|
|
return false;
|
|
}
|
|
if ((eno = ::pthread_mutex_init(&mutex_, &mutex_attr)) != 0) {
|
|
ipc::log("fail pthread_mutex_init[%d]: %s\n", eno, name);
|
|
return false;
|
|
}
|
|
auto guard_mutex = unique_ptr(&mutex_, ::pthread_mutex_destroy);
|
|
// init condition
|
|
pthread_condattr_t cond_attr;
|
|
if ((eno = ::pthread_condattr_init(&cond_attr)) != 0) {
|
|
ipc::log("fail pthread_condattr_init[%d]: %s\n", eno, name);
|
|
return false;
|
|
}
|
|
IPC_UNUSED_ auto guard_cond_attr = unique_ptr(&cond_attr, ::pthread_condattr_destroy);
|
|
if ((eno = ::pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED)) != 0) {
|
|
ipc::log("fail pthread_condattr_setpshared[%d]: %s\n", eno, name);
|
|
return false;
|
|
}
|
|
if ((eno = ::pthread_cond_init(&cond_, &cond_attr)) != 0) {
|
|
ipc::log("fail pthread_cond_init[%d]: %s\n", eno, name);
|
|
return false;
|
|
}
|
|
// no need to guard condition
|
|
// release guards
|
|
guard_mutex.release();
|
|
return true;
|
|
}
|
|
|
|
void close() {
|
|
::pthread_cond_destroy(&cond_);
|
|
::pthread_mutex_destroy(&mutex_);
|
|
}
|
|
|
|
bool wait() {
|
|
int eno;
|
|
if ((eno = ::pthread_mutex_lock(&mutex_)) != 0) {
|
|
ipc::log("fail pthread_mutex_lock[%d]\n", eno);
|
|
return false;
|
|
}
|
|
IPC_UNUSED_ auto guard = unique_ptr(&mutex_, ::pthread_mutex_unlock);
|
|
if ((eno = ::pthread_cond_wait(&cond_, &mutex_)) != 0) {
|
|
ipc::log("fail pthread_cond_wait[%d]\n", eno);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void notify() {
|
|
int eno;
|
|
if ((eno = ::pthread_cond_signal(&cond_)) != 0) {
|
|
ipc::log("fail pthread_cond_signal[%d]\n", eno);
|
|
}
|
|
}
|
|
|
|
void broadcast() {
|
|
int eno;
|
|
if ((eno = ::pthread_cond_broadcast(&cond_)) != 0) {
|
|
ipc::log("fail pthread_cond_broadcast[%d]\n", eno);
|
|
}
|
|
}
|
|
};
|
|
|
|
class waiter {
|
|
ipc::detail::condition cond_;
|
|
std::atomic<unsigned> counter_ { 0 };
|
|
|
|
public:
|
|
using handle_t = waiter*;
|
|
|
|
public:
|
|
constexpr static handle_t invalid() {
|
|
return nullptr;
|
|
}
|
|
|
|
handle_t open(char const * name) {
|
|
if (name == nullptr || name[0] == '\0') return invalid();
|
|
if ((counter_.fetch_add(1, std::memory_order_acq_rel) == 0) && !cond_.open(name)) {
|
|
return invalid();
|
|
}
|
|
return this;
|
|
}
|
|
|
|
void close(handle_t h) {
|
|
if (h == invalid()) return;
|
|
if (counter_.fetch_sub(1, std::memory_order_acq_rel) == 1) {
|
|
cond_.close();
|
|
}
|
|
}
|
|
|
|
bool wait(handle_t h) {
|
|
if (h == invalid()) return false;
|
|
return cond_.wait();
|
|
}
|
|
|
|
void notify(handle_t h) {
|
|
if (h == invalid()) return;
|
|
cond_.notify();
|
|
}
|
|
|
|
void broadcast(handle_t h) {
|
|
if (h == invalid()) return;
|
|
cond_.broadcast();
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
} // namespace ipc
|