From 314ab2c6e7ecc18225ca0c406729e717f4553ac6 Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Sun, 23 Mar 2008 12:33:04 +0000 Subject: [PATCH] Update internal libevent to upstream (v1.4.2-rc + OMPI changes). Greatly reduce the number of "foo" -> "opal_foo" symbol renames in the libevent source, and instead greatly expand the event_rename.h file that uses preprocessor macros to make all public symbols be "opal_foo". This commit was SVN r17923. --- config/ompi_setup_libevent.m4 | 9 + contrib/amca-param-sets/ft-enable-cr | 5 + opal/event/Makefile.am | 7 +- opal/event/README | 36 +- opal/event/WIN32-Code/config.h | 329 ++--- opal/event/WIN32-Code/misc.c | 19 +- opal/event/WIN32-Code/misc.h | 18 +- opal/event/{compat/sys => WIN32-Code}/tree.h | 677 ++++++++++ opal/event/WIN32-Code/win32.c | 654 +++++----- opal/event/buffer.c | 97 +- opal/event/compat/sys/Makefile.am | 3 +- opal/event/compat/sys/_time.h | 23 +- opal/event/devpoll.c | 95 +- opal/event/epoll.c | 140 ++- opal/event/epoll_sub.c | 1 + opal/event/evbuffer.c | 129 +- opal/event/event-config.h | 262 ++++ opal/event/event-internal.h | 48 +- opal/event/event.c | 952 ++++++++------ opal/event/event.h | 1114 ++++++++++++++--- opal/event/event_rename.h | 146 ++- opal/event/evsignal.h | 27 +- opal/event/evutil.c | 199 +++ opal/event/evutil.h | 176 +++ opal/event/kqueue.c | 290 +++-- opal/event/log.c | 1 - opal/event/log.h | 24 +- opal/event/min_heap.h | 138 ++ opal/event/poll.c | 183 +-- opal/event/rtsig.c | 437 ------- opal/event/sample/Makefile.am | 3 +- opal/event/sample/Makefile.in | 129 +- opal/event/sample/event-test.c | 34 +- opal/event/sample/signal-test.c | 28 +- opal/event/sample/time-test.c | 30 +- opal/event/select.c | 180 +-- opal/event/signal.c | 331 ++--- opal/event/test/Makefile.am | 34 +- opal/event/test/Makefile.in | 225 ++-- opal/event/test/bench.c | 48 +- opal/event/test/regress.c | 900 ++++++++++++- opal/event/test/test-eof.c | 36 +- opal/event/test/test-init.c | 12 +- opal/event/test/test-time.c | 44 +- opal/event/test/test-weof.c | 38 +- opal/event/test/test.sh | 32 +- .../windows/paffinity_windows_module.c | 6 +- orte/orted/orted_main.c | 31 + 48 files changed, 5819 insertions(+), 2561 deletions(-) rename opal/event/{compat/sys => WIN32-Code}/tree.h (50%) create mode 100644 opal/event/event-config.h create mode 100644 opal/event/evutil.c create mode 100644 opal/event/evutil.h create mode 100644 opal/event/min_heap.h delete mode 100644 opal/event/rtsig.c diff --git a/config/ompi_setup_libevent.m4 b/config/ompi_setup_libevent.m4 index 6d8f50ec49..c39855624c 100644 --- a/config/ompi_setup_libevent.m4 +++ b/config/ompi_setup_libevent.m4 @@ -305,6 +305,15 @@ main() fi fi +haveeventports=no +AC_CHECK_FUNCS(port_create, [haveeventports=yes], ) +if test "x$haveeventports" = "xyes" ; then + AC_DEFINE(HAVE_EVENT_PORTS, 1, + [Define if your system supports event ports]) + sources="evport.c $sources" + needsignal=yes +fi + if test "x$needsignal" = "xyes" ; then # OMPI: don't use AC_LIBOBJ sources="signal.c $sources" diff --git a/contrib/amca-param-sets/ft-enable-cr b/contrib/amca-param-sets/ft-enable-cr index e114dd5031..e106114160 100644 --- a/contrib/amca-param-sets/ft-enable-cr +++ b/contrib/amca-param-sets/ft-enable-cr @@ -36,3 +36,8 @@ snapc=full # pml_wrapper=crcpw crcp=coord + +# +# Temporary fix to force the event engine to use poll to behave well with BLCR +# +opal_event_include=poll diff --git a/opal/event/Makefile.am b/opal/event/Makefile.am index 4c88d29e45..764e84e9e5 100644 --- a/opal/event/Makefile.am +++ b/opal/event/Makefile.am @@ -9,6 +9,7 @@ # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. +# Copyright (c) 2008 Cisco Systems, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow @@ -29,7 +30,7 @@ AM_CPPFLAGS = \ SUBDIRS = compat EXTRA_DIST = event.h event-internal.h evsignal.h event.3 \ - kqueue.c epoll_sub.c epoll.c select.c rtsig.c poll.c signal.c \ + kqueue.c epoll_sub.c epoll.c select.c poll.c signal.c \ devpoll.c log.h\ WIN32-Code/config.h WIN32-Code/misc.c \ WIN32-Code/misc.h WIN32-Code/win32.c @@ -56,9 +57,9 @@ noinst_LTLIBRARIES = libevent.la objects = $(OMPI_LIBEVENT_SOURCES:.c=.lo) # OMPI: Changed to libevent_la_* -headers = event.h event_rename.h +headers = event.h event_rename.h evutil.h min_heap.h -libevent_la_SOURCES = event.c buffer.c evbuffer.c log.c $(headers) +libevent_la_SOURCES = event.c log.c evutil.c $(headers) libevent_la_LIBADD = $(objects) libevent_la_DEPENDENCIES = $(objects) diff --git a/opal/event/README b/opal/event/README index b8f69cdee4..b0650392ed 100644 --- a/opal/event/README +++ b/opal/event/README @@ -2,6 +2,10 @@ To build libevent, type $ ./configure && make + (If you got libevent from the subversion repository, you will + first need to run the included "autogen.sh" script in order to + generate the configure script.) + Install as root via # make install @@ -12,18 +16,42 @@ $ make verify Before, reporting any problems, please run the regression tests. +To enable the low-level tracing build the library as: + +CFLAGS=-DUSE_DEBUG ./configure [...] + Acknowledgements: ----------------- The following people have helped with suggestions, ideas, code or fixing bugs: - Nick Mathewson - Andrew Danforth - Shie Erlich - Mike Davis + Alejo + Weston Andros Adamson William Ahern + Stas Bekman + Andrew Danforth + Mike Davis + Shie Erlich Alexander von Gernler Artur Grabowski + Aaron Hopkins + Claudio Jeker + Scott Lamb + Adam Langley + Philip Lewis + David Libenzi + Nick Mathewson + Andrey Matveev + Richard Nyberg + Jon Oberheide + Phil Oleson + Dave Pacheco + Tassilo von Parseval + Pierre Phaneuf + Jon Poland + Bert JW Regeer + Dug Song + Taral If I have forgotten your name, please contact me. diff --git a/opal/event/WIN32-Code/config.h b/opal/event/WIN32-Code/config.h index 204fdcff7c..4964c145ee 100644 --- a/opal/event/WIN32-Code/config.h +++ b/opal/event/WIN32-Code/config.h @@ -1,236 +1,243 @@ -/* config.h.in. Generated automatically from configure.in by autoheader. */ -/* Define if kqueue works correctly with pipes */ -#undef HAVE_WORKING_KQUEUE +/* config.h. Generated by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ -/* Define to `unsigned long long' if doesn't define. */ -#undef u_int64_t +/* Define if clock_gettime is available in libc */ +/* #undef DNS_USE_CPU_CLOCK_FOR_ID */ -/* Define to `unsigned int' if doesn't define. */ -#undef u_int32_t +/* Define if no secure id variant is available */ +#define DNS_USE_FTIME_FOR_ID 1 -/* Define to `unsigned short' if doesn't define. */ -#undef u_int16_t +/* Define if no secure id variant is available */ +/* #define DNS_USE_GETTIMEOFDAY_FOR_ID 1 */ -/* Define to `unsigned char' if doesn't define. */ -#undef u_int8_t - -/* Define if timeradd is defined in */ -#undef HAVE_TIMERADD -#ifndef HAVE_TIMERADD -#undef timersub -#define timeradd(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ - if ((vvp)->tv_usec >= 1000000) { \ - (vvp)->tv_sec++; \ - (vvp)->tv_usec -= 1000000; \ - } \ - } while (0) -#define timersub(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ - if ((vvp)->tv_usec < 0) { \ - (vvp)->tv_sec--; \ - (vvp)->tv_usec += 1000000; \ - } \ - } while (0) -#endif /* !HAVE_TIMERADD */ - -#undef HAVE_TIMERCLEAR -#ifndef HAVE_TIMERCLEAR -#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#endif - -#define HAVE_TIMERCMP -#ifndef HAVE_TIMERCMP -#undef timercmp -#define timercmp(tvp, uvp, cmp) \ - (((tvp)->tv_sec == (uvp)->tv_sec) ? \ - ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ - ((tvp)->tv_sec cmp (uvp)->tv_sec)) -#endif - -#undef HAVE_TIMERISSET -#ifndef HAVE_TIMERISSET -#undef timerisset -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#endif - -/* Define if TAILQ_FOREACH is defined in */ -#define HAVE_TAILQFOREACH -#ifndef HAVE_TAILQFOREACH -#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_END(head) NULL -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#define TAILQ_FOREACH(var, head, field) \ - for((var) = TAILQ_FIRST(head); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_NEXT(var, field)) -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - (elm)->field.tqe_next = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ -} while (0) -#endif /* TAILQ_FOREACH */ +/* Define to 1 if you have the `clock_gettime' function. */ +/* #undef HAVE_CLOCK_GETTIME */ /* Define if /dev/poll is available */ -#undef HAVE_DEVPOLL +/* #undef HAVE_DEVPOLL */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ /* Define if your system supports the epoll system calls */ -#undef HAVE_EPOLL +/* #undef HAVE_EPOLL */ -/* Define if you have the `epoll_ctl' function. */ -#undef HAVE_EPOLL_CTL +/* Define to 1 if you have the `epoll_ctl' function. */ +/* #undef HAVE_EPOLL_CTL */ -/* Define if you have the `err' function. */ -#undef HAVE_ERR +/* Define if your system supports event ports */ +/* #undef HAVE_EVENT_PORTS */ -/* Define if you have the `fcntl' function. */ -#undef HAVE_FCNTL +/* Define to 1 if you have the `fcntl' function. */ +/* #undef HAVE_FCNTL */ -/* Define if you have the header file. */ -#undef HAVE_FCNTL_H +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 -/* Define if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY 1 +/* Define to 1 if you have the `getaddrinfo' function. */ +/* #undef HAVE_GETADDRINFO */ -/* Define if you have the header file. */ -/* #undef HAVE_INTTYPES_H */ +/* Define to 1 if you have the `getnameinfo' function. */ +/* #undef HAVE_GETNAMEINFO */ -/* Define if you have the `kqueue' function. */ -#undef HAVE_KQUEUE +/* Define to 1 if you have the `gettimeofday' function. */ +/* #define HAVE_GETTIMEOFDAY 1 */ -/* Define if you have the `socket' library (-lsocket). */ -#undef HAVE_LIBSOCKET +/* Define to 1 if you have the `inet_ntop' function. */ +/* #undef HAVE_INET_NTOP */ -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `kqueue' function. */ +/* #undef HAVE_KQUEUE */ + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +/* #undef HAVE_LIBRESOLV */ + +/* Define to 1 if you have the `rt' library (-lrt). */ +/* #undef HAVE_LIBRT */ + +/* Define to 1 if you have the `socket' library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 -/* Define if you have the `poll' function. */ -#undef HAVE_POLL +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETINET_IN6_H */ -/* Define if you have the header file. */ -#undef HAVE_POLL_H +/* Define to 1 if you have the `poll' function. */ +/* #undef HAVE_POLL */ -/* Define if your system supports POSIX realtime signals */ -#undef HAVE_RTSIG +/* Define to 1 if you have the header file. */ +/* #undef HAVE_POLL_H */ -/* Define if you have the `select' function. */ -#undef HAVE_SELECT +/* Define to 1 if you have the `port_create' function. */ +/* #undef HAVE_PORT_CREATE */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PORT_H */ + +/* Define to 1 if you have the `select' function. */ +/* #undef HAVE_SELECT */ /* Define if F_SETFD is defined in */ -#undef HAVE_SETFD +/* #undef HAVE_SETFD */ -/* Define if you have the header file. */ -#undef HAVE_SIGNAL_H +/* Define to 1 if you have the `sigaction' function. */ +/* #undef HAVE_SIGACTION */ -/* Define if you have the `sigtimedwait' function. */ -#undef HAVE_SIGTIMEDWAIT +/* Define to 1 if you have the `signal' function. */ +#define HAVE_SIGNAL 1 -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 -/* Define if you have the header file. */ -#undef HAVE_STDINT_H +/* Define to 1 if you have the header file. */ +/* #define HAVE_STDINT_H 1 */ -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 -/* Define if you have the header file. */ -#undef HAVE_STRINGS_H +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 -/* Define if you have the header file. */ -#undef HAVE_SYS_DEVPOLL_H +/* Define to 1 if you have the `strlcpy' function. */ +/* #undef HAVE_STRLCPY */ -/* Define if you have the header file. */ -#undef HAVE_SYS_EPOLL_H +/* Define to 1 if you have the `strsep' function. */ +/* #undef HAVE_STRSEP */ -/* Define if you have the header file. */ -#undef HAVE_SYS_EVENT_H +/* Define to 1 if you have the `strtok_r' function. */ +/* #undef HAVE_STRTOK_R */ -/* Define if you have the header file. */ -#undef HAVE_SYS_IOCTL_H +/* Define to 1 if the system has the type `struct in6_addr'. */ +#define HAVE_STRUCT_IN6_ADDR 1 -/* Define if you have the header file. */ -#undef HAVE_SYS_QUEUE_H +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DEVPOLL_H */ -/* Define if you have the header file. */ -#define HAVE_SYS_STAT_H 1 +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EPOLL_H */ -/* Define if you have the header file. */ -#undef HAVE_SYS_TIME_H +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EVENT_H */ -/* Define if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_IOCTL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_QUEUE_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SELECT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SOCKET_H */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_STAT_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_TIME_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_TYPES_H 1 */ /* Define if TAILQ_FOREACH is defined in */ -#undef HAVE_TAILQFOREACH +/* #undef HAVE_TAILQFOREACH */ /* Define if timeradd is defined in */ -#undef HAVE_TIMERADD +/* #undef HAVE_TIMERADD */ -/* Define if you have the header file. */ -#undef HAVE_UNISTD_H +/* Define if timerclear is defined in */ +/* #define HAVE_TIMERCLEAR 1 */ -/* Define if you have the `vasprintf' function. */ -#undef HAVE_VASPRINTF +/* Define if timercmp is defined in */ +#define HAVE_TIMERCMP 1 + +/* Define if timerisset is defined in */ +#define HAVE_TIMERISSET 1 + +/* Define to 1 if you have the header file. */ +/* #define HAVE_UNISTD_H 1 */ + +/* Define to 1 if you have the `vasprintf' function. */ +/* #undef HAVE_VASPRINTF */ /* Define if kqueue works correctly with pipes */ -#undef HAVE_WORKING_KQUEUE - -/* Define if realtime signals work on pipes */ -#undef HAVE_WORKING_RTSIG +/* #undef HAVE_WORKING_KQUEUE */ /* Name of package */ #define PACKAGE "libevent" -/* Define if you have the ANSI C header files. */ -#undef STDC_HEADERS +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" -/* Define if you can safely include both and . */ -#undef TIME_WITH_SYS_TIME +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 /* Version number of package */ -#define VERSION "1.0b" +#define VERSION "1.3.99-trunk" + +/* Define to appropriate substitue if compiler doesnt have __func__ */ +#if defined(_MSC_VER) && _MSC_VER < 1300 +#define __func__ "??" +#else +#define __func__ __FUNCTION__ +#endif /* Define to empty if `const' does not conform to ANSI C. */ -#undef const +/* #undef const */ -/* Define as `__inline' if that's what the C compiler calls it, or to nothing - if it is not supported. */ +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus #define inline __inline +#endif /* Define to `int' if does not define. */ -#undef pid_t +/* #undef pid_t */ /* Define to `unsigned' if does not define. */ -#undef size_t +/* #undef size_t */ /* Define to unsigned int if you dont have it */ -#undef socklen_t +#define socklen_t unsigned int /* Define to `unsigned short' if does not define. */ -#undef u_int16_t +#define uint16_t unsigned short /* Define to `unsigned int' if does not define. */ -#undef u_int32_t +#define uint32_t unsigned int /* Define to `unsigned long long' if does not define. */ -/* #undef u_int64_t */ +#define uint64_t __uint64_t /* Define to `unsigned char' if does not define. */ -/* #undef u_int8_t */ - -int win_read(int, void *, unsigned int); -int win_write(int, void *, unsigned int); -int socketpair(int d, int type, int protocol, int *sv); - -#if !defined(__func__) -#define __func__ __FILE__ -#endif /* !defined(__func__) */ +#define uint8_t unsigned char diff --git a/opal/event/WIN32-Code/misc.c b/opal/event/WIN32-Code/misc.c index 822e779ab8..371e192bea 100644 --- a/opal/event/WIN32-Code/misc.c +++ b/opal/event/WIN32-Code/misc.c @@ -1,10 +1,15 @@ -#include "opal_config.h" #include #include #include #include #include +#ifdef __GNUC__ +/*our prototypes for timeval and timezone are in here, just in case the above + headers don't have them*/ +#include "misc.h" +#endif + /**************************************************************************** * * Function: gettimeofday(struct timeval *, struct timezone *) @@ -18,25 +23,26 @@ * ****************************************************************************/ -#if 0 +#ifndef HAVE_GETTIMEOFDAY int gettimeofday(struct timeval *tv, struct timezone *tz) { - struct _timeb tb; + struct _timeb tb; if(tv == NULL) return -1; _ftime(&tb); - tv->tv_sec = (long)tb.time; + tv->tv_sec = (long) tb.time; tv->tv_usec = ((int) tb.millitm) * 1000; return 0; } #endif +#if 0 int win_read(int fd, void *buf, unsigned int length) { DWORD dwBytesRead; - int res = ReadFile((HANDLE)fd, buf, length, &dwBytesRead, NULL); + int res = ReadFile((HANDLE) fd, buf, length, &dwBytesRead, NULL); if (res == 0) { DWORD error = GetLastError(); if (error == ERROR_NO_DATA) @@ -83,4 +89,5 @@ socketpair(int d, int type, int protocol, int *sv) sv[1] = (int)fd; return (0); -} \ No newline at end of file +} +#endif diff --git a/opal/event/WIN32-Code/misc.h b/opal/event/WIN32-Code/misc.h index 8505e0e28b..aced574687 100644 --- a/opal/event/WIN32-Code/misc.h +++ b/opal/event/WIN32-Code/misc.h @@ -1,23 +1,11 @@ #ifndef MISC_H #define MISC_H -#include "opal/event/event.h" - -#if defined(c_plusplus) || defined(__cplusplus) -extern "C" { -#endif +struct timezone; +struct timeval; +#ifndef HAVE_GETTIMEOFDAY int gettimeofday(struct timeval *,struct timezone *); - -OPAL_DECLSPEC extern void *win32_init (void); -OPAL_DECLSPEC extern int win32_insert(struct win32op *win32op, struct opal_event *ev); -OPAL_DECLSPEC extern int win32_del(struct win32op *win32op, struct opal_event *ev); -OPAL_DECLSPEC extern int win32_dispatch(struct event_base *base, struct win32op *win32op, - struct timeval *tv); -OPAL_DECLSPEC extern int win32_recalc (struct event_base *base, void *, int); - -#if defined(c_plusplus) || defined(__cplusplus) -} #endif #endif diff --git a/opal/event/compat/sys/tree.h b/opal/event/WIN32-Code/tree.h similarity index 50% rename from opal/event/compat/sys/tree.h rename to opal/event/WIN32-Code/tree.h index 6a3381caee..79e8d91f0e 100644 --- a/opal/event/compat/sys/tree.h +++ b/opal/event/WIN32-Code/tree.h @@ -675,3 +675,680 @@ name##_RB_MINMAX(struct name *head, int val) \ (x) = name##_RB_NEXT(x)) #endif /* _SYS_TREE_H_ */ +/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ +/* + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while ((__comp = (cmp)(elm, (head)->sph_root))) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-back tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ +void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +struct type *name##_RB_REMOVE(struct name *, struct type *); \ +struct type *name##_RB_INSERT(struct name *, struct type *); \ +struct type *name##_RB_FIND(struct name *, struct type *); \ +struct type *name##_RB_NEXT(struct type *); \ +struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ +void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)))\ + RB_COLOR(oleft, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)))\ + RB_COLOR(oright, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field))) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ + RB_LEFT(RB_PARENT(old, field), field) = elm;\ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field))); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#endif /* _SYS_TREE_H_ */ diff --git a/opal/event/WIN32-Code/win32.c b/opal/event/WIN32-Code/win32.c index 48dd136696..6291a41516 100644 --- a/opal/event/WIN32-Code/win32.c +++ b/opal/event/WIN32-Code/win32.c @@ -1,7 +1,6 @@ /* * Copyright 2000-2002 Niels Provos * Copyright 2003 Michael A. Davis - * Copyright 2006 George Bosilca * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,35 +25,37 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "opal_config.h" -#include "config.h" +#ifdef _MSC_VER +#include "./config.h" +#else +/* Avoid the windows/msvc thing. */ +#include "../config.h" +#endif #include - #include #include #include -#include -#if defined(HAVE_SIGNAL_H) #include -#endif /* defined(HAVE_SIGNAL_H) */ #include #include #include #include #include -#include "opal/event/event_rename.h" +#define RB_AUGMENT(x) (void)(x) +#include "./tree.h" #include "opal/event/log.h" #include "opal/event/event.h" #include "opal/event/event-internal.h" -#include "opal/event/WIN32-Code/misc.h" #define XFREE(ptr) do { if (ptr) free(ptr); } while(0) -extern struct opal_event_list opal_timequeue; -extern struct opal_event_list opal_addqueue; -extern struct opal_event_list opal_signalqueue; +extern struct event_list timequeue; +extern struct event_list addqueue; +#if 0 +extern struct event_list signalqueue; +#endif struct win_fd_set { u_int fd_count; @@ -66,9 +67,32 @@ volatile sig_atomic_t signal_caught = 0; /* MSDN says this is required to handle SIGFPE */ volatile double SIGFPE_REQ = 0.0f; -void signal_handler(int sig); +#if 0 +static void signal_handler(int sig); + void signal_process(void); int signal_recalc(void); +#endif + +struct event_entry { + RB_ENTRY(event_entry) node; + SOCKET sock; + int read_pos; + int write_pos; + struct event *read_event; + struct event *write_event; +}; + +static int +compare(struct event_entry *a, struct event_entry *b) +{ + if (a->sock < b->sock) + return -1; + else if (a->sock > b->sock) + return 1; + else + return 0; +} struct win32op { int fd_setsz; @@ -77,375 +101,349 @@ struct win32op { struct win_fd_set *readset_out; struct win_fd_set *writeset_out; struct win_fd_set *exset_out; - int n_events; - int n_events_alloc; - opal_event_t **events; + RB_HEAD(event_map, event_entry) event_root; }; -const struct opal_eventop opal_win32ops = { +RB_PROTOTYPE(event_map, event_entry, node, compare); +RB_GENERATE(event_map, event_entry, node, compare); + +void *win32_init (struct event_base *); +int win32_insert (void *, struct event *); +int win32_del (void *, struct event *); +int win32_dispatch (struct event_base *base, void *, struct timeval *); +void win32_dealloc (struct event_base *, void *); + +struct eventop win32ops = { "win32", win32_init, - (int (*)(void *, struct opal_event *))win32_insert, - (int (*)(void *, struct opal_event *))win32_del, - (int (*)(struct event_base *, void *, int))win32_recalc, - (int (*)(struct event_base *, void *, struct timeval *))win32_dispatch + win32_insert, + win32_del, + win32_dispatch, + win32_dealloc, + 0 }; #define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET))) +static int +realloc_fd_sets(struct win32op *op, size_t new_size) +{ + size_t size; + + assert(new_size >= op->readset_in->fd_count && + new_size >= op->writeset_in->fd_count); + assert(new_size >= 1); + + size = FD_SET_ALLOC_SIZE(new_size); + if (!(op->readset_in = realloc(op->readset_in, size))) + return (-1); + if (!(op->writeset_in = realloc(op->writeset_in, size))) + return (-1); + if (!(op->readset_out = realloc(op->readset_out, size))) + return (-1); + if (!(op->exset_out = realloc(op->exset_out, size))) + return (-1); + if (!(op->writeset_out = realloc(op->writeset_out, size))) + return (-1); + op->fd_setsz = new_size; + return (0); +} + +static int +timeval_to_ms(struct timeval *tv) +{ + return ((tv->tv_sec * 1000) + (tv->tv_usec / 1000)); +} + +static struct event_entry* +get_event_entry(struct win32op *op, SOCKET s, int create) +{ + struct event_entry key, *val; + key.sock = s; + val = RB_FIND(event_map, &op->event_root, &key); + if (val || !create) + return val; + if (!(val = calloc(1, sizeof(struct event_entry)))) { + event_warn("%s: calloc", __func__); + return NULL; + } + val->sock = s; + val->read_pos = val->write_pos = -1; + RB_INSERT(event_map, &op->event_root, val); + return val; +} + +static int +do_fd_set(struct win32op *op, struct event_entry *ent, int read) +{ + SOCKET s = ent->sock; + struct win_fd_set *set = read ? op->readset_in : op->writeset_in; + if (read) { + if (ent->read_pos >= 0) + return (0); + } else { + if (ent->write_pos >= 0) + return (0); + } + if (set->fd_count == op->fd_setsz) { + if (realloc_fd_sets(op, op->fd_setsz*2)) + return (-1); + /* set pointer will have changed and needs reiniting! */ + set = read ? op->readset_in : op->writeset_in; + } + set->fd_array[set->fd_count] = s; + if (read) + ent->read_pos = set->fd_count; + else + ent->write_pos = set->fd_count; + return (set->fd_count++); +} + +static int +do_fd_clear(struct win32op *op, struct event_entry *ent, int read) +{ + int i; + struct win_fd_set *set = read ? op->readset_in : op->writeset_in; + if (read) { + i = ent->read_pos; + ent->read_pos = -1; + } else { + i = ent->write_pos; + ent->write_pos = -1; + } + if (i < 0) + return (0); + if (--set->fd_count != i) { + struct event_entry *ent2; + SOCKET s2; + s2 = set->fd_array[i] = set->fd_array[set->fd_count]; + ent2 = get_event_entry(op, s2, 0); + if (!ent) /* This indicates a bug. */ + return (0); + if (read) + ent2->read_pos = i; + else + ent2->write_pos = i; + } + return (0); +} + #define NEVENT 64 void * -win32_init(void) +win32_init(struct event_base *_base) { struct win32op *winop; size_t size; - if (!(winop = (struct win32op*)calloc(1, sizeof(struct win32op)))) + if (!(winop = calloc(1, sizeof(struct win32op)))) return NULL; winop->fd_setsz = NEVENT; size = FD_SET_ALLOC_SIZE(NEVENT); - if (!(winop->readset_in = (struct win_fd_set*)malloc(size))) + if (!(winop->readset_in = malloc(size))) goto err; - if (!(winop->writeset_in = (struct win_fd_set*)malloc(size))) + if (!(winop->writeset_in = malloc(size))) goto err; - if (!(winop->readset_out = (struct win_fd_set*)malloc(size))) + if (!(winop->readset_out = malloc(size))) goto err; - if (!(winop->writeset_out = (struct win_fd_set*)malloc(size))) + if (!(winop->writeset_out = malloc(size))) goto err; - if (!(winop->exset_out = (struct win_fd_set*)malloc(size))) - goto err; - winop->n_events = 0; - winop->n_events_alloc = NEVENT; - if (!(winop->events = (opal_event_t**)malloc(NEVENT*sizeof(opal_event_t*)))) + if (!(winop->exset_out = malloc(size))) goto err; + RB_INIT(&winop->event_root); winop->readset_in->fd_count = winop->writeset_in->fd_count = 0; winop->readset_out->fd_count = winop->writeset_out->fd_count = winop->exset_out->fd_count = 0; + evsignal_init(_base); + return (winop); - err: - XFREE(winop->readset_in); - XFREE(winop->writeset_in); - XFREE(winop->readset_out); - XFREE(winop->writeset_out); - XFREE(winop->exset_out); - XFREE(winop->events); - XFREE(winop); - return (NULL); + XFREE(winop->readset_in); + XFREE(winop->writeset_in); + XFREE(winop->readset_out); + XFREE(winop->writeset_out); + XFREE(winop->exset_out); + XFREE(winop); + return (NULL); } int -win32_recalc(struct event_base *base, void *arg, int max) +win32_insert(void *op, struct event *ev) { - return 0/*(signal_recalc())*/; -} + struct win32op *win32op = op; + struct event_entry *ent; -static bool win32_is_fd_a_socket( int fd ) -{ - int error; - u_long value = 123456; - - if( SOCKET_ERROR == WSAHtonl( fd, value, &value ) ) { - error = WSAGetLastError(); - return false; - } - return true; -} - -void CALLBACK win32_socket_event_callback( void* lpParameter, BOOLEAN TimerOrWaitFired ) -{ - opal_event_t* master = (opal_event_t*)lpParameter; - WSANETWORKEVENTS network_events; - int got, error; - opal_event_t* next; - - assert( FALSE == TimerOrWaitFired ); - - /* The handle will be automatically reset */ - if( SOCKET_ERROR == WSAEnumNetworkEvents( master->ev_fd, master->base_handle, &network_events ) ) { - error = WSAGetLastError(); - return; - } - - do { - got = 0; - next = master->ev_similar; - if( network_events.lNetworkEvents & (FD_READ | FD_ACCEPT) ) { - if( master->ev_events & OPAL_EV_READ ) { - network_events.lNetworkEvents &= ~(FD_READ | FD_ACCEPT); - got |= OPAL_EV_READ; - } - } - if( master->ev_events & OPAL_EV_WRITE ) { - got |= OPAL_EV_WRITE; - if( 0 == WSASetEvent(master->base_handle) ) { - int error = WSAGetLastError(); - } - } - - if( got ) { - if (!(master->ev_events & OPAL_EV_PERSIST)) { - opal_event_del(master); - } - - (*master->ev_callback)((int)master->ev_fd, got, master->ev_arg); - /*opal_event_active( ev, got, 1 );*/ - } - master = next; - } while( master != ((opal_event_t*)lpParameter) ); -} - -void CALLBACK win32_file_event_callback( void* lpParameter, BOOLEAN TimerOrWaitFired ) -{ - opal_event_t* ev = (opal_event_t*)lpParameter; - int got = 0; - - assert( FALSE == TimerOrWaitFired ); - - if( ev->ev_events & OPAL_EV_READ ) { - got |= OPAL_EV_READ; + if (ev->ev_events & EV_SIGNAL) { + return (evsignal_add(ev)); } - if( ev->ev_events & OPAL_EV_WRITE ) { - got |= OPAL_EV_WRITE; - } - - if (!(ev->ev_events & OPAL_EV_PERSIST)) { - opal_event_del(ev); - } - - if( got ) { - /*(*ev->ev_callback)((int)ev->ev_fd, got, ev->ev_arg);*/ - opal_event_active( ev, got, 1 ); - } -} - -static int win32_recompute_event( opal_event_t* master ) -{ - long flags = FD_CLOSE; - opal_event_t* temp; - int error; - - if( INVALID_HANDLE_VALUE == master->base_handle ) { - master->base_handle = WSACreateEvent(); - if( INVALID_HANDLE_VALUE == master->base_handle ) { - return 0; - } - } - - /* Compute the flags we're looking at */ - temp = master; - do { - if( temp->ev_events & OPAL_EV_READ ) flags |= FD_READ | FD_ACCEPT; - if( temp->ev_events & OPAL_EV_WRITE ) flags |= FD_WRITE | FD_CONNECT; - temp = temp->ev_similar; - } while( temp != master ); - - if( SOCKET_ERROR == WSAEventSelect( master->ev_fd, master->base_handle, flags ) ) { - error = WSAGetLastError(); - WSACloseEvent( master->base_handle ); - master->base_handle = INVALID_HANDLE_VALUE; - return 0; - } - if( INVALID_HANDLE_VALUE == master->registered_handle ) { - if( 0 == RegisterWaitForSingleObject( &master->registered_handle, master->base_handle, win32_socket_event_callback, - (void*)master, INFINITE, WT_EXECUTEINWAITTHREAD ) ) { - error = GetLastError(); - WSACloseEvent( master->base_handle ); - master->base_handle = INVALID_HANDLE_VALUE; - master->registered_handle = INVALID_HANDLE_VALUE; - return 0; - } - } - if( flags & FD_WRITE ) { - if( 0 == WSASetEvent(master->base_handle) ) { - error = WSAGetLastError(); - } - } - return 1; -} - -int -win32_insert(struct win32op *win32op, opal_event_t *ev) -{ - int i; - opal_event_t* master = NULL; - - if (ev->ev_events & OPAL_EV_SIGNAL) { - if (ev->ev_events & (OPAL_EV_READ|OPAL_EV_WRITE)) - event_errx(1, "%s: EV_SIGNAL incompatible use", - __func__); - if( signal(OPAL_EVENT_SIGNAL(ev), signal_handler) == SIG_ERR) - return (-1); - + if (!(ev->ev_events & (EV_READ|EV_WRITE))) return (0); + ent = get_event_entry(win32op, ev->ev_fd, 1); + if (!ent) + return (-1); /* out of memory */ + + event_debug(("%s: adding event for %d", __func__, (int)ev->ev_fd)); + if (ev->ev_events & EV_READ) { + if (do_fd_set(win32op, ent, 1)<0) + return (-1); + ent->read_event = ev; } - - /** - * Find a place for the current event. - */ - for( i = 0; i < win32op->n_events; ++i ) { - if( win32op->events[i]->ev_fd != ev->ev_fd ) continue; - master = win32op->events[i]; - if( master == ev ) { - event_debug( ("%s: Event for %d already inserted.", - __func__, (int)ev->ev_fd)); - return (0); - } - - if( master->ev_events & ev->ev_events ) { - event_debug( ("%d Event for %d already have a similar event posted.", - __func__, (int)ev->ev_fd) ); - } - ev->ev_similar = master->ev_similar; - master->ev_similar = ev; - break; + if (ev->ev_events & EV_WRITE) { + if (do_fd_set(win32op, ent, 0)<0) + return (-1); + ent->write_event = ev; } - if( NULL == master ) { - event_debug(("%s: adding event for %d", __func__, (int)ev->ev_fd)); - - if (win32op->n_events_alloc == win32op->n_events) { - size_t sz; - win32op->n_events_alloc *= 2; - sz = sizeof(opal_event_t*) * win32op->n_events_alloc; - if (!(win32op->events = (opal_event_t**)realloc(win32op->events, sz))) - return (-1); - } - win32op->events[win32op->n_events++] = ev; - ev->ev_similar = ev; - master = ev; - } - ev->base_handle = INVALID_HANDLE_VALUE; - ev->registered_handle = INVALID_HANDLE_VALUE; - /** - * Decide if we have a socket or a normal file descriptor. If it's a socket - * create a WSA event otherwise a normal file event will be what we need. - */ - if( win32_is_fd_a_socket(ev->ev_fd) ) { - win32_recompute_event( master ); - } else { - /* - if( ev->ev_events & OPAL_EV_READ ) flags |= FD_READ; - if( ev->ev_events & OPAL_EV_WRITE ) flags |= FD_WRITE; - ev->base_handle = (HANDLE)_get_osfhandle( ev->ev_fd ); - if( INVALID_HANDLE_VALUE == ev->base_handle ) { - int error = errno; - } - if( 0 == RegisterWaitForSingleObject( &ev->registered_handle, ev->base_handle, win32_file_event_callback, - (void*)ev, INFINITE, WT_EXECUTEINWAITTHREAD ) ) { - error = GetLastError(); - }*/ - } - return (0); } int -win32_del(struct win32op *win32op, opal_event_t *ev) +win32_del(void *op, struct event *ev) { - int i, error; - opal_event_t *master = NULL, *temp; + struct win32op *win32op = op; + struct event_entry *ent; - if (ev->ev_events & OPAL_EV_SIGNAL) - return (signal(OPAL_EVENT_SIGNAL(ev), SIG_IGN) != SIG_ERR); + if (ev->ev_events & EV_SIGNAL) + return (evsignal_del(ev)); - for( i = 0; i < win32op->n_events; ++i ) { - if( win32op->events[i]->ev_fd != ev->ev_fd ) continue; - master = win32op->events[i]; - break; - } - if( NULL == master ) { - event_debug(("%s: Unable to remove non-inserted event for %d", - __func__, ev->ev_fd)); + if (!(ent = get_event_entry(win32op, ev->ev_fd, 0))) return (-1); - } event_debug(("%s: Removing event for %d", __func__, ev->ev_fd)); - - /** - * Remove the current event and recompute the registered event - * based on the opal events pending on the same master. - */ - if( master == ev ) { - /* Disable all pending events */ - if( INVALID_HANDLE_VALUE != ev->registered_handle ) { - if( 0 == UnregisterWait(ev->registered_handle) ) { - error = GetLastError(); - } - ev->registered_handle = INVALID_HANDLE_VALUE; - } - if( ev->ev_similar == ev ) { - /* Only one event in the queue. Remove everything. */ - if( INVALID_HANDLE_VALUE != ev->base_handle ) { /* socket */ - /* Now detach the base event from the socket. */ - if( SOCKET_ERROR == WSAEventSelect( ev->ev_fd, ev->base_handle, 0) ) { - error = WSAGetLastError(); - } - /* Finally, destroy the event handle. */ - if( 0 == WSACloseEvent(ev->base_handle) ) { - error = WSAGetLastError(); - } - ev->base_handle = INVALID_HANDLE_VALUE; - } - - if (i != --win32op->n_events) { - win32op->events[i] = win32op->events[win32op->n_events]; - } - - return 0; - } - master = ev->ev_similar; - master->base_handle = ev->base_handle; - master->registered_handle = ev->registered_handle; - win32op->events[i] = master; - temp = master; - while( temp->ev_similar != ev ) { - temp = temp->ev_similar; - } - temp->ev_similar = master; - } else { - temp = master; - while( temp->ev_similar != ev ) { - temp = temp->ev_similar; - } - temp->ev_similar = ev->ev_similar; - } - win32_recompute_event( master ); + if (ev == ent->read_event) { + do_fd_clear(win32op, ent, 1); + ent->read_event = NULL; + } + if (ev == ent->write_event) { + do_fd_clear(win32op, ent, 0); + ent->write_event = NULL; + } + if (!ent->read_event && !ent->write_event) { + RB_REMOVE(event_map, &win32op->event_root, ent); + free(ent); + } return 0; } -int -win32_dispatch( struct event_base *base, struct win32op *win32op, - struct timeval *tv ) +static void +fd_set_copy(struct win_fd_set *out, const struct win_fd_set *in) { - DWORD milisec; - - /*milisec = tv->tv_sec * 1000; - if( tv->tv_usec > 1000 ) { - milisec += tv->tv_usec / 1000; - }*/ - milisec = tv->tv_sec; /* BLAH BLAH REMOVE ME */ - SleepEx( milisec, TRUE ); - if( 0 != signal_caught ) { - signal_process(); - signal_recalc(); - } - return 0; + out->fd_count = in->fd_count; + memcpy(out->fd_array, in->fd_array, in->fd_count * (sizeof(SOCKET))); } +/* + static void dump_fd_set(struct win_fd_set *s) + { + unsigned int i; + printf("[ "); + for(i=0;ifd_count;++i) + printf("%d ",(int)s->fd_array[i]); + printf("]\n"); + } +*/ -static void signal_handler(int sig) +int +win32_dispatch(struct event_base *base, void *op, + struct timeval *tv) +{ + struct win32op *win32op = op; + int res = 0; + int i; + int fd_count; + + fd_set_copy(win32op->readset_out, win32op->readset_in); + fd_set_copy(win32op->exset_out, win32op->readset_in); + fd_set_copy(win32op->writeset_out, win32op->writeset_in); + + fd_count = + (win32op->readset_out->fd_count > win32op->writeset_out->fd_count) ? + win32op->readset_out->fd_count : win32op->writeset_out->fd_count; + + if (!fd_count) { + /* Windows doesn't like you to call select() with no sockets */ + Sleep(timeval_to_ms(tv)); + evsignal_process(base); + return (0); + } + + res = select(fd_count, + (struct fd_set*)win32op->readset_out, + (struct fd_set*)win32op->writeset_out, + (struct fd_set*)win32op->exset_out, tv); + + event_debug(("%s: select returned %d", __func__, res)); + + if(res <= 0) { + evsignal_process(base); + return res; + } else if (base->sig.evsignal_caught) { + evsignal_process(base); + } + + for (i=0; ireadset_out->fd_count; ++i) { + struct event_entry *ent; + SOCKET s = win32op->readset_out->fd_array[i]; + if ((ent = get_event_entry(win32op, s, 0)) && ent->read_event) + event_active(ent->read_event, EV_READ, 1); + } + for (i=0; iexset_out->fd_count; ++i) { + struct event_entry *ent; + SOCKET s = win32op->exset_out->fd_array[i]; + if ((ent = get_event_entry(win32op, s, 0)) && ent->read_event) + event_active(ent->read_event, EV_READ, 1); + } + for (i=0; iwriteset_out->fd_count; ++i) { + struct event_entry *ent; + SOCKET s = win32op->writeset_out->fd_array[i]; + if ((ent = get_event_entry(win32op, s, 0)) && ent->write_event) + event_active(ent->write_event, EV_WRITE, 1); + } + +#if 0 + if (signal_recalc() == -1) + return (-1); +#endif + + return (0); +} + +void +win32_dealloc(struct event_base *_base, void *arg) +{ + struct win32op *win32op = arg; + + evsignal_dealloc(_base); + if (win32op->readset_in) + free(win32op->readset_in); + if (win32op->writeset_in) + free(win32op->writeset_in); + if (win32op->readset_out) + free(win32op->readset_out); + if (win32op->writeset_out) + free(win32op->writeset_out); + if (win32op->exset_out) + free(win32op->exset_out); + /* XXXXX free the tree. */ + + memset(win32op, 0, sizeof(win32op)); + free(win32op); +} + +#if 0 +static void +signal_handler(int sig) { evsigcaught[sig]++; signal_caught = 1; } -int signal_recalc(void) +int +signal_recalc(void) { - opal_event_t *ev; + struct event *ev; /* Reinstall our signal handler. */ - TAILQ_FOREACH(ev, &opal_signalqueue, ev_signal_next) { - if( signal(OPAL_EVENT_SIGNAL(ev), signal_handler) == SIG_ERR) + TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { + if((int)signal(EVENT_SIGNAL(ev), signal_handler) == -1) return (-1); } return (0); @@ -454,18 +452,20 @@ int signal_recalc(void) void signal_process(void) { - opal_event_t *ev; + struct event *ev; short ncalls; - TAILQ_FOREACH(ev, &opal_signalqueue, ev_signal_next) { - ncalls = evsigcaught[OPAL_EVENT_SIGNAL(ev)]; + TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { + ncalls = evsigcaught[EVENT_SIGNAL(ev)]; if (ncalls) { - if (!(ev->ev_events & OPAL_EV_PERSIST)) - opal_event_del(ev); - opal_event_active(ev, OPAL_EV_SIGNAL, ncalls); + if (!(ev->ev_events & EV_PERSIST)) + event_del(ev); + event_active(ev, EV_SIGNAL, ncalls); } } memset(evsigcaught, 0, sizeof(evsigcaught)); signal_caught = 0; } +#endif + diff --git a/opal/event/buffer.c b/opal/event/buffer.c index f27e2d5766..968c5767d0 100644 --- a/opal/event/buffer.c +++ b/opal/event/buffer.c @@ -27,6 +27,11 @@ #include "opal_config.h" +#ifdef WIN32 +#include +#include +#endif + #ifdef HAVE_VASPRINTF /* If we have vasprintf, we need to define this before we include stdio.h. */ #ifndef _GNU_SOURCE @@ -44,6 +49,7 @@ #include #endif +#include #include #include #include @@ -57,6 +63,7 @@ #include "event.h" + struct evbuffer * evbuffer_new(void) { @@ -106,7 +113,7 @@ evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf) /* * Optimization comes with a price; we need to notify the * buffer if necessary of the changes. oldoff is the amount - * of data that we tranfered from inbuf to outbuf + * of data that we transfered from inbuf to outbuf */ if (inbuf->off != oldoff && inbuf->cb != NULL) (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg); @@ -132,20 +139,33 @@ evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap) size_t space; size_t oldoff = buf->off; int sz; + va_list aq; + /* make sure that at least some space is available */ + evbuffer_expand(buf, 64); for (;;) { - buffer = (char*) buf->buffer + buf->off; - space = buf->totallen - buf->misalign - buf->off; + size_t used = buf->misalign + buf->off; + buffer = (char *)buf->buffer + buf->off; + assert(buf->totallen >= used); + space = buf->totallen - used; + +#ifndef va_copy +#define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list)) +#endif + va_copy(aq, ap); #ifdef WIN32 - sz = vsnprintf(buffer, space - 1, fmt, ap); + sz = vsnprintf(buffer, space - 1, fmt, aq); buffer[space - 1] = '\0'; #else - sz = vsnprintf(buffer, space, fmt, ap); + sz = vsnprintf(buffer, space, fmt, aq); #endif - if (sz == -1) + + va_end(aq); + + if (sz < 0) return (-1); - if ((size_t) sz < space) { + if (sz < space) { buf->off += sz; if (buf->cb != NULL) (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); @@ -194,17 +214,17 @@ evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen) char * evbuffer_readline(struct evbuffer *buffer) { - u_char *data = OPAL_EVBUFFER_DATA(buffer); - size_t len = OPAL_EVBUFFER_LENGTH(buffer); + u_char *data = EVBUFFER_DATA(buffer); + size_t len = EVBUFFER_LENGTH(buffer); char *line; - u_int i; + unsigned int i; - for (i = 0; i < (u_int) len; i++) { + for (i = 0; i < len; i++) { if (data[i] == '\r' || data[i] == '\n') break; } - if (i == (u_int) len) + if (i == len) return (NULL); if ((line = malloc(i + 1)) == NULL) { @@ -220,7 +240,7 @@ evbuffer_readline(struct evbuffer *buffer) * Some protocols terminate a line with '\r\n', so check for * that, too. */ - if ( i < (u_int) len - 1 ) { + if ( i < len - 1 ) { char fch = data[i], sch = data[i+1]; /* Drain one more character if needed */ @@ -235,7 +255,7 @@ evbuffer_readline(struct evbuffer *buffer) /* Adds data to an event buffer */ -static inline void +static void evbuffer_align(struct evbuffer *buf) { memmove(buf->orig_buffer, buf->buffer, buf->off); @@ -282,7 +302,7 @@ evbuffer_expand(struct evbuffer *buf, size_t datlen) } int -evbuffer_add(struct evbuffer *buf, void *data, size_t datlen) +evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen) { size_t need = buf->misalign + buf->off + datlen; size_t oldoff = buf->off; @@ -337,12 +357,14 @@ evbuffer_read(struct evbuffer *buf, int fd, int howmuch) u_char *p; size_t oldoff = buf->off; int n = EVBUFFER_MAX_READ; -#ifdef WIN32 - DWORD dwBytesRead; -#endif -#ifdef FIONREAD +#if defined(FIONREAD) +#ifdef WIN32 + long lng = n; + if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) == 0) { +#else if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) { +#endif n = EVBUFFER_MAX_READ; } else if (n > EVBUFFER_MAX_READ && n > howmuch) { /* @@ -352,7 +374,7 @@ evbuffer_read(struct evbuffer *buf, int fd, int howmuch) * about it. If the reader does not tell us how much * data we should read, we artifically limit it. */ - if ((size_t) n > buf->totallen << 2) + if (n > buf->totallen << 2) n = buf->totallen << 2; if (n < EVBUFFER_MAX_READ) n = EVBUFFER_MAX_READ; @@ -370,18 +392,13 @@ evbuffer_read(struct evbuffer *buf, int fd, int howmuch) #ifndef WIN32 n = read(fd, p, howmuch); +#else + n = recv(fd, p, howmuch, 0); +#endif if (n == -1) return (-1); if (n == 0) return (0); -#else - n = ReadFile((HANDLE)fd, p, howmuch, &dwBytesRead, NULL); - if (n == 0) - return (-1); - if (dwBytesRead == 0) - return (0); - n = dwBytesRead; -#endif buf->off += n; @@ -396,24 +413,16 @@ int evbuffer_write(struct evbuffer *buffer, int fd) { int n; -#ifdef WIN32 - DWORD dwBytesWritten; -#endif #ifndef WIN32 n = write(fd, buffer->buffer, buffer->off); +#else + n = send(fd, buffer->buffer, buffer->off, 0); +#endif if (n == -1) return (-1); if (n == 0) return (0); -#else - n = WriteFile((HANDLE)fd, buffer->buffer, buffer->off, &dwBytesWritten, NULL); - if (n == 0) - return (-1); - if (dwBytesWritten == 0) - return (0); - n = dwBytesWritten; -#endif evbuffer_drain(buffer, n); return (n); @@ -422,16 +431,16 @@ evbuffer_write(struct evbuffer *buffer, int fd) u_char * evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len) { - size_t remain = buffer->off; - u_char *search = buffer->buffer; + u_char *search = buffer->buffer, *end = search + buffer->off; u_char *p; - while ((p = memchr(search, *what, remain)) != NULL && remain >= len) { + while (search < end && + (p = memchr(search, *what, end - search)) != NULL) { + if (p + len > end) + break; if (memcmp(p, what, len) == 0) return (p); - search = p + 1; - remain = buffer->off - (size_t)(search - buffer->buffer); } return (NULL); diff --git a/opal/event/compat/sys/Makefile.am b/opal/event/compat/sys/Makefile.am index e10b9d05f1..905e20834f 100644 --- a/opal/event/compat/sys/Makefile.am +++ b/opal/event/compat/sys/Makefile.am @@ -9,6 +9,7 @@ # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. +# Copyright (c) 2008 Cisco Systems, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow @@ -18,4 +19,4 @@ -noinst_HEADERS = queue.h _time.h _timeradd.h tree.h +noinst_HEADERS = queue.h _time.h _timeradd.h diff --git a/opal/event/compat/sys/_time.h b/opal/event/compat/sys/_time.h index 7dbcc3e30d..8cabb0d55e 100644 --- a/opal/event/compat/sys/_time.h +++ b/opal/event/compat/sys/_time.h @@ -32,13 +32,10 @@ * @(#)time.h 8.2 (Berkeley) 7/10/94 */ -#ifndef OMPI_TIME_H #ifndef _SYS_TIME_H_ #define _SYS_TIME_H_ -#ifdef HAVE_SYS_TYPES_H #include -#endif /* * Structure returned by gettimeofday(2) system call, @@ -85,7 +82,24 @@ struct timezone { (((tvp)->tv_sec == (uvp)->tv_sec) ? \ ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ ((tvp)->tv_sec cmp (uvp)->tv_sec)) -#include +#define timeradd(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) +#define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) /* Operations on timespecs. */ #define timespecclear(tsp) (tsp)->tv_sec = (tsp)->tv_nsec = 0 @@ -147,4 +161,3 @@ struct clockinfo { /* --- stuff got cut here - niels --- */ #endif /* !_SYS_TIME_H_ */ -#endif /* !OMPI_TIME_H */ diff --git a/opal/event/devpoll.c b/opal/event/devpoll.c index 46f7e08628..a1a3255705 100644 --- a/opal/event/devpoll.c +++ b/opal/event/devpoll.c @@ -45,6 +45,7 @@ #include #include "event.h" +#include "event-internal.h" #include "evsignal.h" #include "log.h" @@ -54,12 +55,13 @@ extern opal_mutex_t opal_event_lock; extern volatile sig_atomic_t opal_evsignal_caught; + /* due to limitations in the devpoll interface, we need to keep track of * all file descriptors outself. */ struct evdevpoll { - struct opal_event *evread; - struct opal_event *evwrite; + struct event *evread; + struct event *evwrite; }; struct devpollop { @@ -68,24 +70,24 @@ struct devpollop { struct pollfd *events; int nevents; int dpfd; - sigset_t evsigmask; struct pollfd *changes; int nchanges; }; -static void *devpoll_init (void); -static int devpoll_add (void *, struct opal_event *); -static int devpoll_del (void *, struct opal_event *); -static int devpoll_recalc (struct event_base *, void *, int); +static void *devpoll_init (struct event_base *); +static int devpoll_add (void *, struct event *); +static int devpoll_del (void *, struct event *); static int devpoll_dispatch (struct event_base *, void *, struct timeval *); +static void devpoll_dealloc (struct event_base *, void *); -struct opal_eventop devpollops = { +struct eventop devpollops = { "devpoll", devpoll_init, devpoll_add, devpoll_del, - devpoll_recalc, - devpoll_dispatch + devpoll_dispatch, + devpoll_dealloc, + 1 /* need reinit */ }; #define NEVENT 32000 @@ -126,8 +128,8 @@ devpoll_queue(struct devpollop *devpollop, int fd, int events) { return(0); } -void * -devpoll_init(void) +static void * +devpoll_init(struct event_base *base) { int dpfd, nfiles = NEVENT; struct rlimit rl; @@ -180,12 +182,12 @@ devpoll_init(void) return (NULL); } - opal_evsignal_init(&devpollop->evsigmask); + evsignal_init(base); return (devpollop); } -int +static int devpoll_recalc(struct event_base *base, void *arg, int max) { struct devpollop *devpollop = arg; @@ -209,42 +211,37 @@ devpoll_recalc(struct event_base *base, void *arg, int max) devpollop->nfds = nfds; } - return (opal_evsignal_recalc(&devpollop->evsigmask)); + return (0); } -int +static int devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) { struct devpollop *devpollop = arg; struct pollfd *events = devpollop->events; struct dvpoll dvp; struct evdevpoll *evdp; - int i, res, timeout; - - if (opal_evsignal_deliver(&devpollop->evsigmask) == -1) - return (-1); + int i, res, timeout = -1; if (devpollop->nchanges) devpoll_commit(devpollop); - timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; + if (tv != NULL) + timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; dvp.dp_fds = devpollop->events; dvp.dp_nfds = devpollop->nevents; dvp.dp_timeout = timeout; - /* we should release the lock if we're going to enter the kernel in a multi-threaded application. However, if we're single threaded, there's really no advantage to releasing the lock and it just takes up time we could spend doing something else. */ OPAL_THREAD_UNLOCK(&opal_event_lock); - res = ioctl(devpollop->dpfd, DP_POLL, &dvp); + res = ioctl(devpollop->dpfd, DP_POLL, &dvp); OPAL_THREAD_LOCK(&opal_event_lock); - if (opal_evsignal_recalc(&devpollop->evsigmask) == -1) - return (-1); if (res == -1) { if (errno != EINTR) { @@ -252,17 +249,18 @@ devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) return (-1); } - opal_evsignal_process(); + evsignal_process(base); return (0); - } else if (opal_evsignal_caught) - opal_evsignal_process(); + } else if (base->sig.evsignal_caught) { + evsignal_process(base); + } event_debug(("%s: devpoll_wait reports %d", __func__, res)); for (i = 0; i < res; i++) { int which = 0; int what = events[i].revents; - struct opal_event *evread = NULL, *evwrite = NULL; + struct event *evread = NULL, *evwrite = NULL; assert(events[i].fd < devpollop->nfds); evdp = &devpollop->fds[events[i].fd]; @@ -286,30 +284,30 @@ devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) continue; if (evread != NULL && !(evread->ev_events & OPAL_EV_PERSIST)) - opal_event_del_i(evread); + event_del(evread); if (evwrite != NULL && evwrite != evread && !(evwrite->ev_events & OPAL_EV_PERSIST)) - opal_event_del_i(evwrite); + event_del(evwrite); if (evread != NULL) - opal_event_active_i(evread, OPAL_EV_READ, 1); + event_active(evread, OPAL_EV_READ, 1); if (evwrite != NULL) - opal_event_active_i(evwrite, OPAL_EV_WRITE, 1); + event_active(evwrite, OPAL_EV_WRITE, 1); } return (0); } -int -devpoll_add(void *arg, struct opal_event *ev) +static int +devpoll_add(void *arg, struct event *ev) { struct devpollop *devpollop = arg; struct evdevpoll *evdp; int fd, events; if (ev->ev_events & OPAL_EV_SIGNAL) - return (opal_evsignal_add(&devpollop->evsigmask, ev)); + return (evsignal_add(ev)); fd = ev->ev_fd; if (fd >= devpollop->nfds) { @@ -355,8 +353,8 @@ devpoll_add(void *arg, struct opal_event *ev) return (0); } -int -devpoll_del(void *arg, struct opal_event *ev) +static int +devpoll_del(void *arg, struct event *ev) { struct devpollop *devpollop = arg; struct evdevpoll *evdp; @@ -364,7 +362,7 @@ devpoll_del(void *arg, struct opal_event *ev) int needwritedelete = 1, needreaddelete = 1; if (ev->ev_events & OPAL_EV_SIGNAL) - return (opal_evsignal_del(&devpollop->evsigmask, ev)); + return (evsignal_del(ev)); fd = ev->ev_fd; if (fd >= devpollop->nfds) @@ -411,3 +409,22 @@ devpoll_del(void *arg, struct opal_event *ev) return (0); } + +static void +devpoll_dealloc(struct event_base *base, void *arg) +{ + struct devpollop *devpollop = arg; + + evsignal_dealloc(base); + if (devpollop->fds) + free(devpollop->fds); + if (devpollop->events) + free(devpollop->events); + if (devpollop->changes) + free(devpollop->changes); + if (devpollop->dpfd >= 0) + close(devpollop->dpfd); + + memset(devpollop, 0, sizeof(struct devpollop)); + free(devpollop); +} diff --git a/opal/event/epoll.c b/opal/event/epoll.c index d4d493932f..0bdb98c790 100644 --- a/opal/event/epoll.c +++ b/opal/event/epoll.c @@ -25,7 +25,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "opal_config.h" - #ifdef HAVE_STDINT_H #include #endif @@ -55,6 +54,7 @@ #endif #include "event.h" +#include "event-internal.h" #include "evsignal.h" #include "log.h" @@ -67,8 +67,8 @@ extern opal_mutex_t opal_event_lock; * all file descriptors outself. */ struct evepoll { - struct opal_event *evread; - struct opal_event *evwrite; + struct event *evread; + struct event *evwrite; }; struct epollop { @@ -77,22 +77,22 @@ struct epollop { struct epoll_event *events; int nevents; int epfd; - sigset_t evsigmask; }; -static void *epoll_init (void); -static int epoll_add (void *, struct opal_event *); -static int epoll_del (void *, struct opal_event *); -static int epoll_recalc (struct event_base *, void *, int); +static void *epoll_init (struct event_base *); +static int epoll_add (void *, struct event *); +static int epoll_del (void *, struct event *); static int epoll_dispatch (struct event_base *, void *, struct timeval *); +static void epoll_dealloc (struct event_base *, void *); -struct opal_eventop opal_epollops = { +struct eventop epollops = { "epoll", epoll_init, epoll_add, epoll_del, - epoll_recalc, - epoll_dispatch + epoll_dispatch, + epoll_dealloc, + 1 /* need reinit */ }; #ifdef HAVE_SETFD @@ -107,7 +107,7 @@ struct opal_eventop opal_epollops = { #define NEVENT 32000 static void * -epoll_init(void) +epoll_init(struct event_base *base) { int epfd, nfiles = NEVENT; struct rlimit rl; @@ -157,8 +157,9 @@ epoll_init(void) } epollop->nfds = nfiles; - opal_evsignal_init(&epollop->evsigmask); - +#if OPAL_EVENT_USE_SIGNALS + evsignal_init(base); +#endif return (epollop); } @@ -166,6 +167,7 @@ static int epoll_recalc(struct event_base *base, void *arg, int max) { struct epollop *epollop = arg; + if (max > epollop->nfds) { struct evepoll *fds; int nfds; @@ -185,81 +187,72 @@ epoll_recalc(struct event_base *base, void *arg, int max) epollop->nfds = nfds; } - return (opal_evsignal_recalc(&epollop->evsigmask)); + return (0); } -int +static int epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) { struct epollop *epollop = arg; struct epoll_event *events = epollop->events; struct evepoll *evep; - int i, res, timeout; + int i, res, timeout = -1; - if (opal_evsignal_deliver(&epollop->evsigmask) == -1) - return (-1); + if (tv != NULL) + timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; - timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; /* we should release the lock if we're going to enter the kernel in a multi-threaded application. However, if we're single threaded, there's really no advantage to releasing the lock and it just takes up time we could spend doing something else. */ OPAL_THREAD_UNLOCK(&opal_event_lock); - res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout); + res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout); OPAL_THREAD_LOCK(&opal_event_lock); - - if (opal_evsignal_recalc(&epollop->evsigmask) == -1) - return (-1); - + if (res == -1) { if (errno != EINTR) { event_warn("epoll_wait"); return (-1); } - - opal_evsignal_process(); +#if OPAL_EVENT_USE_SIGNALS + evsignal_process(base); +#endif return (0); - } else if (opal_evsignal_caught) - opal_evsignal_process(); + } else if (base->sig.evsignal_caught) { +#if OPAL_EVENT_USE_SIGNALS + evsignal_process(base); +#endif + } event_debug(("%s: epoll_wait reports %d", __func__, res)); for (i = 0; i < res; i++) { - int which = 0; int what = events[i].events; - struct opal_event *evread = NULL, *evwrite = NULL; + struct event *evread = NULL, *evwrite = NULL; evep = (struct evepoll *)events[i].data.ptr; - - if (what & EPOLLHUP) - what |= EPOLLIN | EPOLLOUT; - else if (what & EPOLLERR) - what |= EPOLLIN | EPOLLOUT; - if (what & EPOLLIN) { + if (what & (EPOLLHUP|EPOLLERR)) { evread = evep->evread; - which |= OPAL_EV_READ; - } - - if (what & EPOLLOUT) { evwrite = evep->evwrite; - which |= OPAL_EV_WRITE; + } else { + if (what & EPOLLIN) { + evread = evep->evread; + } + + if (what & EPOLLOUT) { + evwrite = evep->evwrite; + } } - if (!which) + if (!(evread||evwrite)) continue; - if (evread != NULL && !(evread->ev_events & OPAL_EV_PERSIST)) - opal_event_del_i(evread); - if (evwrite != NULL && evwrite != evread && - !(evwrite->ev_events & OPAL_EV_PERSIST)) - opal_event_del_i(evwrite); - if (evread != NULL) - opal_event_active_i(evread, OPAL_EV_READ, 1); + event_active(evread, EV_READ, 1); if (evwrite != NULL) - opal_event_active_i(evwrite, OPAL_EV_WRITE, 1); + event_active(evwrite, EV_WRITE, 1); } return (0); @@ -267,15 +260,17 @@ epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) static int -epoll_add(void *arg, struct opal_event *ev) +epoll_add(void *arg, struct event *ev) { struct epollop *epollop = arg; struct epoll_event epev = {0, {0}}; struct evepoll *evep; int fd, op, events; - if (ev->ev_events & OPAL_EV_SIGNAL) - return (opal_evsignal_add(&epollop->evsigmask, ev)); +#if OPAL_EVENT_USE_SIGNALS + if (ev->ev_events & EV_SIGNAL) + return (evsignal_add(ev)); +#endif fd = ev->ev_fd; if (fd >= epollop->nfds) { @@ -295,9 +290,9 @@ epoll_add(void *arg, struct opal_event *ev) op = EPOLL_CTL_MOD; } - if (ev->ev_events & OPAL_EV_READ) + if (ev->ev_events & EV_READ) events |= EPOLLIN; - if (ev->ev_events & OPAL_EV_WRITE) + if (ev->ev_events & EV_WRITE) events |= EPOLLOUT; epev.data.ptr = evep; @@ -306,16 +301,16 @@ epoll_add(void *arg, struct opal_event *ev) return (-1); /* Update events responsible */ - if (ev->ev_events & OPAL_EV_READ) + if (ev->ev_events & EV_READ) evep->evread = ev; - if (ev->ev_events & OPAL_EV_WRITE) + if (ev->ev_events & EV_WRITE) evep->evwrite = ev; return (0); } static int -epoll_del(void *arg, struct opal_event *ev) +epoll_del(void *arg, struct event *ev) { struct epollop *epollop = arg; struct epoll_event epev = {0, {0}}; @@ -323,8 +318,10 @@ epoll_del(void *arg, struct opal_event *ev) int fd, events, op; int needwritedelete = 1, needreaddelete = 1; - if (ev->ev_events & OPAL_EV_SIGNAL) - return (opal_evsignal_del(&epollop->evsigmask, ev)); +#if OPAL_EVENT_USE_SIGNALS + if (ev->ev_events & EV_SIGNAL) + return (evsignal_del(ev)); +#endif fd = ev->ev_fd; if (fd >= epollop->nfds) @@ -334,9 +331,9 @@ epoll_del(void *arg, struct opal_event *ev) op = EPOLL_CTL_DEL; events = 0; - if (ev->ev_events & OPAL_EV_READ) + if (ev->ev_events & EV_READ) events |= EPOLLIN; - if (ev->ev_events & OPAL_EV_WRITE) + if (ev->ev_events & EV_WRITE) events |= EPOLLOUT; if ((events & (EPOLLIN|EPOLLOUT)) != (EPOLLIN|EPOLLOUT)) { @@ -364,3 +361,20 @@ epoll_del(void *arg, struct opal_event *ev) return (0); } + +static void +epoll_dealloc(struct event_base *base, void *arg) +{ + struct epollop *epollop = arg; + + evsignal_dealloc(base); + if (epollop->fds) + free(epollop->fds); + if (epollop->events) + free(epollop->events); + if (epollop->epfd >= 0) + close(epollop->epfd); + + memset(epollop, 0, sizeof(struct epollop)); + free(epollop); +} diff --git a/opal/event/epoll_sub.c b/opal/event/epoll_sub.c index 4161a2313f..2009a0100b 100644 --- a/opal/event/epoll_sub.c +++ b/opal/event/epoll_sub.c @@ -25,6 +25,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "opal_config.h" + #ifdef HAVE_STDINT_H #include #endif diff --git a/opal/event/evbuffer.c b/opal/event/evbuffer.c index 0160e94d0e..aa8d7d893d 100644 --- a/opal/event/evbuffer.c +++ b/opal/event/evbuffer.c @@ -24,11 +24,14 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #include "opal_config.h" #include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #ifdef HAVE_SYS_TIME_H #include #endif @@ -41,20 +44,25 @@ #include #endif +#ifdef WIN32 +#include +#endif + +#include "evutil.h" #include "event.h" /* prototypes */ -void bufferevent_setwatermark(struct bufferevent *, short, size_t, size_t); +static void bufferevent_setwatermark(struct bufferevent *, short, size_t, size_t); static void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *); static int -bufferevent_add(struct opal_event *ev, int timeout) +bufferevent_add(struct event *ev, int timeout) { struct timeval tv, *ptv = NULL; if (timeout) { - timerclear(&tv); + evutil_timerclear(&tv); tv.tv_sec = timeout; ptv = &tv; } @@ -72,13 +80,13 @@ bufferevent_read_pressure_cb(struct evbuffer *buf, size_t old, size_t now, void *arg) { struct bufferevent *bufev = arg; /* - * If we are below the watermak then reschedule reading if it's + * If we are below the watermark then reschedule reading if it's * still enabled. */ if (bufev->wm_read.high == 0 || now < bufev->wm_read.high) { evbuffer_setcb(buf, NULL, NULL); - if (bufev->enabled & OPAL_EV_READ) + if (bufev->enabled & EV_READ) bufferevent_add(&bufev->ev_read, bufev->timeout_read); } } @@ -88,23 +96,31 @@ bufferevent_readcb(int fd, short event, void *arg) { struct bufferevent *bufev = arg; int res = 0; - short what = OPAL_EVBUFFER_READ; + short what = EVBUFFER_READ; size_t len; + int howmuch = -1; - if (event == OPAL_EV_TIMEOUT) { - what |= OPAL_EVBUFFER_TIMEOUT; + if (event == EV_TIMEOUT) { + what |= EVBUFFER_TIMEOUT; goto error; } - res = evbuffer_read(bufev->input, fd, -1); + /* + * If we have a high watermark configured then we don't want to + * read more data than would make us reach the watermark. + */ + if (bufev->wm_read.high != 0) + howmuch = bufev->wm_read.high; + + res = evbuffer_read(bufev->input, fd, howmuch); if (res == -1) { if (errno == EAGAIN || errno == EINTR) goto reschedule; /* error case */ - what |= OPAL_EVBUFFER_ERROR; + what |= EVBUFFER_ERROR; } else if (res == 0) { /* eof case */ - what |= OPAL_EVBUFFER_EOF; + what |= EVBUFFER_EOF; } if (res <= 0) @@ -113,7 +129,7 @@ bufferevent_readcb(int fd, short event, void *arg) bufferevent_add(&bufev->ev_read, bufev->timeout_read); /* See if this callbacks meets the water marks */ - len = OPAL_EVBUFFER_LENGTH(bufev->input); + len = EVBUFFER_LENGTH(bufev->input); if (bufev->wm_read.low != 0 && len < bufev->wm_read.low) return; if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) { @@ -126,7 +142,8 @@ bufferevent_readcb(int fd, short event, void *arg) } /* Invoke the user callback - must always be called last */ - (*bufev->readcb)(bufev, bufev->cbarg); + if (bufev->readcb != NULL) + (*bufev->readcb)(bufev, bufev->cbarg); return; reschedule: @@ -142,44 +159,53 @@ bufferevent_writecb(int fd, short event, void *arg) { struct bufferevent *bufev = arg; int res = 0; - short what = OPAL_EVBUFFER_WRITE; + short what = EVBUFFER_WRITE; - if (event == OPAL_EV_TIMEOUT) { - what |= OPAL_EVBUFFER_TIMEOUT; + if (event == EV_TIMEOUT) { + what |= EVBUFFER_TIMEOUT; goto error; } - if (OPAL_EVBUFFER_LENGTH(bufev->output)) { + if (EVBUFFER_LENGTH(bufev->output)) { res = evbuffer_write(bufev->output, fd); if (res == -1) { +#ifndef WIN32 +/*todo. evbuffer uses WriteFile when WIN32 is set. WIN32 system calls do not + *set errno. thus this error checking is not portable*/ if (errno == EAGAIN || errno == EINTR || errno == EINPROGRESS) goto reschedule; /* error case */ - what |= OPAL_EVBUFFER_ERROR; + what |= EVBUFFER_ERROR; + +#else + goto reschedule; +#endif + } else if (res == 0) { /* eof case */ - what |= OPAL_EVBUFFER_EOF; + what |= EVBUFFER_EOF; } if (res <= 0) goto error; } - if (OPAL_EVBUFFER_LENGTH(bufev->output) != 0) + if (EVBUFFER_LENGTH(bufev->output) != 0) bufferevent_add(&bufev->ev_write, bufev->timeout_write); /* * Invoke the user callback if our buffer is drained or below the * low watermark. */ - if (OPAL_EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low) + if (bufev->writecb != NULL && + EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low) (*bufev->writecb)(bufev, bufev->cbarg); return; reschedule: - if (OPAL_EVBUFFER_LENGTH(bufev->output) != 0) + if (EVBUFFER_LENGTH(bufev->output) != 0) bufferevent_add(&bufev->ev_write, bufev->timeout_write); return; @@ -193,6 +219,9 @@ bufferevent_writecb(int fd, short event, void *arg) * The read callback is invoked whenever we read new data. * The write callback is invoked whenever the output buffer is drained. * The error callback is invoked on a write/read error or on EOF. + * + * Both read and write callbacks maybe NULL. The error callback is not + * allowed to be NULL and have to be provided always. */ struct bufferevent * @@ -215,8 +244,8 @@ bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb, return (NULL); } - opal_event_set(&bufev->ev_read, fd, OPAL_EV_READ, bufferevent_readcb, bufev); - opal_event_set(&bufev->ev_write, fd, OPAL_EV_WRITE, bufferevent_writecb, bufev); + event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev); + event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev); bufev->readcb = readcb; bufev->writecb = writecb; @@ -224,7 +253,12 @@ bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb, bufev->cbarg = cbarg; - bufev->enabled = OPAL_EV_READ | OPAL_EV_WRITE; + /* + * Set to EV_WRITE so that using bufferevent_write is going to + * trigger a callback. Reading needs to be explicitly enabled + * because otherwise no data will be available. + */ + bufev->enabled = EV_WRITE; return (bufev); } @@ -232,9 +266,9 @@ bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb, int bufferevent_priority_set(struct bufferevent *bufev, int priority) { - if (opal_event_priority_set(&bufev->ev_read, priority) == -1) + if (event_priority_set(&bufev->ev_read, priority) == -1) return (-1); - if (opal_event_priority_set(&bufev->ev_write, priority) == -1) + if (event_priority_set(&bufev->ev_write, priority) == -1) return (-1); return (0); @@ -245,8 +279,8 @@ bufferevent_priority_set(struct bufferevent *bufev, int priority) void bufferevent_free(struct bufferevent *bufev) { - opal_event_del(&bufev->ev_read); - opal_event_del(&bufev->ev_write); + event_del(&bufev->ev_read); + event_del(&bufev->ev_write); evbuffer_free(bufev->input); evbuffer_free(bufev->output); @@ -260,7 +294,7 @@ bufferevent_free(struct bufferevent *bufev) */ int -bufferevent_write(struct bufferevent *bufev, void *data, size_t size) +bufferevent_write(struct bufferevent *bufev, const void *data, size_t size) { int res; @@ -270,7 +304,7 @@ bufferevent_write(struct bufferevent *bufev, void *data, size_t size) return (res); /* If everything is okay, we need to schedule a write */ - if (size > 0 && (bufev->enabled & OPAL_EV_WRITE)) + if (size > 0 && (bufev->enabled & EV_WRITE)) bufferevent_add(&bufev->ev_write, bufev->timeout_write); return (res); @@ -308,11 +342,11 @@ bufferevent_read(struct bufferevent *bufev, void *data, size_t size) int bufferevent_enable(struct bufferevent *bufev, short event) { - if (event & OPAL_EV_READ) { + if (event & EV_READ) { if (bufferevent_add(&bufev->ev_read, bufev->timeout_read) == -1) return (-1); } - if (event & OPAL_EV_WRITE) { + if (event & EV_WRITE) { if (bufferevent_add(&bufev->ev_write, bufev->timeout_write) == -1) return (-1); } @@ -324,12 +358,12 @@ bufferevent_enable(struct bufferevent *bufev, short event) int bufferevent_disable(struct bufferevent *bufev, short event) { - if (event & OPAL_EV_READ) { - if (opal_event_del(&bufev->ev_read) == -1) + if (event & EV_READ) { + if (event_del(&bufev->ev_read) == -1) return (-1); } - if (event & OPAL_EV_WRITE) { - if (opal_event_del(&bufev->ev_write) == -1) + if (event & EV_WRITE) { + if (event_del(&bufev->ev_write) == -1) return (-1); } @@ -356,17 +390,30 @@ void bufferevent_setwatermark(struct bufferevent *bufev, short events, size_t lowmark, size_t highmark) { - if (events & OPAL_EV_READ) { + if (events & EV_READ) { bufev->wm_read.low = lowmark; bufev->wm_read.high = highmark; } - if (events & OPAL_EV_WRITE) { + if (events & EV_WRITE) { bufev->wm_write.low = lowmark; bufev->wm_write.high = highmark; } /* If the watermarks changed then see if we should call read again */ bufferevent_read_pressure_cb(bufev->input, - 0, OPAL_EVBUFFER_LENGTH(bufev->input), bufev); + 0, EVBUFFER_LENGTH(bufev->input), bufev); +} + +int +bufferevent_base_set(struct event_base *base, struct bufferevent *bufev) +{ + int res; + + res = event_base_set(base, &bufev->ev_read); + if (res == -1) + return (res); + + res = event_base_set(base, &bufev->ev_write); + return (res); } diff --git a/opal/event/event-config.h b/opal/event/event-config.h new file mode 100644 index 0000000000..4dc7f0fb71 --- /dev/null +++ b/opal/event/event-config.h @@ -0,0 +1,262 @@ +/* event-config.h + * Generated by autoconf; post-processed by libevent. + * Do not edit this file. + * Do not rely on macros in this file existing in later versions. + */ +#ifndef _EVENT_CONFIG_H_ +#define _EVENT_CONFIG_H_ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define if clock_gettime is available in libc */ +/* #undef _EVENT_DNS_USE_CPU_CLOCK_FOR_ID */ + +/* Define is no secure id variant is available */ +#define _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID 1 + +/* Define to 1 if you have the `clock_gettime' function. */ +/* #undef _EVENT_HAVE_CLOCK_GETTIME */ + +/* Define if /dev/poll is available */ +/* #undef _EVENT_HAVE_DEVPOLL */ + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_DLFCN_H 1 + +/* Define if your system supports the epoll system calls */ +/* #undef _EVENT_HAVE_EPOLL */ + +/* Define to 1 if you have the `epoll_ctl' function. */ +/* #undef _EVENT_HAVE_EPOLL_CTL */ + +/* Define if your system supports event ports */ +/* #undef _EVENT_HAVE_EVENT_PORTS */ + +/* Define to 1 if you have the `fcntl' function. */ +#define _EVENT_HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `getaddrinfo' function. */ +#define _EVENT_HAVE_GETADDRINFO 1 + +/* Define to 1 if you have the `getnameinfo' function. */ +#define _EVENT_HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define _EVENT_HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `inet_ntop' function. */ +#define _EVENT_HAVE_INET_NTOP 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `kqueue' function. */ +#define _EVENT_HAVE_KQUEUE 1 + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +/* #undef _EVENT_HAVE_LIBNSL */ + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#define _EVENT_HAVE_LIBRESOLV 1 + +/* Define to 1 if you have the `rt' library (-lrt). */ +/* #undef _EVENT_HAVE_LIBRT */ + +/* Define to 1 if you have the `socket' library (-lsocket). */ +/* #undef _EVENT_HAVE_LIBSOCKET */ + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef _EVENT_HAVE_NETINET_IN6_H */ + +/* Define to 1 if you have the `poll' function. */ +#define _EVENT_HAVE_POLL 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_POLL_H 1 + +/* Define to 1 if you have the `port_create' function. */ +/* #undef _EVENT_HAVE_PORT_CREATE */ + +/* Define to 1 if you have the header file. */ +/* #undef _EVENT_HAVE_PORT_H */ + +/* Define to 1 if you have the `select' function. */ +#define _EVENT_HAVE_SELECT 1 + +/* Define if F_SETFD is defined in */ +#define _EVENT_HAVE_SETFD 1 + +/* Define to 1 if you have the `sigaction' function. */ +#define _EVENT_HAVE_SIGACTION 1 + +/* Define to 1 if you have the `signal' function. */ +#define _EVENT_HAVE_SIGNAL 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcpy' function. */ +#define _EVENT_HAVE_STRLCPY 1 + +/* Define to 1 if you have the `strsep' function. */ +#define _EVENT_HAVE_STRSEP 1 + +/* Define to 1 if you have the `strtok_r' function. */ +#define _EVENT_HAVE_STRTOK_R 1 + +/* Define to 1 if you have the `strtoll' function. */ +#define _EVENT_HAVE_STRTOLL 1 + +/* Define to 1 if the system has the type `struct in6_addr'. */ +#define _EVENT_HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if you have the header file. */ +/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef _EVENT_HAVE_SYS_EPOLL_H */ + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_EVENT_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_QUEUE_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_SYS_TYPES_H 1 + +/* Define if TAILQ_FOREACH is defined in */ +#define _EVENT_HAVE_TAILQFOREACH 1 + +/* Define if timeradd is defined in */ +#define _EVENT_HAVE_TIMERADD 1 + +/* Define if timerclear is defined in */ +#define _EVENT_HAVE_TIMERCLEAR 1 + +/* Define if timercmp is defined in */ +#define _EVENT_HAVE_TIMERCMP 1 + +/* Define if timerisset is defined in */ +#define _EVENT_HAVE_TIMERISSET 1 + +/* Define to 1 if the system has the type `uint16_t'. */ +#define _EVENT_HAVE_UINT16_T 1 + +/* Define to 1 if the system has the type `uint32_t'. */ +#define _EVENT_HAVE_UINT32_T 1 + +/* Define to 1 if the system has the type `uint64_t'. */ +#define _EVENT_HAVE_UINT64_T 1 + +/* Define to 1 if the system has the type `uint8_t'. */ +#define _EVENT_HAVE_UINT8_T 1 + +/* Define to 1 if you have the header file. */ +#define _EVENT_HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `vasprintf' function. */ +#define _EVENT_HAVE_VASPRINTF 1 + +/* Define if kqueue works correctly with pipes */ +#define _EVENT_HAVE_WORKING_KQUEUE 1 + +/* Name of package */ +#define _EVENT_PACKAGE "libevent" + +/* Define to the address where bug reports for this package should be sent. */ +#define _EVENT_PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define _EVENT_PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define _EVENT_PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define _EVENT_PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define _EVENT_PACKAGE_VERSION "" + +/* The size of `int', as computed by sizeof. */ +#define _EVENT_SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define _EVENT_SIZEOF_LONG 4 + +/* The size of `long long', as computed by sizeof. */ +#define _EVENT_SIZEOF_LONG_LONG 8 + +/* The size of `short', as computed by sizeof. */ +#define _EVENT_SIZEOF_SHORT 2 + +/* Define to 1 if you have the ANSI C header files. */ +#define _EVENT_STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define _EVENT_TIME_WITH_SYS_TIME 1 + +/* Version number of package */ +#define _EVENT_VERSION "1.4.2-rc" + +/* Define to appropriate substitue if compiler doesnt have __func__ */ +/* #undef _EVENT___func__ */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef _EVENT_const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef _EVENT___cplusplus +/* #undef _EVENT_inline */ +#endif + +/* Define to `int' if does not define. */ +/* #undef _EVENT_pid_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef _EVENT_size_t */ + +/* Define to unsigned int if you dont have it */ +/* #undef _EVENT_socklen_t */ +#endif diff --git a/opal/event/event-internal.h b/opal/event/event-internal.h index ec9a9c93fb..03c2358854 100644 --- a/opal/event/event-internal.h +++ b/opal/event/event-internal.h @@ -31,24 +31,64 @@ extern "C" { #endif +#include "opal_config.h" +#include "min_heap.h" +#include "evsignal.h" + +struct eventop { + const char *name; + void *(*init)(struct event_base *); + int (*add)(void *, struct event *); + int (*del)(void *, struct event *); + int (*dispatch)(struct event_base *, void *, struct timeval *); + void (*dealloc)(struct event_base *, void *); + /* set if we need to reinitialize the event base */ + int need_reinit; +}; + struct event_base { - const struct opal_eventop *evsel; + const struct eventop *evsel; void *evbase; int event_count; /* counts number of total events */ int event_count_active; /* counts number of active events */ int event_gotterm; /* Set to terminate loop */ + int event_break; /* Set to terminate loop immediately */ /* active event management */ - struct opal_event_list **activequeues; + struct event_list **activequeues; int nactivequeues; - struct opal_event_list eventqueue; + /* signal handling info */ + struct evsignal_info sig; + + struct event_list eventqueue; struct timeval event_tv; - RB_HEAD(opal_event_tree, opal_event) timetree; + struct min_heap timeheap; }; +/* Internal use only: Functions that might be missing from */ +#ifndef HAVE_TAILQFOREACH +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) +#endif /* TAILQ_FOREACH */ + +int _evsignal_set_handler(struct event_base *base, int evsignal, + void (*fn)(int)); +int _evsignal_restore_handler(struct event_base *base, int evsignal); + #ifdef __cplusplus } #endif diff --git a/opal/event/event.c b/opal/event/event.c index 826f008c0d..daa7db2259 100644 --- a/opal/event/event.c +++ b/opal/event/event.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2008 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2000-2004 Niels Provos * All rights reserved. * @@ -24,13 +25,18 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #include "opal_config.h" - #ifdef HAVE_SYS_TYPES_H #include #endif -#include + + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include "misc.h" +#endif #ifdef HAVE_SYS_TIME_H #include #else @@ -42,12 +48,16 @@ #include #include #include +#ifndef WIN32 #ifdef HAVE_UNISTD_H #include #endif +#endif #include +#include #include #include +#include #include "opal/event/event.h" #include "opal/class/opal_object.h" @@ -55,95 +65,116 @@ #include "opal/threads/threads.h" #include "opal/util/output.h" #include "opal/constants.h" +#include "opal/util/argv.h" +#include "opal/mca/base/mca_base_param.h" + #include "event-internal.h" +#include "evutil.h" #include "log.h" +#if defined(HAVE_EVENT_PORTS) && HAVE_EVENT_PORTS +extern const struct eventop evportops; +#endif #if defined(HAVE_SELECT) && HAVE_SELECT -extern const struct opal_eventop opal_selectops; +extern const struct eventop selectops; #endif - #if defined(HAVE_POLL) && HAVE_POLL && HAVE_WORKING_POLL -extern const struct opal_eventop opal_pollops; +extern const struct eventop pollops; #endif - -#if defined(HAVE_RTSIG) && HAVE_RTSIG -extern const struct opal_eventop opal_rtsigops; -#endif - #if defined(HAVE_EPOLL) && HAVE_EPOLL -extern const struct opal_eventop opal_epollops; +extern const struct eventop epollops; #endif - #if defined(HAVE_WORKING_KQUEUE) && HAVE_WORKING_KQUEUE -extern const struct opal_eventop opal_kqops; +extern const struct eventop kqops; #endif - #ifdef HAVE_DEVPOLL -extern const struct opal_eventop devpollops; +extern const struct eventop devpollops; +#endif +#ifdef WIN32 +extern const struct eventop win32ops; #endif /* In order of preference */ -static const struct opal_eventop *eventops[] = { -#if 0 /* no KQUEUE or EPOLL support for us -- neither seem to work - right */ -#if HAVE_WORKING_KQUEUE - &opal_kqops, +const struct eventop *eventops[] = { +#if defined(HAVE_EVENT_PORTS) && HAVE_EVENT_PORTS + &evportops, #endif -#if HAVE_EPOLL - &opal_epollops, +#if defined(HAVE_WORKING_KQUEUE) && HAVE_WORKING_KQUEUE + &kqops, #endif +#if defined(HAVE_EPOLL) && HAVE_EPOLL + &epollops, #endif -#if 0 /* Sun reports /dev/poll borks up on 2 nodes with new Solaris */ -#ifdef HAVE_DEVPOLL +#if defined(HAVE_DEVPOLL) && HAVE_DEVPOLL &devpollops, #endif -#endif -#if 0 /* no RTSIGS support for us */ -#if HAVE_RTSIG - &opal_rtsigops, -#endif -#endif /* #if 0 -- no RTSIGS support for us */ #if defined(HAVE_POLL) && HAVE_POLL && HAVE_WORKING_POLL - &opal_pollops, + &pollops, #endif #if defined(HAVE_SELECT) && HAVE_SELECT - &opal_selectops, + &selectops, +#endif +#ifdef WIN32 + &win32ops, #endif - /** - * One of the most stupid comment in the libevent project. Why ? How ? - * - * This is to prevent event library from picking up the - * win32_ops since this will be picked up over select(). By - * using select, we can pretty much use the OOB and PTL as - * is. Otherwise, there would have to be a lot of magic to be - * done to get this to work - */ -#if defined(__WINDOWS__) - &opal_win32ops, -#endif /* defined(__WINDOWS__) */ NULL }; /* Global state */ -struct opal_event_list opal_signalqueue; - struct event_base *current_base = NULL; +extern struct event_base *evsignal_base; +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) +static int use_monotonic; +#endif /* defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) */ /* Handle signals - This is a deprecated interface */ -int (*event_sigcb)(void); /* Signal callback when gotsig is set */ -volatile int event_gotsig; /* Set in signal handler */ +int (*event_sigcb)(void); /* Signal callback when gotsig is set */ +volatile sig_atomic_t event_gotsig; /* Set in signal handler */ /* Prototypes */ +static void event_queue_insert(struct event_base *, struct event *, int); +static void event_queue_remove(struct event_base *, struct event *, int); +static int event_haveevents(struct event_base *); -static void opal_event_queue_insert(struct event_base *, struct opal_event *, int); -static void opal_event_queue_remove(struct event_base *, struct opal_event *, int); -static int opal_event_haveevents(struct event_base *); +static void event_process_active(struct event_base *); -static void opal_event_process_active(struct event_base *); - -static int timeout_next(struct event_base *, struct timeval *); +static int timeout_next(struct event_base *, struct timeval **); static void timeout_process(struct event_base *); +#if 0 +/* Let's not delete this yet */ static void timeout_correct(struct event_base *, struct timeval *); +#endif + +static void +detect_monotonic(void) +{ +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + use_monotonic = 1; +#endif +} + +static int +gettime(struct timeval *tp) +{ +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + struct timespec ts; + + if (use_monotonic) { + if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) + return (-1); + + tp->tv_sec = ts.tv_sec; + tp->tv_usec = ts.tv_nsec / 1000; + return (0); + } +#endif + + return (gettimeofday(tp, NULL)); +} + OPAL_DECLSPEC opal_mutex_t opal_event_lock; static int opal_event_inited = 0; @@ -163,39 +194,20 @@ bool opal_event_progress_thread(void) return true; #endif } - -static int -compare(struct opal_event *a, struct opal_event *b) -{ - if (timercmp(&a->ev_timeout, &b->ev_timeout, <)) - return (-1); - else if (timercmp(&a->ev_timeout, &b->ev_timeout, >)) - return (1); - if (a < b) - return (-1); - else if (a > b) - return (1); - return (0); -} - -static RB_PROTOTYPE(opal_event_tree, opal_event, ev_timeout_node, compare) - -static RB_GENERATE(opal_event_tree, opal_event, ev_timeout_node, compare) - #if OMPI_ENABLE_PROGRESS_THREADS /* run loop for dispatch thread */ static void* opal_event_run(opal_object_t* arg) { /* Open MPI: Prevent compiler warnings about unused variables */ #if defined(NDEBUG) - opal_event_loop(0); + event_loop(0); #else - int rc = opal_event_loop(0); + int rc = event_loop(0); assert(rc >= 0); #endif opal_mutex_lock(&opal_event_lock); - opal_event_del_i(&opal_event_pipe_event); + event_del(&opal_event_pipe_event); close(opal_event_pipe[0]); close(opal_event_pipe[1]); opal_event_pipe[0] = -1; @@ -218,56 +230,106 @@ static void opal_event_pipe_handler(int sd, short flags, void* user) } #endif /* OMPI_ENABLE_PROGRESS_THREADS */ +static char** opal_event_module_include = NULL; + +static int opal_event_allow_system( const char* eventop_name) +{ + char** argv = opal_event_module_include; + + /* if the user specified an event interface - use these exclusively */ + while(argv && *argv) { + if( 0 == strcmp(*argv, "all") ) return 1; /* all match */ + if( 0 == strcmp(*argv, eventop_name) ) return 1; + argv++; + } + return 0; +} + int opal_event_init(void) { - int i; - if(opal_event_inited++ != 0) - return OPAL_SUCCESS; + struct event_base *base; + char* event_module_include; + + if(opal_event_inited++ != 0) + return OPAL_SUCCESS; #if OPAL_HAVE_WORKING_EVENTOPS - if ((current_base = (struct event_base*)calloc(1, sizeof(struct event_base))) == NULL) - event_err(1, "%s: calloc"); + /** + * Retrieve the upper level specified event system, if any. + */ + mca_base_param_reg_string_name("opal", "event_include", + "Comma-delimited list of libevent subsystems to use (kqueue, devpoll, epoll, poll, select, and rtsig)", + false, false, "all", &event_module_include); + if (NULL == event_module_include) { + /* Shouldn't happen, but... */ + event_module_include = strdup("all"); + } + opal_event_module_include = opal_argv_split(event_module_include,','); + free(event_module_include); + + base = event_base_new(); + OBJ_CONSTRUCT(&opal_event_lock, opal_mutex_t); + if (base != NULL) + opal_current_base = base; + opal_event_enable(); +#endif + return OPAL_SUCCESS; +} + + +struct event_base * +event_base_new(void) +{ + int i; + struct event_base *base; + + if ((base = calloc(1, sizeof(struct event_base))) == NULL) + event_err(1, "%s: calloc", __func__); event_sigcb = NULL; event_gotsig = 0; - gettimeofday(¤t_base->event_tv, NULL); - OBJ_CONSTRUCT(&opal_event_lock, opal_mutex_t); + detect_monotonic(); + gettime(&base->event_tv); + + min_heap_ctor(&base->timeheap); + TAILQ_INIT(&base->eventqueue); + TAILQ_INIT(&base->sig.signalqueue); + base->sig.ev_signal_pair[0] = -1; + base->sig.ev_signal_pair[1] = -1; + + base->evbase = NULL; + for (i = 0; eventops[i] && !base->evbase; i++) { + /* Allow only the user selected event mechanisms to be initialized */ + if( !opal_event_allow_system(eventops[i]->name) ) continue; + base->evsel = eventops[i]; - RB_INIT(¤t_base->timetree); - TAILQ_INIT(¤t_base->eventqueue); - TAILQ_INIT(&opal_signalqueue); - - current_base->evbase = NULL; - for (i = 0; eventops[i] && !current_base->evbase; i++) { - current_base->evsel = eventops[i]; - - current_base->evbase = current_base->evsel->init(); + base->evbase = base->evsel->init(base); } - if (current_base->evbase == NULL) + if (base->evbase == NULL) event_errx(1, "%s: no event mechanism available", __func__); if (getenv("EVENT_SHOW_METHOD")) event_msgx("libevent using: %s\n", - current_base->evsel->name); + base->evsel->name); /* allocate a single active event queue */ - opal_event_base_priority_init(current_base, 1); + event_base_priority_init(base, 1); - opal_event_enable(); -#endif /* HAVE_WORKING_EVENTOPS */ - - return OPAL_SUCCESS; + return (base); } int opal_event_fini(void) { - opal_event_disable(); - opal_event_inited--; - return OPAL_SUCCESS; + opal_event_disable(); + opal_event_inited--; + if (NULL != opal_event_module_include) { + opal_argv_free(opal_event_module_include); + } + return OPAL_SUCCESS; } int opal_event_enable(void) @@ -290,13 +352,13 @@ int opal_event_enable(void) } opal_event_pipe_signalled = 1; - opal_event_set( + event_set( &opal_event_pipe_event, opal_event_pipe[0], - OPAL_EV_READ|OPAL_EV_PERSIST, + EV_READ|EV_PERSIST, opal_event_pipe_handler, 0); - opal_event_add_i(&opal_event_pipe_event, 0); + event_add(&opal_event_pipe_event, 0); opal_event_pipe_signalled = 0; /* spin up a thread to dispatch events */ @@ -351,11 +413,10 @@ int opal_event_disable(void) int opal_event_restart(void) { #if OPAL_HAVE_WORKING_EVENTOPS && !defined(__WINDOWS__) - int rc; #if OMPI_ENABLE_PROGRESS_THREADS opal_mutex_lock(&opal_event_lock); if(opal_event_pipe[0] >= 0) { - opal_event_del_i(&opal_event_pipe_event); + event_del(&opal_event_pipe_event); /* do not close pipes - in case of bproc_vrfork they are not open * and we may close something else */ @@ -367,26 +428,98 @@ int opal_event_restart(void) #endif opal_event_enable(); -#if !defined(__WINDOWS__) - if((rc = opal_evsignal_restart()) != 0) - return OPAL_ERROR; -#endif /* defined(__WINDOWS__) */ return (OPAL_SUCCESS); #else /* OPAL_HAVE_WORKING_EVENTOPS */ return OPAL_ERR_NOT_SUPPORTED; #endif } -int -opal_event_priority_init(int npriorities) +void +event_base_free(struct event_base *base) { - return opal_event_base_priority_init(current_base, npriorities); + int i, n_deleted=0; + struct event *ev; + + if (base == NULL && current_base) + base = current_base; + if (base == current_base) + current_base = NULL; + + /* XXX(niels) - check for internal events first */ + assert(base); + /* Delete all non-internal events. */ + for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) { + struct event *next = TAILQ_NEXT(ev, ev_next); + if (!(ev->ev_flags & EVLIST_INTERNAL)) { + opal_event_del(ev); + ++n_deleted; + } + ev = next; + } + while ((ev = min_heap_top(&base->timeheap)) != NULL) { + opal_event_del(ev); + ++n_deleted; + } + + if (n_deleted) + event_debug(("%s: %d events were still set in base", + __func__, n_deleted)); + + if (base->evsel->dealloc != NULL) + base->evsel->dealloc(base, base->evbase); + + for (i = 0; i < base->nactivequeues; ++i) + assert(TAILQ_EMPTY(base->activequeues[i])); + + assert(min_heap_empty(&base->timeheap)); + min_heap_dtor(&base->timeheap); + + for (i = 0; i < base->nactivequeues; ++i) + free(base->activequeues[i]); + free(base->activequeues); + + assert(TAILQ_EMPTY(&base->eventqueue)); + + free(base); +} + +/* reinitialized the event base after a fork */ +int +event_reinit(struct event_base *base) +{ + const struct eventop *evsel = base->evsel; + void *evbase = base->evbase; + int res = 0; + struct event *ev; + + /* check if this event mechanism requires reinit */ + if (!evsel->need_reinit) + return (0); + + if (base->evsel->dealloc != NULL) + base->evsel->dealloc(base, base->evbase); + base->evbase = evsel->init(base); + if (base->evbase == NULL) + event_errx(1, "%s: could not reinitialize event mechanism", + __func__); + + TAILQ_FOREACH(ev, &base->eventqueue, ev_next) { + if (evsel->add(evbase, ev) == -1) + res = -1; + } + + return (res); } int -opal_event_base_priority_init(struct event_base *base, int npriorities) +event_priority_init(int npriorities) +{ + return event_base_priority_init(current_base, npriorities); +} + +int +event_base_priority_init(struct event_base *base, int npriorities) { -#if OPAL_HAVE_WORKING_EVENTOPS int i; if (base->event_count_active) @@ -401,29 +534,25 @@ opal_event_base_priority_init(struct event_base *base, int npriorities) /* Allocate our priority queues */ base->nactivequeues = npriorities; - base->activequeues = (struct opal_event_list **)calloc(base->nactivequeues, - npriorities * sizeof(struct opal_event_list *)); + base->activequeues = (struct event_list **)calloc(base->nactivequeues, + npriorities * sizeof(struct event_list *)); if (base->activequeues == NULL) event_err(1, "%s: calloc", __func__); for (i = 0; i < base->nactivequeues; ++i) { - base->activequeues[i] = (struct opal_event_list*)malloc(sizeof(struct opal_event_list)); + base->activequeues[i] = malloc(sizeof(struct event_list)); if (base->activequeues[i] == NULL) event_err(1, "%s: malloc", __func__); TAILQ_INIT(base->activequeues[i]); } -#endif + return (0); } int -opal_event_haveevents(struct event_base *base) +event_haveevents(struct event_base *base) { -#if OPAL_HAVE_WORKING_EVENTOPS return (base->event_count > 0); -#else - return 0; -#endif } /* @@ -433,17 +562,13 @@ opal_event_haveevents(struct event_base *base) */ static void -opal_event_process_active(struct event_base *base) +event_process_active(struct event_base *base) { -#if OPAL_HAVE_WORKING_EVENTOPS - struct opal_event *ev; - struct opal_event_list *activeq = NULL; + struct event *ev; + struct event_list *activeq = NULL; int i; short ncalls; - if (!base->event_count_active) - return; - for (i = 0; i < base->nactivequeues; ++i) { if (TAILQ_FIRST(base->activequeues[i]) != NULL) { activeq = base->activequeues[i]; @@ -451,9 +576,14 @@ opal_event_process_active(struct event_base *base) } } - for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) { - opal_event_queue_remove(base, ev, OPAL_EVLIST_ACTIVE); + assert(activeq != NULL); + for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) { + if (ev->ev_events & EV_PERSIST) + event_queue_remove(base, ev, EVLIST_ACTIVE); + else + event_del(ev); + /* Allows deletes to work */ ncalls = ev->ev_ncalls; ev->ev_pncalls = &ncalls; @@ -461,11 +591,12 @@ opal_event_process_active(struct event_base *base) ncalls--; ev->ev_ncalls = ncalls; OPAL_THREAD_UNLOCK(&opal_event_lock); - (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg); - OPAL_THREAD_LOCK(&opal_event_lock); + (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg); + OPAL_THREAD_LOCK(&opal_event_lock); + if (event_gotsig || base->event_break) + return; } } -#endif } /* @@ -473,81 +604,108 @@ opal_event_process_active(struct event_base *base) */ int -opal_event_dispatch(void) +event_dispatch(void) { - return (opal_event_loop(0)); + return (event_loop(0)); } int -opal_event_base_dispatch(struct event_base *event_base) +event_base_dispatch(struct event_base *event_base) { - return (opal_event_base_loop(event_base, 0)); + return (event_base_loop(event_base, 0)); +} + +const char * +event_base_get_method(struct event_base *base) +{ + assert(base); + return (base->evsel->name); } static void event_loopexit_cb(int fd, short what, void *arg) { #if OPAL_HAVE_WORKING_EVENTOPS - struct event_base *base = (struct event_base*)arg; + struct event_base *base = arg; base->event_gotterm = 1; #endif /* OPAL_HAVE_WORKING_EVENTOPS */ } /* not thread safe */ - int -opal_event_loopexit(struct timeval *tv) +event_loopexit(struct timeval *tv) { - return (opal_event_once(-1, OPAL_EV_TIMEOUT, event_loopexit_cb, - current_base, tv)); + return (event_once(-1, EV_TIMEOUT, event_loopexit_cb, + current_base, tv)); } int event_base_loopexit(struct event_base *event_base, struct timeval *tv) { - return (opal_event_once(-1, OPAL_EV_TIMEOUT, event_loopexit_cb, + return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb, event_base, tv)); } /* not thread safe */ - int -opal_event_loop(int flags) +event_loopbreak(void) { - return opal_event_base_loop(current_base, flags); + return (event_base_loopbreak(current_base)); } int -opal_event_base_loop(struct event_base *base, int flags) +event_base_loopbreak(struct event_base *event_base) +{ + if (event_base == NULL) + return (-1); + + event_base->event_break = 1; + return (0); +} + + + +/* not thread safe */ + +int +event_loop(int flags) +{ + return event_base_loop(current_base, flags); +} + +int +event_base_loop(struct event_base *base, int flags) { #if OPAL_HAVE_WORKING_EVENTOPS - const struct opal_eventop *evsel = base->evsel; + const struct eventop *evsel = base->evsel; void *evbase = base->evbase; struct timeval tv; + struct timeval *tv_p; int res, done; #endif /* OPAL_HAVE_WORKING_EVENTOPS */ - if (opal_event_inited == false) + if (opal_event_inited == false) return(0); #if OPAL_HAVE_WORKING_EVENTOPS res = OPAL_THREAD_TRYLOCK(&opal_event_lock); if (0 != res) return 0; - + + if(!TAILQ_EMPTY(&base->sig.signalqueue)) + evsignal_base = base; done = 0; while (!done && opal_event_enabled) { - /* Calculate the initial events that we are waiting for */ - if (evsel->recalc(base, evbase, 0) == -1) { - OPAL_THREAD_UNLOCK(&opal_event_lock); - return (-1); - } - /* Terminate the loop if we have been asked to */ if (base->event_gotterm) { base->event_gotterm = 0; break; } + if (base->event_break) { + base->event_break = 0; + break; + } + /* You cannot use this interface for multi-threaded apps */ while (event_gotsig) { event_gotsig = 0; @@ -555,72 +713,76 @@ opal_event_base_loop(struct event_base *base, int flags) res = (*event_sigcb)(); if (res == -1) { errno = EINTR; - OPAL_THREAD_UNLOCK(&opal_event_lock); - return (-1); + OPAL_THREAD_UNLOCK(&opal_event_lock); + return (-1); } } } -#if !defined(__WINDOWS__) - /* Check if time is running backwards */ - gettimeofday(&tv, NULL); - if (timercmp(&tv, &base->event_tv, <)) { - struct timeval off; - event_debug(("%s: time is running backwards, corrected", - __func__)); - timersub(&base->event_tv, &tv, &off); - timeout_correct(base, &off); - } - base->event_tv = tv; -#endif /* !defined(__WINDOWS__) */ - if (!base->event_count_active && !(flags & OPAL_EVLOOP_NONBLOCK)) - timeout_next(base, &tv); - else - timerclear(&tv); +#if 0 + /* OMPI: George wants to comment this out for now */ + OPAL_THREAD_UNLOCK(&opal_event_lock); + timeout_correct(base, &tv); +#endif + + tv_p = &tv; + if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) { + timeout_next(base, &tv_p); + } else { + /* + * if we have active events, we just poll new events + * without waiting. + */ + evutil_timerclear(&tv); + } + /* If we have no events, we just exit */ - if (!opal_event_haveevents(base)) { - OPAL_THREAD_UNLOCK(&opal_event_lock); - event_debug(("%s: no events registered.", __func__)); - return (1); + if (!event_haveevents(base)) { + OPAL_THREAD_UNLOCK(&opal_event_lock); + event_debug(("%s: no events registered.", __func__)); + return (1); } #if OMPI_ENABLE_PROGRESS_THREADS opal_event_pipe_signalled = 0; #endif - res = evsel->dispatch(base, evbase, &tv); + + res = evsel->dispatch(base, evbase, tv_p); + #if OMPI_ENABLE_PROGRESS_THREADS opal_event_pipe_signalled = 1; #endif - if (res == -1) { - opal_output(0, "opal_event_loop: ompi_evesel->dispatch() failed."); + if (res == -1) + { + opal_output(0, "%s: ompi_evesel->dispatch() failed.", __func__); OPAL_THREAD_UNLOCK(&opal_event_lock); - return (-1); - } + return (-1); + } timeout_process(base); if (base->event_count_active) { - opal_event_process_active(base); - if (!base->event_count_active && (flags & (OPAL_EVLOOP_ONCE|OPAL_EVLOOP_ONELOOP))) + event_process_active(base); + if (!base->event_count_active && (flags & (EVLOOP_ONCE|EVLOOP_ONELOOP))) done = 1; - } else if (flags & (OPAL_EVLOOP_NONBLOCK|OPAL_EVLOOP_ONELOOP)) + } else if (flags & (EVLOOP_NONBLOCK|EVLOOP_ONELOOP)) done = 1; } event_debug(("%s: asked to terminate loop.", __func__)); - + OPAL_THREAD_UNLOCK(&opal_event_lock); return (base->event_count_active); #else - return 0; + return 0; #endif } /* Sets up an event for processing once */ struct event_once { - struct opal_event ev; + struct event ev; void (*cb)(int, short, void *); void *arg; @@ -631,56 +793,70 @@ struct event_once { static void event_once_cb(int fd, short events, void *arg) { - struct event_once *eonce = (struct event_once*)arg; + struct event_once *eonce = arg; (*eonce->cb)(fd, events, eonce->arg); free(eonce); } -/* Schedules an event once */ - +/* not threadsafe, event scheduled once. */ int -opal_event_once(int fd, short events, - void (*callback)(int, short, void *), void *arg, struct timeval *tv) +event_once(int fd, short events, + void (*callback)(int, short, void *), void *arg, struct timeval *tv) +{ + return event_base_once(current_base, fd, events, callback, arg, tv); +} + +/* Schedules an event once */ +int +event_base_once(struct event_base *base, int fd, short events, + void (*callback)(int, short, void *), void *arg, struct timeval *tv) { struct event_once *eonce; struct timeval etv; + int res; /* We cannot support signals that just fire once */ - if (events & OPAL_EV_SIGNAL) + if (events & EV_SIGNAL) return (-1); - if ((eonce = (struct event_once*)calloc(1, sizeof(struct event_once))) == NULL) + if ((eonce = (struct event_once *)calloc(1, sizeof(struct event_once))) == NULL) return (-1); eonce->cb = callback; eonce->arg = arg; - if (events == OPAL_EV_TIMEOUT) { + if (events == EV_TIMEOUT) { if (tv == NULL) { - timerclear(&etv); + evutil_timerclear(&etv); tv = &etv; } opal_evtimer_set(&eonce->ev, event_once_cb, eonce); - } else if (events & (OPAL_EV_READ|OPAL_EV_WRITE)) { - events &= OPAL_EV_READ|OPAL_EV_WRITE; + } else if (events & (EV_READ|EV_WRITE)) { + events &= EV_READ|EV_WRITE; - opal_event_set(&eonce->ev, fd, events, event_once_cb, eonce); + event_set(&eonce->ev, fd, events, event_once_cb, eonce); } else { /* Bad event combination */ free(eonce); return (-1); } - opal_event_add(&eonce->ev, tv); + res = event_base_set(base, &eonce->ev); + if (res == 0) + res = event_add(&eonce->ev, tv); + if (res != 0) { + free(eonce); + return (res); + } return (0); } void -opal_event_set(struct opal_event *ev, int fd, short events, - void (*callback)(int, short, void *), void *arg) +event_set(struct event *ev, int fd, short events, + void (*callback)(int, short, void *), void *arg) { /* Take the current base - caller needs to set the real base later */ ev->ev_base = current_base; @@ -689,31 +865,27 @@ opal_event_set(struct opal_event *ev, int fd, short events, ev->ev_arg = arg; ev->ev_fd = fd; ev->ev_events = events; - ev->ev_flags = OPAL_EVLIST_INIT; + ev->ev_res = 0; + ev->ev_flags = EVLIST_INIT; ev->ev_ncalls = 0; ev->ev_pncalls = NULL; + min_heap_elem_init(ev); + /* by default, we put new events into the middle priority */ -#if OPAL_HAVE_WORKING_EVENTOPS - ev->ev_pri = current_base->nactivequeues/2; -#else - ev->ev_pri = 0; -#endif + if(current_base) + ev->ev_pri = current_base->nactivequeues/2; } int -opal_event_base_set(struct event_base *base, struct opal_event *ev) +event_base_set(struct event_base *base, struct event *ev) { /* Only innocent events may be assigned to a different base */ - if (ev->ev_flags != OPAL_EVLIST_INIT) + if (ev->ev_flags != EVLIST_INIT) return (-1); ev->ev_base = base; -#if OPAL_HAVE_WORKING_EVENTOPS ev->ev_pri = base->nactivequeues/2; -#else - ev->ev_pri = 0; -#endif return (0); } @@ -724,14 +896,12 @@ opal_event_base_set(struct event_base *base, struct opal_event *ev) */ int -opal_event_priority_set(struct opal_event *ev, int pri) +event_priority_set(struct event *ev, int pri) { - if (ev->ev_flags & OPAL_EVLIST_ACTIVE) + if (ev->ev_flags & EVLIST_ACTIVE) return (-1); -#if OPAL_HAVE_WORKING_EVENTOPS if (pri < 0 || pri >= ev->ev_base->nactivequeues) return (-1); -#endif ev->ev_pri = pri; @@ -742,11 +912,10 @@ opal_event_priority_set(struct opal_event *ev, int pri) * Checks if a specific event is pending or scheduled. */ -#if 0 -/* Open MPI: Moved into inline function in event.h */ int event_pending(struct event *ev, short event, struct timeval *tv) { + struct timeval now, res; int flags = 0; if (ev->ev_flags & EVLIST_INSERTED) @@ -761,43 +930,48 @@ event_pending(struct event *ev, short event, struct timeval *tv) event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL); /* See if there is a timeout that we should report */ - if (tv != NULL && (flags & event & EV_TIMEOUT)) - *tv = ev->ev_timeout; + if (tv != NULL && (flags & event & EV_TIMEOUT)) { + gettime(&now); + evutil_timersub(&ev->ev_timeout, &now, &res); + /* correctly remap to real time */ + gettimeofday(&now, NULL); + evutil_timeradd(&now, &res, tv); + } return (flags & event); } -#endif /* #if 0 */ int -opal_event_add_i(struct opal_event *ev, struct timeval *tv) +event_add(struct event *ev, struct timeval *tv) { - int rc = OPAL_SUCCESS; -#if OPAL_HAVE_WORKING_EVENTOPS struct event_base *base = ev->ev_base; - const struct opal_eventop *evsel = base->evsel; + const struct eventop *evsel = base->evsel; void *evbase = base->evbase; + int res = 0; + event_debug(( + "event_add: event: %p, %s%s%scall %p", + ev, + ev->ev_events & EV_READ ? "EV_READ " : " ", + ev->ev_events & EV_WRITE ? "EV_WRITE " : " ", + tv ? "EV_TIMEOUT " : " ", + ev->ev_callback)); - event_debug(( - "event_add: event: %p, %s%s%scall %p", - ev, - ev->ev_events & OPAL_EV_READ ? "EV_READ " : " ", - ev->ev_events & OPAL_EV_WRITE ? "EV_WRITE " : " ", - tv ? "EV_TIMEOUT " : " ", - ev->ev_callback)); - - assert(!(ev->ev_flags & ~OPAL_EVLIST_ALL)); + assert(!(ev->ev_flags & ~EVLIST_ALL)); if (tv != NULL) { struct timeval now; - if (ev->ev_flags & OPAL_EVLIST_TIMEOUT) - opal_event_queue_remove(base, ev, OPAL_EVLIST_TIMEOUT); + if (ev->ev_flags & EVLIST_TIMEOUT) + event_queue_remove(base, ev, EVLIST_TIMEOUT); + else if (min_heap_reserve(&base->timeheap, + 1 + min_heap_size(&base->timeheap)) == -1) + return (-1); /* ENOMEM == errno */ /* Check if it is active due to a timeout. Rescheduling * this timeout before the callback can be executed * removes it from the active list. */ - if ((ev->ev_flags & OPAL_EVLIST_ACTIVE) && - (ev->ev_res & OPAL_EV_TIMEOUT)) { + if ((ev->ev_flags & EVLIST_ACTIVE) && + (ev->ev_res & EV_TIMEOUT)) { /* See if we are just active executing this * event in a loop */ @@ -805,62 +979,57 @@ opal_event_add_i(struct opal_event *ev, struct timeval *tv) /* Abort loop */ *ev->ev_pncalls = 0; } - - opal_event_queue_remove(base, ev, OPAL_EVLIST_ACTIVE); + + event_queue_remove(base, ev, EVLIST_ACTIVE); } - gettimeofday(&now, NULL); - timeradd(&now, tv, &ev->ev_timeout); + gettime(&now); + evutil_timeradd(&now, tv, &ev->ev_timeout); event_debug(( - "event_add: timeout in %d seconds, call %p", - tv->tv_sec, ev->ev_callback)); + "event_add: timeout in %d seconds, call %p", + tv->tv_sec, ev->ev_callback)); - opal_event_queue_insert(base, ev, OPAL_EVLIST_TIMEOUT); + event_queue_insert(base, ev, EVLIST_TIMEOUT); } - if ((ev->ev_events & (OPAL_EV_READ|OPAL_EV_WRITE)) && - !(ev->ev_flags & (OPAL_EVLIST_INSERTED|OPAL_EVLIST_ACTIVE))) { - opal_event_queue_insert(base, ev, OPAL_EVLIST_INSERTED); + if ((ev->ev_events & (EV_READ|EV_WRITE)) && + !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) { + res = evsel->add(evbase, ev); + if (res != -1) + event_queue_insert(base, ev, EVLIST_INSERTED); - rc = (evsel->add(evbase, ev)); - } else if ((ev->ev_events & OPAL_EV_SIGNAL) && - !(ev->ev_flags & OPAL_EVLIST_SIGNAL)) { - opal_event_queue_insert(base, ev, OPAL_EVLIST_SIGNAL); + return (res); + } else if ((ev->ev_events & EV_SIGNAL) && + !(ev->ev_flags & EVLIST_SIGNAL)) { + res = evsel->add(evbase, ev); + if (res != -1) + event_queue_insert(base, ev, EVLIST_SIGNAL); - rc = (evsel->add(evbase, ev)); - } + } #if OMPI_ENABLE_PROGRESS_THREADS if(opal_using_threads() && opal_event_pipe_signalled == 0) { - unsigned char byte = 0; - if(write(opal_event_pipe[1], &byte, 1) != 1) - opal_output(0, "opal_event_add: write() to opal_event_pipe[1] failed with errno=%d\n", errno); - opal_event_pipe_signalled++; + unsigned char byte = 0; + if(write(opal_event_pipe[1], &byte, 1) != 1) + opal_output(0, "opal_event_add: write() to opal_event_pipe[1] failed with errno=%d\n", errno); + opal_event_pipe_signalled++; } #endif -#else /* OPAL_HAVE_WORKING_EVENTOPS */ - rc = OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_HAVE_WORKING_EVENTOPS */ - - return rc; + return res; } - int -opal_event_del_i(struct opal_event *ev) +event_del(struct event *ev) { - int rc = 0; -#if OPAL_HAVE_WORKING_EVENTOPS + int rc = 0; struct event_base *base; - const struct opal_eventop *evsel; + const struct eventop *evsel; void *evbase; -#endif /* OPAL_HAVE_WORKING_EVENTOPS */ event_debug(("event_del: %p, callback %p", ev, ev->ev_callback)); -#if OPAL_HAVE_WORKING_EVENTOPS /* An event without a base has not been added */ if (ev->ev_base == NULL) return (-1); @@ -869,48 +1038,44 @@ opal_event_del_i(struct opal_event *ev) evsel = base->evsel; evbase = base->evbase; - assert(!(ev->ev_flags & ~OPAL_EVLIST_ALL)); + assert(!(ev->ev_flags & ~EVLIST_ALL)); - /* See if we are just active executing this event in a loop */ - if (ev->ev_ncalls && ev->ev_pncalls) { - /* Abort loop */ - *ev->ev_pncalls = 0; - } - - if (ev->ev_flags & OPAL_EVLIST_TIMEOUT) - opal_event_queue_remove(base, ev, OPAL_EVLIST_TIMEOUT); - - if (ev->ev_flags & OPAL_EVLIST_ACTIVE) - opal_event_queue_remove(base, ev, OPAL_EVLIST_ACTIVE); - - if (ev->ev_flags & OPAL_EVLIST_INSERTED) { - opal_event_queue_remove(base, ev, OPAL_EVLIST_INSERTED); - rc = (evsel->del(evbase, ev)); - } else if (ev->ev_flags & OPAL_EVLIST_SIGNAL) { - opal_event_queue_remove(base, ev, OPAL_EVLIST_SIGNAL); - rc = (evsel->del(evbase, ev)); + /* See if we are just active executing this event in a loop */ + if (ev->ev_ncalls && ev->ev_pncalls) { + /* Abort loop */ + *ev->ev_pncalls = 0; } + if (ev->ev_flags & EVLIST_TIMEOUT) + event_queue_remove(base, ev, EVLIST_TIMEOUT); + + if (ev->ev_flags & EVLIST_ACTIVE) + event_queue_remove(base, ev, EVLIST_ACTIVE); + + if (ev->ev_flags & EVLIST_INSERTED) { + event_queue_remove(base, ev, EVLIST_INSERTED); + rc = (evsel->del(evbase, ev)); + } else if (ev->ev_flags & EVLIST_SIGNAL) { + event_queue_remove(base, ev, EVLIST_SIGNAL); + rc = (evsel->del(evbase, ev)); + } #if OMPI_ENABLE_PROGRESS_THREADS - if(opal_using_threads() && opal_event_pipe_signalled == 0) { - unsigned char byte = 0; - if(write(opal_event_pipe[1], &byte, 1) != 1) - opal_output(0, "opal_event_add: write() to opal_event_pipe[1] failed with errno=%d\n", errno); - opal_event_pipe_signalled++; - } + if(opal_using_threads() && opal_event_pipe_signalled == 0) { + unsigned char byte = 0; + if(write(opal_event_pipe[1], &byte, 1) != 1) + opal_output(0, "opal_event_add: write() to opal_event_pipe[1] failed with errno=%d\n", errno); + opal_event_pipe_signalled++; + } #endif -#else /* OPAL_HAVE_WORKING_EVENTOPS */ - rc = OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_HAVE_WORKING_EVENTOPS */ return (rc); } -void opal_event_active_i(struct opal_event * ev, int res, short ncalls) +void +event_active(struct event *ev, int res, short ncalls) { -#if OPAL_HAVE_WORKING_EVENTOPS /* We get different kinds of events, add them together */ - if (ev->ev_flags & OPAL_EVLIST_ACTIVE) { + if (ev->ev_flags & EVLIST_ACTIVE) { ev->ev_res |= res; return; } @@ -918,168 +1083,171 @@ void opal_event_active_i(struct opal_event * ev, int res, short ncalls) ev->ev_res = res; ev->ev_ncalls = ncalls; ev->ev_pncalls = NULL; - opal_event_queue_insert(ev->ev_base, ev, OPAL_EVLIST_ACTIVE); -#endif + event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE); } static int -timeout_next(struct event_base *base, struct timeval *tv) -{ - struct timeval dflt = OPAL_TIMEOUT_DEFAULT; +timeout_next(struct event_base *base, struct timeval **tv_p) +{ + struct timeval now = OPAL_TIMEOUT_DEFAULT; + struct event *ev; + struct timeval *tv = *tv_p; - struct timeval now; - struct opal_event *ev; - - if ((ev = RB_MIN(opal_event_tree, &base->timetree)) == NULL) { - *tv = dflt; + if ((ev = min_heap_top(&base->timeheap)) == NULL) { + /* if no time-based events are active wait for I/O */ + *tv = now; return (0); } - if (gettimeofday(&now, NULL) == -1) - return (-1); + if (gettime(&now) == -1) + return (-1); - if (timercmp(&ev->ev_timeout, &now, <=)) { - timerclear(tv); - return (0); - } - - timersub(&ev->ev_timeout, &now, tv); + if (evutil_timercmp(&ev->ev_timeout, &now, <=)) { + evutil_timerclear(tv); + return (0); + } + + evutil_timersub(&ev->ev_timeout, &now, tv); assert(tv->tv_sec >= 0); assert(tv->tv_usec >= 0); event_debug(("timeout_next: in %d seconds", tv->tv_sec)); - return (0); -} + return (0); +} + +#if 0 +/* Let's not delete this yet, but it doesn't look necessary right now */ +/* + * Determines if the time is running backwards by comparing the current + * time against the last time we checked. Not needed when using clock + * monotonic. + */ static void -timeout_correct(struct event_base *base, struct timeval *off) +timeout_correct(struct event_base *base, struct timeval *tv) { -#if OPAL_HAVE_WORKING_EVENTOPS - struct opal_event *ev; + struct event **pev; + unsigned int size; + struct timeval off; + + if (use_monotonic) + return; + + /* Check if time is running backwards */ + gettime(tv); + if (evutil_timercmp(tv, &base->event_tv, >=)) { + base->event_tv = *tv; + return; + } + + event_debug(("%s: time is running backwards, corrected", + __func__)); + evutil_timersub(&base->event_tv, tv, &off); /* * We can modify the key element of the node without destroying * the key, beause we apply it to all in the right order. */ - RB_FOREACH(ev, opal_event_tree, &base->timetree) - timersub(&ev->ev_timeout, off, &ev->ev_timeout); -#endif + pev = base->timeheap.p; + size = base->timeheap.n; + for (; size-- > 0; ++pev) { + struct timeval *ev_tv = &(**pev).ev_timeout; + evutil_timersub(ev_tv, &off, ev_tv); + } } +#endif - -static void +void timeout_process(struct event_base *base) { -#if OPAL_HAVE_WORKING_EVENTOPS - struct timeval now; - struct opal_event *ev, *next; + struct timeval now; + struct event *ev; - gettimeofday(&now, NULL); + if (min_heap_empty(&base->timeheap)) + return; - for (ev = RB_MIN(opal_event_tree, &base->timetree); ev; ev = next) { - if (timercmp(&ev->ev_timeout, &now, >)) + gettime(&now); + + while ((ev = min_heap_top(&base->timeheap))) { + if (evutil_timercmp(&ev->ev_timeout, &now, >)) break; - next = RB_NEXT(opal_event_tree, &base->timetree, ev); - opal_event_queue_remove(base, ev, OPAL_EVLIST_TIMEOUT); - - /* delete this event from the I/O queues */ - opal_event_del_i(ev); + /* delete this event from the I/O queues */ + event_del(ev); event_debug(("timeout_process: call %p", ev->ev_callback)); - opal_event_active_i(ev, OPAL_EV_TIMEOUT, 1); + event_active(ev, EV_TIMEOUT, 1); } -#endif } void -opal_event_queue_remove(struct event_base *base, struct opal_event *ev, int queue) +event_queue_remove(struct event_base *base, struct event *ev, int queue) { -#if OPAL_HAVE_WORKING_EVENTOPS - int docount = 1; - if (!(ev->ev_flags & queue)) event_errx(1, "%s: %p(fd %d) not on queue %x", __func__, - ev, ev->ev_fd, queue); + (void*)ev, ev->ev_fd, queue); - if (ev->ev_flags & OPAL_EVLIST_INTERNAL) - docount = 0; - - if (docount) + if (~ev->ev_flags & EVLIST_INTERNAL) base->event_count--; ev->ev_flags &= ~queue; switch (queue) { - case OPAL_EVLIST_ACTIVE: - if (docount) - base->event_count_active--; + case EVLIST_ACTIVE: + base->event_count_active--; TAILQ_REMOVE(base->activequeues[ev->ev_pri], ev, ev_active_next); break; - case OPAL_EVLIST_SIGNAL: - TAILQ_REMOVE(&opal_signalqueue, ev, ev_signal_next); + case EVLIST_SIGNAL: + TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next); break; - case OPAL_EVLIST_TIMEOUT: - RB_REMOVE(opal_event_tree, &base->timetree, ev); + case EVLIST_TIMEOUT: + min_heap_erase(&base->timeheap, ev); break; - case OPAL_EVLIST_INSERTED: + case EVLIST_INSERTED: TAILQ_REMOVE(&base->eventqueue, ev, ev_next); break; default: event_errx(1, "%s: unknown queue %x", __func__, queue); } -#endif } void -opal_event_queue_insert(struct event_base *base, struct opal_event *ev, int queue) +event_queue_insert(struct event_base *base, struct event *ev, int queue) { -#if OPAL_HAVE_WORKING_EVENTOPS - int docount = 1; - if (ev->ev_flags & queue) { /* Double insertion is possible for active events */ - if (queue & OPAL_EVLIST_ACTIVE) + if (queue & EVLIST_ACTIVE) return; event_errx(1, "%s: %p(fd %d) already on queue %x", __func__, - ev, ev->ev_fd, queue); + (void*)ev, ev->ev_fd, queue); } - if (ev->ev_flags & OPAL_EVLIST_INTERNAL) - docount = 0; - - if (docount) + if (~ev->ev_flags & EVLIST_INTERNAL) base->event_count++; ev->ev_flags |= queue; switch (queue) { - case OPAL_EVLIST_ACTIVE: - if (docount) - base->event_count_active++; + case EVLIST_ACTIVE: + base->event_count_active++; TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], ev,ev_active_next); break; - case OPAL_EVLIST_SIGNAL: - TAILQ_INSERT_TAIL(&opal_signalqueue, ev, ev_signal_next); + case EVLIST_SIGNAL: + TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next); break; - case OPAL_EVLIST_TIMEOUT: { -#ifndef NDEBUG - struct opal_event *tmp = -#endif - RB_INSERT(opal_event_tree, &base->timetree, ev); - assert(tmp == NULL); + case EVLIST_TIMEOUT: { + min_heap_push(&base->timeheap, ev); break; } - case OPAL_EVLIST_INSERTED: + case EVLIST_INSERTED: TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next); break; default: event_errx(1, "%s: unknown queue %x", __func__, queue); } -#endif } /* Functions for debugging */ diff --git a/opal/event/event.h b/opal/event/event.h index 06500efaa8..e07f0c1ad0 100644 --- a/opal/event/event.h +++ b/opal/event/event.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2000-2004 Niels Provos + * Copyright (c) 2008 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2000-2007 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,45 +28,183 @@ #ifndef _EVENT_H_ #define _EVENT_H_ +/** @mainpage + + @section intro Introduction + + libevent is an event notification library for developing scalable network + servers. The libevent API provides a mechanism to execute a callback + function when a specific event occurs on a file descriptor or after a + timeout has been reached. Furthermore, libevent also support callbacks due + to signals or regular timeouts. + + libevent is meant to replace the event loop found in event driven network + servers. An application just needs to call event_dispatch() and then add or + remove events dynamically without having to change the event loop. + + Currently, libevent supports /dev/poll, kqueue(2), select(2), poll(2) and + epoll(4). It also has experimental support for real-time signals. The + internal event mechanism is completely independent of the exposed event API, + and a simple update of libevent can provide new functionality without having + to redesign the applications. As a result, Libevent allows for portable + application development and provides the most scalable event notification + mechanism available on an operating system. Libevent can also be used for + multi-threaded aplications; see Steven Grimm's explanation. Libevent should + compile on Linux, *BSD, Mac OS X, Solaris and Windows. + + @section usage Standard usage + + Every program that uses libevent must include the header, and pass + the -levent flag to the linker. Before using any of the functions in the + library, you must call event_init() or event_base_new() to perform one-time + initialization of the libevent library. + + @section event Event notification + + For each file descriptor that you wish to monitor, you must declare an event + structure and call event_set() to initialize the members of the structure. + To enable notification, you add the structure to the list of monitored + events by calling event_add(). The event structure must remain allocated as + long as it is active, so it should be allocated on the heap. Finally, you + call event_dispatch() to loop and dispatch events. + + @section bufferevent I/O Buffers + + libevent provides an abstraction on top of the regular event callbacks. This + abstraction is called a buffered event. A buffered event provides input and + output buffers that get filled and drained automatically. The user of a + buffered event no longer deals directly with the I/O, but instead is reading + from input and writing to output buffers. + + Once initialized via bufferevent_new(), the bufferevent structure can be + used repeatedly with bufferevent_enable() and bufferevent_disable(). + Instead of reading and writing directly to a socket, you would call + bufferevent_read() and bufferevent_write(). + + When read enabled the bufferevent will try to read from the file descriptor + and call the read callback. The write callback is executed whenever the + output buffer is drained below the write low watermark, which is 0 by + default. + + @section timers Timers + + libevent can also be used to create timers that invoke a callback after a + certain amount of time has expired. The evtimer_set() function prepares an + event struct to be used as a timer. To activate the timer, call + evtimer_add(). Timers can be deactivated by calling evtimer_del(). + + @section timeouts Timeouts + + In addition to simple timers, libevent can assign timeout events to file + descriptors that are triggered whenever a certain amount of time has passed + with no activity on a file descriptor. The timeout_set() function + initializes an event struct for use as a timeout. Once initialized, the + event must be activated by using timeout_add(). To cancel the timeout, call + timeout_del(). + + @section evdns Asynchronous DNS resolution + + libevent provides an asynchronous DNS resolver that should be used instead + of the standard DNS resolver functions. These functions can be imported by + including the header in your program. Before using any of the + resolver functions, you must call evdns_init() to initialize the library. To + convert a hostname to an IP address, you call the evdns_resolve_ipv4() + function. To perform a reverse lookup, you would call the + evdns_resolve_reverse() function. All of these functions use callbacks to + avoid blocking while the lookup is performed. + + @section evhttp Event-driven HTTP servers + + libevent provides a very simple event-driven HTTP server that can be + embedded in your program and used to service HTTP requests. + + To use this capability, you need to include the header in your + program. You create the server by calling evhttp_new(). Add addresses and + ports to listen on with evhttp_bind_socket(). You then register one or more + callbacks to handle incoming requests. Each URI can be assigned a callback + via the evhttp_set_cb() function. A generic callback function can also be + registered via evhttp_set_gencb(); this callback will be invoked if no other + callbacks have been registered for a given URI. + + @section evrpc A framework for RPC servers and clients + + libevents provides a framework for creating RPC servers and clients. It + takes care of marshaling and unmarshaling all data structures. + + @section api API Reference + + To browse the complete documentation of the libevent API, click on any of + the following links. + + event.h + The primary libevent header + + evdns.h + Asynchronous DNS resolution + + evhttp.h + An embedded libevent-based HTTP server + + evrpc.h + A framework for creating RPC servers and clients + + */ + +/** @file event.h + + A library for writing event-driven network servers + + */ + #include "opal_config.h" #include "opal/threads/mutex.h" -#include "opal/event/event_rename.h" +#include "event_rename.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef _EVENT_HAVE_SYS_TYPES_H +#include +#endif +#ifdef _EVENT_HAVE_SYS_TIME_H +#include +#endif +#ifdef _EVENT_HAVE_STDINT_H +#include +#endif #ifdef HAVE_STDARG_H #include #endif - -#ifdef HAVE_SYS_TIME_H -#include -#endif +/* For int types. */ +#include "opal/event/evutil.h" #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN typedef unsigned char u_char; +typedef unsigned short u_short; #endif -#if defined(c_plusplus) || defined(__cplusplus) -extern "C" { -#endif - -#define OPAL_EVLIST_TIMEOUT 0x01 -#define OPAL_EVLIST_INSERTED 0x02 -#define OPAL_EVLIST_SIGNAL 0x04 -#define OPAL_EVLIST_ACTIVE 0x08 -#define OPAL_EVLIST_INTERNAL 0x10 -#define OPAL_EVLIST_INIT 0x80 +#define EVLIST_TIMEOUT 0x01 +#define EVLIST_INSERTED 0x02 +#define EVLIST_SIGNAL 0x04 +#define EVLIST_ACTIVE 0x08 +#define EVLIST_INTERNAL 0x10 +#define EVLIST_INIT 0x80 /* EVLIST_X_ Private space: 0x1000-0xf000 */ -#define OPAL_EVLIST_ALL (0xf000 | 0x9f) +#define EVLIST_ALL (0xf000 | 0x9f) -#define OPAL_EV_TIMEOUT 0x01 -#define OPAL_EV_READ 0x02 -#define OPAL_EV_WRITE 0x04 -#define OPAL_EV_SIGNAL 0x08 -#define OPAL_EV_PERSIST 0x10 /* Persistant event */ +#define EV_TIMEOUT 0x01 +#define EV_READ 0x02 +#define EV_WRITE 0x04 +#define EV_SIGNAL 0x08 +#define EV_PERSIST 0x10 /* Persistant event */ #ifdef OPAL_EVENT_USE_SIGNALS #undef OPAL_EVENT_USE_SIGNALS @@ -94,25 +233,16 @@ struct { \ struct type **tqe_prev; /* address of previous next element */ \ } #endif /* !TAILQ_ENTRY */ -#ifndef RB_ENTRY -#define _EVENT_DEFINED_RBENTRY -#define RB_ENTRY(type) \ -struct { \ - struct type *rbe_left; /* left element */ \ - struct type *rbe_right; /* right element */ \ - struct type *rbe_parent; /* parent element */ \ - int rbe_color; /* node color */ \ -} -#endif /* !RB_ENTRY */ struct event_base; -struct opal_event { - TAILQ_ENTRY (opal_event) ev_next; - TAILQ_ENTRY (opal_event) ev_active_next; - TAILQ_ENTRY (opal_event) ev_signal_next; - RB_ENTRY (opal_event) ev_timeout_node; +struct event { + TAILQ_ENTRY (event) ev_next; + TAILQ_ENTRY (event) ev_active_next; + TAILQ_ENTRY (event) ev_signal_next; + unsigned int min_heap_idx; /* for managing timeouts */ struct event_base *ev_base; + int ev_fd; short ev_events; short ev_ncalls; @@ -128,41 +258,105 @@ struct opal_event { int ev_res; /* result passed to event callback */ int ev_flags; #if defined(__WINDOWS__) - HANDLE base_handle; - HANDLE registered_handle; + HANDLE base_handle; + HANDLE registered_handle; struct opal_event* ev_similar; #endif /* defined(__WINDOWS__) */ -}; -typedef struct opal_event opal_event_t; -#define OPAL_EVENT_SIGNAL(ev) (int)ev->ev_fd -#define OPAL_EVENT_FD(ev) (int)ev->ev_fd +}; +typedef struct event opal_event_t; + +#define EVENT_SIGNAL(ev) (int)(ev)->ev_fd +#define EVENT_FD(ev) (int)(ev)->ev_fd + +/* + * Key-Value pairs. Can be used for HTTP headers but also for + * query argument parsing. + */ +struct evkeyval { + TAILQ_ENTRY(evkeyval) next; + + char *key; + char *value; +}; #ifdef _EVENT_DEFINED_TQENTRY #undef TAILQ_ENTRY +struct event_list; +struct evkeyvalq; #undef _EVENT_DEFINED_TQENTRY #else -TAILQ_HEAD (opal_event_list, opal_event); +TAILQ_HEAD (event_list, event); +TAILQ_HEAD (evkeyvalq, evkeyval); #endif /* _EVENT_DEFINED_TQENTRY */ -#ifdef _EVENT_DEFINED_RBENTRY -#undef RB_ENTRY -#undef _EVENT_DEFINED_RBENTRY -#endif /* _EVENT_DEFINED_RBENTRY */ -struct opal_eventop { - char *name; - void *(*init)(void); - int (*add)(void *, struct opal_event *); - int (*del)(void *, struct opal_event *); - int (*recalc)(struct event_base *, void *, int); - int (*dispatch)(struct event_base *, void *, struct timeval *); -}; +/** + Initialize the event API. + Use event_base_new() to initialize a new event base, but does not set + the current_base global. If using only event_base_new(), each event + added must have an event base set with event_base_set() + + @see event_base_set(), event_base_free(), event_init() + */ +struct event_base * event_base_new(void); + +/** + Initialize the event API. + + The event API needs to be initialized with event_init() before it can be + used. Sets the current_base global representing the default base for + events that have no base associated with them. + + @see event_base_set(), event_base_new() + */ +int event_init(void); + +/** + Reinitialized the event base after a fork + + Some event mechanisms do not survive across fork. The event base needs + to be reinitialized with the event_reinit() function. + + @param base the event base that needs to be re-initialized + @return 0 if successful, or -1 if some events could not be re-added. + @see event_base_new(), event_init() +*/ +int event_reinit(struct event_base *base); + +/** + Loop to process events. + + In order to process events, an application needs to call + event_dispatch(). This function only returns on error, and should + replace the event core of the application program. + + @see event_base_dispatch() + */ +int event_dispatch(void); + + +/** + Threadsafe event dispatching loop. + + @param eb the event_base structure returned by event_init() + @see event_init(), event_dispatch() + */ +int event_base_dispatch(struct event_base *); + + +/** + Get the kernel event notification mechanism used by libevent. + + @param eb the event_base structure returned by event_base_new() + @return a string identifying the kernel event mechanism (kqueue, epoll, etc.) + */ +const char * event_base_get_method(struct event_base *); #define OPAL_TIMEOUT_DEFAULT {1, 0} -OPAL_DECLSPEC int opal_event_init(void); -OPAL_DECLSPEC int opal_event_dispatch(void); -OPAL_DECLSPEC int opal_event_base_dispatch(struct event_base *); +OPAL_DECLSPEC int event_init(void); +OPAL_DECLSPEC int event_dispatch(void); +OPAL_DECLSPEC int event_base_dispatch(struct opal_event_base *); OPAL_DECLSPEC int opal_event_fini(void); OPAL_DECLSPEC int opal_event_enable(void); @@ -170,68 +364,285 @@ OPAL_DECLSPEC int opal_event_disable(void); OPAL_DECLSPEC bool opal_event_progress_thread(void); OPAL_DECLSPEC int opal_event_restart(void); + +/** + Deallocate all memory associated with an event_base, and free the base. + + Note that this function will not close any fds or free any memory passed + to event_set as the argument to callback. + + @param eb an event_base to be freed + */ +void event_base_free(struct event_base *); + + #define _EVENT_LOG_DEBUG 0 #define _EVENT_LOG_MSG 1 #define _EVENT_LOG_WARN 2 #define _EVENT_LOG_ERR 3 typedef void (*event_log_cb)(int severity, const char *msg); +/** + Redirect libevent's log messages. + + @param cb a function taking two arguments: an integer severity between + _EVENT_LOG_DEBUG and _EVENT_LOG_ERR, and a string. If cb is NULL, + then the default log is used. + */ void event_set_log_callback(event_log_cb cb); -/* Associate a different event base with an event */ -int opal_event_base_set(struct event_base *, struct opal_event *); +/** + Associate a different event base with an event. + + @param eb the event base + @param ev the event + */ +int event_base_set(struct event_base *, struct event *); + +/** + event_loop() flags + */ +/*@{*/ +#define EVLOOP_ONCE 0x01 /**< Block at most once. */ +#define EVLOOP_NONBLOCK 0x02 /**< Do not block. */ -#define OPAL_EVLOOP_ONCE 0x01 -#define OPAL_EVLOOP_NONBLOCK 0x02 /* run once through the loop, but do have the default timeout. - Need to be both something special *AND* EVLOOP_ONCE */ -#define OPAL_EVLOOP_ONELOOP 0x05 + * Need to be both something special *AND* EVLOOP_ONCE */ +#define EVLOOP_ONELOOP 0x05 -OPAL_DECLSPEC int opal_event_loop(int); -int opal_event_base_loop(struct event_base *, int); -int opal_event_loopexit(struct timeval *); /* Causes the loop to exit */ +/*@}*/ + +/** + Handle events. + + This is a more flexible version of event_dispatch(). + + @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK + @return 0 if successful, -1 if an error occurred, or 1 if no events were + registered. + @see event_loopexit(), event_base_loop() +*/ +OPAL_DECLSPEC int event_loop(int); + +/** + Handle events (threadsafe version). + + This is a more flexible version of event_base_dispatch(). + + @param eb the event_base structure returned by event_init() + @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK + @return 0 if successful, -1 if an error occurred, or 1 if no events were + registered. + @see event_loopexit(), event_base_loop() + */ +int event_base_loop(struct event_base *, int); + +/** + Exit the event loop after the specified time. + + The next event_loop() iteration after the given timer expires will + complete normally (handling all queued events) then exit without + blocking for events again. + + Subsequent invocations of event_loop() will proceed normally. + + @param tv the amount of time after which the loop should terminate. + @return 0 if successful, or -1 if an error occurred + @see event_loop(), event_base_loop(), event_base_loopexit() + */ +int event_loopexit(struct timeval *); + + +/** + Exit the event loop after the specified time (threadsafe variant). + + The next event_base_loop() iteration after the given timer expires will + complete normally (handling all queued events) then exit without + blocking for events again. + + Subsequent invocations of event_base_loop() will proceed normally. + + @param eb the event_base structure returned by event_init() + @param tv the amount of time after which the loop should terminate. + @return 0 if successful, or -1 if an error occurred + @see event_loopexit() + */ int event_base_loopexit(struct event_base *, struct timeval *); -#define opal_evtimer_add(ev, tv) opal_event_add(ev, tv) -#define opal_evtimer_set(ev, cb, arg) opal_event_set(ev, -1, 0, cb, arg) -#define opal_evtimer_del(ev) opal_event_del(ev) -#define opal_evtimer_pending(ev, tv) opal_event_pending(ev, OPAL_EV_TIMEOUT, tv) -#define opal_evtimer_initialized(ev) ((ev)->ev_flags & OPAL_EVLIST_INIT) +/** + Abort the active event_loop() immediately. -#define opal_timeout_add(ev, tv) opal_event_add(ev, tv) -#define opal_timeout_set(ev, cb, arg) opal_event_set(ev, -1, 0, cb, arg) -#define opal_timeout_del(ev) opal_event_del(ev) -#define opal_timeout_pending(ev, tv) opal_event_pending(ev, OPAL_EV_TIMEOUT, tv) -#define opal_timeout_initialized(ev) ((ev)->ev_flags & OPAL_EVLIST_INIT) + event_loop() will abort the loop after the next event is completed; + event_loopbreak() is typically invoked from this event's callback. + This behavior is analogous to the "break;" statement. -#define opal_signal_add(ev, tv) opal_event_add(ev, tv) + Subsequent invocations of event_loop() will proceed normally. + + @return 0 if successful, or -1 if an error occurred + @see event_base_loopbreak(), event_loopexit() + */ +int event_loopbreak(void); + +/** + Abort the active event_base_loop() immediately. + + event_base_loop() will abort the loop after the next event is completed; + event_base_loopbreak() is typically invoked from this event's callback. + This behavior is analogous to the "break;" statement. + + Subsequent invocations of event_loop() will proceed normally. + + @param eb the event_base structure returned by event_init() + @return 0 if successful, or -1 if an error occurred + @see event_base_loopexit + */ +int event_base_loopbreak(struct event_base *); + + +/** + Add a timer event. + + @param ev the event struct + @param tv timeval struct + */ +#define opal_evtimer_add(ev, tv) event_add(ev, tv) + + +/** + Define a timer event. + + @param ev event struct to be modified + @param cb callback function + @param arg argument that will be passed to the callback function + */ +#define opal_evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) + + +/** + * Delete a timer event. + * + * @param ev the event struct to be disabled + */ +#define opal_evtimer_del(ev) event_del(ev) +#define opal_evtimer_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv) +#define opal_evtimer_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) + +/** + * Add a timeout event. + * + * @param ev the event struct to be disabled + * @param tv the timeout value, in seconds + */ +#define oapl_timeout_add(ev, tv) event_add(ev, tv) + + +/** + * Define a timeout event. + * + * @param ev the event struct to be defined + * @param cb the callback to be invoked when the timeout expires + * @param arg the argument to be passed to the callback + */ +#define opal_timeout_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) + + +/** + * Disable a timeout event. + * + * @param ev the timeout event to be disabled + */ +#define opal_timeout_del(ev) event_del(ev) + +#define opal_timeout_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv) +#define opal_timeout_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) + +#define opal_signal_add(ev, tv) event_add(ev, tv) #define opal_signal_set(ev, x, cb, arg) \ - opal_event_set(ev, x, OPAL_EV_SIGNAL|OPAL_EV_PERSIST, cb, arg) -#define opal_signal_del(ev) opal_event_del(ev) -#define opal_signal_pending(ev, tv) opal_event_pending(ev, OPAL_EV_SIGNAL, tv) -#define opal_signal_initialized(ev) ((ev)->ev_flags & OPAL_EVLIST_INIT) + event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) +#define opal_signal_del(ev) event_del(ev) +#define opal_signal_pending(ev, tv) event_pending(ev, EV_SIGNAL, tv) +#define opal_signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) -/* for internal use only */ -OPAL_DECLSPEC int opal_event_add_i(struct opal_event *, struct timeval *); -OPAL_DECLSPEC int opal_event_del_i(struct opal_event *); -OPAL_DECLSPEC void opal_event_active_i(struct opal_event*, int, short); +/** + Prepare an event structure to be added. + + The function event_set() prepares the event structure ev to be used in + future calls to event_add() and event_del(). The event will be prepared to + call the function specified by the fn argument with an int argument + indicating the file descriptor, a short argument indicating the type of + event, and a void * argument given in the arg argument. The fd indicates + the file descriptor that should be monitored for events. The events can be + either EV_READ, EV_WRITE, or both. Indicating that an application can read + or write from the file descriptor respectively without blocking. + + The function fn will be called with the file descriptor that triggered the + event and the type of event which will be either EV_TIMEOUT, EV_SIGNAL, + EV_READ, or EV_WRITE. The additional flag EV_PERSIST makes an event_add() + persistent until event_del() has been called. + + @param ev an event struct to be modified + @param fd the file descriptor to be monitored + @param event desired events to monitor; can be EV_READ and/or EV_WRITE + @param fn callback function to be invoked when the event occurs + @param arg an argument to be passed to the callback function + + @see event_add(), event_del(), event_once() + + */ +OPAL_DECLSPEC void event_set(struct event *, int, short, void (*)(int, short, void *), void *); + +OPAL_DECLSPEC int event_add(struct opal_event *, struct timeval *); +OPAL_DECLSPEC int event_del(struct opal_event *); +OPAL_DECLSPEC void event_active(struct opal_event*, int, short); OPAL_DECLSPEC extern opal_mutex_t opal_event_lock; -OPAL_DECLSPEC extern int opal_evsignal_restart(void); -extern struct event_base *current_base; -/* public functions */ -OPAL_DECLSPEC void -opal_event_set(struct opal_event *ev, int fd, short events, - void (*callback)(int, short, void *), void *arg); +/** + Schedule a one-time event to occur. -int opal_event_once(int, short, void (*)(int, short, void *), void *, struct timeval *); + The function event_once() is similar to event_set(). However, it schedules + a callback to be called exactly once and does not require the caller to + prepare an event structure. + + @param fd a file descriptor to monitor + @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ | + EV_WRITE + @param callback callback function to be invoked when the event occurs + @param arg an argument to be passed to the callback function + @param timeout the maximum amount of time to wait for the event, or NULL + to wait forever + @return 0 if successful, or -1 if an error occurred + @see event_set() + + */ +int event_once(int, short, void (*)(int, short, void *), void *, struct timeval *); + + +/** + Schedule a one-time event (threadsafe variant) + + The function event_base_once() is similar to event_set(). However, it + schedules a callback to be called exactly once and does not require the + caller to prepare an event structure. + + @param base an event_base returned by event_init() + @param fd a file descriptor to monitor + @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ | + EV_WRITE + @param callback callback function to be invoked when the event occurs + @param arg an argument to be passed to the callback function + @param timeout the maximum amount of time to wait for the event, or NULL + to wait forever + @return 0 if successful, or -1 if an error occurred + @see event_once() + */ +int event_base_once(struct event_base *, int, short, void (*)(int, short, void *), void *, struct timeval *); static inline int opal_event_add(struct opal_event *ev, struct timeval *tv) { int rc; - OPAL_THREAD_SCOPED_LOCK(&opal_event_lock, rc = opal_event_add_i(ev, tv)); + OPAL_THREAD_SCOPED_LOCK(&opal_event_lock, rc = event_add(ev, tv)); return rc; } @@ -239,54 +650,147 @@ static inline int opal_event_del(struct opal_event *ev) { int rc; - OPAL_THREAD_SCOPED_LOCK(&opal_event_lock, rc = opal_event_del_i(ev)); + OPAL_THREAD_SCOPED_LOCK(&opal_event_lock, rc = event_del(ev)); return rc; } static inline void opal_event_active(struct opal_event* ev, int res, short ncalls) { - OPAL_THREAD_SCOPED_LOCK(&opal_event_lock, opal_event_active_i(ev, res, ncalls)); -} - -static inline int -opal_event_pending(struct opal_event *ev, short event, struct timeval *tv) -{ - int flags = 0; - - if (ev->ev_flags & OPAL_EVLIST_INSERTED) - flags |= (ev->ev_events & (OPAL_EV_READ|OPAL_EV_WRITE)); - if (ev->ev_flags & OPAL_EVLIST_ACTIVE) - flags |= ev->ev_res; - if (ev->ev_flags & OPAL_EVLIST_TIMEOUT) - flags |= OPAL_EV_TIMEOUT; - if (ev->ev_flags & OPAL_EVLIST_SIGNAL) - flags |= OPAL_EV_SIGNAL; - - event &= (OPAL_EV_TIMEOUT|OPAL_EV_READ|OPAL_EV_WRITE|OPAL_EV_SIGNAL); - - /* See if there is a timeout that we should report */ - if (tv != NULL && (flags & event & OPAL_EV_TIMEOUT)) - *tv = ev->ev_timeout; - - return (flags & event); + OPAL_THREAD_SCOPED_LOCK(&opal_event_lock, event_active(ev, res, ncalls)); } + +/** + Add an event to the set of monitored events. + + The function event_add() schedules the execution of the ev event when the + event specified in event_set() occurs or in at least the time specified in + the tv. If tv is NULL, no timeout occurs and the function will only be + called if a matching event occurs on the file descriptor. The event in the + ev argument must be already initialized by event_set() and may not be used + in calls to event_set() until it has timed out or been removed with + event_del(). If the event in the ev argument already has a scheduled + timeout, the old timeout will be replaced by the new one. + + @param ev an event struct initialized via event_set() + @param timeout the maximum amount of time to wait for the event, or NULL + to wait forever + @return 0 if successful, or -1 if an error occurred + @see event_del(), event_set() + */ +int event_add(struct event *, struct timeval *); + + +/** + Remove an event from the set of monitored events. + + The function event_del() will cancel the event in the argument ev. If the + event has already executed or has never been added the call will have no + effect. + + @param ev an event struct to be removed from the working set + @return 0 if successful, or -1 if an error occurred + @see event_add() + */ +int event_del(struct event *); + +void event_active(struct event *, int, short); + + +/** + Checks if a specific event is pending or scheduled. + + @param ev an event struct previously passed to event_add() + @param event the requested event type; any of EV_TIMEOUT|EV_READ| + EV_WRITE|EV_SIGNAL + @param tv an alternate timeout (FIXME - is this true?) + + @return 1 if the event is pending, or 0 if the event has not occurred + + */ +int event_pending(struct event *, short, struct timeval *); + + +/** + Test if an event structure has been initialized. + + The event_initialized() macro can be used to check if an event has been + initialized. + + @param ev an event structure to be tested + @return 1 if the structure has been initialized, or 0 if it has not been + initialized + */ #ifdef WIN32 -#define opal_event_initialized(ev) ((ev)->ev_flags & OPAL_EVLIST_INIT && (ev)->ev_fd != INVALID_HANDLE_VALUE) +#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != (int)INVALID_HANDLE_VALUE) #else -#define opal_event_initialized(ev) ((ev)->ev_flags & OPAL_EVLIST_INIT) +#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) #endif -/* Some simple debugging functions */ + +/** + Get the libevent version number. + + @return a string containing the version number of libevent + */ const char *event_get_version(void); + + +/** + Get the kernel event notification mechanism used by libevent. + + @return a string identifying the kernel event mechanism (kqueue, epoll, etc.) + */ const char *event_get_method(void); -/* These functions deal with event priorities */ -int opal_event_priority_init(int); -int opal_event_base_priority_init(struct event_base *, int); -int opal_event_priority_set(struct opal_event *, int); +/** + Set the number of different event priorities. + + By default libevent schedules all active events with the same priority. + However, some time it is desirable to process some events with a higher + priority than others. For that reason, libevent supports strict priority + queues. Active events with a lower priority are always processed before + events with a higher priority. + + The number of different priorities can be set initially with the + event_priority_init() function. This function should be called before the + first call to event_dispatch(). The event_priority_set() function can be + used to assign a priority to an event. By default, libevent assigns the + middle priority to all events unless their priority is explicitly set. + + @param npriorities the maximum number of priorities + @return 0 if successful, or -1 if an error occurred + @see event_base_priority_init(), event_priority_set() + + */ +int event_priority_init(int); + + +/** + Set the number of different event priorities (threadsafe variant). + + See the description of event_priority_init() for more information. + + @param eb the event_base structure returned by event_init() + @param npriorities the maximum number of priorities + @return 0 if successful, or -1 if an error occurred + @see event_priority_init(), event_priority_set() + */ +int event_base_priority_init(struct event_base *, int); + + +/** + Assign a priority to an event. + + @param ev an event struct + @param priority the new priority to be assigned + @return 0 if successful, or -1 if an error occurred + @see event_priority_init() + */ +int event_priority_set(struct event *, int); + /* These functions deal with buffering input and output */ @@ -303,11 +807,11 @@ struct evbuffer { }; /* Just for error reporting - use other constants otherwise */ -#define OPAL_EVBUFFER_READ 0x01 -#define OPAL_EVBUFFER_WRITE 0x02 -#define OPAL_EVBUFFER_EOF 0x10 -#define OPAL_EVBUFFER_ERROR 0x20 -#define OPAL_EVBUFFER_TIMEOUT 0x40 +#define EVBUFFER_READ 0x01 +#define EVBUFFER_WRITE 0x02 +#define EVBUFFER_EOF 0x10 +#define EVBUFFER_ERROR 0x20 +#define EVBUFFER_TIMEOUT 0x40 struct bufferevent; typedef void (*evbuffercb)(struct bufferevent *, void *); @@ -319,8 +823,8 @@ struct event_watermark { }; struct bufferevent { - struct opal_event ev_read; - struct opal_event ev_write; + struct event ev_read; + struct event ev_write; struct evbuffer *input; struct evbuffer *output; @@ -339,38 +843,361 @@ struct bufferevent { short enabled; /* events that are currently enabled */ }; -struct bufferevent *bufferevent_new(int fd, + +/** + Create a new bufferevent. + + libevent provides an abstraction on top of the regular event callbacks. + This abstraction is called a buffered event. A buffered event provides + input and output buffers that get filled and drained automatically. The + user of a buffered event no longer deals directly with the I/O, but + instead is reading from input and writing to output buffers. + + Once initialized, the bufferevent structure can be used repeatedly with + bufferevent_enable() and bufferevent_disable(). + + When read enabled the bufferevent will try to read from the file descriptor + and call the read callback. The write callback is executed whenever the + output buffer is drained below the write low watermark, which is 0 by + default. + + If multiple bases are in use, bufferevent_base_set() must be called before + enabling the bufferevent for the first time. + + @param fd the file descriptor from which data is read and written to. + This file descriptor is not allowed to be a pipe(2). + @param readcb callback to invoke when there is data to be read, or NULL if + no callback is desired + @param writecb callback to invoke when the file descriptor is ready for + writing, or NULL if no callback is desired + @param errorcb callback to invoke when there is an error on the file + descriptor + @param cbarg an argument that will be supplied to each of the callbacks + (readcb, writecb, and errorcb) + @return a pointer to a newly allocated bufferevent struct, or NULL if an + error occurred + @see bufferevent_base_set(), bufferevent_free() + */ +struct bufferevent * bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg); + + +/** + Assign a bufferevent to a specific event_base. + + @param base an event_base returned by event_init() + @param bufev a bufferevent struct returned by bufferevent_new() + @return 0 if successful, or -1 if an error occurred + @see bufferevent_new() + */ +int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev); + + +/** + Assign a priority to a bufferevent. + + @param bufev a bufferevent struct + @param pri the priority to be assigned + @return 0 if successful, or -1 if an error occurred + */ int bufferevent_priority_set(struct bufferevent *bufev, int pri); + + +/** + Deallocate the storage associated with a bufferevent structure. + + @param bufev the bufferevent structure to be freed. + */ void bufferevent_free(struct bufferevent *bufev); -int bufferevent_write(struct bufferevent *bufev, void *data, size_t size); + + +/** + Write data to a bufferevent buffer. + + The bufferevent_write() function can be used to write data to the file + descriptor. The data is appended to the output buffer and written to the + descriptor automatically as it becomes available for writing. + + @param bufev the bufferevent to be written to + @param data a pointer to the data to be written + @param size the length of the data, in bytes + @return 0 if successful, or -1 if an error occurred + @see bufferevent_write_buffer() + */ +int bufferevent_write(struct bufferevent *bufev, + const void *data, size_t size); + + +/** + Write data from an evbuffer to a bufferevent buffer. The evbuffer is + being drained as a result. + + @param bufev the bufferevent to be written to + @param buf the evbuffer to be written + @return 0 if successful, or -1 if an error occurred + @see bufferevent_write() + */ int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf); + + +/** + Read data from a bufferevent buffer. + + The bufferevent_read() function is used to read data from the input buffer. + + @param bufev the bufferevent to be read from + @param data pointer to a buffer that will store the data + @param size the size of the data buffer, in bytes + @return the amount of data read, in bytes. + */ size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size); + +/** + Enable a bufferevent. + + @param bufev the bufferevent to be enabled + @param event any combination of EV_READ | EV_WRITE. + @return 0 if successful, or -1 if an error occurred + @see bufferevent_disable() + */ int bufferevent_enable(struct bufferevent *bufev, short event); + + +/** + Disable a bufferevent. + + @param bufev the bufferevent to be disabled + @param event any combination of EV_READ | EV_WRITE. + @return 0 if successful, or -1 if an error occurred + @see bufferevent_enable() + */ int bufferevent_disable(struct bufferevent *bufev, short event); + + +/** + Set the read and write timeout for a buffered event. + + @param bufev the bufferevent to be modified + @param timeout_read the read timeout + @param timeout_write the write timeout + */ void bufferevent_settimeout(struct bufferevent *bufev, int timeout_read, int timeout_write); -#define OPAL_EVBUFFER_LENGTH(x) (x)->off -#define OPAL_EVBUFFER_DATA(x) (x)->buffer -#define OPAL_EVBUFFER_INPUT(x) (x)->input -#define OPAL_EVBUFFER_OUTPUT(x) (x)->output +#define EVBUFFER_LENGTH(x) (x)->off +#define EVBUFFER_DATA(x) (x)->buffer +#define EVBUFFER_INPUT(x) (x)->input +#define EVBUFFER_OUTPUT(x) (x)->output + + +/** + Allocate storage for a new evbuffer. + + @return a pointer to a newly allocated evbuffer struct, or NULL if an error + occurred + */ struct evbuffer *evbuffer_new(void); + + +/** + Deallocate storage for an evbuffer. + + @param pointer to the evbuffer to be freed + */ void evbuffer_free(struct evbuffer *); + + +/** + Expands the available space in an event buffer. + + Expands the available space in the event buffer to at least datlen + + @param buf the event buffer to be expanded + @param datlen the new minimum length requirement + @return 0 if successful, or -1 if an error occurred +*/ int evbuffer_expand(struct evbuffer *, size_t); -int evbuffer_add(struct evbuffer *, void *, size_t); + + +/** + Append data to the end of an evbuffer. + + @param buf the event buffer to be appended to + @param data pointer to the beginning of the data buffer + @param datlen the number of bytes to be copied from the data buffer + */ +int evbuffer_add(struct evbuffer *, const void *, size_t); + + + +/** + Read data from an event buffer and drain the bytes read. + + @param buf the event buffer to be read from + @param data the destination buffer to store the result + @param datlen the maximum size of the destination buffer + @return the number of bytes read + */ int evbuffer_remove(struct evbuffer *, void *, size_t); + + +/** + * Read a single line from an event buffer. + * + * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'. + * The returned buffer needs to be freed by the caller. + * + * @param buffer the evbuffer to read from + * @return pointer to a single line, or NULL if an error occurred + */ char *evbuffer_readline(struct evbuffer *); + + +/** + Move data from one evbuffer into another evbuffer. + + This is a destructive add. The data from one buffer moves into + the other buffer. The destination buffer is expanded as needed. + + @param outbuf the output buffer + @param inbuf the input buffer + @return 0 if successful, or -1 if an error occurred + */ int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *); -int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...); + + +/** + Append a formatted string to the end of an evbuffer. + + @param buf the evbuffer that will be appended to + @param fmt a format string + @param ... arguments that will be passed to printf(3) + @return 0 if successful, or -1 if an error occurred + */ +int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 2, 3))) +#endif +; + + +/** + Append a va_list formatted string to the end of an evbuffer. + + @param buf the evbuffer that will be appended to + @param fmt a format string + @param ap a varargs va_list argument array that will be passed to vprintf(3) + @return 0 if successful, or -1 if an error occurred + */ int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap); + + +/** + Remove a specified number of bytes data from the beginning of an evbuffer. + + @param buf the evbuffer to be drained + @param len the number of bytes to drain from the beginning of the buffer + @return 0 if successful, or -1 if an error occurred + */ void evbuffer_drain(struct evbuffer *, size_t); + + +/** + Write the contents of an evbuffer to a file descriptor. + + The evbuffer will be drained after the bytes have been successfully written. + + @param buffer the evbuffer to be written and drained + @param fd the file descriptor to be written to + @return the number of bytes written, or -1 if an error occurred + @see evbuffer_read() + */ int evbuffer_write(struct evbuffer *, int); + + +/** + Read from a file descriptor and store the result in an evbuffer. + + @param buf the evbuffer to store the result + @param fd the file descriptor to read from + @param howmuch the number of bytes to be read + @return the number of bytes read, or -1 if an error occurred + @see evbuffer_write() + */ int evbuffer_read(struct evbuffer *, int, int); + + +/** + Find a string within an evbuffer. + + @param buffer the evbuffer to be searched + @param what the string to be searched for + @param len the length of the search string + @return a pointer to the beginning of the search string, or NULL if the search failed. + */ u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t); + +/** + Set a callback to invoke when the evbuffer is modified. + + @param buffer the evbuffer to be monitored + @param cb the callback function to invoke when the evbuffer is modified + @param cbarg an argument to be provided to the callback function + */ void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_t, void *), void *); +/* + * Marshaling tagged data - We assume that all tags are inserted in their + * numeric order - so that unknown tags will always be higher than the + * known ones - and we can just ignore the end of an event buffer. + */ + +void evtag_init(void); + +void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data, + ev_uint32_t len); + +/** + Encode an integer and store it in an evbuffer. + + We encode integer's by nibbles; the first nibble contains the number + of significant nibbles - 1; this allows us to encode up to 64-bit + integers. This function is byte-order independent. + + @param evbuf evbuffer to store the encoded number + @param number a 32-bit integer + */ +void encode_int(struct evbuffer *evbuf, ev_uint32_t number); + +void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, + ev_uint32_t integer); + +void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, + const char *string); + +void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, + struct timeval *tv); + +int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, + struct evbuffer *dst); +int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag); +int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength); +int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength); +int evtag_consume(struct evbuffer *evbuf); + +int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, + ev_uint32_t *pinteger); + +int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, + void *data, size_t len); + +int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag, + char **pstring); + +int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag, + struct timeval *ptv); + /* This is to prevent event library from picking up the win32_ops since this will be picked up over select(). By using select, we can pretty much use the OOB and PTL as is. Otherwise, there would have @@ -383,6 +1210,7 @@ extern const struct opal_eventop opal_win32ops; } #endif + /* #defines to allow callers to know if opal_event_loop is going to do anything */ #if defined(HAVE_SELECT) && HAVE_SELECT @@ -401,4 +1229,6 @@ extern const struct opal_eventop opal_win32ops; #define OPAL_HAVE_WORKING_EVENTOPS 0 #endif + + #endif /* _EVENT_H_ */ diff --git a/opal/event/event_rename.h b/opal/event/event_rename.h index bdda6e8271..23cb74f5c0 100644 --- a/opal/event/event_rename.h +++ b/opal/event/event_rename.h @@ -2,6 +2,7 @@ * * Copyright (c) 2004-2006 The Regents of the University of California. * All rights reserved. + * Copyright (c) 2008 Cisco Systems, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -13,8 +14,8 @@ /* buffer.c */ #define evbuffer_add opal_evbuffer_add #define evbuffer_add_buffer opal_evbuffer_add_buffer -#define evbuffer_add_vprintf opal_evbuffer_add_vprintf #define evbuffer_add_printf opal_evbuffer_add_printf +#define evbuffer_add_vprintf opal_evbuffer_add_vprintf #define evbuffer_drain opal_evbuffer_drain #define evbuffer_expand opal_evbuffer_expand #define evbuffer_find opal_evbuffer_find @@ -32,17 +33,20 @@ /* epoll_sub.c */ /* these symbols should *NOT* be renamed */ -/* evbuffer.c */ -#define bufferevent_disable opal_bufferevent_disable -#define bufferevent_enable opal_bufferevent_enable -#define bufferevent_free opal_bufferevent_free -#define bufferevent_new opal_bufferevent_new -#define bufferevent_priority_set opal_bufferevent_priority_set -#define bufferevent_read opal_bufferevent_read -#define bufferevent_settimeout opal_bufferevent_settimeout -#define bufferevent_setwatermark opal_bufferevent_setwatermark -#define bufferevent_write opal_bufferevent_write -#define bufferevent_write_buffer opal_bufferevent_write_buffer + +/* event.h */ +#define OPAL_EV_TIMEOUT EV_TIMEOUT +#define OPAL_EV_READ EV_READ +#define OPAL_EV_WRITE EV_WRITE +#define OPAL_EV_SIGNAL EV_SIGNAL +#define OPAL_EV_PERSIST EV_PERSIST + +#define OPAL_EVENT_SIGNAL(ev) EVENT_SIGNAL(ev) + +#define OPAL_EVLOOP_ONCE EVLOOP_ONCE +#define OPAL_EVLOOP_NONBLOCK EVLOOP_NONBLOCK +#define OPAL_EVLOOP_ONELOOP EVLOOP_ONELOOP + /* event.c */ #define current_base opal_current_base @@ -51,6 +55,76 @@ #define event_get_version opal_event_get_version #define event_gotsig opal_event_gotsig #define event_sigcb opal_event_sigcb +#define event_add opal_event_add_i +#define event_del opal_event_del_i +#define event_active opal_event_active_i +#define event_base opal_event_base +#define event opal_event +#define event_base_new opal_event_base_new +#define event_init opal_event_init +#define event_reinit opal_event_reinit +#define event_dispatch opal_event_dispatch +#define event_base_dispatch opal_event_base_dispatch +#define event_base_get_method opal_event_base_get_method +#define event_base_free opal_event_base_free +#define event_set_log_callback opal_event_set_log_callback +#define event_base_set opal_event_base_set +#define event_loop opal_event_loop +#define event_base_loop opal_event_base_loop +#define event_loopexit opal_event_loopexit +#define event_loopbreak opal_event_loopbreak +#define event_base_loopbreak opal_event_base_loopbreak +#define event_set opal_event_set +#define event_once opal_event_once +#define event_base_once opal_event_base_once +#define event_pending opal_event_pending +#define event_get_version opal_event_get_version +#define event_get_method opal_event_get_method +#define event_priority_init opal_event_priority_init +#define event_base_priority_init opal_event_base_priority_init +#define event_priority_set opal_event_priority_set +#define evbuffer opal_evbuffer +#define bufferevent opal_bufferevent +#define event_watermark opal_event_watermark +#define bufferevent_new opal_bufferevent_new +#define bufferevent_priority_set opal_bufferevent_priority_set +#define bufferevent_free opal_bufferevent_free +#define bufferevent_write opal_bufferevent_write +#define bufferevent_write_buffer opal_bufferevent_write_buffer +#define bufferevent_read opal_bufferevent_read +#define bufferevent_enable opal_bufferevent_enable +#define bufferevent_disable opal_bufferevent_disable +#define bufferevent_settimeout opal_bufferevent_settimeout +#define evbuffer_new opal_evbuffer_new +#define evbuffer_free opal_evbuffer_free +#define evbuffer_expand opal_evbuffer_expand +#define evbuffer_add opal_evbuffer_add +#define evbuffer_remove opal_evbuffer_remove +#define evbuffer_readline opal_evbuffer_readline +#define evbuffer_add_buffer opal_evbuffer_add_buffer +#define evbuffer_add_printf opal_evbuffer_add_printf +#define evbuffer_add_vprintf opal_evbuffer_add_vprintf +#define evbuffer_drain opal_evbuffer_drain +#define evbuffer_write opal_evbuffer_write +#define evbuffer_read opal_evbuffer_read +#define evbuffer_find opal_evbuffer_find +#define evbuffer_setcb opal_evbuffer_setcb +#define evtag_init opal_evtag_init +#define evtag_marshal opal_evtag_marshal +#define encode_int opal_encode_int +#define evtag_marshal_int opal_evtag_marshal_int +#define evtag_marshal_string opal_evtag_marshal_string +#define evtag_marshal_timeval opal_evtag_marshal_timeval +#define evtag_unmarshal opal_evtag_unmarshal +#define evtag_peek opal_evtag_peek +#define evtag_peek_length opal_evtag_peek_length +#define evtag_payload_length opal_evtag_payload_length +#define evtag_consume opal_evtag_consume +#define evtag_unmarshal_fixed opal_evtag_unmarshal_fixed +#define evtag_unmarshal_string opal_evtag_unmarshal_string +#define evtag_unmarshal_timeval opal_evtag_unmarshal_timeval +#define evtag_unmarshal_int opal_evtag_unmarshal_int + /* log.c */ #define _event_debugx opal__event_debugx @@ -62,9 +136,47 @@ #define event_warnx opal_event_warnx /* poll.c */ -#define poll_add opal_poll_add -#define poll_del opal_poll_del -#define poll_dispatch opal_poll_dispatch -#define poll_init opal_poll_init -#define poll_recalc opal_poll_recalc +#define pollop opal_pollop + +/* event-internal.h */ +#define eventop opal_eventop +#define event_base opal_event_base +#define _evsignal_set_handler _opal__evsignal_set_handler +#define _evsignal_restore_handler _opal__evsignal_restore_handler + +/* evsignal.h */ +#define evsignal_info opal_evsignal_info +#define evsignal_init opal_evsignal_init +#define evsignal_process opal_evsignal_process +#define evsignal_add opal_evsignal_add +#define evsignal_del opal_evsignal_del +#define evsignal_dealloc opal_evsignal_dealloc + +/* evutil.c*/ +#define evutil_socketpair opal_evutil_socketpair +#define evutil_make_socket_nonblocking opal_evutil_make_socket_nonblocking + +/* kqueue.c */ +#define kqop opal_kqop + +/* min_heap.h */ +#define min_heap_t opal_min_heap_t +#define min_heap_ctor opal_min_heap_ctor +#define min_heap_dtor opal_min_heap_dtor +#define min_heap_elem_init opal_min_heap_elem_init +#define min_heap_elem_greater opal_min_heap_elem_greater +#define min_heap_empty opal_min_heap_empty +#define min_heap_size opal_min_heap_size +#define min_heap_top opal_min_heap_top +#define min_heap_reserve opal_min_heap_reserve +#define min_heap_push opal_min_heap_push +#define min_heap_pop opal_min_heap_pop +#define min_heap_erase opal_min_heap_erase +#define min_heap_shift_up_ opal_min_heap_shift_up_ +#define min_heap_shift_down_ opal_min_heap_shift_down_ + +/* select.c */ +#define selectop opal_selectop + + diff --git a/opal/event/evsignal.h b/opal/event/evsignal.h index 8866ca4317..0d1e83140b 100644 --- a/opal/event/evsignal.h +++ b/opal/event/evsignal.h @@ -27,11 +27,26 @@ #ifndef _EVSIGNAL_H_ #define _EVSIGNAL_H_ -void opal_evsignal_init(sigset_t *); -void opal_evsignal_process(void); -int opal_evsignal_recalc(sigset_t *); -int opal_evsignal_deliver(sigset_t *); -int opal_evsignal_add(sigset_t *, struct opal_event *); -int opal_evsignal_del(sigset_t *, struct opal_event *); +typedef void (*ev_sighandler_t)(int); + +struct evsignal_info { + struct event_list signalqueue; + struct event ev_signal; + int ev_signal_pair[2]; + int ev_signal_added; + volatile sig_atomic_t evsignal_caught; + sig_atomic_t evsigcaught[NSIG]; +#ifdef HAVE_SIGACTION + struct sigaction **sh_old; +#else + ev_sighandler_t **sh_old; +#endif + int sh_old_max; +}; +void evsignal_init(struct event_base *); +void evsignal_process(struct event_base *); +int evsignal_add(struct event *); +int evsignal_del(struct event *); +void evsignal_dealloc(struct event_base *); #endif /* _EVSIGNAL_H_ */ diff --git a/opal/event/evutil.c b/opal/event/evutil.c new file mode 100644 index 0000000000..35366ae453 --- /dev/null +++ b/opal/event/evutil.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2007 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "opal_config.h" + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include +#include "misc.h" +#endif + +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +#include "evutil.h" +#include "log.h" + +int +evutil_socketpair(int family, int type, int protocol, int fd[2]) +{ +#ifndef WIN32 + return socketpair(family, type, protocol, fd); +#else + /* This code is originally from Tor. Used with permission. */ + + /* This socketpair does not work when localhost is down. So + * it's really not the same thing at all. But it's close enough + * for now, and really, when localhost is down sometimes, we + * have other problems too. + */ + int listener = -1; + int connector = -1; + int acceptor = -1; + struct sockaddr_in listen_addr; + struct sockaddr_in connect_addr; + int size; + int saved_errno = -1; + + if (protocol +#ifdef AF_UNIX + || family != AF_UNIX +#endif + ) { + EVUTIL_SET_SOCKET_ERROR(WSAEAFNOSUPPORT); + return -1; + } + if (!fd) { + EVUTIL_SET_SOCKET_ERROR(WSAEINVAL); + return -1; + } + + listener = socket(AF_INET, type, 0); + if (listener < 0) + return -1; + memset(&listen_addr, 0, sizeof(listen_addr)); + listen_addr.sin_family = AF_INET; + listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + listen_addr.sin_port = 0; /* kernel chooses port. */ + if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr)) + == -1) + goto tidy_up_and_fail; + if (listen(listener, 1) == -1) + goto tidy_up_and_fail; + + connector = socket(AF_INET, type, 0); + if (connector < 0) + goto tidy_up_and_fail; + /* We want to find out the port number to connect to. */ + size = sizeof(connect_addr); + if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1) + goto tidy_up_and_fail; + if (size != sizeof (connect_addr)) + goto abort_tidy_up_and_fail; + if (connect(connector, (struct sockaddr *) &connect_addr, + sizeof(connect_addr)) == -1) + goto tidy_up_and_fail; + + size = sizeof(listen_addr); + acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size); + if (acceptor < 0) + goto tidy_up_and_fail; + if (size != sizeof(listen_addr)) + goto abort_tidy_up_and_fail; + EVUTIL_CLOSESOCKET(listener); + /* Now check we are talking to ourself by matching port and host on the + two sockets. */ + if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1) + goto tidy_up_and_fail; + if (size != sizeof (connect_addr) + || listen_addr.sin_family != connect_addr.sin_family + || listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr + || listen_addr.sin_port != connect_addr.sin_port) + goto abort_tidy_up_and_fail; + fd[0] = connector; + fd[1] = acceptor; + + return 0; + + abort_tidy_up_and_fail: + saved_errno = WSAECONNABORTED; + tidy_up_and_fail: + if (saved_errno < 0) + saved_errno = WSAGetLastError(); + if (listener != -1) + EVUTIL_CLOSESOCKET(listener); + if (connector != -1) + EVUTIL_CLOSESOCKET(connector); + if (acceptor != -1) + EVUTIL_CLOSESOCKET(acceptor); + + EVUTIL_SET_SOCKET_ERROR(saved_errno); + return -1; +#endif +} + +int +evutil_make_socket_nonblocking(int fd) +{ +#ifdef WIN32 + { + unsigned long nonblocking = 1; + ioctlsocket(fd, FIONBIO, (unsigned long*) &nonblocking); + } +#else + if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { + event_warn("fcntl(O_NONBLOCK)"); + return -1; +} +#endif + return 0; +} + +#if 0 +ev_int64_t +evutil_strtoll(const char *s, char **endptr, int base) +{ +#ifdef HAVE_STRTOLL + return (ev_int64_t)strtoll(s, endptr, base); +#elif SIZEOF_LONG == 8 + return (ev_int64_t)strtol(s, endptr, base); +#elif defined(WIN32) && defined(_MSC_VER) && _MSC_VER < 1300 + /* XXXX on old versions of MS APIs, we only support base + * 10. */ + ev_int64_t r; + if (base != 10) + return 0; + r = (ev_int64_t) _atoi64(s); + while (isspace(*s)) + ++s; + while (isdigit(*s)) + ++s; + if (endptr) + *endptr = (char*) s; + return r; +#elif defined(WIN32) + return (ev_int64_t) _strtoi64(s, endptr, base); +#else +#error "I don't know how to parse 64-bit integers." +#endif +} +#endif + diff --git a/opal/event/evutil.h b/opal/event/evutil.h new file mode 100644 index 0000000000..af6e8ec8ad --- /dev/null +++ b/opal/event/evutil.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2007 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _EVUTIL_H_ +#define _EVUTIL_H_ + +/** @file evutil.h + + Common convenience functions for cross-platform portability and + related socket manipulations. + + */ +#include "opal_config.h" +#include "event_rename.h" +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef _EVENT_HAVE_SYS_TIME_H +#include +#endif +#ifdef _EVENT_HAVE_STDINT_H +#include +#elif defined(_EVENT_HAVE_INTTYPES_H) +#include +#endif +#ifdef _EVENT_HAVE_SYS_TYPES_H +#include +#endif + +#ifdef _EVENT_HAVE_UINT64_T +#define ev_uint64_t uint64_t +#define ev_int64_t int64_t +#elif defined(WIN32) +#define ev_uint64_t __uint64_t +#define ev_int64_t __int64_t +#elif SIZEOF_LONG_LONG == 8 +#define ev_uint64_t unsigned long long +#define ev_int64_t long long +#elif SIZEOF_LONG == 8 +#define ev_uint64_t unsigned long +#define ev_int64_t long +#else +#error "No way to define ev_uint64_t" +#endif + +#ifdef _EVENT_HAVE_UINT32_T +#define ev_uint32_t uint32_t +#elif defined(WIN32) +#define ev_uint32_t unsigned int +#elif SIZEOF_LONG == 4 +#define ev_uint32_t unsigned long +#elif SIZEOF_INT == 4 +#define ev_uint32_t unsigned int +#else +#error "No way to define ev_uint32_t" +#endif + +#ifdef _EVENT_HAVE_UINT16_T +#define ev_uint16_t uint16_t +#elif defined(WIN32) +#define ev_uint16_t unsigned short +#elif SIZEOF_INT == 2 +#define ev_uint16_t unsigned int +#elif SIZEOF_SHORT == 2 +#define ev_uint16_t unsigned short +#else +#error "No way to define ev_uint16_t" +#endif + +#ifdef _EVENT_HAVE_UINT8_T +#define ev_uint8_t uint8_t +#else +#define ev_uint8_t unsigned char +#endif + +OPAL_DECLSPEC int evutil_socketpair(int d, int type, int protocol, int sv[2]); +OPAL_DECLSPEC int evutil_make_socket_nonblocking(int sock); + +#ifdef WIN32 +#define EVUTIL_CLOSESOCKET(s) closesocket(s) +#else +#define EVUTIL_CLOSESOCKET(s) close(s) +#endif + +#ifdef WIN32 +#define EVUTIL_SOCKET_ERROR() WSAGetLastError() +#define EVUTIL_SET_SOCKET_ERROR(errcode) \ + do { WSASetLastError(errcode); } while (0) +#else +#define EVUTIL_SOCKET_ERROR() (errno) +#define EVUTIL_SET_SOCKET_ERROR(errcode) \ + do { errno = (errcode); } while (0) +#endif + +/* + * Manipulation functions for struct timeval + */ +#ifdef _EVENT_HAVE_TIMERADD +#define evutil_timeradd(tvp, uvp, vvp) timeradd((tvp), (uvp), (vvp)) +#define evutil_timersub(tvp, uvp, vvp) timersub((tvp), (uvp), (vvp)) +#else +#define evutil_timeradd(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) +#define evutil_timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) +#endif /* !_EVENT_HAVE_HAVE_TIMERADD */ + +#ifdef _EVENT_HAVE_TIMERCLEAR +#define evutil_timerclear(tvp) timerclear(tvp) +#else +#define evutil_timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif + +#ifdef _EVENT_HAVE_TIMERCMP +#define evutil_timercmp(tvp, uvp, cmp) timercmp((tvp), (uvp), cmp) +#else +#define evutil_timercmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) +#endif + +#ifdef _EVENT_HAVE_TIMERISSET +#define evutil_timerisset(tvp) timerisset(tvp) +#else +#define evutil_timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#endif + + +/* big-int related functions */ +ev_int64_t evutil_strtoll(const char *s, char **endptr, int base); + +#ifdef __cplusplus +} +#endif + +#endif /* _EVUTIL_H_ */ diff --git a/opal/event/kqueue.c b/opal/event/kqueue.c index 3b11c38bbc..af8bdd95fc 100644 --- a/opal/event/kqueue.c +++ b/opal/event/kqueue.c @@ -26,8 +26,8 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "opal_config.h" +#include "opal_config.h" #ifdef HAVE_SYS_TYPES_H #include #endif @@ -50,19 +50,24 @@ #include #endif -#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) -#define INTPTR(x) (intptr_t)x +/* Some platforms apparently define the udata field of struct kevent as + * intptr_t, whereas others define it as void*. There doesn't seem to be an + * easy way to tell them apart via autoconf, so we need to use OS macros. */ +#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__) +#define PTR_TO_UDATA(x) ((intptr_t)(x)) #else -#define INTPTR(x) x +#define PTR_TO_UDATA(x) (x) #endif #include "event.h" +#include "event-internal.h" #include "log.h" - #include "opal/threads/mutex.h" extern opal_mutex_t opal_event_lock; + + #define EVLIST_X_KQINKERNEL 0x1000 #define NEVENT 64 @@ -75,87 +80,150 @@ struct kqop { int kq; }; -static void *kq_init (void); -static int kq_add (void *, struct opal_event *); -static int kq_del (void *, struct opal_event *); -static int kq_recalc (struct event_base *, void *, int); +static void *kq_init (struct event_base *); +static int kq_add (void *, struct event *); +static int kq_del (void *, struct event *); static int kq_dispatch (struct event_base *, void *, struct timeval *); static int kq_insert (struct kqop *, struct kevent *); +static void kq_dealloc (struct event_base *, void *); -const struct opal_eventop opal_kqops = { +const struct eventop kqops = { "kqueue", kq_init, kq_add, kq_del, - kq_recalc, - kq_dispatch + kq_dispatch, + kq_dealloc, + 1 /* need reinit */ }; static void * -kq_init(void) +kq_init(struct event_base *base) { - int kq; - struct kqop *kqueueop; + int kq; + struct kqop *kqueueop; - /* Disable kqueue when this environment variable is set */ - if (getenv("EVENT_NOKQUEUE")) - return (NULL); + /* Disable kqueue when this environment variable is set */ + if (getenv("EVENT_NOKQUEUE")) + return (NULL); - if (!(kqueueop = calloc(1, sizeof(struct kqop)))) - return (NULL); + if (!(kqueueop = calloc(1, sizeof(struct kqop)))) + return (NULL); - /* Initalize the kernel queue */ + /* Initalize the kernel queue */ - if ((kq = kqueue()) == -1) { - event_warn("kqueue"); - free (kqueueop); - return (NULL); - } + if ((kq = kqueue()) == -1) { + event_warn("kqueue"); + free (kqueueop); + return (NULL); + } - kqueueop->kq = kq; + kqueueop->kq = kq; - /* Initalize fields */ - kqueueop->changes = malloc(NEVENT * sizeof(struct kevent)); - if (kqueueop->changes == NULL) { - free (kqueueop); - return (NULL); - } - kqueueop->events = malloc(NEVENT * sizeof(struct kevent)); - if (kqueueop->events == NULL) { - free (kqueueop->changes); - free (kqueueop); - return (NULL); - } - kqueueop->nevents = NEVENT; + /* Initalize fields */ + kqueueop->changes = malloc(NEVENT * sizeof(struct kevent)); + if (kqueueop->changes == NULL) { + free (kqueueop); + return (NULL); + } + kqueueop->events = malloc(NEVENT * sizeof(struct kevent)); + if (kqueueop->events == NULL) { + free (kqueueop->changes); + free (kqueueop); + return (NULL); + } + kqueueop->nevents = NEVENT; - /* Check for Mac OS X kqueue bug. */ - kqueueop->changes[0].ident = -1; - kqueueop->changes[0].filter = EVFILT_READ; - kqueueop->changes[0].flags = EV_ADD; - /* - * If kqueue works, then kevent will succeed, and it will - * stick an error in events[0]. If kqueue is broken, then - * kevent will fail. - */ + /* Check for Mac OS X kqueue bug. */ + kqueueop->changes[0].ident = -1; + kqueueop->changes[0].filter = EVFILT_READ; + kqueueop->changes[0].flags = EV_ADD; + /* + * If kqueue works, then kevent will succeed, and it will + * stick an error in events[0]. If kqueue is broken, then + * kevent will fail. + */ + if (kevent(kq, + kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 || + kqueueop->events[0].ident != -1 || + kqueueop->events[0].flags != EV_ERROR) { + event_warn("%s: detected broken kqueue; not using.", __func__); + free(kqueueop->changes); + free(kqueueop->events); + free(kqueueop); + close(kq); + return (NULL); + } + /* Check if the kqueue can support pty */ + { + int master, slave; + char name[1024]; + + if( 0 > openpty( &master, &slave, name, NULL, NULL ) ) { + event_warn("%s: unable to call openpty: error %d (%s)\n", + __func__, errno, strerror(errno) ); + free(kqueueop->changes); + free(kqueueop->events); + free(kqueueop); + close(kq); + return NULL; + } + kqueueop->changes[0].ident = master; + kqueueop->changes[0].filter = EVFILT_READ; + kqueueop->changes[0].flags = EV_ADD; if (kevent(kq, - kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 || - kqueueop->events[0].ident != (unsigned int) -1 || + kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 || + kqueueop->events[0].ident != master || kqueueop->events[0].flags != EV_ERROR) { - event_warn("%s: detected broken kqueue; not using.", __func__); - free(kqueueop->changes); - free(kqueueop->events); - free(kqueueop); - close(kq); - return (NULL); + event_warn("%s: detected broken kqueue (failed add); not using error %d (%s)\n", + __func__, errno, strerror(errno)); + free(kqueueop->changes); + free(kqueueop->events); + free(kqueueop); + close(kq); + close(master); + close(slave); + return (NULL); } + kqueueop->changes[0].ident = master; + kqueueop->changes[0].filter = EVFILT_READ; + kqueueop->changes[0].flags = EV_DELETE; + if (kevent(kq, + kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 || + kqueueop->events[0].ident != master || + kqueueop->events[0].flags != EV_ERROR) { + event_warn("%s: detected broken kqueue (failed delete); not using error %d (%s)", + __func__, errno, strerror(errno)); + free(kqueueop->changes); + free(kqueueop->events); + free(kqueueop); + close(kq); + close(master); + close(slave); + return (NULL); + } + kqueueop->changes[0].ident = master; + kqueueop->changes[0].filter = EVFILT_READ; + kqueueop->changes[0].flags = EV_DELETE; + if (kevent(kq, + kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 || + kqueueop->events[0].ident != master || + kqueueop->events[0].flags != EV_ERROR) { + event_warn("%s: detected broken kqueue (failed delete); not using error %d (%s)", + __func__, errno, strerror(errno)); + free(kqueueop->changes); + free(kqueueop->events); + free(kqueueop); + close(kq); + close(master); + close(slave); + return (NULL); + } + close(master); + close(slave); + } - return (kqueueop); -} - -static int -kq_recalc(struct event_base *base, void *arg, int max) -{ - return (0); + return (kqueueop); } static int @@ -215,23 +283,26 @@ kq_dispatch(struct event_base *base, void *arg, struct timeval *tv) struct kqop *kqop = arg; struct kevent *changes = kqop->changes; struct kevent *events = kqop->events; - struct opal_event *ev; - struct timespec ts; + struct event *ev; + struct timespec ts, *ts_p = NULL; int i, res; - TIMEVAL_TO_TIMESPEC(tv, &ts); - + if (tv != NULL) { + TIMEVAL_TO_TIMESPEC(tv, &ts); + ts_p = &ts; + } /* we should release the lock if we're going to enter the kernel in a multi-threaded application. However, if we're single threaded, there's really no advantage to releasing the lock and it just takes up time we could spend doing something else. */ OPAL_THREAD_UNLOCK(&opal_event_lock); - res = kevent(kqop->kq, changes, kqop->nchanges, - events, kqop->nevents, &ts); + + res = kevent(kqop->kq, changes, kqop->nchanges, + events, kqop->nevents, ts_p); OPAL_THREAD_LOCK(&opal_event_lock); - kqop->nchanges = 0; + kqop->nchanges = 0; if (res == -1) { if (errno != EINTR) { event_warn("kevent"); @@ -264,27 +335,29 @@ kq_dispatch(struct event_base *base, void *arg, struct timeval *tv) events[i].data == ENOENT) continue; errno = events[i].data; + event_warn( "kevent failed with error code %d (%s)\n", + errno, strerror(errno) ); return (-1); } - ev = (struct opal_event *)events[i].udata; + ev = (struct event *)events[i].udata; if (events[i].filter == EVFILT_READ) { - which |= OPAL_EV_READ; + which |= EV_READ; } else if (events[i].filter == EVFILT_WRITE) { - which |= OPAL_EV_WRITE; + which |= EV_WRITE; } else if (events[i].filter == EVFILT_SIGNAL) { - which |= OPAL_EV_SIGNAL; + which |= EV_SIGNAL; } if (!which) continue; - if (!(ev->ev_events & OPAL_EV_PERSIST)) - opal_event_del_i(ev); + if (!(ev->ev_events & EV_PERSIST)) + ev->ev_flags &= ~EVLIST_X_KQINKERNEL; - opal_event_active_i(ev, which, - ev->ev_events & OPAL_EV_SIGNAL ? events[i].data : 1); + event_active(ev, which, + ev->ev_events & EV_SIGNAL ? events[i].data : 1); } return (0); @@ -292,33 +365,37 @@ kq_dispatch(struct event_base *base, void *arg, struct timeval *tv) static int -kq_add(void *arg, struct opal_event *ev) +kq_add(void *arg, struct event *ev) { struct kqop *kqop = arg; struct kevent kev; - if (ev->ev_events & OPAL_EV_SIGNAL) { + if (ev->ev_events & EV_SIGNAL) { int nsignal = OPAL_EVENT_SIGNAL(ev); + struct timespec timeout = { 0, 0 }; memset(&kev, 0, sizeof(kev)); kev.ident = nsignal; kev.filter = EVFILT_SIGNAL; kev.flags = EV_ADD; - if (!(ev->ev_events & OPAL_EV_PERSIST)) + if (!(ev->ev_events & EV_PERSIST)) kev.flags |= EV_ONESHOT; - kev.udata = (void *) INTPTR(ev); - - if (kq_insert(kqop, &kev) == -1) - return (-1); + kev.udata = PTR_TO_UDATA(ev); - if (signal(nsignal, kq_sighandler) == SIG_ERR) + /* Be ready for the signal if it is sent any time between + * now and the next call to kq_dispatch. */ + if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) + return (-1); + + if (_evsignal_set_handler(ev->ev_base, nsignal, + kq_sighandler) == -1) return (-1); ev->ev_flags |= EVLIST_X_KQINKERNEL; return (0); } - if (ev->ev_events & OPAL_EV_READ) { + if (ev->ev_events & EV_READ) { memset(&kev, 0, sizeof(kev)); kev.ident = ev->ev_fd; kev.filter = EVFILT_READ; @@ -327,9 +404,9 @@ kq_add(void *arg, struct opal_event *ev) kev.fflags = NOTE_EOF; #endif kev.flags = EV_ADD; - if (!(ev->ev_events & OPAL_EV_PERSIST)) + if (!(ev->ev_events & EV_PERSIST)) kev.flags |= EV_ONESHOT; - kev.udata = (void *) INTPTR(ev); + kev.udata = PTR_TO_UDATA(ev); if (kq_insert(kqop, &kev) == -1) return (-1); @@ -337,14 +414,14 @@ kq_add(void *arg, struct opal_event *ev) ev->ev_flags |= EVLIST_X_KQINKERNEL; } - if (ev->ev_events & OPAL_EV_WRITE) { + if (ev->ev_events & EV_WRITE) { memset(&kev, 0, sizeof(kev)); kev.ident = ev->ev_fd; kev.filter = EVFILT_WRITE; kev.flags = EV_ADD; - if (!(ev->ev_events & OPAL_EV_PERSIST)) + if (!(ev->ev_events & EV_PERSIST)) kev.flags |= EV_ONESHOT; - kev.udata = (void *) INTPTR(ev); + kev.udata = PTR_TO_UDATA(ev); if (kq_insert(kqop, &kev) == -1) return (-1); @@ -356,7 +433,7 @@ kq_add(void *arg, struct opal_event *ev) } static int -kq_del(void *arg, struct opal_event *ev) +kq_del(void *arg, struct event *ev) { struct kqop *kqop = arg; struct kevent kev; @@ -364,25 +441,25 @@ kq_del(void *arg, struct opal_event *ev) if (!(ev->ev_flags & EVLIST_X_KQINKERNEL)) return (0); - if (ev->ev_events & OPAL_EV_SIGNAL) { + if (ev->ev_events & EV_SIGNAL) { int nsignal = OPAL_EVENT_SIGNAL(ev); memset(&kev, 0, sizeof(kev)); - kev.ident = (int)signal; + kev.ident = nsignal; kev.filter = EVFILT_SIGNAL; kev.flags = EV_DELETE; if (kq_insert(kqop, &kev) == -1) return (-1); - if (signal(nsignal, SIG_DFL) == SIG_ERR) + if (_evsignal_restore_handler(ev->ev_base, nsignal) == -1) return (-1); ev->ev_flags &= ~EVLIST_X_KQINKERNEL; return (0); } - if (ev->ev_events & OPAL_EV_READ) { + if (ev->ev_events & EV_READ) { memset(&kev, 0, sizeof(kev)); kev.ident = ev->ev_fd; kev.filter = EVFILT_READ; @@ -394,7 +471,7 @@ kq_del(void *arg, struct opal_event *ev) ev->ev_flags &= ~EVLIST_X_KQINKERNEL; } - if (ev->ev_events & OPAL_EV_WRITE) { + if (ev->ev_events & EV_WRITE) { memset(&kev, 0, sizeof(kev)); kev.ident = ev->ev_fd; kev.filter = EVFILT_WRITE; @@ -408,3 +485,18 @@ kq_del(void *arg, struct opal_event *ev) return (0); } + +static void +kq_dealloc(struct event_base *base, void *arg) +{ + struct kqop *kqop = arg; + + if (kqop->changes) + free(kqop->changes); + if (kqop->events) + free(kqop->events); + if (kqop->kq) + close(kqop->kq); + memset(kqop, 0, sizeof(struct kqop)); + free(kqop); +} diff --git a/opal/event/log.c b/opal/event/log.c index a91160310f..5823071d9a 100644 --- a/opal/event/log.c +++ b/opal/event/log.c @@ -46,7 +46,6 @@ #include "misc.h" #endif #include -#include #ifdef HAVE_SYS_TIME_H #include #else diff --git a/opal/event/log.h b/opal/event/log.h index e19d8a06ea..7bc6632b8d 100644 --- a/opal/event/log.h +++ b/opal/event/log.h @@ -27,17 +27,25 @@ #ifndef _LOG_H_ #define _LOG_H_ -void event_err(int eval, const char *fmt, ...); -void event_warn(const char *fmt, ...); -void event_errx(int eval, const char *fmt, ...); -void event_warnx(const char *fmt, ...); -void event_msgx(const char *fmt, ...); -void _event_debugx(const char *fmt, ...); -#undef USE_DEBUG +#ifdef __GNUC__ +#define EV_CHECK_FMT(a,b) __attribute__((format(printf, a, b))) +#else +#define EV_CHECK_FMT(a,b) +#endif + +void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3); +void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2); +void event_errx(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3); +void event_warnx(const char *fmt, ...) EV_CHECK_FMT(1,2); +void event_msgx(const char *fmt, ...) EV_CHECK_FMT(1,2); +void _event_debugx(const char *fmt, ...) EV_CHECK_FMT(1,2); + #ifdef USE_DEBUG #define event_debug(x) _event_debugx x #else -#define event_debug(x) +#define event_debug(x) do {;} while (0) #endif +#undef EV_CHECK_FMT + #endif diff --git a/opal/event/min_heap.h b/opal/event/min_heap.h new file mode 100644 index 0000000000..389d6dbed4 --- /dev/null +++ b/opal/event/min_heap.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2006 Maxim Yegorushkin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _MIN_HEAP_H_ +#define _MIN_HEAP_H_ + +#include "event.h" + +typedef struct min_heap +{ + struct event** p; + unsigned n, a; +} min_heap_t; + +static inline void min_heap_ctor(min_heap_t* s); +static inline void min_heap_dtor(min_heap_t* s); +static inline void min_heap_elem_init(struct event* e); +static inline int min_heap_elem_greater(struct event *a, struct event *b); +static inline int min_heap_empty(min_heap_t* s); +static inline unsigned min_heap_size(min_heap_t* s); +static inline struct event* min_heap_top(min_heap_t* s); +static inline int min_heap_reserve(min_heap_t* s, unsigned n); +static inline int min_heap_push(min_heap_t* s, struct event* e); +static inline struct event* min_heap_pop(min_heap_t* s); +static inline int min_heap_erase(min_heap_t* s, struct event* e); +static inline void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e); +static inline void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e); + +int min_heap_elem_greater(struct event *a, struct event *b) +{ + return timercmp(&a->ev_timeout, &b->ev_timeout, >); +} + +void min_heap_ctor(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; } +void min_heap_dtor(min_heap_t* s) { free(s->p); } +void min_heap_elem_init(struct event* e) { e->min_heap_idx = -1; } +int min_heap_empty(min_heap_t* s) { return 0u == s->n; } +unsigned min_heap_size(min_heap_t* s) { return s->n; } +struct event* min_heap_top(min_heap_t* s) { return s->n ? *s->p : 0; } + +int min_heap_push(min_heap_t* s, struct event* e) +{ + if(min_heap_reserve(s, s->n + 1)) + return -1; + min_heap_shift_up_(s, s->n++, e); + return 0; +} + +struct event* min_heap_pop(min_heap_t* s) +{ + if(s->n) + { + struct event* e = *s->p; + e->min_heap_idx = -1; + min_heap_shift_down_(s, 0u, s->p[--s->n]); + return e; + } + return 0; +} + +int min_heap_erase(min_heap_t* s, struct event* e) +{ + if(((unsigned int)-1) != e->min_heap_idx) + { + min_heap_shift_down_(s, e->min_heap_idx, s->p[--s->n]); + e->min_heap_idx = -1; + return 0; + } + return -1; +} + +int min_heap_reserve(min_heap_t* s, unsigned n) +{ + if(s->a < n) + { + struct event** p; + unsigned a = s->a ? s->a * 2 : 8; + if(a < n) + a = n; + if(!(p = (struct event**)realloc(s->p, a * sizeof *p))) + return -1; + s->p = p; + s->a = a; + } + return 0; +} + +void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e) +{ + unsigned parent = (hole_index - 1) / 2; + while(hole_index && min_heap_elem_greater(s->p[parent], e)) + { + (s->p[hole_index] = s->p[parent])->min_heap_idx = hole_index; + hole_index = parent; + parent = (hole_index - 1) / 2; + } + (s->p[hole_index] = e)->min_heap_idx = hole_index; +} + +void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e) +{ + unsigned min_child = 2 * (hole_index + 1); + while(min_child <= s->n) + { + min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]); + if(!(min_heap_elem_greater(e, s->p[min_child]))) + break; + (s->p[hole_index] = s->p[min_child])->min_heap_idx = hole_index; + hole_index = min_child; + min_child = 2 * (hole_index + 1); + } + min_heap_shift_up_(s, hole_index, e); +} + +#endif /* _MIN_HEAP_H_ */ diff --git a/opal/event/poll.c b/opal/event/poll.c index 6877843357..b19043c93c 100644 --- a/opal/event/poll.c +++ b/opal/event/poll.c @@ -37,7 +37,6 @@ #include #endif #include -#include #ifdef HAVE_POLL_H #include #endif @@ -66,80 +65,58 @@ extern volatile sig_atomic_t opal_evsignal_caught; extern opal_mutex_t opal_event_lock; -extern volatile sig_atomic_t evsignal_caught; struct pollop { int event_count; /* Highest number alloc */ int nfds; /* Size of event_* */ int fd_count; /* Size of idxplus1_by_fd */ struct pollfd *event_set; - struct opal_event **event_r_back; - struct opal_event **event_w_back; + struct event **event_r_back; + struct event **event_w_back; int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so * that 0 (which is easy to memset) can mean * "no entry." */ -#if OPAL_EVENT_USE_SIGNALS - sigset_t evsigmask; -#endif }; -void *poll_init (void); -int poll_add (void *, struct opal_event *); -int poll_del (void *, struct opal_event *); -int poll_recalc (struct event_base *, void *, int); -int poll_dispatch (struct event_base *, void *, struct timeval *); +static void *poll_init (struct event_base *); +static int poll_add (void *, struct event *); +static int poll_del (void *, struct event *); +static int poll_dispatch (struct event_base *, void *, struct timeval *); +static void poll_dealloc (struct event_base *, void *); -struct opal_eventop opal_pollops = { +const struct eventop pollops = { "poll", poll_init, poll_add, poll_del, - poll_recalc, - poll_dispatch + poll_dispatch, + poll_dealloc, + 0 }; -void * -poll_init(void) +static void * +poll_init(struct event_base *base) { struct pollop *pollop; - /* Disable kqueue when this environment variable is set */ + /* Disable poll when this environment variable is set */ if (getenv("EVENT_NOPOLL")) return (NULL); - if (!(pollop = calloc(1, sizeof(struct pollop)))) + if (!(pollop = calloc(1, sizeof(struct pollop)))) return (NULL); - #if OPAL_EVENT_USE_SIGNALS - opal_evsignal_init(&pollop->evsigmask); + evsignal_init(base); #endif - return (pollop); } -/* - * Called with the highest fd that we know about. If it is 0, completely - * recalculate everything. - */ - -int -poll_recalc(struct event_base *base, void *arg, int max) -{ -#if OPAL_EVENT_USE_SIGNALS - struct pollop *pop = arg; - - return (opal_evsignal_recalc(&pop->evsigmask)); -#else - return 0; -#endif -} - #ifdef CHECK_INVARIANTS static void poll_check_ok(struct pollop *pop) { int i, idx; - struct opal_event *ev; + struct event *ev; for (i = 0; i < pop->fd_count; ++i) { idx = pop->idxplus1_by_fd[i]-1; @@ -168,49 +145,44 @@ poll_check_ok(struct pollop *pop) #define poll_check_ok(pop) #endif -int +static int poll_dispatch(struct event_base *base, void *arg, struct timeval *tv) { - int res, i, sec, nfds; + int res, i, msec = -1, nfds; struct pollop *pop = arg; -#if OPAL_EVENT_USE_SIGNALS - if (opal_evsignal_deliver(&pop->evsigmask) == -1) - return (-1); -#endif - poll_check_ok(pop); - sec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; + + if (tv != NULL) + msec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; + nfds = pop->nfds; + /* we should release the lock if we're going to enter the kernel in a multi-threaded application. However, if we're single threaded, there's really no advantage to releasing the lock and it just takes up time we could spend doing something else. */ OPAL_THREAD_UNLOCK(&opal_event_lock); - res = poll(pop->event_set, nfds, sec); - OPAL_THREAD_LOCK(&opal_event_lock); -#if OPAL_EVENT_USE_SIGNALS - if (opal_evsignal_recalc(&pop->evsigmask) == -1) - return (-1); -#endif + res = poll(pop->event_set, nfds, msec); + + OPAL_THREAD_LOCK(&opal_event_lock); if (res == -1) { if (errno != EINTR) { event_warn("poll"); return (-1); } - #if OPAL_EVENT_USE_SIGNALS - opal_evsignal_process(); + evsignal_process(base); #endif return (0); - } + } else if (base->sig.evsignal_caught) { #if OPAL_EVENT_USE_SIGNALS - else if (opal_evsignal_caught) - opal_evsignal_process(); + evsignal_process(base); #endif + } event_debug(("%s: poll reports %d", __func__, res)); @@ -218,8 +190,8 @@ poll_dispatch(struct event_base *base, void *arg, struct timeval *tv) return (0); for (i = 0; i < nfds; i++) { - int what = pop->event_set[i].revents; - struct opal_event *r_ev = NULL, *w_ev = NULL; + int what = pop->event_set[i].revents; + struct event *r_ev = NULL, *w_ev = NULL; if (!what) continue; @@ -240,22 +212,18 @@ poll_dispatch(struct event_base *base, void *arg, struct timeval *tv) continue; if (r_ev && (res & r_ev->ev_events)) { - if (!(r_ev->ev_events & OPAL_EV_PERSIST)) - opal_event_del_i(r_ev); - opal_event_active_i(r_ev, res & r_ev->ev_events, 1); + event_active(r_ev, res & r_ev->ev_events, 1); } if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) { - if (!(w_ev->ev_events & OPAL_EV_PERSIST)) - opal_event_del_i(w_ev); - opal_event_active_i(w_ev, res & w_ev->ev_events, 1); + event_active(w_ev, res & w_ev->ev_events, 1); } } return (0); } -int -poll_add(void *arg, struct opal_event *ev) +static int +poll_add(void *arg, struct event *ev) { struct pollop *pop = arg; struct pollfd *pfd = NULL; @@ -263,36 +231,55 @@ poll_add(void *arg, struct opal_event *ev) #if OPAL_EVENT_USE_SIGNALS if (ev->ev_events & OPAL_EV_SIGNAL) - return (opal_evsignal_add(&pop->evsigmask, ev)); + return (evsignal_add(ev)); #endif if (!(ev->ev_events & (OPAL_EV_READ|OPAL_EV_WRITE))) return (0); poll_check_ok(pop); if (pop->nfds + 1 >= pop->event_count) { + struct pollfd *tmp_event_set; + struct event **tmp_event_r_back; + struct event **tmp_event_w_back; + int tmp_event_count; + if (pop->event_count < 32) - pop->event_count = 32; + tmp_event_count = 32; else - pop->event_count *= 2; + tmp_event_count = pop->event_count * 2; /* We need more file descriptors */ - pop->event_set = realloc(pop->event_set, - pop->event_count * sizeof(struct pollfd)); - if (pop->event_set == NULL) { + tmp_event_set = realloc(pop->event_set, + tmp_event_count * sizeof(struct pollfd)); + if (tmp_event_set == NULL) { event_warn("realloc"); return (-1); } - pop->event_r_back = realloc(pop->event_r_back, - pop->event_count * sizeof(struct opal_event *)); - pop->event_w_back = realloc(pop->event_w_back, - pop->event_count * sizeof(struct opal_event *)); - if (pop->event_r_back == NULL || - pop->event_w_back == NULL) { + pop->event_set = tmp_event_set; + + tmp_event_r_back = realloc(pop->event_r_back, + tmp_event_count * sizeof(struct event *)); + if (tmp_event_r_back == NULL) { + /* event_set overallocated; that's okay. */ event_warn("realloc"); return (-1); } + pop->event_r_back = tmp_event_r_back; + + tmp_event_w_back = realloc(pop->event_w_back, + tmp_event_count * sizeof(struct event *)); + if (tmp_event_w_back == NULL) { + /* event_set and event_r_back overallocated; that's + * okay. */ + event_warn("realloc"); + return (-1); + } + pop->event_w_back = tmp_event_w_back; + + pop->event_count = tmp_event_count; } if (ev->ev_fd >= pop->fd_count) { + int *tmp_idxplus1_by_fd; int new_count; if (pop->fd_count < 32) new_count = 32; @@ -300,12 +287,13 @@ poll_add(void *arg, struct opal_event *ev) new_count = pop->fd_count * 2; while (new_count <= ev->ev_fd) new_count *= 2; - pop->idxplus1_by_fd = - realloc(pop->idxplus1_by_fd, new_count*sizeof(int)); - if (pop->idxplus1_by_fd == NULL) { + tmp_idxplus1_by_fd = + realloc(pop->idxplus1_by_fd, new_count * sizeof(int)); + if (tmp_idxplus1_by_fd == NULL) { event_warn("realloc"); return (-1); } + pop->idxplus1_by_fd = tmp_idxplus1_by_fd; memset(pop->idxplus1_by_fd + pop->fd_count, 0, sizeof(int)*(new_count - pop->fd_count)); pop->fd_count = new_count; @@ -341,18 +329,16 @@ poll_add(void *arg, struct opal_event *ev) * Nothing to be done here. */ -int -poll_del(void *arg, struct opal_event *ev) +static int +poll_del(void *arg, struct event *ev) { struct pollop *pop = arg; struct pollfd *pfd = NULL; int i; - #if OPAL_EVENT_USE_SIGNALS if (ev->ev_events & OPAL_EV_SIGNAL) - return (opal_evsignal_del(&pop->evsigmask, ev)); + return (evsignal_del(ev)); #endif - if (!(ev->ev_events & (OPAL_EV_READ|OPAL_EV_WRITE))) return (0); @@ -395,3 +381,22 @@ poll_del(void *arg, struct opal_event *ev) poll_check_ok(pop); return (0); } + +static void +poll_dealloc(struct event_base *base, void *arg) +{ + struct pollop *pop = arg; + + evsignal_dealloc(base); + if (pop->event_set) + free(pop->event_set); + if (pop->event_r_back) + free(pop->event_r_back); + if (pop->event_w_back) + free(pop->event_w_back); + if (pop->idxplus1_by_fd) + free(pop->idxplus1_by_fd); + + memset(pop, 0, sizeof(struct pollop)); + free(pop); +} diff --git a/opal/event/rtsig.c b/opal/event/rtsig.c deleted file mode 100644 index 0111c8e6ec..0000000000 --- a/opal/event/rtsig.c +++ /dev/null @@ -1,437 +0,0 @@ -#include "opal_config.h" - -/* Enable F_SETSIG and F_SETOWN */ -#define _GNU_SOURCE - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_TIME_H -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef HAVE_WORKING_RTSIG -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - -#define EVLIST_X_NORT 0x1000 /* Skip RT signals (internal) */ - -#include "event.h" -#include "log.h" -extern struct event_list signalqueue; - -struct rtsigop { - sigset_t sigs; - struct pollfd *poll; - struct event **toev; - int cur, max, total; -#ifndef HAVE_WORKING_RTSIG - int pollmode; -#endif -}; - -#define INIT_MAX 16 - -static int -poll_add(struct rtsigop *op, struct event *ev) -{ - struct pollfd *pfd; - - if (op->poll == NULL) return 0; - - if (op->cur == op->max) { - void *p; - - p = realloc(op->poll, sizeof(*op->poll) * (op->max << 1)); - if (!p) { - errno = ENOMEM; - return -1; - } - op->poll = p; - p = realloc(op->toev, sizeof(*op->toev) * (op->max << 1)); - if (!p) { - op->poll = realloc(op->poll, sizeof(*op->poll) * op->max); - errno = ENOMEM; - return -1; - } - op->toev = p; - op->max <<= 1; - } - - pfd = &op->poll[op->cur]; - pfd->fd = ev->ev_fd; - pfd->events = 0; - if (ev->ev_events & EV_READ) pfd->events |= POLLIN; - if (ev->ev_events & EV_WRITE) pfd->events |= POLLOUT; - pfd->revents = 0; - - op->toev[op->cur] = ev; - op->cur++; - - return 0; -} - -static void -poll_free(struct rtsigop *op, int n) -{ - if (op->poll == NULL) return; - - op->cur--; - if (n < op->cur) { - memcpy(&op->poll[n], &op->poll[op->cur], sizeof(*op->poll)); - op->toev[n] = op->toev[op->cur]; - } - if (op->max > INIT_MAX && op->cur < op->max >> 1) { - op->max >>= 1; - op->poll = realloc(op->poll, sizeof(*op->poll) * op->max); - op->toev = realloc(op->toev, sizeof(*op->toev) * op->max); - } -} - -static void -poll_remove(struct rtsigop *op, struct event *ev) -{ - int i; - - for (i = 0; i < op->cur; i++) { - if (op->toev[i] == ev) { - poll_free(op, i); - break; - } - } -} - -static void -activate(struct event *ev, int flags) -{ - if (!(ev->ev_events & EV_PERSIST)) event_del_i(ev); - event_active_i(ev, flags, 1); -} - -static void *rtsig_init(void); -static int rtsig_add(void *, struct event *); -static int rtsig_del(void *, struct event *); -static int rtsig_recalc(struct event_base *, void *, int); -static int rtsig_dispatch(struct event_base *, void *, struct timeval *); - -struct opal_eventop rtsigops = { - "rtsig", - rtsig_init, - rtsig_add, - rtsig_del, - rtsig_recalc, - rtsig_dispatch -}; - -static void * -rtsig_init(void) -{ - struct rtsigop *op; - - if (getenv("EVENT_NORTSIG")) - return (NULL); - - op = malloc(sizeof(*op)); - if (op == NULL) return (NULL); - - memset(op, 0, sizeof(*op)); - - op->max = INIT_MAX; - op->poll = malloc(sizeof(*op->poll) * op->max); - if (op->poll == NULL) { - free(op); - return (NULL); - } - op->toev = malloc(sizeof(*op->toev) * op->max); - if (op->toev == NULL) { - free(op->poll); - free(op); - return (NULL); - } - - sigemptyset(&op->sigs); - sigaddset(&op->sigs, SIGIO); - sigaddset(&op->sigs, SIGRTMIN); - sigprocmask(SIG_BLOCK, &op->sigs, NULL); - - return (op); -} - -static int -rtsig_add(void *arg, struct event *ev) -{ - struct rtsigop *op = (struct rtsigop *) arg; - int flags, i; -#ifndef HAVE_WORKING_RTSIG - struct stat st; -#endif - - if (ev->ev_events & EV_SIGNAL) { - sigaddset(&op->sigs, EVENT_SIGNAL(ev)); - return sigprocmask(SIG_BLOCK, &op->sigs, NULL); - } - - if (!(ev->ev_events & (EV_READ | EV_WRITE))) return 0; - -#ifndef HAVE_WORKING_RTSIG - if (fstat(ev->ev_fd, &st) == -1) return -1; - if (S_ISFIFO(st.st_mode)) { - ev->ev_flags |= EVLIST_X_NORT; - op->pollmode++; - } -#endif - - flags = fcntl(ev->ev_fd, F_GETFL); - if (flags == -1) - return (-1); - - if (!(flags & O_ASYNC)) { - if (fcntl(ev->ev_fd, F_SETSIG, SIGRTMIN) == -1 - || fcntl(ev->ev_fd, F_SETOWN, (int) getpid()) == -1) - return (-1); - - if (fcntl(ev->ev_fd, F_SETFL, flags | O_ASYNC)) - return (-1); - } - -#ifdef O_ONESIGFD - fcntl(ev->ev_fd, F_SETAUXFL, O_ONESIGFD); -#endif - - op->total++; - if (poll_add(op, ev) == -1) - goto err; - - return (0); - - err: - i = errno; - fcntl(ev->ev_fd, F_SETFL, flags); - errno = i; - return (-1); -} - -static int -rtsig_del(void *arg, struct event *ev) -{ - struct rtsigop *op = (struct rtsigop *) arg; - - if (ev->ev_events & EV_SIGNAL) { - sigset_t sigs; - - sigdelset(&op->sigs, EVENT_SIGNAL(ev)); - - sigemptyset(&sigs); - sigaddset(&sigs, EVENT_SIGNAL(ev)); - return (sigprocmask(SIG_UNBLOCK, &sigs, NULL)); - } - - if (!(ev->ev_events & (EV_READ | EV_WRITE))) - return (0); - -#ifndef HAVE_WORKING_RTSIG - if (ev->ev_flags & EVLIST_X_NORT) - op->pollmode--; -#endif - poll_remove(op, ev); - op->total--; - - return (0); -} - -static int -rtsig_recalc(struct event_base *base, void *arg, int max) -{ - return (0); -} - -static int -rtsig_dispatch(struct event_base *base, void *arg, struct timeval *tv) -{ - struct rtsigop *op = (struct rtsigop *) arg; - struct timespec ts; - int res, i; - - if (op->poll == NULL) - goto retry_poll; -#ifndef HAVE_WORKING_RTSIG - if (op->pollmode) - goto poll_all; -#endif - - if (op->cur) { - ts.tv_sec = ts.tv_nsec = 0; - } else { - ts.tv_sec = tv->tv_sec; - ts.tv_nsec = tv->tv_usec * 1000; - } - - for (;;) { - siginfo_t info; - struct event *ev; - int signum; - - signum = sigtimedwait(&op->sigs, &info, &ts); - - if (signum == -1) { - if (errno == EAGAIN) - break; - return (errno == EINTR ? 0 : -1); - } - - ts.tv_sec = ts.tv_nsec = 0; - - if (signum == SIGIO) { -#ifndef HAVE_WORKING_RTSIG - poll_all: -#endif - free(op->poll); - free(op->toev); - retry_poll: - op->cur = 0; - op->max = op->total; - op->poll = malloc(sizeof(*op->poll) * op->total); - if (op->poll == NULL) - return (-1); - op->toev = malloc(sizeof(*op->toev) * op->total); - if (op->toev == NULL) { - free(op->poll); - op->poll = NULL; - return (-1); - } - - TAILQ_FOREACH(ev, &base->eventqueue, ev_next) - if (!(ev->ev_flags & EVLIST_X_NORT)) - poll_add(op, ev); - - break; - } - - if (signum == SIGRTMIN) { - int flags, i, sigok = 0; - - if (info.si_band <= 0) { /* SI_SIGIO */ - flags = EV_READ | EV_WRITE; - } else { - flags = 0; - if (info.si_band & POLLIN) flags |= EV_READ; - if (info.si_band & POLLOUT) flags |= EV_WRITE; - if (!flags) continue; - } - - for (i = 0; flags && i < op->cur; i++) { - ev = op->toev[i]; - - if (ev->ev_fd == info.si_fd) { - flags &= ~ev->ev_events; - sigok = 1; - } - } - - for (ev = TAILQ_FIRST(&base->eventqueue); - flags && ev != TAILQ_END(&base->eventqueue); - ev = TAILQ_NEXT(ev, ev_next)) { - if (ev->ev_fd == info.si_fd) { - if (flags & ev->ev_events) { - i = poll_add(op, ev); - if (i == -1) return -1; - flags &= ~ev->ev_events; - } - sigok = 1; - } - } - - if (!sigok) { - flags = fcntl(info.si_fd, F_GETFL); - if (flags == -1) return -1; - fcntl(info.si_fd, F_SETFL, flags & ~O_ASYNC); - } - } else { - TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { - if (EVENT_SIGNAL(ev) == signum) - activate(ev, EV_SIGNAL); - } - } - } - - if (!op->cur) - return (0); - - res = poll(op->poll, op->cur, tv->tv_sec * 1000 + - (tv->tv_usec + 999) / 1000); - if (res < 0) - return (-1); - - i = 0; -#ifdef HAVE_WORKING_RTSIG - while (i < res) { -#else - while (i < op->cur) { -#endif - if (op->poll[i].revents) { - int flags = 0; - struct event *ev = op->toev[i]; - - if (op->poll[i].revents & POLLIN) - flags |= EV_READ; - if (op->poll[i].revents & POLLOUT) - flags |= EV_WRITE; - - if (!(ev->ev_events & EV_PERSIST)) { - event_del_i(ev); - res--; - } else { - i++; - } - event_active_i(ev, flags, 1); - } else { -#ifndef HAVE_WORKING_RTSIG - if (op->toev[i]->ev_flags & EVLIST_X_NORT) { - i++; - res++; - continue; - } -#endif - for (;;) { - op->cur--; - if (i == op->cur) - break; - if (op->poll[op->cur].revents) { - memcpy(&op->poll[i], &op->poll[op->cur], sizeof(*op->poll)); - op->toev[i] = op->toev[op->cur]; - break; - } - } - } - } -#ifdef HAVE_WORKING_RTSIG - op->cur = res; -#endif - - if (!op->cur) { - op->max = INIT_MAX; - free(op->poll); - free(op->toev); - /* We just freed it, we shouldn't have a problem getting it back. */ - op->poll = malloc(sizeof(*op->poll) * op->max); - op->toev = malloc(sizeof(*op->toev) * op->max); - - if (op->poll == NULL || op->toev == NULL) - event_err(1, "%s: malloc"); - } - - return (0); -} diff --git a/opal/event/sample/Makefile.am b/opal/event/sample/Makefile.am index b749b80656..2f4e26e2f3 100644 --- a/opal/event/sample/Makefile.am +++ b/opal/event/sample/Makefile.am @@ -1,8 +1,7 @@ AUTOMAKE_OPTIONS = foreign no-dependencies LDADD = ../libevent.la -CPPFPLAGS = -I.. -CFLAGS = -I../compat +AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat noinst_PROGRAMS = event-test time-test signal-test diff --git a/opal/event/sample/Makefile.in b/opal/event/sample/Makefile.in index c4adc3c317..6a2be93758 100644 --- a/opal/event/sample/Makefile.in +++ b/opal/event/sample/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.8.5 from Makefile.am. +# Makefile.in generated by automake 1.10 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -14,17 +14,11 @@ @SET_MAKE@ -SOURCES = event-test.c signal-test.c time-test.c - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ -top_builddir = .. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c @@ -36,6 +30,7 @@ POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : +build_triplet = @build@ host_triplet = @host@ noinst_PROGRAMS = event-test$(EXEEXT) time-test$(EXEEXT) \ signal-test$(EXEEXT) @@ -61,25 +56,24 @@ time_test_SOURCES = time-test.c time_test_OBJECTS = time-test.$(OBJEXT) time_test_LDADD = $(LDADD) time_test_DEPENDENCIES = ../libevent.la -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) -LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ SOURCES = event-test.c signal-test.c time-test.c DIST_SOURCES = event-test.c signal-test.c time-test.c ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ -AMDEP_FALSE = @AMDEP_FALSE@ -AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ @@ -88,7 +82,7 @@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ -CFLAGS = -I../compat +CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ @@ -106,6 +100,8 @@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ +GREP = @GREP@ +INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -117,10 +113,8 @@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -MAINT = @MAINT@ -MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ -MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ @@ -130,54 +124,65 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ -ac_ct_AR = @ac_ct_AR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ -ac_ct_RANLIB = @ac_ct_RANLIB@ -ac_ct_STRIP = @ac_ct_STRIP@ -am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ -am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ -am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ -am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ +builddir = @builddir@ datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ +htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ +localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ +psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies LDADD = ../libevent.la -CPPFPLAGS = -I.. +AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat event_test_sources = event-test.c time_test_sources = time-test.c signal_test_sources = signal-test.c @@ -186,7 +191,7 @@ all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ @@ -211,9 +216,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) +$(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstPROGRAMS: @@ -224,13 +229,13 @@ clean-noinstPROGRAMS: done event-test$(EXEEXT): $(event_test_OBJECTS) $(event_test_DEPENDENCIES) @rm -f event-test$(EXEEXT) - $(LINK) $(event_test_LDFLAGS) $(event_test_OBJECTS) $(event_test_LDADD) $(LIBS) + $(LINK) $(event_test_OBJECTS) $(event_test_LDADD) $(LIBS) signal-test$(EXEEXT): $(signal_test_OBJECTS) $(signal_test_DEPENDENCIES) @rm -f signal-test$(EXEEXT) - $(LINK) $(signal_test_LDFLAGS) $(signal_test_OBJECTS) $(signal_test_LDADD) $(LIBS) + $(LINK) $(signal_test_OBJECTS) $(signal_test_LDADD) $(LIBS) time-test$(EXEEXT): $(time_test_OBJECTS) $(time_test_DEPENDENCIES) @rm -f time-test$(EXEEXT) - $(LINK) $(time_test_LDFLAGS) $(time_test_OBJECTS) $(time_test_LDADD) $(LIBS) + $(LINK) $(time_test_OBJECTS) $(time_test_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -253,10 +258,6 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs -distclean-libtool: - -rm -f libtool -uninstall-info-am: - ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -306,22 +307,21 @@ distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ - list='$(DISTFILES)'; for file in $$list; do \ - case $$file in \ - $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ - $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ - esac; \ + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test "$$dir" != "$$file" && test "$$dir" != "."; then \ - dir="/$$dir"; \ - $(mkdir_p) "$(distdir)$$dir"; \ - else \ - dir=''; \ - fi; \ if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ @@ -355,7 +355,7 @@ mostlyclean-generic: clean-generic: distclean-generic: - -rm -f $(CONFIG_CLEAN_FILES) + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @@ -369,7 +369,7 @@ clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ - distclean-libtool distclean-tags + distclean-tags dvi: dvi-am @@ -383,12 +383,20 @@ info-am: install-data-am: +install-dvi: install-dvi-am + install-exec-am: +install-html: install-html-am + install-info: install-info-am install-man: +install-pdf: install-pdf-am + +install-ps: install-ps-am + installcheck-am: maintainer-clean: maintainer-clean-am @@ -408,19 +416,22 @@ ps: ps-am ps-am: -uninstall-am: uninstall-info-am +uninstall-am: + +.MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstPROGRAMS ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-exec \ - install-exec-am install-info install-info-am install-man \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ - pdf pdf-am ps ps-am tags uninstall uninstall-am \ - uninstall-info-am + pdf pdf-am ps ps-am tags uninstall uninstall-am verify: diff --git a/opal/event/sample/event-test.c b/opal/event/sample/event-test.c index 499b08849a..2c6cb93864 100644 --- a/opal/event/sample/event-test.c +++ b/opal/event/sample/event-test.c @@ -3,20 +3,16 @@ * cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent */ -#ifdef HAVE_SYS_TYPES_H -#include +#ifdef HAVE_CONFIG_H +#include "config.h" #endif + +#include #include #ifndef WIN32 -#ifdef HAVE_SYS_QUEUE_H #include -#endif -#ifdef HAVE_UNISTD_H #include -#endif -#ifdef HAVE_SYS_TIME_H #include -#endif #else #include #endif @@ -28,18 +24,18 @@ #include -void +static void fifo_read(int fd, short event, void *arg) { char buf[255]; int len; - struct opal_event *ev = arg; + struct event *ev = arg; #ifdef WIN32 DWORD dwBytesRead; #endif /* Reschedule this event */ - opal_event_add(ev, NULL); + event_add(ev, NULL); fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n", fd, event, arg); @@ -49,7 +45,7 @@ fifo_read(int fd, short event, void *arg) // Check for end of file. if(len && dwBytesRead == 0) { fprintf(stderr, "End Of File"); - opal_event_del(ev); + event_del(ev); return; } @@ -73,7 +69,7 @@ fifo_read(int fd, short event, void *arg) int main (int argc, char **argv) { - struct opal_event evfifo; + struct event evfifo; #ifdef WIN32 HANDLE socket; // Open a file. @@ -90,7 +86,7 @@ main (int argc, char **argv) #else struct stat st; - char *fifo = "event.fifo"; + const char *fifo = "event.fifo"; int socket; if (lstat (fifo, &st) == 0) { @@ -122,19 +118,19 @@ main (int argc, char **argv) fprintf(stderr, "Write data to %s\n", fifo); #endif /* Initalize the event library */ - opal_event_init(); + event_init(); /* Initalize one event */ #ifdef WIN32 - opal_event_set(&evfifo, (int)socket, OPAL_EV_READ, fifo_read, &evfifo); + event_set(&evfifo, (int)socket, EV_READ, fifo_read, &evfifo); #else - opal_event_set(&evfifo, socket, OPAL_EV_READ, fifo_read, &evfifo); + event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo); #endif /* Add it to the active events, without a timeout */ - opal_event_add(&evfifo, NULL); + event_add(&evfifo, NULL); - opal_event_dispatch(); + event_dispatch(); #ifdef WIN32 CloseHandle(socket); #endif diff --git a/opal/event/sample/signal-test.c b/opal/event/sample/signal-test.c index 17df7d3b2d..d04c00e4bf 100644 --- a/opal/event/sample/signal-test.c +++ b/opal/event/sample/signal-test.c @@ -3,21 +3,17 @@ * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent */ -#ifdef HAVE_SYS_TYPES_H #include + +#ifdef HAVE_CONFIG_H +#include "config.h" #endif #include #ifndef WIN32 -#ifdef HAVE_SYS_QUEUE_H #include -#endif -#ifdef HAVE_UNISTD_H #include -#endif -#ifdef HAVE_SYS_TIME_H #include -#endif #else #include #endif @@ -32,15 +28,15 @@ int called = 0; -void +static void signal_cb(int fd, short event, void *arg) { - struct opal_event *signal = arg; + struct event *signal = arg; - printf("%s: got signal %d\n", __func__, OPAL_EVENT_SIGNAL(signal)); + printf("%s: got signal %d\n", __func__, EVENT_SIGNAL(signal)); if (called >= 2) - opal_event_del(signal); + event_del(signal); called++; } @@ -48,18 +44,18 @@ signal_cb(int fd, short event, void *arg) int main (int argc, char **argv) { - struct opal_event signal_int; + struct event signal_int; /* Initalize the event library */ - opal_event_init(); + event_init(); /* Initalize one event */ - opal_event_set(&signal_int, SIGINT, OPAL_EV_SIGNAL|OPAL_EV_PERSIST, signal_cb, + event_set(&signal_int, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb, &signal_int); - opal_event_add(&signal_int, NULL); + event_add(&signal_int, NULL); - opal_event_dispatch(); + event_dispatch(); return (0); } diff --git a/opal/event/sample/time-test.c b/opal/event/sample/time-test.c index c1f4d960d8..069d4f8f78 100644 --- a/opal/event/sample/time-test.c +++ b/opal/event/sample/time-test.c @@ -3,21 +3,18 @@ * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent */ -#ifdef HAVE_SYS_TYPES_H #include + +#ifdef HAVE_CONFIG_H +#include "config.h" #endif #include #ifndef WIN32 -#ifdef HAVE_SYS_QUEUE_H #include -#endif -#ifdef HAVE_UNISTD_H #include #endif -#else #include -#endif #ifdef HAVE_SYS_TIME_H #include #endif @@ -28,44 +25,45 @@ #include #include +#include int lasttime; -void +static void timeout_cb(int fd, short event, void *arg) { struct timeval tv; - struct opal_event *timeout = arg; + struct event *timeout = arg; int newtime = time(NULL); printf("%s: called at %d: %d\n", __func__, newtime, newtime - lasttime); lasttime = newtime; - timerclear(&tv); + evutil_timerclear(&tv); tv.tv_sec = 2; - opal_event_add(timeout, &tv); + event_add(timeout, &tv); } int main (int argc, char **argv) { - struct opal_event timeout; + struct event timeout; struct timeval tv; /* Initalize the event library */ - opal_event_init(); + event_init(); /* Initalize one event */ - opal_evtimer_set(&timeout, timeout_cb, &timeout); + evtimer_set(&timeout, timeout_cb, &timeout); - timerclear(&tv); + evutil_timerclear(&tv); tv.tv_sec = 2; - opal_event_add(&timeout, &tv); + event_add(&timeout, &tv); lasttime = time(NULL); - opal_event_dispatch(); + event_dispatch(); return (0); } diff --git a/opal/event/select.c b/opal/event/select.c index 795e111dea..dcab3790c8 100644 --- a/opal/event/select.c +++ b/opal/event/select.c @@ -28,7 +28,6 @@ */ #include "opal_config.h" #include "opal/util/output.h" - #ifdef HAVE_SYS_TYPES_H #include #endif @@ -41,10 +40,7 @@ #include #endif #include -#include -#ifndef __WINDOWS__ #include -#endif #include #include #include @@ -58,15 +54,13 @@ #include "event.h" #include "event-internal.h" -#if OPAL_EVENT_USE_SIGNALS #include "evsignal.h" -#endif #include "log.h" - #include "opal/threads/mutex.h" extern opal_mutex_t opal_event_lock; + #ifndef howmany #define howmany(x, y) (((x)+((y)-1))/(y)) #endif @@ -74,12 +68,13 @@ extern opal_mutex_t opal_event_lock; #if OPAL_EVENT_USE_SIGNALS extern volatile sig_atomic_t opal_evsignal_caught; #endif - #ifdef __WINDOWS__ #define NFDBITS 32 int fd_mask; #endif + + struct selectop { int event_fds; /* Highest fd in fd set */ int event_fdsz; @@ -87,51 +82,45 @@ struct selectop { fd_set *event_writeset_in; fd_set *event_readset_out; fd_set *event_writeset_out; - struct opal_event **event_r_by_fd; - struct opal_event **event_w_by_fd; -#if OPAL_EVENT_USE_SIGNALS - sigset_t evsigmask; -#endif + struct event **event_r_by_fd; + struct event **event_w_by_fd; }; -static void *select_init (void); -static int select_add (void *, struct opal_event *); -static int select_del (void *, struct opal_event *); -static int select_recalc (struct event_base *, void *, int); +static void *select_init (struct event_base *); +static int select_add (void *, struct event *); +static int select_del (void *, struct event *); static int select_dispatch (struct event_base *, void *, struct timeval *); +static void select_dealloc (struct event_base *, void *); -const struct opal_eventop opal_selectops = { +const struct eventop selectops = { "select", select_init, select_add, select_del, -#ifdef WIN32 - NULL, -#else - select_recalc, -#endif - select_dispatch + select_dispatch, + select_dealloc, + 0 }; static int select_resize(struct selectop *sop, int fdsz); static void * -select_init(void) +select_init(struct event_base *base) { struct selectop *sop; - /* Disable kqueue when this environment variable is set */ + /* Disable select when this environment variable is set */ if (getenv("EVENT_NOSELECT")) return (NULL); + if (!(sop = calloc(1, sizeof(struct selectop)))) return (NULL); - select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask)); + select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask)); #if OPAL_EVENT_USE_SIGNALS - opal_evsignal_init(&sop->evsigmask); + evsignal_init(base); #endif - return (sop); } @@ -140,17 +129,17 @@ static void check_selectop(struct selectop *sop) { int i; - for (i=0;i<=sop->event_fds;++i) { + for (i = 0; i <= sop->event_fds; ++i) { if (FD_ISSET(i, sop->event_readset_in)) { assert(sop->event_r_by_fd[i]); - assert(sop->event_r_by_fd[i]->ev_events & EV_READ); + assert(sop->event_r_by_fd[i]->ev_events & OPAL_EV_READ); assert(sop->event_r_by_fd[i]->ev_fd == i); } else { assert(! sop->event_r_by_fd[i]); } if (FD_ISSET(i, sop->event_writeset_in)) { assert(sop->event_w_by_fd[i]); - assert(sop->event_w_by_fd[i]->ev_events & EV_WRITE); + assert(sop->event_w_by_fd[i]->ev_events & OPAL_EV_WRITE); assert(sop->event_w_by_fd[i]->ev_fd == i); } else { assert(! sop->event_w_by_fd[i]); @@ -159,28 +148,9 @@ check_selectop(struct selectop *sop) } #else -#define check_selectop(sop) +#define check_selectop(sop) do { (void) sop; } while (0) #endif -/* - * Called with the highest fd that we know about. If it is 0, completely - * recalculate everything. - */ - -static int -select_recalc(struct event_base *base, void *arg, int max) -{ - struct selectop *sop = arg; - - check_selectop(sop); - -#if OPAL_EVENT_USE_SIGNALS - return (opal_evsignal_recalc(&sop->evsigmask)); -#else - return (0); -#endif -} - static int select_dispatch(struct event_base *base, void *arg, struct timeval *tv) { @@ -194,73 +164,40 @@ select_dispatch(struct event_base *base, void *arg, struct timeval *tv) memcpy(sop->event_writeset_out, sop->event_writeset_in, sop->event_fdsz); -#if OPAL_EVENT_USE_SIGNALS - if (opal_evsignal_deliver(&sop->evsigmask) == -1) - return (-1); -#endif - /* we should release the lock if we're going to enter the kernel in a multi-threaded application. However, if we're single threaded, there's really no advantage to releasing the lock and it just takes up time we could spend doing something else. */ OPAL_THREAD_UNLOCK(&opal_event_lock); - res = select(sop->event_fds + 1, sop->event_readset_out, - sop->event_writeset_out, NULL, tv); - OPAL_THREAD_LOCK(&opal_event_lock); + + res = select(sop->event_fds + 1, sop->event_readset_out, + sop->event_writeset_out, NULL, tv); - check_selectop(sop); -#if OPAL_EVENT_USE_SIGNALS - if (opal_evsignal_recalc(&sop->evsigmask) == -1) - return (-1); -#endif + OPAL_THREAD_LOCK(&opal_event_lock); + + check_selectop(sop); if (res == -1) { -#if 0 - if (errno == EBADF) { - /* poll each of the file descriptors individually to determine - * which is bad - */ - for (ev = TAILQ_FIRST(&base->eventqueue); ev != NULL; ev = next) { - next = TAILQ_NEXT(ev, ev_next); - - tv->tv_sec = 0; - tv->tv_usec = 0; - memset(sop->event_readset, 0, sop->event_fdsz); - memset(sop->event_writeset, 0, sop->event_fdsz); - if (ev->ev_events & OPAL_EV_WRITE) - FD_SET(ev->ev_fd, sop->event_writeset); - if (ev->ev_events & OPAL_EV_READ) - FD_SET(ev->ev_fd, sop->event_readset); - res = select(sop->event_fds + 1, sop->event_readset, - sop->event_writeset, NULL, tv); - if(res < 0) { - opal_output(0, "bad file descriptor: %d\n", ev->ev_fd); - opal_event_del_i(ev); - } - } - } -#endif if (errno != EINTR) { - opal_output(0, "select failed with errno=%d\n", errno); + event_warn("select"); return (-1); } - #if OPAL_EVENT_USE_SIGNALS - opal_evsignal_process(); + evsignal_process(base); #endif return (0); - } #if OPAL_EVENT_USE_SIGNALS - else if (opal_evsignal_caught) - opal_evsignal_process(); + } else if (base->sig.evsignal_caught) { + evsignal_process(base); #endif + } event_debug(("%s: select reports %d", __func__, res)); check_selectop(sop); for (i = 0; i <= sop->event_fds; ++i) { - struct opal_event *r_ev = NULL, *w_ev = NULL; + struct event *r_ev = NULL, *w_ev = NULL; res = 0; if (FD_ISSET(i, sop->event_readset_out)) { r_ev = sop->event_r_by_fd[i]; @@ -271,14 +208,10 @@ select_dispatch(struct event_base *base, void *arg, struct timeval *tv) res |= OPAL_EV_WRITE; } if (r_ev && (res & r_ev->ev_events)) { - if (!(r_ev->ev_events & OPAL_EV_PERSIST)) - opal_event_del_i(r_ev); - opal_event_active_i(r_ev, res & r_ev->ev_events, 1); + event_active(r_ev, res & r_ev->ev_events, 1); } if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) { - if (!(w_ev->ev_events & OPAL_EV_PERSIST)) - opal_event_del_i(w_ev); - opal_event_active_i(w_ev, res & w_ev->ev_events, 1); + event_active(w_ev, res & w_ev->ev_events, 1); } } check_selectop(sop); @@ -286,6 +219,7 @@ select_dispatch(struct event_base *base, void *arg, struct timeval *tv) return (0); } + static int select_resize(struct selectop *sop, int fdsz) { @@ -295,8 +229,8 @@ select_resize(struct selectop *sop, int fdsz) fd_set *writeset_in = NULL; fd_set *readset_out = NULL; fd_set *writeset_out = NULL; - struct opal_event **r_by_fd = NULL; - struct opal_event **w_by_fd = NULL; + struct event **r_by_fd = NULL; + struct event **w_by_fd = NULL; n_events = (fdsz/sizeof(fd_mask)) * NFDBITS; n_events_old = (sop->event_fdsz/sizeof(fd_mask)) * NFDBITS; @@ -344,16 +278,15 @@ select_resize(struct selectop *sop, int fdsz) return (-1); } + static int -select_add(void *arg, struct opal_event *ev) +select_add(void *arg, struct event *ev) { struct selectop *sop = arg; - #if OPAL_EVENT_USE_SIGNALS if (ev->ev_events & OPAL_EV_SIGNAL) - return (opal_evsignal_add(&sop->evsigmask, ev)); + return (evsignal_add(ev)); #endif - check_selectop(sop); /* * Keep track of the highest fd, so that we can calculate the size @@ -362,7 +295,7 @@ select_add(void *arg, struct opal_event *ev) if (sop->event_fds < ev->ev_fd) { int fdsz = sop->event_fdsz; - if (fdsz < (int) sizeof(fd_mask)) + if (fdsz < (int)sizeof(fd_mask)) fdsz = sizeof(fd_mask); while (fdsz < @@ -397,16 +330,15 @@ select_add(void *arg, struct opal_event *ev) */ static int -select_del(void *arg, struct opal_event *ev) +select_del(void *arg, struct event *ev) { struct selectop *sop = arg; check_selectop(sop); #if OPAL_EVENT_USE_SIGNALS if (ev->ev_events & OPAL_EV_SIGNAL) - return (opal_evsignal_del(&sop->evsigmask, ev)); + return (evsignal_del(ev)); #endif - if (sop->event_fds < ev->ev_fd) { check_selectop(sop); return (0); @@ -426,3 +358,25 @@ select_del(void *arg, struct opal_event *ev) return (0); } +static void +select_dealloc(struct event_base *base, void *arg) +{ + struct selectop *sop = arg; + + evsignal_dealloc(base); + if (sop->event_readset_in) + free(sop->event_readset_in); + if (sop->event_writeset_in) + free(sop->event_writeset_in); + if (sop->event_readset_out) + free(sop->event_readset_out); + if (sop->event_writeset_out) + free(sop->event_writeset_out); + if (sop->event_r_by_fd) + free(sop->event_r_by_fd); + if (sop->event_w_by_fd) + free(sop->event_w_by_fd); + + memset(sop, 0, sizeof(struct selectop)); + free(sop); +} diff --git a/opal/event/signal.c b/opal/event/signal.c index 0f13566686..0a6da9c90a 100644 --- a/opal/event/signal.c +++ b/opal/event/signal.c @@ -28,17 +28,22 @@ */ #include "opal_config.h" +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#undef WIN32_LEAN_AND_MEAN +#endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_TIME_H #include -#else -#include #endif #include -#include +#ifdef HAVE_SYS_SOCKET_H #include +#endif #include #include #include @@ -50,45 +55,33 @@ #ifdef HAVE_FCNTL_H #include #endif +#include #include "event.h" #include "event-internal.h" #include "evsignal.h" +#include "evutil.h" #include "log.h" - #include "opal/util/output.h" +struct event_base *evsignal_base = NULL; -extern struct opal_event_list opal_signalqueue; - -#if defined(VXWORKS) -#define OPAL_NSIG (_NSIGS + 1) -#else -#define OPAL_NSIG NSIG -#endif - -static sig_atomic_t opal_evsigcaught[OPAL_NSIG]; -static int opal_needrecalc; -volatile sig_atomic_t opal_evsignal_caught = 0; - -void opal_evsignal_handler(int sig); - -static struct opal_event ev_signal; -static int ev_signal_pair[2]; -static int ev_signal_added; +static void evsignal_handler(int sig); /* Callback for when the signal handler write a byte to our signaling socket */ static void evsignal_cb(int fd, short what, void *arg) { static char signals[100]; - struct opal_event *ev = arg; +#ifdef WIN32 + SSIZE_T n; +#else ssize_t n; +#endif - n = read(fd, signals, sizeof(signals)); + n = recv(fd, signals, sizeof(signals), 0); if (n == -1) event_err(1, "%s: read", __func__); - opal_event_add_i(ev, NULL); } #ifdef HAVE_SETFD @@ -101,184 +94,212 @@ evsignal_cb(int fd, short what, void *arg) #endif void -opal_evsignal_init(sigset_t *evsigmask) +evsignal_init(struct event_base *base) { -#ifndef WIN32 - sigemptyset(evsigmask); -#endif - /* * Our signal handler is going to write to one end of the socket * pair to wake up our event loop. The event loop then scans for * signals that got delivered. */ -#ifdef HAVE_SOCKETPAIR - if (socketpair(AF_UNIX, SOCK_STREAM, 0, ev_signal_pair) == -1) + if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) event_err(1, "%s: socketpair", __func__); -#else - if (socketpair(AF_UNIX, SOCK_STREAM, 0, ev_signal_pair) == -1) - event_err(1, "%s: pipe", __func__); -#endif - FD_CLOSEONEXEC(ev_signal_pair[0]); - FD_CLOSEONEXEC(ev_signal_pair[1]); + FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]); + FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]); + base->sig.sh_old = NULL; + base->sig.sh_old_max = 0; + base->sig.evsignal_caught = 0; + memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG); - fcntl(ev_signal_pair[0], F_SETFL, O_NONBLOCK); + evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]); - opal_event_set(&ev_signal, ev_signal_pair[1], OPAL_EV_READ, - evsignal_cb, &ev_signal); - ev_signal.ev_flags |= OPAL_EVLIST_INTERNAL; + event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1], + OPAL_EV_READ | OPAL_EV_PERSIST, evsignal_cb, &base->sig.ev_signal); + base->sig.ev_signal.ev_base = base; + base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL; } +/* Helper: set the signal handler for evsignal to handler in base, so that + * we can restore the original handler when we clear the current one. */ +int +_evsignal_set_handler(struct event_base *base, + int evsignal, void (*handler)(int)) +{ +#ifdef HAVE_SIGACTION + struct sigaction sa; +#else + ev_sighandler_t sh; +#endif + struct evsignal_info *sig = &base->sig; + void *p; + + /* + * resize saved signal handler array up to the highest signal number. + * a dynamic array is used to keep footprint on the low side. + */ + if (evsignal >= sig->sh_old_max) { + event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing", + __func__, evsignal, sig->sh_old_max)); + sig->sh_old_max = evsignal + 1; + p = realloc(sig->sh_old, sig->sh_old_max * sizeof *sig->sh_old); + if (p == NULL) { + event_warn("realloc"); + return (-1); + } + sig->sh_old = p; + } + + /* allocate space for previous handler out of dynamic array */ + sig->sh_old[evsignal] = malloc(sizeof *sig->sh_old[evsignal]); + if (sig->sh_old[evsignal] == NULL) { + event_warn("malloc"); + return (-1); + } + + /* save previous handler and setup new handler */ +#ifdef HAVE_SIGACTION + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handler; + sa.sa_flags |= SA_RESTART; + sigfillset(&sa.sa_mask); + + if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) { + event_warn("sigaction"); + free(sig->sh_old[evsignal]); + return (-1); + } +#else + if ((sh = signal(evsignal, handler)) == SIG_ERR) { + event_warn("signal"); + free(sig->sh_old[evsignal]); + return (-1); + } + *sig->sh_old[evsignal] = sh; +#endif + + return (0); +} int -opal_evsignal_add(sigset_t *evsigmask, struct opal_event *ev) +evsignal_add(struct event *ev) { int evsignal; + struct event_base *base = ev->ev_base; + struct evsignal_info *sig = &ev->ev_base->sig; if (ev->ev_events & (OPAL_EV_READ|OPAL_EV_WRITE)) event_errx(1, "%s: OPAL_EV_SIGNAL incompatible use", __func__); evsignal = OPAL_EVENT_SIGNAL(ev); - /* force a recalc of the events we are waiting for, otherwise - events aren't recalculated until the next time event_loop - is called. Since that might not be for some time, that - gives a window where a signal handler *should* be installed - but actually is not. */ - if (ev->ev_base->evsel->recalc && ev->ev_base->evsel->recalc(ev->ev_base, ev->ev_base->evbase, 0) == -1) { - opal_output(0, "opal_evsignal_add: opal_evsel->recalc() failed."); - return (-1); - } + event_debug(("%s: %p: changing signal handler", __func__, ev)); + if (_evsignal_set_handler(base, evsignal, evsignal_handler) == -1) + return (-1); -#ifndef WIN32 - sigaddset(evsigmask, evsignal); -#endif + /* catch signals if they happen quickly */ + evsignal_base = base; + + if (!sig->ev_signal_added) { + sig->ev_signal_added = 1; + event_add(&sig->ev_signal, NULL); + } return (0); } -int -opal_evsignal_restart(void) +int +_evsignal_restore_handler(struct event_base *base, int evsignal) { - return (0); -} + int ret = 0; + struct evsignal_info *sig = &base->sig; +#ifdef HAVE_SIGACTION + struct sigaction *sh; +#else + ev_sighandler_t *sh; +#endif -/* - * Nothing to be done here. - */ + /* restore previous handler */ + sh = sig->sh_old[evsignal]; + sig->sh_old[evsignal] = NULL; +#ifdef HAVE_SIGACTION + if (sigaction(evsignal, sh, NULL) == -1) { + event_warn("sigaction"); + ret = -1; + } +#else + if (signal(evsignal, *sh) == SIG_ERR) { + event_warn("signal"); + ret = -1; + } +#endif + free(sh); + + return ret; +} int -opal_evsignal_del(sigset_t *evsigmask, struct opal_event *ev) +evsignal_del(struct event *ev) { -#ifdef WIN32 - return 0; -#else - int evsignal, ret; - struct sigaction sa; - sigset_t set; - - evsignal = OPAL_EVENT_SIGNAL(ev); - - /* remove from the "in use" signal list */ - sigdelset(evsigmask, evsignal); - opal_needrecalc = 1; - - /* set back to default handler */ - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; - - ret = sigaction(evsignal, &sa, NULL); - - /* unblock signal, in case we were blocking the "in use" signals - when this function was called */ - sigemptyset(&set); - sigaddset(&set, evsignal); - sigprocmask(SIG_UNBLOCK, &set, NULL); - - return ret; -#endif + event_debug(("%s: %p: restoring signal handler", __func__, ev)); + return _evsignal_restore_handler(ev->ev_base, OPAL_EVENT_SIGNAL(ev)); } -void -opal_evsignal_handler(int sig) +static void +evsignal_handler(int sig) { int save_errno = errno; - opal_evsigcaught[sig]++; - opal_evsignal_caught = 1; + if(evsignal_base == NULL) { + event_warn( + "%s: received signal %d, but have no base configured", + __func__, sig); + return; + } + + evsignal_base->sig.evsigcaught[sig]++; + evsignal_base->sig.evsignal_caught = 1; + +#ifndef HAVE_SIGACTION + signal(sig, evsignal_handler); +#endif /* Wake up our notification mechanism */ - write(ev_signal_pair[0], "a", 1); + send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0); errno = save_errno; } -int -opal_evsignal_recalc(sigset_t *evsigmask) +void +evsignal_process(struct event_base *base) { -#ifdef WIN32 - return 0; -#else - struct sigaction sa; - struct opal_event *ev; - - if (!ev_signal_added) { - ev_signal_added = 1; - opal_event_add_i(&ev_signal, NULL); + struct event *ev; + sig_atomic_t ncalls; + + base->sig.evsignal_caught = 0; + TAILQ_FOREACH(ev, &base->sig.signalqueue, ev_signal_next) { + ncalls = base->sig.evsigcaught[OPAL_EVENT_SIGNAL(ev)]; + if (ncalls) { + if (!(ev->ev_events & OPAL_EV_PERSIST)) + event_del(ev); + event_active(ev, OPAL_EV_SIGNAL, ncalls); + base->sig.evsigcaught[OPAL_EVENT_SIGNAL(ev)] = 0; + } } - - if (TAILQ_FIRST(&opal_signalqueue) == NULL && !opal_needrecalc) - return (0); - opal_needrecalc = 0; - - if (sigprocmask(SIG_BLOCK, evsigmask, NULL) == -1) - return (-1); - - /* Reinstall our signal handler. */ - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = opal_evsignal_handler; - sa.sa_mask = *evsigmask; -#if OMPI_HAVE_SA_RESTART - sa.sa_flags |= SA_RESTART; -#endif - - TAILQ_FOREACH(ev, &opal_signalqueue, ev_signal_next) { - if (sigaction(OPAL_EVENT_SIGNAL(ev), &sa, NULL) == -1) - return (-1); - } - return (0); -#endif -} - -int -opal_evsignal_deliver(sigset_t *evsigmask) -{ - if (TAILQ_FIRST(&opal_signalqueue) == NULL) - return (0); - -#ifdef WIN32 - return 0; -#else - return (sigprocmask(SIG_UNBLOCK, evsigmask, NULL)); - /* XXX - pending signals handled here */ -#endif } void -opal_evsignal_process(void) +evsignal_dealloc(struct event_base *base) { - struct opal_event *ev; - sig_atomic_t ncalls; - - TAILQ_FOREACH(ev, &opal_signalqueue, ev_signal_next) { - ncalls = opal_evsigcaught[OPAL_EVENT_SIGNAL(ev)]; - if (ncalls) { - if (!(ev->ev_events & OPAL_EV_PERSIST)) - opal_event_del_i(ev); - opal_event_active_i(ev, OPAL_EV_SIGNAL, ncalls); - } + if(base->sig.ev_signal_added) { + event_del(&base->sig.ev_signal); + base->sig.ev_signal_added = 0; } + assert(TAILQ_EMPTY(&base->sig.signalqueue)); - memset(opal_evsigcaught, 0, sizeof(opal_evsigcaught)); - opal_evsignal_caught = 0; + EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]); + base->sig.ev_signal_pair[0] = -1; + EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]); + base->sig.ev_signal_pair[1] = -1; + base->sig.sh_old_max = 0; + + /* per index frees are handled in evsignal_del() */ + free(base->sig.sh_old); } - diff --git a/opal/event/test/Makefile.am b/opal/event/test/Makefile.am index 0efdd40c16..0859af7980 100644 --- a/opal/event/test/Makefile.am +++ b/opal/event/test/Makefile.am @@ -1,23 +1,35 @@ AUTOMAKE_OPTIONS = foreign no-dependencies -LDADD = ../libevent.la -CPPFPLAGS = -I.. -CFLAGS = -I../compat @CFLAGS@ +CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat + +EXTRA_DIST = regress.rpc regress.gen.h regress.gen.c noinst_PROGRAMS = test-init test-eof test-weof test-time regress bench -test_init_sources = test-init.c -test_eof_sources = test-eof.c -test_weof_sources = test-weof.c -test_time_sources = test-time.c -regress_sources = regress.c -bench_sources = bench.c +BUILT_SOURCES = regress.gen.c regress.gen.h +test_init_SOURCES = test-init.c +test_init_LDADD = ../libevent_core.la +test_eof_SOURCES = test-eof.c +test_eof_LDADD = ../libevent_core.la +test_weof_SOURCES = test-weof.c +test_weof_LDADD = ../libevent_core.la +test_time_SOURCES = test-time.c +test_time_LDADD = ../libevent_core.la +regress_SOURCES = regress.c regress.h regress_http.c regress_dns.c \ + regress_rpc.c \ + regress.gen.c regress.gen.h +regress_LDADD = ../libevent.la +bench_SOURCES = bench.c +bench_LDADD = ../libevent.la + +regress.gen.c regress.gen.h: regress.rpc $(top_srcdir)/event_rpcgen.py + $(top_srcdir)/event_rpcgen.py $(srcdir)/regress.rpc || echo "No Python installed" DISTCLEANFILES = *~ test: test-init test-eof test-weof test-time regress verify: test - @./test.sh + @$(srcdir)/test.sh -bench test-init test-eof test-weof test-time regress: ../libevent.la +bench test-init test-eof test-weof test-time: ../libevent.la diff --git a/opal/event/test/Makefile.in b/opal/event/test/Makefile.in index 5c3a0b2c36..e84b720697 100644 --- a/opal/event/test/Makefile.in +++ b/opal/event/test/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.8.5 from Makefile.am. +# Makefile.in generated by automake 1.10 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -14,17 +14,11 @@ @SET_MAKE@ -SOURCES = bench.c regress.c test-eof.c test-init.c test-time.c test-weof.c - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ -top_builddir = .. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c @@ -36,6 +30,7 @@ POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : +build_triplet = @build@ host_triplet = @host@ noinst_PROGRAMS = test-init$(EXEEXT) test-eof$(EXEEXT) \ test-weof$(EXEEXT) test-time$(EXEEXT) regress$(EXEEXT) \ @@ -50,51 +45,46 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = PROGRAMS = $(noinst_PROGRAMS) -bench_SOURCES = bench.c -bench_OBJECTS = bench.$(OBJEXT) -bench_LDADD = $(LDADD) +am_bench_OBJECTS = bench.$(OBJEXT) +bench_OBJECTS = $(am_bench_OBJECTS) bench_DEPENDENCIES = ../libevent.la -regress_SOURCES = regress.c -regress_OBJECTS = regress.$(OBJEXT) -regress_LDADD = $(LDADD) +am_regress_OBJECTS = regress.$(OBJEXT) regress_http.$(OBJEXT) \ + regress_dns.$(OBJEXT) regress_rpc.$(OBJEXT) \ + regress.gen.$(OBJEXT) +regress_OBJECTS = $(am_regress_OBJECTS) regress_DEPENDENCIES = ../libevent.la -test_eof_SOURCES = test-eof.c -test_eof_OBJECTS = test-eof.$(OBJEXT) -test_eof_LDADD = $(LDADD) -test_eof_DEPENDENCIES = ../libevent.la -test_init_SOURCES = test-init.c -test_init_OBJECTS = test-init.$(OBJEXT) -test_init_LDADD = $(LDADD) -test_init_DEPENDENCIES = ../libevent.la -test_time_SOURCES = test-time.c -test_time_OBJECTS = test-time.$(OBJEXT) -test_time_LDADD = $(LDADD) -test_time_DEPENDENCIES = ../libevent.la -test_weof_SOURCES = test-weof.c -test_weof_OBJECTS = test-weof.$(OBJEXT) -test_weof_LDADD = $(LDADD) -test_weof_DEPENDENCIES = ../libevent.la -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +am_test_eof_OBJECTS = test-eof.$(OBJEXT) +test_eof_OBJECTS = $(am_test_eof_OBJECTS) +test_eof_DEPENDENCIES = ../libevent_core.la +am_test_init_OBJECTS = test-init.$(OBJEXT) +test_init_OBJECTS = $(am_test_init_OBJECTS) +test_init_DEPENDENCIES = ../libevent_core.la +am_test_time_OBJECTS = test-time.$(OBJEXT) +test_time_OBJECTS = $(am_test_time_OBJECTS) +test_time_DEPENDENCIES = ../libevent_core.la +am_test_weof_OBJECTS = test-weof.$(OBJEXT) +test_weof_OBJECTS = $(am_test_weof_OBJECTS) +test_weof_DEPENDENCIES = ../libevent_core.la +DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) -LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -SOURCES = bench.c regress.c test-eof.c test-init.c test-time.c \ - test-weof.c -DIST_SOURCES = bench.c regress.c test-eof.c test-init.c test-time.c \ - test-weof.c +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(bench_SOURCES) $(regress_SOURCES) $(test_eof_SOURCES) \ + $(test_init_SOURCES) $(test_time_SOURCES) $(test_weof_SOURCES) +DIST_SOURCES = $(bench_SOURCES) $(regress_SOURCES) $(test_eof_SOURCES) \ + $(test_init_SOURCES) $(test_time_SOURCES) $(test_weof_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ -AMDEP_FALSE = @AMDEP_FALSE@ -AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ @@ -103,9 +93,9 @@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ -CFLAGS = -I../compat @CFLAGS@ +CFLAGS = @CFLAGS@ CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ +CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ @@ -121,6 +111,8 @@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ +GREP = @GREP@ +INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -132,10 +124,8 @@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -MAINT = @MAINT@ -MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ -MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ @@ -145,66 +135,87 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ +SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ -ac_ct_AR = @ac_ct_AR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ -ac_ct_RANLIB = @ac_ct_RANLIB@ -ac_ct_STRIP = @ac_ct_STRIP@ -am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ -am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ -am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ -am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ +builddir = @builddir@ datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ +htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ +localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ +psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies -LDADD = ../libevent.la -CPPFPLAGS = -I.. -test_init_sources = test-init.c -test_eof_sources = test-eof.c -test_weof_sources = test-weof.c -test_time_sources = test-time.c -regress_sources = regress.c -bench_sources = bench.c +EXTRA_DIST = regress.rpc regress.gen.h regress.gen.c +BUILT_SOURCES = regress.gen.c regress.gen.h +test_init_SOURCES = test-init.c +test_init_LDADD = ../libevent_core.la +test_eof_SOURCES = test-eof.c +test_eof_LDADD = ../libevent_core.la +test_weof_SOURCES = test-weof.c +test_weof_LDADD = ../libevent_core.la +test_time_SOURCES = test-time.c +test_time_LDADD = ../libevent_core.la +regress_SOURCES = regress.c regress.h regress_http.c regress_dns.c \ + regress_rpc.c \ + regress.gen.c regress.gen.h + +regress_LDADD = ../libevent.la +bench_SOURCES = bench.c +bench_LDADD = ../libevent.la DISTCLEANFILES = *~ -all: all-am +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ @@ -229,9 +240,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) +$(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstPROGRAMS: @@ -242,22 +253,22 @@ clean-noinstPROGRAMS: done bench$(EXEEXT): $(bench_OBJECTS) $(bench_DEPENDENCIES) @rm -f bench$(EXEEXT) - $(LINK) $(bench_LDFLAGS) $(bench_OBJECTS) $(bench_LDADD) $(LIBS) + $(LINK) $(bench_OBJECTS) $(bench_LDADD) $(LIBS) regress$(EXEEXT): $(regress_OBJECTS) $(regress_DEPENDENCIES) @rm -f regress$(EXEEXT) - $(LINK) $(regress_LDFLAGS) $(regress_OBJECTS) $(regress_LDADD) $(LIBS) + $(LINK) $(regress_OBJECTS) $(regress_LDADD) $(LIBS) test-eof$(EXEEXT): $(test_eof_OBJECTS) $(test_eof_DEPENDENCIES) @rm -f test-eof$(EXEEXT) - $(LINK) $(test_eof_LDFLAGS) $(test_eof_OBJECTS) $(test_eof_LDADD) $(LIBS) + $(LINK) $(test_eof_OBJECTS) $(test_eof_LDADD) $(LIBS) test-init$(EXEEXT): $(test_init_OBJECTS) $(test_init_DEPENDENCIES) @rm -f test-init$(EXEEXT) - $(LINK) $(test_init_LDFLAGS) $(test_init_OBJECTS) $(test_init_LDADD) $(LIBS) + $(LINK) $(test_init_OBJECTS) $(test_init_LDADD) $(LIBS) test-time$(EXEEXT): $(test_time_OBJECTS) $(test_time_DEPENDENCIES) @rm -f test-time$(EXEEXT) - $(LINK) $(test_time_LDFLAGS) $(test_time_OBJECTS) $(test_time_LDADD) $(LIBS) + $(LINK) $(test_time_OBJECTS) $(test_time_LDADD) $(LIBS) test-weof$(EXEEXT): $(test_weof_OBJECTS) $(test_weof_DEPENDENCIES) @rm -f test-weof$(EXEEXT) - $(LINK) $(test_weof_LDFLAGS) $(test_weof_OBJECTS) $(test_weof_LDADD) $(LIBS) + $(LINK) $(test_weof_OBJECTS) $(test_weof_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -280,10 +291,6 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs -distclean-libtool: - -rm -f libtool -uninstall-info-am: - ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -333,22 +340,21 @@ distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ - list='$(DISTFILES)'; for file in $$list; do \ - case $$file in \ - $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ - $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ - esac; \ + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test "$$dir" != "$$file" && test "$$dir" != "."; then \ - dir="/$$dir"; \ - $(mkdir_p) "$(distdir)$$dir"; \ - else \ - dir=''; \ - fi; \ if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ @@ -360,10 +366,12 @@ distdir: $(DISTFILES) fi; \ done check-am: all-am -check: check-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(PROGRAMS) installdirs: -install: install-am +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am @@ -382,12 +390,13 @@ mostlyclean-generic: clean-generic: distclean-generic: - -rm -f $(CONFIG_CLEAN_FILES) + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ @@ -396,7 +405,7 @@ clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ - distclean-libtool distclean-tags + distclean-tags dvi: dvi-am @@ -410,12 +419,20 @@ info-am: install-data-am: +install-dvi: install-dvi-am + install-exec-am: +install-html: install-html-am + install-info: install-info-am install-man: +install-pdf: install-pdf-am + +install-ps: install-ps-am + installcheck-am: maintainer-clean: maintainer-clean-am @@ -435,27 +452,33 @@ ps: ps-am ps-am: -uninstall-am: uninstall-info-am +uninstall-am: + +.MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstPROGRAMS ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-exec \ - install-exec-am install-info install-info-am install-man \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ - pdf pdf-am ps ps-am tags uninstall uninstall-am \ - uninstall-info-am + pdf pdf-am ps ps-am tags uninstall uninstall-am +regress.gen.c regress.gen.h: regress.rpc $(top_srcdir)/event_rpcgen.py + $(top_srcdir)/event_rpcgen.py $(srcdir)/regress.rpc || echo "No Python installed" + test: test-init test-eof test-weof test-time regress verify: test - @./test.sh + @$(srcdir)/test.sh -bench test-init test-eof test-weof test-time regress: ../libevent.la +bench test-init test-eof test-weof test-time: ../libevent.la # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/opal/event/test/bench.c b/opal/event/test/bench.c index 8a9e0a5a67..48fd32a925 100644 --- a/opal/event/test/bench.c +++ b/opal/event/test/bench.c @@ -16,13 +16,13 @@ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO OPAL_EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWLAM_EVER CAUSED AND ON ANY + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, OPAL_EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * Mon 03/10/2003 - Modified by Davide Libenzi @@ -37,40 +37,35 @@ #include "config.h" #endif -#ifdef HAVE_SYS_TYPES_H #include -#endif #include -#ifdef HAVE_SYS_TIME_H #include -#endif -#ifdef HAVE_SYS_SOCKET_H +#ifdef WIN32 +#include +#else #include -#endif #include -#ifdef HAVE_SYS_RESOURCE_H #include #endif #include #include #include #include -#ifdef HAVE_UNISTD_H #include -#endif #include #include +#include static int count, writes, fired; static int *pipes; static int num_pipes, num_active, num_writes; -static struct opal_event *events; +static struct event *events; -void +static void read_cb(int fd, short which, void *arg) { int idx = (int) arg, widx = idx + 1; @@ -86,19 +81,19 @@ read_cb(int fd, short which, void *arg) } } -struct timeval * +static struct timeval * run_once(void) { int *cp, i, space; static struct timeval ts, te; for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { - opal_event_del(&events[i]); - opal_event_set(&events[i], cp[0], OPAL_EV_READ | OPAL_EV_PERSIST, read_cb, (void *) i); - opal_event_add(&events[i], NULL); + event_del(&events[i]); + event_set(&events[i], cp[0], EV_READ | EV_PERSIST, read_cb, (void *) i); + event_add(&events[i], NULL); } - opal_event_loop(OPAL_EVLOOP_ONCE | OPAL_EVLOOP_NONBLOCK); + event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK); fired = 0; space = num_pipes / num_active; @@ -111,7 +106,7 @@ run_once(void) { int xcount = 0; gettimeofday(&ts, NULL); do { - opal_event_loop(OPAL_EVLOOP_ONCE | OPAL_EVLOOP_NONBLOCK); + event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK); xcount++; } while (count != fired); gettimeofday(&te, NULL); @@ -119,7 +114,7 @@ run_once(void) if (xcount != count) fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count); } - timersub(&te, &ts, &te); + evutil_timersub(&te, &ts, &te); return (&te); } @@ -127,11 +122,12 @@ run_once(void) int main (int argc, char **argv) { +#ifndef WIN32 struct rlimit rl; +#endif int i, c; struct timeval *tv; int *cp; - extern char *optarg; num_pipes = 100; num_active = 1; @@ -153,26 +149,28 @@ main (int argc, char **argv) } } +#ifndef WIN32 rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50; if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { perror("setrlimit"); exit(1); } +#endif - events = calloc(num_pipes, sizeof(struct opal_event)); + events = calloc(num_pipes, sizeof(struct event)); pipes = calloc(num_pipes * 2, sizeof(int)); if (events == NULL || pipes == NULL) { perror("malloc"); exit(1); } - opal_event_init(); + event_init(); for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { #ifdef USE_PIPES if (pipe(cp) == -1) { #else - if (socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) { + if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) { #endif perror("pipe"); exit(1); diff --git a/opal/event/test/regress.c b/opal/event/test/regress.c index ce47d22599..0c8d92bde7 100644 --- a/opal/event/test/regress.c +++ b/opal/event/test/regress.c @@ -39,21 +39,31 @@ #ifdef HAVE_SYS_TIME_H #include #endif +#include #ifndef WIN32 #include +#include #include #include +#include #endif #include +#include #include #include #include #include -#include +#include "event.h" +#include "evutil.h" +#include "event-internal.h" +#include "log.h" -static int pair[2]; -static int test_ok; +#include "regress.h" +#include "regress.gen.h" + +int pair[2]; +int test_ok; static int called; static char wbuf[4096]; static char rbuf[4096]; @@ -62,12 +72,21 @@ static int roff; static int usepersist; static struct timeval tset; static struct timeval tcalled; -static struct event_base *event_base; +static struct event_base *global_base; #define TEST1 "this is a test" #define SECONDS 1 -void +#ifndef SHUT_WR +#define SHUT_WR 1 +#endif + +#ifdef WIN32 +#define write(fd,buf,len) send((fd),(buf),(len),0) +#define read(fd,buf,len) recv((fd),(buf),(len),0) +#endif + +static void simple_read_cb(int fd, short event, void *arg) { char buf[256]; @@ -86,7 +105,7 @@ simple_read_cb(int fd, short event, void *arg) called++; } -void +static void simple_write_cb(int fd, short event, void *arg) { int len; @@ -98,7 +117,7 @@ simple_write_cb(int fd, short event, void *arg) test_ok = 1; } -void +static void multiple_write_cb(int fd, short event, void *arg) { struct event *ev = arg; @@ -131,7 +150,7 @@ multiple_write_cb(int fd, short event, void *arg) } } -void +static void multiple_read_cb(int fd, short event, void *arg) { struct event *ev = arg; @@ -153,17 +172,17 @@ multiple_read_cb(int fd, short event, void *arg) } } -void +static void timeout_cb(int fd, short event, void *arg) { struct timeval tv; int diff; gettimeofday(&tcalled, NULL); - if (timercmp(&tcalled, &tset, >)) - timersub(&tcalled, &tset, &tv); + if (evutil_timercmp(&tcalled, &tset, >)) + evutil_timersub(&tcalled, &tset, &tv); else - timersub(&tset, &tcalled, &tv); + evutil_timersub(&tset, &tcalled, &tv); diff = tv.tv_sec*1000 + tv.tv_usec/1000 - SECONDS * 1000; if (diff < 0) @@ -173,7 +192,13 @@ timeout_cb(int fd, short event, void *arg) test_ok = 1; } -void +static void +signal_cb_sa(int sig) +{ + test_ok = 2; +} + +static void signal_cb(int fd, short event, void *arg) { struct event *ev = arg; @@ -187,7 +212,7 @@ struct both { int nread; }; -void +static void combined_read_cb(int fd, short event, void *arg) { struct both *both = arg; @@ -205,7 +230,7 @@ combined_read_cb(int fd, short event, void *arg) exit(1); } -void +static void combined_write_cb(int fd, short event, void *arg) { struct both *both = arg; @@ -231,13 +256,13 @@ combined_write_cb(int fd, short event, void *arg) /* Test infrastructure */ -int -setup_test(char *name) +static int +setup_test(const char *name) { fprintf(stdout, "%s", name); - if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { + if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { fprintf(stderr, "%s: socketpair\n", __func__); exit(1); } @@ -255,7 +280,7 @@ setup_test(char *name) return (0); } -int +static int cleanup_test(void) { #ifndef WIN32 @@ -271,12 +296,12 @@ cleanup_test(void) fprintf(stdout, "FAILED\n"); exit(1); } - + test_ok = 0; return (0); } -void -test1(void) +static void +test_simpleread(void) { struct event ev; @@ -294,8 +319,8 @@ test1(void) cleanup_test(); } -void -test2(void) +static void +test_simplewrite(void) { struct event ev; @@ -310,8 +335,8 @@ test2(void) cleanup_test(); } -void -test3(void) +static void +test_multiple(void) { struct event ev, ev2; int i; @@ -339,8 +364,8 @@ test3(void) cleanup_test(); } -void -test4(void) +static void +test_persistent(void) { struct event ev, ev2; int i; @@ -368,8 +393,8 @@ test4(void) cleanup_test(); } -void -test5(void) +static void +test_combined(void) { struct both r1, r2, w1, w2; @@ -403,8 +428,8 @@ test5(void) cleanup_test(); } -void -test6(void) +static void +test_simpletimeout(void) { struct timeval tv; struct event ev; @@ -423,8 +448,63 @@ test6(void) } #ifndef WIN32 -void -test7(void) +extern struct event_base *current_base; +static void +test_fork(void) +{ + int status; + struct event ev; + pid_t pid; + + setup_test("After fork: "); + + write(pair[0], TEST1, strlen(TEST1)+1); + + event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev); + if (event_add(&ev, NULL) == -1) + exit(1); + + if ((pid = fork()) == 0) { + /* in the child */ + if (event_reinit(current_base) == -1) { + fprintf(stderr, "FAILED (reinit)\n"); + exit(1); + } + + event_dispatch(); + + /* we do not send an EOF; simple_read_cb requires an EOF + * to set test_ok. we just verify that the callback was + * called. */ + exit(test_ok != 0 || called != 2); + } + + /* wait for the child to read the data */ + sleep(1); + + write(pair[0], TEST1, strlen(TEST1)+1); + + if (waitpid(pid, &status, 0) == -1) { + fprintf(stderr, "FAILED (fork)\n"); + exit(1); + } + + if (WEXITSTATUS(status) != 0) { + fprintf(stderr, "FAILED (exit)\n"); + exit(1); + } + + /* test that the current event loop still works */ + write(pair[0], TEST1, strlen(TEST1)+1); + shutdown(pair[0], SHUT_WR); + + event_dispatch(); + + cleanup_test(); +} + +static void +test_simplesignal(void) { struct event ev; struct itimerval itv; @@ -440,14 +520,228 @@ test7(void) event_dispatch(); skip_simplesignal: - signal_del(&ev); + if (signal_del(&ev) == -1) + test_ok = 0; cleanup_test(); } + +static void +test_immediatesignal(void) +{ + struct event ev; + + test_ok = 0; + printf("Immediate signal: "); + signal_set(&ev, SIGUSR1, signal_cb, &ev); + signal_add(&ev, NULL); + raise(SIGUSR1); + event_loop(EVLOOP_NONBLOCK); + signal_del(&ev); + cleanup_test(); +} + +static void +test_signal_dealloc(void) +{ + /* make sure that signal_event is event_del'ed and pipe closed */ + struct event ev; + struct event_base *base = event_init(); + printf("Signal dealloc: "); + signal_set(&ev, SIGUSR1, signal_cb, &ev); + signal_add(&ev, NULL); + signal_del(&ev); + event_base_free(base); + /* If we got here without asserting, we're fine. */ + test_ok = 1; + cleanup_test(); +} + +static void +test_signal_pipeloss(void) +{ + /* make sure that the base1 pipe is closed correctly. */ + struct event_base *base1, *base2; + int pipe1; + test_ok = 0; + printf("Signal pipeloss: "); + base1 = event_init(); + pipe1 = base1->sig.ev_signal_pair[0]; + base2 = event_init(); + event_base_free(base2); + event_base_free(base1); + if (close(pipe1) != -1 || errno!=EBADF) { + /* fd must be closed, so second close gives -1, EBADF */ + printf("signal pipe not closed. "); + test_ok = 0; + } else { + test_ok = 1; + } + cleanup_test(); +} + +/* + * make two bases to catch signals, use both of them. this only works + * for event mechanisms that use our signal pipe trick. kqueue handles + * signals internally, and all interested kqueues get all the signals. + */ +static void +test_signal_switchbase(void) +{ + struct event ev1, ev2; + struct event_base *base1, *base2; + int is_kqueue; + test_ok = 0; + printf("Signal switchbase: "); + base1 = event_init(); + base2 = event_init(); + is_kqueue = !strcmp(event_get_method(),"kqueue"); + signal_set(&ev1, SIGUSR1, signal_cb, &ev1); + signal_set(&ev2, SIGUSR1, signal_cb, &ev2); + if (event_base_set(base1, &ev1) || + event_base_set(base2, &ev2) || + event_add(&ev1, NULL) || + event_add(&ev2, NULL)) { + fprintf(stderr, "%s: cannot set base, add\n", __func__); + exit(1); + } + + test_ok = 0; + /* can handle signal before loop is called */ + raise(SIGUSR1); + event_base_loop(base2, EVLOOP_NONBLOCK); + if (is_kqueue) { + if (!test_ok) + goto done; + test_ok = 0; + } + event_base_loop(base1, EVLOOP_NONBLOCK); + if (test_ok && !is_kqueue) { + test_ok = 0; + + /* set base1 to handle signals */ + event_base_loop(base1, EVLOOP_NONBLOCK); + raise(SIGUSR1); + event_base_loop(base1, EVLOOP_NONBLOCK); + event_base_loop(base2, EVLOOP_NONBLOCK); + } + done: + event_base_free(base1); + event_base_free(base2); + cleanup_test(); +} + +/* + * assert that a signal event removed from the event queue really is + * removed - with no possibility of it's parent handler being fired. + */ +static void +test_signal_assert(void) +{ + struct event ev; + struct event_base *base = event_init(); + test_ok = 0; + printf("Signal handler assert: "); + /* use SIGCONT so we don't kill ourselves when we signal to nowhere */ + signal_set(&ev, SIGCONT, signal_cb, &ev); + signal_add(&ev, NULL); + /* + * if signal_del() fails to reset the handler, it's current handler + * will still point to evsignal_handler(). + */ + signal_del(&ev); + + raise(SIGCONT); + /* only way to verify we were in evsignal_handler() */ + if (base->sig.evsignal_caught) + test_ok = 0; + else + test_ok = 1; + + event_base_free(base); + cleanup_test(); + return; +} + +/* + * assert that we restore our previous signal handler properly. + */ +static void +test_signal_restore(void) +{ + struct event ev; + struct event_base *base = event_init(); +#ifdef HAVE_SIGACTION + struct sigaction sa; #endif -void -test8(void) + test_ok = 0; + printf("Signal handler restore: "); +#ifdef HAVE_SIGACTION + sa.sa_handler = signal_cb_sa; + sa.sa_flags = 0x0; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGUSR1, &sa, NULL) == -1) + goto out; +#else + if (signal(SIGUSR1, signal_cb_sa) == SIG_ERR) + goto out; +#endif + signal_set(&ev, SIGUSR1, signal_cb, &ev); + signal_add(&ev, NULL); + signal_del(&ev); + + raise(SIGUSR1); + /* 1 == signal_cb, 2 == signal_cb_sa, we want our previous handler */ + if (test_ok != 2) + test_ok = 0; +out: + event_base_free(base); + cleanup_test(); + return; +} +#endif + +static void +test_free_active_base(void) +{ + struct event_base *base1; + struct event ev1; + setup_test("Free active base: "); + base1 = event_init(); + event_set(&ev1, pair[1], EV_READ, simple_read_cb, &ev1); + event_base_set(base1, &ev1); + event_add(&ev1, NULL); + /* event_del(&ev1); */ + event_base_free(base1); + test_ok = 1; + cleanup_test(); +} + +static void +test_event_base_new(void) +{ + struct event_base *base; + struct event ev1; + setup_test("Event base new: "); + + write(pair[0], TEST1, strlen(TEST1)+1); + shutdown(pair[0], SHUT_WR); + + base = event_base_new(); + event_set(&ev1, pair[1], EV_READ, simple_read_cb, &ev1); + event_base_set(base, &ev1); + event_add(&ev1, NULL); + + event_base_dispatch(base); + + event_base_free(base); + test_ok = 1; + cleanup_test(); +} + +static void +test_loopexit(void) { struct timeval tv, tv_start, tv_end; struct event ev; @@ -466,7 +760,7 @@ test8(void) gettimeofday(&tv_start, NULL); event_dispatch(); gettimeofday(&tv_end, NULL); - timersub(&tv_end, &tv_start, &tv_end); + evutil_timersub(&tv_end, &tv_start, &tv_end); evtimer_del(&ev); @@ -476,7 +770,142 @@ test8(void) cleanup_test(); } -void +static void +test_loopexit_multiple(void) +{ + struct timeval tv; + struct event_base *base; + + setup_test("Loop Multiple exit: "); + + base = event_base_new(); + + tv.tv_usec = 0; + tv.tv_sec = 1; + event_base_loopexit(base, &tv); + + tv.tv_usec = 0; + tv.tv_sec = 2; + event_base_loopexit(base, &tv); + + event_base_dispatch(base); + + event_base_free(base); + + test_ok = 1; + + cleanup_test(); +} + +static void +break_cb(int fd, short events, void *arg) +{ + test_ok = 1; + event_loopbreak(); +} + +static void +fail_cb(int fd, short events, void *arg) +{ + test_ok = 0; +} + +static void +test_loopbreak(void) +{ + struct event ev1, ev2; + struct timeval tv; + + setup_test("Loop break: "); + + tv.tv_sec = 0; + tv.tv_usec = 0; + evtimer_set(&ev1, break_cb, NULL); + evtimer_add(&ev1, &tv); + evtimer_set(&ev2, fail_cb, NULL); + evtimer_add(&ev2, &tv); + + event_dispatch(); + + evtimer_del(&ev1); + evtimer_del(&ev2); + + cleanup_test(); +} + +static void +test_evbuffer(void) { + + struct evbuffer *evb = evbuffer_new(); + setup_test("Testing Evbuffer: "); + + evbuffer_add_printf(evb, "%s/%d", "hello", 1); + + if (EVBUFFER_LENGTH(evb) == 7 && + strcmp((char*)EVBUFFER_DATA(evb), "hello/1") == 0) + test_ok = 1; + + evbuffer_free(evb); + + cleanup_test(); +} + +static void +test_evbuffer_find(void) +{ + u_char* p; + const char* test1 = "1234567890\r\n"; + const char* test2 = "1234567890\r"; +#define EVBUFFER_INITIAL_LENGTH 256 + char test3[EVBUFFER_INITIAL_LENGTH]; + unsigned int i; + struct evbuffer * buf = evbuffer_new(); + + /* make sure evbuffer_find doesn't match past the end of the buffer */ + fprintf(stdout, "Testing evbuffer_find 1: "); + evbuffer_add(buf, (u_char*)test1, strlen(test1)); + evbuffer_drain(buf, strlen(test1)); + evbuffer_add(buf, (u_char*)test2, strlen(test2)); + p = evbuffer_find(buf, (u_char*)"\r\n", 2); + if (p == NULL) { + fprintf(stdout, "OK\n"); + } else { + fprintf(stdout, "FAILED\n"); + exit(1); + } + + /* + * drain the buffer and do another find; in r309 this would + * read past the allocated buffer causing a valgrind error. + */ + fprintf(stdout, "Testing evbuffer_find 2: "); + evbuffer_drain(buf, strlen(test2)); + for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i) + test3[i] = 'a'; + test3[EVBUFFER_INITIAL_LENGTH - 1] = 'x'; + evbuffer_add(buf, (u_char *)test3, EVBUFFER_INITIAL_LENGTH); + p = evbuffer_find(buf, (u_char *)"xy", 2); + if (p == NULL) { + printf("OK\n"); + } else { + fprintf(stdout, "FAILED\n"); + exit(1); + } + + /* simple test for match at end of allocated buffer */ + fprintf(stdout, "Testing evbuffer_find 3: "); + p = evbuffer_find(buf, (u_char *)"ax", 2); + if (p != NULL && strncmp((char*)p, "ax", 2) == 0) { + printf("OK\n"); + } else { + fprintf(stdout, "FAILED\n"); + exit(1); + } + + evbuffer_free(buf); +} + +static void readcb(struct bufferevent *bev, void *arg) { if (EVBUFFER_LENGTH(bev->input) == 8333) { @@ -485,21 +914,21 @@ readcb(struct bufferevent *bev, void *arg) } } -void +static void writecb(struct bufferevent *bev, void *arg) { if (EVBUFFER_LENGTH(bev->output) == 0) test_ok++; } -void +static void errorcb(struct bufferevent *bev, short what, void *arg) { test_ok = -2; } -void -test9(void) +static void +test_bufferevent(void) { struct bufferevent *bev1, *bev2; char buffer[8333]; @@ -514,7 +943,7 @@ test9(void) bufferevent_enable(bev2, EV_READ); for (i = 0; i < sizeof(buffer); i++) - buffer[0] = i; + buffer[i] = i; bufferevent_write(bev1, buffer, sizeof(buffer)); @@ -534,7 +963,7 @@ struct test_pri_event { int count; }; -void +static void test_priorities_cb(int fd, short what, void *arg) { struct test_pri_event *pri = arg; @@ -547,21 +976,21 @@ test_priorities_cb(int fd, short what, void *arg) pri->count++; - timerclear(&tv); + evutil_timerclear(&tv); event_add(&pri->ev, &tv); } -void +static void test_priorities(int npriorities) { char buf[32]; struct test_pri_event one, two; struct timeval tv; - snprintf(buf, sizeof(buf), "Priorities %d: ", npriorities); + snprintf(buf, sizeof(buf), "Testing Priorities %d: ", npriorities); setup_test(buf); - event_base_priority_init(event_base, npriorities); + event_base_priority_init(global_base, npriorities); memset(&one, 0, sizeof(one)); memset(&two, 0, sizeof(two)); @@ -578,7 +1007,7 @@ test_priorities(int npriorities) exit(1); } - timerclear(&tv); + evutil_timerclear(&tv); if (event_add(&one.ev, &tv) == -1) exit(1); @@ -614,7 +1043,7 @@ test_multiple_cb(int fd, short event, void *arg) test_ok |= 2; } -void +static void test_multiple_events_for_same_fd(void) { struct event e1, e2; @@ -637,6 +1066,301 @@ test_multiple_events_for_same_fd(void) cleanup_test(); } +int evtag_decode_int(uint32_t *pnumber, struct evbuffer *evbuf); +int evtag_encode_tag(struct evbuffer *evbuf, uint32_t number); +int evtag_decode_tag(uint32_t *pnumber, struct evbuffer *evbuf); + +static void +read_once_cb(int fd, short event, void *arg) +{ + char buf[256]; + int len; + + len = read(fd, buf, sizeof(buf)); + + if (called) { + test_ok = 0; + } else if (len) { + /* Assumes global pair[0] can be used for writing */ + write(pair[0], TEST1, strlen(TEST1)+1); + test_ok = 1; + } + + called++; +} + +static void +test_want_only_once(void) +{ + struct event ev; + struct timeval tv; + + /* Very simple read test */ + setup_test("Want read only once: "); + + write(pair[0], TEST1, strlen(TEST1)+1); + + /* Setup the loop termination */ + evutil_timerclear(&tv); + tv.tv_sec = 1; + event_loopexit(&tv); + + event_set(&ev, pair[1], EV_READ, read_once_cb, &ev); + if (event_add(&ev, NULL) == -1) + exit(1); + event_dispatch(); + + cleanup_test(); +} + +#define TEST_MAX_INT 6 + +static void +evtag_int_test(void) +{ + struct evbuffer *tmp = evbuffer_new(); + uint32_t integers[TEST_MAX_INT] = { + 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000 + }; + uint32_t integer; + int i; + + for (i = 0; i < TEST_MAX_INT; i++) { + int oldlen, newlen; + oldlen = EVBUFFER_LENGTH(tmp); + encode_int(tmp, integers[i]); + newlen = EVBUFFER_LENGTH(tmp); + fprintf(stdout, "\t\tencoded 0x%08x with %d bytes\n", + integers[i], newlen - oldlen); + } + + for (i = 0; i < TEST_MAX_INT; i++) { + if (evtag_decode_int(&integer, tmp) == -1) { + fprintf(stderr, "decode %d failed", i); + exit(1); + } + if (integer != integers[i]) { + fprintf(stderr, "got %x, wanted %x", + integer, integers[i]); + exit(1); + } + } + + if (EVBUFFER_LENGTH(tmp) != 0) { + fprintf(stderr, "trailing data"); + exit(1); + } + evbuffer_free(tmp); + + fprintf(stdout, "\t%s: OK\n", __func__); +} + +static void +evtag_fuzz(void) +{ + u_char buffer[4096]; + struct evbuffer *tmp = evbuffer_new(); + struct timeval tv; + int i, j; + + int not_failed = 0; + for (j = 0; j < 100; j++) { + for (i = 0; i < sizeof(buffer); i++) + buffer[i] = rand(); + evbuffer_drain(tmp, -1); + evbuffer_add(tmp, buffer, sizeof(buffer)); + + if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) + not_failed++; + } + + /* The majority of decodes should fail */ + if (not_failed >= 10) { + fprintf(stderr, "evtag_unmarshal should have failed"); + exit(1); + } + + /* Now insert some corruption into the tag length field */ + evbuffer_drain(tmp, -1); + evutil_timerclear(&tv); + tv.tv_sec = 1; + evtag_marshal_timeval(tmp, 0, &tv); + evbuffer_add(tmp, buffer, sizeof(buffer)); + + EVBUFFER_DATA(tmp)[1] = 0xff; + if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) { + fprintf(stderr, "evtag_unmarshal_timeval should have failed"); + exit(1); + } + + evbuffer_free(tmp); + + fprintf(stdout, "\t%s: OK\n", __func__); +} + +static void +evtag_tag_encoding(void) +{ + struct evbuffer *tmp = evbuffer_new(); + uint32_t integers[TEST_MAX_INT] = { + 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000 + }; + uint32_t integer; + int i; + + for (i = 0; i < TEST_MAX_INT; i++) { + int oldlen, newlen; + oldlen = EVBUFFER_LENGTH(tmp); + evtag_encode_tag(tmp, integers[i]); + newlen = EVBUFFER_LENGTH(tmp); + fprintf(stdout, "\t\tencoded 0x%08x with %d bytes\n", + integers[i], newlen - oldlen); + } + + for (i = 0; i < TEST_MAX_INT; i++) { + if (evtag_decode_tag(&integer, tmp) == -1) { + fprintf(stderr, "decode %d failed", i); + exit(1); + } + if (integer != integers[i]) { + fprintf(stderr, "got %x, wanted %x", + integer, integers[i]); + exit(1); + } + } + + if (EVBUFFER_LENGTH(tmp) != 0) { + fprintf(stderr, "trailing data"); + exit(1); + } + evbuffer_free(tmp); + + fprintf(stdout, "\t%s: OK\n", __func__); +} + +static void +evtag_test(void) +{ + fprintf(stdout, "Testing Tagging:\n"); + + evtag_init(); + evtag_int_test(); + evtag_fuzz(); + + evtag_tag_encoding(); + + fprintf(stdout, "OK\n"); +} + +static void +rpc_test(void) +{ + struct msg *msg, *msg2; + struct kill *attack; + struct run *run; + struct evbuffer *tmp = evbuffer_new(); + struct timeval tv_start, tv_end; + uint32_t tag; + int i; + + fprintf(stdout, "Testing RPC: "); + + msg = msg_new(); + EVTAG_ASSIGN(msg, from_name, "niels"); + EVTAG_ASSIGN(msg, to_name, "phoenix"); + + if (EVTAG_GET(msg, attack, &attack) == -1) { + fprintf(stderr, "Failed to set kill message.\n"); + exit(1); + } + + EVTAG_ASSIGN(attack, weapon, "feather"); + EVTAG_ASSIGN(attack, action, "tickle"); + + gettimeofday(&tv_start, NULL); + for (i = 0; i < 1000; ++i) { + run = EVTAG_ADD(msg, run); + if (run == NULL) { + fprintf(stderr, "Failed to add run message.\n"); + exit(1); + } + EVTAG_ASSIGN(run, how, "very fast but with some data in it"); + } + + if (msg_complete(msg) == -1) { + fprintf(stderr, "Failed to make complete message.\n"); + exit(1); + } + + evtag_marshal_msg(tmp, 0xdeaf, msg); + + if (evtag_peek(tmp, &tag) == -1) { + fprintf(stderr, "Failed to peak tag.\n"); + exit (1); + } + + if (tag != 0xdeaf) { + fprintf(stderr, "Got incorrect tag: %0x.\n", tag); + exit (1); + } + + msg2 = msg_new(); + if (evtag_unmarshal_msg(tmp, 0xdeaf, msg2) == -1) { + fprintf(stderr, "Failed to unmarshal message.\n"); + exit(1); + } + + gettimeofday(&tv_end, NULL); + evutil_timersub(&tv_end, &tv_start, &tv_end); + fprintf(stderr, "(%.1f us/add) ", + (float)tv_end.tv_sec/(float)i * 1000000.0 + + tv_end.tv_usec / (float)i); + + if (!EVTAG_HAS(msg2, from_name) || + !EVTAG_HAS(msg2, to_name) || + !EVTAG_HAS(msg2, attack)) { + fprintf(stderr, "Missing data structures.\n"); + exit(1); + } + + if (EVTAG_LEN(msg2, run) != i) { + fprintf(stderr, "Wrong number of run messages.\n"); + exit(1); + } + + msg_free(msg); + msg_free(msg2); + + evbuffer_free(tmp); + + fprintf(stdout, "OK\n"); +} + +static void +test_evutil_strtoll(void) +{ + const char *s; + char *endptr; + setup_test("evutil_stroll: "); + test_ok = 0; + + if (evutil_strtoll("5000000000", NULL, 10) != ((ev_int64_t)5000000)*1000) + goto err; + if (evutil_strtoll("-5000000000", NULL, 10) != ((ev_int64_t)5000000)*-1000) + goto err; + s = " 99999stuff"; + if (evutil_strtoll(s, &endptr, 10) != (ev_int64_t)99999) + goto err; + if (endptr != s+6) + goto err; + if (evutil_strtoll("foo", NULL, 10) != 0) + goto err; + + test_ok = 1; + err: + cleanup_test(); +} + int main (int argc, char **argv) @@ -654,32 +1378,70 @@ main (int argc, char **argv) setvbuf(stdout, NULL, _IONBF, 0); /* Initalize the event library */ - event_base = event_init(); + global_base = event_init(); - test1(); - - test2(); - - test3(); - - test4(); - - test5(); - - test6(); -#ifndef WIN32 - test7(); -#endif - test8(); - - test9(); + test_evutil_strtoll(); + /* use the global event base and need to be called first */ test_priorities(1); test_priorities(2); test_priorities(3); + test_evbuffer(); + test_evbuffer_find(); + + test_bufferevent(); + + test_free_active_base(); + + test_event_base_new(); + + http_suite(); + + rpc_suite(); + + dns_suite(); + +#ifndef WIN32 + test_fork(); +#endif + + test_simpleread(); + + test_simplewrite(); + + test_multiple(); + + test_persistent(); + + test_combined(); + + test_simpletimeout(); +#ifndef WIN32 + test_simplesignal(); + test_immediatesignal(); +#endif + test_loopexit(); + test_loopbreak(); + + test_loopexit_multiple(); + test_multiple_events_for_same_fd(); + test_want_only_once(); + + evtag_test(); + + rpc_test(); + +#ifndef WIN32 + test_signal_dealloc(); + test_signal_pipeloss(); + test_signal_switchbase(); + test_signal_restore(); + test_signal_assert(); +#endif + return (0); } diff --git a/opal/event/test/test-eof.c b/opal/event/test/test-eof.c index 5ee478984a..4fc1a19f22 100644 --- a/opal/event/test/test-eof.c +++ b/opal/event/test/test-eof.c @@ -2,14 +2,17 @@ * Compile with: * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif -#ifdef HAVE_SYS_TYPES_H + +#ifdef WIN32 +#include +#endif #include -#endif #include -#ifdef HAVE_SYS_TIME_H #include -#endif #ifdef HAVE_SYS_SOCKET_H #include #endif @@ -17,17 +20,16 @@ #include #include #include -#ifdef HAVE_UNISTD_H #include -#endif #include #include +#include int test_okay = 1; int called = 0; -void +static void read_cb(int fd, short event, void *arg) { char buf[256]; @@ -40,21 +42,25 @@ read_cb(int fd, short event, void *arg) if (len) { if (!called) - opal_event_add(arg, NULL); + event_add(arg, NULL); } else if (called == 1) test_okay = 0; called++; } +#ifndef SHUT_WR +#define SHUT_WR 1 +#endif + int main (int argc, char **argv) { - struct opal_event ev; - char *test = "test string"; + struct event ev; + const char *test = "test string"; int pair[2]; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) + if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) return (1); @@ -62,14 +68,14 @@ main (int argc, char **argv) shutdown(pair[0], SHUT_WR); /* Initalize the event library */ - opal_event_init(); + event_init(); /* Initalize one event */ - opal_event_set(&ev, pair[1], OPAL_EV_READ, read_cb, &ev); + event_set(&ev, pair[1], EV_READ, read_cb, &ev); - opal_event_add(&ev, NULL); + event_add(&ev, NULL); - opal_event_dispatch(); + event_dispatch(); return (test_okay); } diff --git a/opal/event/test/test-init.c b/opal/event/test/test-init.c index ce5a3f54cc..c368715fd6 100644 --- a/opal/event/test/test-init.c +++ b/opal/event/test/test-init.c @@ -2,14 +2,14 @@ * Compile with: * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + -#ifdef HAVE_SYS_TYPES_H #include -#endif #include -#ifdef HAVE_SYS_TIME_H #include -#endif #ifdef HAVE_SYS_SOCKET_H #include #endif @@ -17,9 +17,7 @@ #include #include #include -#ifdef HAVE_UNISTD_H #include -#endif #include #include @@ -28,7 +26,7 @@ int main(int argc, char **argv) { /* Initalize the event library */ - opal_event_init(); + event_init(); return (0); } diff --git a/opal/event/test/test-time.c b/opal/event/test/test-time.c index 4a84a26c81..a847d55ef3 100644 --- a/opal/event/test/test-time.c +++ b/opal/event/test/test-time.c @@ -2,21 +2,19 @@ * Compile with: * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + -#ifdef HAVE_SYS_TYPES_H #include -#endif #include -#ifdef HAVE_SYS_TIME_H #include -#endif #include #include #include #include -#ifdef HAVE_UNISTD_H #include -#endif #include #include @@ -25,9 +23,19 @@ int called = 0; #define NEVENT 20000 -struct opal_event *ev[NEVENT]; +struct event *ev[NEVENT]; -void +static int +rand_int(int n) +{ +#ifdef WIN32 + return (int)(rand() * n); +#else + return (int)(random() % n); +#endif +} + +static void time_cb(int fd, short event, void *arg) { struct timeval tv; @@ -37,13 +45,13 @@ time_cb(int fd, short event, void *arg) if (called < 10*NEVENT) { for (i = 0; i < 10; i++) { - j = random() % NEVENT; + j = rand_int(NEVENT); tv.tv_sec = 0; - tv.tv_usec = random() % 50000L; + tv.tv_usec = rand_int(50000); if (tv.tv_usec % 2) - opal_evtimer_add(ev[j], &tv); + evtimer_add(ev[j], &tv); else - opal_evtimer_del(ev[j]); + evtimer_del(ev[j]); } } } @@ -55,19 +63,19 @@ main (int argc, char **argv) int i; /* Initalize the event library */ - opal_event_init(); + event_init(); for (i = 0; i < NEVENT; i++) { - ev[i] = malloc(sizeof(struct opal_event)); + ev[i] = malloc(sizeof(struct event)); /* Initalize one event */ - opal_evtimer_set(ev[i], time_cb, ev[i]); + evtimer_set(ev[i], time_cb, ev[i]); tv.tv_sec = 0; - tv.tv_usec = random() % 50000L; - opal_evtimer_add(ev[i], &tv); + tv.tv_usec = rand_int(50000); + evtimer_add(ev[i], &tv); } - opal_event_dispatch(); + event_dispatch(); return (called < NEVENT); } diff --git a/opal/event/test/test-weof.c b/opal/event/test/test-weof.c index 0ad59c0e65..5d87ceb8eb 100644 --- a/opal/event/test/test-weof.c +++ b/opal/event/test/test-weof.c @@ -2,14 +2,17 @@ * Compile with: * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif -#ifdef HAVE_SYS_TYPES_H + +#ifdef WIN32 +#include +#endif #include -#endif #include -#ifdef HAVE_SYS_TIME_H #include -#endif #ifdef HAVE_SYS_SOCKET_H #include #endif @@ -18,21 +21,20 @@ #include #include #include -#ifdef HAVE_UNISTD_H #include -#endif #include #include +#include int pair[2]; int test_okay = 1; int called = 0; -void +static void write_cb(int fd, short event, void *arg) { - char *test = "test string"; + const char *test = "test string"; int len; len = write(fd, test, strlen(test) + 1); @@ -42,7 +44,7 @@ write_cb(int fd, short event, void *arg) if (len > 0) { if (!called) - opal_event_add(arg, NULL); + event_add(arg, NULL); close(pair[0]); } else if (called == 1) test_okay = 0; @@ -53,21 +55,25 @@ write_cb(int fd, short event, void *arg) int main (int argc, char **argv) { - struct opal_event ev; + struct event ev; - if (signal(SIGPIPE, SIG_IGN) == SIG_IGN) +#ifndef WIN32 + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) return (1); +#endif - if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) + if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) return (1); /* Initalize the event library */ - opal_event_init(); + event_init(); /* Initalize one event */ - opal_event_set(&ev, pair[1], OPAL_EV_WRITE, write_cb, &ev); - opal_event_add(&ev, NULL); - opal_event_dispatch(); + event_set(&ev, pair[1], EV_WRITE, write_cb, &ev); + + event_add(&ev, NULL); + + event_dispatch(); return (test_okay); } diff --git a/opal/event/test/test.sh b/opal/event/test/test.sh index d23c1fac4c..506a1988c3 100755 --- a/opal/event/test/test.sh +++ b/opal/event/test/test.sh @@ -1,17 +1,19 @@ #!/bin/sh setup () { - export EVENT_NOKQUEUE=yes - export EVENT_NODEVPOLL=yes - export EVENT_NOPOLL=yes - export EVENT_NOSELECT=yes - export EVENT_NOEPOLL=yes - export EVENT_NORTSIG=yes + EVENT_NOKQUEUE=yes; export EVENT_NOKQUEUE + EVENT_NODEVPOLL=yes; export EVENT_NODEVPOLL + EVENT_NOPOLL=yes; export EVENT_NOPOLL + EVENT_NOSELECT=yes; export EVENT_NOSELECT + EVENT_NOEPOLL=yes; export EVENT_NOEPOLL + EVENT_NOEVPORT=yes; export EVENT_NOEVPORT } test () { - if ! ./test-init 2>/dev/null ; + if ./test-init 2>/dev/null ; then + true + else echo Skipping test return fi @@ -51,33 +53,39 @@ echo "Running tests:" # Need to do this by hand? setup unset EVENT_NOKQUEUE +export EVENT_NOKQUEUE echo "KQUEUE" test setup unset EVENT_NODEVPOLL +export EVENT_NODEVPOLL echo "DEVPOLL" test setup unset EVENT_NOPOLL +export EVENT_NOPOLL echo "POLL" test setup unset EVENT_NOSELECT +export EVENT_NOSELECT echo "SELECT" test -setup -unset EVENT_NORTSIG -echo "RTSIG" -test - setup unset EVENT_NOEPOLL +export EVENT_NOEPOLL echo "EPOLL" test +setup +unset EVENT_NOEVPORT +export EVENT_NOEVPORT +echo "EVPORT" +test + diff --git a/opal/mca/paffinity/windows/paffinity_windows_module.c b/opal/mca/paffinity/windows/paffinity_windows_module.c index 949051f961..9a0127885e 100644 --- a/opal/mca/paffinity/windows/paffinity_windows_module.c +++ b/opal/mca/paffinity/windows/paffinity_windows_module.c @@ -134,17 +134,17 @@ static int windows_module_map_to_socket_core(int processor_id, int *socket, int return OPAL_ERR_NOT_SUPPORTED; } -static int windows_module_get_processor_info(int *num_processors, int *max_processor_id); +static int windows_module_get_processor_info(int *num_processors, int *max_processor_id) { return OPAL_ERR_NOT_SUPPORTED; } -static int windows_module_get_socket_info(int *num_sockets, int *max_socket_num); +static int windows_module_get_socket_info(int *num_sockets, int *max_socket_num) { return OPAL_ERR_NOT_SUPPORTED; } -static int windows_module_get_core_info(int socket, int *num_cores, int *max_core_num); +static int windows_module_get_core_info(int socket, int *num_cores, int *max_core_num) { return OPAL_ERR_NOT_SUPPORTED; } diff --git a/orte/orted/orted_main.c b/orte/orted/orted_main.c index f698c45135..2749697eb7 100644 --- a/orte/orted/orted_main.c +++ b/orte/orted/orted_main.c @@ -179,6 +179,7 @@ int orte_daemon(int argc, char *argv[]) char log_file[PATH_MAX]; char *jobidstring; char *rml_uri; + char *tmp1, *tmp2; int i; opal_buffer_t *buffer; char hostname[100]; @@ -263,6 +264,36 @@ int orte_daemon(int argc, char *argv[]) i++; if (1000 < i) i=0; } + + /* _After_ opal_init_util() (and various other bookkeeping) but + _before_ orte_init(), we need to set an MCA param that tells + the orted not to use any other libevent mechanism except + "select" or "poll" (per potential pty issues with scalable + fd-monitoring mechanisms such as epoll() and friends -- these + issues *may* have been fixed in later OS releases and/or newer + versions of libevent, but we weren't willing to do all the + testing to figure it out. So force the orted to use + select()/poll() *only* -- there's so few fd's in the orted that + it really doesn't matter. + + Note that pty's work fine with poll() on most systems, so we + prefer that (because it's more scalable than select()). + However, poll() does *not* work with ptys on OS X, so we use + select() there. */ + mca_base_param_reg_string_name("opal", "event_include", + "Internal orted MCA param: tell opal_init() to use a specific mechanism in libevent", + true, true, +#ifdef __APPLE__ + "select", +#else + "poll", +#endif + NULL); + tmp1 = mca_base_param_environ_variable("opal", NULL, "event_include"); + asprintf(&tmp2, "%s=select", tmp1); + putenv(tmp2); + free(tmp1); + free(tmp2); /* Okay, now on to serious business! */