#include "ring.h"
#include "events.h"
-#if (defined(USE_KQUEUE_EVENTS) && defined(USE_DEVPOLL_EVENTS)) \
- || (defined(USE_KQUEUE_EVENTS) && defined(USE_EPOLL_EVENTS)) \
- || (defined(USE_KQUEUE_EVENTS) && defined(USE_SELECT_EVENTS)) \
- || (defined(USE_DEVPOLL_EVENTS) && defined(USE_EPOLL_EVENTS)) \
- || (defined(USE_DEVPOLL_EVENTS) && defined(USE_SELECT_EVENTS)) \
- || (defined(USE_EPOLL_EVENTS) && defined(USE_SELECT_EVENTS))
-#error "don't define multiple USE_KQUEUE/DEVPOLL/EPOLL/SELECT_EVENTS"
-#endif
-
-#if !defined(USE_KQUEUE_EVENTS) && !defined(USE_DEVPOLL_EVENTS) \
- && !defined(USE_EPOLL_EVENTS) && !defined(USE_SELECT_EVENTS)
-#error "define one of USE_KQUEUE/DEVPOLL/EPOLL/SELECT_EVENTS"
+#if !defined(EVENTS_STYLE)
+#error "must define EVENTS_STYLE"
#endif
/*
*/
#define EVENT_ALLOC_INCR 10
-#ifdef USE_SELECT_EVENTS
+#if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
typedef fd_set EVENT_MASK;
#define EVENT_MASK_BYTE_COUNT(mask) sizeof(*(mask))
* descriptor is closed, so our information could get out of sync with the
* kernel. But that will never happen, because we have to meticulously
* unregister a file descriptor before it is closed, to avoid errors on
- * systems that are built with USE_SELECT_EVENTS.
+ * systems that are built with EVENTS_STYLE == EVENTS_STYLE_SELECT.
*/
-#ifdef USE_KQUEUE_EVENTS
+#if (EVENTS_STYLE == EVENTS_STYLE_KQUEUE)
#include <sys/event.h>
/*
* Solaris /dev/poll does have a way to query if a specific descriptor is
* registered. However, we maintain a descriptor mask anyway because a) it
* avoids having to make an expensive system call to find out if something
- * is registered, b) some USE_MUMBLE_EVENTS implementations need a
+ * is registered, b) some EVENTS_STYLE_MUMBLE implementations need a
* descriptor bitmask anyway and c) we use the bitmask already to implement
* sanity checks.
*/
-#ifdef USE_DEVPOLL_EVENTS
+#if (EVENTS_STYLE == EVENTS_STYLE_DEVPOLL)
#include <sys/devpoll.h>
#include <fcntl.h>
* kernel. But that will never happen, because we have to meticulously
* unregister a file descriptor before it is closed, to avoid errors on
*/
-#ifdef USE_EPOLL_EVENTS
+#if (EVENTS_STYLE == EVENTS_STYLE_EPOLL)
#include <sys/epoll.h>
/*
#define EVENT_REG_DEL_OP(e, f, ev) EVENT_REG_FD_OP((e), (f), (ev), EPOLL_CTL_DEL)
#define EVENT_REG_DEL_READ(e, f) EVENT_REG_DEL_OP((e), (f), EPOLLIN)
#define EVENT_REG_DEL_WRITE(e, f) EVENT_REG_DEL_OP((e), (f), EPOLLOUT)
-#define EVENT_REG_DEL_TEXT "epoll_ctl(EPOLL_CTL_DEL)"
+#define EVENT_REG_DEL_TEXT "epoll_ctl EPOLL_CTL_DEL"
/*
* Macros to retrieve event buffers from the kernel; see event_loop().
* possible we extend these data structures on the fly. With select(2)
* based implementations we can only handle FD_SETSIZE open files.
*/
-#ifdef USE_SELECT_EVENTS
+#if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
if ((event_fdlimit = open_limit(FD_SETSIZE)) < 0)
msg_fatal("unable to determine open file limit");
#else
/*
* Initialize the I/O event request masks.
*/
-#ifdef USE_SELECT_EVENTS
+#if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
EVENT_MASK_ZERO(&event_rmask);
EVENT_MASK_ZERO(&event_wmask);
EVENT_MASK_ZERO(&event_xmask);
/*
* Initialize the I/O event request masks.
*/
-#ifndef USE_SELECT_EVENTS
+#if (EVENTS_STYLE != EVENTS_STYLE_SELECT)
EVENT_MASK_REALLOC(&event_rmask, new_slots);
EVENT_MASK_REALLOC(&event_wmask, new_slots);
EVENT_MASK_REALLOC(&event_xmask, new_slots);
EVENT_MASK_SET(fd, &event_rmask);
if (event_max_fd < fd)
event_max_fd = fd;
-#ifndef USE_SELECT_EVENTS
+#if (EVENTS_STYLE != EVENTS_STYLE_SELECT)
EVENT_REG_ADD_READ(err, fd);
if (err < 0)
msg_fatal("%s: %s: %m", myname, EVENT_REG_ADD_TEXT);
EVENT_MASK_SET(fd, &event_wmask);
if (event_max_fd < fd)
event_max_fd = fd;
-#ifndef USE_SELECT_EVENTS
+#if (EVENTS_STYLE != EVENTS_STYLE_SELECT)
EVENT_REG_ADD_WRITE(err, fd);
if (err < 0)
msg_fatal("%s: %s: %m", myname, EVENT_REG_ADD_TEXT);
*/
if (fd >= event_fdslots)
return;
-#ifndef USE_SELECT_EVENTS
+#if (EVENTS_STYLE != EVENTS_STYLE_SELECT)
#ifdef EVENT_REG_DEL_BOTH
/* XXX Can't seem to disable READ and WRITE events selectively. */
if (EVENT_MASK_ISSET(fd, &event_rmask)
msg_fatal("%s: %s: %m", myname, EVENT_REG_DEL_TEXT);
}
#endif /* EVENT_REG_DEL_BOTH */
-#endif /* USE_SELECT_EVENTS */
+#endif /* != EVENTS_STYLE_SELECT */
EVENT_MASK_CLR(fd, &event_xmask);
EVENT_MASK_CLR(fd, &event_rmask);
EVENT_MASK_CLR(fd, &event_wmask);
const char *myname = "event_loop";
static int nested;
-#ifdef USE_SELECT_EVENTS
+#if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
fd_set rmask;
fd_set wmask;
fd_set xmask;
struct timeval tv;
struct timeval *tvp;
+ int new_max_fd;
#else
EVENT_BUFFER event_buf[100];
* Negative delay means: wait until something happens. Zero delay means:
* poll. Positive delay means: wait at most this long.
*/
-#ifdef USE_SELECT_EVENTS
+#if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
if (select_delay < 0) {
tvp = 0;
} else {
* wanted. We do not change the event request masks. It is up to the
* application to determine when a read or write is complete.
*/
-#ifdef USE_SELECT_EVENTS
- for (fd = 0; event_count > 0 && fd <= event_max_fd; fd++) {
- if (FD_ISSET(fd, &event_xmask)) {
- /* In case event_fdtable is updated. */
- fdp = event_fdtable + fd;
- if (FD_ISSET(fd, &xmask)) {
- if (msg_verbose > 2)
- msg_info("%s: exception fd=%d act=0x%lx 0x%lx", myname,
+#if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
+ if (event_count > 0) {
+ for (new_max_fd = 0, fd = 0; fd <= event_max_fd; fd++) {
+ if (FD_ISSET(fd, &event_xmask)) {
+ new_max_fd = fd;
+ /* In case event_fdtable is updated. */
+ fdp = event_fdtable + fd;
+ if (FD_ISSET(fd, &xmask)) {
+ if (msg_verbose > 2)
+ msg_info("%s: exception fd=%d act=0x%lx 0x%lx", myname,
fd, (long) fdp->callback, (long) fdp->context);
- fdp->callback(EVENT_XCPT, fdp->context);
- } else if (FD_ISSET(fd, &wmask)) {
- if (msg_verbose > 2)
- msg_info("%s: write fd=%d act=0x%lx 0x%lx", myname,
+ fdp->callback(EVENT_XCPT, fdp->context);
+ } else if (FD_ISSET(fd, &wmask)) {
+ if (msg_verbose > 2)
+ msg_info("%s: write fd=%d act=0x%lx 0x%lx", myname,
fd, (long) fdp->callback, (long) fdp->context);
- fdp->callback(EVENT_WRITE, fdp->context);
- } else if (FD_ISSET(fd, &rmask)) {
- if (msg_verbose > 2)
- msg_info("%s: read fd=%d act=0x%lx 0x%lx", myname,
+ fdp->callback(EVENT_WRITE, fdp->context);
+ } else if (FD_ISSET(fd, &rmask)) {
+ if (msg_verbose > 2)
+ msg_info("%s: read fd=%d act=0x%lx 0x%lx", myname,
fd, (long) fdp->callback, (long) fdp->context);
- fdp->callback(EVENT_READ, fdp->context);
+ fdp->callback(EVENT_READ, fdp->context);
+ }
}
}
+ event_max_fd = new_max_fd;
}
#else
for (bp = event_buf; bp < event_buf + event_count; bp++) {
# if (defined(__FreeBSD_version) && __FreeBSD_version >= 410000) \
|| (defined(__NetBSD_Version__) && __NetBSD_Version__ >= 200000000) \
|| (defined(OpenBSD) && OpenBSD >= 200105) /* OpenBSD 2.9 */
-# define USE_KQUEUE_EVENTS
+# define EVENTS_STYLE EVENTS_STYLE_KQUEUE
# endif
#endif
#endif
#define USE_SYSV_POLL
#ifndef NO_DEVPOLL
-# define USE_DEVPOLL_EVENTS
+# define EVENTS_STYLE EVENTS_STYLE_DEVPOLL
#endif
/*
#endif
#define BROKEN_AI_PASSIVE_NULL_HOST
#define BROKEN_AI_NULL_SERVICE
+#define USE_SYSV_POLL
#endif
#ifdef AIX4
#endif
#define HAS_DEV_URANDOM /* introduced in 1.1 */
#ifndef NO_EPOLL
-# define USE_EPOLL_EVENTS /* introduced in 2.5 */
+# define EVENTS_STYLE EVENTS_STYLE_EPOLL /* introduced in 2.5 */
#endif
#define USE_SYSV_POLL
#endif
/*
* Defaults for systems without kqueue, /dev/poll or epoll support.
- * master/multi-server.c relies on this.
+ * master/multi-server.c and *qmgr/qmgr_transport.c depend on this.
*/
-#if !defined(USE_KQUEUE_EVENTS) && !defined(USE_DEVPOLL_EVENTS) \
- && !defined(USE_EPOLL_EVENTS)
-#define USE_SELECT_EVENTS
+#if !defined(EVENTS_STYLE)
+#define EVENTS_STYLE EVENTS_STYLE_SELECT
#endif
+#define EVENTS_STYLE_SELECT 1 /* Traditional BSD select */
+#define EVENTS_STYLE_KQUEUE 2 /* FreeBSD kqueue */
+#define EVENTS_STYLE_DEVPOLL 3 /* Solaris /dev/poll */
+#define EVENTS_STYLE_EPOLL 4 /* Linux epoll */
+
/*
* Defaults for all systems.
*/
* Safety. On some systems, ctype.h misbehaves with non-ASCII or negative
* characters. More importantly, Postfix uses the ISXXX() macros to ensure
* protocol compliance, so we have to rule out non-ASCII characters.
+ *
+ * XXX The (unsigned char) casts in isalnum() etc arguments are unnecessary
+ * because the ISASCII() guard already ensures that the values are
+ * non-negative; the casts are done anyway to shut up chatty compilers.
*/
#define ISASCII(c) isascii(_UCHAR_(c))
#define _UCHAR_(c) ((unsigned char)(c))
-#define ISALNUM(c) (ISASCII(c) && isalnum(c))
-#define ISALPHA(c) (ISASCII(c) && isalpha(c))
-#define ISCNTRL(c) (ISASCII(c) && iscntrl(c))
-#define ISDIGIT(c) (ISASCII(c) && isdigit(c))
-#define ISGRAPH(c) (ISASCII(c) && isgraph(c))
-#define ISLOWER(c) (ISASCII(c) && islower(c))
-#define ISPRINT(c) (ISASCII(c) && isprint(c))
-#define ISPUNCT(c) (ISASCII(c) && ispunct(c))
-#define ISSPACE(c) (ISASCII(c) && isspace(c))
-#define ISUPPER(c) (ISASCII(c) && isupper(c))
-#define TOLOWER(c) (ISUPPER(c) ? tolower(c) : (c))
-#define TOUPPER(c) (ISLOWER(c) ? toupper(c) : (c))
+#define ISALNUM(c) (ISASCII(c) && isalnum((unsigned char)(c)))
+#define ISALPHA(c) (ISASCII(c) && isalpha((unsigned char)(c)))
+#define ISCNTRL(c) (ISASCII(c) && iscntrl((unsigned char)(c)))
+#define ISDIGIT(c) (ISASCII(c) && isdigit((unsigned char)(c)))
+#define ISGRAPH(c) (ISASCII(c) && isgraph((unsigned char)(c)))
+#define ISLOWER(c) (ISASCII(c) && islower((unsigned char)(c)))
+#define ISPRINT(c) (ISASCII(c) && isprint((unsigned char)(c)))
+#define ISPUNCT(c) (ISASCII(c) && ispunct((unsigned char)(c)))
+#define ISSPACE(c) (ISASCII(c) && isspace((unsigned char)(c)))
+#define ISUPPER(c) (ISASCII(c) && isupper((unsigned char)(c)))
+#define TOLOWER(c) (ISUPPER(c) ? tolower((unsigned char)(c)) : (c))
+#define TOUPPER(c) (ISLOWER(c) ? toupper((unsigned char)(c)) : (c))
/*
* Scaffolding. I don't want to lose messages while the program is under