diff --git a/postfix/HISTORY b/postfix/HISTORY index ea1ffb2be..0aa87e917 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -13248,6 +13248,13 @@ Apologies for any names omitted. cleanup/cleanup_final.c, cleanup/cleanup_bounce.c, cleanup/cleanup_api.c. +20050217 + + Streamline the compile time selection of event handling + styles, replacing multiple on/off macros by just one + multi-valued macro. Files: util/sys_defs.h, util/events.c, + master/multi_server.c, *qmgr/qmgr_transport.c. + Wish list: Update message content length when adding/removing headers. diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index e289aab1e..9d9e76760 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20070215" +#define MAIL_RELEASE_DATE "20070218" #define MAIL_VERSION_NUMBER "2.4" #ifdef SNAPSHOT diff --git a/postfix/src/master/multi_server.c b/postfix/src/master/multi_server.c index c54c8a19c..77d024e39 100644 --- a/postfix/src/master/multi_server.c +++ b/postfix/src/master/multi_server.c @@ -333,7 +333,7 @@ static void multi_server_wakeup(int fd) VSTREAM *stream; char *tmp; -#ifndef USE_SELECT_EVENTS +#if defined(F_DUPFD) && (EVENTS_STYLE != EVENTS_STYLE_SELECT) int new_fd; /* diff --git a/postfix/src/oqmgr/qmgr_transport.c b/postfix/src/oqmgr/qmgr_transport.c index 768c39bfe..cc9fdebc4 100644 --- a/postfix/src/oqmgr/qmgr_transport.c +++ b/postfix/src/oqmgr/qmgr_transport.c @@ -341,7 +341,7 @@ void qmgr_transport_alloc(QMGR_TRANSPORT *transport, QMGR_TRANSPORT_ALLOC_NOT event_request_timer(qmgr_transport_event, (char *) alloc, 0); return; } -#if !defined(USE_SELECT_EVENTS) && defined(VSTREAM_CTL_DUPFD) +#if (EVENTS_STYLE != EVENTS_STYLE_SELECT) && defined(VSTREAM_CTL_DUPFD) vstream_control(alloc->stream, VSTREAM_CTL_DUPFD, FD_SETSIZE / 8, VSTREAM_CTL_END); diff --git a/postfix/src/qmgr/qmgr_transport.c b/postfix/src/qmgr/qmgr_transport.c index 862979dd2..3925a5437 100644 --- a/postfix/src/qmgr/qmgr_transport.c +++ b/postfix/src/qmgr/qmgr_transport.c @@ -346,7 +346,7 @@ void qmgr_transport_alloc(QMGR_TRANSPORT *transport, QMGR_TRANSPORT_ALLOC_NOT event_request_timer(qmgr_transport_event, (char *) alloc, 0); return; } -#if !defined(USE_SELECT_EVENTS) && defined(VSTREAM_CTL_DUPFD) +#if (EVENTS_STYLE != EVENTS_STYLE_SELECT) && defined(VSTREAM_CTL_DUPFD) vstream_control(alloc->stream, VSTREAM_CTL_DUPFD, FD_SETSIZE / 8, VSTREAM_CTL_END); diff --git a/postfix/src/util/events.c b/postfix/src/util/events.c index 81f2e6b80..868064b79 100644 --- a/postfix/src/util/events.c +++ b/postfix/src/util/events.c @@ -152,18 +152,8 @@ #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 /* @@ -175,7 +165,7 @@ */ #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)) @@ -261,9 +251,9 @@ static int event_max_fd = -1; /* highest fd number seen */ * 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 /* @@ -348,11 +338,11 @@ typedef struct kevent EVENT_BUFFER; * 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 #include @@ -424,7 +414,7 @@ typedef struct pollfd EVENT_BUFFER; * 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 /* @@ -456,7 +446,7 @@ static int event_epollfd; /* epoll handle */ #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(). @@ -525,7 +515,7 @@ static void event_init(void) * 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 @@ -545,7 +535,7 @@ static void event_init(void) /* * 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); @@ -600,7 +590,7 @@ static void event_extend(int fd) /* * 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); @@ -684,7 +674,7 @@ void event_enable_read(int fd, EVENT_NOTIFY_RDWR callback, char *context) 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); @@ -739,7 +729,7 @@ void event_enable_write(int fd, EVENT_NOTIFY_RDWR callback, char *context) 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); @@ -778,7 +768,7 @@ void event_disable_readwrite(int fd) */ 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) @@ -798,7 +788,7 @@ void event_disable_readwrite(int fd) 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); @@ -911,12 +901,13 @@ void event_loop(int delay) 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]; @@ -967,7 +958,7 @@ void event_loop(int delay) * 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 { @@ -1037,28 +1028,32 @@ void event_loop(int delay) * 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++) { diff --git a/postfix/src/util/sys_defs.h b/postfix/src/util/sys_defs.h index e4e5af3a4..f99405119 100644 --- a/postfix/src/util/sys_defs.h +++ b/postfix/src/util/sys_defs.h @@ -161,7 +161,7 @@ # 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 @@ -409,7 +409,7 @@ extern int opterr; #endif #define USE_SYSV_POLL #ifndef NO_DEVPOLL -# define USE_DEVPOLL_EVENTS +# define EVENTS_STYLE EVENTS_STYLE_DEVPOLL #endif /* @@ -543,6 +543,7 @@ extern int opterr; #endif #define BROKEN_AI_PASSIVE_NULL_HOST #define BROKEN_AI_NULL_SERVICE +#define USE_SYSV_POLL #endif #ifdef AIX4 @@ -724,7 +725,7 @@ extern int initgroups(const char *, int); #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 @@ -1239,13 +1240,17 @@ extern int inet_pton(int, const char *, void *); /* * 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. */ @@ -1496,21 +1501,25 @@ typedef int pid_t; * 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 diff --git a/postfix/src/util/vstream.c b/postfix/src/util/vstream.c index e9b4a9fb4..ba94a1ce5 100644 --- a/postfix/src/util/vstream.c +++ b/postfix/src/util/vstream.c @@ -1241,6 +1241,8 @@ void vstream_control(VSTREAM *stream, int name,...) stream->write_fd = stream->read_fd; else VSTREAM_TRY_DUPFD(old_fd, stream->write_fd, floor); + stream->fd = (stream->buf.flags & VSTREAM_FLAG_READ) ? + stream->read_fd : stream->write_fd; } else { VSTREAM_TRY_DUPFD(old_fd, stream->fd, floor); }