view release on metacpan or search on metacpan
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define BF_RWLOCK_WRITER_BIT 0x80000000U
#define BF_RWLOCK_PID_MASK 0x7FFFFFFFU
#define BF_RWLOCK_WR(pid) (BF_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & BF_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int bf_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int bf_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !bf_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < BF_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || bf_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
bf_occ_set(h, i);
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void bf_recover_after_timeout(BfHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= BF_RWLOCK_WRITER_BIT) {
uint32_t pid = val & BF_RWLOCK_PID_MASK;
if (!bf_pid_alive(pid))
bf_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= BF_RWLOCK_WRITER_BIT &&
!bf_pid_alive(cur & BF_RWLOCK_PID_MASK)) {
bf_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < BF_RWLOCK_SPIN_LIMIT, 1)) {
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= BF_RWLOCK_WRITER_BIT &&
!bf_pid_alive(expected & BF_RWLOCK_PID_MASK)) {
bf_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < BF_RWLOCK_SPIN_LIMIT, 1)) {
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!bf_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
lib/Data/Buffer/Shared.pm view on Meta::CPAN
Zero-copy:
my $sv = $buf->as_scalar; # mmap-aliased read-only scalar ref
The returned scalar aliases the mapped bytes directly (no copy) and holds a
reference to the buffer so the mapping stays alive while it is in use.
Cross-process notification (all variants):
my $efd = $buf->create_eventfd; # create + attach an eventfd, returns the fd
$buf->attach_eventfd($fd); # attach an already-open eventfd
view all matches for this distribution
view release on metacpan or search on metacpan
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define CMS_RWLOCK_WRITER_BIT 0x80000000U
#define CMS_RWLOCK_PID_MASK 0x7FFFFFFFU
#define CMS_RWLOCK_WR(pid) (CMS_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & CMS_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int cms_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int cms_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !cms_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < CMS_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || cms_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
cms_occ_set(h, i);
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void cms_recover_after_timeout(CmsHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= CMS_RWLOCK_WRITER_BIT) {
uint32_t pid = val & CMS_RWLOCK_PID_MASK;
if (!cms_pid_alive(pid))
cms_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= CMS_RWLOCK_WRITER_BIT &&
!cms_pid_alive(cur & CMS_RWLOCK_PID_MASK)) {
cms_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < CMS_RWLOCK_SPIN_LIMIT, 1)) {
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= CMS_RWLOCK_WRITER_BIT &&
!cms_pid_alive(expected & CMS_RWLOCK_PID_MASK)) {
cms_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < CMS_RWLOCK_SPIN_LIMIT, 1)) {
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!cms_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define CBF_RWLOCK_WRITER_BIT 0x80000000U
#define CBF_RWLOCK_PID_MASK 0x7FFFFFFFU
#define CBF_RWLOCK_WR(pid) (CBF_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & CBF_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int cbf_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int cbf_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !cbf_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < CBF_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || cbf_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
cbf_occ_set(h, i);
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void cbf_recover_after_timeout(CbfHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= CBF_RWLOCK_WRITER_BIT) {
uint32_t pid = val & CBF_RWLOCK_PID_MASK;
if (!cbf_pid_alive(pid))
cbf_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= CBF_RWLOCK_WRITER_BIT &&
!cbf_pid_alive(cur & CBF_RWLOCK_PID_MASK)) {
cbf_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < CBF_RWLOCK_SPIN_LIMIT, 1)) {
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= CBF_RWLOCK_WRITER_BIT &&
!cbf_pid_alive(expected & CBF_RWLOCK_PID_MASK)) {
cbf_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < CBF_RWLOCK_SPIN_LIMIT, 1)) {
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!cbf_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define CF_RWLOCK_WRITER_BIT 0x80000000U
#define CF_RWLOCK_PID_MASK 0x7FFFFFFFU
#define CF_RWLOCK_WR(pid) (CF_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & CF_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int cf_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int cf_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !cf_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < CF_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || cf_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
cf_occ_set(h, i);
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void cf_recover_after_timeout(CfHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= CF_RWLOCK_WRITER_BIT) {
uint32_t pid = val & CF_RWLOCK_PID_MASK;
if (!cf_pid_alive(pid))
cf_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= CF_RWLOCK_WRITER_BIT &&
!cf_pid_alive(cur & CF_RWLOCK_PID_MASK)) {
cf_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < CF_RWLOCK_SPIN_LIMIT, 1)) {
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= CF_RWLOCK_WRITER_BIT &&
!cf_pid_alive(expected & CF_RWLOCK_PID_MASK)) {
cf_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < CF_RWLOCK_SPIN_LIMIT, 1)) {
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!cf_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define DD_RWLOCK_WRITER_BIT 0x80000000U
#define DD_RWLOCK_PID_MASK 0x7FFFFFFFU
#define DD_RWLOCK_WR(pid) (DD_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & DD_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int dd_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int dd_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !dd_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < DD_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || dd_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
dd_occ_set(h, i);
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void dd_recover_after_timeout(DdHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= DD_RWLOCK_WRITER_BIT) {
uint32_t pid = val & DD_RWLOCK_PID_MASK;
if (!dd_pid_alive(pid))
dd_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= DD_RWLOCK_WRITER_BIT &&
!dd_pid_alive(cur & DD_RWLOCK_PID_MASK)) {
dd_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < DD_RWLOCK_SPIN_LIMIT, 1)) {
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= DD_RWLOCK_WRITER_BIT &&
!dd_pid_alive(expected & DD_RWLOCK_PID_MASK)) {
dd_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < DD_RWLOCK_SPIN_LIMIT, 1)) {
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!dd_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define DSU_RWLOCK_WRITER_BIT 0x80000000U
#define DSU_RWLOCK_PID_MASK 0x7FFFFFFFU
#define DSU_RWLOCK_WR(pid) (DSU_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & DSU_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int dsu_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int dsu_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !dsu_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < DSU_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || dsu_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
dsu_occ_set(h, i);
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void dsu_recover_after_timeout(DsuHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= DSU_RWLOCK_WRITER_BIT) {
uint32_t pid = val & DSU_RWLOCK_PID_MASK;
if (!dsu_pid_alive(pid))
dsu_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= DSU_RWLOCK_WRITER_BIT &&
!dsu_pid_alive(cur & DSU_RWLOCK_PID_MASK)) {
dsu_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < DSU_RWLOCK_SPIN_LIMIT, 1)) {
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= DSU_RWLOCK_WRITER_BIT &&
!dsu_pid_alive(expected & DSU_RWLOCK_PID_MASK)) {
dsu_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < DSU_RWLOCK_SPIN_LIMIT, 1)) {
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!dsu_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
lib/Data/Dump/Streamer.pm view on Meta::CPAN
# from link from [ysth]: http://groups.google.com/groups?selm=laUs8gzkgOlT092yn%40efn.org
# translate arg (or reference to it) into a B::* object
# To work-around perl commit
# 2acc3314e31a9342e325f35c5b592967c9850c9b, keep the
# value \*$lhs alive while we inspect it as a B object
# or else it'll be reaped while we're using it.
my $lhs_glob= \*$lhs;
my $Bobj= B::svref_2object($lhs_glob);
# if passed a glob or globref, get the format
view all matches for this distribution
view release on metacpan or search on metacpan
lib/Data/Edit/Xml.pm view on Meta::CPAN
die "success!"; # Halt the search
}
});
};
confess $@ if $@ and $@ !~ /success!/; # Report any suppressed error messages at this point
$x # Return node found if we are still alive
}
sub firstSibling($@) #CYU Return the first sibling of the specified B<$node> in the optional B<@context> else B<undef>
{my ($node, @context) = @_; # Node, array of tags specifying context.
return undef if @context and !$node->at(@context); # Not in specified context
lib/Data/Edit/Xml.pm view on Meta::CPAN
die "success!"; # Halt the search
}
});
};
confess $@ if $@ and $@ !~ /success!/; # Report any suppressed error messages at this point
$x # Return node found if we are still alive
}
sub lastSibling($@) #CYU Return the last sibling of the specified B<$node> in the optional B<@context> else B<undef>
{my ($node, @context) = @_; # Node, array of tags specifying context.
return undef if @context and !$node->at(@context); # Not in specified context
view all matches for this distribution
view release on metacpan or search on metacpan
lib/Data/FR/Town.pm view on Meta::CPAN
21574;;Saint-Seine-sur-Vingeanne;SAINT-SEINE-SUR-VINGEANNE;21610;21;COTE D'OR;1
21575;;Saint-Symphorien-sur-Saône;SAINT-SYMPHORIEN-SUR-SAONE;21170;21;COTE D'OR;1
21576;;Saint-Thibault;SAINT-THIBAULT;21350;21;COTE D'OR;1
21577;;Saint-Usage;SAINT-USAGE;21170;21;COTE D'OR;1
21578;;Saint-Victor-sur-Ouche;SAINT-VICTOR-SUR-OUCHE;21410;21;COTE D'OR;1
21579;;Salives;SALIVES;21580;21;COTE D'OR;1
21580;;Salmaise;SALMAISE;21690;21;COTE D'OR;1
21581;;Samerey;SAMEREY;21170;21;COTE D'OR;1
21582;;Santenay;SANTENAY;21590;21;COTE D'OR;1
21583;;Santosse;SANTOSSE;21340;21;COTE D'OR;1
21584;;Saulieu;SAULIEU;21210;21;COTE D'OR;1
lib/Data/FR/Town.pm view on Meta::CPAN
33535;;Tresses;TRESSES;33370;33;GIRONDE;1
33536;Le;Tuzan;TUZAN;33125;33;GIRONDE;1
33537;;Uzeste;UZESTE;33730;33;GIRONDE;1
33538;;Valeyrac;VALEYRAC;33340;33;GIRONDE;1
33539;;Vayres;VAYRES;33870;33;GIRONDE;1
33540;;Vendays-Montalivet;VENDAYS-MONTALIVET;33930;33;GIRONDE;1
33541;;Vensac;VENSAC;33590;33;GIRONDE;1
33542;;Vérac;VERAC;33240;33;GIRONDE;1
33543;;Verdelais;VERDELAIS;33490;33;GIRONDE;1
33544;Le;Verdon-sur-Mer;VERDON-SUR-MER;33123;33;GIRONDE;1
33545;;Vertheuil;VERTHEUIL;33180;33;GIRONDE;1
view all matches for this distribution
view release on metacpan or search on metacpan
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define FEN_RWLOCK_WRITER_BIT 0x80000000U
#define FEN_RWLOCK_PID_MASK 0x7FFFFFFFU
#define FEN_RWLOCK_WR(pid) (FEN_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & FEN_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int fen_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int fen_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !fen_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < FEN_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || fen_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
fen_occ_set(h, i);
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void fen_recover_after_timeout(FenHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= FEN_RWLOCK_WRITER_BIT) {
uint32_t pid = val & FEN_RWLOCK_PID_MASK;
if (!fen_pid_alive(pid))
fen_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= FEN_RWLOCK_WRITER_BIT &&
!fen_pid_alive(cur & FEN_RWLOCK_PID_MASK)) {
fen_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < FEN_RWLOCK_SPIN_LIMIT, 1)) {
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= FEN_RWLOCK_WRITER_BIT &&
!fen_pid_alive(expected & FEN_RWLOCK_PID_MASK)) {
fen_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < FEN_RWLOCK_SPIN_LIMIT, 1)) {
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!fen_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
fenwick2d.h view on Meta::CPAN
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define F2D_RWLOCK_WRITER_BIT 0x80000000U
#define F2D_RWLOCK_PID_MASK 0x7FFFFFFFU
#define F2D_RWLOCK_WR(pid) (F2D_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & F2D_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int f2d_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
fenwick2d.h view on Meta::CPAN
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int f2d_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !f2d_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
fenwick2d.h view on Meta::CPAN
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < F2D_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || f2d_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
f2d_occ_set(h, i);
fenwick2d.h view on Meta::CPAN
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void f2d_recover_after_timeout(F2dHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= F2D_RWLOCK_WRITER_BIT) {
uint32_t pid = val & F2D_RWLOCK_PID_MASK;
if (!f2d_pid_alive(pid))
f2d_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
fenwick2d.h view on Meta::CPAN
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= F2D_RWLOCK_WRITER_BIT &&
!f2d_pid_alive(cur & F2D_RWLOCK_PID_MASK)) {
f2d_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < F2D_RWLOCK_SPIN_LIMIT, 1)) {
fenwick2d.h view on Meta::CPAN
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= F2D_RWLOCK_WRITER_BIT &&
!f2d_pid_alive(expected & F2D_RWLOCK_PID_MASK)) {
f2d_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < F2D_RWLOCK_SPIN_LIMIT, 1)) {
fenwick2d.h view on Meta::CPAN
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!f2d_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
* Mutex (same pattern as Heap)
* ================================================================ */
static const struct timespec graph_lock_timeout = { 2, 0 };
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int graph_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
static inline int graph_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !graph_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
static inline void graph_mutex_lock(GraphHeader *hdr) {
if (cur != 0) {
long rc = syscall(SYS_futex, &hdr->mutex, FUTEX_WAIT, cur,
&graph_lock_timeout, NULL, 0);
if (rc == -1 && errno == ETIMEDOUT && cur >= GRAPH_MUTEX_BIT) {
uint32_t pid = cur & GRAPH_MUTEX_PID;
if (!graph_pid_alive(pid) &&
__atomic_compare_exchange_n(&hdr->mutex, &cur, 0,
0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED)) {
/* Recovered -- wake one waiter so it can proceed. */
syscall(SYS_futex, &hdr->mutex, FUTEX_WAKE, 1, NULL, NULL, 0);
}
view all matches for this distribution
view release on metacpan or search on metacpan
my $v = shm_si_get $map, "counter";
printf "counter=%s (expired: %s)\n", $v // 'undef', defined $v ? 'no' : 'yes';
my $p = shm_si_get $map, "permanent";
printf "permanent=%s (still alive)\n", $p;
$map->unlink;
view all matches for this distribution
view release on metacpan or search on metacpan
sleep 1;
# Re-put refreshes TTL
hm_ii_put $m, 1, 20;
sleep 2;
# 3 seconds since original put, but only 2 since refresh (TTL=3)
is(hm_ii_get $m, 1, 20, 'TTL: put refresh keeps entry alive');
}
# ---- Iteration skips expired entries ----
{
view all matches for this distribution
view release on metacpan or search on metacpan
* Mutex (PID-based, stale-recoverable)
* ================================================================ */
static const struct timespec heap_lock_timeout = { 2, 0 };
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int heap_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
static inline int heap_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !heap_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
static inline void heap_mutex_lock(HeapHeader *hdr) {
if (cur != 0) {
long rc = syscall(SYS_futex, &hdr->mutex, FUTEX_WAIT, cur,
&heap_lock_timeout, NULL, 0);
if (rc == -1 && errno == ETIMEDOUT && cur >= HEAP_MUTEX_BIT) {
uint32_t pid = cur & HEAP_MUTEX_PID;
if (!heap_pid_alive(pid)) {
if (__atomic_compare_exchange_n(&hdr->mutex, &cur, 0,
0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED)) {
__atomic_add_fetch(&hdr->stat_recoveries, 1, __ATOMIC_RELAXED);
/* Wake one waiter so recovery latency is not bounded by the 2s timeout. */
if (__atomic_load_n(&hdr->mutex_waiters, __ATOMIC_RELAXED) > 0)
view all matches for this distribution
view release on metacpan or search on metacpan
hiertimingwheel.h view on Meta::CPAN
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define HW_RWLOCK_WRITER_BIT 0x80000000U
#define HW_RWLOCK_PID_MASK 0x7FFFFFFFU
#define HW_RWLOCK_WR(pid) (HW_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & HW_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int hw_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
hiertimingwheel.h view on Meta::CPAN
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int hw_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !hw_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
hiertimingwheel.h view on Meta::CPAN
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < HW_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || hw_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
hw_occ_set(h, i);
hiertimingwheel.h view on Meta::CPAN
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void hw_recover_after_timeout(HwHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= HW_RWLOCK_WRITER_BIT) {
uint32_t pid = val & HW_RWLOCK_PID_MASK;
if (!hw_pid_alive(pid))
hw_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
hiertimingwheel.h view on Meta::CPAN
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= HW_RWLOCK_WRITER_BIT &&
!hw_pid_alive(cur & HW_RWLOCK_PID_MASK)) {
hw_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < HW_RWLOCK_SPIN_LIMIT, 1)) {
hiertimingwheel.h view on Meta::CPAN
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= HW_RWLOCK_WRITER_BIT &&
!hw_pid_alive(expected & HW_RWLOCK_PID_MASK)) {
hw_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < HW_RWLOCK_SPIN_LIMIT, 1)) {
hiertimingwheel.h view on Meta::CPAN
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!hw_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define HIST_RWLOCK_WRITER_BIT 0x80000000U
#define HIST_RWLOCK_PID_MASK 0x7FFFFFFFU
#define HIST_RWLOCK_WR(pid) (HIST_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & HIST_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int hist_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int hist_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !hist_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < HIST_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || hist_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
hist_occ_set(h, i);
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void hist_recover_after_timeout(HistHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= HIST_RWLOCK_WRITER_BIT) {
uint32_t pid = val & HIST_RWLOCK_PID_MASK;
if (!hist_pid_alive(pid))
hist_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= HIST_RWLOCK_WRITER_BIT &&
!hist_pid_alive(cur & HIST_RWLOCK_PID_MASK)) {
hist_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < HIST_RWLOCK_SPIN_LIMIT, 1)) {
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= HIST_RWLOCK_WRITER_BIT &&
!hist_pid_alive(expected & HIST_RWLOCK_PID_MASK)) {
hist_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < HIST_RWLOCK_SPIN_LIMIT, 1)) {
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!hist_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define HLL_RWLOCK_WRITER_BIT 0x80000000U
#define HLL_RWLOCK_PID_MASK 0x7FFFFFFFU
#define HLL_RWLOCK_WR(pid) (HLL_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & HLL_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int hll_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int hll_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !hll_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < HLL_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || hll_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
hll_occ_set(h, i);
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void hll_recover_after_timeout(HllHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= HLL_RWLOCK_WRITER_BIT) {
uint32_t pid = val & HLL_RWLOCK_PID_MASK;
if (!hll_pid_alive(pid))
hll_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= HLL_RWLOCK_WRITER_BIT &&
!hll_pid_alive(cur & HLL_RWLOCK_PID_MASK)) {
hll_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < HLL_RWLOCK_SPIN_LIMIT, 1)) {
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= HLL_RWLOCK_WRITER_BIT &&
!hll_pid_alive(expected & HLL_RWLOCK_PID_MASK)) {
hll_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < HLL_RWLOCK_SPIN_LIMIT, 1)) {
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!hll_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define SI_RWLOCK_WRITER_BIT 0x80000000U
#define SI_RWLOCK_PID_MASK 0x7FFFFFFFU
#define SI_RWLOCK_WR(pid) (SI_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & SI_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int si_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int si_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !si_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < SI_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || si_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
si_occ_set(h, i);
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void si_recover_after_timeout(SiHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= SI_RWLOCK_WRITER_BIT) {
uint32_t pid = val & SI_RWLOCK_PID_MASK;
if (!si_pid_alive(pid))
si_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= SI_RWLOCK_WRITER_BIT &&
!si_pid_alive(cur & SI_RWLOCK_PID_MASK)) {
si_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < SI_RWLOCK_SPIN_LIMIT, 1)) {
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= SI_RWLOCK_WRITER_BIT &&
!si_pid_alive(expected & SI_RWLOCK_PID_MASK)) {
si_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < SI_RWLOCK_SPIN_LIMIT, 1)) {
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!si_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
intervaltree.h view on Meta::CPAN
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define IT_RWLOCK_WRITER_BIT 0x80000000U
#define IT_RWLOCK_PID_MASK 0x7FFFFFFFU
#define IT_RWLOCK_WR(pid) (IT_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & IT_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int it_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
intervaltree.h view on Meta::CPAN
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int it_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !it_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
intervaltree.h view on Meta::CPAN
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < IT_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || it_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
it_occ_set(h, i);
intervaltree.h view on Meta::CPAN
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void it_recover_after_timeout(ItHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= IT_RWLOCK_WRITER_BIT) {
uint32_t pid = val & IT_RWLOCK_PID_MASK;
if (!it_pid_alive(pid))
it_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
intervaltree.h view on Meta::CPAN
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= IT_RWLOCK_WRITER_BIT &&
!it_pid_alive(cur & IT_RWLOCK_PID_MASK)) {
it_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < IT_RWLOCK_SPIN_LIMIT, 1)) {
intervaltree.h view on Meta::CPAN
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= IT_RWLOCK_WRITER_BIT &&
!it_pid_alive(expected & IT_RWLOCK_PID_MASK)) {
it_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < IT_RWLOCK_SPIN_LIMIT, 1)) {
intervaltree.h view on Meta::CPAN
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!it_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define KD_RWLOCK_WRITER_BIT 0x80000000U
#define KD_RWLOCK_PID_MASK 0x7FFFFFFFU
#define KD_RWLOCK_WR(pid) (KD_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & KD_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int kd_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int kd_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !kd_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < KD_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || kd_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
kd_occ_set(h, i);
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void kd_recover_after_timeout(KdHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= KD_RWLOCK_WRITER_BIT) {
uint32_t pid = val & KD_RWLOCK_PID_MASK;
if (!kd_pid_alive(pid))
kd_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= KD_RWLOCK_WRITER_BIT &&
!kd_pid_alive(cur & KD_RWLOCK_PID_MASK)) {
kd_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < KD_RWLOCK_SPIN_LIMIT, 1)) {
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= KD_RWLOCK_WRITER_BIT &&
!kd_pid_alive(expected & KD_RWLOCK_PID_MASK)) {
kd_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < KD_RWLOCK_SPIN_LIMIT, 1)) {
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!kd_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
msgpack-3.3.0/README view on Meta::CPAN
msgpack_pack_true(&pk);
msgpack_pack_str(&pk, 7);
msgpack_pack_str_body(&pk, "example", 7);
/* deserialize the buffer into msgpack_object instance. */
/* deserialized object is valid during the msgpack_zone instance alive. */
msgpack_zone mempool;
msgpack_zone_init(&mempool, 2048);
msgpack_object deserialized;
msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized);
msgpack-3.3.0/README view on Meta::CPAN
std::string str(buffer.str());
msgpack::object_handle oh =
msgpack::unpack(str.data(), str.size());
// deserialized object is valid during the msgpack::object_handle instance is alive.
msgpack::object deserialized = oh.get();
// msgpack::object supports ostream.
std::cout << deserialized << std::endl;
view all matches for this distribution
view release on metacpan or search on metacpan
/* Writer word encoding: WRITER_BIT|pid when write-locked, 0 when free. */
#define MNH_RWLOCK_WRITER_BIT 0x80000000U
#define MNH_RWLOCK_PID_MASK 0x7FFFFFFFU
#define MNH_RWLOCK_WR(pid) (MNH_RWLOCK_WRITER_BIT | ((uint32_t)(pid) & MNH_RWLOCK_PID_MASK))
/* A zombie (dead but not yet reaped) still answers kill(pid,0) as alive, so a
* process that crashed while holding the lock and lingers unreaped would never
* be recovered. Treat /proc/<pid>/stat state 'Z' as dead. Linux-only (as is
* this module); if /proc is unreadable we fall back to "alive" (safe: we never
* force-recover a possibly-live holder). */
static inline int mnh_pid_is_zombie(uint32_t pid) {
char path[32], buf[256];
snprintf(path, sizeof(path), "/proc/%u/stat", (unsigned)pid);
int fd = open(path, O_RDONLY | O_CLOEXEC);
/* "pid (comm) state ..."; comm may contain ')', so scan to the last one. */
char *rp = strrchr(buf, ')');
if (!rp || rp + 2 >= buf + n) return 0; /* need ") X" within the bytes read */
return rp[1] == ' ' && rp[2] == 'Z';
}
/* 1 if alive or unknown, 0 if definitely dead. Cannot detect PID reuse: a
* recycled PID reports "alive" and the slot is not reclaimed until that
* process exits. See "Crash Safety" in the POD. */
static inline int mnh_pid_alive(uint32_t pid) {
if (pid == 0) return 1; /* no owner recorded, assume alive */
if (kill((pid_t)pid, 0) == -1 && errno == ESRCH) return 0; /* definitely dead */
return !mnh_pid_is_zombie(pid); /* kill() also succeeds for a zombie -> treat as dead */
}
/* Force-recover a stale WRITE lock left by a dead writer (held or mid-drain).
* if its rdepth>0: clearing pid drops the dead reader's entire contribution
* (a writer scan ignores rdepth when pid==0) and we reset rdepth to 0 as we
* claim it. */
for (uint32_t i = 0; i < MNH_READER_SLOTS; i++) {
uint32_t dpid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (dpid == 0 || dpid == now_pid || mnh_pid_alive(dpid)) continue;
uint32_t expected = dpid;
if (__atomic_compare_exchange_n(&h->reader_slots[i].pid, &expected, now_pid, 0,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__atomic_store_n(&h->reader_slots[i].rdepth, 0, __ATOMIC_RELAXED);
mnh_occ_set(h, i);
* wlock drains readers, and it clears dead readers inline in its own scan. */
static inline void mnh_recover_after_timeout(MnhHandle *h) {
uint32_t val = __atomic_load_n(&h->hdr->wlock, __ATOMIC_RELAXED);
if (val >= MNH_RWLOCK_WRITER_BIT) {
uint32_t pid = val & MNH_RWLOCK_PID_MASK;
if (!mnh_pid_alive(pid))
mnh_recover_stale_lock(h, val);
}
}
/* Bump/drop the parked-waiter hint. Both readers (blocked at the gate) and
spin = 0;
continue;
}
/* wlock != 0: a writer holds or is acquiring. Recover if it is dead. */
if (cur >= MNH_RWLOCK_WRITER_BIT &&
!mnh_pid_alive(cur & MNH_RWLOCK_PID_MASK)) {
mnh_recover_stale_lock(h, cur);
spin = 0;
continue;
}
if (__builtin_expect(spin < MNH_RWLOCK_SPIN_LIMIT, 1)) {
if (__atomic_compare_exchange_n(&hdr->wlock, &expected, mypid,
0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED))
break;
/* Contended: expected now holds the current wlock value. */
if (expected >= MNH_RWLOCK_WRITER_BIT &&
!mnh_pid_alive(expected & MNH_RWLOCK_PID_MASK)) {
mnh_recover_stale_lock(h, expected);
spin = 0;
continue;
}
if (__builtin_expect(spin < MNH_RWLOCK_SPIN_LIMIT, 1)) {
word &= word - 1; /* consume this bit (local copy) */
uint32_t rd = __atomic_load_n(&h->reader_slots[i].rdepth, __ATOMIC_SEQ_CST);
if (rd == 0) continue; /* occupied but not read-locking now */
uint32_t pid = __atomic_load_n(&h->reader_slots[i].pid, __ATOMIC_ACQUIRE);
if (pid == 0) continue; /* stale rdepth on a freed slot */
if (!mnh_pid_alive(pid)) {
/* Dead reader: drop its pid so the slot no longer counts. Leave
* the occ bit set (harmless -- a later scan hits pid==0 and skips,
* a re-claim re-sets it) to avoid racing a concurrent claimant. */
uint32_t ep = pid;
__atomic_compare_exchange_n(&h->reader_slots[i].pid, &ep, 0,
view all matches for this distribution
view release on metacpan or search on metacpan
lib/Data/NDArray/Shared.pm view on Meta::CPAN
}
# Zero-copy: a PDL ndarray ALIASING this array's shared mmap, built via PDL's C
# API (PDL_DONTTOUCHDATA, so PDL never frees/reallocates our mapping). In-place
# PDL ops write straight through (visible to every sharing process); reads see
# live data. NO locking -- coordinate access yourself. The array is kept alive
# while the piddle lives. Needs PDL at BUILD time (the C path); croaks otherwise.
sub as_pdl_alias {
my ($self) = @_;
_require_pdl();
my $typenum = _pdl_ctor($self->dtype)->()->enum; # PDL type number for our dtype
# _alias_pdl_create croaks if the module was built without PDL (no C path).
my $p = $self->_alias_pdl_create($typenum, [ reverse $self->shape ]); # dims in PDL order
$p->hdr->{_nda_shared} = $self; # keep the mapping alive while the piddle lives
return $p;
}
1;
__END__
lib/Data/NDArray/Shared.pm view on Meta::CPAN
A piddle that B<aliases the shared mapping with no copy> (a real
C<PDL_DONTTOUCHDATA> ndarray over our memory): an B<in-place> PDL operation
(C<< $p .= ... >>, C<< $p-E<gt>inplace-E<gt>... >>) writes straight through to
shared memory -- visible to every process that maps it -- and reads see live
data. The array is kept alive for as long as the piddle.
This one method needs PDL at B<build> time (it is compiled against PDL's C API):
if the module was installed without PDL present it C<croak>s, while the copy
methods above keep working through a runtime C<require PDL>. Reinstall with PDL
installed to enable it.
view all matches for this distribution
view release on metacpan or search on metacpan
share/dictionary.txt view on Meta::CPAN
alike
alimentary
alimony
alimony's
alit
alive
alkali
alkali's
alkalies
alkaline
alkalinity
view all matches for this distribution
view release on metacpan or search on metacpan
lib/Data/Password/Top10000.pm view on Meta::CPAN
bambi
babycake
aprilia
ANDREW
allgood
alive
adriano
808080
7777777a
777666
31121986
view all matches for this distribution
view release on metacpan or search on metacpan
src/passwdqc/wordset_4k.c view on Meta::CPAN
"alibi",
"alien",
"alight",
"align",
"alike",
"alive",
"alkali",
"all",
"alley",
"allied",
"allow",
view all matches for this distribution
view release on metacpan or search on metacpan
lib/Data/Password/zxcvbn/RankedDictionaries/English.pm view on Meta::CPAN
'aliens' => 2024,
'alight' => 18559,
'alike' => 2174,
'alimony' => 6443,
'alistair' => 2423,
'alive' => 435,
'all' => 25,
'allah' => 5270,
'allahu' => 18558,
'allegiances' => 21432,
'alleluia' => 16553,
view all matches for this distribution