summary refs log tree commit diff
path: root/evloop/kqueue.c
blob: 649e838fa6f4130a96e88af7da7fd9f3da987b08 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>

#include <errno.h>
#include <string.h>
#include <unistd.h>

#include "evloop.h"

static int m_kq;

static struct kevent m_evs[100];
static uint8_t m_valid[100];

int
evloop_init(void)
{
    if (timeheap_init() != 0)
        return -1;
    m_kq = kqueue();
    return m_kq >= 0 ? 0 : -1;
}

int
fdev_new(struct fdev *ev, int fd, uint16_t flags, evloop_cb_t cb, void *arg)
{
    ev->fd = fd;
    ev->cb = cb;
    ev->arg = arg;
    ev->flags = 0;
    ev->index = -1;
    return fdev_enable(ev, flags);
}

int
fdev_enable(struct fdev *ev, uint16_t flags)
{
    struct kevent kev[2], *kp = NULL;
    int count = 0;
    uint16_t sf = ev->flags;
    ev->flags |= flags;
    if ((sf & EV_READ) == 0 && (flags & EV_READ) != 0) {
        EV_SET(&kev[0], ev->fd, EVFILT_READ, EV_ADD, 0, 0, ev);
        kp = kev;
        count = 1;
    }
    if ((sf & EV_WRITE) == 0 && (flags & EV_WRITE) != 0) {
        EV_SET(&kev[1], ev->fd, EVFILT_WRITE, EV_ADD, 0, 0, ev);
        if (count == 0)
            kp = &kev[1];
        count++;
    }
    return count > 0 ? kevent(m_kq, kp, count, NULL, 0, NULL) : 0;
}

int
fdev_disable(struct fdev *ev, uint16_t flags)
{
    struct kevent kev[2], *kp = NULL;
    int count = 0;
    uint16_t sf = ev->flags;
    ev->flags &= ~flags;
    if ((sf & EV_READ) != 0 && (flags & EV_READ) != 0) {
        EV_SET(&kev[0], ev->fd, EVFILT_READ, EV_DELETE, 0, 0, ev);
        kp = kev;
        count = 1;
    }
    if ((sf & EV_WRITE) != 0 && (flags & EV_WRITE) != 0) {
        EV_SET(&kev[1], ev->fd, EVFILT_WRITE, EV_DELETE, 0, 0, ev);
        if (count == 0)
            kp = &kev[1];
        count++;
    }
    return count > 0 ? kevent(m_kq, kp, count, NULL, 0, NULL) : 0;
}

int
fdev_del(struct fdev *ev)
{
    if (ev->index >= 0)
        m_valid[ev->index] = 0;
    return fdev_disable(ev, EV_READ|EV_WRITE);
}

int
evloop(void)
{
    int nev, i;
    struct timespec delay;
    while (1) {
        evtimers_run();
        delay = evtimer_delay();

        if ((nev = kevent(m_kq, NULL, 0, m_evs, 100, &delay)) < 0) {
            if (errno == EINTR)
                continue;
            else
                return -1;
        }
        memset(m_valid, 1, nev);
        for (i = 0; i < nev; i++) {
            struct fdev *ev = (struct fdev *)m_evs[i].udata;
            ev->index = i;
        }
        for (i = 0; i < nev; i++) {
            if (m_evs[i].flags & EV_ERROR) {
                errno = m_evs[i].data;
                return -1;
            }
            struct fdev *ev = (struct fdev *)m_evs[i].udata;
            if (m_valid[i] && ev->flags & EV_READ &&
                m_evs[i].filter == EVFILT_READ)
                ev->cb(ev->fd, EV_READ, ev->arg);
            if (m_valid[i] && ev->flags & EV_WRITE &&
                m_evs[i].filter == EVFILT_WRITE)
                ev->cb(ev->fd, EV_WRITE, ev->arg);
            if (m_valid[i])
                ev->index = -1;
        }
    }
}