Branch Coverage

pubsub.h
Criterion Covered Total %
branch 242 450 53.7


line true false branch
163 0 149 if (v < 2) return 2;
164 0 149 if (v > 0x80000000U) return 0;
181 688 270 if (needed <= sub->copy_buf_cap) return 1;
182 33 237 uint32_t ns = sub->copy_buf_cap ? sub->copy_buf_cap : 64;
183 69 270 while (ns < needed) {
185 0 69 if (n2 <= ns) { ns = needed; break; }
189 0 270 if (!nb) return 0;
204 0 0 if (pid == 0) return 1;
205 0 0 return !(kill((pid_t)pid, 0) == -1 && errno == ESRCH);
0 0 return !(kill((pid_t)pid, 0) == -1 && errno == ESRCH);
211 0 0 if (!__atomic_compare_exchange_n(&hdr->mutex, &observed, 0,
215 0 0 if (__atomic_load_n(&hdr->mutex_waiters, __ATOMIC_RELAXED) > 0)
223 397 0 if (__atomic_compare_exchange_n(&hdr->mutex, &expected, mypid,
226 0 0 if (__builtin_expect(spin < PUBSUB_SPIN_LIMIT, 1)) {
232 0 0 if (cur != 0) {
235 0 0 if (rc == -1 && errno == ETIMEDOUT) {
0 0 if (rc == -1 && errno == ETIMEDOUT) {
238 0 0 if (val >= PUBSUB_MUTEX_WRITER_BIT) {
240 0 0 if (!pubsub_pid_alive(pid))
254 0 397 if (__atomic_load_n(&hdr->mutex_waiters, __ATOMIC_RELAXED) > 0)
265 97 879 if (__atomic_load_n(&hdr->sub_waiters, __ATOMIC_RELAXED) > 0) {
277 6 5 if (remaining->tv_nsec < 0) {
288 0 11 if (deadline->tv_nsec >= 1000000000L) {
300 20 0 if (hdr->magic != PUBSUB_MAGIC ||
301 20 0 hdr->version != PUBSUB_VERSION ||
302 16 4 hdr->mode != mode ||
303 16 0 hdr->capacity == 0 ||
304 16 0 (hdr->capacity & (hdr->capacity - 1)) != 0 ||
305 16 0 hdr->total_size != file_size ||
306 0 16 hdr->slots_off != sizeof(PubSubHeader))
310 6 10 : (mode == PUBSUB_MODE_INT32) ? sizeof(PubSubInt32Slot)
311 5 1 : (mode == PUBSUB_MODE_INT16) ? sizeof(PubSubInt16Slot)
312 1 4 : sizeof(PubSubStrSlot);
313 0 16 if (hdr->capacity > (hdr->total_size - hdr->slots_off) / slot_size)
315 4 12 if (mode == PUBSUB_MODE_STR) {
316 4 0 if (hdr->data_off == 0 || hdr->msg_size == 0 || hdr->arena_cap == 0)
4 0 if (hdr->data_off == 0 || hdr->msg_size == 0 || hdr->arena_cap == 0)
0 4 if (hdr->data_off == 0 || hdr->msg_size == 0 || hdr->arena_cap == 0)
319 4 0 if (hdr->data_off < slots_end ||
320 0 4 hdr->data_off + hdr->arena_cap > hdr->total_size)
336 0 149 if (!h) return NULL;
340 57 92 h->data = (mode == PUBSUB_MODE_STR) ? (char *)base + hdr->data_off : NULL;
347 47 102 h->path = path ? strdup(path) : NULL;
378 82 67 : (mode == PUBSUB_MODE_INT32) ? sizeof(PubSubInt32Slot)
379 69 13 : (mode == PUBSUB_MODE_INT16) ? sizeof(PubSubInt16Slot)
380 12 57 : sizeof(PubSubStrSlot);
383 57 92 if (mode == PUBSUB_MODE_STR) {
394 0 57 if (arena_cap > UINT32_MAX) {
413 51 0 for (int attempt = 0; attempt < 100; attempt++) {
415 35 16 if (fd >= 0) { (void)fchmod(fd, mode); return fd; } /* exact mode: umask narrowed the O_EXCL create */
416 0 16 if (errno != EEXIST) { PUBSUB_ERR("create %s: %s", path, strerror(errno)); return -1; }
0 0 if (errno != EEXIST) { PUBSUB_ERR("create %s: %s", path, strerror(errno)); return -1; }
418 16 0 if (fd >= 0) return fd;
419 0 0 if (errno == ENOENT) continue; /* creator unlinked between our two opens; retry */
420 0 0 PUBSUB_ERR("open %s: %s", path, strerror(errno)); /* ELOOP => symlink rejected */
423 0 0 PUBSUB_ERR("open %s: create/attach kept racing", path);
430 145 0 if (errbuf) errbuf[0] = '\0';
433 0 145 if (cap == 0) { PUBSUB_ERR("invalid capacity"); return NULL; }
0 0 if (cap == 0) { PUBSUB_ERR("invalid capacity"); return NULL; }
434 0 145 if (mode > PUBSUB_MODE_INT16) { PUBSUB_ERR("unknown mode %u", mode); return NULL; }
0 0 if (mode > PUBSUB_MODE_INT16) { PUBSUB_ERR("unknown mode %u", mode); return NULL; }
436 56 89 if (mode == PUBSUB_MODE_STR && msg_size == 0)
35 21 if (mode == PUBSUB_MODE_STR && msg_size == 0)
440 0 145 if (!pubsub_calc_layout(cap, mode, msg_size, &slots_off, &data_off, &arena_cap, &total_size)) {
441 0 0 PUBSUB_ERR("capacity * (msg_size+8) exceeds 4GB arena limit");
449 94 51 if (anonymous) {
453 0 94 if (base == MAP_FAILED) {
454 0 0 PUBSUB_ERR("mmap(anonymous): %s", strerror(errno));
461 0 51 if (fd < 0) return NULL;
463 0 51 if (flock(fd, LOCK_EX) < 0) {
464 0 0 PUBSUB_ERR("flock(%s): %s", path, strerror(errno));
469 0 51 if (fstat(fd, &st) < 0) {
470 0 0 PUBSUB_ERR("fstat(%s): %s", path, strerror(errno));
476 16 35 if (!is_new && (uint64_t)st.st_size < sizeof(PubSubHeader)) {
0 16 if (!is_new && (uint64_t)st.st_size < sizeof(PubSubHeader)) {
477 0 0 PUBSUB_ERR("%s: file too small (%lld)", path, (long long)st.st_size);
481 35 16 if (is_new) {
482 0 35 if (ftruncate(fd, (off_t)total_size) < 0) {
483 0 0 PUBSUB_ERR("ftruncate(%s): %s", path, strerror(errno));
488 16 35 map_size = is_new ? (size_t)total_size : (size_t)st.st_size;
490 0 51 if (base == MAP_FAILED) {
491 0 0 PUBSUB_ERR("mmap(%s): %s", path, strerror(errno));
495 16 35 if (!is_new) {
496 4 12 if (!pubsub_validate_header((PubSubHeader *)base, mode, (uint64_t)st.st_size)) {
497 4 0 PUBSUB_ERR("%s: invalid or incompatible pubsub file", path);
512 0 129 if (!h) { munmap(base, (size_t)total_size); return NULL; }
519 4 0 if (errbuf) errbuf[0] = '\0';
522 0 4 if (cap == 0) { PUBSUB_ERR("invalid capacity"); return NULL; }
0 0 if (cap == 0) { PUBSUB_ERR("invalid capacity"); return NULL; }
523 0 4 if (mode > PUBSUB_MODE_INT16) { PUBSUB_ERR("unknown mode %u", mode); return NULL; }
0 0 if (mode > PUBSUB_MODE_INT16) { PUBSUB_ERR("unknown mode %u", mode); return NULL; }
525 1 3 if (mode == PUBSUB_MODE_STR && msg_size == 0)
1 0 if (mode == PUBSUB_MODE_STR && msg_size == 0)
529 0 4 if (!pubsub_calc_layout(cap, mode, msg_size, &slots_off, &data_off, &arena_cap, &total_size)) {
530 0 0 PUBSUB_ERR("capacity * (msg_size+8) exceeds 4GB arena limit");
534 4 0 int fd = memfd_create(name ? name : "pubsub", MFD_CLOEXEC | MFD_ALLOW_SEALING);
535 0 4 if (fd < 0) { PUBSUB_ERR("memfd_create: %s", strerror(errno)); return NULL; }
0 0 if (fd < 0) { PUBSUB_ERR("memfd_create: %s", strerror(errno)); return NULL; }
537 0 4 if (ftruncate(fd, (off_t)total_size) < 0) {
538 0 0 PUBSUB_ERR("ftruncate(memfd): %s", strerror(errno));
544 0 4 if (base == MAP_FAILED) {
545 0 0 PUBSUB_ERR("mmap(memfd): %s", strerror(errno));
553 0 4 if (!h) { munmap(base, (size_t)total_size); close(fd); return NULL; }
559 4 0 if (errbuf) errbuf[0] = '\0';
562 0 4 if (fstat(fd, &st) < 0) {
563 0 0 PUBSUB_ERR("fstat(fd=%d): %s", fd, strerror(errno));
567 0 4 if ((uint64_t)st.st_size < sizeof(PubSubHeader)) {
568 0 0 PUBSUB_ERR("fd %d: too small (%lld)", fd, (long long)st.st_size);
574 0 4 if (base == MAP_FAILED) {
575 0 0 PUBSUB_ERR("mmap(fd=%d): %s", fd, strerror(errno));
579 0 4 if (!pubsub_validate_header((PubSubHeader *)base, mode, (uint64_t)st.st_size)) {
580 0 0 PUBSUB_ERR("fd %d: invalid or incompatible pubsub", fd);
586 0 4 if (myfd < 0) {
587 0 0 PUBSUB_ERR("fcntl(F_DUPFD_CLOEXEC): %s", strerror(errno));
593 0 4 if (!h) { munmap(base, map_size); close(myfd); return NULL; }
599 0 149 if (!h) return;
600 13 136 if (h->notify_fd >= 0) close(h->notify_fd);
601 8 141 if (h->backing_fd >= 0) close(h->backing_fd);
602 149 0 if (h->hdr) munmap(h->hdr, h->mmap_size);
613 0 311 if (!sub) return NULL;
626 64 247 if (from_oldest && wp > h->capacity)
1 63 if (from_oldest && wp > h->capacity)
628 63 247 else if (from_oldest)
637 0 311 if (!sub) return;
648 22 10 return (wp > sub->cursor) ? (wp - sub->cursor) : 0;
765 5 6 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
0 6 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
6 0 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
0 6 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
6 0 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
0 6 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
4 2 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
2 0 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
2 0 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
30 1186 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
2 1184 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
0 1184 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
0 0 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
0 0 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
0 0 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
0 1184 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
1216 0 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
208 4 DEFINE_INT_PUBSUB(int, PubSubIntSlot, int64_t, uint64_t, int64_t)
768 1 1 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
0 1 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
1 0 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
0 1 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
1 0 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
0 1 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
0 1 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
1 0 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
1 0 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
7 31 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
1 30 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
0 30 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
0 0 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
0 0 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
0 0 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
0 30 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
38 0 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
3 1 DEFINE_INT_PUBSUB(int32, PubSubInt32Slot, int32_t, uint32_t, int32_t)
771 1 1 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
0 1 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
1 0 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
0 1 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
1 0 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
0 1 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
0 1 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
1 0 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
1 0 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
7 31 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
1 30 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
0 30 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
0 0 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
0 0 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
0 0 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
0 30 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
38 0 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
3 1 DEFINE_INT_PUBSUB(int16, PubSubInt16Slot, int16_t, uint32_t, int32_t)
783 0 404 if (len > PUBSUB_STR_LEN_MASK) return -1;
784 1 403 if (len > h->msg_size) return -1;
797 3 400 if (alloc == 0) alloc = 8;
798 0 403 if (alloc > h->arena_cap) return -1;
817 0 403 if ((uint64_t)apos + alloc > h->arena_cap) return -1;
822 3 400 slot->packed_len = len | (utf8 ? PUBSUB_STR_UTF8_FLAG : 0);
833 2 391 if (len > h->msg_size) return -1;
837 391 0 if (r == 1) pubsub_wake_subscribers(h->hdr);
847 978 0 for (int attempt = 0; attempt < PUBSUB_POLL_RETRIES; attempt++) {
851 18 960 if (cursor >= wp) return 0;
853 2 958 if (wp - cursor > sub->capacity) {
863 0 958 if (seq1 != cursor + 1) {
864 0 0 if (seq1 > cursor + 1) {
865 0 0 uint64_t new_cursor = wp > sub->capacity ? wp - sub->capacity : 0;
866 0 0 if (new_cursor > cursor)
885 0 958 if (len > sub->msg_size) continue;
886 0 958 if ((uint64_t)aoff + len > sub->arena_cap) continue;
888 0 958 if (!pubsub_ensure_copy_buf(sub, len + 1)) return 0;
890 955 3 if (len > 0)
895 0 958 if (seq2 != seq1) continue;
910 52 3 if (r != 0) return r;
911 0 3 if (timeout == 0.0) return 0;
916 3 0 if (has_deadline) pubsub_make_deadline(timeout, &deadline);
923 0 3 if (r != 0) {
929 3 0 if (has_deadline) {
930 0 3 if (!pubsub_remaining_time(&deadline, &remaining)) {
941 2 1 if (r != 0) return r;
942 1 0 if (rc == -1 && errno == ETIMEDOUT) return 0;
1 0 if (rc == -1 && errno == ETIMEDOUT) return 0;
952 2 6 if (h->mode == PUBSUB_MODE_STR)
957 2 6 if (h->mode == PUBSUB_MODE_STR)
962 4 4 if (h->mode == PUBSUB_MODE_INT) {
964 256 4 for (uint32_t i = 0; i < cap; i++)
966 1 3 } else if (h->mode == PUBSUB_MODE_INT32) {
968 64 1 for (uint32_t i = 0; i < cap; i++)
970 1 2 } else if (h->mode == PUBSUB_MODE_INT16) {
972 64 1 for (uint32_t i = 0; i < cap; i++)
976 80 2 for (uint32_t i = 0; i < cap; i++)
980 2 6 if (h->mode == PUBSUB_MODE_STR)
990 0 13 if (h->notify_fd >= 0) return h->notify_fd;
996 1 0 if (h->notify_fd >= 0 && h->notify_fd != fd)
0 1 if (h->notify_fd >= 0 && h->notify_fd != fd)
1002 8 0 if (h->notify_fd >= 0) {
1009 0 6 if (h->notify_fd < 0) return -1;
1011 0 6 if (read(h->notify_fd, &val, sizeof(val)) != sizeof(val)) return -1;
1016 4 0 if (sub->notify_fd >= 0) {