jabberd2
2.2.16
|
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)