1#include "EXTERN.h"
2#include "perl.h"
3#include "XSUB.h"
4
5#include <errno.h>
6#include <string.h>
7
8#include <sys/types.h>
9#include <sys/event.h>
10#include <sys/time.h>
11
12#include "const-c.inc"
13
14typedef int kqueue_t;
15
16struct kevent *ke2 = NULL;
17AV * ke2av = NULL;
18
19MODULE = IO::KQueue  PACKAGE = IO::KQueue
20
21PROTOTYPES: DISABLE
22
23INCLUDE: const-xs.inc
24
25BOOT:
26    Newz(0, ke2, 1000, struct kevent);
27    ke2av = newAV();
28    av_store(ke2av, 0, (newSViv(0)));
29    av_store(ke2av, 1, (newSViv(0)));
30    av_store(ke2av, 2, (newSViv(0)));
31    av_store(ke2av, 3, (newSViv(0)));
32    av_store(ke2av, 4, (newSViv(0)));
33
34kqueue_t
35new(CLASS)
36    const char * CLASS
37    CODE:
38        RETVAL = kqueue();
39        if (RETVAL == -1) {
40            croak("kqueue() failed: %s", strerror(errno));
41        }
42    OUTPUT:
43        RETVAL
44
45void
46EV_SET(kq, ident, filter, flags, fflags = 0, data = 0, udata = NULL)
47    kqueue_t    kq
48    uintptr_t   ident
49    short       filter
50    u_short     flags
51    u_short     fflags
52    intptr_t    data
53    SV        * udata
54  PREINIT:
55    struct kevent ke;
56    int i;
57  PPCODE:
58    memset(&ke, 0, sizeof(struct kevent));
59    if (udata)
60        SvREFCNT_inc(udata);
61    else
62        udata = &PL_sv_undef;
63    EV_SET(&ke, ident, filter, flags, fflags, data, udata);
64    i = kevent(kq, &ke, 1, NULL, 0, NULL);
65    if (i == -1) {
66        croak("set kevent failed: %s", strerror(errno));
67    }
68
69void
70kevent(kq, timeout=&PL_sv_undef)
71    kqueue_t    kq
72    SV *        timeout
73  PREINIT:
74    int num_events, i;
75    struct timespec t;
76    struct kevent *ke = NULL;
77    struct timespec *tbuf = (struct timespec *)0;
78    I32 max_events = SvIV(get_sv("IO::KQueue::MAX_EVENTS", FALSE));
79  PPCODE:
80    Newxz(ke, max_events, struct kevent);
81    if (ke == NULL) {
82        croak("malloc failed");
83    }
84
85    if (timeout != &PL_sv_undef) {
86        I32 time = SvIV(timeout);
87        if (time >= 0) {
88            t.tv_sec = time / 1000;
89            t.tv_nsec = (time % 1000) * 1000000;
90            tbuf = &t;
91        }
92    }
93
94    num_events = kevent(kq, NULL, 0, ke, max_events, tbuf);
95
96    if (num_events == -1) {
97        Safefree(ke);
98        croak("kevent error: %s", strerror(errno));
99    }
100
101    /* extend it for the number of events we have */
102    EXTEND(SP, num_events);
103    for (i = 0; i < num_events; i++) {
104        AV * array = newAV();
105        av_push(array, newSViv(ke[i].ident));
106        av_push(array, newSViv(ke[i].filter));
107        av_push(array, newSViv(ke[i].flags));
108        av_push(array, newSViv(ke[i].fflags));
109        av_push(array, newSViv(ke[i].data));
110        av_push(array, SvREFCNT_inc(ke[i].udata));
111        PUSHs(sv_2mortal(newRV_noinc((SV*)array)));
112    }
113
114    Safefree(ke);
115
116int
117kevent2(kq, timeout=&PL_sv_undef)
118    kqueue_t    kq
119    SV *        timeout
120  PREINIT:
121    int num_events, i;
122    struct timespec t;
123    struct timespec *tbuf = (struct timespec *)0;
124  CODE:
125    if (timeout != &PL_sv_undef) {
126        I32 time = SvIV(timeout);
127        if (time >= 0) {
128            t.tv_sec = time / 1000;
129            t.tv_nsec = (time % 1000) * 1000000;
130            tbuf = &t;
131        }
132    }
133
134    RETVAL = kevent(kq, NULL, 0, ke2, 1000, tbuf);
135
136  OUTPUT:
137    RETVAL
138
139SV*
140get_kev(kq, i)
141    kqueue_t    kq
142    int  i
143  PREINIT:
144    dXSTARG;
145  CODE:
146    if (i < 0 || i >= 1000) {
147        croak("Invalid kevent id: %d", i);
148    }
149
150    sv_setiv(AvARRAY(ke2av)[0], ke2[i-1].ident);
151    sv_setiv(AvARRAY(ke2av)[1], ke2[i-1].filter);
152    sv_setiv(AvARRAY(ke2av)[2], ke2[i-1].flags);
153    sv_setiv(AvARRAY(ke2av)[3], ke2[i-1].fflags);
154    sv_setiv(AvARRAY(ke2av)[4], ke2[i-1].data);
155    av_store(ke2av, 5, SvREFCNT_inc(ke2[i-1].udata));
156
157    RETVAL = newRV_inc((SV*) ke2av);
158
159  OUTPUT:
160    RETVAL
161
162