mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2026-02-14 06:09:49 +08:00
fix bugs in force-push
This commit is contained in:
parent
fe3fc07829
commit
518550070d
@ -29,6 +29,8 @@ class conn_head {
|
|||||||
ipc::spin_lock lc_;
|
ipc::spin_lock lc_;
|
||||||
std::atomic<bool> constructed_;
|
std::atomic<bool> constructed_;
|
||||||
|
|
||||||
|
std::atomic<bool> dis_flag_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init() {
|
void init() {
|
||||||
/* DCLP */
|
/* DCLP */
|
||||||
@ -53,6 +55,21 @@ public:
|
|||||||
return cc_.fetch_sub(1, std::memory_order_acq_rel);
|
return cc_.fetch_sub(1, std::memory_order_acq_rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void try_disconnect() noexcept {
|
||||||
|
if (!dis_flag_.load(std::memory_order_acquire)) {
|
||||||
|
cc_.fetch_sub(1, std::memory_order_relaxed);
|
||||||
|
dis_flag_.store(true, std::memory_order_release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_dis_flag(std::memory_order order = std::memory_order_release) noexcept {
|
||||||
|
dis_flag_.store(false, order);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dis_flag(std::memory_order order = std::memory_order_acquire) const noexcept {
|
||||||
|
return dis_flag_.load(order);
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t conn_count(std::memory_order order = std::memory_order_acquire) const noexcept {
|
std::size_t conn_count(std::memory_order order = std::memory_order_acquire) const noexcept {
|
||||||
return cc_.load(order);
|
return cc_.load(order);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -95,6 +95,7 @@ struct conn_info_head {
|
|||||||
|
|
||||||
template <typename W, typename F>
|
template <typename W, typename F>
|
||||||
bool wait_for(W& waiter, F&& pred, std::size_t tm) {
|
bool wait_for(W& waiter, F&& pred, std::size_t tm) {
|
||||||
|
if (tm == 0) return !pred();
|
||||||
for (unsigned k = 0; pred();) {
|
for (unsigned k = 0; pred();) {
|
||||||
bool loop = true, ret = true;
|
bool loop = true, ret = true;
|
||||||
ipc::sleep(k, [&k, &loop, &ret, &waiter, &pred, tm] {
|
ipc::sleep(k, [&k, &loop, &ret, &waiter, &pred, tm] {
|
||||||
@ -245,7 +246,8 @@ static bool send(ipc::handle_t h, void const * data, std::size_t size) {
|
|||||||
return [info, que, msg_id](int remain, void const * data, std::size_t size) {
|
return [info, que, msg_id](int remain, void const * data, std::size_t size) {
|
||||||
if (!wait_for(info->wt_waiter_, [&] {
|
if (!wait_for(info->wt_waiter_, [&] {
|
||||||
return !que->push(que, msg_id, remain, data, size);
|
return !que->push(que, msg_id, remain, data, size);
|
||||||
}, default_timeut)) {
|
}, que->dis_flag() ? 0 : static_cast<std::size_t>(default_timeut))) {
|
||||||
|
ipc::log("force_push: msg_id = %zd, remain = %d, size = %zd\n", msg_id, remain, size);
|
||||||
if (!que->force_push(que, msg_id, remain, data, size)) {
|
if (!que->force_push(que, msg_id, remain, data, size)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,19 +105,22 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool wait(mutex& mtx, std::size_t tm = invalid_value) {
|
bool wait(mutex& mtx, std::size_t tm = invalid_value) {
|
||||||
if (tm == invalid_value) {
|
switch (tm) {
|
||||||
|
case 0:
|
||||||
|
return true;
|
||||||
|
case invalid_value:
|
||||||
IPC_PTHREAD_FUNC_(pthread_cond_wait, &cond_, &mtx.native());
|
IPC_PTHREAD_FUNC_(pthread_cond_wait, &cond_, &mtx.native());
|
||||||
}
|
default: {
|
||||||
else {
|
timespec ts;
|
||||||
timespec ts;
|
calc_wait_time(ts, tm);
|
||||||
calc_wait_time(ts, tm);
|
int eno;
|
||||||
int eno;
|
if ((eno = ::pthread_cond_timedwait(&cond_, &mtx.native(), &ts)) != 0) {
|
||||||
if ((eno = ::pthread_cond_timedwait(&cond_, &mtx.native(), &ts)) != 0) {
|
if (eno != ETIMEDOUT) {
|
||||||
if (eno != ETIMEDOUT) {
|
ipc::error("fail pthread_cond_timedwait[%d]: tm = %zd, tv_sec = %ld, tv_nsec = %ld\n",
|
||||||
ipc::error("fail pthread_cond_timedwait[%d]: tm = %zd, tv_sec = %ld, tv_nsec = %ld\n",
|
eno, tm, ts.tv_sec, ts.tv_nsec);
|
||||||
eno, tm, ts.tv_sec, ts.tv_nsec);
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -176,18 +179,21 @@ public:
|
|||||||
|
|
||||||
static bool wait(handle_t h, std::size_t tm = invalid_value) {
|
static bool wait(handle_t h, std::size_t tm = invalid_value) {
|
||||||
if (h == invalid()) return false;
|
if (h == invalid()) return false;
|
||||||
if (tm == invalid_value) {
|
switch (tm) {
|
||||||
|
case 0:
|
||||||
|
return true;
|
||||||
|
case invalid_value:
|
||||||
IPC_SEMAPHORE_FUNC_(sem_wait, h);
|
IPC_SEMAPHORE_FUNC_(sem_wait, h);
|
||||||
}
|
default: {
|
||||||
else {
|
timespec ts;
|
||||||
timespec ts;
|
calc_wait_time(ts, tm);
|
||||||
calc_wait_time(ts, tm);
|
if (::sem_timedwait(h, &ts) != 0) {
|
||||||
if (::sem_timedwait(h, &ts) != 0) {
|
if (errno != ETIMEDOUT) {
|
||||||
if (errno != ETIMEDOUT) {
|
ipc::error("fail sem_timedwait[%d]: tm = %zd, tv_sec = %ld, tv_nsec = %ld\n",
|
||||||
ipc::error("fail sem_timedwait[%d]: tm = %zd, tv_sec = %ld, tv_nsec = %ld\n",
|
errno, tm, ts.tv_sec, ts.tv_nsec);
|
||||||
errno, tm, ts.tv_sec, ts.tv_nsec);
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -190,14 +190,23 @@ struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
|
|||||||
|
|
||||||
template <typename W, typename F, typename E>
|
template <typename W, typename F, typename E>
|
||||||
bool push(W* wrapper, F&& f, E* elems) {
|
bool push(W* wrapper, F&& f, E* elems) {
|
||||||
auto cc = wrapper->conn_count(std::memory_order_relaxed);
|
E* el;
|
||||||
if (cc == 0) return false; // no reader
|
for (unsigned k = 0;;) {
|
||||||
auto* el = elems + circ::index_of(wt_.load(std::memory_order_acquire));
|
auto cc = wrapper->conn_count(std::memory_order_relaxed);
|
||||||
// check all consumers have finished reading this element
|
if (cc == 0) return false; // no reader
|
||||||
rc_t expected = 0;
|
el = elems + circ::index_of(wt_.load(std::memory_order_acquire));
|
||||||
if (!el->rc_.compare_exchange_strong(
|
// check all consumers have finished reading this element
|
||||||
expected, static_cast<rc_t>(cc), std::memory_order_acq_rel)) {
|
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
||||||
return false; // full
|
if (cur_rc) {
|
||||||
|
return false; // full
|
||||||
|
}
|
||||||
|
// cur_rc should be 0 here
|
||||||
|
if (el->rc_.compare_exchange_weak(
|
||||||
|
cur_rc, static_cast<rc_t>(cc), std::memory_order_release)) {
|
||||||
|
wrapper->clear_dis_flag(std::memory_order_relaxed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ipc::yield(k);
|
||||||
}
|
}
|
||||||
std::forward<F>(f)(&(el->data_));
|
std::forward<F>(f)(&(el->data_));
|
||||||
wt_.fetch_add(1, std::memory_order_release);
|
wt_.fetch_add(1, std::memory_order_release);
|
||||||
@ -206,13 +215,25 @@ struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
|
|||||||
|
|
||||||
template <typename W, typename F, typename E>
|
template <typename W, typename F, typename E>
|
||||||
bool force_push(W* wrapper, F&& f, E* elems) {
|
bool force_push(W* wrapper, F&& f, E* elems) {
|
||||||
auto cc = wrapper->conn_count(std::memory_order_relaxed);
|
E* el;
|
||||||
if (cc == 0) return false; // no reader
|
for (unsigned k = 0;;) {
|
||||||
cc = wrapper->disconnect() - 1; // disconnect a reader
|
auto cc = wrapper->conn_count(std::memory_order_relaxed);
|
||||||
if (cc == 0) return false; // no reader
|
if (cc == 0) return false; // no reader
|
||||||
auto* el = elems + circ::index_of(wt_.load(std::memory_order_acquire));
|
el = elems + circ::index_of(wt_.load(std::memory_order_acquire));
|
||||||
// reset reading flag
|
// check all consumers have finished reading this element
|
||||||
el->rc_.store(static_cast<rc_t>(cc), std::memory_order_relaxed);
|
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
||||||
|
if (cur_rc) {
|
||||||
|
wrapper->try_disconnect(); // try disconnect a reader
|
||||||
|
cc = wrapper->conn_count(std::memory_order_relaxed);
|
||||||
|
if (cc == 0) return false; // no reader
|
||||||
|
}
|
||||||
|
// just compare & exchange
|
||||||
|
if (el->rc_.compare_exchange_weak(
|
||||||
|
cur_rc, static_cast<rc_t>(cc), std::memory_order_release)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ipc::yield(k);
|
||||||
|
}
|
||||||
std::forward<F>(f)(&(el->data_));
|
std::forward<F>(f)(&(el->data_));
|
||||||
wt_.fetch_add(1, std::memory_order_release);
|
wt_.fetch_add(1, std::memory_order_release);
|
||||||
return true;
|
return true;
|
||||||
@ -267,10 +288,9 @@ struct prod_cons_impl<wr<relat::multi , relat::multi, trans::broadcast>> {
|
|||||||
circ::u2_t cur_ct;
|
circ::u2_t cur_ct;
|
||||||
for (unsigned k = 0;;) {
|
for (unsigned k = 0;;) {
|
||||||
auto cc = wrapper->conn_count(std::memory_order_relaxed);
|
auto cc = wrapper->conn_count(std::memory_order_relaxed);
|
||||||
if (cc == 0) {
|
if (cc == 0) return false; // no reader
|
||||||
return false; // no reader
|
|
||||||
}
|
|
||||||
el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
|
el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
|
||||||
|
// check all consumers have finished reading this element
|
||||||
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
||||||
if (cur_rc & rc_mask) {
|
if (cur_rc & rc_mask) {
|
||||||
return false; // full
|
return false; // full
|
||||||
@ -279,9 +299,10 @@ struct prod_cons_impl<wr<relat::multi , relat::multi, trans::broadcast>> {
|
|||||||
if ((cur_fl != cur_ct) && cur_fl) {
|
if ((cur_fl != cur_ct) && cur_fl) {
|
||||||
return false; // full
|
return false; // full
|
||||||
}
|
}
|
||||||
// (cur_rc & rc_mask) should == 0 here
|
// (cur_rc & rc_mask) should be 0 here
|
||||||
if (el->rc_.compare_exchange_weak(
|
if (el->rc_.compare_exchange_weak(
|
||||||
cur_rc, static_cast<rc_t>(cc) | ((cur_rc & ~rc_mask) + rc_incr), std::memory_order_release)) {
|
cur_rc, static_cast<rc_t>(cc) | ((cur_rc & ~rc_mask) + rc_incr), std::memory_order_release)) {
|
||||||
|
wrapper->clear_dis_flag(std::memory_order_relaxed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ipc::yield(k);
|
ipc::yield(k);
|
||||||
@ -298,20 +319,27 @@ struct prod_cons_impl<wr<relat::multi , relat::multi, trans::broadcast>> {
|
|||||||
bool force_push(W* wrapper, F&& f, E* elems) {
|
bool force_push(W* wrapper, F&& f, E* elems) {
|
||||||
E* el;
|
E* el;
|
||||||
circ::u2_t cur_ct;
|
circ::u2_t cur_ct;
|
||||||
auto cc = wrapper->conn_count(std::memory_order_relaxed);
|
|
||||||
if (cc == 0) return false; // no reader
|
|
||||||
wrapper->disconnect(); // disconnect a reader
|
|
||||||
for (unsigned k = 0;;) {
|
for (unsigned k = 0;;) {
|
||||||
cc = wrapper->conn_count(std::memory_order_relaxed);
|
auto cc = wrapper->conn_count(std::memory_order_relaxed);
|
||||||
if (cc == 0) return false; // no reader
|
if (cc == 0) return false; // no reader
|
||||||
el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
|
el = elems + circ::index_of(cur_ct = ct_.load(std::memory_order_relaxed));
|
||||||
|
// check all consumers have finished reading this element
|
||||||
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
||||||
el->rc_.store(static_cast<rc_t>(cc) | ((cur_rc & ~rc_mask) + rc_incr), std::memory_order_relaxed);
|
ipc::log("force_push: k = %d, cc = %zd, rc = %zd\n", k, cc, (cur_rc & rc_mask));
|
||||||
if (ct_.compare_exchange_weak(cur_ct, cur_ct + 1, std::memory_order_release)) {
|
if (cur_rc & rc_mask) {
|
||||||
|
wrapper->try_disconnect(); // try disconnect a reader
|
||||||
|
cc = wrapper->conn_count(std::memory_order_relaxed);
|
||||||
|
if (cc == 0) return false; // no reader
|
||||||
|
}
|
||||||
|
// just compare & exchange
|
||||||
|
if (el->rc_.compare_exchange_weak(
|
||||||
|
cur_rc, static_cast<rc_t>(cc) | ((cur_rc & ~rc_mask) + rc_incr), std::memory_order_release)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ipc::yield(k);
|
ipc::yield(k);
|
||||||
}
|
}
|
||||||
|
// only one thread/process would touch here at one time
|
||||||
|
ct_.store(cur_ct + 1, std::memory_order_release);
|
||||||
std::forward<F>(f)(&(el->data_));
|
std::forward<F>(f)(&(el->data_));
|
||||||
// set flag & try update wt
|
// set flag & try update wt
|
||||||
el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
|
el->f_ct_.store(~static_cast<flag_t>(cur_ct), std::memory_order_release);
|
||||||
|
|||||||
@ -125,6 +125,10 @@ public:
|
|||||||
return base_t::disconnect(elems_);
|
return base_t::disconnect(elems_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool dis_flag() {
|
||||||
|
return elems_->dis_flag();
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t conn_count() const noexcept {
|
std::size_t conn_count() const noexcept {
|
||||||
return (elems_ == nullptr) ? invalid_value : elems_->conn_count();
|
return (elems_ == nullptr) ? invalid_value : elems_->conn_count();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user