File Coverage

Shared.xs
Criterion Covered Total %
statement 145 210 69.0
branch 147 340 43.2
condition n/a
subroutine n/a
pod n/a
total 292 550 53.0


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             #include "ppport.h"
6             #include "deque.h"
7              
8             #define EXTRACT_DEQ(sv) \
9             if (!sv_isobject(sv) || !sv_derived_from(sv, "Data::Deque::Shared")) \
10             croak("Expected a Data::Deque::Shared object"); \
11             DeqHandle *h = INT2PTR(DeqHandle*, SvIV(SvRV(sv))); \
12             if (!h) croak("Attempted to use a destroyed Data::Deque::Shared object")
13              
14             #define MAKE_OBJ(class, handle) \
15             SV *obj = newSViv(PTR2IV(handle)); \
16             SV *ref = newRV_noinc(obj); \
17             sv_bless(ref, gv_stashpv(class, GV_ADD)); \
18             RETVAL = ref
19              
20             MODULE = Data::Deque::Shared PACKAGE = Data::Deque::Shared
21              
22             PROTOTYPES: DISABLE
23              
24             void
25             DESTROY(self)
26             SV *self
27             CODE:
28 20 50         if (!SvROK(self)) return;
29 20           DeqHandle *h = INT2PTR(DeqHandle*, SvIV(SvRV(self)));
30 20 50         if (!h) return;
31 20           sv_setiv(SvRV(self), 0);
32 20           deq_destroy(h);
33              
34             UV
35             size(self)
36             SV *self
37             PREINIT:
38 12 50         EXTRACT_DEQ(self);
    50          
    50          
39             CODE:
40 12 50         RETVAL = (UV)deq_size(h);
41             OUTPUT:
42             RETVAL
43              
44             UV
45             capacity(self)
46             SV *self
47             PREINIT:
48 10 50         EXTRACT_DEQ(self);
    50          
    50          
49             CODE:
50 10 50         RETVAL = (UV)h->hdr->capacity;
51             OUTPUT:
52             RETVAL
53              
54             bool
55             is_empty(self)
56             SV *self
57             PREINIT:
58 7 50         EXTRACT_DEQ(self);
    50          
    50          
59             CODE:
60 7 50         RETVAL = deq_size(h) == 0;
61             OUTPUT:
62             RETVAL
63              
64             bool
65             is_full(self)
66             SV *self
67             PREINIT:
68 3 50         EXTRACT_DEQ(self);
    50          
    50          
69             CODE:
70 3 50         RETVAL = deq_size(h) >= h->hdr->capacity;
71             OUTPUT:
72             RETVAL
73              
74             void
75             clear(self)
76             SV *self
77             PREINIT:
78 3 50         EXTRACT_DEQ(self);
    50          
    50          
79             CODE:
80 3           deq_clear(h);
81              
82             UV
83             drain(self)
84             SV *self
85             PREINIT:
86 4 50         EXTRACT_DEQ(self);
    50          
    50          
87             CODE:
88 4 50         RETVAL = (UV)deq_drain(h);
89             OUTPUT:
90             RETVAL
91              
92             SV *
93             path(self)
94             SV *self
95             PREINIT:
96 1 50         EXTRACT_DEQ(self);
    50          
    50          
97             CODE:
98 1 50         RETVAL = h->path ? newSVpv(h->path, 0) : &PL_sv_undef;
99             OUTPUT:
100             RETVAL
101              
102             IV
103             memfd(self)
104             SV *self
105             PREINIT:
106 1 50         EXTRACT_DEQ(self);
    50          
    50          
107             CODE:
108 1 50         RETVAL = h->backing_fd;
109             OUTPUT:
110             RETVAL
111              
112             IV
113             eventfd(self)
114             SV *self
115             PREINIT:
116 2 50         EXTRACT_DEQ(self);
    50          
    50          
117             CODE:
118 2           RETVAL = deq_create_eventfd(h);
119 2 50         if (RETVAL < 0) croak("eventfd: %s", strerror(errno));
120             OUTPUT:
121             RETVAL
122              
123             void
124             eventfd_set(self, fd)
125             SV *self
126             int fd
127             PREINIT:
128 3 50         EXTRACT_DEQ(self);
    50          
    50          
129             CODE:
130 3 50         if (h->notify_fd >= 0 && h->notify_fd != fd) close(h->notify_fd);
    100          
131 3           h->notify_fd = fd;
132              
133             IV
134             fileno(self)
135             SV *self
136             PREINIT:
137 3 50         EXTRACT_DEQ(self);
    50          
    50          
138             CODE:
139 3 50         RETVAL = h->notify_fd;
140             OUTPUT:
141             RETVAL
142              
143             bool
144             notify(self)
145             SV *self
146             PREINIT:
147 2 50         EXTRACT_DEQ(self);
    50          
    50          
148             CODE:
149 2 50         RETVAL = deq_notify(h);
150             OUTPUT:
151             RETVAL
152              
153             SV *
154             eventfd_consume(self)
155             SV *self
156             PREINIT:
157 2 50         EXTRACT_DEQ(self);
    50          
    50          
158             CODE:
159 2           int64_t v = deq_eventfd_consume(h);
160 2 50         RETVAL = (v >= 0) ? newSViv((IV)v) : &PL_sv_undef;
161             OUTPUT:
162             RETVAL
163              
164             void
165             sync(self)
166             SV *self
167             PREINIT:
168 1 50         EXTRACT_DEQ(self);
    50          
    50          
169             CODE:
170 1 50         if (deq_msync(h) != 0) croak("msync: %s", strerror(errno));
171              
172             void
173             unlink(self_or_class, ...)
174             SV *self_or_class
175             CODE:
176             const char *p;
177 2 50         if (sv_isobject(self_or_class)) {
178 2           DeqHandle *h = INT2PTR(DeqHandle*, SvIV(SvRV(self_or_class)));
179 2 50         if (!h) croak("Attempted to use a destroyed object");
180 2           p = h->path;
181             } else {
182 0 0         if (items < 2) croak("Usage: ...->unlink($path)");
183 0           p = SvPV_nolen(ST(1));
184             }
185 2 50         if (!p) croak("cannot unlink anonymous or memfd object");
186 2 50         if (unlink(p) != 0) croak("unlink(%s): %s", p, strerror(errno));
187              
188             SV *
189             stats(self)
190             SV *self
191             PREINIT:
192 3 50         EXTRACT_DEQ(self);
    50          
    50          
193             CODE:
194 3           HV *hv = newHV();
195 3           DeqHeader *hdr = h->hdr;
196 3           hv_store(hv, "size", 4, newSVuv((UV)deq_size(h)), 0);
197 3           hv_store(hv, "capacity", 8, newSVuv((UV)hdr->capacity), 0);
198 3           hv_store(hv, "pushes", 6, newSVuv((UV)__atomic_load_n(&hdr->stat_pushes, __ATOMIC_RELAXED)), 0);
199 3           hv_store(hv, "pops", 4, newSVuv((UV)__atomic_load_n(&hdr->stat_pops, __ATOMIC_RELAXED)), 0);
200 3           hv_store(hv, "waits", 5, newSVuv((UV)__atomic_load_n(&hdr->stat_waits, __ATOMIC_RELAXED)), 0);
201 3           hv_store(hv, "timeouts", 8, newSVuv((UV)__atomic_load_n(&hdr->stat_timeouts, __ATOMIC_RELAXED)), 0);
202 3           hv_store(hv, "recoveries", 10, newSVuv((UV)__atomic_load_n(&hdr->stat_recoveries, __ATOMIC_RELAXED)), 0);
203 3           hv_store(hv, "mmap_size", 9, newSVuv((UV)h->mmap_size), 0);
204 3           RETVAL = newRV_noinc((SV *)hv);
205             OUTPUT:
206             RETVAL
207              
208              
209             MODULE = Data::Deque::Shared PACKAGE = Data::Deque::Shared::Int
210              
211             PROTOTYPES: DISABLE
212              
213             SV *
214             new(class, path, capacity, ...)
215             const char *class
216             SV *path
217             UV capacity
218             PREINIT:
219             char errbuf[DEQ_ERR_BUFLEN];
220             CODE:
221 15 50         mode_t mode = (items > 3 && (SvGETMAGIC(ST(3)), SvOK(ST(3)))) ? (mode_t)SvUV(ST(3)) : 0600;
    0          
    0          
    0          
222 15 50         const char *p = (SvGETMAGIC(path), SvOK(path)) ? SvPV_nolen(path) : NULL;
    0          
    100          
223 15           DeqHandle *h = deq_create(p, capacity, sizeof(int64_t), DEQ_VAR_INT, mode, errbuf);
224 15 100         if (!h) croak("Data::Deque::Shared::Int->new: %s", errbuf);
225 13           MAKE_OBJ(class, h);
226             OUTPUT:
227             RETVAL
228              
229             SV *
230             new_memfd(class, name, capacity)
231             const char *class
232             const char *name
233             UV capacity
234             PREINIT:
235             char errbuf[DEQ_ERR_BUFLEN];
236             CODE:
237 1           DeqHandle *h = deq_create_memfd(name, capacity, sizeof(int64_t), DEQ_VAR_INT, errbuf);
238 1 50         if (!h) croak("Data::Deque::Shared::Int->new_memfd: %s", errbuf);
239 1           MAKE_OBJ(class, h);
240             OUTPUT:
241             RETVAL
242              
243             SV *
244             new_from_fd(class, fd)
245             const char *class
246             int fd
247             PREINIT:
248             char errbuf[DEQ_ERR_BUFLEN];
249             CODE:
250 1           DeqHandle *h = deq_open_fd(fd, DEQ_VAR_INT, errbuf);
251 1 50         if (!h) croak("Data::Deque::Shared::Int->new_from_fd: %s", errbuf);
252 1           MAKE_OBJ(class, h);
253             OUTPUT:
254             RETVAL
255              
256             bool
257             push_back(self, val)
258             SV *self
259             IV val
260             PREINIT:
261 95 50         EXTRACT_DEQ(self);
    50          
    50          
262             CODE:
263 95           int64_t v = (int64_t)val;
264 95 100         RETVAL = deq_try_push_back(h, &v, sizeof(v));
265             OUTPUT:
266             RETVAL
267              
268             bool
269             push_front(self, val)
270             SV *self
271             IV val
272             PREINIT:
273 10 50         EXTRACT_DEQ(self);
    50          
    50          
274             CODE:
275 10           int64_t v = (int64_t)val;
276 10 100         RETVAL = deq_try_push_front(h, &v, sizeof(v));
277             OUTPUT:
278             RETVAL
279              
280             bool
281             push_back_wait(self, val, ...)
282             SV *self
283             IV val
284             PREINIT:
285 1 50         EXTRACT_DEQ(self);
    50          
    50          
286 1           double timeout = -1;
287             CODE:
288 1 50         if (items > 2) timeout = SvNV(ST(2));
289 1           int64_t v = (int64_t)val;
290 1 50         RETVAL = deq_push_wait(h, &v, sizeof(v), 0, timeout);
291             OUTPUT:
292             RETVAL
293              
294             bool
295             push_front_wait(self, val, ...)
296             SV *self
297             IV val
298             PREINIT:
299 1 50         EXTRACT_DEQ(self);
    50          
    50          
300 1           double timeout = -1;
301             CODE:
302 1 50         if (items > 2) timeout = SvNV(ST(2));
303 1           int64_t v = (int64_t)val;
304 1 50         RETVAL = deq_push_wait(h, &v, sizeof(v), 1, timeout);
305             OUTPUT:
306             RETVAL
307              
308             SV *
309             pop_front(self)
310             SV *self
311             PREINIT:
312 18032 50         EXTRACT_DEQ(self);
    50          
    50          
313             CODE:
314             int64_t v;
315 18032 100         RETVAL = deq_try_pop_front(h, &v) ? newSViv((IV)v) : &PL_sv_undef;
316             OUTPUT:
317             RETVAL
318              
319             SV *
320             pop_back(self)
321             SV *self
322             PREINIT:
323 10 50         EXTRACT_DEQ(self);
    50          
    50          
324             CODE:
325             int64_t v;
326 10 100         RETVAL = deq_try_pop_back(h, &v) ? newSViv((IV)v) : &PL_sv_undef;
327             OUTPUT:
328             RETVAL
329              
330             SV *
331             pop_front_wait(self, ...)
332             SV *self
333             PREINIT:
334 2 50         EXTRACT_DEQ(self);
    50          
    50          
335 2           double timeout = -1;
336             CODE:
337 2 50         if (items > 1) timeout = SvNV(ST(1));
338             int64_t v;
339 2 100         RETVAL = deq_pop_wait(h, &v, 0, timeout) ? newSViv((IV)v) : &PL_sv_undef;
340             OUTPUT:
341             RETVAL
342              
343             SV *
344             pop_back_wait(self, ...)
345             SV *self
346             PREINIT:
347 1 50         EXTRACT_DEQ(self);
    50          
    50          
348 1           double timeout = -1;
349             CODE:
350 1 50         if (items > 1) timeout = SvNV(ST(1));
351             int64_t v;
352 1 50         RETVAL = deq_pop_wait(h, &v, 1, timeout) ? newSViv((IV)v) : &PL_sv_undef;
353             OUTPUT:
354             RETVAL
355              
356             MODULE = Data::Deque::Shared PACKAGE = Data::Deque::Shared::Str
357              
358             PROTOTYPES: DISABLE
359              
360             SV *
361             new(class, path, capacity, max_len, ...)
362             const char *class
363             SV *path
364             UV capacity
365             UV max_len
366             PREINIT:
367             char errbuf[DEQ_ERR_BUFLEN];
368             CODE:
369 7 100         if (max_len == 0) croak("max_len must be > 0");
370 6 50         if (max_len >= 0x80000000u) /* bit 31 of the stored length is the UTF8 flag */
371 0           croak("max_len too large (>= 2 GiB)");
372 6 50         mode_t mode = (items > 4 && (SvGETMAGIC(ST(4)), SvOK(ST(4)))) ? (mode_t)SvUV(ST(4)) : 0600;
    0          
    0          
    0          
373 6           uint32_t elem_size = (uint32_t)(sizeof(uint32_t) + max_len);
374 6 50         const char *p = (SvGETMAGIC(path), SvOK(path)) ? SvPV_nolen(path) : NULL;
    0          
    100          
375 6           DeqHandle *h = deq_create(p, capacity, elem_size, DEQ_VAR_STR, mode, errbuf);
376 6 100         if (!h) croak("Data::Deque::Shared::Str->new: %s", errbuf);
377 5           MAKE_OBJ(class, h);
378             OUTPUT:
379             RETVAL
380              
381             SV *
382             new_memfd(class, name, capacity, max_len)
383             const char *class
384             const char *name
385             UV capacity
386             UV max_len
387             PREINIT:
388             char errbuf[DEQ_ERR_BUFLEN];
389             CODE:
390 0 0         if (max_len == 0) croak("max_len must be > 0");
391 0 0         if (max_len >= 0x80000000u) /* bit 31 of the stored length is the UTF8 flag */
392 0           croak("max_len too large (>= 2 GiB)");
393 0           uint32_t elem_size = (uint32_t)(sizeof(uint32_t) + max_len);
394 0           DeqHandle *h = deq_create_memfd(name, capacity, elem_size, DEQ_VAR_STR, errbuf);
395 0 0         if (!h) croak("Data::Deque::Shared::Str->new_memfd: %s", errbuf);
396 0           MAKE_OBJ(class, h);
397             OUTPUT:
398             RETVAL
399              
400             SV *
401             new_from_fd(class, fd)
402             const char *class
403             int fd
404             PREINIT:
405             char errbuf[DEQ_ERR_BUFLEN];
406             CODE:
407 0           DeqHandle *h = deq_open_fd(fd, DEQ_VAR_STR, errbuf);
408 0 0         if (!h) croak("Data::Deque::Shared::Str->new_from_fd: %s", errbuf);
409 0           MAKE_OBJ(class, h);
410             OUTPUT:
411             RETVAL
412              
413             bool
414             push_back(self, val)
415             SV *self
416             SV *val
417             PREINIT:
418 25 50         EXTRACT_DEQ(self);
    50          
    50          
419             CODE:
420             STRLEN slen;
421 25           const char *s = SvPV(val, slen);
422 25           uint32_t max_len = h->elem_size - sizeof(uint32_t);
423 25 100         if (slen > max_len) slen = max_len; /* fixed-size slot: truncate (documented + tested) */
424             uint8_t *buf;
425 25           Newxz(buf, h->elem_size, uint8_t);
426 25           uint32_t l32 = (uint32_t)slen | (SvUTF8(val) ? 0x80000000u : 0u); /* bit 31 = SvUTF8 */
427 25           memcpy(buf, &l32, sizeof(uint32_t));
428 25           memcpy(buf + sizeof(uint32_t), s, slen);
429 25           RETVAL = deq_try_push_back(h, buf, h->elem_size);
430 25           Safefree(buf);
431             OUTPUT:
432             RETVAL
433              
434             bool
435             push_front(self, val)
436             SV *self
437             SV *val
438             PREINIT:
439 3 50         EXTRACT_DEQ(self);
    50          
    50          
440             CODE:
441             STRLEN slen;
442 3           const char *s = SvPV(val, slen);
443 3           uint32_t max_len = h->elem_size - sizeof(uint32_t);
444 3 50         if (slen > max_len) slen = max_len; /* fixed-size slot: truncate (documented + tested) */
445             uint8_t *buf;
446 3           Newxz(buf, h->elem_size, uint8_t);
447 3           uint32_t l32 = (uint32_t)slen | (SvUTF8(val) ? 0x80000000u : 0u); /* bit 31 = SvUTF8 */
448 3           memcpy(buf, &l32, sizeof(uint32_t));
449 3           memcpy(buf + sizeof(uint32_t), s, slen);
450 3           RETVAL = deq_try_push_front(h, buf, h->elem_size);
451 3           Safefree(buf);
452             OUTPUT:
453             RETVAL
454              
455             bool
456             push_back_wait(self, val, ...)
457             SV *self
458             SV *val
459             PREINIT:
460 0 0         EXTRACT_DEQ(self);
    0          
    0          
461 0           double timeout = -1;
462             CODE:
463 0 0         if (items > 2) timeout = SvNV(ST(2));
464             STRLEN slen;
465 0           const char *s = SvPV(val, slen);
466 0           uint32_t max_len = h->elem_size - sizeof(uint32_t);
467 0 0         if (slen > max_len) slen = max_len; /* fixed-size slot: truncate (documented + tested) */
468             uint8_t *buf;
469 0           Newxz(buf, h->elem_size, uint8_t);
470 0           uint32_t l32 = (uint32_t)slen | (SvUTF8(val) ? 0x80000000u : 0u); /* bit 31 = SvUTF8 */
471 0           memcpy(buf, &l32, sizeof(uint32_t));
472 0           memcpy(buf + sizeof(uint32_t), s, slen);
473 0           RETVAL = deq_push_wait(h, buf, h->elem_size, 0, timeout);
474 0           Safefree(buf);
475             OUTPUT:
476             RETVAL
477              
478             bool
479             push_front_wait(self, val, ...)
480             SV *self
481             SV *val
482             PREINIT:
483 0 0         EXTRACT_DEQ(self);
    0          
    0          
484 0           double timeout = -1;
485             CODE:
486 0 0         if (items > 2) timeout = SvNV(ST(2));
487             STRLEN slen;
488 0           const char *s = SvPV(val, slen);
489 0           uint32_t max_len = h->elem_size - sizeof(uint32_t);
490 0 0         if (slen > max_len) slen = max_len; /* fixed-size slot: truncate (documented + tested) */
491             uint8_t *buf;
492 0           Newxz(buf, h->elem_size, uint8_t);
493 0           uint32_t l32 = (uint32_t)slen | (SvUTF8(val) ? 0x80000000u : 0u); /* bit 31 = SvUTF8 */
494 0           memcpy(buf, &l32, sizeof(uint32_t));
495 0           memcpy(buf + sizeof(uint32_t), s, slen);
496 0           RETVAL = deq_push_wait(h, buf, h->elem_size, 1, timeout);
497 0           Safefree(buf);
498             OUTPUT:
499             RETVAL
500              
501             SV *
502             pop_front(self)
503             SV *self
504             PREINIT:
505 26 50         EXTRACT_DEQ(self);
    50          
    50          
506             CODE:
507             uint8_t *buf;
508 26           Newx(buf, h->elem_size, uint8_t);
509 26           SAVEFREEPV(buf);
510 26 100         if (deq_try_pop_front(h, buf)) {
511             uint32_t l32;
512 25           memcpy(&l32, buf, sizeof(uint32_t));
513 25           int is_utf8 = (l32 & 0x80000000u) != 0;
514 25           uint32_t len = l32 & 0x7FFFFFFFu;
515 25           uint32_t max_len = h->elem_size - sizeof(uint32_t);
516 25 50         if (len > max_len) len = max_len;
517 25           RETVAL = newSVpvn((char *)buf + sizeof(uint32_t), len);
518 25 50         if (is_utf8) SvUTF8_on(RETVAL);
519             } else {
520 1           RETVAL = &PL_sv_undef;
521             }
522             OUTPUT:
523             RETVAL
524              
525             SV *
526             pop_back(self)
527             SV *self
528             PREINIT:
529 2 50         EXTRACT_DEQ(self);
    50          
    50          
530             CODE:
531             uint8_t *buf;
532 2           Newx(buf, h->elem_size, uint8_t);
533 2           SAVEFREEPV(buf);
534 2 100         if (deq_try_pop_back(h, buf)) {
535             uint32_t l32;
536 1           memcpy(&l32, buf, sizeof(uint32_t));
537 1           int is_utf8 = (l32 & 0x80000000u) != 0;
538 1           uint32_t len = l32 & 0x7FFFFFFFu;
539 1           uint32_t max_len = h->elem_size - sizeof(uint32_t);
540 1 50         if (len > max_len) len = max_len;
541 1           RETVAL = newSVpvn((char *)buf + sizeof(uint32_t), len);
542 1 50         if (is_utf8) SvUTF8_on(RETVAL);
543             } else {
544 1           RETVAL = &PL_sv_undef;
545             }
546             OUTPUT:
547             RETVAL
548              
549             SV *
550             pop_front_wait(self, ...)
551             SV *self
552             PREINIT:
553 0 0         EXTRACT_DEQ(self);
    0          
    0          
554 0           double timeout = -1;
555             CODE:
556 0 0         if (items > 1) timeout = SvNV(ST(1));
557             uint8_t *buf;
558 0           Newx(buf, h->elem_size, uint8_t);
559 0           SAVEFREEPV(buf);
560 0 0         if (deq_pop_wait(h, buf, 0, timeout)) {
561             uint32_t l32;
562 0           memcpy(&l32, buf, sizeof(uint32_t));
563 0           int is_utf8 = (l32 & 0x80000000u) != 0;
564 0           uint32_t len = l32 & 0x7FFFFFFFu;
565 0           uint32_t max_len = h->elem_size - sizeof(uint32_t);
566 0 0         if (len > max_len) len = max_len;
567 0           RETVAL = newSVpvn((char *)buf + sizeof(uint32_t), len);
568 0 0         if (is_utf8) SvUTF8_on(RETVAL);
569             } else {
570 0           RETVAL = &PL_sv_undef;
571             }
572             OUTPUT:
573             RETVAL
574              
575             SV *
576             pop_back_wait(self, ...)
577             SV *self
578             PREINIT:
579 0 0         EXTRACT_DEQ(self);
    0          
    0          
580 0           double timeout = -1;
581             CODE:
582 0 0         if (items > 1) timeout = SvNV(ST(1));
583             uint8_t *buf;
584 0           Newx(buf, h->elem_size, uint8_t);
585 0           SAVEFREEPV(buf);
586 0 0         if (deq_pop_wait(h, buf, 1, timeout)) {
587             uint32_t l32;
588 0           memcpy(&l32, buf, sizeof(uint32_t));
589 0           int is_utf8 = (l32 & 0x80000000u) != 0;
590 0           uint32_t len = l32 & 0x7FFFFFFFu;
591 0           uint32_t max_len = h->elem_size - sizeof(uint32_t);
592 0 0         if (len > max_len) len = max_len;
593 0           RETVAL = newSVpvn((char *)buf + sizeof(uint32_t), len);
594 0 0         if (is_utf8) SvUTF8_on(RETVAL);
595             } else {
596 0           RETVAL = &PL_sv_undef;
597             }
598             OUTPUT:
599             RETVAL