jabberd2  2.3.6
mio_kqueue.h
Go to the documentation of this file.
1 /* MIO backend for kqueue() */
2 
3 #ifdef HAVE_SYS_TYPES_H
4 #include <sys/types.h>
5 #endif
6 #ifdef HAVE_SYS_EVENT_H
7 #include <sys/event.h>
8 #endif
9 #ifdef HAVE_SYS_TIME_H
10 #include <sys/time.h>
11 #endif
12 
13 #define MIO_FUNCS \
14  \
15  mio_priv_t dbjdebug; \
16  static mio_fd_t \
17  _mio_alloc_fd(mio_t m, int fd) \
18  { \
19  struct kevent events[2]; \
20  mio_priv_fd_t priv_fd; \
21  dbjdebug = m; \
22  priv_fd = malloc(sizeof(*priv_fd)); \
23  memset(priv_fd, 0, sizeof(*priv_fd)); \
24  priv_fd->mio_fd.fd = fd; \
25  EV_SET(&events[0], fd, EVFILT_READ, EV_ADD|EV_DISABLE, 0, 0, priv_fd); \
26  EV_SET(&events[1], fd, EVFILT_WRITE, EV_ADD|EV_DISABLE, 0, 0, priv_fd); \
27  if (kevent(MIO(m)->kq, events, sizeof(events)/sizeof(events[0]), NULL, 0, NULL) == -1) { \
28  mio_debug(ZONE,"error creating kevents on fd %d (%d)", fd, errno); \
29  } \
30  return (mio_fd_t)priv_fd; \
31  } \
32  \
33  static void \
34  _mio_free_fd(mio_t m, mio_fd_t mfd) \
35  { \
36  int i; \
37  /* Unfortunately, the mio_impl.h api is a bit broken in that it \
38  * assumes that we can defer free until the end of the current iteration. \
39  * Unfortunately, with kqueue, a given fd may appear in the iteration loop \
40  * more than once, so we need to both defer free and also clear out any \
41  * other instances of the current fd in the return data. Fortunately, the \
42  * amount of data we ask for in each call to kevent is small and constant. \
43  */ \
44  for (i = 0; i < MIO(m)->nevents; i++) { \
45  if (MIO(m)->events[i].udata == mfd) { \
46  MIO(m)->events[i].udata = &MIO(m)->dummy; \
47  } \
48  } \
49  memset(mfd, 0x5a, sizeof(mio_priv_fd_t)); /* debugging only */ \
50  free(mfd); \
51  } \
52  \
53  static int \
54  _mio_check(mio_t m, int timeout) \
55  { \
56  struct timespec ts; \
57  int ret; \
58  ts.tv_nsec = 0; \
59  ts.tv_sec = timeout; \
60  ret = kevent(MIO(m)->kq, NULL, 0, MIO(m)->events, sizeof(MIO(m)->events)/sizeof(MIO(m)->events[0]), &ts); \
61  if (ret >= 0) \
62  MIO(m)->nevents = ret; \
63  return ret; \
64  }
65 
66 #define MIO_FD_VARS
67 
68 #define MIO_VARS \
69  int kq; \
70  int nevents; \
71  struct kevent events[32]; \
72  struct mio_priv_fd_st dummy;
73 
74 #define MIO_INIT_VARS(m) \
75  do { \
76  MIO(m)->nevents = 0; \
77  MIO(m)->dummy.type = type_CLOSED; \
78  if ((MIO(m)->kq = kqueue()) == -1) { \
79  mio_debug(ZONE,"internal error creating kqueue (%d)", errno); \
80  return NULL; \
81  } \
82  } while(0)
83 
84 #define MIO_FREE_VARS(m) close(MIO(m)->kq)
85 
86 #define MIO_ALLOC_FD(m, rfd) _mio_alloc_fd(m,rfd)
87 #define MIO_CAN_FREE(m) (MIO(m)->nevents == 0)
88 #define MIO_FREE_FD(m, mfd) _mio_free_fd(m, mfd)
89 
90 #define MIO_REMOVE_FD(m, mfd) \
91  do { \
92  struct kevent events[2]; \
93  EV_SET(&events[0], mfd->mio_fd.fd, EVFILT_READ, EV_DELETE, 0, 0, mfd); \
94  EV_SET(&events[1], mfd->mio_fd.fd, EVFILT_WRITE, EV_DELETE, 0, 0, mfd); \
95  if (kevent(MIO(m)->kq, events, sizeof(events)/sizeof(events[0]), NULL, 0, NULL) == -1) { \
96  mio_debug(ZONE,"error deleting kevents on fd %d (%d)", mfd->mio_fd.fd, errno); \
97  } \
98  } while (0)
99 
100 /*
101  * This could be tweaked to be more efficient and only apply filter changes
102  * once every loop, but that can be done if testing shows it to be helpful
103  */
104 #define MIO_SET_READ(m, mfd) \
105  do { \
106  struct kevent changelist; \
107  EV_SET(&changelist, mfd->mio_fd.fd, EVFILT_READ, EV_ENABLE, 0, 0, mfd); \
108  if (kevent(MIO(m)->kq, &changelist, 1, NULL, 0, NULL) == -1) { \
109  mio_debug(ZONE,"error setting kevent EVFILT_READ on fd %d (%d)", mfd->mio_fd.fd, errno); \
110  } \
111  } while (0)
112 
113 #define MIO_SET_WRITE(m, mfd) \
114  do { \
115  struct kevent changelist; \
116  EV_SET(&changelist, mfd->mio_fd.fd, EVFILT_WRITE, EV_ENABLE, 0, 0, mfd); \
117  if (kevent(MIO(m)->kq, &changelist, 1, NULL, 0, NULL) == -1) { \
118  mio_debug(ZONE,"error setting kevent EVFILT_WRITE on fd %d (%d)", mfd->mio_fd.fd, errno); \
119  } \
120  } while (0)
121 
122 #define MIO_UNSET_READ(m, mfd) \
123  do { \
124  struct kevent changelist; \
125  EV_SET(&changelist, mfd->mio_fd.fd, EVFILT_READ, EV_DISABLE, 0, 0, mfd); \
126  if (kevent(MIO(m)->kq, &changelist, 1, NULL, 0, NULL) == -1) { \
127  mio_debug(ZONE,"error setting kevent EVFILT_READ on fd %d (%d)", mfd->mio_fd.fd, errno); \
128  } \
129  } while (0)
130 
131 #define MIO_UNSET_WRITE(m, mfd) \
132  do { \
133  struct kevent changelist; \
134  EV_SET(&changelist, mfd->mio_fd.fd, EVFILT_WRITE, EV_DISABLE, 0, 0, mfd); \
135  if (kevent(MIO(m)->kq, &changelist, 1, NULL, 0, NULL) == -1) { \
136  mio_debug(ZONE,"error setting kevent EVFILT_WRITE on fd %d (%d)", mfd->mio_fd.fd, errno); \
137  } \
138  } while (0)
139 
140 #define MIO_INIT_ITERATOR(iter) \
141  int iter;
142 
143 #define MIO_ITERATE_RESULTS(m, retval, iter) \
144  for(iter = 0; (iter < retval) || ((MIO(m)->nevents = 0)); iter++)
145 
146 #define MIO_CAN_READ(m, iter) (MIO((m))->events[(iter)].filter == EVFILT_READ)
147 #define MIO_CAN_WRITE(m, iter) (MIO((m))->events[(iter)].filter == EVFILT_WRITE)
148 
149 #define MIO_ITERATOR_FD(m, iter) ((mio_fd_t)(MIO(m)->events[(iter)].udata))
150 
151 #define MIO_CHECK(m, t) _mio_check(m, t)