+/*
+ * NOTE: naming convention for macros:
+ *
+ * - SLAP_SOCK_* and SLAP_EVENT_* for public interface that deals
+ * with file descriptors and events respectively
+ *
+ * - SLAP_<type>_* for private interface; type by now is one of
+ * EPOLL, DEVPOLL, SELECT
+ *
+ * private interface should not be used in the code.
+ */
+#if defined(HAVE_EPOLL)
+/***************************************
+ * Use epoll infrastructure - epoll(4) *
+ ***************************************/
+# define SLAP_EVENT_FNAME "epoll"
+# define SLAP_EVENTS_ARE_INDEXED 0
+# define SLAP_EPOLL_SOCK_IX(s) (slap_daemon.sd_index[(s)])
+# define SLAP_EPOLL_SOCK_EP(s) (slap_daemon.sd_epolls[SLAP_EPOLL_SOCK_IX(s)])
+# define SLAP_EPOLL_SOCK_EV(s) (SLAP_EPOLL_SOCK_EP(s).events)
+# define SLAP_SOCK_IS_ACTIVE(s) (SLAP_EPOLL_SOCK_IX(s) != -1)
+# define SLAP_SOCK_NOT_ACTIVE(s) (SLAP_EPOLL_SOCK_IX(s) == -1)
+# define SLAP_EPOLL_SOCK_IS_SET(s, mode) (SLAP_EPOLL_SOCK_EV(s) & (mode))
+
+# define SLAP_SOCK_IS_READ(s) SLAP_EPOLL_SOCK_IS_SET((s), EPOLLIN)
+# define SLAP_SOCK_IS_WRITE(s) SLAP_EPOLL_SOCK_IS_SET((s), EPOLLOUT)
+
+# define SLAP_EPOLL_SOCK_SET(s, mode) do { \
+ if ( (SLAP_EPOLL_SOCK_EV(s) & (mode)) != (mode) ) { \
+ SLAP_EPOLL_SOCK_EV(s) |= (mode); \
+ epoll_ctl( slap_daemon.sd_epfd, EPOLL_CTL_MOD, (s), \
+ &SLAP_EPOLL_SOCK_EP(s) ); \
+ } \
+} while (0)
+
+# define SLAP_EPOLL_SOCK_CLR(s, mode) do { \
+ if ( (SLAP_EPOLL_SOCK_EV(s) & (mode)) ) { \
+ SLAP_EPOLL_SOCK_EV(s) &= ~(mode); \
+ epoll_ctl( slap_daemon.sd_epfd, EPOLL_CTL_MOD, s, \
+ &SLAP_EPOLL_SOCK_EP(s) ); \
+ } \
+} while (0)
+
+# define SLAP_SOCK_SET_READ(s) SLAP_EPOLL_SOCK_SET(s, EPOLLIN)
+# define SLAP_SOCK_SET_WRITE(s) SLAP_EPOLL_SOCK_SET(s, EPOLLOUT)
+
+# define SLAP_SOCK_CLR_READ(s) SLAP_EPOLL_SOCK_CLR((s), EPOLLIN)
+# define SLAP_SOCK_CLR_WRITE(s) SLAP_EPOLL_SOCK_CLR((s), EPOLLOUT)
+
+# ifdef SLAP_LIGHTWEIGHT_DISPATCHER
+# define SLAP_SOCK_SET_SUSPEND(s) \
+ ( slap_daemon.sd_suspend[SLAP_EPOLL_SOCK_IX(s)] = 1 )
+# define SLAP_SOCK_CLR_SUSPEND(s) \
+ ( slap_daemon.sd_suspend[SLAP_EPOLL_SOCK_IX(s)] = 0 )
+# define SLAP_SOCK_IS_SUSPEND(s) \
+ ( slap_daemon.sd_suspend[SLAP_EPOLL_SOCK_IX(s)] == 1 )
+# endif /* SLAP_LIGHTWEIGHT_DISPATCHER */
+
+# define SLAP_EPOLL_EVENT_CLR(i, mode) (revents[(i)].events &= ~(mode))
+
+# define SLAP_EVENT_MAX slap_daemon.sd_nfds
+
+/* If a Listener address is provided, store that as the epoll data.
+ * Otherwise, store the address of this socket's slot in the
+ * index array. If we can't do this add, the system is out of
+ * resources and we need to shutdown.
+ */
+# define SLAP_SOCK_ADD(s, l) do { \
+ int rc; \
+ SLAP_EPOLL_SOCK_IX((s)) = slap_daemon.sd_nfds; \
+ SLAP_EPOLL_SOCK_EP((s)).data.ptr = (l) ? (l) : (void *)(&SLAP_EPOLL_SOCK_IX(s)); \
+ SLAP_EPOLL_SOCK_EV((s)) = EPOLLIN; \
+ rc = epoll_ctl(slap_daemon.sd_epfd, EPOLL_CTL_ADD, \
+ (s), &SLAP_EPOLL_SOCK_EP((s))); \
+ if ( rc == 0 ) { \
+ slap_daemon.sd_nfds++; \
+ } else { \
+ Debug( LDAP_DEBUG_ANY, \
+ "daemon: epoll_ctl(ADD,fd=%d) failed, errno=%d, shutting down\n", \
+ s, errno, 0 ); \
+ slapd_shutdown = 2; \
+ } \
+} while (0)
+
+# define SLAP_EPOLL_EV_LISTENER(ptr) \
+ (((int *)(ptr) >= slap_daemon.sd_index && \
+ (int *)(ptr) <= &slap_daemon.sd_index[dtblsize]) ? 0 : 1 )
+
+# define SLAP_EPOLL_EV_PTRFD(ptr) (SLAP_EPOLL_EV_LISTENER(ptr) ? \
+ ((Listener *)ptr)->sl_sd : (int *)(ptr) - slap_daemon.sd_index)
+
+# define SLAP_SOCK_DEL(s) do { \
+ int fd, rc, index = SLAP_EPOLL_SOCK_IX((s)); \
+ if ( index < 0 ) break; \
+ rc = epoll_ctl(slap_daemon.sd_epfd, EPOLL_CTL_DEL, \
+ (s), &SLAP_EPOLL_SOCK_EP((s))); \
+ slap_daemon.sd_epolls[index] = \
+ slap_daemon.sd_epolls[slap_daemon.sd_nfds-1]; \
+ fd = SLAP_EPOLL_EV_PTRFD(slap_daemon.sd_epolls[index].data.ptr); \
+ slap_daemon.sd_index[fd] = index; \
+ slap_daemon.sd_index[(s)] = -1; \
+ slap_daemon.sd_nfds--; \
+} while (0)
+
+# define SLAP_EVENT_CLR_READ(i) SLAP_EPOLL_EVENT_CLR((i), EPOLLIN)
+# define SLAP_EVENT_CLR_WRITE(i) SLAP_EPOLL_EVENT_CLR((i), EPOLLOUT)
+
+# define SLAP_EPOLL_EVENT_CHK(i, mode) (revents[(i)].events & mode)
+
+# define SLAP_EVENT_IS_READ(i) SLAP_EPOLL_EVENT_CHK((i), EPOLLIN)
+# define SLAP_EVENT_IS_WRITE(i) SLAP_EPOLL_EVENT_CHK((i), EPOLLOUT)
+# define SLAP_EVENT_IS_LISTENER(i) SLAP_EPOLL_EV_LISTENER(revents[(i)].data.ptr)
+# define SLAP_EVENT_LISTENER(i) ((Listener *)(revents[(i)].data.ptr))
+
+# define SLAP_EVENT_FD(i) SLAP_EPOLL_EV_PTRFD(revents[(i)].data.ptr)
+
+# define SLAP_SOCK_INIT do { \
+ slap_daemon.sd_epolls = ch_calloc(1, \
+ ( sizeof(struct epoll_event) * 2 \
+ + sizeof(int) ) * dtblsize * 2); \
+ slap_daemon.sd_index = (int *)&slap_daemon.sd_epolls[ 2 * dtblsize ]; \
+ slap_daemon.sd_epfd = epoll_create( dtblsize ); \
+ for ( i = 0; i < dtblsize; i++ ) slap_daemon.sd_index[i] = -1; \
+} while (0)
+
+# define SLAP_SOCK_DESTROY do { \
+ if ( slap_daemon.sd_epolls != NULL ) { \
+ ch_free( slap_daemon.sd_epolls ); \
+ slap_daemon.sd_epolls = NULL; \
+ slap_daemon.sd_index = NULL; \
+ close( slap_daemon.sd_epfd ); \
+ } \
+} while ( 0 )
+
+# define SLAP_EVENT_DECL struct epoll_event *revents
+
+# define SLAP_EVENT_INIT do { \
+ revents = slap_daemon.sd_epolls + dtblsize; \
+} while (0)
+
+# define SLAP_EVENT_WAIT(tvp, nsp) do { \
+ *(nsp) = epoll_wait( slap_daemon.sd_epfd, revents, \
+ dtblsize, (tvp) ? (tvp)->tv_sec * 1000 : -1 ); \
+} while (0)
+
+#elif defined(SLAP_X_DEVPOLL) && defined(HAVE_DEVPOLL)
+
+/*************************************************************
+ * Use Solaris' (>= 2.7) /dev/poll infrastructure - poll(7d) *
+ *************************************************************/
+# define SLAP_EVENT_FNAME "/dev/poll"
+# define SLAP_EVENTS_ARE_INDEXED 0
+/*
+ * - sd_index is used much like with epoll()
+ * - sd_l is maintained as an array containing the address
+ * of the listener; the index is the fd itself
+ * - sd_pollfd is used to keep track of what data has been
+ * registered in /dev/poll
+ */
+# define SLAP_DEVPOLL_SOCK_IX(s) (slap_daemon.sd_index[(s)])
+# define SLAP_DEVPOLL_SOCK_LX(s) (slap_daemon.sd_l[(s)])
+# define SLAP_DEVPOLL_SOCK_EP(s) (slap_daemon.sd_pollfd[SLAP_DEVPOLL_SOCK_IX((s))])
+# define SLAP_DEVPOLL_SOCK_FD(s) (SLAP_DEVPOLL_SOCK_EP((s)).fd)
+# define SLAP_DEVPOLL_SOCK_EV(s) (SLAP_DEVPOLL_SOCK_EP((s)).events)
+# define SLAP_SOCK_IS_ACTIVE(s) (SLAP_DEVPOLL_SOCK_IX((s)) != -1)
+# define SLAP_SOCK_NOT_ACTIVE(s) (SLAP_DEVPOLL_SOCK_IX((s)) == -1)
+# define SLAP_SOCK_IS_SET(s, mode) (SLAP_DEVPOLL_SOCK_EV((s)) & (mode))
+
+# define SLAP_SOCK_IS_READ(s) SLAP_SOCK_IS_SET((s), POLLIN)
+# define SLAP_SOCK_IS_WRITE(s) SLAP_SOCK_IS_SET((s), POLLOUT)
+
+/* as far as I understand, any time we need to communicate with the kernel
+ * about the number and/or properties of a file descriptor we need it to
+ * wait for, we have to rewrite the whole set */
+# define SLAP_DEVPOLL_WRITE_POLLFD(s, pfd, n, what, shdn) do { \
+ int rc; \
+ size_t size = (n) * sizeof( struct pollfd ); \
+ /* FIXME: use pwrite? */ \
+ rc = write( slap_daemon.sd_dpfd, (pfd), size ); \
+ if ( rc != size ) { \
+ Debug( LDAP_DEBUG_ANY, "daemon: " SLAP_EVENT_FNAME ": " \
+ "%s fd=%d failed errno=%d\n", \
+ (what), (s), errno ); \
+ if ( (shdn) ) { \
+ slapd_shutdown = 2; \
+ } \
+ } \
+} while (0)
+
+# define SLAP_DEVPOLL_SOCK_SET(s, mode) do { \
+ Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_SET_%s(%d)=%d\n", \
+ (mode) == POLLIN ? "READ" : "WRITE", (s), \
+ ( (SLAP_DEVPOLL_SOCK_EV((s)) & (mode)) != (mode) ) ); \
+ if ( (SLAP_DEVPOLL_SOCK_EV((s)) & (mode)) != (mode) ) { \
+ struct pollfd pfd; \
+ SLAP_DEVPOLL_SOCK_EV((s)) |= (mode); \
+ pfd.fd = SLAP_DEVPOLL_SOCK_FD((s)); \
+ pfd.events = /* (mode) */ SLAP_DEVPOLL_SOCK_EV((s)); \
+ SLAP_DEVPOLL_WRITE_POLLFD((s), &pfd, 1, "SET", 0); \
+ } \
+} while (0)
+
+# define SLAP_DEVPOLL_SOCK_CLR(s, mode) do { \
+ Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_CLR_%s(%d)=%d\n", \
+ (mode) == POLLIN ? "READ" : "WRITE", (s), \
+ ( (SLAP_DEVPOLL_SOCK_EV((s)) & (mode)) == (mode) ) ); \
+ if ((SLAP_DEVPOLL_SOCK_EV((s)) & (mode)) == (mode) ) { \
+ struct pollfd pfd[2]; \
+ SLAP_DEVPOLL_SOCK_EV((s)) &= ~(mode); \
+ pfd[0].fd = SLAP_DEVPOLL_SOCK_FD((s)); \
+ pfd[0].events = POLLREMOVE; \
+ pfd[1] = SLAP_DEVPOLL_SOCK_EP((s)); \
+ SLAP_DEVPOLL_WRITE_POLLFD((s), &pfd[0], 2, "CLR", 0); \
+ } \
+} while (0)
+
+# define SLAP_SOCK_SET_READ(s) SLAP_DEVPOLL_SOCK_SET(s, POLLIN)
+# define SLAP_SOCK_SET_WRITE(s) SLAP_DEVPOLL_SOCK_SET(s, POLLOUT)
+
+# define SLAP_SOCK_CLR_READ(s) SLAP_DEVPOLL_SOCK_CLR((s), POLLIN)
+# define SLAP_SOCK_CLR_WRITE(s) SLAP_DEVPOLL_SOCK_CLR((s), POLLOUT)
+
+# ifdef SLAP_LIGHTWEIGHT_DISPATCHER
+# define SLAP_SOCK_SET_SUSPEND(s) \
+ ( slap_daemon.sd_suspend[SLAP_DEVPOLL_SOCK_IX((s))] = 1 )
+# define SLAP_SOCK_CLR_SUSPEND(s) \
+ ( slap_daemon.sd_suspend[SLAP_DEVPOLL_SOCK_IX((s))] = 0 )
+# define SLAP_SOCK_IS_SUSPEND(s) \
+ ( slap_daemon.sd_suspend[SLAP_DEVPOLL_SOCK_IX((s))] == 1 )
+# endif /* SLAP_LIGHTWEIGHT_DISPATCHER */
+
+# define SLAP_DEVPOLL_EVENT_CLR(i, mode) (revents[(i)].events &= ~(mode))
+
+# define SLAP_EVENT_MAX slap_daemon.sd_nfds
+
+/* If a Listener address is provided, store that in the sd_l array.
+ * If we can't do this add, the system is out of resources and we
+ * need to shutdown.
+ */
+# define SLAP_SOCK_ADD(s, l) do { \
+ Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_ADD(%d, %p)\n", (s), (l), 0 ); \
+ SLAP_DEVPOLL_SOCK_IX((s)) = slap_daemon.sd_nfds; \
+ SLAP_DEVPOLL_SOCK_LX((s)) = (l); \
+ SLAP_DEVPOLL_SOCK_FD((s)) = (s); \
+ SLAP_DEVPOLL_SOCK_EV((s)) = POLLIN; \
+ SLAP_DEVPOLL_WRITE_POLLFD((s), &SLAP_DEVPOLL_SOCK_EP((s)), 1, "ADD", 1); \
+ slap_daemon.sd_nfds++; \
+} while (0)
+
+# define SLAP_DEVPOLL_EV_LISTENER(ptr) ((ptr) != NULL)
+
+# define SLAP_SOCK_DEL(s) do { \
+ int fd, index = SLAP_DEVPOLL_SOCK_IX((s)); \
+ Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_DEL(%d)\n", (s), 0, 0 ); \
+ if ( index < 0 ) break; \
+ if ( index < slap_daemon.sd_nfds - 1 ) { \
+ struct pollfd pfd = slap_daemon.sd_pollfd[index]; \
+ fd = slap_daemon.sd_pollfd[slap_daemon.sd_nfds - 1].fd; \
+ slap_daemon.sd_pollfd[index] = slap_daemon.sd_pollfd[slap_daemon.sd_nfds - 1]; \
+ slap_daemon.sd_pollfd[slap_daemon.sd_nfds - 1] = pfd; \
+ slap_daemon.sd_index[fd] = index; \
+ } \
+ slap_daemon.sd_index[(s)] = -1; \
+ slap_daemon.sd_pollfd[slap_daemon.sd_nfds - 1].events = POLLREMOVE; \
+ SLAP_DEVPOLL_WRITE_POLLFD((s), &slap_daemon.sd_pollfd[slap_daemon.sd_nfds - 1], 1, "DEL", 0); \
+ slap_daemon.sd_pollfd[slap_daemon.sd_nfds - 1].events = 0; \
+ slap_daemon.sd_nfds--; \
+} while (0)
+
+# define SLAP_EVENT_CLR_READ(i) SLAP_DEVPOLL_EVENT_CLR((i), POLLIN)
+# define SLAP_EVENT_CLR_WRITE(i) SLAP_DEVPOLL_EVENT_CLR((i), POLLOUT)
+
+# define SLAP_DEVPOLL_EVENT_CHK(i, mode) (revents[(i)].events & (mode))
+
+# define SLAP_EVENT_FD(i) (revents[(i)].fd)
+
+# define SLAP_EVENT_IS_READ(i) SLAP_DEVPOLL_EVENT_CHK((i), POLLIN)
+# define SLAP_EVENT_IS_WRITE(i) SLAP_DEVPOLL_EVENT_CHK((i), POLLOUT)
+# define SLAP_EVENT_IS_LISTENER(i) SLAP_DEVPOLL_EV_LISTENER(SLAP_DEVPOLL_SOCK_LX(SLAP_EVENT_FD((i))))
+# define SLAP_EVENT_LISTENER(i) SLAP_DEVPOLL_SOCK_LX(SLAP_EVENT_FD((i)))
+
+# define SLAP_SOCK_INIT do { \
+ slap_daemon.sd_pollfd = ch_calloc( 1, \
+ ( sizeof(struct pollfd) * 2 \
+ + sizeof( int ) \
+ + sizeof( Listener * ) ) * dtblsize ); \
+ slap_daemon.sd_index = (int *)&slap_daemon.sd_pollfd[ 2 * dtblsize ]; \
+ slap_daemon.sd_l = (Listener **)&slap_daemon.sd_index[ dtblsize ]; \
+ slap_daemon.sd_dpfd = open( SLAP_EVENT_FNAME, O_RDWR ); \
+ if ( slap_daemon.sd_dpfd == -1 ) { \
+ Debug( LDAP_DEBUG_ANY, "daemon: " SLAP_EVENT_FNAME ": " \
+ "open(\"" SLAP_EVENT_FNAME "\") failed errno=%d\n", \
+ errno, 0, 0 ); \
+ SLAP_SOCK_DESTROY; \
+ return -1; \
+ } \
+ for ( i = 0; i < dtblsize; i++ ) { \
+ slap_daemon.sd_pollfd[i].fd = -1; \
+ slap_daemon.sd_index[i] = -1; \
+ } \
+} while (0)
+
+# define SLAP_SOCK_DESTROY do { \
+ if ( slap_daemon.sd_pollfd != NULL ) { \
+ ch_free( slap_daemon.sd_pollfd ); \
+ slap_daemon.sd_pollfd = NULL; \
+ slap_daemon.sd_index = NULL; \
+ slap_daemon.sd_l = NULL; \
+ close( slap_daemon.sd_dpfd ); \
+ } \
+} while ( 0 )
+
+# define SLAP_EVENT_DECL struct pollfd *revents
+
+# define SLAP_EVENT_INIT do { \
+ revents = &slap_daemon.sd_pollfd[ dtblsize ]; \
+} while (0)
+
+# define SLAP_EVENT_WAIT(tvp, nsp) do { \
+ struct dvpoll sd_dvpoll; \
+ sd_dvpoll.dp_timeout = (tvp) ? (tvp)->tv_sec * 1000 : -1; \
+ sd_dvpoll.dp_nfds = dtblsize; \
+ sd_dvpoll.dp_fds = revents; \
+ *(nsp) = ioctl( slap_daemon.sd_dpfd, DP_POLL, &sd_dvpoll ); \
+} while (0)
+
+#else /* ! epoll && ! /dev/poll */
+
+/**************************************
+ * Use select system call - select(2) *
+ **************************************/
+# define SLAP_EVENT_FNAME "select"
+/* select */
+
+# define SLAP_EVENTS_ARE_INDEXED 1
+# define SLAP_EVENT_DECL fd_set readfds, writefds
+
+# define SLAP_EVENT_INIT do { \
+ AC_MEMCPY( &readfds, &slap_daemon.sd_readers, sizeof(fd_set) ); \
+ if ( nwriters ) { \
+ AC_MEMCPY( &writefds, &slap_daemon.sd_writers, sizeof(fd_set) ); \
+ } else { \
+ FD_ZERO( &writefds ); \
+ } \
+} while (0)
+
+# ifdef FD_SETSIZE
+# define SLAP_SELECT_CHK_SETSIZE do { \
+ if (dtblsize > FD_SETSIZE) dtblsize = FD_SETSIZE; \
+} while (0)
+# else /* ! FD_SETSIZE */
+# define SLAP_SELECT_CHK_SETSIZE do { ; } while (0)
+# endif /* ! FD_SETSIZE */
+
+# define SLAP_SOCK_INIT do { \
+ SLAP_SELECT_CHK_SETSIZE; \
+ FD_ZERO(&slap_daemon.sd_actives); \
+ FD_ZERO(&slap_daemon.sd_readers); \
+ FD_ZERO(&slap_daemon.sd_writers); \
+} while (0)
+
+# define SLAP_SOCK_DESTROY
+
+# define SLAP_SOCK_IS_ACTIVE(fd) FD_ISSET((fd), &slap_daemon.sd_actives)
+# define SLAP_SOCK_IS_READ(fd) FD_ISSET((fd), &slap_daemon.sd_readers)
+# define SLAP_SOCK_IS_WRITE(fd) FD_ISSET((fd), &slap_daemon.sd_writers)
+
+# define SLAP_SOCK_NOT_ACTIVE(fd) (!SLAP_SOCK_IS_ACTIVE(fd) && \
+ !SLAP_SOCK_IS_READ(fd) && !SLAP_SOCK_IS_WRITE(fd))
+
+# ifdef HAVE_WINSOCK
+# define SLAP_SOCK_SET_READ(fd) do { \
+ if (!SLAP_SOCK_IS_READ(fd)) { FD_SET((fd), &slap_daemon.sd_readers); } \
+} while (0)
+# define SLAP_SOCK_SET_WRITE(fd) do { \
+ if (!SLAP_SOCK_IS_WRITE(fd)) { FD_SET((fd), &slap_daemon.sd_writers); } \
+} while (0)
+
+# define SLAP_SELECT_ADDTEST(s)
+# define SLAP_EVENT_MAX dtblsize
+# else /* ! HAVE_WINSOCK */
+# define SLAP_SOCK_SET_READ(fd) FD_SET((fd), &slap_daemon.sd_readers)
+# define SLAP_SOCK_SET_WRITE(fd) FD_SET((fd), &slap_daemon.sd_writers)
+
+# define SLAP_EVENT_MAX slap_daemon.sd_nfds
+# define SLAP_SELECT_ADDTEST(s) do { \
+ if ((s) >= slap_daemon.sd_nfds) slap_daemon.sd_nfds = (s)+1; \
+} while (0)
+# endif /* ! HAVE_WINSOCK */
+
+# define SLAP_SOCK_CLR_READ(fd) FD_CLR((fd), &slap_daemon.sd_readers)
+# define SLAP_SOCK_CLR_WRITE(fd) FD_CLR((fd), &slap_daemon.sd_writers)
+
+# define SLAP_SOCK_ADD(s, l) do { \
+ SLAP_SELECT_ADDTEST((s)); \
+ FD_SET((s), &slap_daemon.sd_actives); \
+ FD_SET((s), &slap_daemon.sd_readers); \
+} while (0)
+
+# define SLAP_SOCK_DEL(s) do { \
+ FD_CLR((s), &slap_daemon.sd_actives); \
+ FD_CLR((s), &slap_daemon.sd_readers); \
+ FD_CLR((s), &slap_daemon.sd_writers); \
+} while (0)
+
+# define SLAP_EVENT_IS_READ(fd) FD_ISSET((fd), &readfds)
+# define SLAP_EVENT_IS_WRITE(fd) FD_ISSET((fd), &writefds)
+
+# define SLAP_EVENT_CLR_READ(fd) FD_CLR((fd), &readfds)
+# define SLAP_EVENT_CLR_WRITE(fd) FD_CLR((fd), &writefds)
+
+# define SLAP_EVENT_WAIT(tvp, nsp) do { \
+ *(nsp) = select( SLAP_EVENT_MAX, &readfds, \
+ nwriters > 0 ? &writefds : NULL, NULL, (tvp) ); \
+} while (0)
+#endif /* ! epoll && ! /dev/poll */