jabberd2  2.2.16
mio/mio_kqueue.h
Go to the documentation of this file.
00001 /* MIO backend for kqueue() */
00002 
00003 #ifdef HAVE_SYS_TYPES_H
00004 #include <sys/types.h>
00005 #endif
00006 #ifdef HAVE_SYS_EVENT_H
00007 #include <sys/event.h>
00008 #endif
00009 #ifdef HAVE_SYS_TIME_H
00010 #include <sys/time.h>
00011 #endif
00012 
00013 #define MIO_FUNCS \
00014  \
00015   mio_priv_t dbjdebug; \
00016     static mio_fd_t \
00017     _mio_alloc_fd(mio_t m, int fd) \
00018     { \
00019         struct kevent events[2]; \
00020         mio_priv_fd_t priv_fd; \
00021         dbjdebug = m; \
00022         priv_fd = malloc(sizeof(*priv_fd)); \
00023         memset(priv_fd, 0, sizeof(*priv_fd)); \
00024         priv_fd->mio_fd.fd = fd; \
00025         EV_SET(&events[0], fd, EVFILT_READ, EV_ADD|EV_DISABLE, 0, 0, priv_fd); \
00026         EV_SET(&events[1], fd, EVFILT_WRITE, EV_ADD|EV_DISABLE, 0, 0, priv_fd); \
00027         if (kevent(MIO(m)->kq, events, sizeof(events)/sizeof(events[0]), NULL, 0, NULL) == -1) { \
00028             mio_debug(ZONE,"error creating kevents on fd %d (%d)", fd, errno); \
00029         } \
00030         return (mio_fd_t)priv_fd; \
00031     } \
00032      \
00033     static void \
00034     _mio_free_fd(mio_t m, mio_fd_t mfd) \
00035     { \
00036       int i; \
00037       /* Unfortunately, the mio_impl.h api is a bit broken in that it \
00038        * assumes that we can defer free until the end of the current iteration. \
00039        * Unfortunately, with kqueue, a given fd may appear in the iteration loop \
00040        * more than once, so we need to both defer free and also clear out any \
00041        * other instances of the current fd in the return data.  Fortunately, the \
00042        * amount of data we ask for in each call to kevent is small and constant. \
00043        */ \
00044       for (i = 0; i < MIO(m)->nevents; i++) {  \
00045         if (MIO(m)->events[i].udata == mfd) { \
00046           MIO(m)->events[i].udata = &MIO(m)->dummy; \
00047         } \
00048         } \
00049       memset(mfd, 0x5a, sizeof(mio_priv_fd_t)); /* debugging only */ \
00050       free(mfd); \
00051     } \
00052                                                                         \
00053     static int \
00054     _mio_check(mio_t m, int timeout) \
00055     { \
00056       struct timespec ts; \
00057       int ret; \
00058       ts.tv_nsec = 0; \
00059       ts.tv_sec = timeout; \
00060       ret = kevent(MIO(m)->kq, NULL, 0, MIO(m)->events, sizeof(MIO(m)->events)/sizeof(MIO(m)->events[0]), &ts); \
00061       if (ret >= 0) \
00062         MIO(m)->nevents = ret; \
00063       return ret; \
00064     }
00065     
00066 #define MIO_FD_VARS
00067 
00068 #define MIO_VARS \
00069     int kq; \
00070     int nevents; \
00071     struct kevent events[32]; \
00072     struct mio_priv_fd_st dummy;
00073 
00074 #define MIO_INIT_VARS(m) \
00075     do {                                                                \
00076         MIO(m)->nevents = 0;                        \
00077         MIO(m)->dummy.type = type_CLOSED; \
00078         if ((MIO(m)->kq = kqueue()) == -1) {                            \
00079              mio_debug(ZONE,"internal error creating kqueue (%d)", errno); \
00080             return NULL;                                                \
00081         }                                                               \
00082     } while(0)
00083 
00084 #define MIO_FREE_VARS(m) close(MIO(m)->kq)
00085 
00086 #define MIO_ALLOC_FD(m, rfd) _mio_alloc_fd(m,rfd)
00087 #define MIO_CAN_FREE(m)         (MIO(m)->nevents == 0)
00088 #define MIO_FREE_FD(m, mfd)     _mio_free_fd(m, mfd)
00089 
00090 #define MIO_REMOVE_FD(m, mfd) \
00091     do { \
00092         struct kevent events[2]; \
00093         EV_SET(&events[0], mfd->mio_fd.fd, EVFILT_READ, EV_DELETE, 0, 0, mfd); \
00094         EV_SET(&events[1], mfd->mio_fd.fd, EVFILT_WRITE, EV_DELETE, 0, 0, mfd); \
00095         if (kevent(MIO(m)->kq, events, sizeof(events)/sizeof(events[0]), NULL, 0, NULL) == -1) { \
00096            mio_debug(ZONE,"error deleting kevents on fd %d (%d)", mfd->mio_fd.fd, errno); \
00097         } \
00098     } while (0)
00099 
00100 /*
00101  * This could be tweaked to be more efficient and only apply filter changes
00102  * once every loop, but that can be done if testing shows it to be helpful
00103  */
00104 #define MIO_SET_READ(m, mfd)    \
00105     do { \
00106         struct kevent changelist; \
00107         EV_SET(&changelist, mfd->mio_fd.fd, EVFILT_READ, EV_ENABLE, 0, 0, mfd); \
00108         if (kevent(MIO(m)->kq, &changelist, 1, NULL, 0, NULL) == -1) { \
00109            mio_debug(ZONE,"error setting kevent EVFILT_READ on fd %d (%d)", mfd->mio_fd.fd, errno); \
00110         } \
00111     } while (0)
00112 
00113 #define MIO_SET_WRITE(m, mfd) \
00114     do { \
00115         struct kevent changelist; \
00116         EV_SET(&changelist, mfd->mio_fd.fd, EVFILT_WRITE, EV_ENABLE, 0, 0, mfd); \
00117         if (kevent(MIO(m)->kq, &changelist, 1, NULL, 0, NULL) == -1) { \
00118            mio_debug(ZONE,"error setting kevent EVFILT_WRITE on fd %d (%d)", mfd->mio_fd.fd, errno); \
00119         } \
00120     } while (0)
00121 
00122 #define MIO_UNSET_READ(m, mfd)    \
00123     do { \
00124         struct kevent changelist; \
00125         EV_SET(&changelist, mfd->mio_fd.fd, EVFILT_READ, EV_DISABLE, 0, 0, mfd); \
00126         if (kevent(MIO(m)->kq, &changelist, 1, NULL, 0, NULL) == -1) { \
00127            mio_debug(ZONE,"error setting kevent EVFILT_READ on fd %d (%d)", mfd->mio_fd.fd, errno); \
00128         } \
00129     } while (0)
00130 
00131 #define MIO_UNSET_WRITE(m, mfd) \
00132     do { \
00133         struct kevent changelist; \
00134         EV_SET(&changelist, mfd->mio_fd.fd, EVFILT_WRITE, EV_DISABLE, 0, 0, mfd); \
00135         if (kevent(MIO(m)->kq, &changelist, 1, NULL, 0, NULL) == -1) { \
00136            mio_debug(ZONE,"error setting kevent EVFILT_WRITE on fd %d (%d)", mfd->mio_fd.fd, errno); \
00137         } \
00138     } while (0)
00139 
00140 #define MIO_INIT_ITERATOR(iter) \
00141     int iter;
00142 
00143 #define MIO_ITERATE_RESULTS(m, retval, iter) \
00144     for(iter = 0; (iter < retval) || ((MIO(m)->nevents = 0)); iter++)
00145 
00146 #define MIO_CAN_READ(m, iter)  (MIO((m))->events[(iter)].filter == EVFILT_READ)
00147 #define MIO_CAN_WRITE(m, iter) (MIO((m))->events[(iter)].filter == EVFILT_WRITE)
00148 
00149 #define MIO_ITERATOR_FD(m, iter) ((mio_fd_t)(MIO(m)->events[(iter)].udata))
00150 
00151 #define MIO_CHECK(m, t) _mio_check(m, t)