File Coverage

Shared.xs
Criterion Covered Total %
statement 609 705 86.3
branch 614 1380 44.4
condition n/a
subroutine n/a
pod n/a
total 1223 2085 58.6


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             #include "ppport.h"
7             #include "pubsub.h"
8              
9             #include "XSParseKeyword.h"
10              
11 16           static int build_kw_1arg(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata) {
12             (void)nargs;
13 16           const char *func = (const char *)hookdata;
14 16           OP *q_op = args[0]->op;
15 16           OP *cvref = newCVREF(0, newGVOP(OP_GV, 0, gv_fetchpv(func, GV_ADD, SVt_PVCV)));
16 16           *out = op_convert_list(OP_ENTERSUB, OPf_STACKED,
17             op_append_elem(OP_LIST, q_op, cvref));
18 16           return KEYWORD_PLUGIN_EXPR;
19             }
20              
21 8           static int build_kw_2arg(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata) {
22             (void)nargs;
23 8           const char *func = (const char *)hookdata;
24 8           OP *q_op = args[0]->op;
25 8           OP *val_op = args[1]->op;
26 8           OP *cvref = newCVREF(0, newGVOP(OP_GV, 0, gv_fetchpv(func, GV_ADD, SVt_PVCV)));
27 8           OP *arglist = op_append_elem(OP_LIST, q_op, val_op);
28 8           arglist = op_append_elem(OP_LIST, arglist, cvref);
29 8           *out = op_convert_list(OP_ENTERSUB, OPf_STACKED, arglist);
30 8           return KEYWORD_PLUGIN_EXPR;
31             }
32              
33             static const struct XSParseKeywordPieceType pieces_1expr[] = {
34             XPK_TERMEXPR, {0}
35             };
36              
37             static const struct XSParseKeywordPieceType pieces_2expr[] = {
38             XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, {0}
39             };
40              
41             #define DEFINE_PS_KW(variant, PKG, kw, nargs, builder) \
42             static const struct XSParseKeywordHooks hooks_ps_##variant##_##kw = { \
43             .flags = XPK_FLAG_EXPR, \
44             .permit_hintkey = "Data::PubSub::Shared::" PKG "/ps_" #variant "_" #kw, \
45             .pieces = pieces_##nargs##expr, \
46             .build = builder, \
47             };
48              
49             /* Publisher keywords */
50             DEFINE_PS_KW(int, "Int", publish, 2, build_kw_2arg)
51              
52             /* Subscriber keywords */
53             DEFINE_PS_KW(int, "Int", poll, 1, build_kw_1arg)
54             DEFINE_PS_KW(int, "Int", lag, 1, build_kw_1arg)
55              
56             /* Str publisher keywords */
57             DEFINE_PS_KW(str, "Str", publish, 2, build_kw_2arg)
58              
59             /* Int32 keywords */
60             DEFINE_PS_KW(int32, "Int32", publish, 2, build_kw_2arg)
61             DEFINE_PS_KW(int32, "Int32", poll, 1, build_kw_1arg)
62             DEFINE_PS_KW(int32, "Int32", lag, 1, build_kw_1arg)
63              
64             /* Int16 keywords */
65             DEFINE_PS_KW(int16, "Int16", publish, 2, build_kw_2arg)
66             DEFINE_PS_KW(int16, "Int16", poll, 1, build_kw_1arg)
67             DEFINE_PS_KW(int16, "Int16", lag, 1, build_kw_1arg)
68              
69             /* Str subscriber keywords */
70             DEFINE_PS_KW(str, "Str", poll, 1, build_kw_1arg)
71             DEFINE_PS_KW(str, "Str", lag, 1, build_kw_1arg)
72              
73             #define REGISTER_PS_KW(variant, kw, func_name) \
74             register_xs_parse_keyword("ps_" #variant "_" #kw, \
75             &hooks_ps_##variant##_##kw, (void*)func_name)
76              
77             #define EXTRACT_HANDLE(classname, sv) \
78             if (!sv_isobject(sv) || !sv_derived_from(sv, classname)) \
79             croak("Expected a %s object", classname); \
80             PubSubHandle *h = INT2PTR(PubSubHandle*, SvIV(SvRV(sv))); \
81             if (!h) croak("Attempted to use a destroyed %s object", classname)
82              
83             #define MAKE_OBJ(class, ptr) \
84             SV *ref = newRV_noinc(newSViv(PTR2IV(ptr))); \
85             sv_bless(ref, gv_stashpv(class, GV_ADD)); \
86             RETVAL = ref
87              
88             #define EXTRACT_SUB(classname, sv) \
89             if (!sv_isobject(sv) || !sv_derived_from(sv, classname)) \
90             croak("Expected a %s object", classname); \
91             PubSubSub *sub = INT2PTR(PubSubSub*, SvIV(SvRV(sv))); \
92             if (!sub) croak("Attempted to use a destroyed %s object", classname)
93              
94             MODULE = Data::PubSub::Shared PACKAGE = Data::PubSub::Shared::Int
95              
96             PROTOTYPES: DISABLE
97              
98             BOOT:
99 24           boot_xs_parse_keyword(0.40);
100 24           REGISTER_PS_KW(int, publish, "Data::PubSub::Shared::Int::publish");
101 24           REGISTER_PS_KW(int, poll, "Data::PubSub::Shared::Int::Sub::poll");
102 24           REGISTER_PS_KW(int, lag, "Data::PubSub::Shared::Int::Sub::lag");
103 24           REGISTER_PS_KW(int32, publish, "Data::PubSub::Shared::Int32::publish");
104 24           REGISTER_PS_KW(int32, poll, "Data::PubSub::Shared::Int32::Sub::poll");
105 24           REGISTER_PS_KW(int32, lag, "Data::PubSub::Shared::Int32::Sub::lag");
106 24           REGISTER_PS_KW(int16, publish, "Data::PubSub::Shared::Int16::publish");
107 24           REGISTER_PS_KW(int16, poll, "Data::PubSub::Shared::Int16::Sub::poll");
108 24           REGISTER_PS_KW(int16, lag, "Data::PubSub::Shared::Int16::Sub::lag");
109 24           REGISTER_PS_KW(str, publish, "Data::PubSub::Shared::Str::publish");
110 24           REGISTER_PS_KW(str, poll, "Data::PubSub::Shared::Str::Sub::poll");
111 24           REGISTER_PS_KW(str, lag, "Data::PubSub::Shared::Str::Sub::lag");
112              
113             SV *
114             new(class, path, capacity, ...)
115             const char *class
116             SV *path
117             UV capacity
118             PREINIT:
119             char errbuf[PUBSUB_ERR_BUFLEN];
120             CODE:
121 66 50         mode_t fmode = (items > 3 && (SvGETMAGIC(ST(3)), SvOK(ST(3)))) ? (mode_t)SvUV(ST(3)) : 0600;
    0          
    0          
    0          
122 66 50         const char *p = (SvGETMAGIC(path), SvOK(path)) ? SvPV_nolen(path) : NULL;
    0          
    100          
123 66           PubSubHandle *h = pubsub_create(p, (uint32_t)capacity, PUBSUB_MODE_INT, 0, fmode, errbuf);
124 66 100         if (!h) croak("Data::PubSub::Shared::Int->new: %s", errbuf);
125 65           MAKE_OBJ(class, h);
126             OUTPUT:
127             RETVAL
128              
129             SV *
130             new_memfd(class, name, capacity)
131             const char *class
132             const char *name
133             UV capacity
134             PREINIT:
135             char errbuf[PUBSUB_ERR_BUFLEN];
136             CODE:
137 1           PubSubHandle *h = pubsub_create_memfd(name, (uint32_t)capacity, PUBSUB_MODE_INT, 0, errbuf);
138 1 50         if (!h) croak("Data::PubSub::Shared::Int->new_memfd: %s", errbuf);
139 1           MAKE_OBJ(class, h);
140             OUTPUT:
141             RETVAL
142              
143             SV *
144             new_from_fd(class, fd)
145             const char *class
146             int fd
147             PREINIT:
148             char errbuf[PUBSUB_ERR_BUFLEN];
149             CODE:
150 1           PubSubHandle *h = pubsub_open_fd(fd, PUBSUB_MODE_INT, errbuf);
151 1 50         if (!h) croak("Data::PubSub::Shared::Int->new_from_fd: %s", errbuf);
152 1           MAKE_OBJ(class, h);
153             OUTPUT:
154             RETVAL
155              
156             IV
157             memfd(self)
158             SV *self
159             PREINIT:
160 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
161             CODE:
162 1 50         RETVAL = h->backing_fd;
163             OUTPUT:
164             RETVAL
165              
166             void
167             DESTROY(self)
168             SV *self
169             CODE:
170 67 50         if (!SvROK(self)) return;
171 67           PubSubHandle *h = INT2PTR(PubSubHandle*, SvIV(SvRV(self)));
172 67 50         if (!h) return;
173 67           sv_setiv(SvRV(self), 0);
174 67           pubsub_destroy(h);
175              
176             bool
177             publish(self, value)
178             SV *self
179             IV value
180             PREINIT:
181 468 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
182             CODE:
183 468 50         RETVAL = pubsub_int_publish(h, (int64_t)value);
184             OUTPUT:
185             RETVAL
186              
187             UV
188             publish_multi(self, ...)
189             SV *self
190             PREINIT:
191 5 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
192             CODE:
193 5           uint32_t count = items - 1;
194 5 100         if (count == 0) { RETVAL = 0; }
195             else {
196 4 50         if (count > 8192) croak("publish_multi: too many values (%u > 8192)", count);
197 4           int64_t *vals = (int64_t *)alloca(count * sizeof(int64_t));
198 212 100         for (uint32_t i = 0; i < count; i++)
199 208           vals[i] = (int64_t)SvIV(ST(i + 1));
200 4           RETVAL = pubsub_int_publish_multi(h, vals, count);
201             }
202             OUTPUT:
203             RETVAL
204              
205             void
206             publish_notify(self, value)
207             SV *self
208             IV value
209             PREINIT:
210 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
211             CODE:
212 1           pubsub_int_publish(h, (int64_t)value);
213 1           pubsub_notify(h);
214              
215             SV *
216             subscribe(self)
217             SV *self
218             PREINIT:
219 21 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
220             CODE:
221 21           PubSubSub *sub = pubsub_subscribe(h, 0);
222 21 50         if (!sub) croak("subscribe: out of memory");
223 21           sub->userdata = (void *)newSVsv(self);
224 21           MAKE_OBJ("Data::PubSub::Shared::Int::Sub", sub);
225             OUTPUT:
226             RETVAL
227              
228             SV *
229             subscribe_all(self)
230             SV *self
231             PREINIT:
232 26 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
233             CODE:
234 26           PubSubSub *sub = pubsub_subscribe(h, 1);
235 26 50         if (!sub) croak("subscribe_all: out of memory");
236 26           sub->userdata = (void *)newSVsv(self);
237 26           MAKE_OBJ("Data::PubSub::Shared::Int::Sub", sub);
238             OUTPUT:
239             RETVAL
240              
241             UV
242             capacity(self)
243             SV *self
244             PREINIT:
245 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
246             CODE:
247 1 50         RETVAL = h->capacity;
248             OUTPUT:
249             RETVAL
250              
251             UV
252             write_pos(self)
253             SV *self
254             PREINIT:
255 13 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
256             CODE:
257 13 50         RETVAL = (UV)__atomic_load_n(&h->hdr->write_pos, __ATOMIC_RELAXED);
258             OUTPUT:
259             RETVAL
260              
261             SV *
262             path(self)
263             SV *self
264             PREINIT:
265 2 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
266             CODE:
267 2 100         RETVAL = h->path ? newSVpv(h->path, 0) : &PL_sv_undef;
268             OUTPUT:
269             RETVAL
270              
271             SV *
272             stats(self)
273             SV *self
274             PREINIT:
275 5 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
276             CODE:
277 5           HV *hv = newHV();
278 5           PubSubHeader *hdr = h->hdr;
279 5           hv_store(hv, "capacity", 8, newSVuv(h->capacity), 0);
280 5           hv_store(hv, "mmap_size", 9, newSVuv((UV)h->mmap_size), 0);
281 5           hv_store(hv, "write_pos", 9,
282             newSVuv((UV)__atomic_load_n(&hdr->write_pos, __ATOMIC_RELAXED)), 0);
283 5           hv_store(hv, "publish_ok", 10,
284             newSVuv((UV)__atomic_load_n(&hdr->stat_publish_ok, __ATOMIC_RELAXED)), 0);
285 5           hv_store(hv, "recoveries", 10,
286             newSVuv(__atomic_load_n(&hdr->stat_recoveries, __ATOMIC_RELAXED)), 0);
287 5           hv_store(hv, "sub_waiters", 11,
288             newSVuv(__atomic_load_n(&hdr->sub_waiters, __ATOMIC_RELAXED)), 0);
289 5           RETVAL = newRV_noinc((SV *)hv);
290             OUTPUT:
291             RETVAL
292              
293             void
294             clear(self)
295             SV *self
296             PREINIT:
297 4 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
298             CODE:
299 4           pubsub_clear(h);
300              
301             void
302             sync(self)
303             SV *self
304             PREINIT:
305 4 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
306             CODE:
307 4 50         if (pubsub_sync(h) != 0)
308 0           croak("msync: %s", strerror(errno));
309              
310             void
311             unlink(self_or_class, ...)
312             SV *self_or_class
313             CODE:
314             const char *path;
315 1 50         if (sv_isobject(self_or_class)) {
316 1           PubSubHandle *h = INT2PTR(PubSubHandle*, SvIV(SvRV(self_or_class)));
317 1 50         if (!h) croak("Attempted to use a destroyed object");
318 1           path = h->path;
319             } else {
320 0 0         if (items < 2) croak("Usage: Data::PubSub::Shared::Int->unlink($path)");
321 0           path = SvPV_nolen(ST(1));
322             }
323 1 50         if (!path) croak("cannot unlink anonymous or memfd pubsub");
324 1 50         if (unlink(path) != 0)
325 0           croak("unlink(%s): %s", path, strerror(errno));
326              
327             IV
328             eventfd(self)
329             SV *self
330             PREINIT:
331 9 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
332             CODE:
333 9           RETVAL = pubsub_eventfd_create(h);
334 9 50         if (RETVAL < 0) croak("eventfd: %s", strerror(errno));
335             OUTPUT:
336             RETVAL
337              
338             void
339             eventfd_set(self, fd)
340             SV *self
341             int fd
342             PREINIT:
343 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
344             CODE:
345 1           pubsub_eventfd_set(h, fd);
346              
347             IV
348             fileno(self)
349             SV *self
350             PREINIT:
351 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
352             CODE:
353 1 50         RETVAL = h->notify_fd;
354             OUTPUT:
355             RETVAL
356              
357             SV *
358             eventfd_consume(self)
359             SV *self
360             PREINIT:
361 4 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
362             CODE:
363 4           int64_t v = pubsub_eventfd_consume(h);
364 4 50         RETVAL = (v >= 0) ? newSViv((IV)v) : &PL_sv_undef;
365             OUTPUT:
366             RETVAL
367              
368             void
369             notify(self)
370             SV *self
371             PREINIT:
372 4 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int", self);
    50          
    50          
373             CODE:
374 4           pubsub_notify(h);
375              
376             MODULE = Data::PubSub::Shared PACKAGE = Data::PubSub::Shared::Int::Sub
377              
378             void
379             DESTROY(self)
380             SV *self
381             CODE:
382 47 50         if (!SvROK(self)) return;
383 47           PubSubSub *sub = INT2PTR(PubSubSub*, SvIV(SvRV(self)));
384 47 50         if (!sub) return;
385 47           sv_setiv(SvRV(self), 0);
386 47 50         if (sub->userdata) SvREFCNT_dec((SV *)sub->userdata);
387 47           pubsub_sub_destroy(sub);
388              
389             SV *
390             poll(self)
391             SV *self
392             PREINIT:
393 35 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
394             int64_t value;
395             CODE:
396 35           int r = pubsub_int_poll(sub, &value);
397 35 100         if (r == 1)
398 31           RETVAL = newSViv((IV)value);
399             else
400 4           RETVAL = &PL_sv_undef;
401             OUTPUT:
402             RETVAL
403              
404             void
405             poll_multi(self, count)
406             SV *self
407             UV count
408             PREINIT:
409 2 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
410             int64_t value;
411             PPCODE:
412 12 100         for (UV i = 0; i < count; i++) {
413 10           int r = pubsub_int_poll(sub, &value);
414 10 50         if (r != 1) break;
415 10 50         mXPUSHi((IV)value);
416             }
417              
418             SV *
419             poll_wait(self, ...)
420             SV *self
421             PREINIT:
422 9 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
423 9           double timeout = -1;
424             int64_t value;
425             CODE:
426 9 50         if (items > 1) timeout = SvNV(ST(1));
427 9           int r = pubsub_int_poll_wait(sub, &value, timeout);
428 9 100         if (r == 1)
429 8           RETVAL = newSViv((IV)value);
430             else
431 1           RETVAL = &PL_sv_undef;
432             OUTPUT:
433             RETVAL
434              
435             void
436             drain(self, ...)
437             SV *self
438             PREINIT:
439 8 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
440             int64_t value;
441             uint32_t max_count;
442             PPCODE:
443 8 100         max_count = (items > 1) ? (uint32_t)SvUV(ST(1)) : UINT32_MAX;
444 1028 100         while (max_count-- > 0 && pubsub_int_poll(sub, &value))
    100          
445 1020 50         mXPUSHi((IV)value);
446              
447             void
448             poll_wait_multi(self, count, ...)
449             SV *self
450             UV count
451             PREINIT:
452 3 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
453 3           double timeout = -1;
454             int64_t value;
455             PPCODE:
456 3 100         if (count == 0) XSRETURN(0);
457 2 50         if (items > 2) timeout = SvNV(ST(2));
458 2 100         if (!pubsub_int_poll_wait(sub, &value, timeout)) XSRETURN(0);
459 1 50         mXPUSHi((IV)value);
460 5 100         for (UV i = 1; i < count; i++) {
461 4 50         if (!pubsub_int_poll(sub, &value)) break;
462 4 50         mXPUSHi((IV)value);
463             }
464              
465             UV
466             lag(self)
467             SV *self
468             PREINIT:
469 18 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
470             CODE:
471 18           RETVAL = (UV)pubsub_lag(sub);
472             OUTPUT:
473             RETVAL
474              
475             UV
476             overflow_count(self)
477             SV *self
478             PREINIT:
479 2 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
480             CODE:
481 2 50         RETVAL = (UV)sub->overflow_count;
482             OUTPUT:
483             RETVAL
484              
485             UV
486             write_pos(self)
487             SV *self
488             PREINIT:
489 2 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
490             CODE:
491 2 50         RETVAL = (UV)__atomic_load_n(&sub->hdr->write_pos, __ATOMIC_RELAXED);
492             OUTPUT:
493             RETVAL
494              
495             bool
496             has_overflow(self)
497             SV *self
498             PREINIT:
499 2 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
500             CODE:
501 2           uint64_t wp = __atomic_load_n(&sub->hdr->write_pos, __ATOMIC_RELAXED);
502 2 100         RETVAL = (sub->cursor < wp && wp - sub->cursor > sub->capacity);
    50          
    100          
503             OUTPUT:
504             RETVAL
505              
506             UV
507             cursor(self, ...)
508             SV *self
509             PREINIT:
510 6 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
511             CODE:
512 6 100         if (items > 1) sub->cursor = (uint64_t)SvUV(ST(1));
513 6 50         RETVAL = (UV)sub->cursor;
514             OUTPUT:
515             RETVAL
516              
517             void
518             reset(self)
519             SV *self
520             PREINIT:
521 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
522             CODE:
523 1           sub->cursor = __atomic_load_n(&sub->hdr->write_pos, __ATOMIC_ACQUIRE);
524              
525             void
526             reset_oldest(self)
527             SV *self
528             PREINIT:
529 2 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
530             CODE:
531 2           uint64_t wp = __atomic_load_n(&sub->hdr->write_pos, __ATOMIC_ACQUIRE);
532 2 50         sub->cursor = (wp > sub->capacity) ? wp - sub->capacity : 0;
533              
534             UV
535             poll_cb(self, cb)
536             SV *self
537             SV *cb
538             PREINIT:
539 3 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
540             int64_t value;
541             CODE:
542 3           RETVAL = 0;
543             /* Keep the backing handle alive across the callback: a callback that
544             * drops self's last reference would free `sub` mid-loop (UAF). Guard
545             * the referent (the blessed handle), not the RV container -- assigning
546             * undef to self overwrites the container and frees the referent. */
547 3           SV *psx_guard = SvRV(self);
548 3           SvREFCNT_inc_simple_void_NN(psx_guard);
549 3           SAVEFREESV(psx_guard);
550 108 100         while (pubsub_int_poll(sub, &value)) {
551 105           dSP;
552 105           ENTER; SAVETMPS;
553 105 50         PUSHMARK(SP);
554 105 50         mXPUSHi((IV)value);
555 105           PUTBACK;
556 105           call_sv(cb, G_DISCARD);
557 105 50         FREETMPS; LEAVE;
558 105           RETVAL++;
559             }
560             OUTPUT:
561             RETVAL
562              
563             void
564             drain_notify(self, ...)
565             SV *self
566             PREINIT:
567 3 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
568             int64_t value;
569             uint32_t max_count;
570             PPCODE:
571 3           pubsub_sub_eventfd_consume(sub);
572 3 100         max_count = (items > 1) ? (uint32_t)SvUV(ST(1)) : UINT32_MAX;
573 8 100         while (max_count-- > 0 && pubsub_int_poll(sub, &value))
    100          
574 5 50         mXPUSHi((IV)value);
575              
576             void
577             eventfd_set(self, fd)
578             SV *self
579             int fd
580             PREINIT:
581 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
582             CODE:
583 1           sub->notify_fd = fd;
584              
585             IV
586             fileno(self)
587             SV *self
588             PREINIT:
589 3 50         EXTRACT_SUB("Data::PubSub::Shared::Int::Sub", self);
    50          
    50          
590             CODE:
591 3 50         RETVAL = sub->notify_fd;
592             OUTPUT:
593             RETVAL
594              
595             MODULE = Data::PubSub::Shared PACKAGE = Data::PubSub::Shared::Str
596              
597             SV *
598             new(class, path, capacity, ...)
599             const char *class
600             SV *path
601             UV capacity
602             PREINIT:
603             char errbuf[PUBSUB_ERR_BUFLEN];
604             uint32_t msg_size;
605             CODE:
606 56 100         msg_size = (items > 3) ? (uint32_t)SvUV(ST(3)) : 0;
607 56 50         mode_t fmode = (items > 4 && (SvGETMAGIC(ST(4)), SvOK(ST(4)))) ? (mode_t)SvUV(ST(4)) : 0600;
    0          
    0          
    0          
608 56 50         const char *p = (SvGETMAGIC(path), SvOK(path)) ? SvPV_nolen(path) : NULL;
    0          
    100          
609 56           PubSubHandle *h = pubsub_create(p, (uint32_t)capacity, PUBSUB_MODE_STR, msg_size, fmode, errbuf);
610 56 100         if (!h) croak("Data::PubSub::Shared::Str->new: %s", errbuf);
611 55           MAKE_OBJ(class, h);
612             OUTPUT:
613             RETVAL
614              
615             SV *
616             new_memfd(class, name, capacity, ...)
617             const char *class
618             const char *name
619             UV capacity
620             PREINIT:
621             char errbuf[PUBSUB_ERR_BUFLEN];
622             uint32_t msg_size;
623             CODE:
624 1 50         msg_size = (items > 3) ? (uint32_t)SvUV(ST(3)) : 0;
625 1           PubSubHandle *h = pubsub_create_memfd(name, (uint32_t)capacity, PUBSUB_MODE_STR, msg_size, errbuf);
626 1 50         if (!h) croak("Data::PubSub::Shared::Str->new_memfd: %s", errbuf);
627 1           MAKE_OBJ(class, h);
628             OUTPUT:
629             RETVAL
630              
631             SV *
632             new_from_fd(class, fd)
633             const char *class
634             int fd
635             PREINIT:
636             char errbuf[PUBSUB_ERR_BUFLEN];
637             CODE:
638 1           PubSubHandle *h = pubsub_open_fd(fd, PUBSUB_MODE_STR, errbuf);
639 1 50         if (!h) croak("Data::PubSub::Shared::Str->new_from_fd: %s", errbuf);
640 1           MAKE_OBJ(class, h);
641             OUTPUT:
642             RETVAL
643              
644             IV
645             memfd(self)
646             SV *self
647             PREINIT:
648 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
649             CODE:
650 1 50         RETVAL = h->backing_fd;
651             OUTPUT:
652             RETVAL
653              
654             void
655             DESTROY(self)
656             SV *self
657             CODE:
658 57 50         if (!SvROK(self)) return;
659 57           PubSubHandle *h = INT2PTR(PubSubHandle*, SvIV(SvRV(self)));
660 57 50         if (!h) return;
661 57           sv_setiv(SvRV(self), 0);
662 57           pubsub_destroy(h);
663              
664             SV *
665             publish(self, value)
666             SV *self
667             SV *value
668             PREINIT:
669 392 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
670             CODE:
671             STRLEN len;
672 392 50         SvGETMAGIC(value); /* run get-magic/overload before reading the UTF8 flag */
    0          
673 392           bool utf8 = SvUTF8(value) ? true : false;
674 392           const char *str = SvPV_nomg(value, len);
675 392           int r = pubsub_str_publish(h, str, (uint32_t)len, utf8);
676 392 100         if (r == -1) croak("publish: message too long (%u > %u)", (unsigned)len, h->msg_size);
677 390           RETVAL = &PL_sv_yes;
678             OUTPUT:
679             RETVAL
680              
681             UV
682             publish_multi(self, ...)
683             SV *self
684             PREINIT:
685 5 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
686             CODE:
687 5           RETVAL = 0;
688 5           uint32_t count = items - 1;
689 5 100         if (count > 0) {
690             /* Extract SV data BEFORE locking: SvPV(utf8) can run magic
691             * (tied/overloaded stringification) that longjmps; doing it under
692             * the process-shared mutex would abandon the lock and deadlock peers.
693             * Newx+SAVEFREEPV so a die during extraction cannot leak args. */
694             struct psm_arg { const char *str; STRLEN len; bool utf8; };
695             struct psm_arg *args;
696 4           Newx(args, count, struct psm_arg);
697 4           SAVEFREEPV(args);
698 17 100         for (uint32_t i = 0; i < count; i++) {
699 13           SV *val = ST(i + 1);
700 13 50         SvGETMAGIC(val);
    0          
701 13           args[i].utf8 = SvUTF8(val) ? true : false;
702 13           args[i].str = SvPV_nomg(val, args[i].len);
703             }
704 4           pubsub_mutex_lock(h->hdr);
705 16 100         for (uint32_t i = 0; i < count; i++) {
706 13           int r = pubsub_str_publish_locked(h, args[i].str, (uint32_t)args[i].len, args[i].utf8);
707 13 100         if (r == -1) {
708 1           pubsub_mutex_unlock(h->hdr);
709 1           croak("publish_multi: message too long (%u > %u)", (unsigned)args[i].len, h->msg_size);
710             }
711 12           RETVAL++;
712             }
713 3           pubsub_mutex_unlock(h->hdr);
714 3           pubsub_wake_subscribers(h->hdr);
715             }
716             OUTPUT:
717             RETVAL
718              
719             void
720             publish_notify(self, value)
721             SV *self
722             SV *value
723             PREINIT:
724 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
725             CODE:
726             STRLEN len;
727 1 50         SvGETMAGIC(value); /* run get-magic/overload before reading the UTF8 flag */
    0          
728 1           bool utf8 = SvUTF8(value) ? true : false;
729 1           const char *str = SvPV_nomg(value, len);
730 1           int r = pubsub_str_publish(h, str, (uint32_t)len, utf8);
731 1 50         if (r == -1) croak("publish_notify: message too long (%u > %u)", (unsigned)len, h->msg_size);
732 1           pubsub_notify(h);
733              
734             SV *
735             subscribe(self)
736             SV *self
737             PREINIT:
738 218 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
739             CODE:
740 218           PubSubSub *sub = pubsub_subscribe(h, 0);
741 218 50         if (!sub) croak("subscribe: out of memory");
742 218           sub->userdata = (void *)newSVsv(self);
743 218           MAKE_OBJ("Data::PubSub::Shared::Str::Sub", sub);
744             OUTPUT:
745             RETVAL
746              
747             SV *
748             subscribe_all(self)
749             SV *self
750             PREINIT:
751 24 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
752             CODE:
753 24           PubSubSub *sub = pubsub_subscribe(h, 1);
754 24 50         if (!sub) croak("subscribe_all: out of memory");
755 24           sub->userdata = (void *)newSVsv(self);
756 24           MAKE_OBJ("Data::PubSub::Shared::Str::Sub", sub);
757             OUTPUT:
758             RETVAL
759              
760             UV
761             capacity(self)
762             SV *self
763             PREINIT:
764 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
765             CODE:
766 1 50         RETVAL = h->capacity;
767             OUTPUT:
768             RETVAL
769              
770             UV
771             msg_size(self)
772             SV *self
773             PREINIT:
774 2 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
775             CODE:
776 2 50         RETVAL = h->msg_size;
777             OUTPUT:
778             RETVAL
779              
780             UV
781             write_pos(self)
782             SV *self
783             PREINIT:
784 7 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
785             CODE:
786 7 50         RETVAL = (UV)__atomic_load_n(&h->hdr->write_pos, __ATOMIC_RELAXED);
787             OUTPUT:
788             RETVAL
789              
790             SV *
791             path(self)
792             SV *self
793             PREINIT:
794 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    0          
    0          
795             CODE:
796 0 0         RETVAL = h->path ? newSVpv(h->path, 0) : &PL_sv_undef;
797             OUTPUT:
798             RETVAL
799              
800             SV *
801             stats(self)
802             SV *self
803             PREINIT:
804 2 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
805             CODE:
806 2           HV *hv = newHV();
807 2           PubSubHeader *hdr = h->hdr;
808 2           hv_store(hv, "capacity", 8, newSVuv(h->capacity), 0);
809 2           hv_store(hv, "msg_size", 8, newSVuv(h->msg_size), 0);
810 2           hv_store(hv, "arena_cap", 9, newSVuv((UV)h->arena_cap), 0);
811 2           hv_store(hv, "mmap_size", 9, newSVuv((UV)h->mmap_size), 0);
812 2           hv_store(hv, "write_pos", 9,
813             newSVuv((UV)__atomic_load_n(&hdr->write_pos, __ATOMIC_RELAXED)), 0);
814 2           hv_store(hv, "publish_ok", 10,
815             newSVuv((UV)__atomic_load_n(&hdr->stat_publish_ok, __ATOMIC_RELAXED)), 0);
816 2           hv_store(hv, "recoveries", 10,
817             newSVuv(__atomic_load_n(&hdr->stat_recoveries, __ATOMIC_RELAXED)), 0);
818 2           hv_store(hv, "sub_waiters", 11,
819             newSVuv(__atomic_load_n(&hdr->sub_waiters, __ATOMIC_RELAXED)), 0);
820 2           RETVAL = newRV_noinc((SV *)hv);
821             OUTPUT:
822             RETVAL
823              
824             void
825             clear(self)
826             SV *self
827             PREINIT:
828 2 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
829             CODE:
830 2           pubsub_clear(h);
831              
832             void
833             sync(self)
834             SV *self
835             PREINIT:
836 2 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
837             CODE:
838 2 50         if (pubsub_sync(h) != 0)
839 0           croak("msync: %s", strerror(errno));
840              
841             void
842             unlink(self_or_class, ...)
843             SV *self_or_class
844             CODE:
845             const char *path;
846 1 50         if (sv_isobject(self_or_class)) {
847 1           PubSubHandle *h = INT2PTR(PubSubHandle*, SvIV(SvRV(self_or_class)));
848 1 50         if (!h) croak("Attempted to use a destroyed object");
849 1           path = h->path;
850             } else {
851 0 0         if (items < 2) croak("Usage: Data::PubSub::Shared::Str->unlink($path)");
852 0           path = SvPV_nolen(ST(1));
853             }
854 1 50         if (!path) croak("cannot unlink anonymous or memfd pubsub");
855 1 50         if (unlink(path) != 0)
856 0           croak("unlink(%s): %s", path, strerror(errno));
857              
858             IV
859             eventfd(self)
860             SV *self
861             PREINIT:
862 4 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
863             CODE:
864 4           RETVAL = pubsub_eventfd_create(h);
865 4 50         if (RETVAL < 0) croak("eventfd: %s", strerror(errno));
866             OUTPUT:
867             RETVAL
868              
869             void
870             eventfd_set(self, fd)
871             SV *self
872             int fd
873             PREINIT:
874 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    0          
    0          
875             CODE:
876 0           pubsub_eventfd_set(h, fd);
877              
878             IV
879             fileno(self)
880             SV *self
881             PREINIT:
882 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    0          
    0          
883             CODE:
884 0 0         RETVAL = h->notify_fd;
885             OUTPUT:
886             RETVAL
887              
888             SV *
889             eventfd_consume(self)
890             SV *self
891             PREINIT:
892 2 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
893             CODE:
894 2           int64_t v = pubsub_eventfd_consume(h);
895 2 50         RETVAL = (v >= 0) ? newSViv((IV)v) : &PL_sv_undef;
896             OUTPUT:
897             RETVAL
898              
899             void
900             notify(self)
901             SV *self
902             PREINIT:
903 2 50         EXTRACT_HANDLE("Data::PubSub::Shared::Str", self);
    50          
    50          
904             CODE:
905 2           pubsub_notify(h);
906              
907             MODULE = Data::PubSub::Shared PACKAGE = Data::PubSub::Shared::Str::Sub
908              
909             void
910             DESTROY(self)
911             SV *self
912             CODE:
913 242 50         if (!SvROK(self)) return;
914 242           PubSubSub *sub = INT2PTR(PubSubSub*, SvIV(SvRV(self)));
915 242 50         if (!sub) return;
916 242           sv_setiv(SvRV(self), 0);
917 242 50         if (sub->userdata) SvREFCNT_dec((SV *)sub->userdata);
918 242           pubsub_sub_destroy(sub);
919              
920             SV *
921             poll(self)
922             SV *self
923             PREINIT:
924 881 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
925             const char *str;
926             uint32_t len;
927             bool utf8;
928             CODE:
929 881           int r = pubsub_str_poll(sub, &str, &len, &utf8);
930 881 100         if (r == 1) {
931 878           RETVAL = newSVpvn(str, len);
932 878 100         if (utf8) SvUTF8_on(RETVAL);
933             } else {
934 3           RETVAL = &PL_sv_undef;
935             }
936             OUTPUT:
937             RETVAL
938              
939             void
940             poll_multi(self, count)
941             SV *self
942             UV count
943             PREINIT:
944 1 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
945             const char *str;
946             uint32_t len;
947             bool utf8;
948             PPCODE:
949 4 50         for (UV i = 0; i < count; i++) {
950 4           int r = pubsub_str_poll(sub, &str, &len, &utf8);
951 4 100         if (r != 1) break;
952 3           SV *sv = newSVpvn(str, len);
953 3 50         if (utf8) SvUTF8_on(sv);
954 3 50         mXPUSHs(sv);
955             }
956              
957             SV *
958             poll_wait(self, ...)
959             SV *self
960             PREINIT:
961 54 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
962 54           double timeout = -1;
963             const char *str;
964             uint32_t len;
965             bool utf8;
966             CODE:
967 54 50         if (items > 1) timeout = SvNV(ST(1));
968 54           int r = pubsub_str_poll_wait(sub, &str, &len, &utf8, timeout);
969 54 100         if (r == 1) {
970 53           RETVAL = newSVpvn(str, len);
971 53 50         if (utf8) SvUTF8_on(RETVAL);
972             } else {
973 1           RETVAL = &PL_sv_undef;
974             }
975             OUTPUT:
976             RETVAL
977              
978             void
979             drain(self, ...)
980             SV *self
981             PREINIT:
982 4 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
983             const char *str;
984             uint32_t len;
985             bool utf8;
986             uint32_t max_count;
987             PPCODE:
988 4 50         max_count = (items > 1) ? (uint32_t)SvUV(ST(1)) : UINT32_MAX;
989 20 50         while (max_count-- > 0 && pubsub_str_poll(sub, &str, &len, &utf8) == 1) {
    100          
990 16           SV *sv = newSVpvn(str, len);
991 16 50         if (utf8) SvUTF8_on(sv);
992 16 50         mXPUSHs(sv);
993             }
994              
995             void
996             poll_wait_multi(self, count, ...)
997             SV *self
998             UV count
999             PREINIT:
1000 2 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
1001 2           double timeout = -1;
1002             const char *str;
1003             uint32_t len;
1004             bool utf8;
1005             PPCODE:
1006 2 100         if (count == 0) XSRETURN(0);
1007 1 50         if (items > 2) timeout = SvNV(ST(2));
1008 1 50         if (pubsub_str_poll_wait(sub, &str, &len, &utf8, timeout) != 1) XSRETURN(0);
1009             {
1010 1           SV *sv = newSVpvn(str, len);
1011 1 50         if (utf8) SvUTF8_on(sv);
1012 1 50         mXPUSHs(sv);
1013             }
1014 3 100         for (UV i = 1; i < count; i++) {
1015 2 50         if (pubsub_str_poll(sub, &str, &len, &utf8) != 1) break;
1016 2           SV *sv = newSVpvn(str, len);
1017 2 50         if (utf8) SvUTF8_on(sv);
1018 2 50         mXPUSHs(sv);
1019             }
1020              
1021             UV
1022             lag(self)
1023             SV *self
1024             PREINIT:
1025 8 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
1026             CODE:
1027 8           RETVAL = (UV)pubsub_lag(sub);
1028             OUTPUT:
1029             RETVAL
1030              
1031             UV
1032             overflow_count(self)
1033             SV *self
1034             PREINIT:
1035 1 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
1036             CODE:
1037 1 50         RETVAL = (UV)sub->overflow_count;
1038             OUTPUT:
1039             RETVAL
1040              
1041             UV
1042             write_pos(self)
1043             SV *self
1044             PREINIT:
1045 1 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
1046             CODE:
1047 1 50         RETVAL = (UV)__atomic_load_n(&sub->hdr->write_pos, __ATOMIC_RELAXED);
1048             OUTPUT:
1049             RETVAL
1050              
1051             bool
1052             has_overflow(self)
1053             SV *self
1054             PREINIT:
1055 2 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
1056             CODE:
1057 2           uint64_t wp = __atomic_load_n(&sub->hdr->write_pos, __ATOMIC_RELAXED);
1058 2 100         RETVAL = (sub->cursor < wp && wp - sub->cursor > sub->capacity);
    50          
    100          
1059             OUTPUT:
1060             RETVAL
1061              
1062             UV
1063             cursor(self, ...)
1064             SV *self
1065             PREINIT:
1066 848 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
1067             CODE:
1068 848 100         if (items > 1) sub->cursor = (uint64_t)SvUV(ST(1));
1069 848 100         RETVAL = (UV)sub->cursor;
1070             OUTPUT:
1071             RETVAL
1072              
1073             void
1074             reset(self)
1075             SV *self
1076             PREINIT:
1077 1 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
1078             CODE:
1079 1           sub->cursor = __atomic_load_n(&sub->hdr->write_pos, __ATOMIC_ACQUIRE);
1080              
1081             void
1082             reset_oldest(self)
1083             SV *self
1084             PREINIT:
1085 1 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
1086             CODE:
1087 1           uint64_t wp = __atomic_load_n(&sub->hdr->write_pos, __ATOMIC_ACQUIRE);
1088 1 50         sub->cursor = (wp > sub->capacity) ? wp - sub->capacity : 0;
1089              
1090             UV
1091             poll_cb(self, cb)
1092             SV *self
1093             SV *cb
1094             PREINIT:
1095 2 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
1096             const char *str;
1097             uint32_t len;
1098             bool utf8;
1099             CODE:
1100 2           RETVAL = 0;
1101             /* Keep the backing handle alive across the callback: a callback that
1102             * drops self's last reference would free `sub` mid-loop (UAF). Guard
1103             * the referent (the blessed handle), not the RV container -- assigning
1104             * undef to self overwrites the container and frees the referent. */
1105 2           SV *psx_guard = SvRV(self);
1106 2           SvREFCNT_inc_simple_void_NN(psx_guard);
1107 2           SAVEFREESV(psx_guard);
1108 6 100         while (pubsub_str_poll(sub, &str, &len, &utf8) == 1) {
1109 4           dSP;
1110 4           ENTER; SAVETMPS;
1111 4           SV *sv = newSVpvn(str, len);
1112 4 100         if (utf8) SvUTF8_on(sv);
1113 4 50         PUSHMARK(SP);
1114 4 50         mXPUSHs(sv);
1115 4           PUTBACK;
1116 4           call_sv(cb, G_DISCARD);
1117 4 50         FREETMPS; LEAVE;
1118 4           RETVAL++;
1119             }
1120             OUTPUT:
1121             RETVAL
1122              
1123             void
1124             drain_notify(self, ...)
1125             SV *self
1126             PREINIT:
1127 1 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
1128             const char *str;
1129             uint32_t len;
1130             bool utf8;
1131             uint32_t max_count;
1132             PPCODE:
1133 1           pubsub_sub_eventfd_consume(sub);
1134 1 50         max_count = (items > 1) ? (uint32_t)SvUV(ST(1)) : UINT32_MAX;
1135 2 50         while (max_count-- > 0 && pubsub_str_poll(sub, &str, &len, &utf8) == 1) {
    100          
1136 1           SV *sv = newSVpvn(str, len);
1137 1 50         if (utf8) SvUTF8_on(sv);
1138 1 50         mXPUSHs(sv);
1139             }
1140              
1141             void
1142             eventfd_set(self, fd)
1143             SV *self
1144             int fd
1145             PREINIT:
1146 0 0         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    0          
    0          
1147             CODE:
1148 0           sub->notify_fd = fd;
1149              
1150             IV
1151             fileno(self)
1152             SV *self
1153             PREINIT:
1154 1 50         EXTRACT_SUB("Data::PubSub::Shared::Str::Sub", self);
    50          
    50          
1155             CODE:
1156 1 50         RETVAL = sub->notify_fd;
1157             OUTPUT:
1158             RETVAL
1159              
1160             MODULE = Data::PubSub::Shared PACKAGE = Data::PubSub::Shared::Int32
1161              
1162             SV *
1163             new(class, path, capacity, ...)
1164             const char *class
1165             SV *path
1166             UV capacity
1167             PREINIT:
1168             char errbuf[PUBSUB_ERR_BUFLEN];
1169             CODE:
1170 12 50         mode_t fmode = (items > 3 && (SvGETMAGIC(ST(3)), SvOK(ST(3)))) ? (mode_t)SvUV(ST(3)) : 0600;
    0          
    0          
    0          
1171 12 50         const char *p = (SvGETMAGIC(path), SvOK(path)) ? SvPV_nolen(path) : NULL;
    0          
    100          
1172 12           PubSubHandle *h = pubsub_create(p, (uint32_t)capacity, PUBSUB_MODE_INT32, 0, fmode, errbuf);
1173 12 100         if (!h) croak("Data::PubSub::Shared::Int32->new: %s", errbuf);
1174 11           MAKE_OBJ(class, h);
1175             OUTPUT:
1176             RETVAL
1177              
1178             SV *
1179             new_memfd(class, name, capacity)
1180             const char *class
1181             const char *name
1182             UV capacity
1183             PREINIT:
1184             char errbuf[PUBSUB_ERR_BUFLEN];
1185             CODE:
1186 1           PubSubHandle *h = pubsub_create_memfd(name, (uint32_t)capacity, PUBSUB_MODE_INT32, 0, errbuf);
1187 1 50         if (!h) croak("Data::PubSub::Shared::Int32->new_memfd: %s", errbuf);
1188 1           MAKE_OBJ(class, h);
1189             OUTPUT:
1190             RETVAL
1191              
1192             SV *
1193             new_from_fd(class, fd)
1194             const char *class
1195             int fd
1196             PREINIT:
1197             char errbuf[PUBSUB_ERR_BUFLEN];
1198             CODE:
1199 1           PubSubHandle *h = pubsub_open_fd(fd, PUBSUB_MODE_INT32, errbuf);
1200 1 50         if (!h) croak("Data::PubSub::Shared::Int32->new_from_fd: %s", errbuf);
1201 1           MAKE_OBJ(class, h);
1202             OUTPUT:
1203             RETVAL
1204              
1205             IV
1206             memfd(self)
1207             SV *self
1208             PREINIT:
1209 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    50          
    50          
1210             CODE:
1211 1 50         RETVAL = h->backing_fd;
1212             OUTPUT:
1213             RETVAL
1214              
1215             void
1216             DESTROY(self)
1217             SV *self
1218             CODE:
1219 13 50         if (!SvROK(self)) return;
1220 13           PubSubHandle *h = INT2PTR(PubSubHandle*, SvIV(SvRV(self)));
1221 13 50         if (!h) return;
1222 13           sv_setiv(SvRV(self), 0);
1223 13           pubsub_destroy(h);
1224              
1225             bool
1226             publish(self, value)
1227             SV *self
1228             IV value
1229             PREINIT:
1230 50 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    50          
    50          
1231             CODE:
1232 50 50         RETVAL = pubsub_int32_publish(h, (int32_t)value);
1233             OUTPUT:
1234             RETVAL
1235              
1236             UV
1237             publish_multi(self, ...)
1238             SV *self
1239             PREINIT:
1240 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    50          
    50          
1241             CODE:
1242 1           uint32_t count = items - 1;
1243 1 50         if (count == 0) { RETVAL = 0; }
1244             else {
1245 1 50         if (count > 8192) croak("publish_multi: too many values (%u > 8192)", count);
1246 1           int32_t *vals = (int32_t *)alloca(count * sizeof(int32_t));
1247 4 100         for (uint32_t i = 0; i < count; i++)
1248 3           vals[i] = (int32_t)SvIV(ST(i + 1));
1249 1           RETVAL = pubsub_int32_publish_multi(h, vals, count);
1250             }
1251             OUTPUT:
1252             RETVAL
1253              
1254             void
1255             publish_notify(self, value)
1256             SV *self
1257             IV value
1258             PREINIT:
1259 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    0          
    0          
1260             CODE:
1261 0           pubsub_int32_publish(h, (int32_t)value);
1262 0           pubsub_notify(h);
1263              
1264             SV *
1265             subscribe(self)
1266             SV *self
1267             PREINIT:
1268 4 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    50          
    50          
1269             CODE:
1270 4           PubSubSub *sub = pubsub_subscribe(h, 0);
1271 4 50         if (!sub) croak("subscribe: out of memory");
1272 4           sub->userdata = (void *)newSVsv(self);
1273 4           MAKE_OBJ("Data::PubSub::Shared::Int32::Sub", sub);
1274             OUTPUT:
1275             RETVAL
1276              
1277             SV *
1278             subscribe_all(self)
1279             SV *self
1280             PREINIT:
1281 7 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    50          
    50          
1282             CODE:
1283 7           PubSubSub *sub = pubsub_subscribe(h, 1);
1284 7 50         if (!sub) croak("subscribe_all: out of memory");
1285 7           sub->userdata = (void *)newSVsv(self);
1286 7           MAKE_OBJ("Data::PubSub::Shared::Int32::Sub", sub);
1287             OUTPUT:
1288             RETVAL
1289              
1290             UV
1291             capacity(self)
1292             SV *self
1293             PREINIT:
1294 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    50          
    50          
1295             CODE:
1296 1 50         RETVAL = h->capacity;
1297             OUTPUT:
1298             RETVAL
1299              
1300             UV
1301             write_pos(self)
1302             SV *self
1303             PREINIT:
1304 4 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    50          
    50          
1305             CODE:
1306 4 50         RETVAL = (UV)__atomic_load_n(&h->hdr->write_pos, __ATOMIC_RELAXED);
1307             OUTPUT:
1308             RETVAL
1309              
1310             SV *
1311             path(self)
1312             SV *self
1313             PREINIT:
1314 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    0          
    0          
1315             CODE:
1316 0 0         RETVAL = h->path ? newSVpv(h->path, 0) : &PL_sv_undef;
1317             OUTPUT:
1318             RETVAL
1319              
1320             SV *
1321             stats(self)
1322             SV *self
1323             PREINIT:
1324 2 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    50          
    50          
1325             CODE:
1326 2           HV *hv = newHV();
1327 2           PubSubHeader *hdr = h->hdr;
1328 2           hv_store(hv, "capacity", 8, newSVuv(h->capacity), 0);
1329 2           hv_store(hv, "mmap_size", 9, newSVuv((UV)h->mmap_size), 0);
1330 2           hv_store(hv, "write_pos", 9,
1331             newSVuv((UV)__atomic_load_n(&hdr->write_pos, __ATOMIC_RELAXED)), 0);
1332 2           hv_store(hv, "publish_ok", 10,
1333             newSVuv((UV)__atomic_load_n(&hdr->stat_publish_ok, __ATOMIC_RELAXED)), 0);
1334 2           hv_store(hv, "recoveries", 10,
1335             newSVuv(__atomic_load_n(&hdr->stat_recoveries, __ATOMIC_RELAXED)), 0);
1336 2           hv_store(hv, "sub_waiters", 11,
1337             newSVuv(__atomic_load_n(&hdr->sub_waiters, __ATOMIC_RELAXED)), 0);
1338 2           RETVAL = newRV_noinc((SV *)hv);
1339             OUTPUT:
1340             RETVAL
1341              
1342             void
1343             clear(self)
1344             SV *self
1345             PREINIT:
1346 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    50          
    50          
1347             CODE:
1348 1           pubsub_clear(h);
1349              
1350             void
1351             sync(self)
1352             SV *self
1353             PREINIT:
1354 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    50          
    50          
1355             CODE:
1356 1 50         if (pubsub_sync(h) != 0)
1357 0           croak("msync: %s", strerror(errno));
1358              
1359             void
1360             unlink(self_or_class, ...)
1361             SV *self_or_class
1362             CODE:
1363             const char *path;
1364 0 0         if (sv_isobject(self_or_class)) {
1365 0           PubSubHandle *h = INT2PTR(PubSubHandle*, SvIV(SvRV(self_or_class)));
1366 0 0         if (!h) croak("Attempted to use a destroyed object");
1367 0           path = h->path;
1368             } else {
1369 0 0         if (items < 2) croak("Usage: Data::PubSub::Shared::Int32->unlink($path)");
1370 0           path = SvPV_nolen(ST(1));
1371             }
1372 0 0         if (!path) croak("cannot unlink anonymous or memfd pubsub");
1373 0 0         if (unlink(path) != 0)
1374 0           croak("unlink(%s): %s", path, strerror(errno));
1375              
1376             IV
1377             eventfd(self)
1378             SV *self
1379             PREINIT:
1380 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    0          
    0          
1381             CODE:
1382 0           RETVAL = pubsub_eventfd_create(h);
1383 0 0         if (RETVAL < 0) croak("eventfd: %s", strerror(errno));
1384             OUTPUT:
1385             RETVAL
1386              
1387             void
1388             eventfd_set(self, fd)
1389             SV *self
1390             int fd
1391             PREINIT:
1392 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    0          
    0          
1393             CODE:
1394 0           pubsub_eventfd_set(h, fd);
1395              
1396             IV
1397             fileno(self)
1398             SV *self
1399             PREINIT:
1400 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    0          
    0          
1401             CODE:
1402 0 0         RETVAL = h->notify_fd;
1403             OUTPUT:
1404             RETVAL
1405              
1406             SV *
1407             eventfd_consume(self)
1408             SV *self
1409             PREINIT:
1410 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    0          
    0          
1411             CODE:
1412 0           int64_t v = pubsub_eventfd_consume(h);
1413 0 0         RETVAL = (v >= 0) ? newSViv((IV)v) : &PL_sv_undef;
1414             OUTPUT:
1415             RETVAL
1416              
1417             void
1418             notify(self)
1419             SV *self
1420             PREINIT:
1421 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int32", self);
    0          
    0          
1422             CODE:
1423 0           pubsub_notify(h);
1424              
1425             MODULE = Data::PubSub::Shared PACKAGE = Data::PubSub::Shared::Int32::Sub
1426              
1427             void
1428             DESTROY(self)
1429             SV *self
1430             CODE:
1431 11 50         if (!SvROK(self)) return;
1432 11           PubSubSub *sub = INT2PTR(PubSubSub*, SvIV(SvRV(self)));
1433 11 50         if (!sub) return;
1434 11           sv_setiv(SvRV(self), 0);
1435 11 50         if (sub->userdata) SvREFCNT_dec((SV *)sub->userdata);
1436 11           pubsub_sub_destroy(sub);
1437              
1438             SV *
1439             poll(self)
1440             SV *self
1441             PREINIT:
1442 9 50         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    50          
    50          
1443             int32_t value;
1444             CODE:
1445 9           int r = pubsub_int32_poll(sub, &value);
1446 9 100         if (r == 1)
1447 8           RETVAL = newSViv((IV)value);
1448             else
1449 1           RETVAL = &PL_sv_undef;
1450             OUTPUT:
1451             RETVAL
1452              
1453             void
1454             poll_multi(self, count)
1455             SV *self
1456             UV count
1457             PREINIT:
1458 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    50          
    50          
1459             int32_t value;
1460             PPCODE:
1461 7 50         for (UV i = 0; i < count; i++) {
1462 7           int r = pubsub_int32_poll(sub, &value);
1463 7 100         if (r != 1) break;
1464 6 50         mXPUSHi((IV)value);
1465             }
1466              
1467             SV *
1468             poll_wait(self, ...)
1469             SV *self
1470             PREINIT:
1471 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    50          
    50          
1472 1           double timeout = -1;
1473             int32_t value;
1474             CODE:
1475 1 50         if (items > 1) timeout = SvNV(ST(1));
1476 1           int r = pubsub_int32_poll_wait(sub, &value, timeout);
1477 1 50         if (r == 1)
1478 0           RETVAL = newSViv((IV)value);
1479             else
1480 1           RETVAL = &PL_sv_undef;
1481             OUTPUT:
1482             RETVAL
1483              
1484             void
1485             drain(self, ...)
1486             SV *self
1487             PREINIT:
1488 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    50          
    50          
1489             int32_t value;
1490             uint32_t max_count;
1491             PPCODE:
1492 1 50         max_count = (items > 1) ? (uint32_t)SvUV(ST(1)) : UINT32_MAX;
1493 9 50         while (max_count-- > 0 && pubsub_int32_poll(sub, &value))
    100          
1494 8 50         mXPUSHi((IV)value);
1495              
1496             void
1497             poll_wait_multi(self, count, ...)
1498             SV *self
1499             UV count
1500             PREINIT:
1501 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    50          
    50          
1502 1           double timeout = -1;
1503             int32_t value;
1504             PPCODE:
1505 1 50         if (count == 0) XSRETURN(0);
1506 1 50         if (items > 2) timeout = SvNV(ST(2));
1507 1 50         if (!pubsub_int32_poll_wait(sub, &value, timeout)) XSRETURN(0);
1508 1 50         mXPUSHi((IV)value);
1509 3 100         for (UV i = 1; i < count; i++) {
1510 2 50         if (!pubsub_int32_poll(sub, &value)) break;
1511 2 50         mXPUSHi((IV)value);
1512             }
1513              
1514             UV
1515             lag(self)
1516             SV *self
1517             PREINIT:
1518 3 50         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    50          
    50          
1519             CODE:
1520 3           RETVAL = (UV)pubsub_lag(sub);
1521             OUTPUT:
1522             RETVAL
1523              
1524             UV
1525             overflow_count(self)
1526             SV *self
1527             PREINIT:
1528 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    50          
    50          
1529             CODE:
1530 1 50         RETVAL = (UV)sub->overflow_count;
1531             OUTPUT:
1532             RETVAL
1533              
1534             UV
1535             write_pos(self)
1536             SV *self
1537             PREINIT:
1538 0 0         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    0          
    0          
1539             CODE:
1540 0 0         RETVAL = (UV)__atomic_load_n(&sub->hdr->write_pos, __ATOMIC_RELAXED);
1541             OUTPUT:
1542             RETVAL
1543              
1544             bool
1545             has_overflow(self)
1546             SV *self
1547             PREINIT:
1548 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    50          
    50          
1549             CODE:
1550 1           uint64_t wp = __atomic_load_n(&sub->hdr->write_pos, __ATOMIC_RELAXED);
1551 1 50         RETVAL = (sub->cursor < wp && wp - sub->cursor > sub->capacity);
    50          
    50          
1552             OUTPUT:
1553             RETVAL
1554              
1555             UV
1556             cursor(self, ...)
1557             SV *self
1558             PREINIT:
1559 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    50          
    50          
1560             CODE:
1561 1 50         if (items > 1) sub->cursor = (uint64_t)SvUV(ST(1));
1562 1 50         RETVAL = (UV)sub->cursor;
1563             OUTPUT:
1564             RETVAL
1565              
1566             void
1567             reset(self)
1568             SV *self
1569             PREINIT:
1570 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    50          
    50          
1571             CODE:
1572 1           sub->cursor = __atomic_load_n(&sub->hdr->write_pos, __ATOMIC_ACQUIRE);
1573              
1574             void
1575             reset_oldest(self)
1576             SV *self
1577             PREINIT:
1578 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    50          
    50          
1579             CODE:
1580 1           uint64_t wp = __atomic_load_n(&sub->hdr->write_pos, __ATOMIC_ACQUIRE);
1581 1 50         sub->cursor = (wp > sub->capacity) ? wp - sub->capacity : 0;
1582              
1583             UV
1584             poll_cb(self, cb)
1585             SV *self
1586             SV *cb
1587             PREINIT:
1588 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    50          
    50          
1589             int32_t value;
1590             CODE:
1591 1           RETVAL = 0;
1592             /* Keep the backing handle alive across the callback: a callback that
1593             * drops self's last reference would free `sub` mid-loop (UAF). Guard
1594             * the referent (the blessed handle), not the RV container -- assigning
1595             * undef to self overwrites the container and frees the referent. */
1596 1           SV *psx_guard = SvRV(self);
1597 1           SvREFCNT_inc_simple_void_NN(psx_guard);
1598 1           SAVEFREESV(psx_guard);
1599 6 100         while (pubsub_int32_poll(sub, &value)) {
1600 5           dSP;
1601 5           ENTER; SAVETMPS;
1602 5 50         PUSHMARK(SP);
1603 5 50         mXPUSHi((IV)value);
1604 5           PUTBACK;
1605 5           call_sv(cb, G_DISCARD);
1606 5 50         FREETMPS; LEAVE;
1607 5           RETVAL++;
1608             }
1609             OUTPUT:
1610             RETVAL
1611              
1612             void
1613             drain_notify(self, ...)
1614             SV *self
1615             PREINIT:
1616 0 0         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    0          
    0          
1617             int32_t value;
1618             uint32_t max_count;
1619             PPCODE:
1620 0           pubsub_sub_eventfd_consume(sub);
1621 0 0         max_count = (items > 1) ? (uint32_t)SvUV(ST(1)) : UINT32_MAX;
1622 0 0         while (max_count-- > 0 && pubsub_int32_poll(sub, &value))
    0          
1623 0 0         mXPUSHi((IV)value);
1624              
1625             void
1626             eventfd_set(self, fd)
1627             SV *self
1628             int fd
1629             PREINIT:
1630 0 0         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    0          
    0          
1631             CODE:
1632 0           sub->notify_fd = fd;
1633              
1634             IV
1635             fileno(self)
1636             SV *self
1637             PREINIT:
1638 0 0         EXTRACT_SUB("Data::PubSub::Shared::Int32::Sub", self);
    0          
    0          
1639             CODE:
1640 0 0         RETVAL = sub->notify_fd;
1641             OUTPUT:
1642             RETVAL
1643              
1644             MODULE = Data::PubSub::Shared PACKAGE = Data::PubSub::Shared::Int16
1645              
1646             SV *
1647             new(class, path, capacity, ...)
1648             const char *class
1649             SV *path
1650             UV capacity
1651             PREINIT:
1652             char errbuf[PUBSUB_ERR_BUFLEN];
1653             CODE:
1654 11 50         mode_t fmode = (items > 3 && (SvGETMAGIC(ST(3)), SvOK(ST(3)))) ? (mode_t)SvUV(ST(3)) : 0600;
    0          
    0          
    0          
1655 11 50         const char *p = (SvGETMAGIC(path), SvOK(path)) ? SvPV_nolen(path) : NULL;
    0          
    100          
1656 11           PubSubHandle *h = pubsub_create(p, (uint32_t)capacity, PUBSUB_MODE_INT16, 0, fmode, errbuf);
1657 11 100         if (!h) croak("Data::PubSub::Shared::Int16->new: %s", errbuf);
1658 10           MAKE_OBJ(class, h);
1659             OUTPUT:
1660             RETVAL
1661              
1662             SV *
1663             new_memfd(class, name, capacity)
1664             const char *class
1665             const char *name
1666             UV capacity
1667             PREINIT:
1668             char errbuf[PUBSUB_ERR_BUFLEN];
1669             CODE:
1670 1           PubSubHandle *h = pubsub_create_memfd(name, (uint32_t)capacity, PUBSUB_MODE_INT16, 0, errbuf);
1671 1 50         if (!h) croak("Data::PubSub::Shared::Int16->new_memfd: %s", errbuf);
1672 1           MAKE_OBJ(class, h);
1673             OUTPUT:
1674             RETVAL
1675              
1676             SV *
1677             new_from_fd(class, fd)
1678             const char *class
1679             int fd
1680             PREINIT:
1681             char errbuf[PUBSUB_ERR_BUFLEN];
1682             CODE:
1683 1           PubSubHandle *h = pubsub_open_fd(fd, PUBSUB_MODE_INT16, errbuf);
1684 1 50         if (!h) croak("Data::PubSub::Shared::Int16->new_from_fd: %s", errbuf);
1685 1           MAKE_OBJ(class, h);
1686             OUTPUT:
1687             RETVAL
1688              
1689             IV
1690             memfd(self)
1691             SV *self
1692             PREINIT:
1693 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    50          
    50          
1694             CODE:
1695 1 50         RETVAL = h->backing_fd;
1696             OUTPUT:
1697             RETVAL
1698              
1699             void
1700             DESTROY(self)
1701             SV *self
1702             CODE:
1703 12 50         if (!SvROK(self)) return;
1704 12           PubSubHandle *h = INT2PTR(PubSubHandle*, SvIV(SvRV(self)));
1705 12 50         if (!h) return;
1706 12           sv_setiv(SvRV(self), 0);
1707 12           pubsub_destroy(h);
1708              
1709             bool
1710             publish(self, value)
1711             SV *self
1712             IV value
1713             PREINIT:
1714 49 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    50          
    50          
1715             CODE:
1716 49 50         RETVAL = pubsub_int16_publish(h, (int16_t)value);
1717             OUTPUT:
1718             RETVAL
1719              
1720             UV
1721             publish_multi(self, ...)
1722             SV *self
1723             PREINIT:
1724 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    50          
    50          
1725             CODE:
1726 1           uint32_t count = items - 1;
1727 1 50         if (count == 0) { RETVAL = 0; }
1728             else {
1729 1 50         if (count > 8192) croak("publish_multi: too many values (%u > 8192)", count);
1730 1           int16_t *vals = (int16_t *)alloca(count * sizeof(int16_t));
1731 4 100         for (uint32_t i = 0; i < count; i++)
1732 3           vals[i] = (int16_t)SvIV(ST(i + 1));
1733 1           RETVAL = pubsub_int16_publish_multi(h, vals, count);
1734             }
1735             OUTPUT:
1736             RETVAL
1737              
1738             void
1739             publish_notify(self, value)
1740             SV *self
1741             IV value
1742             PREINIT:
1743 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    0          
    0          
1744             CODE:
1745 0           pubsub_int16_publish(h, (int16_t)value);
1746 0           pubsub_notify(h);
1747              
1748             SV *
1749             subscribe(self)
1750             SV *self
1751             PREINIT:
1752 4 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    50          
    50          
1753             CODE:
1754 4           PubSubSub *sub = pubsub_subscribe(h, 0);
1755 4 50         if (!sub) croak("subscribe: out of memory");
1756 4           sub->userdata = (void *)newSVsv(self);
1757 4           MAKE_OBJ("Data::PubSub::Shared::Int16::Sub", sub);
1758             OUTPUT:
1759             RETVAL
1760              
1761             SV *
1762             subscribe_all(self)
1763             SV *self
1764             PREINIT:
1765 7 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    50          
    50          
1766             CODE:
1767 7           PubSubSub *sub = pubsub_subscribe(h, 1);
1768 7 50         if (!sub) croak("subscribe_all: out of memory");
1769 7           sub->userdata = (void *)newSVsv(self);
1770 7           MAKE_OBJ("Data::PubSub::Shared::Int16::Sub", sub);
1771             OUTPUT:
1772             RETVAL
1773              
1774             UV
1775             capacity(self)
1776             SV *self
1777             PREINIT:
1778 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    50          
    50          
1779             CODE:
1780 1 50         RETVAL = h->capacity;
1781             OUTPUT:
1782             RETVAL
1783              
1784             UV
1785             write_pos(self)
1786             SV *self
1787             PREINIT:
1788 4 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    50          
    50          
1789             CODE:
1790 4 50         RETVAL = (UV)__atomic_load_n(&h->hdr->write_pos, __ATOMIC_RELAXED);
1791             OUTPUT:
1792             RETVAL
1793              
1794             SV *
1795             path(self)
1796             SV *self
1797             PREINIT:
1798 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    0          
    0          
1799             CODE:
1800 0 0         RETVAL = h->path ? newSVpv(h->path, 0) : &PL_sv_undef;
1801             OUTPUT:
1802             RETVAL
1803              
1804             SV *
1805             stats(self)
1806             SV *self
1807             PREINIT:
1808 2 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    50          
    50          
1809             CODE:
1810 2           HV *hv = newHV();
1811 2           PubSubHeader *hdr = h->hdr;
1812 2           hv_store(hv, "capacity", 8, newSVuv(h->capacity), 0);
1813 2           hv_store(hv, "mmap_size", 9, newSVuv((UV)h->mmap_size), 0);
1814 2           hv_store(hv, "write_pos", 9,
1815             newSVuv((UV)__atomic_load_n(&hdr->write_pos, __ATOMIC_RELAXED)), 0);
1816 2           hv_store(hv, "publish_ok", 10,
1817             newSVuv((UV)__atomic_load_n(&hdr->stat_publish_ok, __ATOMIC_RELAXED)), 0);
1818 2           hv_store(hv, "recoveries", 10,
1819             newSVuv(__atomic_load_n(&hdr->stat_recoveries, __ATOMIC_RELAXED)), 0);
1820 2           hv_store(hv, "sub_waiters", 11,
1821             newSVuv(__atomic_load_n(&hdr->sub_waiters, __ATOMIC_RELAXED)), 0);
1822 2           RETVAL = newRV_noinc((SV *)hv);
1823             OUTPUT:
1824             RETVAL
1825              
1826             void
1827             clear(self)
1828             SV *self
1829             PREINIT:
1830 1 50         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    50          
    50          
1831             CODE:
1832 1           pubsub_clear(h);
1833              
1834             void
1835             sync(self)
1836             SV *self
1837             PREINIT:
1838 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    0          
    0          
1839             CODE:
1840 0 0         if (pubsub_sync(h) != 0)
1841 0           croak("msync: %s", strerror(errno));
1842              
1843             void
1844             unlink(self_or_class, ...)
1845             SV *self_or_class
1846             CODE:
1847             const char *path;
1848 0 0         if (sv_isobject(self_or_class)) {
1849 0           PubSubHandle *h = INT2PTR(PubSubHandle*, SvIV(SvRV(self_or_class)));
1850 0 0         if (!h) croak("Attempted to use a destroyed object");
1851 0           path = h->path;
1852             } else {
1853 0 0         if (items < 2) croak("Usage: Data::PubSub::Shared::Int16->unlink($path)");
1854 0           path = SvPV_nolen(ST(1));
1855             }
1856 0 0         if (!path) croak("cannot unlink anonymous or memfd pubsub");
1857 0 0         if (unlink(path) != 0)
1858 0           croak("unlink(%s): %s", path, strerror(errno));
1859              
1860             IV
1861             eventfd(self)
1862             SV *self
1863             PREINIT:
1864 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    0          
    0          
1865             CODE:
1866 0           RETVAL = pubsub_eventfd_create(h);
1867 0 0         if (RETVAL < 0) croak("eventfd: %s", strerror(errno));
1868             OUTPUT:
1869             RETVAL
1870              
1871             void
1872             eventfd_set(self, fd)
1873             SV *self
1874             int fd
1875             PREINIT:
1876 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    0          
    0          
1877             CODE:
1878 0           pubsub_eventfd_set(h, fd);
1879              
1880             IV
1881             fileno(self)
1882             SV *self
1883             PREINIT:
1884 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    0          
    0          
1885             CODE:
1886 0 0         RETVAL = h->notify_fd;
1887             OUTPUT:
1888             RETVAL
1889              
1890             SV *
1891             eventfd_consume(self)
1892             SV *self
1893             PREINIT:
1894 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    0          
    0          
1895             CODE:
1896 0           int64_t v = pubsub_eventfd_consume(h);
1897 0 0         RETVAL = (v >= 0) ? newSViv((IV)v) : &PL_sv_undef;
1898             OUTPUT:
1899             RETVAL
1900              
1901             void
1902             notify(self)
1903             SV *self
1904             PREINIT:
1905 0 0         EXTRACT_HANDLE("Data::PubSub::Shared::Int16", self);
    0          
    0          
1906             CODE:
1907 0           pubsub_notify(h);
1908              
1909             MODULE = Data::PubSub::Shared PACKAGE = Data::PubSub::Shared::Int16::Sub
1910              
1911             void
1912             DESTROY(self)
1913             SV *self
1914             CODE:
1915 11 50         if (!SvROK(self)) return;
1916 11           PubSubSub *sub = INT2PTR(PubSubSub*, SvIV(SvRV(self)));
1917 11 50         if (!sub) return;
1918 11           sv_setiv(SvRV(self), 0);
1919 11 50         if (sub->userdata) SvREFCNT_dec((SV *)sub->userdata);
1920 11           pubsub_sub_destroy(sub);
1921              
1922             SV *
1923             poll(self)
1924             SV *self
1925             PREINIT:
1926 9 50         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    50          
    50          
1927             int16_t value;
1928             CODE:
1929 9           int r = pubsub_int16_poll(sub, &value);
1930 9 100         if (r == 1)
1931 8           RETVAL = newSViv((IV)value);
1932             else
1933 1           RETVAL = &PL_sv_undef;
1934             OUTPUT:
1935             RETVAL
1936              
1937             void
1938             poll_multi(self, count)
1939             SV *self
1940             UV count
1941             PREINIT:
1942 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    50          
    50          
1943             int16_t value;
1944             PPCODE:
1945 7 50         for (UV i = 0; i < count; i++) {
1946 7           int r = pubsub_int16_poll(sub, &value);
1947 7 100         if (r != 1) break;
1948 6 50         mXPUSHi((IV)value);
1949             }
1950              
1951             SV *
1952             poll_wait(self, ...)
1953             SV *self
1954             PREINIT:
1955 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    50          
    50          
1956 1           double timeout = -1;
1957             int16_t value;
1958             CODE:
1959 1 50         if (items > 1) timeout = SvNV(ST(1));
1960 1           int r = pubsub_int16_poll_wait(sub, &value, timeout);
1961 1 50         if (r == 1)
1962 0           RETVAL = newSViv((IV)value);
1963             else
1964 1           RETVAL = &PL_sv_undef;
1965             OUTPUT:
1966             RETVAL
1967              
1968             void
1969             drain(self, ...)
1970             SV *self
1971             PREINIT:
1972 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    50          
    50          
1973             int16_t value;
1974             uint32_t max_count;
1975             PPCODE:
1976 1 50         max_count = (items > 1) ? (uint32_t)SvUV(ST(1)) : UINT32_MAX;
1977 9 50         while (max_count-- > 0 && pubsub_int16_poll(sub, &value))
    100          
1978 8 50         mXPUSHi((IV)value);
1979              
1980             void
1981             poll_wait_multi(self, count, ...)
1982             SV *self
1983             UV count
1984             PREINIT:
1985 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    50          
    50          
1986 1           double timeout = -1;
1987             int16_t value;
1988             PPCODE:
1989 1 50         if (count == 0) XSRETURN(0);
1990 1 50         if (items > 2) timeout = SvNV(ST(2));
1991 1 50         if (!pubsub_int16_poll_wait(sub, &value, timeout)) XSRETURN(0);
1992 1 50         mXPUSHi((IV)value);
1993 3 100         for (UV i = 1; i < count; i++) {
1994 2 50         if (!pubsub_int16_poll(sub, &value)) break;
1995 2 50         mXPUSHi((IV)value);
1996             }
1997              
1998             UV
1999             lag(self)
2000             SV *self
2001             PREINIT:
2002 3 50         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    50          
    50          
2003             CODE:
2004 3           RETVAL = (UV)pubsub_lag(sub);
2005             OUTPUT:
2006             RETVAL
2007              
2008             UV
2009             overflow_count(self)
2010             SV *self
2011             PREINIT:
2012 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    50          
    50          
2013             CODE:
2014 1 50         RETVAL = (UV)sub->overflow_count;
2015             OUTPUT:
2016             RETVAL
2017              
2018             UV
2019             write_pos(self)
2020             SV *self
2021             PREINIT:
2022 0 0         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    0          
    0          
2023             CODE:
2024 0 0         RETVAL = (UV)__atomic_load_n(&sub->hdr->write_pos, __ATOMIC_RELAXED);
2025             OUTPUT:
2026             RETVAL
2027              
2028             bool
2029             has_overflow(self)
2030             SV *self
2031             PREINIT:
2032 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    50          
    50          
2033             CODE:
2034 1           uint64_t wp = __atomic_load_n(&sub->hdr->write_pos, __ATOMIC_RELAXED);
2035 1 50         RETVAL = (sub->cursor < wp && wp - sub->cursor > sub->capacity);
    50          
    50          
2036             OUTPUT:
2037             RETVAL
2038              
2039             UV
2040             cursor(self, ...)
2041             SV *self
2042             PREINIT:
2043 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    50          
    50          
2044             CODE:
2045 1 50         if (items > 1) sub->cursor = (uint64_t)SvUV(ST(1));
2046 1 50         RETVAL = (UV)sub->cursor;
2047             OUTPUT:
2048             RETVAL
2049              
2050             void
2051             reset(self)
2052             SV *self
2053             PREINIT:
2054 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    50          
    50          
2055             CODE:
2056 1           sub->cursor = __atomic_load_n(&sub->hdr->write_pos, __ATOMIC_ACQUIRE);
2057              
2058             void
2059             reset_oldest(self)
2060             SV *self
2061             PREINIT:
2062 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    50          
    50          
2063             CODE:
2064 1           uint64_t wp = __atomic_load_n(&sub->hdr->write_pos, __ATOMIC_ACQUIRE);
2065 1 50         sub->cursor = (wp > sub->capacity) ? wp - sub->capacity : 0;
2066              
2067             UV
2068             poll_cb(self, cb)
2069             SV *self
2070             SV *cb
2071             PREINIT:
2072 1 50         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    50          
    50          
2073             int16_t value;
2074             CODE:
2075 1           RETVAL = 0;
2076             /* Keep the backing handle alive across the callback: a callback that
2077             * drops self's last reference would free `sub` mid-loop (UAF). Guard
2078             * the referent (the blessed handle), not the RV container -- assigning
2079             * undef to self overwrites the container and frees the referent. */
2080 1           SV *psx_guard = SvRV(self);
2081 1           SvREFCNT_inc_simple_void_NN(psx_guard);
2082 1           SAVEFREESV(psx_guard);
2083 6 100         while (pubsub_int16_poll(sub, &value)) {
2084 5           dSP;
2085 5           ENTER; SAVETMPS;
2086 5 50         PUSHMARK(SP);
2087 5 50         mXPUSHi((IV)value);
2088 5           PUTBACK;
2089 5           call_sv(cb, G_DISCARD);
2090 5 50         FREETMPS; LEAVE;
2091 5           RETVAL++;
2092             }
2093             OUTPUT:
2094             RETVAL
2095              
2096             void
2097             drain_notify(self, ...)
2098             SV *self
2099             PREINIT:
2100 0 0         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    0          
    0          
2101             int16_t value;
2102             uint32_t max_count;
2103             PPCODE:
2104 0           pubsub_sub_eventfd_consume(sub);
2105 0 0         max_count = (items > 1) ? (uint32_t)SvUV(ST(1)) : UINT32_MAX;
2106 0 0         while (max_count-- > 0 && pubsub_int16_poll(sub, &value))
    0          
2107 0 0         mXPUSHi((IV)value);
2108              
2109             void
2110             eventfd_set(self, fd)
2111             SV *self
2112             int fd
2113             PREINIT:
2114 0 0         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    0          
    0          
2115             CODE:
2116 0           sub->notify_fd = fd;
2117              
2118             IV
2119             fileno(self)
2120             SV *self
2121             PREINIT:
2122 0 0         EXTRACT_SUB("Data::PubSub::Shared::Int16::Sub", self);
    0          
    0          
2123             CODE:
2124 0 0         RETVAL = sub->notify_fd;
2125             OUTPUT:
2126             RETVAL