|
|||||||||||
|
bk commit into 6.0 tree (dkatz:1.2647)
From: <damien(at)mysql.com>
Date: Wed Oct 31 2007 - 14:24:28 EDT
ChangeSet@1.2647, 2007-10-31 14:24:15-04:00, dkatz@damien-katzs-computer.local +41 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. config/ac-macros/libevent.m4@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +304 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. config/ac-macros/libevent.m4@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 configure.in@1.386, 2007-10-31 14:24:04-04:00, dkatz@damien-katzs-computer.local +2 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/Makefile.am@1.47, 2007-10-31 14:24:04-04:00, dkatz@damien-katzs-computer.local +2 -2 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/Makefile.am@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +20 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/Makefile.am@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/README@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +53 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/README@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/buffer.c@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +460 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/buffer.c@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/compat/sys/_time.h@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +163 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/compat/sys/_time.h@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/compat/sys/queue.h@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +488 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/compat/sys/queue.h@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/compat/sys/tree.h@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +677 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/compat/sys/tree.h@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/devpoll.c@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +419 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/devpoll.c@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/epoll.c@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +366 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/epoll.c@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/epoll_sub.c@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +52 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/epoll_sub.c@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/evbuffer.c@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +413 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/evbuffer.c@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/evdns.c@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +3116 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/evdns.c@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/evdns.h@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +367 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/evdns.h@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/event-internal.h@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +61 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/event-internal.h@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/event.c@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +928 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/event.c@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/event.h@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +340 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/event.h@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/event_tagging.c@1.1, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +372 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/event_tagging.c@1.0, 2007-10-31 14:24:06-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/evhttp.h@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +221 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/evhttp.h@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/evport.c@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +531 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/evport.c@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/evsignal.h@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +44 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/evsignal.h@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/http-internal.h@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +122 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/http-internal.h@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/http.c@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +2368 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/http.c@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/kqueue.c@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +419 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/kqueue.c@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/log.c@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +219 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/log.c@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/log.h@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +43 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/log.h@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/poll.c@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +391 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/poll.c@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/select.c@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +373 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/select.c@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/signal.c@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +195 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/signal.c@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/strlcpy-internal.h@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +23 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/strlcpy-internal.h@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 extra/libevent/strlcpy.c@1.1, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +76 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. extra/libevent/strlcpy.c@1.0, 2007-10-31 14:24:07-04:00, dkatz@damien-katzs-computer.local +0 -0 libmysqld/Makefile.am@1.118, 2007-10-31 14:24:04-04:00, dkatz@damien-katzs-computer.local +5 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. mysql-test/r/sp-threads.result@1.10, 2007-10-31 14:24:04-04:00, dkatz@damien-katzs-computer.local +2 -2 Changed code that populates the process table to uniformally output blank status as NULL, instead of sometimes NULL/sometimes emptry string. mysql-test/t/crash_commit_before.test@1.7, 2007-10-31 14:24:04-04:00, dkatz@damien-katzs-computer.local +1 -1 Fix a test case that fails by setting the global debug variable instead of the session debug variable. "SET SESSION debug" sets a value that is actually stored in a OS thread variable, instead of the session (THD) object. The libevent work breaks this because each request is likely handled by a different OS thread. sql/Makefile.am@1.200, 2007-10-31 14:24:05-04:00, dkatz@damien-katzs-computer.local +3 -2 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. sql/mysql_priv.h@1.530, 2007-10-31 14:24:05-04:00, dkatz@damien-katzs-computer.local +1 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. sql/scheduler.cc@1.2, 2007-10-31 14:24:05-04:00, dkatz@damien-katzs-computer.local +514 -3 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. sql/scheduler.h@1.2, 2007-10-31 14:24:05-04:00, dkatz@damien-katzs-computer.local +26 -0 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. sql/sql_connect.cc@1.15, 2007-10-31 14:24:05-04:00, dkatz@damien-katzs-computer.local +1 -1 WL441: Work to integrate libevent and support the --thread_handling=pool-of-threads runtime option. sql/sql_show.cc@1.438, 2007-10-31 14:24:05-04:00, dkatz@damien-katzs-computer.local +2 -2 Changed code that populates the process table to uniformally output blank status as NULL, instead of sometimes NULL/sometimes emptry string. diff -Nrup a/config/ac-macros/libevent.m4 b/config/ac-macros/libevent.m4 --- /dev/null Wed Dec 31 16:00:00 196900@@ -0,0 +1,304 @@ +dnl --------------------------------------------------------------------------- +dnl Macro: MYSQL_USE_BUNDLED_LIBEVENT +dnl +dnl SYNOPSIS +dnl MYSQL_USE_BUNDLED_LIBEVENT() +dnl +dnl DESCRIPTION +dnl Add defines so libevent is built and linked with +dnl --------------------------------------------------------------------------- +AC_DEFUN([MYSQL_USE_BUNDLED_LIBEVENT], [ + + libevent_dir="libevent" + AC_SUBST([libevent_dir]) + + libevent_libs="\$(top_builddir)/extra/libevent/libevent.la" + libevent_includes="-I\$(top_builddir)/extra/libevent" + AC_SUBST(libevent_libs) + AC_SUBST(libevent_includes) + + AC_DEFINE([HAVE_LIBEVENT], [1], [If we want to use libevent and have connection pooling]) + AC_MSG_RESULT([using bundled libevent]) + + dnl Things that libevent needs + AC_CHECK_HEADERS(inttypes.h stdint.h poll.h signal.h sys/epoll.h sys/time.h \ + sys/queue.h sys/event.h sys/devpoll.h netinet/in6.h) + +if test "x$ac_cv_header_sys_queue_h" = "xyes"; then + AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h) + AC_EGREP_CPP(yes, +[ +#include <sys/queue.h> +#ifdef TAILQ_FOREACH + yes +#endif +], [AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_TAILQFOREACH, 1, + [Define if TAILQ_FOREACH is defined in <sys/queue.h>])], + AC_MSG_RESULT(no) + ) +fi + +if test "x$ac_cv_header_sys_time_h" = "xyes"; then + AC_MSG_CHECKING(for timeradd in sys/time.h) + AC_EGREP_CPP(yes, +[ +#include <sys/time.h> +#ifdef timeradd + yes +#endif +], [ AC_DEFINE(HAVE_TIMERADD, 1, + [Define if timeradd is defined in <sys/time.h>]) + AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) +) +fi + +if test "x$ac_cv_header_sys_time_h" = "xyes"; then + AC_MSG_CHECKING(for timercmp in sys/time.h) + AC_EGREP_CPP(yes, +[ +#include <sys/time.h> +#ifdef timercmp + yes +#endif +], [ AC_DEFINE(HAVE_TIMERCMP, 1, + [Define if timercmp is defined in <sys/time.h>]) + AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) +) +fi + +if test "x$ac_cv_header_sys_time_h" = "xyes"; then + AC_MSG_CHECKING(for timerclear in sys/time.h) + AC_EGREP_CPP(yes, +[ +#include <sys/time.h> +#ifdef timerclear + yes +#endif +], [ AC_DEFINE(HAVE_TIMERCLEAR, 1, + [Define if timerclear is defined in <sys/time.h>]) + AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) +) +fi + +if test "x$ac_cv_header_sys_time_h" = "xyes"; then + AC_MSG_CHECKING(for timerisset in sys/time.h) + AC_EGREP_CPP(yes, +[ +#include <sys/time.h> +#ifdef timerisset + yes +#endif +], [ AC_DEFINE(HAVE_TIMERISSET, 1, + [Define if timerisset is defined in <sys/time.h>]) + AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) +) +fi + +dnl Checks for library functions. +AC_CHECK_FUNCS(vasprintf strsep getaddrinfo getnameinfo inet_ntop) + +if test "x$ac_cv_func_clock_gettime" = "xyes"; then + AC_DEFINE(DNS_USE_CPU_CLOCK_FOR_ID, 1, [Define if clock_gettime is available in libc]) +else + AC_DEFINE(DNS_USE_GETTIMEOFDAY_FOR_ID, 1, [Define is no secure id variant is available]) +fi + +AC_MSG_CHECKING(for F_SETFD in fcntl.h) +AC_EGREP_CPP(yes, +[ +#define _GNU_SOURCE +#include <fcntl.h> +#ifdef F_SETFD +yes +#endif +], [ AC_DEFINE(HAVE_SETFD, 1, + [Define if F_SETFD is defined in <fcntl.h>]) + AC_MSG_RESULT(yes) ], AC_MSG_RESULT(no)) + +needsignal=no +if test "x$ac_cv_func_select" = "xyes" ; then + AC_LIBOBJ(select) + needsignal=yes +fi + +if test "x$ac_cv_func_poll" = "xyes" ; then + AC_LIBOBJ(poll) + needsignal=yes +fi + +haveepoll=no +AC_CHECK_FUNCS(epoll_ctl, [haveepoll=yes], ) +if test "x$haveepoll" = "xyes" ; then + AC_DEFINE(HAVE_EPOLL, 1, + [Define if your system supports the epoll system calls]) + AC_LIBOBJ(epoll) + needsignal=yes +fi + +havedevpoll=no +if test "x$ac_cv_header_sys_devpoll_h" = "xyes"; then + AC_DEFINE(HAVE_DEVPOLL, 1, + [Define if /dev/poll is available]) + AC_LIBOBJ(devpoll) +fi + +havekqueue=no +if test "x$ac_cv_header_sys_event_h" = "xyes"; then + AC_CHECK_FUNCS(kqueue, [havekqueue=yes], ) + if test "x$havekqueue" = "xyes" ; then + AC_MSG_CHECKING(for working kqueue) + AC_TRY_RUN( +#include <sys/types.h> +#include <sys/time.h> +#include <sys/event.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> + +int +main(int argc, char **argv) +{ + int kq; + int n; + int fd[[2]]; + struct kevent ev; + struct timespec ts; + char buf[[8000]]; + + if (pipe(fd) == -1) + exit(1); + if (fcntl(fd[[1]], F_SETFL, O_NONBLOCK) == -1) + exit(1); + + while ((n = write(fd[[1]], buf, sizeof(buf))) == sizeof(buf)) + ; + + if ((kq = kqueue()) == -1) + exit(1); + + ev.ident = fd[[1]]; + ev.filter = EVFILT_WRITE; + ev.flags = EV_ADD | EV_ENABLE; + n = kevent(kq, &ev, 1, NULL, 0, NULL); + if (n == -1) + exit(1); + + read(fd[[0]], buf, sizeof(buf)); + + ts.tv_sec = 0; + ts.tv_nsec = 0; + n = kevent(kq, NULL, 0, &ev, 1, &ts); + if (n == -1 || n == 0) + exit(1); + + exit(0); +}, [AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_WORKING_KQUEUE, 1, + [Define if kqueue works correctly with pipes]) + AC_LIBOBJ(kqueue)], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) + fi +fi + +haveepollsyscall=no +if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then + if test "x$haveepoll" = "xno" ; then + AC_MSG_CHECKING(for epoll system call) + AC_TRY_RUN( +#include <stdint.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/syscall.h> +#include <sys/epoll.h> +#include <unistd.h> + +int +epoll_create(int size) +{ + return (syscall(__NR_epoll_create, size)); +} + +int +main(int argc, char **argv) +{ + int epfd; + + epfd = epoll_create(256); + exit (epfd == -1 ? 1 : 0); +}, [AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_EPOLL, 1, + [Define if your system supports the epoll system calls]) + needsignal=yes + AC_LIBOBJ(epoll_sub) + AC_LIBOBJ(epoll)], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) + 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]) + AC_LIBOBJ(evport) + needsignal=yes +fi +if test "x$needsignal" = "xyes" ; then + AC_LIBOBJ(signal) +fi + +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_CHECK_TYPE(uint64_t, unsigned long long) +AC_CHECK_TYPE(uint32_t, unsigned int) +AC_CHECK_TYPE(uint16_t, unsigned short) +AC_CHECK_TYPE(uint8_t, unsigned char) +AC_CHECK_TYPES([struct in6_addr], , , +[#ifdef WIN32 +#include <winsock2.h> +#else +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> +#endif +#ifdef HAVE_NETINET_IN6_H +#include <netinet/in6.h> +#endif]) + +AC_MSG_CHECKING([for socklen_t]) +AC_TRY_COMPILE([ + #include <sys/types.h> + #include <sys/socket.h>], + [socklen_t x;], + AC_MSG_RESULT([yes]), + [AC_MSG_RESULT([no]) + AC_DEFINE(socklen_t, unsigned int, + [Define to unsigned int if you dont have it])] +) + +]) + + +dnl ------------------------------------------------------------------------ +dnl Macro: MYSQL_CHECK_LIBEVENT +dnl +dnl SYNOPSIS +dnl MYSQL_CHECK_LIBEVENT +dnl +dnl ------------------------------------------------------------------------ +AC_DEFUN([MYSQL_CHECK_LIBEVENT], [ + + AC_CONFIG_FILES(extra/libevent/Makefile) + + AC_MSG_CHECKING(for libevent) + AC_ARG_WITH([libevent], + [ --with-libevent use libevent and have connection pooling], + [with_libevent=$withval], + [with_libevent=no] + ) + + if test "$with_libevent" != "no" + then + MYSQL_USE_BUNDLED_LIBEVENT + fi + AM_CONDITIONAL([HAVE_LIBEVENT], [ test "$with_libevent" != "no" ]) +]) diff -Nrup a/configure.in b/configure.in --- a/configure.in 2007-10-19 16:19:57 -04:00@@ -49,6 +49,7 @@ sinclude(config/ac-macros/large_file.m4) sinclude(config/ac-macros/misc.m4) sinclude(config/ac-macros/readline.m4) sinclude(config/ac-macros/ssl.m4) +sinclude(config/ac-macros/libevent.m4) sinclude(config/ac-macros/zlib.m4) # Remember to add a directory sql/share/LANGUAGE @@ -2275,6 +2276,7 @@ MYSQL_CHECK_BIG_TABLES MYSQL_CHECK_MAX_INDEXES MYSQL_CHECK_VIO MYSQL_CHECK_SSL +MYSQL_CHECK_LIBEVENT #--------------------------------------------------------------------# Declare our plugin modules diff -Nrup a/extra/Makefile.am b/extra/Makefile.am --- a/extra/Makefile.am 2007-08-30 19:23:48 -04:00 # This will build mysqld_error.h, mysqld_ername.h and sql_state.h # NOTE Built files should depend on their sources to avoid diff -Nrup a/extra/libevent/Makefile.am b/extra/libevent/Makefile.am --- /dev/null Wed Dec 31 16:00:00 196900@@ -0,0 +1,20 @@ +AUTOMAKE_OPTIONS = foreign no-dependencies + +EXTRA_DIST = select.c poll.c epoll.c epoll_sub.c devpoll.c kqueue.c \ + evport.c evsignal.h signal.c event-internal.h README compat/sys + +lib_LTLIBRARIES = libevent.la + +SYS_LIBS = +SYS_SRC = +SYS_INCLUDES = + +libevent_la_SOURCES = event.c buffer.c evbuffer.c log.c event_tagging.c \ + http.c evhttp.h http-internal.h evdns.c evdns.h strlcpy.c \ + strlcpy-internal.h strlcpy-internal.h +libevent_la_LIBADD = @LTLIBOBJS@ +libevent_la_LDFLAGS = -release 1.3e -version-info 1:3:0 + +include_HEADERS = event.h evhttp.h evdns.h log.h + +INCLUDES = -Icompat -I$(top_srcdir)/include diff -Nrup a/extra/libevent/README b/extra/libevent/README --- /dev/null Wed Dec 31 16:00:00 196900@@ -0,0 +1,53 @@ +To build libevent, type + +$ ./configure && make + +Install as root via + +# make install + +You can run the regression tests by + +$ 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: + + 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 -Nrup a/extra/libevent/buffer.c b/extra/libevent/buffer.c --- /dev/null Wed Dec 31 16:00:00 196900@@ -0,0 +1,460 @@ +/* + * Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu> + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_VASPRINTF +/* If we have vasprintf, we need to define this before we include stdio.h. */ +#define _GNU_SOURCE +#endif + +#include <sys/types.h> + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_STDARG_H +#include <stdarg.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "event.h" + +struct evbuffer * +evbuffer_new(void) +{ + struct evbuffer *buffer; + + buffer = calloc(1, sizeof(struct evbuffer)); + + return (buffer); +} + +void +evbuffer_free(struct evbuffer *buffer) +{ + if (buffer->orig_buffer != NULL) + free(buffer->orig_buffer); + free(buffer); +} + +/* + * This is a destructive add. The data from one buffer moves into + * the other buffer. + */ + +#define SWAP(x,y) do { \ + (x)->buffer = (y)->buffer; \ + (x)->orig_buffer = (y)->orig_buffer; \ + (x)->misalign = (y)->misalign; \ + (x)->totallen = (y)->totallen; \ + (x)->off = (y)->off; \ +} while (0) + +int +evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf) +{ + int res; + + /* Short cut for better performance */ + if (outbuf->off == 0) { + struct evbuffer tmp; + size_t oldoff = inbuf->off; + + /* Swap them directly */ + SWAP(&tmp, outbuf); + SWAP(outbuf, inbuf); + SWAP(inbuf, &tmp); + + /* + * Optimization comes with a price; we need to notify the + * buffer if necessary of the changes. oldoff is the amount + * of data that we transfered from inbuf to outbuf + */ + if (inbuf->off != oldoff && inbuf->cb != NULL) + (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg); + if (oldoff && outbuf->cb != NULL) + (*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg); + + return (0); + } + + res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off); + if (res == 0) { + /* We drain the input buffer on success */ + evbuffer_drain(inbuf, inbuf->off); + } + + return (res); +} + +int +evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap) +{ + char *buffer; + 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 (;;) { + 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, aq); + buffer[space - 1] = '\0'; +#else + sz = vsnprintf(buffer, space, fmt, aq); +#endif + + va_end(aq); + + if (sz < 0) + return (-1); + if (sz < space) { + buf->off += sz; + if (buf->cb != NULL) + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); + return (sz); + } + if (evbuffer_expand(buf, sz + 1) == -1) + return (-1); + + } + /* NOTREACHED */ +} + +int +evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...) +{ + int res = -1; + va_list ap; + + va_start(ap, fmt); + res = evbuffer_add_vprintf(buf, fmt, ap); + va_end(ap); + + return (res); +} + +/* Reads data from an event buffer and drains the bytes read */ + +int +evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen) +{ + size_t nread = datlen; + if (nread >= buf->off) + nread = buf->off; + + memcpy(data, buf->buffer, nread); + evbuffer_drain(buf, nread); + + return (nread); +} + +/* + * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'. + * The returned buffer needs to be freed by the called. + */ + +char * +evbuffer_readline(struct evbuffer *buffer) +{ + u_char *data = EVBUFFER_DATA(buffer); + size_t len = EVBUFFER_LENGTH(buffer); + char *line; + unsigned int i; + + for (i = 0; i < len; i++) { + if (data[i] == '\r' || data[i] == '\n') + break; + } + + if (i == len) + return (NULL); + + if ((line = malloc(i + 1)) == NULL) { + fprintf(stderr, "%s: out of memory\n", __func__); + evbuffer_drain(buffer, i); + return (NULL); + } + + memcpy(line, data, i); + line[i] = '\0'; + + /* + * Some protocols terminate a line with '\r\n', so check for + * that, too. + */ + if ( i < len - 1 ) { + char fch = data[i], sch = data[i+1]; + + /* Drain one more character if needed */ + if ( (sch == '\r' || sch == '\n') && sch != fch ) + i += 1; + } + + evbuffer_drain(buffer, i + 1); + + return (line); +} + +/* Adds data to an event buffer */ + +static void +evbuffer_align(struct evbuffer *buf) +{ + memmove(buf->orig_buffer, buf->buffer, buf->off); + buf->buffer = buf->orig_buffer; + buf->misalign = 0; +} + +/* Expands the available space in the event buffer to at least datlen */ + +int +evbuffer_expand(struct evbuffer *buf, size_t datlen) +{ + size_t need = buf->misalign + buf->off + datlen; + + /* If we can fit all the data, then we don't have to do anything */ + if (buf->totallen >= need) + return (0); + + /* + * If the misalignment fulfills our data needs, we just force an + * alignment to happen. Afterwards, we have enough space. + */ + if (buf->misalign >= datlen) { + evbuffer_align(buf); + } else { + void *newbuf; + size_t length = buf->totallen; + + if (length < 256) + length = 256; + while (length < need) + length <<= 1; + + if (buf->orig_buffer != buf->buffer) + evbuffer_align(buf); + if ((newbuf = realloc(buf->buffer, length)) == NULL) + return (-1); + + buf->orig_buffer = buf->buffer = newbuf; + buf->totallen = length; + } + + return (0); +} + +int +evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen) +{ + size_t need = buf->misalign + buf->off + datlen; + size_t oldoff = buf->off; + + if (buf->totallen < need) { + if (evbuffer_expand(buf, datlen) == -1) + return (-1); + } + + memcpy(buf->buffer + buf->off, data, datlen); + buf->off += datlen; + + if (datlen && buf->cb != NULL) + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); + + return (0); +} + +void +evbuffer_drain(struct evbuffer *buf, size_t len) +{ + size_t oldoff = buf->off; + + if (len >= buf->off) { + buf->off = 0; + buf->buffer = buf->orig_buffer; + buf->misalign = 0; + goto done; + } + + buf->buffer += len; + buf->misalign += len; + + buf->off -= len; + + done: + /* Tell someone about changes in this buffer */ + if (buf->off != oldoff && buf->cb != NULL) + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); + +} + +/* + * Reads data from a file descriptor into a buffer. + */ + +#define EVBUFFER_MAX_READ 4096 + +int +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 (ioctl(fd, FIONREAD, &n) == -1 || n == 0) { + n = EVBUFFER_MAX_READ; + } else if (n > EVBUFFER_MAX_READ && n > howmuch) { + /* + * It's possible that a lot of data is available for + * reading. We do not want to exhaust resources + * before the reader has a chance to do something + * about it. If the reader does not tell us how much + * data we should read, we artifically limit it. + */ + if (n > buf->totallen << 2) + n = buf->totallen << 2; + if (n < EVBUFFER_MAX_READ) + n = EVBUFFER_MAX_READ; + } +#endif + if (howmuch < 0 || howmuch > n) + howmuch = n; + + /* If we don't have FIONREAD, we might waste some space here */ + if (evbuffer_expand(buf, howmuch) == -1) + return (-1); + + /* We can append new data at this point */ + p = buf->buffer + buf->off; + +#ifndef WIN32 + n = read(fd, p, howmuch); + 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; + + /* Tell someone about changes in this buffer */ + if (buf->off != oldoff && buf->cb != NULL) + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); + + return (n); +} + +int +evbuffer_write(struct evbuffer *buffer, int fd) +{ + int n; +#ifdef WIN32 + DWORD dwBytesWritten; +#endif + +#ifndef WIN32 + n = write(fd, buffer->buffer, buffer->off); + 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); +} + +u_char * +evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len) +{ + u_char *search = buffer->buffer, *end = search + buffer->off; + u_char *p; + + 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; + } + + return (NULL); +} + +void evbuffer_setcb(struct evbuffer *buffer, + void (*cb)(struct evbuffer *, size_t, size_t, void *), + void *cbarg) +{ + buffer->cb = cb; + buffer->cbarg = cbarg; +} diff -Nrup a/extra/libevent/compat/sys/_time.h b/extra/libevent/compat/sys/_time.h --- /dev/null Wed Dec 31 16:00:00 196900+ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)time.h 8.2 (Berkeley) 7/10/94 + */ + +#ifndef _SYS_TIME_H_ +#define _SYS_TIME_H_ + +#include <sys/types.h> + +/* + * Structure returned by gettimeofday(2) system call, + * and used in other calls. + */ +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; + +/* + * Structure defined by POSIX.1b to be like a timeval. + */ +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* and nanoseconds */ +}; + +#define TIMEVAL_TO_TIMESPEC(tv, ts) { \ + (ts)->tv_sec = (tv)->tv_sec; \ + (ts)->tv_nsec = (tv)->tv_usec * 1000; \ +} +#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ + (tv)->tv_sec = (ts)->tv_sec; \ + (tv)->tv_usec = (ts)->tv_nsec / 1000; \ +} + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; +#define DST_NONE 0 /* not on dst */ +#define DST_USA 1 /* USA style dst */ +#define DST_AUST 2 /* Australian style dst */ +#define DST_WET 3 /* Western European dst */ +#define DST_MET 4 /* Middle European dst */ +#define DST_EET 5 /* Eastern European dst */ +#define DST_CAN 6 /* Canada */ + +/* Operations on timevals. */ +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#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)) +#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 +#define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec) +#define timespeccmp(tsp, usp, cmp) \ + (((tsp)->tv_sec == (usp)->tv_sec) ? \ + ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \ + ((tsp)->tv_sec cmp (usp)->tv_sec)) +#define timespecadd(tsp, usp, vsp) \ + do { \ + (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \ + (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \ + if ((vsp)->tv_nsec >= 1000000000L) { \ + (vsp)->tv_sec++; \ + (vsp)->tv_nsec -= 1000000000L; \ + } \ + } while (0) +#define timespecsub(tsp, usp, vsp) \ + do { \ + (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ + (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ + if ((vsp)->tv_nsec < 0) { \ + (vsp)->tv_sec--; \ + (vsp)->tv_nsec += 1000000000L; \ + } \ + } while (0) + +/* + * Names of the interval timers, and structure + * defining a timer setting. + */ +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +struct itimerval { + struct timeval it_interval; /* timer interval */ + struct timeval it_value; /* current value */ +}; + +/* + * Getkerninfo clock information structure + */ +struct clockinfo { + int hz; /* clock frequency */ + int tick; /* micro-seconds per hz tick */ + int tickadj; /* clock skew rate for adjtime() */ + int stathz; /* statistics clock frequency */ + int profhz; /* profiling clock frequency */ +}; + +#define CLOCK_REALTIME 0 +#define CLOCK_VIRTUAL 1 +#define CLOCK_PROF 2 + +#define TIMER_RELTIME 0x0 /* relative timer */ +#define TIMER_ABSTIME 0x1 /* absolute timer */ + +/* --- stuff got cut here - niels --- */ + +#endif /* !_SYS_TIME_H_ */ diff -Nrup a/extra/libevent/compat/sys/queue.h b/extra/libevent/compat/sys/queue.h --- /dev/null Wed Dec 31 16:00:00 196900+ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#ifndef WIN32 +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} +#endif + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \ + if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_REVERSE(var, head, field, headname) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#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) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(hea | ||||||||||