mirror of https://github.com/lukechilds/node.git
Ryan
16 years ago
45 changed files with 28836 additions and 0 deletions
@ -0,0 +1,11 @@ |
|||||
|
Revision history for libeio |
||||
|
|
||||
|
TODO: maybe add mincore support? available on at leats darwin, solaris, linux, freebsd |
||||
|
|
||||
|
1.0 |
||||
|
- added msync, mtouch support (untested). |
||||
|
- added sync_file_range (untested). |
||||
|
- fixed custom support. |
||||
|
- use a more robust feed-add detection method. |
||||
|
- "outbundled" from IO::AIO. |
||||
|
|
@ -0,0 +1,36 @@ |
|||||
|
All files in libeio are Copyright (C)2007,2008 Marc Alexander Lehmann. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are |
||||
|
met: |
||||
|
|
||||
|
* Redistributions of source code must retain the above copyright |
||||
|
notice, this list of conditions and the following disclaimer. |
||||
|
|
||||
|
* 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 COPYRIGHT HOLDERS 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 COPYRIGHT |
||||
|
OWNER 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. |
||||
|
|
||||
|
Alternatively, the contents of this package may be used under the terms |
||||
|
of the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
in which case the provisions of the GPL are applicable instead of the |
||||
|
above. If you wish to allow the use of your version of this package only |
||||
|
under the terms of the GPL and not to allow others to use your version of |
||||
|
this file under the BSD license, indicate your decision by deleting the |
||||
|
provisions above and replace them with the notice and other provisions |
||||
|
required by the GPL in this and the other files of this package. If you do |
||||
|
not delete the provisions above, a recipient may use your version of this |
||||
|
file under either the BSD or the GPL. |
@ -0,0 +1,15 @@ |
|||||
|
AUTOMAKE_OPTIONS = foreign no-dependencies |
||||
|
|
||||
|
VERSION_INFO = 1:0 |
||||
|
|
||||
|
EXTRA_DIST = LICENSE Changes autogen.sh |
||||
|
|
||||
|
#man_MANS = ev.3
|
||||
|
|
||||
|
include_HEADERS = eio.h |
||||
|
|
||||
|
lib_LTLIBRARIES = libeio.la |
||||
|
|
||||
|
libeio_la_SOURCES = eio.c xthread.h config.h |
||||
|
libeio_la_LDFLAGS = -version-info $(VERSION_INFO) |
||||
|
|
File diff suppressed because it is too large
@ -0,0 +1,5 @@ |
|||||
|
libtoolize |
||||
|
aclocal |
||||
|
automake --add-missing |
||||
|
autoconf |
||||
|
autoheader |
@ -0,0 +1,73 @@ |
|||||
|
/* config.h.in. Generated from configure.ac by autoheader. */ |
||||
|
|
||||
|
/* Define to 1 if you have the <dlfcn.h> header file. */ |
||||
|
#undef HAVE_DLFCN_H |
||||
|
|
||||
|
/* fdatasync(2) is available */ |
||||
|
#undef HAVE_FDATASYNC |
||||
|
|
||||
|
/* futimes(2) is available */ |
||||
|
#undef HAVE_FUTIMES |
||||
|
|
||||
|
/* Define to 1 if you have the <inttypes.h> header file. */ |
||||
|
#undef HAVE_INTTYPES_H |
||||
|
|
||||
|
/* Define to 1 if you have the <memory.h> header file. */ |
||||
|
#undef HAVE_MEMORY_H |
||||
|
|
||||
|
/* pread(2) and pwrite(2) are available */ |
||||
|
#undef HAVE_PREADWRITE |
||||
|
|
||||
|
/* readahead(2) is available (linux) */ |
||||
|
#undef HAVE_READAHEAD |
||||
|
|
||||
|
/* sendfile(2) is available and supported */ |
||||
|
#undef HAVE_SENDFILE |
||||
|
|
||||
|
/* Define to 1 if you have the <stdint.h> header file. */ |
||||
|
#undef HAVE_STDINT_H |
||||
|
|
||||
|
/* Define to 1 if you have the <stdlib.h> header file. */ |
||||
|
#undef HAVE_STDLIB_H |
||||
|
|
||||
|
/* Define to 1 if you have the <strings.h> header file. */ |
||||
|
#undef HAVE_STRINGS_H |
||||
|
|
||||
|
/* Define to 1 if you have the <string.h> header file. */ |
||||
|
#undef HAVE_STRING_H |
||||
|
|
||||
|
/* sync_file_range(2) is available */ |
||||
|
#undef HAVE_SYNC_FILE_RANGE |
||||
|
|
||||
|
/* Define to 1 if you have the <sys/stat.h> header file. */ |
||||
|
#undef HAVE_SYS_STAT_H |
||||
|
|
||||
|
/* Define to 1 if you have the <sys/types.h> header file. */ |
||||
|
#undef HAVE_SYS_TYPES_H |
||||
|
|
||||
|
/* Define to 1 if you have the <unistd.h> header file. */ |
||||
|
#undef HAVE_UNISTD_H |
||||
|
|
||||
|
/* Name of package */ |
||||
|
#undef PACKAGE |
||||
|
|
||||
|
/* Define to the address where bug reports for this package should be sent. */ |
||||
|
#undef PACKAGE_BUGREPORT |
||||
|
|
||||
|
/* Define to the full name of this package. */ |
||||
|
#undef PACKAGE_NAME |
||||
|
|
||||
|
/* Define to the full name and version of this package. */ |
||||
|
#undef PACKAGE_STRING |
||||
|
|
||||
|
/* Define to the one symbol short name of this package. */ |
||||
|
#undef PACKAGE_TARNAME |
||||
|
|
||||
|
/* Define to the version of this package. */ |
||||
|
#undef PACKAGE_VERSION |
||||
|
|
||||
|
/* Define to 1 if you have the ANSI C header files. */ |
||||
|
#undef STDC_HEADERS |
||||
|
|
||||
|
/* Version number of package */ |
||||
|
#undef VERSION |
@ -0,0 +1,22 @@ |
|||||
|
AC_PREREQ(2.59) |
||||
|
AC_INIT |
||||
|
AC_CONFIG_SRCDIR([eio.h]) |
||||
|
AC_CONFIG_HEADERS([config.h]) |
||||
|
|
||||
|
AM_INIT_AUTOMAKE(libeio,1.0) |
||||
|
AM_MAINTAINER_MODE |
||||
|
AC_PROG_LIBTOOL |
||||
|
|
||||
|
AC_PROG_CC |
||||
|
|
||||
|
if test "x$GCC" = xyes ; then |
||||
|
CFLAGS="$CFLAGS -O3" |
||||
|
fi |
||||
|
|
||||
|
dnl somebody will forgive me |
||||
|
CFLAGS="-D_GNU_SOURCE" |
||||
|
|
||||
|
m4_include([libeio.m4]) |
||||
|
|
||||
|
AC_CONFIG_FILES([Makefile]) |
||||
|
AC_OUTPUT |
@ -0,0 +1,194 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <unistd.h> |
||||
|
#include <poll.h> |
||||
|
#include <string.h> |
||||
|
#include <assert.h> |
||||
|
#include <fcntl.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/stat.h> |
||||
|
|
||||
|
#include "eio.h" |
||||
|
|
||||
|
int respipe [2]; |
||||
|
|
||||
|
void |
||||
|
want_poll (void) |
||||
|
{ |
||||
|
char dummy; |
||||
|
printf ("want_poll ()\n"); |
||||
|
write (respipe [1], &dummy, 1); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
done_poll (void) |
||||
|
{ |
||||
|
char dummy; |
||||
|
printf ("done_poll ()\n"); |
||||
|
read (respipe [0], &dummy, 1); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
event_loop (void) |
||||
|
{ |
||||
|
// an event loop. yeah.
|
||||
|
struct pollfd pfd; |
||||
|
pfd.fd = respipe [0]; |
||||
|
pfd.events = POLLIN; |
||||
|
|
||||
|
printf ("\nentering event loop\n"); |
||||
|
while (eio_nreqs ()) |
||||
|
{ |
||||
|
poll (&pfd, 1, -1); |
||||
|
printf ("eio_poll () = %d\n", eio_poll ()); |
||||
|
} |
||||
|
printf ("leaving event loop\n"); |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
res_cb (eio_req *req) |
||||
|
{ |
||||
|
printf ("res_cb(%d|%s) = %d\n", req->type, req->data ? req->data : "?", EIO_RESULT (req)); |
||||
|
|
||||
|
if (req->result < 0) |
||||
|
abort (); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
readdir_cb (eio_req *req) |
||||
|
{ |
||||
|
char *buf = (char *)EIO_BUF (req); |
||||
|
|
||||
|
printf ("readdir_cb = %d\n", EIO_RESULT (req)); |
||||
|
|
||||
|
if (EIO_RESULT (req) < 0) |
||||
|
return 0; |
||||
|
|
||||
|
while (EIO_RESULT (req)--) |
||||
|
{ |
||||
|
printf ("readdir = <%s>\n", buf); |
||||
|
buf += strlen (buf) + 1; |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
stat_cb (eio_req *req) |
||||
|
{ |
||||
|
struct stat *buf = EIO_STAT_BUF (req); |
||||
|
|
||||
|
if (req->type == EIO_FSTAT) |
||||
|
printf ("fstat_cb = %d\n", EIO_RESULT (req)); |
||||
|
else |
||||
|
printf ("stat_cb(%s) = %d\n", EIO_PATH (req), EIO_RESULT (req)); |
||||
|
|
||||
|
if (!EIO_RESULT (req)) |
||||
|
printf ("stat size %d perm 0%o\n", buf->st_size, buf->st_mode & 0777); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
read_cb (eio_req *req) |
||||
|
{ |
||||
|
unsigned char *buf = (unsigned char *)EIO_BUF (req); |
||||
|
|
||||
|
printf ("read_cb = %d (%02x%02x%02x%02x %02x%02x%02x%02x)\n", |
||||
|
EIO_RESULT (req), |
||||
|
buf [0], buf [1], buf [2], buf [3], |
||||
|
buf [4], buf [5], buf [6], buf [7]); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int last_fd; |
||||
|
|
||||
|
int |
||||
|
open_cb (eio_req *req) |
||||
|
{ |
||||
|
printf ("open_cb = %d\n", EIO_RESULT (req)); |
||||
|
|
||||
|
last_fd = EIO_RESULT (req); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
main (void) |
||||
|
{ |
||||
|
printf ("pipe ()\n"); |
||||
|
if (pipe (respipe)) abort (); |
||||
|
|
||||
|
printf ("eio_init ()\n"); |
||||
|
if (eio_init (want_poll, done_poll)) abort (); |
||||
|
|
||||
|
do |
||||
|
{ |
||||
|
/* avoid relative paths yourself(!) */ |
||||
|
eio_mkdir ("eio-test-dir", 0777, 0, res_cb, "mkdir"); |
||||
|
eio_nop (0, res_cb, "nop"); |
||||
|
event_loop (); |
||||
|
|
||||
|
eio_stat ("eio-test-dir", 0, stat_cb, "stat"); |
||||
|
eio_lstat ("eio-test-dir", 0, stat_cb, "stat"); |
||||
|
eio_open ("eio-test-dir/eio-test-file", O_RDWR | O_CREAT, 0777, 0, open_cb, "open"); |
||||
|
eio_symlink ("test", "eio-test-dir/eio-symlink", 0, res_cb, "symlink"); |
||||
|
eio_mknod ("eio-test-dir/eio-fifo", S_IFIFO, 0, 0, res_cb, "mknod"); |
||||
|
event_loop (); |
||||
|
|
||||
|
eio_utime ("eio-test-dir", 12345.678, 23456.789, 0, res_cb, "utime"); |
||||
|
eio_futime (last_fd, 92345.678, 93456.789, 0, res_cb, "futime"); |
||||
|
eio_chown ("eio-test-dir", getuid (), getgid (), 0, res_cb, "chown"); |
||||
|
eio_fchown (last_fd, getuid (), getgid (), 0, res_cb, "fchown"); |
||||
|
eio_fchmod (last_fd, 0123, 0, res_cb, "fchmod"); |
||||
|
eio_readdir ("eio-test-dir", 0, readdir_cb, "readdir"); |
||||
|
eio_readdir ("/nonexistant", 0, readdir_cb, "readdir"); |
||||
|
eio_fstat (last_fd, 0, stat_cb, "stat"); |
||||
|
eio_write (last_fd, "test\nfail\n", 10, 4, 0, res_cb, "write"); |
||||
|
event_loop (); |
||||
|
|
||||
|
eio_read (last_fd, 0, 8, 0, EIO_PRI_DEFAULT, read_cb, "read"); |
||||
|
eio_readlink ("eio-test-dir/eio-symlink", 0, res_cb, "readlink"); |
||||
|
event_loop (); |
||||
|
|
||||
|
eio_dup2 (1, 2, EIO_PRI_DEFAULT, res_cb, "dup"); // dup stdout to stderr
|
||||
|
eio_chmod ("eio-test-dir", 0765, 0, res_cb, "chmod"); |
||||
|
eio_ftruncate (last_fd, 9, 0, res_cb, "ftruncate"); |
||||
|
eio_fdatasync (last_fd, 0, res_cb, "fdatasync"); |
||||
|
eio_fsync (last_fd, 0, res_cb, "fsync"); |
||||
|
eio_sync (0, res_cb, "sync"); |
||||
|
eio_busy (0.5, 0, res_cb, "busy"); |
||||
|
event_loop (); |
||||
|
|
||||
|
eio_sendfile (1, last_fd, 4, 5, 0, res_cb, "sendfile"); // write "test\n" to stdout
|
||||
|
eio_fstat (last_fd, 0, stat_cb, "stat"); |
||||
|
event_loop (); |
||||
|
|
||||
|
eio_truncate ("eio-test-dir/eio-test-file", 6, 0, res_cb, "truncate"); |
||||
|
eio_readahead (last_fd, 0, 64, 0, res_cb, "readahead"); |
||||
|
event_loop (); |
||||
|
|
||||
|
eio_close (last_fd, 0, res_cb, "close"); |
||||
|
eio_link ("eio-test-dir/eio-test-file", "eio-test-dir/eio-test-file-2", 0, res_cb, "link"); |
||||
|
event_loop (); |
||||
|
|
||||
|
eio_rename ("eio-test-dir/eio-test-file", "eio-test-dir/eio-test-file-renamed", 0, res_cb, "rename"); |
||||
|
event_loop (); |
||||
|
|
||||
|
eio_unlink ("eio-test-dir/eio-fifo", 0, res_cb, "unlink"); |
||||
|
eio_unlink ("eio-test-dir/eio-symlink", 0, res_cb, "unlink"); |
||||
|
eio_unlink ("eio-test-dir/eio-test-file-2", 0, res_cb, "unlink"); |
||||
|
eio_unlink ("eio-test-dir/eio-test-file-renamed", 0, res_cb, "unlink"); |
||||
|
event_loop (); |
||||
|
|
||||
|
eio_rmdir ("eio-test-dir", 0, res_cb, "rmdir"); |
||||
|
event_loop (); |
||||
|
} |
||||
|
while (0); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,246 @@ |
|||||
|
/*
|
||||
|
* libeio API header |
||||
|
* |
||||
|
* Copyright (c) 2007,2008 Marc Alexander Lehmann <libeio@schmorp.de> |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without modifica- |
||||
|
* tion, 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 MER- |
||||
|
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- |
||||
|
* CIAL, 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 OTH- |
||||
|
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
* |
||||
|
* Alternatively, the contents of this file may be used under the terms of |
||||
|
* the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
* in which case the provisions of the GPL are applicable instead of |
||||
|
* the above. If you wish to allow the use of your version of this file |
||||
|
* only under the terms of the GPL and not to allow others to use your |
||||
|
* version of this file under the BSD license, indicate your decision |
||||
|
* by deleting the provisions above and replace them with the notice |
||||
|
* and other provisions required by the GPL. If you do not delete the |
||||
|
* provisions above, a recipient may use your version of this file under |
||||
|
* either the BSD or the GPL. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef EIO_H_ |
||||
|
#define EIO_H_ |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#include <stddef.h> |
||||
|
#include <sys/types.h> |
||||
|
|
||||
|
typedef struct eio_req eio_req; |
||||
|
|
||||
|
typedef int (*eio_cb)(eio_req *req); |
||||
|
|
||||
|
#ifndef EIO_REQ_MEMBERS |
||||
|
# define EIO_REQ_MEMBERS |
||||
|
#endif |
||||
|
|
||||
|
#ifndef EIO_STRUCT_STAT |
||||
|
# define EIO_STRUCT_STAT struct stat |
||||
|
#endif |
||||
|
|
||||
|
enum { |
||||
|
EIO_CUSTOM, |
||||
|
EIO_OPEN, EIO_CLOSE, EIO_DUP2, |
||||
|
EIO_READ, EIO_WRITE, |
||||
|
EIO_READAHEAD, EIO_SENDFILE, |
||||
|
EIO_STAT, EIO_LSTAT, EIO_FSTAT, |
||||
|
EIO_TRUNCATE, EIO_FTRUNCATE, |
||||
|
EIO_UTIME, EIO_FUTIME, |
||||
|
EIO_CHMOD, EIO_FCHMOD, |
||||
|
EIO_CHOWN, EIO_FCHOWN, |
||||
|
EIO_SYNC, EIO_FSYNC, EIO_FDATASYNC, |
||||
|
EIO_MSYNC, EIO_MTOUCH, EIO_SYNC_FILE_RANGE, |
||||
|
EIO_UNLINK, EIO_RMDIR, EIO_MKDIR, EIO_RENAME, |
||||
|
EIO_MKNOD, EIO_READDIR, |
||||
|
EIO_LINK, EIO_SYMLINK, EIO_READLINK, |
||||
|
EIO_GROUP, EIO_NOP, |
||||
|
EIO_BUSY |
||||
|
}; |
||||
|
|
||||
|
/* eio_sync_file_range flags */ |
||||
|
|
||||
|
enum { |
||||
|
EIO_SYNC_FILE_RANGE_WAIT_BEFORE = 1, |
||||
|
EIO_SYNC_FILE_RANGE_WRITE = 2, |
||||
|
EIO_SYNC_FILE_RANGE_WAIT_AFTER = 4 |
||||
|
}; |
||||
|
|
||||
|
typedef double eio_tstamp; /* feel free to use double in your code directly */ |
||||
|
|
||||
|
/* eio request structure */ |
||||
|
/* this structure is mostly read-only */ |
||||
|
struct eio_req |
||||
|
{ |
||||
|
eio_req volatile *next; /* private ETP */ |
||||
|
|
||||
|
ssize_t result; /* result of syscall, e.g. result = read (... */ |
||||
|
off_t offs; /* read, write, truncate, readahead, sync_file_range: file offset */ |
||||
|
size_t size; /* read, write, readahead, sendfile, msync, sync_file_range: length */ |
||||
|
void *ptr1; /* all applicable requests: pathname, old name */ |
||||
|
void *ptr2; /* all applicable requests: new name or memory buffer */ |
||||
|
eio_tstamp nv1; /* utime, futime: atime; busy: sleep time */ |
||||
|
eio_tstamp nv2; /* utime, futime: mtime */ |
||||
|
|
||||
|
int type; /* EIO_xxx constant ETP */ |
||||
|
int int1; /* all applicable requests: file descriptor; sendfile: output fd; open, msync: flags */ |
||||
|
long int2; /* chown, fchown: uid; sendfile: input fd; open, chmod, mkdir, mknod: file mode, sync_file_range: flags */ |
||||
|
long int3; /* chown, fchown: gid; mknod: dev_t */ |
||||
|
int errorno; /* errno value on syscall return */ |
||||
|
|
||||
|
unsigned char flags; /* private */ |
||||
|
signed char pri; /* the priority */ |
||||
|
|
||||
|
void *data; |
||||
|
eio_cb finish; |
||||
|
void (*destroy)(eio_req *req); /* called when requets no longer needed */ |
||||
|
void (*feed)(eio_req *req); /* only used for group requests */ |
||||
|
|
||||
|
EIO_REQ_MEMBERS |
||||
|
|
||||
|
eio_req *grp, *grp_prev, *grp_next, *grp_first; /* private */ |
||||
|
}; |
||||
|
|
||||
|
/* _private_ flags */ |
||||
|
enum { |
||||
|
EIO_FLAG_CANCELLED = 0x01, /* request was cancelled */ |
||||
|
EIO_FLAG_PTR1_FREE = 0x02, /* need to free(ptr1) */ |
||||
|
EIO_FLAG_PTR2_FREE = 0x04, /* need to free(ptr2) */ |
||||
|
EIO_FLAG_GROUPADD = 0x08 /* some request was added to the group */ |
||||
|
}; |
||||
|
|
||||
|
enum { |
||||
|
EIO_PRI_MIN = -4, |
||||
|
EIO_PRI_MAX = 4, |
||||
|
EIO_PRI_DEFAULT = 0, |
||||
|
}; |
||||
|
|
||||
|
/* returns < 0 on error, errno set
|
||||
|
* need_poll, if non-zero, will be called when results are available |
||||
|
* and eio_poll_cb needs to be invoked (it MUST NOT call eio_poll_cb itself). |
||||
|
* done_poll is called when the need to poll is gone. |
||||
|
*/ |
||||
|
int eio_init (void (*want_poll)(void), void (*done_poll)(void)); |
||||
|
|
||||
|
/* must be called regularly to handle pending requests */ |
||||
|
/* returns 0 if all requests were handled, -1 if not, or the value of EIO_FINISH if != 0 */ |
||||
|
int eio_poll (void); |
||||
|
|
||||
|
/* stop polling if poll took longer than duration seconds */ |
||||
|
void eio_set_max_poll_time (eio_tstamp nseconds); |
||||
|
/* do not handle more then count requests in one call to eio_poll_cb */ |
||||
|
void eio_set_max_poll_reqs (unsigned int nreqs); |
||||
|
|
||||
|
/* set minimum required number
|
||||
|
* maximum wanted number |
||||
|
* or maximum idle number of threads */ |
||||
|
void eio_set_min_parallel (unsigned int nthreads); |
||||
|
void eio_set_max_parallel (unsigned int nthreads); |
||||
|
void eio_set_max_idle (unsigned int nthreads); |
||||
|
|
||||
|
unsigned int eio_nreqs (void); /* number of requests in-flight */ |
||||
|
unsigned int eio_nready (void); /* number of not-yet handled requests */ |
||||
|
unsigned int eio_npending (void); /* numbe rof finished but unhandled requests */ |
||||
|
unsigned int eio_nthreads (void); /* number of worker threads in use currently */ |
||||
|
|
||||
|
/*****************************************************************************/ |
||||
|
/* convinience wrappers */ |
||||
|
|
||||
|
#ifndef EIO_NO_WRAPPERS |
||||
|
eio_req *eio_nop (int pri, eio_cb cb, void *data); /* does nothing except go through the whole process */ |
||||
|
eio_req *eio_busy (eio_tstamp delay, int pri, eio_cb cb, void *data); /* ties a thread for this long, simulating busyness */ |
||||
|
eio_req *eio_sync (int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_fsync (int fd, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_fdatasync (int fd, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_msync (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_mtouch (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_close (int fd, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_readahead (int fd, off_t offset, size_t length, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_read (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_write (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_fstat (int fd, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ |
||||
|
eio_req *eio_futime (int fd, eio_tstamp atime, eio_tstamp mtime, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_ftruncate (int fd, off_t offset, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_fchmod (int fd, mode_t mode, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_fchown (int fd, uid_t uid, gid_t gid, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_dup2 (int fd, int fd2, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_sendfile (int out_fd, int in_fd, off_t in_offset, size_t length, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_open (const char *path, int flags, mode_t mode, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_utime (const char *path, eio_tstamp atime, eio_tstamp mtime, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_truncate (const char *path, off_t offset, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_chown (const char *path, uid_t uid, gid_t gid, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_chmod (const char *path, mode_t mode, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_mkdir (const char *path, mode_t mode, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_readdir (const char *path, int pri, eio_cb cb, void *data); /* result=ptr2 allocated dynamically */ |
||||
|
eio_req *eio_rmdir (const char *path, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_unlink (const char *path, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data); /* result=ptr2 allocated dynamically */ |
||||
|
eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ |
||||
|
eio_req *eio_lstat (const char *path, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ |
||||
|
eio_req *eio_mknod (const char *path, mode_t mode, dev_t dev, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_link (const char *path, const char *new_path, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_symlink (const char *path, const char *new_path, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_rename (const char *path, const char *new_path, int pri, eio_cb cb, void *data); |
||||
|
eio_req *eio_custom (eio_cb execute, int pri, eio_cb cb, void *data); |
||||
|
#endif |
||||
|
|
||||
|
/*****************************************************************************/ |
||||
|
/* groups */ |
||||
|
|
||||
|
eio_req *eio_grp (eio_cb cb, void *data); |
||||
|
void eio_grp_feed (eio_req *grp, void (*feed)(eio_req *req), int limit); |
||||
|
void eio_grp_limit (eio_req *grp, int limit); |
||||
|
void eio_grp_add (eio_req *grp, eio_req *req); |
||||
|
void eio_grp_cancel (eio_req *grp); /* cancels all sub requests but not the group */ |
||||
|
|
||||
|
/*****************************************************************************/ |
||||
|
/* request api */ |
||||
|
|
||||
|
/* true if the request was cancelled, useful in the invoke callback */ |
||||
|
#define EIO_CANCELLED(req) ((req)->flags & EIO_FLAG_CANCELLED) |
||||
|
|
||||
|
#define EIO_RESULT(req) ((req)->result) |
||||
|
/* returns a pointer to the result buffer allocated by eio */ |
||||
|
#define EIO_BUF(req) ((req)->ptr2) |
||||
|
#define EIO_STAT_BUF(req) ((EIO_STRUCT_STAT *)EIO_BUF(req)) |
||||
|
#define EIO_PATH(req) ((char *)(req)->ptr1) |
||||
|
|
||||
|
/* submit a request for execution */ |
||||
|
void eio_submit (eio_req *req); |
||||
|
/* cancel a request as soon fast as possible, if possible */ |
||||
|
void eio_cancel (eio_req *req); |
||||
|
/* destroy a request that has never been submitted */ |
||||
|
void eio_destroy (eio_req *req); |
||||
|
|
||||
|
/*****************************************************************************/ |
||||
|
/* convinience functions */ |
||||
|
|
||||
|
ssize_t eio_sendfile_sync (int ofd, int ifd, off_t offset, size_t count); |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,282 @@ |
|||||
|
=head1 NAME |
||||
|
|
||||
|
libeio - truly asynchronous POSIX I/O |
||||
|
|
||||
|
=head1 SYNOPSIS |
||||
|
|
||||
|
#include <eio.h> |
||||
|
|
||||
|
=head1 DESCRIPTION |
||||
|
|
||||
|
The newest version of this document is also available as an html-formatted |
||||
|
web page you might find easier to navigate when reading it for the first |
||||
|
time: L<http://pod.tst.eu/http://cvs.schmorp.de/libeio/eio.pod>. |
||||
|
|
||||
|
Note that this library is a by-product of the C<IO::AIO> perl |
||||
|
module, and many of the subtler points regarding requets lifetime |
||||
|
and so on are only documented in its documentation at the |
||||
|
moment: L<http://pod.tst.eu/http://cvs.schmorp.de/IO-AIO/AIO.pm>. |
||||
|
|
||||
|
=head2 FEATURES |
||||
|
|
||||
|
This library provides fully asynchronous versions of most POSIX functions |
||||
|
dealign with I/O. Unlike most asynchronous libraries, this not only |
||||
|
includes C<read> and C<write>, but also C<open>, C<stat>, C<unlink> and |
||||
|
similar functions, as well as less rarely ones such as C<mknod>, C<futime> |
||||
|
or C<readlink>. |
||||
|
|
||||
|
It also offers wrappers around C<sendfile> (Solaris, Linux, HP-UX and |
||||
|
FreeBSD, with emulation on other platforms) and C<readahead> (Linux, with |
||||
|
emulation elsewhere>). |
||||
|
|
||||
|
The goal is to enbale you to write fully non-blocking programs. For |
||||
|
example, in a game server, you would not want to freeze for a few seconds |
||||
|
just because the server is running a backup and you happen to call |
||||
|
C<readdir>. |
||||
|
|
||||
|
=head2 TIME REPRESENTATION |
||||
|
|
||||
|
Libeio represents time as a single floating point number, representing the |
||||
|
(fractional) number of seconds since the (POSIX) epoch (somewhere near |
||||
|
the beginning of 1970, details are complicated, don't ask). This type is |
||||
|
called C<eio_tstamp>, but it is guarenteed to be of type C<double> (or |
||||
|
better), so you can freely use C<double> yourself. |
||||
|
|
||||
|
Unlike the name component C<stamp> might indicate, it is also used for |
||||
|
time differences throughout libeio. |
||||
|
|
||||
|
=head2 FORK SUPPORT |
||||
|
|
||||
|
Calling C<fork ()> is fully supported by this module. It is implemented in these steps: |
||||
|
|
||||
|
1. wait till all requests in "execute" state have been handled |
||||
|
(basically requests that are already handed over to the kernel). |
||||
|
2. fork |
||||
|
3. in the parent, continue business as usual, done |
||||
|
4. in the child, destroy all ready and pending requests and free the |
||||
|
memory used by the worker threads. This gives you a fully empty |
||||
|
libeio queue. |
||||
|
|
||||
|
=head1 INITIALISATION/INTEGRATION |
||||
|
|
||||
|
Before you can call any eio functions you first have to initialise the |
||||
|
library. The library integrates into any event loop, but can also be used |
||||
|
without one, including in polling mode. |
||||
|
|
||||
|
You have to provide the necessary glue yourself, however. |
||||
|
|
||||
|
=over 4 |
||||
|
|
||||
|
=item int eio_init (void (*want_poll)(void), void (*done_poll)(void)) |
||||
|
|
||||
|
This function initialises the library. On success it returns C<0>, on |
||||
|
failure it returns C<-1> and sets C<errno> appropriately. |
||||
|
|
||||
|
It accepts two function pointers specifying callbacks as argument, both of |
||||
|
which can be C<0>, in which case the callback isn't called. |
||||
|
|
||||
|
=item want_poll callback |
||||
|
|
||||
|
The C<want_poll> callback is invoked whenever libeio wants attention (i.e. |
||||
|
it wants to be polled by calling C<eio_poll>). It is "edge-triggered", |
||||
|
that is, it will only be called once when eio wants attention, until all |
||||
|
pending requests have been handled. |
||||
|
|
||||
|
This callback is called while locks are being held, so I<you must |
||||
|
not call any libeio functions inside this callback>. That includes |
||||
|
C<eio_poll>. What you should do is notify some other thread, or wake up |
||||
|
your event loop, and then call C<eio_poll>. |
||||
|
|
||||
|
=item done_poll callback |
||||
|
|
||||
|
This callback is invoked when libeio detects that all pending requests |
||||
|
have been handled. It is "edge-triggered", that is, it will only be |
||||
|
called once after C<want_poll>. To put it differently, C<want_poll> and |
||||
|
C<done_poll> are invoked in pairs: after C<want_poll> you have to call |
||||
|
C<eio_poll ()> until either C<eio_poll> indicates that everything has been |
||||
|
handled or C<done_poll> has been called, which signals the same. |
||||
|
|
||||
|
Note that C<eio_poll> might return after C<done_poll> and C<want_poll> |
||||
|
have been called again, so watch out for races in your code. |
||||
|
|
||||
|
As with C<want_poll>, this callback is called while lcoks are being held, |
||||
|
so you I<must not call any libeio functions form within this callback>. |
||||
|
|
||||
|
=item int eio_poll () |
||||
|
|
||||
|
This function has to be called whenever there are pending requests that |
||||
|
need finishing. You usually call this after C<want_poll> has indicated |
||||
|
that you should do so, but you can also call this function regularly to |
||||
|
poll for new results. |
||||
|
|
||||
|
If any request invocation returns a non-zero value, then C<eio_poll ()> |
||||
|
immediately returns with that value as return value. |
||||
|
|
||||
|
Otherwise, if all requests could be handled, it returns C<0>. If for some |
||||
|
reason not all requests have been handled, i.e. some are still pending, it |
||||
|
returns C<-1>. |
||||
|
|
||||
|
=back |
||||
|
|
||||
|
For libev, you would typically use an C<ev_async> watcher: the |
||||
|
C<want_poll> callback would invoke C<ev_async_send> to wake up the event |
||||
|
loop. Inside the callback set for the watcher, one would call C<eio_poll |
||||
|
()> (followed by C<ev_async_send> again if C<eio_poll> indicates that not |
||||
|
all requests have been handled yet). The race is taken care of because |
||||
|
libev resets/rearms the async watcher before calling your callback, |
||||
|
and therefore, before calling C<eio_poll>. This might result in (some) |
||||
|
spurious wake-ups, but is generally harmless. |
||||
|
|
||||
|
For most other event loops, you would typically use a pipe - the event |
||||
|
loop should be told to wait for read readyness on the read end. In |
||||
|
C<want_poll> you would write a single byte, in C<done_poll> you would try |
||||
|
to read that byte, and in the callback for the read end, you would call |
||||
|
C<eio_poll>. The race is avoided here because the event loop should invoke |
||||
|
your callback again and again until the byte has been read (as the pipe |
||||
|
read callback does not read it, only C<done_poll>). |
||||
|
|
||||
|
=head2 CONFIGURATION |
||||
|
|
||||
|
The functions in this section can sometimes be useful, but the default |
||||
|
configuration will do in most case, so you should skip this section on |
||||
|
first reading. |
||||
|
|
||||
|
=over 4 |
||||
|
|
||||
|
=item eio_set_max_poll_time (eio_tstamp nseconds) |
||||
|
|
||||
|
This causes C<eio_poll ()> to return after it has detected that it was |
||||
|
running for C<nsecond> seconds or longer (this number can be fractional). |
||||
|
|
||||
|
This can be used to limit the amount of time spent handling eio requests, |
||||
|
for example, in interactive programs, you might want to limit this time to |
||||
|
C<0.01> seconds or so. |
||||
|
|
||||
|
Note that: |
||||
|
|
||||
|
a) libeio doesn't know how long your request callbacks take, so the time |
||||
|
spent in C<eio_poll> is up to one callback invocation longer then this |
||||
|
interval. |
||||
|
|
||||
|
b) this is implemented by calling C<gettimeofday> after each request, |
||||
|
which can be costly. |
||||
|
|
||||
|
c) at least one request will be handled. |
||||
|
|
||||
|
=item eio_set_max_poll_reqs (unsigned int nreqs) |
||||
|
|
||||
|
When C<nreqs> is non-zero, then C<eio_poll> will not handle more than |
||||
|
C<nreqs> requests per invocation. This is a less costly way to limit the |
||||
|
amount of work done by C<eio_poll> then setting a time limit. |
||||
|
|
||||
|
If you know your callbacks are generally fast, you could use this to |
||||
|
encourage interactiveness in your programs by setting it to C<10>, C<100> |
||||
|
or even C<1000>. |
||||
|
|
||||
|
=item eio_set_min_parallel (unsigned int nthreads) |
||||
|
|
||||
|
Make sure libeio can handle at least this many requests in parallel. It |
||||
|
might be able handle more. |
||||
|
|
||||
|
=item eio_set_max_parallel (unsigned int nthreads) |
||||
|
|
||||
|
Set the maximum number of threads that libeio will spawn. |
||||
|
|
||||
|
=item eio_set_max_idle (unsigned int nthreads) |
||||
|
|
||||
|
Libeio uses threads internally to handle most requests, and will start and stop threads on demand. |
||||
|
|
||||
|
This call can be used to limit the number of idle threads (threads without |
||||
|
work to do): libeio will keep some threads idle in preperation for more |
||||
|
requests, but never longer than C<nthreads> threads. |
||||
|
|
||||
|
In addition to this, libeio will also stop threads when they are idle for |
||||
|
a few seconds, regardless of this setting. |
||||
|
|
||||
|
=item unsigned int eio_nthreads () |
||||
|
|
||||
|
Return the number of worker threads currently running. |
||||
|
|
||||
|
=item unsigned int eio_nreqs () |
||||
|
|
||||
|
Return the number of requests currently handled by libeio. This is the |
||||
|
total number of requests that have been submitted to libeio, but not yet |
||||
|
destroyed. |
||||
|
|
||||
|
=item unsigned int eio_nready () |
||||
|
|
||||
|
Returns the number of ready requests, i.e. requests that have been |
||||
|
submitted but have not yet entered the execution phase. |
||||
|
|
||||
|
=item unsigned int eio_npending () |
||||
|
|
||||
|
Returns the number of pending requests, i.e. requests that have been |
||||
|
executed and have results, but have not been finished yet by a call to |
||||
|
C<eio_poll>). |
||||
|
|
||||
|
=back |
||||
|
|
||||
|
|
||||
|
=head1 ANATOMY OF AN EIO REQUEST |
||||
|
|
||||
|
#TODO |
||||
|
|
||||
|
|
||||
|
=head1 HIGH LEVEL REQUEST API |
||||
|
|
||||
|
#TODO |
||||
|
|
||||
|
=back |
||||
|
|
||||
|
|
||||
|
=head1 LOW LEVEL REQUEST API |
||||
|
|
||||
|
#TODO |
||||
|
|
||||
|
=head1 EMBEDDING |
||||
|
|
||||
|
Libeio can be embedded directly into programs. This functionality is not |
||||
|
documented and not (yet) officially supported. |
||||
|
|
||||
|
Note that, when including C<libeio.m4>, you are responsible for defining |
||||
|
the compilation environment (C<_LARGEFILE_SOURCE>, C<_GNU_SOURCE> etc.). |
||||
|
|
||||
|
If you need to know how, check the C<IO::AIO> perl module, which does |
||||
|
exactly that. |
||||
|
|
||||
|
|
||||
|
=head1 PORTABILITY REQUIREMENTS |
||||
|
|
||||
|
In addition to a working ISO-C implementation, libeio relies on a few |
||||
|
additional extensions: |
||||
|
|
||||
|
=over 4 |
||||
|
|
||||
|
=item POSIX threads |
||||
|
|
||||
|
To be portable, this module uses threads, specifically, the POSIX threads |
||||
|
library must be available (and working, which partially excludes many xBSD |
||||
|
systems, where C<fork ()> is buggy). |
||||
|
|
||||
|
=item POSIX-compatible filesystem API |
||||
|
|
||||
|
This is actually a harder portability requirement: The libeio API is quite |
||||
|
demanding regarding POSIX API calls (symlinks, user/group management |
||||
|
etc.). |
||||
|
|
||||
|
=item C<double> must hold a time value in seconds with enough accuracy |
||||
|
|
||||
|
The type C<double> is used to represent timestamps. It is required to |
||||
|
have at least 51 bits of mantissa (and 9 bits of exponent), which is good |
||||
|
enough for at least into the year 4000. This requirement is fulfilled by |
||||
|
implementations implementing IEEE 754 (basically all existing ones). |
||||
|
|
||||
|
=back |
||||
|
|
||||
|
If you know of other additional requirements drop me a note. |
||||
|
|
||||
|
|
||||
|
=head1 AUTHOR |
||||
|
|
||||
|
Marc Lehmann <libeio@schmorp.de>. |
||||
|
|
@ -0,0 +1,107 @@ |
|||||
|
AC_SEARCH_LIBS( |
||||
|
pthread_create, |
||||
|
[pthread pthreads pthreadVC2], |
||||
|
, |
||||
|
[AC_MSG_ERROR(pthread functions not found)] |
||||
|
) |
||||
|
|
||||
|
AC_CACHE_CHECK(for futimes, ac_cv_futimes, [AC_LINK_IFELSE([[ |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/time.h> |
||||
|
#include <utime.h> |
||||
|
struct timeval tv[2]; |
||||
|
int res; |
||||
|
int fd; |
||||
|
int main(void) |
||||
|
{ |
||||
|
res = futimes (fd, tv); |
||||
|
return 0; |
||||
|
} |
||||
|
]],ac_cv_futimes=yes,ac_cv_futimes=no)]) |
||||
|
test $ac_cv_futimes = yes && AC_DEFINE(HAVE_FUTIMES, 1, futimes(2) is available) |
||||
|
|
||||
|
AC_CACHE_CHECK(for readahead, ac_cv_readahead, [AC_LINK_IFELSE([ |
||||
|
#include <fcntl.h> |
||||
|
int main(void) |
||||
|
{ |
||||
|
int fd = 0; |
||||
|
size_t count = 2; |
||||
|
ssize_t res; |
||||
|
res = readahead (fd, 0, count); |
||||
|
return 0; |
||||
|
} |
||||
|
],ac_cv_readahead=yes,ac_cv_readahead=no)]) |
||||
|
test $ac_cv_readahead = yes && AC_DEFINE(HAVE_READAHEAD, 1, readahead(2) is available (linux)) |
||||
|
|
||||
|
AC_CACHE_CHECK(for fdatasync, ac_cv_fdatasync, [AC_LINK_IFELSE([ |
||||
|
#include <unistd.h> |
||||
|
int main(void) |
||||
|
{ |
||||
|
int fd = 0; |
||||
|
fdatasync (fd); |
||||
|
return 0; |
||||
|
} |
||||
|
],ac_cv_fdatasync=yes,ac_cv_fdatasync=no)]) |
||||
|
test $ac_cv_fdatasync = yes && AC_DEFINE(HAVE_FDATASYNC, 1, fdatasync(2) is available) |
||||
|
|
||||
|
AC_CACHE_CHECK(for pread and pwrite, ac_cv_preadwrite, [AC_LINK_IFELSE([ |
||||
|
#include <unistd.h> |
||||
|
int main(void) |
||||
|
{ |
||||
|
int fd = 0; |
||||
|
size_t count = 1; |
||||
|
char buf; |
||||
|
off_t offset = 1; |
||||
|
ssize_t res; |
||||
|
res = pread (fd, &buf, count, offset); |
||||
|
res = pwrite (fd, &buf, count, offset); |
||||
|
return 0; |
||||
|
} |
||||
|
],ac_cv_preadwrite=yes,ac_cv_preadwrite=no)]) |
||||
|
test $ac_cv_preadwrite = yes && AC_DEFINE(HAVE_PREADWRITE, 1, pread(2) and pwrite(2) are available) |
||||
|
|
||||
|
AC_CACHE_CHECK(for sendfile, ac_cv_sendfile, [AC_LINK_IFELSE([ |
||||
|
# include <sys/types.h> |
||||
|
#if __linux |
||||
|
# include <sys/sendfile.h> |
||||
|
#elif __freebsd |
||||
|
# include <sys/socket.h> |
||||
|
# include <sys/uio.h> |
||||
|
#elif __hpux |
||||
|
# include <sys/socket.h> |
||||
|
#else |
||||
|
# error unsupported architecture |
||||
|
#endif |
||||
|
int main(void) |
||||
|
{ |
||||
|
int fd = 0; |
||||
|
off_t offset = 1; |
||||
|
size_t count = 2; |
||||
|
ssize_t res; |
||||
|
#if __linux |
||||
|
res = sendfile (fd, fd, offset, count); |
||||
|
#elif __freebsd |
||||
|
res = sendfile (fd, fd, offset, count, 0, &offset, 0); |
||||
|
#elif __hpux |
||||
|
res = sendfile (fd, fd, offset, count, 0, 0); |
||||
|
#endif |
||||
|
return 0; |
||||
|
} |
||||
|
],ac_cv_sendfile=yes,ac_cv_sendfile=no)]) |
||||
|
test $ac_cv_sendfile = yes && AC_DEFINE(HAVE_SENDFILE, 1, sendfile(2) is available and supported) |
||||
|
|
||||
|
AC_CACHE_CHECK(for sync_file_range, ac_cv_sync_file_range, [AC_LINK_IFELSE([ |
||||
|
#include <fcntl.h> |
||||
|
int main(void) |
||||
|
{ |
||||
|
int fd = 0; |
||||
|
off64_t offset = 1; |
||||
|
off64_t nbytes = 1; |
||||
|
unsigned int flags = SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER; |
||||
|
ssize_t res; |
||||
|
res = sync_file_range (fd, offset, nbytes, flags); |
||||
|
return 0; |
||||
|
} |
||||
|
],ac_cv_sync_file_range=yes,ac_cv_sync_file_range=no)]) |
||||
|
test $ac_cv_sync_file_range = yes && AC_DEFINE(HAVE_SYNC_FILE_RANGE, 1, sync_file_range(2) is available) |
||||
|
|
@ -0,0 +1,154 @@ |
|||||
|
#ifndef XTHREAD_H_ |
||||
|
#define XTHREAD_H_ |
||||
|
|
||||
|
/* whether word reads are potentially non-atomic.
|
||||
|
* this is conservatice, likely most arches this runs |
||||
|
* on have atomic word read/writes. |
||||
|
*/ |
||||
|
#ifndef WORDACCESS_UNSAFE |
||||
|
# if __i386 || __x86_64 |
||||
|
# define WORDACCESS_UNSAFE 0 |
||||
|
# else |
||||
|
# define WORDACCESS_UNSAFE 1 |
||||
|
# endif |
||||
|
#endif |
||||
|
|
||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
||||
|
#ifdef _WIN32 |
||||
|
typedef int ssize_t; |
||||
|
|
||||
|
#define NTDDI_VERSION NTDDI_WIN2K // needed to get win2000 api calls
|
||||
|
#define _WIN32_WINNT 0x400 |
||||
|
#include <stdio.h>//D |
||||
|
#include <fcntl.h> |
||||
|
#include <io.h> |
||||
|
#include <time.h> |
||||
|
#include <winsock2.h> |
||||
|
#include <process.h> |
||||
|
#include <windows.h> |
||||
|
#include <pthread.h> |
||||
|
#define sigset_t int |
||||
|
#define sigfillset(a) |
||||
|
#define pthread_sigmask(a,b,c) |
||||
|
#define sigaddset(a,b) |
||||
|
#define sigemptyset(s) |
||||
|
#define sigfillset(s) |
||||
|
|
||||
|
typedef pthread_mutex_t mutex_t; |
||||
|
#define X_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER |
||||
|
#define X_LOCK(mutex) pthread_mutex_lock (&(mutex)) |
||||
|
#define X_UNLOCK(mutex) pthread_mutex_unlock (&(mutex)) |
||||
|
|
||||
|
typedef pthread_cond_t cond_t; |
||||
|
#define X_COND_INIT PTHREAD_COND_INITIALIZER |
||||
|
#define X_COND_SIGNAL(cond) pthread_cond_signal (&(cond)) |
||||
|
#define X_COND_WAIT(cond,mutex) pthread_cond_wait (&(cond), &(mutex)) |
||||
|
#define X_COND_TIMEDWAIT(cond,mutex,to) pthread_cond_timedwait (&(cond), &(mutex), &(to)) |
||||
|
|
||||
|
typedef pthread_t thread_t; |
||||
|
#define X_THREAD_PROC(name) void *name (void *thr_arg) |
||||
|
#define X_THREAD_ATFORK(a,b,c) |
||||
|
|
||||
|
static int |
||||
|
thread_create (thread_t *tid, void *(*proc)(void *), void *arg) |
||||
|
{ |
||||
|
int retval; |
||||
|
pthread_attr_t attr; |
||||
|
|
||||
|
pthread_attr_init (&attr); |
||||
|
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); |
||||
|
|
||||
|
retval = pthread_create (tid, &attr, proc, arg) == 0; |
||||
|
|
||||
|
pthread_attr_destroy (&attr); |
||||
|
|
||||
|
return retval; |
||||
|
} |
||||
|
|
||||
|
#define respipe_read(a,b,c) PerlSock_recv ((a), (b), (c), 0) |
||||
|
#define respipe_write(a,b,c) send ((a), (b), (c), 0) |
||||
|
#define respipe_close(a) PerlSock_closesocket ((a)) |
||||
|
|
||||
|
#else |
||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
||||
|
#if __linux && !defined(_GNU_SOURCE) |
||||
|
# define _GNU_SOURCE |
||||
|
#endif |
||||
|
|
||||
|
/* just in case */ |
||||
|
#define _REENTRANT 1 |
||||
|
|
||||
|
#if __solaris |
||||
|
# define _POSIX_PTHREAD_SEMANTICS 1 |
||||
|
/* try to bribe solaris headers into providing a current pthread API
|
||||
|
* despite environment being configured for an older version. |
||||
|
*/ |
||||
|
# define __EXTENSIONS__ 1 |
||||
|
#endif |
||||
|
|
||||
|
#include <unistd.h> |
||||
|
#include <fcntl.h> |
||||
|
#include <signal.h> |
||||
|
#include <limits.h> |
||||
|
#include <pthread.h> |
||||
|
|
||||
|
typedef pthread_mutex_t mutex_t; |
||||
|
#if __linux && defined (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) |
||||
|
# define X_MUTEX_INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP |
||||
|
#else |
||||
|
# define X_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER |
||||
|
#endif |
||||
|
#define X_LOCK(mutex) pthread_mutex_lock (&(mutex)) |
||||
|
#define X_UNLOCK(mutex) pthread_mutex_unlock (&(mutex)) |
||||
|
|
||||
|
typedef pthread_cond_t cond_t; |
||||
|
#define X_COND_INIT PTHREAD_COND_INITIALIZER |
||||
|
#define X_COND_SIGNAL(cond) pthread_cond_signal (&(cond)) |
||||
|
#define X_COND_WAIT(cond,mutex) pthread_cond_wait (&(cond), &(mutex)) |
||||
|
#define X_COND_TIMEDWAIT(cond,mutex,to) pthread_cond_timedwait (&(cond), &(mutex), &(to)) |
||||
|
|
||||
|
typedef pthread_t thread_t; |
||||
|
#define X_THREAD_PROC(name) static void *name (void *thr_arg) |
||||
|
#define X_THREAD_ATFORK(prepare,parent,child) pthread_atfork (prepare, parent, child) |
||||
|
|
||||
|
// the broken bsd's once more
|
||||
|
#ifndef PTHREAD_STACK_MIN |
||||
|
# define PTHREAD_STACK_MIN 0 |
||||
|
#endif |
||||
|
|
||||
|
static int |
||||
|
thread_create (thread_t *tid, void *(*proc)(void *), void *arg) |
||||
|
{ |
||||
|
int retval; |
||||
|
sigset_t fullsigset, oldsigset; |
||||
|
pthread_attr_t attr; |
||||
|
|
||||
|
pthread_attr_init (&attr); |
||||
|
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); |
||||
|
pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN < sizeof (long) * 4096 |
||||
|
? sizeof (long) * 4096 : PTHREAD_STACK_MIN); |
||||
|
#ifdef PTHREAD_SCOPE_PROCESS |
||||
|
pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS); |
||||
|
#endif |
||||
|
|
||||
|
sigfillset (&fullsigset); |
||||
|
|
||||
|
pthread_sigmask (SIG_SETMASK, &fullsigset, &oldsigset); |
||||
|
retval = pthread_create (tid, &attr, proc, arg) == 0; |
||||
|
pthread_sigmask (SIG_SETMASK, &oldsigset, 0); |
||||
|
|
||||
|
pthread_attr_destroy (&attr); |
||||
|
|
||||
|
return retval; |
||||
|
} |
||||
|
|
||||
|
#define respipe_read(a,b,c) read ((a), (b), (c)) |
||||
|
#define respipe_write(a,b,c) write ((a), (b), (c)) |
||||
|
#define respipe_close(a) close ((a)) |
||||
|
|
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,221 @@ |
|||||
|
Revision history for libev, a high-performance and full-featured event loop. |
||||
|
|
||||
|
3.53 Sun Feb 15 02:38:20 CET 2009 |
||||
|
- fix a bug in event pipe creation on win32 that would cause a |
||||
|
failed assertion on event loop creation (patch by Malek Hadj-Ali). |
||||
|
- probe for CLOCK_REALTIME support at runtime as well and fall |
||||
|
back to gettimeofday if there is an error, to support older |
||||
|
operating systems with newer header files/libraries. |
||||
|
- prefer gettimeofday over clock_gettime with USE_CLOCK_SYSCALL |
||||
|
(default most everywhere), otherwise not. |
||||
|
|
||||
|
3.52 Wed Jan 7 21:43:02 CET 2009 |
||||
|
- fix compilation of select backend in fd_set mode when NFDBITS is |
||||
|
missing (to get it to compile on QNX, reported by Rodrigo Campos). |
||||
|
- better select-nfds handling when select backend is in fd_set mode. |
||||
|
- diagnose fd_set overruns when select backend is in fd_set mode. |
||||
|
- due to a thinko, instead of disabling everything but |
||||
|
select on the borked OS X platform, everything but select was |
||||
|
allowed (reported by Emanuele Giaquinta). |
||||
|
- actually verify that local and remote port are matching in |
||||
|
libev's socketpair emulation, which makes denial-of-service |
||||
|
attacks harder (but not impossible - it's windows). Make sure |
||||
|
it even works under vista, which thinks that getpeer/sockname |
||||
|
should return fantasy port numbers. |
||||
|
- include "libev" in all assertion messages for potentially |
||||
|
clearer diagnostics. |
||||
|
- event_get_version (libevent compatibility) returned |
||||
|
a useless string instead of the expected version string |
||||
|
(patch by W.C.A. Wijngaards). |
||||
|
|
||||
|
3.51 Wed Dec 24 23:00:11 CET 2008 |
||||
|
- fix a bug where an inotify watcher was added twice, causing |
||||
|
freezes on hash collisions (reported and analysed by Graham Leggett). |
||||
|
- new config symbol, EV_USE_CLOCK_SYSCALL, to make libev use |
||||
|
a direct syscall - slower, but no dependency on librt et al. |
||||
|
- assume negative return values != -1 signals success of port_getn |
||||
|
(http://cvs.epicsol.org/cgi/viewcvs.cgi/epic5/source/newio.c?rev=1.52) |
||||
|
(no known failure reports, but it doesn't hurt). |
||||
|
- fork detection in ev_embed now stops and restarts the watcher |
||||
|
automatically. |
||||
|
- EXPERIMENTAL: default the method to operator () in ev++.h, |
||||
|
to make it nicer to use functors (requested by Benedek László). |
||||
|
- fixed const object callbacks in ev++.h. |
||||
|
- replaced loop_ref argument of watcher.set (loop) by a direct |
||||
|
ev_loop * in ev++.h, to avoid clashes with functor patch. |
||||
|
- do not try to watch the empty string via inotify. |
||||
|
- inotify watchers could be leaked under certain circumstances. |
||||
|
- OS X 10.5 is actually even more broken than earlier versions, |
||||
|
so fall back to select on that piece of garbage. |
||||
|
- fixed some weirdness in the ev_embed documentation. |
||||
|
|
||||
|
3.49 Wed Nov 19 11:26:53 CET 2008 |
||||
|
- ev_stat watchers will now use inotify as a mere hint on |
||||
|
kernels <2.6.25, or if the filesystem is not in the |
||||
|
"known to be good" list. |
||||
|
- better mingw32 compatibility (it's not as borked as native win32) |
||||
|
(analysed by Roger Pack). |
||||
|
- include stdio.h in the example program, as too many people are |
||||
|
confused by the weird C language otherwise. I guess the next thing |
||||
|
I get told is that the "..." ellipses in the examples don't compile |
||||
|
with their C compiler. |
||||
|
|
||||
|
3.48 Thu Oct 30 09:02:37 CET 2008 |
||||
|
- further optimise away the EPOLL_CTL_ADD/MOD combo in the epoll |
||||
|
backend by assuming the kernel event mask hasn't changed if |
||||
|
ADD fails with EEXIST. |
||||
|
- work around spurious event notification bugs in epoll by using |
||||
|
a 32-bit generation counter. recreate kernel state if we receive |
||||
|
spurious notifications or unwanted events. this is very costly, |
||||
|
but I didn't come up with this horrible design. |
||||
|
- use memset to initialise most arrays now and do away with the |
||||
|
init functions. |
||||
|
- expand time-out strategies into a "Be smart about timeouts" section. |
||||
|
- drop the "struct" from all ev_watcher declarations in the |
||||
|
documentation and did other clarifications (yeah, it was a mistake |
||||
|
to have a struct AND a function called ev_loop). |
||||
|
- fix a bug where ev_default would not initialise the default |
||||
|
loop again after it was destroyed with ev_default_destroy. |
||||
|
- rename syserr to ev_syserr to avoid name clashes when embedding, |
||||
|
do similar changes for event.c. |
||||
|
|
||||
|
3.45 Tue Oct 21 21:59:26 CEST 2008 |
||||
|
- disable inotify usage on linux <2.6.25, as it is broken |
||||
|
(reported by Yoann Vandoorselaere). |
||||
|
- ev_stat errornously would try to add inotify watchers |
||||
|
even when inotify wasn't available (this should only |
||||
|
have a performance impact). |
||||
|
- ev_once now passes both timeout and io to the callback if both |
||||
|
occur concurrently, instead of giving timeouts precedence. |
||||
|
- disable EV_USE_INOTIFY when sys/inotify.h is too old. |
||||
|
|
||||
|
3.44 Mon Sep 29 05:18:39 CEST 2008 |
||||
|
- embed watchers now automatically invoke ev_loop_fork on the |
||||
|
embedded loop when the parent loop forks. |
||||
|
- new function: ev_now_update (loop). |
||||
|
- verify_watcher was not marked static. |
||||
|
- improve the "associating..." manpage section. |
||||
|
- documentation tweaks here and there. |
||||
|
|
||||
|
3.43 Sun Jul 6 05:34:41 CEST 2008 |
||||
|
- include more include files on windows to get struct _stati64 |
||||
|
(reported by Chris Hulbert, but doesn't quite fix his issue). |
||||
|
- add missing #include <io.h> in ev.c on windows (reported by |
||||
|
Matt Tolton). |
||||
|
|
||||
|
3.42 Tue Jun 17 12:12:07 CEST 2008 |
||||
|
- work around yet another windows bug: FD_SET actually adds fd's |
||||
|
multiple times to the fd_*SET*, despite official MSN docs claiming |
||||
|
otherwise. Reported and well-analysed by Matt Tolton. |
||||
|
- define NFDBITS to 0 when EV_SELECT_IS_WINSOCKET to make it compile |
||||
|
(reported any analysed by Chris Hulbert). |
||||
|
- fix a bug in ev_ebadf (this function is only used to catch |
||||
|
programming errors in the libev user). reported by Matt Tolton. |
||||
|
- fix a bug in fd_intern on win32 (could lead to compile errors |
||||
|
under some circumstances, but would work correctly if it compiles). |
||||
|
reported by Matt Tolton. |
||||
|
- (try to) work around missing lstat on windows. |
||||
|
- pass in the write fd set as except fd set under windows. windows |
||||
|
is so uncontrollably lame that it requires this. this means that |
||||
|
switching off oobinline is not supported (but tcp/ip doesn't |
||||
|
have oob, so that would be stupid anyways. |
||||
|
- use posix module symbol to auto-detect monotonic clock presence |
||||
|
and some other default values. |
||||
|
|
||||
|
3.41 Fri May 23 18:42:54 CEST 2008 |
||||
|
- work around an obscure bug in winsocket select: if you |
||||
|
provide only empty fd sets then select returns WSAEINVAL. how sucky. |
||||
|
- improve timer scheduling stability and reduce use of time_epsilon. |
||||
|
- use 1-based 2-heap for EV_MINIMAL, simplifies code, reduces |
||||
|
codesize and makes for better cache-efficiency. |
||||
|
- use 3-based 4-heap for !EV_MINIMAL. this makes better use |
||||
|
of cpu cache lines and gives better growth behaviour than |
||||
|
2-based heaps. |
||||
|
- cache timestamp within heap for !EV_MINIMAL, to avoid random |
||||
|
memory accesses. |
||||
|
- document/add EV_USE_4HEAP and EV_HEAP_CACHE_AT. |
||||
|
- fix a potential aliasing issue in ev_timer_again. |
||||
|
- add/document ev_periodic_at, retract direct access to ->at. |
||||
|
- improve ev_stat docs. |
||||
|
- add portability requirements section. |
||||
|
- fix manpage headers etc. |
||||
|
- normalise WSA error codes to lower range on windows. |
||||
|
- add consistency check code that can be called automatically |
||||
|
or on demand to check for internal structures (ev_loop_verify). |
||||
|
|
||||
|
3.31 Wed Apr 16 20:45:04 CEST 2008 |
||||
|
- added last minute fix for ev_poll.c by Brandon Black. |
||||
|
|
||||
|
3.3 Wed Apr 16 19:04:10 CEST 2008 |
||||
|
- event_base_loopexit should return 0 on success |
||||
|
(W.C.A. Wijngaards). |
||||
|
- added linux eventfd support. |
||||
|
- try to autodetect epoll and inotify support |
||||
|
by libc header version if not using autoconf. |
||||
|
- new symbols: EV_DEFAULT_UC and EV_DEFAULT_UC_. |
||||
|
- declare functions defined in ev.h as inline if |
||||
|
C99 or gcc are available. |
||||
|
- enable inlining with gcc versions 2 and 3. |
||||
|
- work around broken poll implementations potentially |
||||
|
not clearing revents field in ev_poll (Brandon Black) |
||||
|
(no such systems are known at this time). |
||||
|
- work around a bug in realloc on openbsd and darwin, |
||||
|
also makes the errornous valgrind complaints |
||||
|
go away (noted by various people). |
||||
|
- fix ev_async_pending, add c++ wrapper for ev_async |
||||
|
(based on patch sent by Johannes Deisenhofer. |
||||
|
- add sensible set method to ev::embed. |
||||
|
- made integer constants type int in ev.h. |
||||
|
|
||||
|
3.2 Wed Apr 2 17:11:19 CEST 2008 |
||||
|
- fix a 64 bit overflow issue in the select backend, |
||||
|
by using fd_mask instead of int for the mask. |
||||
|
- rename internal sighandler to avoid clash with very old perls. |
||||
|
- entering ev_loop will not clear the ONESHOT or NONBLOCKING |
||||
|
flags of any outer loops anymore. |
||||
|
- add ev_async_pending. |
||||
|
|
||||
|
3.1 Thu Mar 13 13:45:22 CET 2008 |
||||
|
- implement ev_async watchers. |
||||
|
- only initialise signal pipe on demand. |
||||
|
- make use of sig_atomic_t configurable. |
||||
|
- improved documentation. |
||||
|
|
||||
|
3.0 Mon Jan 28 13:14:47 CET 2008 |
||||
|
- API/ABI bump to version 3.0. |
||||
|
- ev++.h includes "ev.h" by default now, not <ev.h>. |
||||
|
- slightly improved documentation. |
||||
|
- speed up signal detection after a fork. |
||||
|
- only optionally return trace status changed in ev_child |
||||
|
watchers. |
||||
|
- experimental (and undocumented) loop wrappers for ev++.h. |
||||
|
|
||||
|
2.01 Tue Dec 25 08:04:41 CET 2007 |
||||
|
- separate Changes file. |
||||
|
- fix ev_path_set => ev_stat_set typo. |
||||
|
- remove event_compat.h from the libev tarball. |
||||
|
- change how include files are found. |
||||
|
- doc updates. |
||||
|
- update licenses, explicitly allow for GPL relicensing. |
||||
|
|
||||
|
2.0 Sat Dec 22 17:47:03 CET 2007 |
||||
|
- new ev_sleep, ev_set_(io|timeout)_collect_interval. |
||||
|
- removed epoll from embeddable fd set. |
||||
|
- fix embed watchers. |
||||
|
- renamed ev_embed.loop to other. |
||||
|
- added exported Symbol tables. |
||||
|
- undefine member wrapper macros at the end of ev.c. |
||||
|
- respect EV_H in ev++.h. |
||||
|
|
||||
|
1.86 Tue Dec 18 02:36:57 CET 2007 |
||||
|
- fix memleak on loop destroy (not relevant for perl). |
||||
|
|
||||
|
1.85 Fri Dec 14 20:32:40 CET 2007 |
||||
|
- fix some aliasing issues w.r.t. timers and periodics |
||||
|
(not relevant for perl). |
||||
|
|
||||
|
(for historic versions refer to EV/Changes, found in the Perl interface) |
||||
|
|
||||
|
0.1 Wed Oct 31 21:31:48 CET 2007 |
||||
|
- original version; hacked together in <24h. |
||||
|
|
@ -0,0 +1,36 @@ |
|||||
|
All files in libev are Copyright (C)2007,2008 Marc Alexander Lehmann. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are |
||||
|
met: |
||||
|
|
||||
|
* Redistributions of source code must retain the above copyright |
||||
|
notice, this list of conditions and the following disclaimer. |
||||
|
|
||||
|
* 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 COPYRIGHT HOLDERS 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 COPYRIGHT |
||||
|
OWNER 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. |
||||
|
|
||||
|
Alternatively, the contents of this package may be used under the terms |
||||
|
of the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
in which case the provisions of the GPL are applicable instead of the |
||||
|
above. If you wish to allow the use of your version of this package only |
||||
|
under the terms of the GPL and not to allow others to use your version of |
||||
|
this file under the BSD license, indicate your decision by deleting the |
||||
|
provisions above and replace them with the notice and other provisions |
||||
|
required by the GPL in this and the other files of this package. If you do |
||||
|
not delete the provisions above, a recipient may use your version of this |
||||
|
file under either the BSD or the GPL. |
@ -0,0 +1,18 @@ |
|||||
|
AUTOMAKE_OPTIONS = foreign no-dependencies |
||||
|
|
||||
|
VERSION_INFO = 3:0 |
||||
|
|
||||
|
EXTRA_DIST = LICENSE Changes libev.m4 autogen.sh \
|
||||
|
ev_vars.h ev_wrap.h \
|
||||
|
ev_epoll.c ev_select.c ev_poll.c ev_kqueue.c ev_port.c ev_win32.c \
|
||||
|
ev.3 ev.pod |
||||
|
|
||||
|
man_MANS = ev.3 |
||||
|
|
||||
|
include_HEADERS = ev.h ev++.h event.h |
||||
|
|
||||
|
lib_LTLIBRARIES = libev.la |
||||
|
|
||||
|
libev_la_SOURCES = ev.c event.c |
||||
|
libev_la_LDFLAGS = -version-info $(VERSION_INFO) |
||||
|
|
@ -0,0 +1,58 @@ |
|||||
|
libev is a high-performance event loop/event model with lots of features. |
||||
|
(see benchmark at http://libev.schmorp.de/bench.html) |
||||
|
|
||||
|
|
||||
|
ABOUT |
||||
|
|
||||
|
Homepage: http://software.schmorp.de/pkg/libev |
||||
|
Mailinglist: libev@lists.schmorp.de |
||||
|
http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev |
||||
|
Library Documentation: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod |
||||
|
|
||||
|
Libev is modelled (very losely) after libevent and the Event perl |
||||
|
module, but is faster, scales better and is more correct, and also more |
||||
|
featureful. And also smaller. Yay. |
||||
|
|
||||
|
Some of the specialties of libev not commonly found elsewhere are: |
||||
|
|
||||
|
- extensive and detailed, readable documentation (not doxygen garbage). |
||||
|
- fully supports fork, can detect fork in various ways and automatically |
||||
|
re-arms kernel mechanisms that do not support fork. |
||||
|
- highly optimised select, poll, epoll, kqueue and event ports backends. |
||||
|
- filesystem object (path) watching (with optional linux inotify support). |
||||
|
- wallclock-based times (using absolute time, cron-like). |
||||
|
- relative timers/timeouts (handle time jumps). |
||||
|
- fast intra-thread communication between multiple |
||||
|
event loops (with optional fast linux eventfd backend). |
||||
|
- extremely easy to embed. |
||||
|
- very small codebase, no bloated library. |
||||
|
- fully extensible by being able to plug into the event loop, |
||||
|
integrate other event loops, integrate other event loop users. |
||||
|
- very little memory use (small watchers, small event loop data). |
||||
|
- optional C++ interface allowing method and function callbacks |
||||
|
at no extra memory or runtime overhead. |
||||
|
- optional Perl interface with similar characteristics (capable |
||||
|
of running Glib/Gtk2 on libev, interfaces with Net::SNMP and |
||||
|
libadns). |
||||
|
- support for other languages (multiple C++ interfaces, D, Ruby, |
||||
|
Python) available from third-parties. |
||||
|
|
||||
|
Examples of programs that embed libev: the EV perl module, |
||||
|
rxvt-unicode, gvpe (GNU Virtual Private Ethernet), the Deliantra MMORPG |
||||
|
server (http://www.deliantra.net/), Rubinius (a next-generation Ruby |
||||
|
VM), the Ebb web server, the Rev event toolkit. |
||||
|
|
||||
|
|
||||
|
CONTRIBUTORS |
||||
|
|
||||
|
libev was written and designed by Marc Lehmann and Emanuele Giaquinta. |
||||
|
|
||||
|
The following people sent in patches or made other noteworthy |
||||
|
contributions to the design (for minor patches, see the Changes |
||||
|
file. If I forgot to include you, please shout at me, it was an |
||||
|
accident): |
||||
|
|
||||
|
W.C.A. Wijngaards |
||||
|
Christopher Layne |
||||
|
Chris Brody |
||||
|
|
@ -0,0 +1,3 @@ |
|||||
|
This file is now included in the main libev documentation, see |
||||
|
|
||||
|
http://cvs.schmorp.de/libev/ev.html |
@ -0,0 +1,62 @@ |
|||||
|
ev_async_send |
||||
|
ev_async_start |
||||
|
ev_async_stop |
||||
|
ev_backend |
||||
|
ev_check_start |
||||
|
ev_check_stop |
||||
|
ev_child_start |
||||
|
ev_child_stop |
||||
|
ev_clear_pending |
||||
|
ev_default_destroy |
||||
|
ev_default_fork |
||||
|
ev_default_loop_init |
||||
|
ev_default_loop_ptr |
||||
|
ev_embed_start |
||||
|
ev_embed_stop |
||||
|
ev_embed_sweep |
||||
|
ev_embeddable_backends |
||||
|
ev_feed_event |
||||
|
ev_feed_fd_event |
||||
|
ev_feed_signal_event |
||||
|
ev_fork_start |
||||
|
ev_fork_stop |
||||
|
ev_idle_start |
||||
|
ev_idle_stop |
||||
|
ev_invoke |
||||
|
ev_io_start |
||||
|
ev_io_stop |
||||
|
ev_loop |
||||
|
ev_loop_count |
||||
|
ev_loop_destroy |
||||
|
ev_loop_fork |
||||
|
ev_loop_new |
||||
|
ev_loop_verify |
||||
|
ev_now |
||||
|
ev_now_update |
||||
|
ev_once |
||||
|
ev_periodic_again |
||||
|
ev_periodic_start |
||||
|
ev_periodic_stop |
||||
|
ev_prepare_start |
||||
|
ev_prepare_stop |
||||
|
ev_recommended_backends |
||||
|
ev_ref |
||||
|
ev_set_allocator |
||||
|
ev_set_io_collect_interval |
||||
|
ev_set_syserr_cb |
||||
|
ev_set_timeout_collect_interval |
||||
|
ev_signal_start |
||||
|
ev_signal_stop |
||||
|
ev_sleep |
||||
|
ev_stat_start |
||||
|
ev_stat_stat |
||||
|
ev_stat_stop |
||||
|
ev_supported_backends |
||||
|
ev_time |
||||
|
ev_timer_again |
||||
|
ev_timer_start |
||||
|
ev_timer_stop |
||||
|
ev_unloop |
||||
|
ev_unref |
||||
|
ev_version_major |
||||
|
ev_version_minor |
@ -0,0 +1,21 @@ |
|||||
|
event_active |
||||
|
event_add |
||||
|
event_base_dispatch |
||||
|
event_base_free |
||||
|
event_base_loop |
||||
|
event_base_loopexit |
||||
|
event_base_once |
||||
|
event_base_priority_init |
||||
|
event_base_set |
||||
|
event_del |
||||
|
event_dispatch |
||||
|
event_get_method |
||||
|
event_get_version |
||||
|
event_init |
||||
|
event_loop |
||||
|
event_loopexit |
||||
|
event_once |
||||
|
event_pending |
||||
|
event_priority_init |
||||
|
event_priority_set |
||||
|
event_set |
@ -0,0 +1,6 @@ |
|||||
|
#!/bin/sh |
||||
|
|
||||
|
libtoolize --force |
||||
|
automake --add-missing |
||||
|
autoreconf |
||||
|
|
@ -0,0 +1,18 @@ |
|||||
|
AC_INIT |
||||
|
AC_CONFIG_SRCDIR([ev_epoll.c]) |
||||
|
|
||||
|
AM_INIT_AUTOMAKE(libev,3.53) |
||||
|
AC_CONFIG_HEADERS([config.h]) |
||||
|
AM_MAINTAINER_MODE |
||||
|
|
||||
|
AC_PROG_INSTALL |
||||
|
AC_PROG_LIBTOOL |
||||
|
|
||||
|
if test "x$GCC" = xyes ; then |
||||
|
CFLAGS="$CFLAGS -O3" |
||||
|
fi |
||||
|
|
||||
|
m4_include([libev.m4]) |
||||
|
|
||||
|
AC_CONFIG_FILES([Makefile]) |
||||
|
AC_OUTPUT |
@ -0,0 +1,786 @@ |
|||||
|
/*
|
||||
|
* libev simple C++ wrapper classes |
||||
|
* |
||||
|
* Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de> |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without modifica- |
||||
|
* tion, 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 MER- |
||||
|
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- |
||||
|
* CIAL, 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 OTH- |
||||
|
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
* |
||||
|
* Alternatively, the contents of this file may be used under the terms of |
||||
|
* the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
* in which case the provisions of the GPL are applicable instead of |
||||
|
* the above. If you wish to allow the use of your version of this file |
||||
|
* only under the terms of the GPL and not to allow others to use your |
||||
|
* version of this file under the BSD license, indicate your decision |
||||
|
* by deleting the provisions above and replace them with the notice |
||||
|
* and other provisions required by the GPL. If you do not delete the |
||||
|
* provisions above, a recipient may use your version of this file under |
||||
|
* either the BSD or the GPL. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef EVPP_H__ |
||||
|
#define EVPP_H__ |
||||
|
|
||||
|
#ifdef EV_H |
||||
|
# include EV_H |
||||
|
#else |
||||
|
# include "ev.h" |
||||
|
#endif |
||||
|
|
||||
|
#ifndef EV_USE_STDEXCEPT |
||||
|
# define EV_USE_STDEXCEPT 1 |
||||
|
#endif |
||||
|
|
||||
|
#if EV_USE_STDEXCEPT |
||||
|
# include <stdexcept> |
||||
|
#endif |
||||
|
|
||||
|
namespace ev { |
||||
|
|
||||
|
typedef ev_tstamp tstamp; |
||||
|
|
||||
|
enum |
||||
|
{ |
||||
|
UNDEF = EV_UNDEF, |
||||
|
NONE = EV_NONE, |
||||
|
READ = EV_READ, |
||||
|
WRITE = EV_WRITE, |
||||
|
TIMEOUT = EV_TIMEOUT, |
||||
|
PERIODIC = EV_PERIODIC, |
||||
|
SIGNAL = EV_SIGNAL, |
||||
|
CHILD = EV_CHILD, |
||||
|
STAT = EV_STAT, |
||||
|
IDLE = EV_IDLE, |
||||
|
CHECK = EV_CHECK, |
||||
|
PREPARE = EV_PREPARE, |
||||
|
FORK = EV_FORK, |
||||
|
ASYNC = EV_ASYNC, |
||||
|
EMBED = EV_EMBED, |
||||
|
# undef ERROR // some systems stupidly #define ERROR
|
||||
|
ERROR = EV_ERROR, |
||||
|
}; |
||||
|
|
||||
|
enum |
||||
|
{ |
||||
|
AUTO = EVFLAG_AUTO, |
||||
|
NOENV = EVFLAG_NOENV, |
||||
|
FORKCHECK = EVFLAG_FORKCHECK, |
||||
|
|
||||
|
SELECT = EVBACKEND_SELECT, |
||||
|
POLL = EVBACKEND_POLL, |
||||
|
EPOLL = EVBACKEND_EPOLL, |
||||
|
KQUEUE = EVBACKEND_KQUEUE, |
||||
|
DEVPOLL = EVBACKEND_DEVPOLL, |
||||
|
PORT = EVBACKEND_PORT |
||||
|
}; |
||||
|
|
||||
|
enum |
||||
|
{ |
||||
|
NONBLOCK = EVLOOP_NONBLOCK, |
||||
|
ONESHOT = EVLOOP_ONESHOT |
||||
|
}; |
||||
|
|
||||
|
enum how_t |
||||
|
{ |
||||
|
ONE = EVUNLOOP_ONE, |
||||
|
ALL = EVUNLOOP_ALL |
||||
|
}; |
||||
|
|
||||
|
struct bad_loop |
||||
|
#if EV_USE_STDEXCEPT |
||||
|
: std::runtime_error |
||||
|
#endif |
||||
|
{ |
||||
|
#if EV_USE_STDEXCEPT |
||||
|
bad_loop () |
||||
|
: std::runtime_error ("libev event loop cannot be initialized, bad value of LIBEV_FLAGS?") |
||||
|
{ |
||||
|
} |
||||
|
#endif |
||||
|
}; |
||||
|
|
||||
|
#ifdef EV_AX |
||||
|
# undef EV_AX |
||||
|
#endif |
||||
|
|
||||
|
#ifdef EV_AX_ |
||||
|
# undef EV_AX_ |
||||
|
#endif |
||||
|
|
||||
|
#if EV_MULTIPLICITY |
||||
|
# define EV_AX raw_loop |
||||
|
# define EV_AX_ raw_loop, |
||||
|
#else |
||||
|
# define EV_AX |
||||
|
# define EV_AX_ |
||||
|
#endif |
||||
|
|
||||
|
struct loop_ref |
||||
|
{ |
||||
|
loop_ref (EV_P) throw () |
||||
|
#if EV_MULTIPLICITY |
||||
|
: EV_AX (EV_A) |
||||
|
#endif |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
bool operator == (const loop_ref &other) const throw () |
||||
|
{ |
||||
|
#if EV_MULTIPLICITY |
||||
|
return EV_AX == other.EV_AX; |
||||
|
#else |
||||
|
return true; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
bool operator != (const loop_ref &other) const throw () |
||||
|
{ |
||||
|
#if EV_MULTIPLICITY |
||||
|
return ! (*this == other); |
||||
|
#else |
||||
|
return false; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
#if EV_MULTIPLICITY |
||||
|
bool operator == (const EV_P) const throw () |
||||
|
{ |
||||
|
return this->EV_AX == EV_A; |
||||
|
} |
||||
|
|
||||
|
bool operator != (const EV_P) const throw () |
||||
|
{ |
||||
|
return (*this == EV_A); |
||||
|
} |
||||
|
|
||||
|
operator struct ev_loop * () const throw () |
||||
|
{ |
||||
|
return EV_AX; |
||||
|
} |
||||
|
|
||||
|
operator const struct ev_loop * () const throw () |
||||
|
{ |
||||
|
return EV_AX; |
||||
|
} |
||||
|
|
||||
|
bool is_default () const throw () |
||||
|
{ |
||||
|
return EV_AX == ev_default_loop (0); |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
void loop (int flags = 0) |
||||
|
{ |
||||
|
ev_loop (EV_AX_ flags); |
||||
|
} |
||||
|
|
||||
|
void unloop (how_t how = ONE) throw () |
||||
|
{ |
||||
|
ev_unloop (EV_AX_ how); |
||||
|
} |
||||
|
|
||||
|
void post_fork () throw () |
||||
|
{ |
||||
|
#if EV_MULTIPLICITY |
||||
|
ev_loop_fork (EV_AX); |
||||
|
#else |
||||
|
ev_default_fork (); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
unsigned int count () const throw () |
||||
|
{ |
||||
|
return ev_loop_count (EV_AX); |
||||
|
} |
||||
|
|
||||
|
unsigned int backend () const throw () |
||||
|
{ |
||||
|
return ev_backend (EV_AX); |
||||
|
} |
||||
|
|
||||
|
tstamp now () const throw () |
||||
|
{ |
||||
|
return ev_now (EV_AX); |
||||
|
} |
||||
|
|
||||
|
void ref () throw () |
||||
|
{ |
||||
|
ev_ref (EV_AX); |
||||
|
} |
||||
|
|
||||
|
void unref () throw () |
||||
|
{ |
||||
|
ev_unref (EV_AX); |
||||
|
} |
||||
|
|
||||
|
void set_io_collect_interval (tstamp interval) throw () |
||||
|
{ |
||||
|
ev_set_io_collect_interval (EV_AX_ interval); |
||||
|
} |
||||
|
|
||||
|
void set_timeout_collect_interval (tstamp interval) throw () |
||||
|
{ |
||||
|
ev_set_timeout_collect_interval (EV_AX_ interval); |
||||
|
} |
||||
|
|
||||
|
// function callback
|
||||
|
void once (int fd, int events, tstamp timeout, void (*cb)(int, void *), void *arg = 0) throw () |
||||
|
{ |
||||
|
ev_once (EV_AX_ fd, events, timeout, cb, arg); |
||||
|
} |
||||
|
|
||||
|
// method callback
|
||||
|
template<class K, void (K::*method)(int)> |
||||
|
void once (int fd, int events, tstamp timeout, K *object) throw () |
||||
|
{ |
||||
|
once (fd, events, timeout, method_thunk<K, method>, object); |
||||
|
} |
||||
|
|
||||
|
// default method == operator ()
|
||||
|
template<class K> |
||||
|
void once (int fd, int events, tstamp timeout, K *object) throw () |
||||
|
{ |
||||
|
once (fd, events, timeout, method_thunk<K, &K::operator ()>, object); |
||||
|
} |
||||
|
|
||||
|
template<class K, void (K::*method)(int)> |
||||
|
static void method_thunk (int revents, void *arg) |
||||
|
{ |
||||
|
static_cast<K *>(arg)->*method |
||||
|
(revents); |
||||
|
} |
||||
|
|
||||
|
// no-argument method callback
|
||||
|
template<class K, void (K::*method)()> |
||||
|
void once (int fd, int events, tstamp timeout, K *object) throw () |
||||
|
{ |
||||
|
once (fd, events, timeout, method_noargs_thunk<K, method>, object); |
||||
|
} |
||||
|
|
||||
|
template<class K, void (K::*method)()> |
||||
|
static void method_noargs_thunk (int revents, void *arg) |
||||
|
{ |
||||
|
static_cast<K *>(arg)->*method |
||||
|
(); |
||||
|
} |
||||
|
|
||||
|
// simpler function callback
|
||||
|
template<void (*cb)(int)> |
||||
|
void once (int fd, int events, tstamp timeout) throw () |
||||
|
{ |
||||
|
once (fd, events, timeout, simpler_func_thunk<cb>); |
||||
|
} |
||||
|
|
||||
|
template<void (*cb)(int)> |
||||
|
static void simpler_func_thunk (int revents, void *arg) |
||||
|
{ |
||||
|
(*cb) |
||||
|
(revents); |
||||
|
} |
||||
|
|
||||
|
// simplest function callback
|
||||
|
template<void (*cb)()> |
||||
|
void once (int fd, int events, tstamp timeout) throw () |
||||
|
{ |
||||
|
once (fd, events, timeout, simplest_func_thunk<cb>); |
||||
|
} |
||||
|
|
||||
|
template<void (*cb)()> |
||||
|
static void simplest_func_thunk (int revents, void *arg) |
||||
|
{ |
||||
|
(*cb) |
||||
|
(); |
||||
|
} |
||||
|
|
||||
|
void feed_fd_event (int fd, int revents) throw () |
||||
|
{ |
||||
|
ev_feed_fd_event (EV_AX_ fd, revents); |
||||
|
} |
||||
|
|
||||
|
void feed_signal_event (int signum) throw () |
||||
|
{ |
||||
|
ev_feed_signal_event (EV_AX_ signum); |
||||
|
} |
||||
|
|
||||
|
#if EV_MULTIPLICITY |
||||
|
struct ev_loop* EV_AX; |
||||
|
#endif |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
#if EV_MULTIPLICITY |
||||
|
struct dynamic_loop : loop_ref |
||||
|
{ |
||||
|
|
||||
|
dynamic_loop (unsigned int flags = AUTO) throw (bad_loop) |
||||
|
: loop_ref (ev_loop_new (flags)) |
||||
|
{ |
||||
|
if (!EV_AX) |
||||
|
throw bad_loop (); |
||||
|
} |
||||
|
|
||||
|
~dynamic_loop () throw () |
||||
|
{ |
||||
|
ev_loop_destroy (EV_AX); |
||||
|
EV_AX = 0; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
|
||||
|
dynamic_loop (const dynamic_loop &); |
||||
|
|
||||
|
dynamic_loop & operator= (const dynamic_loop &); |
||||
|
|
||||
|
}; |
||||
|
#endif |
||||
|
|
||||
|
struct default_loop : loop_ref |
||||
|
{ |
||||
|
default_loop (unsigned int flags = AUTO) throw (bad_loop) |
||||
|
#if EV_MULTIPLICITY |
||||
|
: loop_ref (ev_default_loop (flags)) |
||||
|
#endif |
||||
|
{ |
||||
|
if ( |
||||
|
#if EV_MULTIPLICITY |
||||
|
!EV_AX |
||||
|
#else |
||||
|
!ev_default_loop (flags) |
||||
|
#endif |
||||
|
) |
||||
|
throw bad_loop (); |
||||
|
} |
||||
|
|
||||
|
~default_loop () throw () |
||||
|
{ |
||||
|
ev_default_destroy (); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
default_loop (const default_loop &); |
||||
|
default_loop &operator = (const default_loop &); |
||||
|
}; |
||||
|
|
||||
|
inline loop_ref get_default_loop () throw () |
||||
|
{ |
||||
|
#if EV_MULTIPLICITY |
||||
|
return ev_default_loop (0); |
||||
|
#else |
||||
|
return loop_ref (); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
#undef EV_AX |
||||
|
#undef EV_AX_ |
||||
|
|
||||
|
#undef EV_PX |
||||
|
#undef EV_PX_ |
||||
|
#if EV_MULTIPLICITY |
||||
|
# define EV_PX loop_ref EV_A |
||||
|
# define EV_PX_ loop_ref EV_A_ |
||||
|
#else |
||||
|
# define EV_PX |
||||
|
# define EV_PX_ |
||||
|
#endif |
||||
|
|
||||
|
template<class ev_watcher, class watcher> |
||||
|
struct base : ev_watcher |
||||
|
{ |
||||
|
#if EV_MULTIPLICITY |
||||
|
EV_PX; |
||||
|
|
||||
|
void set (EV_P) throw () |
||||
|
{ |
||||
|
this->EV_A = EV_A; |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
base (EV_PX) throw () |
||||
|
#if EV_MULTIPLICITY |
||||
|
: EV_A (EV_A) |
||||
|
#endif |
||||
|
{ |
||||
|
ev_init (this, 0); |
||||
|
} |
||||
|
|
||||
|
void set_ (const void *data, void (*cb)(EV_P_ ev_watcher *w, int revents)) throw () |
||||
|
{ |
||||
|
this->data = (void *)data; |
||||
|
ev_set_cb (static_cast<ev_watcher *>(this), cb); |
||||
|
} |
||||
|
|
||||
|
// function callback
|
||||
|
template<void (*function)(watcher &w, int)> |
||||
|
void set (void *data = 0) throw () |
||||
|
{ |
||||
|
set_ (data, function_thunk<function>); |
||||
|
} |
||||
|
|
||||
|
template<void (*function)(watcher &w, int)> |
||||
|
static void function_thunk (EV_P_ ev_watcher *w, int revents) |
||||
|
{ |
||||
|
function |
||||
|
(*static_cast<watcher *>(w), revents); |
||||
|
} |
||||
|
|
||||
|
// method callback
|
||||
|
template<class K, void (K::*method)(watcher &w, int)> |
||||
|
void set (K *object) throw () |
||||
|
{ |
||||
|
set_ (object, method_thunk<K, method>); |
||||
|
} |
||||
|
|
||||
|
// default method == operator ()
|
||||
|
template<class K> |
||||
|
void set (K *object) throw () |
||||
|
{ |
||||
|
set_ (object, method_thunk<K, &K::operator ()>); |
||||
|
} |
||||
|
|
||||
|
template<class K, void (K::*method)(watcher &w, int)> |
||||
|
static void method_thunk (EV_P_ ev_watcher *w, int revents) |
||||
|
{ |
||||
|
(static_cast<K *>(w->data)->*method) |
||||
|
(*static_cast<watcher *>(w), revents); |
||||
|
} |
||||
|
|
||||
|
// no-argument callback
|
||||
|
template<class K, void (K::*method)()> |
||||
|
void set (K *object) throw () |
||||
|
{ |
||||
|
set_ (object, method_noargs_thunk<K, method>); |
||||
|
} |
||||
|
|
||||
|
template<class K, void (K::*method)()> |
||||
|
static void method_noargs_thunk (EV_P_ ev_watcher *w, int revents) |
||||
|
{ |
||||
|
static_cast<K *>(w->data)->*method |
||||
|
(); |
||||
|
} |
||||
|
|
||||
|
void operator ()(int events = EV_UNDEF) |
||||
|
{ |
||||
|
return |
||||
|
ev_cb (static_cast<ev_watcher *>(this)) |
||||
|
(static_cast<ev_watcher *>(this), events); |
||||
|
} |
||||
|
|
||||
|
bool is_active () const throw () |
||||
|
{ |
||||
|
return ev_is_active (static_cast<const ev_watcher *>(this)); |
||||
|
} |
||||
|
|
||||
|
bool is_pending () const throw () |
||||
|
{ |
||||
|
return ev_is_pending (static_cast<const ev_watcher *>(this)); |
||||
|
} |
||||
|
|
||||
|
void feed_event (int revents) throw () |
||||
|
{ |
||||
|
ev_feed_event (EV_A_ static_cast<const ev_watcher *>(this), revents); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
inline tstamp now () throw () |
||||
|
{ |
||||
|
return ev_time (); |
||||
|
} |
||||
|
|
||||
|
inline void delay (tstamp interval) throw () |
||||
|
{ |
||||
|
ev_sleep (interval); |
||||
|
} |
||||
|
|
||||
|
inline int version_major () throw () |
||||
|
{ |
||||
|
return ev_version_major (); |
||||
|
} |
||||
|
|
||||
|
inline int version_minor () throw () |
||||
|
{ |
||||
|
return ev_version_minor (); |
||||
|
} |
||||
|
|
||||
|
inline unsigned int supported_backends () throw () |
||||
|
{ |
||||
|
return ev_supported_backends (); |
||||
|
} |
||||
|
|
||||
|
inline unsigned int recommended_backends () throw () |
||||
|
{ |
||||
|
return ev_recommended_backends (); |
||||
|
} |
||||
|
|
||||
|
inline unsigned int embeddable_backends () throw () |
||||
|
{ |
||||
|
return ev_embeddable_backends (); |
||||
|
} |
||||
|
|
||||
|
inline void set_allocator (void *(*cb)(void *ptr, long size)) throw () |
||||
|
{ |
||||
|
ev_set_allocator (cb); |
||||
|
} |
||||
|
|
||||
|
inline void set_syserr_cb (void (*cb)(const char *msg)) throw () |
||||
|
{ |
||||
|
ev_set_syserr_cb (cb); |
||||
|
} |
||||
|
|
||||
|
#if EV_MULTIPLICITY |
||||
|
#define EV_CONSTRUCT(cppstem,cstem) \ |
||||
|
(EV_PX = get_default_loop ()) throw () \ |
||||
|
: base<ev_ ## cstem, cppstem> (EV_A) \ |
||||
|
{ \ |
||||
|
} |
||||
|
#else |
||||
|
#define EV_CONSTRUCT(cppstem,cstem) \ |
||||
|
() throw () \ |
||||
|
{ \ |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
/* using a template here would require quite a bit more lines,
|
||||
|
* so a macro solution was chosen */ |
||||
|
#define EV_BEGIN_WATCHER(cppstem,cstem) \ |
||||
|
\ |
||||
|
struct cppstem : base<ev_ ## cstem, cppstem> \ |
||||
|
{ \ |
||||
|
void start () throw () \ |
||||
|
{ \ |
||||
|
ev_ ## cstem ## _start (EV_A_ static_cast<ev_ ## cstem *>(this)); \ |
||||
|
} \ |
||||
|
\ |
||||
|
void stop () throw () \ |
||||
|
{ \ |
||||
|
ev_ ## cstem ## _stop (EV_A_ static_cast<ev_ ## cstem *>(this)); \ |
||||
|
} \ |
||||
|
\ |
||||
|
cppstem EV_CONSTRUCT(cppstem,cstem) \ |
||||
|
\ |
||||
|
~cppstem () throw () \ |
||||
|
{ \ |
||||
|
stop (); \ |
||||
|
} \ |
||||
|
\ |
||||
|
using base<ev_ ## cstem, cppstem>::set; \ |
||||
|
\ |
||||
|
private: \ |
||||
|
\ |
||||
|
cppstem (const cppstem &o); \ |
||||
|
\ |
||||
|
cppstem &operator =(const cppstem &o); \ |
||||
|
\ |
||||
|
public: |
||||
|
|
||||
|
#define EV_END_WATCHER(cppstem,cstem) \ |
||||
|
}; |
||||
|
|
||||
|
EV_BEGIN_WATCHER (io, io) |
||||
|
void set (int fd, int events) throw () |
||||
|
{ |
||||
|
int active = is_active (); |
||||
|
if (active) stop (); |
||||
|
ev_io_set (static_cast<ev_io *>(this), fd, events); |
||||
|
if (active) start (); |
||||
|
} |
||||
|
|
||||
|
void set (int events) throw () |
||||
|
{ |
||||
|
int active = is_active (); |
||||
|
if (active) stop (); |
||||
|
ev_io_set (static_cast<ev_io *>(this), fd, events); |
||||
|
if (active) start (); |
||||
|
} |
||||
|
|
||||
|
void start (int fd, int events) throw () |
||||
|
{ |
||||
|
set (fd, events); |
||||
|
start (); |
||||
|
} |
||||
|
EV_END_WATCHER (io, io) |
||||
|
|
||||
|
EV_BEGIN_WATCHER (timer, timer) |
||||
|
void set (ev_tstamp after, ev_tstamp repeat = 0.) throw () |
||||
|
{ |
||||
|
int active = is_active (); |
||||
|
if (active) stop (); |
||||
|
ev_timer_set (static_cast<ev_timer *>(this), after, repeat); |
||||
|
if (active) start (); |
||||
|
} |
||||
|
|
||||
|
void start (ev_tstamp after, ev_tstamp repeat = 0.) throw () |
||||
|
{ |
||||
|
set (after, repeat); |
||||
|
start (); |
||||
|
} |
||||
|
|
||||
|
void again () throw () |
||||
|
{ |
||||
|
ev_timer_again (EV_A_ static_cast<ev_timer *>(this)); |
||||
|
} |
||||
|
EV_END_WATCHER (timer, timer) |
||||
|
|
||||
|
#if EV_PERIODIC_ENABLE |
||||
|
EV_BEGIN_WATCHER (periodic, periodic) |
||||
|
void set (ev_tstamp at, ev_tstamp interval = 0.) throw () |
||||
|
{ |
||||
|
int active = is_active (); |
||||
|
if (active) stop (); |
||||
|
ev_periodic_set (static_cast<ev_periodic *>(this), at, interval, 0); |
||||
|
if (active) start (); |
||||
|
} |
||||
|
|
||||
|
void start (ev_tstamp at, ev_tstamp interval = 0.) throw () |
||||
|
{ |
||||
|
set (at, interval); |
||||
|
start (); |
||||
|
} |
||||
|
|
||||
|
void again () throw () |
||||
|
{ |
||||
|
ev_periodic_again (EV_A_ static_cast<ev_periodic *>(this)); |
||||
|
} |
||||
|
EV_END_WATCHER (periodic, periodic) |
||||
|
#endif |
||||
|
|
||||
|
EV_BEGIN_WATCHER (sig, signal) |
||||
|
void set (int signum) throw () |
||||
|
{ |
||||
|
int active = is_active (); |
||||
|
if (active) stop (); |
||||
|
ev_signal_set (static_cast<ev_signal *>(this), signum); |
||||
|
if (active) start (); |
||||
|
} |
||||
|
|
||||
|
void start (int signum) throw () |
||||
|
{ |
||||
|
set (signum); |
||||
|
start (); |
||||
|
} |
||||
|
EV_END_WATCHER (sig, signal) |
||||
|
|
||||
|
EV_BEGIN_WATCHER (child, child) |
||||
|
void set (int pid, int trace = 0) throw () |
||||
|
{ |
||||
|
int active = is_active (); |
||||
|
if (active) stop (); |
||||
|
ev_child_set (static_cast<ev_child *>(this), pid, trace); |
||||
|
if (active) start (); |
||||
|
} |
||||
|
|
||||
|
void start (int pid, int trace = 0) throw () |
||||
|
{ |
||||
|
set (pid, trace); |
||||
|
start (); |
||||
|
} |
||||
|
EV_END_WATCHER (child, child) |
||||
|
|
||||
|
#if EV_STAT_ENABLE |
||||
|
EV_BEGIN_WATCHER (stat, stat) |
||||
|
void set (const char *path, ev_tstamp interval = 0.) throw () |
||||
|
{ |
||||
|
int active = is_active (); |
||||
|
if (active) stop (); |
||||
|
ev_stat_set (static_cast<ev_stat *>(this), path, interval); |
||||
|
if (active) start (); |
||||
|
} |
||||
|
|
||||
|
void start (const char *path, ev_tstamp interval = 0.) throw () |
||||
|
{ |
||||
|
stop (); |
||||
|
set (path, interval); |
||||
|
start (); |
||||
|
} |
||||
|
|
||||
|
void update () throw () |
||||
|
{ |
||||
|
ev_stat_stat (EV_A_ static_cast<ev_stat *>(this)); |
||||
|
} |
||||
|
EV_END_WATCHER (stat, stat) |
||||
|
#endif |
||||
|
|
||||
|
EV_BEGIN_WATCHER (idle, idle) |
||||
|
void set () throw () { } |
||||
|
EV_END_WATCHER (idle, idle) |
||||
|
|
||||
|
EV_BEGIN_WATCHER (prepare, prepare) |
||||
|
void set () throw () { } |
||||
|
EV_END_WATCHER (prepare, prepare) |
||||
|
|
||||
|
EV_BEGIN_WATCHER (check, check) |
||||
|
void set () throw () { } |
||||
|
EV_END_WATCHER (check, check) |
||||
|
|
||||
|
#if EV_EMBED_ENABLE |
||||
|
EV_BEGIN_WATCHER (embed, embed) |
||||
|
void set (struct ev_loop *embedded_loop) throw () |
||||
|
{ |
||||
|
int active = is_active (); |
||||
|
if (active) stop (); |
||||
|
ev_embed_set (static_cast<ev_embed *>(this), embedded_loop); |
||||
|
if (active) start (); |
||||
|
} |
||||
|
|
||||
|
void start (struct ev_loop *embedded_loop) throw () |
||||
|
{ |
||||
|
set (embedded_loop); |
||||
|
start (); |
||||
|
} |
||||
|
|
||||
|
void sweep () |
||||
|
{ |
||||
|
ev_embed_sweep (EV_A_ static_cast<ev_embed *>(this)); |
||||
|
} |
||||
|
EV_END_WATCHER (embed, embed) |
||||
|
#endif |
||||
|
|
||||
|
#if EV_FORK_ENABLE |
||||
|
EV_BEGIN_WATCHER (fork, fork) |
||||
|
void set () throw () { } |
||||
|
EV_END_WATCHER (fork, fork) |
||||
|
#endif |
||||
|
|
||||
|
#if EV_ASYNC_ENABLE |
||||
|
EV_BEGIN_WATCHER (async, async) |
||||
|
void set () throw () { } |
||||
|
|
||||
|
void send () throw () |
||||
|
{ |
||||
|
ev_async_send (EV_A_ static_cast<ev_async *>(this)); |
||||
|
} |
||||
|
|
||||
|
bool async_pending () throw () |
||||
|
{ |
||||
|
return ev_async_pending (static_cast<ev_async *>(this)); |
||||
|
} |
||||
|
EV_END_WATCHER (async, async) |
||||
|
#endif |
||||
|
|
||||
|
#undef EV_PX |
||||
|
#undef EV_PX_ |
||||
|
#undef EV_CONSTRUCT |
||||
|
#undef EV_BEGIN_WATCHER |
||||
|
#undef EV_END_WATCHER |
||||
|
} |
||||
|
|
||||
|
#endif |
||||
|
|
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,648 @@ |
|||||
|
/*
|
||||
|
* libev native API header |
||||
|
* |
||||
|
* Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <libev@schmorp.de> |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without modifica- |
||||
|
* tion, 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 MER- |
||||
|
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- |
||||
|
* CIAL, 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 OTH- |
||||
|
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
* |
||||
|
* Alternatively, the contents of this file may be used under the terms of |
||||
|
* the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
* in which case the provisions of the GPL are applicable instead of |
||||
|
* the above. If you wish to allow the use of your version of this file |
||||
|
* only under the terms of the GPL and not to allow others to use your |
||||
|
* version of this file under the BSD license, indicate your decision |
||||
|
* by deleting the provisions above and replace them with the notice |
||||
|
* and other provisions required by the GPL. If you do not delete the |
||||
|
* provisions above, a recipient may use your version of this file under |
||||
|
* either the BSD or the GPL. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef EV_H__ |
||||
|
#define EV_H__ |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
typedef double ev_tstamp; |
||||
|
|
||||
|
/* these priorities are inclusive, higher priorities will be called earlier */ |
||||
|
#ifndef EV_MINPRI |
||||
|
# define EV_MINPRI -2 |
||||
|
#endif |
||||
|
#ifndef EV_MAXPRI |
||||
|
# define EV_MAXPRI +2 |
||||
|
#endif |
||||
|
|
||||
|
#ifndef EV_MULTIPLICITY |
||||
|
# define EV_MULTIPLICITY 1 |
||||
|
#endif |
||||
|
|
||||
|
#ifndef EV_PERIODIC_ENABLE |
||||
|
# define EV_PERIODIC_ENABLE 1 |
||||
|
#endif |
||||
|
|
||||
|
#ifndef EV_STAT_ENABLE |
||||
|
# define EV_STAT_ENABLE 1 |
||||
|
#endif |
||||
|
|
||||
|
#ifndef EV_IDLE_ENABLE |
||||
|
# define EV_IDLE_ENABLE 1 |
||||
|
#endif |
||||
|
|
||||
|
#ifndef EV_FORK_ENABLE |
||||
|
# define EV_FORK_ENABLE 1 |
||||
|
#endif |
||||
|
|
||||
|
#ifndef EV_EMBED_ENABLE |
||||
|
# define EV_EMBED_ENABLE 1 |
||||
|
#endif |
||||
|
|
||||
|
#ifndef EV_ASYNC_ENABLE |
||||
|
# define EV_ASYNC_ENABLE 1 |
||||
|
#endif |
||||
|
|
||||
|
#ifndef EV_ATOMIC_T |
||||
|
# include <signal.h> |
||||
|
# define EV_ATOMIC_T sig_atomic_t volatile |
||||
|
#endif |
||||
|
|
||||
|
/*****************************************************************************/ |
||||
|
|
||||
|
#if EV_STAT_ENABLE |
||||
|
# ifdef _WIN32 |
||||
|
# include <time.h> |
||||
|
# include <sys/types.h> |
||||
|
# endif |
||||
|
# include <sys/stat.h> |
||||
|
#endif |
||||
|
|
||||
|
/* support multiple event loops? */ |
||||
|
#if EV_MULTIPLICITY |
||||
|
struct ev_loop; |
||||
|
# define EV_P struct ev_loop *loop |
||||
|
# define EV_P_ EV_P, |
||||
|
# define EV_A loop |
||||
|
# define EV_A_ EV_A, |
||||
|
# define EV_DEFAULT_UC ev_default_loop_uc () |
||||
|
# define EV_DEFAULT_UC_ EV_DEFAULT_UC, |
||||
|
# define EV_DEFAULT ev_default_loop (0) |
||||
|
# define EV_DEFAULT_ EV_DEFAULT, |
||||
|
#else |
||||
|
# define EV_P void |
||||
|
# define EV_P_ |
||||
|
# define EV_A |
||||
|
# define EV_A_ |
||||
|
# define EV_DEFAULT |
||||
|
# define EV_DEFAULT_ |
||||
|
# define EV_DEFAULT_UC |
||||
|
# define EV_DEFAULT_UC_ |
||||
|
# undef EV_EMBED_ENABLE |
||||
|
#endif |
||||
|
|
||||
|
#if __STDC_VERSION__ >= 199901L || __GNUC__ >= 3 |
||||
|
# define EV_INLINE static inline |
||||
|
#else |
||||
|
# define EV_INLINE static |
||||
|
#endif |
||||
|
|
||||
|
/*****************************************************************************/ |
||||
|
|
||||
|
/* eventmask, revents, events... */ |
||||
|
#define EV_UNDEF -1 /* guaranteed to be invalid */ |
||||
|
#define EV_NONE 0x00 /* no events */ |
||||
|
#define EV_READ 0x01 /* ev_io detected read will not block */ |
||||
|
#define EV_WRITE 0x02 /* ev_io detected write will not block */ |
||||
|
#define EV_IOFDSET 0x80 /* internal use only */ |
||||
|
#define EV_TIMEOUT 0x00000100 /* timer timed out */ |
||||
|
#define EV_PERIODIC 0x00000200 /* periodic timer timed out */ |
||||
|
#define EV_SIGNAL 0x00000400 /* signal was received */ |
||||
|
#define EV_CHILD 0x00000800 /* child/pid had status change */ |
||||
|
#define EV_STAT 0x00001000 /* stat data changed */ |
||||
|
#define EV_IDLE 0x00002000 /* event loop is idling */ |
||||
|
#define EV_PREPARE 0x00004000 /* event loop about to poll */ |
||||
|
#define EV_CHECK 0x00008000 /* event loop finished poll */ |
||||
|
#define EV_EMBED 0x00010000 /* embedded event loop needs sweep */ |
||||
|
#define EV_FORK 0x00020000 /* event loop resumed in child */ |
||||
|
#define EV_ASYNC 0x00040000 /* async intra-loop signal */ |
||||
|
#define EV_ERROR 0x80000000 /* sent when an error occurs */ |
||||
|
|
||||
|
/* can be used to add custom fields to all watchers, while losing binary compatibility */ |
||||
|
#ifndef EV_COMMON |
||||
|
# define EV_COMMON void *data; |
||||
|
#endif |
||||
|
#ifndef EV_PROTOTYPES |
||||
|
# define EV_PROTOTYPES 1 |
||||
|
#endif |
||||
|
|
||||
|
#define EV_VERSION_MAJOR 3 |
||||
|
#define EV_VERSION_MINOR 0 |
||||
|
|
||||
|
#ifndef EV_CB_DECLARE |
||||
|
# define EV_CB_DECLARE(type) void (*cb)(EV_P_ struct type *w, int revents); |
||||
|
#endif |
||||
|
#ifndef EV_CB_INVOKE |
||||
|
# define EV_CB_INVOKE(watcher,revents) (watcher)->cb (EV_A_ (watcher), (revents)) |
||||
|
#endif |
||||
|
|
||||
|
/*
|
||||
|
* struct member types: |
||||
|
* private: you may look at them, but not change them, |
||||
|
* and they might not mean anything to you. |
||||
|
* ro: can be read anytime, but only changed when the watcher isn't active. |
||||
|
* rw: can be read and modified anytime, even when the watcher is active. |
||||
|
* |
||||
|
* some internal details that might be helpful for debugging: |
||||
|
* |
||||
|
* active is either 0, which means the watcher is not active, |
||||
|
* or the array index of the watcher (periodics, timers) |
||||
|
* or the array index + 1 (most other watchers) |
||||
|
* or simply 1 for watchers that aren't in some array. |
||||
|
* pending is either 0, in which case the watcher isn't, |
||||
|
* or the array index + 1 in the pendings array. |
||||
|
*/ |
||||
|
|
||||
|
/* shared by all watchers */ |
||||
|
#define EV_WATCHER(type) \ |
||||
|
int active; /* private */ \ |
||||
|
int pending; /* private */ \ |
||||
|
int priority; /* private */ \ |
||||
|
EV_COMMON /* rw */ \ |
||||
|
EV_CB_DECLARE (type) /* private */ |
||||
|
|
||||
|
#define EV_WATCHER_LIST(type) \ |
||||
|
EV_WATCHER (type) \ |
||||
|
struct ev_watcher_list *next; /* private */ |
||||
|
|
||||
|
#define EV_WATCHER_TIME(type) \ |
||||
|
EV_WATCHER (type) \ |
||||
|
ev_tstamp at; /* private */ |
||||
|
|
||||
|
/* base class, nothing to see here unless you subclass */ |
||||
|
typedef struct ev_watcher |
||||
|
{ |
||||
|
EV_WATCHER (ev_watcher) |
||||
|
} ev_watcher; |
||||
|
|
||||
|
/* base class, nothing to see here unless you subclass */ |
||||
|
typedef struct ev_watcher_list |
||||
|
{ |
||||
|
EV_WATCHER_LIST (ev_watcher_list) |
||||
|
} ev_watcher_list; |
||||
|
|
||||
|
/* base class, nothing to see here unless you subclass */ |
||||
|
typedef struct ev_watcher_time |
||||
|
{ |
||||
|
EV_WATCHER_TIME (ev_watcher_time) |
||||
|
} ev_watcher_time; |
||||
|
|
||||
|
/* invoked when fd is either EV_READable or EV_WRITEable */ |
||||
|
/* revent EV_READ, EV_WRITE */ |
||||
|
typedef struct ev_io |
||||
|
{ |
||||
|
EV_WATCHER_LIST (ev_io) |
||||
|
|
||||
|
int fd; /* ro */ |
||||
|
int events; /* ro */ |
||||
|
} ev_io; |
||||
|
|
||||
|
/* invoked after a specific time, repeatable (based on monotonic clock) */ |
||||
|
/* revent EV_TIMEOUT */ |
||||
|
typedef struct ev_timer |
||||
|
{ |
||||
|
EV_WATCHER_TIME (ev_timer) |
||||
|
|
||||
|
ev_tstamp repeat; /* rw */ |
||||
|
} ev_timer; |
||||
|
|
||||
|
/* invoked at some specific time, possibly repeating at regular intervals (based on UTC) */ |
||||
|
/* revent EV_PERIODIC */ |
||||
|
typedef struct ev_periodic |
||||
|
{ |
||||
|
EV_WATCHER_TIME (ev_periodic) |
||||
|
|
||||
|
ev_tstamp offset; /* rw */ |
||||
|
ev_tstamp interval; /* rw */ |
||||
|
ev_tstamp (*reschedule_cb)(struct ev_periodic *w, ev_tstamp now); /* rw */ |
||||
|
} ev_periodic; |
||||
|
|
||||
|
/* invoked when the given signal has been received */ |
||||
|
/* revent EV_SIGNAL */ |
||||
|
typedef struct ev_signal |
||||
|
{ |
||||
|
EV_WATCHER_LIST (ev_signal) |
||||
|
|
||||
|
int signum; /* ro */ |
||||
|
} ev_signal; |
||||
|
|
||||
|
/* invoked when sigchld is received and waitpid indicates the given pid */ |
||||
|
/* revent EV_CHILD */ |
||||
|
/* does not support priorities */ |
||||
|
typedef struct ev_child |
||||
|
{ |
||||
|
EV_WATCHER_LIST (ev_child) |
||||
|
|
||||
|
int flags; /* private */ |
||||
|
int pid; /* ro */ |
||||
|
int rpid; /* rw, holds the received pid */ |
||||
|
int rstatus; /* rw, holds the exit status, use the macros from sys/wait.h */ |
||||
|
} ev_child; |
||||
|
|
||||
|
#if EV_STAT_ENABLE |
||||
|
/* st_nlink = 0 means missing file or other error */ |
||||
|
# ifdef _WIN32 |
||||
|
typedef struct _stati64 ev_statdata; |
||||
|
# else |
||||
|
typedef struct stat ev_statdata; |
||||
|
# endif |
||||
|
|
||||
|
/* invoked each time the stat data changes for a given path */ |
||||
|
/* revent EV_STAT */ |
||||
|
typedef struct ev_stat |
||||
|
{ |
||||
|
EV_WATCHER_LIST (ev_stat) |
||||
|
|
||||
|
ev_timer timer; /* private */ |
||||
|
ev_tstamp interval; /* ro */ |
||||
|
const char *path; /* ro */ |
||||
|
ev_statdata prev; /* ro */ |
||||
|
ev_statdata attr; /* ro */ |
||||
|
|
||||
|
int wd; /* wd for inotify, fd for kqueue */ |
||||
|
} ev_stat; |
||||
|
#endif |
||||
|
|
||||
|
#if EV_IDLE_ENABLE |
||||
|
/* invoked when the nothing else needs to be done, keeps the process from blocking */ |
||||
|
/* revent EV_IDLE */ |
||||
|
typedef struct ev_idle |
||||
|
{ |
||||
|
EV_WATCHER (ev_idle) |
||||
|
} ev_idle; |
||||
|
#endif |
||||
|
|
||||
|
/* invoked for each run of the mainloop, just before the blocking call */ |
||||
|
/* you can still change events in any way you like */ |
||||
|
/* revent EV_PREPARE */ |
||||
|
typedef struct ev_prepare |
||||
|
{ |
||||
|
EV_WATCHER (ev_prepare) |
||||
|
} ev_prepare; |
||||
|
|
||||
|
/* invoked for each run of the mainloop, just after the blocking call */ |
||||
|
/* revent EV_CHECK */ |
||||
|
typedef struct ev_check |
||||
|
{ |
||||
|
EV_WATCHER (ev_check) |
||||
|
} ev_check; |
||||
|
|
||||
|
#if EV_FORK_ENABLE |
||||
|
/* the callback gets invoked before check in the child process when a fork was detected */ |
||||
|
typedef struct ev_fork |
||||
|
{ |
||||
|
EV_WATCHER (ev_fork) |
||||
|
} ev_fork; |
||||
|
#endif |
||||
|
|
||||
|
#if EV_EMBED_ENABLE |
||||
|
/* used to embed an event loop inside another */ |
||||
|
/* the callback gets invoked when the event loop has handled events, and can be 0 */ |
||||
|
typedef struct ev_embed |
||||
|
{ |
||||
|
EV_WATCHER (ev_embed) |
||||
|
|
||||
|
struct ev_loop *other; /* ro */ |
||||
|
ev_io io; /* private */ |
||||
|
ev_prepare prepare; /* private */ |
||||
|
ev_check check; /* unused */ |
||||
|
ev_timer timer; /* unused */ |
||||
|
ev_periodic periodic; /* unused */ |
||||
|
ev_idle idle; /* unused */ |
||||
|
ev_fork fork; /* private */ |
||||
|
} ev_embed; |
||||
|
#endif |
||||
|
|
||||
|
#if EV_ASYNC_ENABLE |
||||
|
/* invoked when somebody calls ev_async_send on the watcher */ |
||||
|
/* revent EV_ASYNC */ |
||||
|
typedef struct ev_async |
||||
|
{ |
||||
|
EV_WATCHER (ev_async) |
||||
|
|
||||
|
EV_ATOMIC_T sent; /* private */ |
||||
|
} ev_async; |
||||
|
|
||||
|
# define ev_async_pending(w) ((w)->sent + 0) |
||||
|
#endif |
||||
|
|
||||
|
/* the presence of this union forces similar struct layout */ |
||||
|
union ev_any_watcher |
||||
|
{ |
||||
|
struct ev_watcher w; |
||||
|
struct ev_watcher_list wl; |
||||
|
|
||||
|
struct ev_io io; |
||||
|
struct ev_timer timer; |
||||
|
struct ev_periodic periodic; |
||||
|
struct ev_signal signal; |
||||
|
struct ev_child child; |
||||
|
#if EV_STAT_ENABLE |
||||
|
struct ev_stat stat; |
||||
|
#endif |
||||
|
#if EV_IDLE_ENABLE |
||||
|
struct ev_idle idle; |
||||
|
#endif |
||||
|
struct ev_prepare prepare; |
||||
|
struct ev_check check; |
||||
|
#if EV_FORK_ENABLE |
||||
|
struct ev_fork fork; |
||||
|
#endif |
||||
|
#if EV_EMBED_ENABLE |
||||
|
struct ev_embed embed; |
||||
|
#endif |
||||
|
#if EV_ASYNC_ENABLE |
||||
|
struct ev_async async; |
||||
|
#endif |
||||
|
}; |
||||
|
|
||||
|
/* bits for ev_default_loop and ev_loop_new */ |
||||
|
/* the default */ |
||||
|
#define EVFLAG_AUTO 0x00000000U /* not quite a mask */ |
||||
|
/* flag bits */ |
||||
|
#define EVFLAG_NOENV 0x01000000U /* do NOT consult environment */ |
||||
|
#define EVFLAG_FORKCHECK 0x02000000U /* check for a fork in each iteration */ |
||||
|
/* method bits to be ored together */ |
||||
|
#define EVBACKEND_SELECT 0x00000001U /* about anywhere */ |
||||
|
#define EVBACKEND_POLL 0x00000002U /* !win */ |
||||
|
#define EVBACKEND_EPOLL 0x00000004U /* linux */ |
||||
|
#define EVBACKEND_KQUEUE 0x00000008U /* bsd */ |
||||
|
#define EVBACKEND_DEVPOLL 0x00000010U /* solaris 8 */ /* NYI */ |
||||
|
#define EVBACKEND_PORT 0x00000020U /* solaris 10 */ |
||||
|
|
||||
|
#if EV_PROTOTYPES |
||||
|
int ev_version_major (void); |
||||
|
int ev_version_minor (void); |
||||
|
|
||||
|
unsigned int ev_supported_backends (void); |
||||
|
unsigned int ev_recommended_backends (void); |
||||
|
unsigned int ev_embeddable_backends (void); |
||||
|
|
||||
|
ev_tstamp ev_time (void); |
||||
|
void ev_sleep (ev_tstamp delay); /* sleep for a while */ |
||||
|
|
||||
|
/* Sets the allocation function to use, works like realloc.
|
||||
|
* It is used to allocate and free memory. |
||||
|
* If it returns zero when memory needs to be allocated, the library might abort |
||||
|
* or take some potentially destructive action. |
||||
|
* The default is your system realloc function. |
||||
|
*/ |
||||
|
void ev_set_allocator (void *(*cb)(void *ptr, long size)); |
||||
|
|
||||
|
/* set the callback function to call on a
|
||||
|
* retryable syscall error |
||||
|
* (such as failed select, poll, epoll_wait) |
||||
|
*/ |
||||
|
void ev_set_syserr_cb (void (*cb)(const char *msg)); |
||||
|
|
||||
|
#if EV_MULTIPLICITY |
||||
|
EV_INLINE struct ev_loop * |
||||
|
ev_default_loop_uc (void) |
||||
|
{ |
||||
|
extern struct ev_loop *ev_default_loop_ptr; |
||||
|
|
||||
|
return ev_default_loop_ptr; |
||||
|
} |
||||
|
|
||||
|
/* the default loop is the only one that handles signals and child watchers */ |
||||
|
/* you can call this as often as you like */ |
||||
|
EV_INLINE struct ev_loop * |
||||
|
ev_default_loop (unsigned int flags) |
||||
|
{ |
||||
|
struct ev_loop *loop = ev_default_loop_uc (); |
||||
|
|
||||
|
if (!loop) |
||||
|
{ |
||||
|
extern struct ev_loop *ev_default_loop_init (unsigned int flags); |
||||
|
|
||||
|
loop = ev_default_loop_init (flags); |
||||
|
} |
||||
|
|
||||
|
return loop; |
||||
|
} |
||||
|
|
||||
|
/* create and destroy alternative loops that don't handle signals */ |
||||
|
struct ev_loop *ev_loop_new (unsigned int flags); |
||||
|
void ev_loop_destroy (EV_P); |
||||
|
void ev_loop_fork (EV_P); |
||||
|
void ev_loop_verify (EV_P); |
||||
|
|
||||
|
ev_tstamp ev_now (EV_P); /* time w.r.t. timers and the eventloop, updated after each poll */ |
||||
|
void ev_now_update (EV_P); |
||||
|
|
||||
|
#else |
||||
|
|
||||
|
int ev_default_loop (unsigned int flags); /* returns true when successful */ |
||||
|
|
||||
|
EV_INLINE ev_tstamp |
||||
|
ev_now (void) |
||||
|
{ |
||||
|
extern ev_tstamp ev_rt_now; |
||||
|
|
||||
|
return ev_rt_now; |
||||
|
} |
||||
|
#endif /* multiplicity */ |
||||
|
|
||||
|
EV_INLINE int |
||||
|
ev_is_default_loop (EV_P) |
||||
|
{ |
||||
|
#if EV_MULTIPLICITY |
||||
|
extern struct ev_loop *ev_default_loop_ptr; |
||||
|
|
||||
|
return !!(EV_A == ev_default_loop_ptr); |
||||
|
#else |
||||
|
return 1; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
void ev_default_destroy (void); /* destroy the default loop */ |
||||
|
/* this needs to be called after fork, to duplicate the default loop */ |
||||
|
/* if you create alternative loops you have to call ev_loop_fork on them */ |
||||
|
/* you can call it in either the parent or the child */ |
||||
|
/* you can actually call it at any time, anywhere :) */ |
||||
|
void ev_default_fork (void); |
||||
|
|
||||
|
unsigned int ev_backend (EV_P); /* backend in use by loop */ |
||||
|
unsigned int ev_loop_count (EV_P); /* number of loop iterations */ |
||||
|
#endif /* prototypes */ |
||||
|
|
||||
|
#define EVLOOP_NONBLOCK 1 /* do not block/wait */ |
||||
|
#define EVLOOP_ONESHOT 2 /* block *once* only */ |
||||
|
#define EVUNLOOP_CANCEL 0 /* undo unloop */ |
||||
|
#define EVUNLOOP_ONE 1 /* unloop once */ |
||||
|
#define EVUNLOOP_ALL 2 /* unloop all loops */ |
||||
|
|
||||
|
#if EV_PROTOTYPES |
||||
|
void ev_loop (EV_P_ int flags); |
||||
|
void ev_unloop (EV_P_ int how); /* set to 1 to break out of event loop, set to 2 to break out of all event loops */ |
||||
|
|
||||
|
void ev_set_io_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ |
||||
|
void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ |
||||
|
|
||||
|
/*
|
||||
|
* ref/unref can be used to add or remove a refcount on the mainloop. every watcher |
||||
|
* keeps one reference. if you have a long-runing watcher you never unregister that |
||||
|
* should not keep ev_loop from running, unref() after starting, and ref() before stopping. |
||||
|
*/ |
||||
|
void ev_ref (EV_P); |
||||
|
void ev_unref (EV_P); |
||||
|
|
||||
|
/* convenience function, wait for a single event, without registering an event watcher */ |
||||
|
/* if timeout is < 0, do wait indefinitely */ |
||||
|
void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg); |
||||
|
#endif |
||||
|
|
||||
|
/* these may evaluate ev multiple times, and the other arguments at most once */ |
||||
|
/* either use ev_init + ev_TYPE_set, or the ev_TYPE_init macro, below, to first initialise a watcher */ |
||||
|
#define ev_init(ev,cb_) do { \ |
||||
|
((ev_watcher *)(void *)(ev))->active = \ |
||||
|
((ev_watcher *)(void *)(ev))->pending = \ |
||||
|
((ev_watcher *)(void *)(ev))->priority = 0; \ |
||||
|
ev_set_cb ((ev), cb_); \ |
||||
|
} while (0) |
||||
|
|
||||
|
#define ev_io_set(ev,fd_,events_) do { (ev)->fd = (fd_); (ev)->events = (events_) | EV_IOFDSET; } while (0) |
||||
|
#define ev_timer_set(ev,after_,repeat_) do { ((ev_watcher_time *)(ev))->at = (after_); (ev)->repeat = (repeat_); } while (0) |
||||
|
#define ev_periodic_set(ev,ofs_,ival_,res_) do { (ev)->offset = (ofs_); (ev)->interval = (ival_); (ev)->reschedule_cb= (res_); } while (0) |
||||
|
#define ev_signal_set(ev,signum_) do { (ev)->signum = (signum_); } while (0) |
||||
|
#define ev_child_set(ev,pid_,trace_) do { (ev)->pid = (pid_); (ev)->flags = !!(trace_); } while (0) |
||||
|
#define ev_stat_set(ev,path_,interval_) do { (ev)->path = (path_); (ev)->interval = (interval_); (ev)->wd = -2; } while (0) |
||||
|
#define ev_idle_set(ev) /* nop, yes, this is a serious in-joke */ |
||||
|
#define ev_prepare_set(ev) /* nop, yes, this is a serious in-joke */ |
||||
|
#define ev_check_set(ev) /* nop, yes, this is a serious in-joke */ |
||||
|
#define ev_embed_set(ev,other_) do { (ev)->other = (other_); } while (0) |
||||
|
#define ev_fork_set(ev) /* nop, yes, this is a serious in-joke */ |
||||
|
#define ev_async_set(ev) do { (ev)->sent = 0; } while (0) |
||||
|
|
||||
|
#define ev_io_init(ev,cb,fd,events) do { ev_init ((ev), (cb)); ev_io_set ((ev),(fd),(events)); } while (0) |
||||
|
#define ev_timer_init(ev,cb,after,repeat) do { ev_init ((ev), (cb)); ev_timer_set ((ev),(after),(repeat)); } while (0) |
||||
|
#define ev_periodic_init(ev,cb,at,ival,res) do { ev_init ((ev), (cb)); ev_periodic_set ((ev),(at),(ival),(res)); } while (0) |
||||
|
#define ev_signal_init(ev,cb,signum) do { ev_init ((ev), (cb)); ev_signal_set ((ev), (signum)); } while (0) |
||||
|
#define ev_child_init(ev,cb,pid,trace) do { ev_init ((ev), (cb)); ev_child_set ((ev),(pid),(trace)); } while (0) |
||||
|
#define ev_stat_init(ev,cb,path,interval) do { ev_init ((ev), (cb)); ev_stat_set ((ev),(path),(interval)); } while (0) |
||||
|
#define ev_idle_init(ev,cb) do { ev_init ((ev), (cb)); ev_idle_set ((ev)); } while (0) |
||||
|
#define ev_prepare_init(ev,cb) do { ev_init ((ev), (cb)); ev_prepare_set ((ev)); } while (0) |
||||
|
#define ev_check_init(ev,cb) do { ev_init ((ev), (cb)); ev_check_set ((ev)); } while (0) |
||||
|
#define ev_embed_init(ev,cb,other) do { ev_init ((ev), (cb)); ev_embed_set ((ev),(other)); } while (0) |
||||
|
#define ev_fork_init(ev,cb) do { ev_init ((ev), (cb)); ev_fork_set ((ev)); } while (0) |
||||
|
#define ev_async_init(ev,cb) do { ev_init ((ev), (cb)); ev_async_set ((ev)); } while (0) |
||||
|
|
||||
|
#define ev_is_pending(ev) (0 + ((ev_watcher *)(void *)(ev))->pending) /* ro, true when watcher is waiting for callback invocation */ |
||||
|
#define ev_is_active(ev) (0 + ((ev_watcher *)(void *)(ev))->active) /* ro, true when the watcher has been started */ |
||||
|
|
||||
|
#define ev_priority(ev) ((((ev_watcher *)(void *)(ev))->priority) + 0) |
||||
|
#define ev_cb(ev) (ev)->cb /* rw */ |
||||
|
#define ev_set_priority(ev,pri) ((ev_watcher *)(void *)(ev))->priority = (pri) |
||||
|
|
||||
|
#define ev_periodic_at(ev) (((ev_watcher_time *)(ev))->at + 0.) |
||||
|
|
||||
|
#ifndef ev_set_cb |
||||
|
# define ev_set_cb(ev,cb_) ev_cb (ev) = (cb_) |
||||
|
#endif |
||||
|
|
||||
|
/* stopping (enabling, adding) a watcher does nothing if it is already running */ |
||||
|
/* stopping (disabling, deleting) a watcher does nothing unless its already running */ |
||||
|
#if EV_PROTOTYPES |
||||
|
|
||||
|
/* feeds an event into a watcher as if the event actually occured */ |
||||
|
/* accepts any ev_watcher type */ |
||||
|
void ev_feed_event (EV_P_ void *w, int revents); |
||||
|
void ev_feed_fd_event (EV_P_ int fd, int revents); |
||||
|
void ev_feed_signal_event (EV_P_ int signum); |
||||
|
void ev_invoke (EV_P_ void *w, int revents); |
||||
|
int ev_clear_pending (EV_P_ void *w); |
||||
|
|
||||
|
void ev_io_start (EV_P_ ev_io *w); |
||||
|
void ev_io_stop (EV_P_ ev_io *w); |
||||
|
|
||||
|
void ev_timer_start (EV_P_ ev_timer *w); |
||||
|
void ev_timer_stop (EV_P_ ev_timer *w); |
||||
|
/* stops if active and no repeat, restarts if active and repeating, starts if inactive and repeating */ |
||||
|
void ev_timer_again (EV_P_ ev_timer *w); |
||||
|
|
||||
|
#if EV_PERIODIC_ENABLE |
||||
|
void ev_periodic_start (EV_P_ ev_periodic *w); |
||||
|
void ev_periodic_stop (EV_P_ ev_periodic *w); |
||||
|
void ev_periodic_again (EV_P_ ev_periodic *w); |
||||
|
#endif |
||||
|
|
||||
|
/* only supported in the default loop */ |
||||
|
void ev_signal_start (EV_P_ ev_signal *w); |
||||
|
void ev_signal_stop (EV_P_ ev_signal *w); |
||||
|
|
||||
|
/* only supported in the default loop */ |
||||
|
void ev_child_start (EV_P_ ev_child *w); |
||||
|
void ev_child_stop (EV_P_ ev_child *w); |
||||
|
|
||||
|
# if EV_STAT_ENABLE |
||||
|
void ev_stat_start (EV_P_ ev_stat *w); |
||||
|
void ev_stat_stop (EV_P_ ev_stat *w); |
||||
|
void ev_stat_stat (EV_P_ ev_stat *w); |
||||
|
# endif |
||||
|
|
||||
|
# if EV_IDLE_ENABLE |
||||
|
void ev_idle_start (EV_P_ ev_idle *w); |
||||
|
void ev_idle_stop (EV_P_ ev_idle *w); |
||||
|
# endif |
||||
|
|
||||
|
void ev_prepare_start (EV_P_ ev_prepare *w); |
||||
|
void ev_prepare_stop (EV_P_ ev_prepare *w); |
||||
|
|
||||
|
void ev_check_start (EV_P_ ev_check *w); |
||||
|
void ev_check_stop (EV_P_ ev_check *w); |
||||
|
|
||||
|
# if EV_FORK_ENABLE |
||||
|
void ev_fork_start (EV_P_ ev_fork *w); |
||||
|
void ev_fork_stop (EV_P_ ev_fork *w); |
||||
|
# endif |
||||
|
|
||||
|
# if EV_EMBED_ENABLE |
||||
|
/* only supported when loop to be embedded is in fact embeddable */ |
||||
|
void ev_embed_start (EV_P_ ev_embed *w); |
||||
|
void ev_embed_stop (EV_P_ ev_embed *w); |
||||
|
void ev_embed_sweep (EV_P_ ev_embed *w); |
||||
|
# endif |
||||
|
|
||||
|
# if EV_ASYNC_ENABLE |
||||
|
void ev_async_start (EV_P_ ev_async *w); |
||||
|
void ev_async_stop (EV_P_ ev_async *w); |
||||
|
void ev_async_send (EV_P_ ev_async *w); |
||||
|
# endif |
||||
|
|
||||
|
#endif |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
File diff suppressed because it is too large
@ -0,0 +1,215 @@ |
|||||
|
/*
|
||||
|
* libev epoll fd activity backend |
||||
|
* |
||||
|
* Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de> |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without modifica- |
||||
|
* tion, 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 MER- |
||||
|
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- |
||||
|
* CIAL, 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 OTH- |
||||
|
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
* |
||||
|
* Alternatively, the contents of this file may be used under the terms of |
||||
|
* the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
* in which case the provisions of the GPL are applicable instead of |
||||
|
* the above. If you wish to allow the use of your version of this file |
||||
|
* only under the terms of the GPL and not to allow others to use your |
||||
|
* version of this file under the BSD license, indicate your decision |
||||
|
* by deleting the provisions above and replace them with the notice |
||||
|
* and other provisions required by the GPL. If you do not delete the |
||||
|
* provisions above, a recipient may use your version of this file under |
||||
|
* either the BSD or the GPL. |
||||
|
*/ |
||||
|
|
||||
|
/*
|
||||
|
* general notes about epoll: |
||||
|
* |
||||
|
* a) epoll silently removes fds from the fd set. as nothing tells us |
||||
|
* that an fd has been removed otherwise, we have to continually |
||||
|
* "rearm" fds that we suspect *might* have changed (same |
||||
|
* problem with kqueue, but much less costly there). |
||||
|
* b) the fact that ADD != MOD creates a lot of extra syscalls due to a) |
||||
|
* and seems not to have any advantage. |
||||
|
* c) the inability to handle fork or file descriptors (think dup) |
||||
|
* limits the applicability over poll, so this is not a generic |
||||
|
* poll replacement. |
||||
|
* |
||||
|
* lots of "weird code" and complication handling in this file is due |
||||
|
* to these design problems with epoll, as we try very hard to avoid |
||||
|
* epoll_ctl syscalls for common usage patterns and handle the breakage |
||||
|
* ensuing from receiving events for closed and otherwise long gone |
||||
|
* file descriptors. |
||||
|
*/ |
||||
|
|
||||
|
#include <sys/epoll.h> |
||||
|
|
||||
|
static void |
||||
|
epoll_modify (EV_P_ int fd, int oev, int nev) |
||||
|
{ |
||||
|
struct epoll_event ev; |
||||
|
unsigned char oldmask; |
||||
|
|
||||
|
/*
|
||||
|
* we handle EPOLL_CTL_DEL by ignoring it here |
||||
|
* on the assumption that the fd is gone anyways |
||||
|
* if that is wrong, we have to handle the spurious |
||||
|
* event in epoll_poll. |
||||
|
* if the fd is added again, we try to ADD it, and, if that |
||||
|
* fails, we assume it still has the same eventmask. |
||||
|
*/ |
||||
|
if (!nev) |
||||
|
return; |
||||
|
|
||||
|
oldmask = anfds [fd].emask; |
||||
|
anfds [fd].emask = nev; |
||||
|
|
||||
|
/* store the generation counter in the upper 32 bits, the fd in the lower 32 bits */ |
||||
|
ev.data.u64 = (uint64_t)(uint32_t)fd |
||||
|
| ((uint64_t)(uint32_t)++anfds [fd].egen << 32); |
||||
|
ev.events = (nev & EV_READ ? EPOLLIN : 0) |
||||
|
| (nev & EV_WRITE ? EPOLLOUT : 0); |
||||
|
|
||||
|
if (expect_true (!epoll_ctl (backend_fd, oev ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, fd, &ev))) |
||||
|
return; |
||||
|
|
||||
|
if (expect_true (errno == ENOENT)) |
||||
|
{ |
||||
|
/* if ENOENT then the fd went away, so try to do the right thing */ |
||||
|
if (!nev) |
||||
|
goto dec_egen; |
||||
|
|
||||
|
if (!epoll_ctl (backend_fd, EPOLL_CTL_ADD, fd, &ev)) |
||||
|
return; |
||||
|
} |
||||
|
else if (expect_true (errno == EEXIST)) |
||||
|
{ |
||||
|
/* EEXIST means we ignored a previous DEL, but the fd is still active */ |
||||
|
/* if the kernel mask is the same as the new mask, we assume it hasn't changed */ |
||||
|
if (oldmask == nev) |
||||
|
goto dec_egen; |
||||
|
|
||||
|
if (!epoll_ctl (backend_fd, EPOLL_CTL_MOD, fd, &ev)) |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
fd_kill (EV_A_ fd); |
||||
|
|
||||
|
dec_egen: |
||||
|
/* we didn't successfully call epoll_ctl, so decrement the generation counter again */ |
||||
|
--anfds [fd].egen; |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
epoll_poll (EV_P_ ev_tstamp timeout) |
||||
|
{ |
||||
|
int i; |
||||
|
int eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax, (int)ceil (timeout * 1000.)); |
||||
|
|
||||
|
if (expect_false (eventcnt < 0)) |
||||
|
{ |
||||
|
if (errno != EINTR) |
||||
|
ev_syserr ("(libev) epoll_wait"); |
||||
|
|
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
for (i = 0; i < eventcnt; ++i) |
||||
|
{ |
||||
|
struct epoll_event *ev = epoll_events + i; |
||||
|
|
||||
|
int fd = (uint32_t)ev->data.u64; /* mask out the lower 32 bits */ |
||||
|
int want = anfds [fd].events; |
||||
|
int got = (ev->events & (EPOLLOUT | EPOLLERR | EPOLLHUP) ? EV_WRITE : 0) |
||||
|
| (ev->events & (EPOLLIN | EPOLLERR | EPOLLHUP) ? EV_READ : 0); |
||||
|
|
||||
|
/* check for spurious notification */ |
||||
|
if (expect_false ((uint32_t)anfds [fd].egen != (uint32_t)(ev->data.u64 >> 32))) |
||||
|
{ |
||||
|
/* recreate kernel state */ |
||||
|
postfork = 1; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (expect_false (got & ~want)) |
||||
|
{ |
||||
|
anfds [fd].emask = want; |
||||
|
|
||||
|
/* we received an event but are not interested in it, try mod or del */ |
||||
|
/* I don't think we ever need MOD, but let's handle it anyways */ |
||||
|
ev->events = (want & EV_READ ? EPOLLIN : 0) |
||||
|
| (want & EV_WRITE ? EPOLLOUT : 0); |
||||
|
|
||||
|
if (epoll_ctl (backend_fd, want ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, fd, ev)) |
||||
|
{ |
||||
|
postfork = 1; /* an error occured, recreate kernel state */ |
||||
|
continue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
fd_event (EV_A_ fd, got); |
||||
|
} |
||||
|
|
||||
|
/* if the receive array was full, increase its size */ |
||||
|
if (expect_false (eventcnt == epoll_eventmax)) |
||||
|
{ |
||||
|
ev_free (epoll_events); |
||||
|
epoll_eventmax = array_nextsize (sizeof (struct epoll_event), epoll_eventmax, epoll_eventmax + 1); |
||||
|
epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int inline_size |
||||
|
epoll_init (EV_P_ int flags) |
||||
|
{ |
||||
|
backend_fd = epoll_create (256); |
||||
|
|
||||
|
if (backend_fd < 0) |
||||
|
return 0; |
||||
|
|
||||
|
fcntl (backend_fd, F_SETFD, FD_CLOEXEC); |
||||
|
|
||||
|
backend_fudge = 0.; /* kernel sources seem to indicate this to be zero */ |
||||
|
backend_modify = epoll_modify; |
||||
|
backend_poll = epoll_poll; |
||||
|
|
||||
|
epoll_eventmax = 64; /* initial number of events receivable per poll */ |
||||
|
epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax); |
||||
|
|
||||
|
return EVBACKEND_EPOLL; |
||||
|
} |
||||
|
|
||||
|
void inline_size |
||||
|
epoll_destroy (EV_P) |
||||
|
{ |
||||
|
ev_free (epoll_events); |
||||
|
} |
||||
|
|
||||
|
void inline_size |
||||
|
epoll_fork (EV_P) |
||||
|
{ |
||||
|
close (backend_fd); |
||||
|
|
||||
|
while ((backend_fd = epoll_create (256)) < 0) |
||||
|
ev_syserr ("(libev) epoll_create"); |
||||
|
|
||||
|
fcntl (backend_fd, F_SETFD, FD_CLOEXEC); |
||||
|
|
||||
|
fd_rearm_all (EV_A); |
||||
|
} |
||||
|
|
@ -0,0 +1,194 @@ |
|||||
|
/*
|
||||
|
* libev kqueue backend |
||||
|
* |
||||
|
* Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de> |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without modifica- |
||||
|
* tion, 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 MER- |
||||
|
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- |
||||
|
* CIAL, 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 OTH- |
||||
|
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
* |
||||
|
* Alternatively, the contents of this file may be used under the terms of |
||||
|
* the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
* in which case the provisions of the GPL are applicable instead of |
||||
|
* the above. If you wish to allow the use of your version of this file |
||||
|
* only under the terms of the GPL and not to allow others to use your |
||||
|
* version of this file under the BSD license, indicate your decision |
||||
|
* by deleting the provisions above and replace them with the notice |
||||
|
* and other provisions required by the GPL. If you do not delete the |
||||
|
* provisions above, a recipient may use your version of this file under |
||||
|
* either the BSD or the GPL. |
||||
|
*/ |
||||
|
|
||||
|
#include <sys/types.h> |
||||
|
#include <sys/time.h> |
||||
|
#include <sys/queue.h> |
||||
|
#include <sys/event.h> |
||||
|
#include <string.h> |
||||
|
#include <errno.h> |
||||
|
|
||||
|
void inline_speed |
||||
|
kqueue_change (EV_P_ int fd, int filter, int flags, int fflags) |
||||
|
{ |
||||
|
++kqueue_changecnt; |
||||
|
array_needsize (struct kevent, kqueue_changes, kqueue_changemax, kqueue_changecnt, EMPTY2); |
||||
|
|
||||
|
EV_SET (&kqueue_changes [kqueue_changecnt - 1], fd, filter, flags, fflags, 0, 0); |
||||
|
} |
||||
|
|
||||
|
#ifndef NOTE_EOF |
||||
|
# define NOTE_EOF 0 |
||||
|
#endif |
||||
|
|
||||
|
static void |
||||
|
kqueue_modify (EV_P_ int fd, int oev, int nev) |
||||
|
{ |
||||
|
if (oev != nev) |
||||
|
{ |
||||
|
if (oev & EV_READ) |
||||
|
kqueue_change (EV_A_ fd, EVFILT_READ , EV_DELETE, 0); |
||||
|
|
||||
|
if (oev & EV_WRITE) |
||||
|
kqueue_change (EV_A_ fd, EVFILT_WRITE, EV_DELETE, 0); |
||||
|
} |
||||
|
|
||||
|
/* to detect close/reopen reliably, we have to re-add */ |
||||
|
/* event requests even when oev == nev */ |
||||
|
|
||||
|
if (nev & EV_READ) |
||||
|
kqueue_change (EV_A_ fd, EVFILT_READ , EV_ADD, NOTE_EOF); |
||||
|
|
||||
|
if (nev & EV_WRITE) |
||||
|
kqueue_change (EV_A_ fd, EVFILT_WRITE, EV_ADD, NOTE_EOF); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
kqueue_poll (EV_P_ ev_tstamp timeout) |
||||
|
{ |
||||
|
int res, i; |
||||
|
struct timespec ts; |
||||
|
|
||||
|
/* need to resize so there is enough space for errors */ |
||||
|
if (kqueue_changecnt > kqueue_eventmax) |
||||
|
{ |
||||
|
ev_free (kqueue_events); |
||||
|
kqueue_eventmax = array_nextsize (sizeof (struct kevent), kqueue_eventmax, kqueue_changecnt); |
||||
|
kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax); |
||||
|
} |
||||
|
|
||||
|
ts.tv_sec = (time_t)timeout; |
||||
|
ts.tv_nsec = (long)((timeout - (ev_tstamp)ts.tv_sec) * 1e9); |
||||
|
res = kevent (backend_fd, kqueue_changes, kqueue_changecnt, kqueue_events, kqueue_eventmax, &ts); |
||||
|
kqueue_changecnt = 0; |
||||
|
|
||||
|
if (expect_false (res < 0)) |
||||
|
{ |
||||
|
if (errno != EINTR) |
||||
|
ev_syserr ("(libev) kevent"); |
||||
|
|
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
for (i = 0; i < res; ++i) |
||||
|
{ |
||||
|
int fd = kqueue_events [i].ident; |
||||
|
|
||||
|
if (expect_false (kqueue_events [i].flags & EV_ERROR)) |
||||
|
{ |
||||
|
int err = kqueue_events [i].data; |
||||
|
|
||||
|
/* we are only interested in errors for fds that we are interested in :) */ |
||||
|
if (anfds [fd].events) |
||||
|
{ |
||||
|
if (err == ENOENT) /* resubmit changes on ENOENT */ |
||||
|
kqueue_modify (EV_A_ fd, 0, anfds [fd].events); |
||||
|
else if (err == EBADF) /* on EBADF, we re-check the fd */ |
||||
|
{ |
||||
|
if (fd_valid (fd)) |
||||
|
kqueue_modify (EV_A_ fd, 0, anfds [fd].events); |
||||
|
else |
||||
|
fd_kill (EV_A_ fd); |
||||
|
} |
||||
|
else /* on all other errors, we error out on the fd */ |
||||
|
fd_kill (EV_A_ fd); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
fd_event ( |
||||
|
EV_A_ |
||||
|
fd, |
||||
|
kqueue_events [i].filter == EVFILT_READ ? EV_READ |
||||
|
: kqueue_events [i].filter == EVFILT_WRITE ? EV_WRITE |
||||
|
: 0 |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
if (expect_false (res == kqueue_eventmax)) |
||||
|
{ |
||||
|
ev_free (kqueue_events); |
||||
|
kqueue_eventmax = array_nextsize (sizeof (struct kevent), kqueue_eventmax, kqueue_eventmax + 1); |
||||
|
kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int inline_size |
||||
|
kqueue_init (EV_P_ int flags) |
||||
|
{ |
||||
|
/* Initalize the kernel queue */ |
||||
|
if ((backend_fd = kqueue ()) < 0) |
||||
|
return 0; |
||||
|
|
||||
|
fcntl (backend_fd, F_SETFD, FD_CLOEXEC); /* not sure if necessary, hopefully doesn't hurt */ |
||||
|
|
||||
|
backend_fudge = 0.; |
||||
|
backend_modify = kqueue_modify; |
||||
|
backend_poll = kqueue_poll; |
||||
|
|
||||
|
kqueue_eventmax = 64; /* initial number of events receivable per poll */ |
||||
|
kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax); |
||||
|
|
||||
|
kqueue_changes = 0; |
||||
|
kqueue_changemax = 0; |
||||
|
kqueue_changecnt = 0; |
||||
|
|
||||
|
return EVBACKEND_KQUEUE; |
||||
|
} |
||||
|
|
||||
|
void inline_size |
||||
|
kqueue_destroy (EV_P) |
||||
|
{ |
||||
|
ev_free (kqueue_events); |
||||
|
ev_free (kqueue_changes); |
||||
|
} |
||||
|
|
||||
|
void inline_size |
||||
|
kqueue_fork (EV_P) |
||||
|
{ |
||||
|
close (backend_fd); |
||||
|
|
||||
|
while ((backend_fd = kqueue ()) < 0) |
||||
|
ev_syserr ("(libev) kqueue"); |
||||
|
|
||||
|
fcntl (backend_fd, F_SETFD, FD_CLOEXEC); |
||||
|
|
||||
|
/* re-register interest in fds */ |
||||
|
fd_rearm_all (EV_A); |
||||
|
} |
||||
|
|
@ -0,0 +1,140 @@ |
|||||
|
/*
|
||||
|
* libev poll fd activity backend |
||||
|
* |
||||
|
* Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de> |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without modifica- |
||||
|
* tion, 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 MER- |
||||
|
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- |
||||
|
* CIAL, 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 OTH- |
||||
|
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
* |
||||
|
* Alternatively, the contents of this file may be used under the terms of |
||||
|
* the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
* in which case the provisions of the GPL are applicable instead of |
||||
|
* the above. If you wish to allow the use of your version of this file |
||||
|
* only under the terms of the GPL and not to allow others to use your |
||||
|
* version of this file under the BSD license, indicate your decision |
||||
|
* by deleting the provisions above and replace them with the notice |
||||
|
* and other provisions required by the GPL. If you do not delete the |
||||
|
* provisions above, a recipient may use your version of this file under |
||||
|
* either the BSD or the GPL. |
||||
|
*/ |
||||
|
|
||||
|
#include <poll.h> |
||||
|
|
||||
|
void inline_size |
||||
|
pollidx_init (int *base, int count) |
||||
|
{ |
||||
|
/* consider using memset (.., -1, ...), which is pratically guarenteed
|
||||
|
* to work on all systems implementing poll */ |
||||
|
while (count--) |
||||
|
*base++ = -1; |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
poll_modify (EV_P_ int fd, int oev, int nev) |
||||
|
{ |
||||
|
int idx; |
||||
|
|
||||
|
if (oev == nev) |
||||
|
return; |
||||
|
|
||||
|
array_needsize (int, pollidxs, pollidxmax, fd + 1, pollidx_init); |
||||
|
|
||||
|
idx = pollidxs [fd]; |
||||
|
|
||||
|
if (idx < 0) /* need to allocate a new pollfd */ |
||||
|
{ |
||||
|
pollidxs [fd] = idx = pollcnt++; |
||||
|
array_needsize (struct pollfd, polls, pollmax, pollcnt, EMPTY2); |
||||
|
polls [idx].fd = fd; |
||||
|
} |
||||
|
|
||||
|
assert (polls [idx].fd == fd); |
||||
|
|
||||
|
if (nev) |
||||
|
polls [idx].events = |
||||
|
(nev & EV_READ ? POLLIN : 0) |
||||
|
| (nev & EV_WRITE ? POLLOUT : 0); |
||||
|
else /* remove pollfd */ |
||||
|
{ |
||||
|
pollidxs [fd] = -1; |
||||
|
|
||||
|
if (expect_true (idx < --pollcnt)) |
||||
|
{ |
||||
|
polls [idx] = polls [pollcnt]; |
||||
|
pollidxs [polls [idx].fd] = idx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
poll_poll (EV_P_ ev_tstamp timeout) |
||||
|
{ |
||||
|
struct pollfd *p; |
||||
|
int res = poll (polls, pollcnt, (int)ceil (timeout * 1000.)); |
||||
|
|
||||
|
if (expect_false (res < 0)) |
||||
|
{ |
||||
|
if (errno == EBADF) |
||||
|
fd_ebadf (EV_A); |
||||
|
else if (errno == ENOMEM && !syserr_cb) |
||||
|
fd_enomem (EV_A); |
||||
|
else if (errno != EINTR) |
||||
|
ev_syserr ("(libev) poll"); |
||||
|
} |
||||
|
else |
||||
|
for (p = polls; res; ++p) |
||||
|
if (expect_false (p->revents)) /* this expect is debatable */ |
||||
|
{ |
||||
|
--res; |
||||
|
|
||||
|
if (expect_false (p->revents & POLLNVAL)) |
||||
|
fd_kill (EV_A_ p->fd); |
||||
|
else |
||||
|
fd_event ( |
||||
|
EV_A_ |
||||
|
p->fd, |
||||
|
(p->revents & (POLLOUT | POLLERR | POLLHUP) ? EV_WRITE : 0) |
||||
|
| (p->revents & (POLLIN | POLLERR | POLLHUP) ? EV_READ : 0) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int inline_size |
||||
|
poll_init (EV_P_ int flags) |
||||
|
{ |
||||
|
backend_fudge = 0.; /* posix says this is zero */ |
||||
|
backend_modify = poll_modify; |
||||
|
backend_poll = poll_poll; |
||||
|
|
||||
|
pollidxs = 0; pollidxmax = 0; |
||||
|
polls = 0; pollmax = 0; pollcnt = 0; |
||||
|
|
||||
|
return EVBACKEND_POLL; |
||||
|
} |
||||
|
|
||||
|
void inline_size |
||||
|
poll_destroy (EV_P) |
||||
|
{ |
||||
|
ev_free (pollidxs); |
||||
|
ev_free (polls); |
||||
|
} |
||||
|
|
@ -0,0 +1,163 @@ |
|||||
|
/*
|
||||
|
* libev solaris event port backend |
||||
|
* |
||||
|
* Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de> |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without modifica- |
||||
|
* tion, 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 MER- |
||||
|
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- |
||||
|
* CIAL, 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 OTH- |
||||
|
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
* |
||||
|
* Alternatively, the contents of this file may be used under the terms of |
||||
|
* the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
* in which case the provisions of the GPL are applicable instead of |
||||
|
* the above. If you wish to allow the use of your version of this file |
||||
|
* only under the terms of the GPL and not to allow others to use your |
||||
|
* version of this file under the BSD license, indicate your decision |
||||
|
* by deleting the provisions above and replace them with the notice |
||||
|
* and other provisions required by the GPL. If you do not delete the |
||||
|
* provisions above, a recipient may use your version of this file under |
||||
|
* either the BSD or the GPL. |
||||
|
*/ |
||||
|
|
||||
|
#include <sys/types.h> |
||||
|
#include <sys/time.h> |
||||
|
#include <poll.h> |
||||
|
#include <port.h> |
||||
|
#include <string.h> |
||||
|
#include <errno.h> |
||||
|
|
||||
|
void inline_speed |
||||
|
port_associate_and_check (EV_P_ int fd, int ev) |
||||
|
{ |
||||
|
if (0 > |
||||
|
port_associate ( |
||||
|
backend_fd, PORT_SOURCE_FD, fd, |
||||
|
(ev & EV_READ ? POLLIN : 0) |
||||
|
| (ev & EV_WRITE ? POLLOUT : 0), |
||||
|
0 |
||||
|
) |
||||
|
) |
||||
|
{ |
||||
|
if (errno == EBADFD) |
||||
|
fd_kill (EV_A_ fd); |
||||
|
else |
||||
|
ev_syserr ("(libev) port_associate"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
port_modify (EV_P_ int fd, int oev, int nev) |
||||
|
{ |
||||
|
/* we need to reassociate no matter what, as closes are
|
||||
|
* once more silently being discarded. |
||||
|
*/ |
||||
|
if (!nev) |
||||
|
{ |
||||
|
if (oev) |
||||
|
port_dissociate (backend_fd, PORT_SOURCE_FD, fd); |
||||
|
} |
||||
|
else |
||||
|
port_associate_and_check (EV_A_ fd, nev); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
port_poll (EV_P_ ev_tstamp timeout) |
||||
|
{ |
||||
|
int res, i; |
||||
|
struct timespec ts; |
||||
|
uint_t nget = 1; |
||||
|
|
||||
|
ts.tv_sec = (time_t)timeout; |
||||
|
ts.tv_nsec = (long)(timeout - (ev_tstamp)ts.tv_sec) * 1e9; |
||||
|
res = port_getn (backend_fd, port_events, port_eventmax, &nget, &ts); |
||||
|
|
||||
|
if (res == -1) |
||||
|
{ |
||||
|
if (errno != EINTR && errno != ETIME) |
||||
|
ev_syserr ("(libev) port_getn"); |
||||
|
|
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
for (i = 0; i < nget; ++i) |
||||
|
{ |
||||
|
if (port_events [i].portev_source == PORT_SOURCE_FD) |
||||
|
{ |
||||
|
int fd = port_events [i].portev_object; |
||||
|
|
||||
|
fd_event ( |
||||
|
EV_A_ |
||||
|
fd, |
||||
|
(port_events [i].portev_events & (POLLOUT | POLLERR | POLLHUP) ? EV_WRITE : 0) |
||||
|
| (port_events [i].portev_events & (POLLIN | POLLERR | POLLHUP) ? EV_READ : 0) |
||||
|
); |
||||
|
|
||||
|
port_associate_and_check (EV_A_ fd, anfds [fd].events); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (expect_false (nget == port_eventmax)) |
||||
|
{ |
||||
|
ev_free (port_events); |
||||
|
port_eventmax = array_nextsize (sizeof (port_event_t), port_eventmax, port_eventmax + 1); |
||||
|
port_events = (port_event_t *)ev_malloc (sizeof (port_event_t) * port_eventmax); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int inline_size |
||||
|
port_init (EV_P_ int flags) |
||||
|
{ |
||||
|
/* Initalize the kernel queue */ |
||||
|
if ((backend_fd = port_create ()) < 0) |
||||
|
return 0; |
||||
|
|
||||
|
fcntl (backend_fd, F_SETFD, FD_CLOEXEC); /* not sure if necessary, hopefully doesn't hurt */ |
||||
|
|
||||
|
backend_fudge = 1e-3; /* needed to compensate for port_getn returning early */ |
||||
|
backend_modify = port_modify; |
||||
|
backend_poll = port_poll; |
||||
|
|
||||
|
port_eventmax = 64; /* intiial number of events receivable per poll */ |
||||
|
port_events = (port_event_t *)ev_malloc (sizeof (port_event_t) * port_eventmax); |
||||
|
|
||||
|
return EVBACKEND_PORT; |
||||
|
} |
||||
|
|
||||
|
void inline_size |
||||
|
port_destroy (EV_P) |
||||
|
{ |
||||
|
ev_free (port_events); |
||||
|
} |
||||
|
|
||||
|
void inline_size |
||||
|
port_fork (EV_P) |
||||
|
{ |
||||
|
close (backend_fd); |
||||
|
|
||||
|
while ((backend_fd = port_create ()) < 0) |
||||
|
ev_syserr ("(libev) port"); |
||||
|
|
||||
|
fcntl (backend_fd, F_SETFD, FD_CLOEXEC); |
||||
|
|
||||
|
/* re-register interest in fds */ |
||||
|
fd_rearm_all (EV_A); |
||||
|
} |
||||
|
|
@ -0,0 +1,300 @@ |
|||||
|
/*
|
||||
|
* libev select fd activity backend |
||||
|
* |
||||
|
* Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <libev@schmorp.de> |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without modifica- |
||||
|
* tion, 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 MER- |
||||
|
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- |
||||
|
* CIAL, 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 OTH- |
||||
|
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
* |
||||
|
* Alternatively, the contents of this file may be used under the terms of |
||||
|
* the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
* in which case the provisions of the GPL are applicable instead of |
||||
|
* the above. If you wish to allow the use of your version of this file |
||||
|
* only under the terms of the GPL and not to allow others to use your |
||||
|
* version of this file under the BSD license, indicate your decision |
||||
|
* by deleting the provisions above and replace them with the notice |
||||
|
* and other provisions required by the GPL. If you do not delete the |
||||
|
* provisions above, a recipient may use your version of this file under |
||||
|
* either the BSD or the GPL. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef _WIN32 |
||||
|
/* for unix systems */ |
||||
|
# include <sys/select.h> |
||||
|
# include <inttypes.h> |
||||
|
#endif |
||||
|
|
||||
|
#ifndef EV_SELECT_USE_FD_SET |
||||
|
# ifdef NFDBITS |
||||
|
# define EV_SELECT_USE_FD_SET 0 |
||||
|
# else |
||||
|
# define EV_SELECT_USE_FD_SET 1 |
||||
|
# endif |
||||
|
#endif |
||||
|
|
||||
|
#if EV_SELECT_IS_WINSOCKET |
||||
|
# undef EV_SELECT_USE_FD_SET |
||||
|
# define EV_SELECT_USE_FD_SET 1 |
||||
|
# undef NFDBITS |
||||
|
# define NFDBITS 0 |
||||
|
#endif |
||||
|
|
||||
|
#if !EV_SELECT_USE_FD_SET |
||||
|
# define NFDBYTES (NFDBITS / 8) |
||||
|
#endif |
||||
|
|
||||
|
#include <string.h> |
||||
|
|
||||
|
static void |
||||
|
select_modify (EV_P_ int fd, int oev, int nev) |
||||
|
{ |
||||
|
if (oev == nev) |
||||
|
return; |
||||
|
|
||||
|
{ |
||||
|
#if EV_SELECT_USE_FD_SET |
||||
|
|
||||
|
#if EV_SELECT_IS_WINSOCKET |
||||
|
SOCKET handle = anfds [fd].handle; |
||||
|
#else |
||||
|
int handle = fd; |
||||
|
#endif |
||||
|
|
||||
|
assert (("libev: fd >= FD_SETSIZE passed to fd_set-based select backend", fd < FD_SETSIZE)); |
||||
|
|
||||
|
/* FD_SET is broken on windows (it adds the fd to a set twice or more,
|
||||
|
* which eventually leads to overflows). Need to call it only on changes. |
||||
|
*/ |
||||
|
#if EV_SELECT_IS_WINSOCKET |
||||
|
if ((oev ^ nev) & EV_READ) |
||||
|
#endif |
||||
|
if (nev & EV_READ) |
||||
|
FD_SET (handle, (fd_set *)vec_ri); |
||||
|
else |
||||
|
FD_CLR (handle, (fd_set *)vec_ri); |
||||
|
|
||||
|
#if EV_SELECT_IS_WINSOCKET |
||||
|
if ((oev ^ nev) & EV_WRITE) |
||||
|
#endif |
||||
|
if (nev & EV_WRITE) |
||||
|
FD_SET (handle, (fd_set *)vec_wi); |
||||
|
else |
||||
|
FD_CLR (handle, (fd_set *)vec_wi); |
||||
|
|
||||
|
#else |
||||
|
|
||||
|
int word = fd / NFDBITS; |
||||
|
fd_mask mask = 1UL << (fd % NFDBITS); |
||||
|
|
||||
|
if (expect_false (vec_max <= word)) |
||||
|
{ |
||||
|
int new_max = word + 1; |
||||
|
|
||||
|
vec_ri = ev_realloc (vec_ri, new_max * NFDBYTES); |
||||
|
vec_ro = ev_realloc (vec_ro, new_max * NFDBYTES); /* could free/malloc */ |
||||
|
vec_wi = ev_realloc (vec_wi, new_max * NFDBYTES); |
||||
|
vec_wo = ev_realloc (vec_wo, new_max * NFDBYTES); /* could free/malloc */ |
||||
|
#ifdef _WIN32 |
||||
|
vec_eo = ev_realloc (vec_eo, new_max * NFDBYTES); /* could free/malloc */ |
||||
|
#endif |
||||
|
|
||||
|
for (; vec_max < new_max; ++vec_max) |
||||
|
((fd_mask *)vec_ri) [vec_max] = |
||||
|
((fd_mask *)vec_wi) [vec_max] = 0; |
||||
|
} |
||||
|
|
||||
|
((fd_mask *)vec_ri) [word] |= mask; |
||||
|
if (!(nev & EV_READ)) |
||||
|
((fd_mask *)vec_ri) [word] &= ~mask; |
||||
|
|
||||
|
((fd_mask *)vec_wi) [word] |= mask; |
||||
|
if (!(nev & EV_WRITE)) |
||||
|
((fd_mask *)vec_wi) [word] &= ~mask; |
||||
|
#endif |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
select_poll (EV_P_ ev_tstamp timeout) |
||||
|
{ |
||||
|
struct timeval tv; |
||||
|
int res; |
||||
|
int fd_setsize; |
||||
|
|
||||
|
tv.tv_sec = (long)timeout; |
||||
|
tv.tv_usec = (long)((timeout - (ev_tstamp)tv.tv_sec) * 1e6); |
||||
|
|
||||
|
#if EV_SELECT_USE_FD_SET |
||||
|
fd_setsize = sizeof (fd_set); |
||||
|
#else |
||||
|
fd_setsize = vec_max * NFDBYTES; |
||||
|
#endif |
||||
|
|
||||
|
memcpy (vec_ro, vec_ri, fd_setsize); |
||||
|
memcpy (vec_wo, vec_wi, fd_setsize); |
||||
|
|
||||
|
#ifdef _WIN32 |
||||
|
/* pass in the write set as except set.
|
||||
|
* the idea behind this is to work around a windows bug that causes |
||||
|
* errors to be reported as an exception and not by setting |
||||
|
* the writable bit. this is so uncontrollably lame. |
||||
|
*/ |
||||
|
memcpy (vec_eo, vec_wi, fd_setsize); |
||||
|
res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, (fd_set *)vec_eo, &tv); |
||||
|
#elif EV_SELECT_USE_FD_SET |
||||
|
fd_setsize = anfdmax < FD_SETSIZE ? anfdmax : FD_SETSIZE; |
||||
|
res = select (fd_setsize, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); |
||||
|
#else |
||||
|
res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); |
||||
|
#endif |
||||
|
|
||||
|
if (expect_false (res < 0)) |
||||
|
{ |
||||
|
#if EV_SELECT_IS_WINSOCKET |
||||
|
errno = WSAGetLastError (); |
||||
|
#endif |
||||
|
#ifdef WSABASEERR |
||||
|
/* on windows, select returns incompatible error codes, fix this */ |
||||
|
if (errno >= WSABASEERR && errno < WSABASEERR + 1000) |
||||
|
if (errno == WSAENOTSOCK) |
||||
|
errno = EBADF; |
||||
|
else |
||||
|
errno -= WSABASEERR; |
||||
|
#endif |
||||
|
|
||||
|
#ifdef _WIN32 |
||||
|
/* select on windows errornously returns EINVAL when no fd sets have been
|
||||
|
* provided (this is documented). what microsoft doesn't tell you that this bug |
||||
|
* exists even when the fd sets _are_ provided, so we have to check for this bug |
||||
|
* here and emulate by sleeping manually. |
||||
|
* we also get EINVAL when the timeout is invalid, but we ignore this case here |
||||
|
* and assume that EINVAL always means: you have to wait manually. |
||||
|
*/ |
||||
|
if (errno == EINVAL) |
||||
|
{ |
||||
|
ev_sleep (timeout); |
||||
|
return; |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
if (errno == EBADF) |
||||
|
fd_ebadf (EV_A); |
||||
|
else if (errno == ENOMEM && !syserr_cb) |
||||
|
fd_enomem (EV_A); |
||||
|
else if (errno != EINTR) |
||||
|
ev_syserr ("(libev) select"); |
||||
|
|
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
#if EV_SELECT_USE_FD_SET |
||||
|
|
||||
|
{ |
||||
|
int fd; |
||||
|
|
||||
|
for (fd = 0; fd < anfdmax; ++fd) |
||||
|
if (anfds [fd].events) |
||||
|
{ |
||||
|
int events = 0; |
||||
|
#if EV_SELECT_IS_WINSOCKET |
||||
|
SOCKET handle = anfds [fd].handle; |
||||
|
#else |
||||
|
int handle = fd; |
||||
|
#endif |
||||
|
|
||||
|
if (FD_ISSET (handle, (fd_set *)vec_ro)) events |= EV_READ; |
||||
|
if (FD_ISSET (handle, (fd_set *)vec_wo)) events |= EV_WRITE; |
||||
|
#ifdef _WIN32 |
||||
|
if (FD_ISSET (handle, (fd_set *)vec_eo)) events |= EV_WRITE; |
||||
|
#endif |
||||
|
|
||||
|
if (expect_true (events)) |
||||
|
fd_event (EV_A_ fd, events); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#else |
||||
|
|
||||
|
{ |
||||
|
int word, bit; |
||||
|
for (word = vec_max; word--; ) |
||||
|
{ |
||||
|
fd_mask word_r = ((fd_mask *)vec_ro) [word]; |
||||
|
fd_mask word_w = ((fd_mask *)vec_wo) [word]; |
||||
|
#ifdef _WIN32 |
||||
|
word_w |= ((fd_mask *)vec_eo) [word]; |
||||
|
#endif |
||||
|
|
||||
|
if (word_r || word_w) |
||||
|
for (bit = NFDBITS; bit--; ) |
||||
|
{ |
||||
|
fd_mask mask = 1UL << bit; |
||||
|
int events = 0; |
||||
|
|
||||
|
events |= word_r & mask ? EV_READ : 0; |
||||
|
events |= word_w & mask ? EV_WRITE : 0; |
||||
|
|
||||
|
if (expect_true (events)) |
||||
|
fd_event (EV_A_ word * NFDBITS + bit, events); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
int inline_size |
||||
|
select_init (EV_P_ int flags) |
||||
|
{ |
||||
|
backend_fudge = 0.; /* posix says this is zero */ |
||||
|
backend_modify = select_modify; |
||||
|
backend_poll = select_poll; |
||||
|
|
||||
|
#if EV_SELECT_USE_FD_SET |
||||
|
vec_ri = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri); |
||||
|
vec_ro = ev_malloc (sizeof (fd_set)); |
||||
|
vec_wi = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi); |
||||
|
vec_wo = ev_malloc (sizeof (fd_set)); |
||||
|
#ifdef _WIN32 |
||||
|
vec_eo = ev_malloc (sizeof (fd_set)); |
||||
|
#endif |
||||
|
#else |
||||
|
vec_max = 0; |
||||
|
vec_ri = 0; |
||||
|
vec_ri = 0; |
||||
|
vec_wo = 0; |
||||
|
vec_wo = 0; |
||||
|
#endif |
||||
|
|
||||
|
return EVBACKEND_SELECT; |
||||
|
} |
||||
|
|
||||
|
void inline_size |
||||
|
select_destroy (EV_P) |
||||
|
{ |
||||
|
ev_free (vec_ri); |
||||
|
ev_free (vec_ro); |
||||
|
ev_free (vec_wi); |
||||
|
ev_free (vec_wo); |
||||
|
} |
||||
|
|
||||
|
|
@ -0,0 +1,164 @@ |
|||||
|
/*
|
||||
|
* loop member variable declarations |
||||
|
* |
||||
|
* Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de> |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without modifica- |
||||
|
* tion, 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 MER- |
||||
|
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- |
||||
|
* CIAL, 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 OTH- |
||||
|
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
* |
||||
|
* Alternatively, the contents of this file may be used under the terms of |
||||
|
* the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
* in which case the provisions of the GPL are applicable instead of |
||||
|
* the above. If you wish to allow the use of your version of this file |
||||
|
* only under the terms of the GPL and not to allow others to use your |
||||
|
* version of this file under the BSD license, indicate your decision |
||||
|
* by deleting the provisions above and replace them with the notice |
||||
|
* and other provisions required by the GPL. If you do not delete the |
||||
|
* provisions above, a recipient may use your version of this file under |
||||
|
* either the BSD or the GPL. |
||||
|
*/ |
||||
|
|
||||
|
#define VARx(type,name) VAR(name, type name) |
||||
|
|
||||
|
VARx(ev_tstamp, now_floor) /* last time we refreshed rt_time */ |
||||
|
VARx(ev_tstamp, mn_now) /* monotonic clock "now" */ |
||||
|
VARx(ev_tstamp, rtmn_diff) /* difference realtime - monotonic time */ |
||||
|
|
||||
|
VARx(ev_tstamp, io_blocktime) |
||||
|
VARx(ev_tstamp, timeout_blocktime) |
||||
|
|
||||
|
VARx(int, backend) |
||||
|
VARx(int, activecnt) /* total number of active events ("refcount") */ |
||||
|
VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */ |
||||
|
|
||||
|
VARx(int, backend_fd) |
||||
|
VARx(ev_tstamp, backend_fudge) /* assumed typical timer resolution */ |
||||
|
VAR (backend_modify, void (*backend_modify)(EV_P_ int fd, int oev, int nev)) |
||||
|
VAR (backend_poll , void (*backend_poll)(EV_P_ ev_tstamp timeout)) |
||||
|
|
||||
|
#if EV_USE_EVENTFD || EV_GENWRAP |
||||
|
VARx(int, evfd) |
||||
|
#endif |
||||
|
VAR (evpipe, int evpipe [2]) |
||||
|
VARx(ev_io, pipeev) |
||||
|
|
||||
|
#if !defined(_WIN32) || EV_GENWRAP |
||||
|
VARx(pid_t, curpid) |
||||
|
#endif |
||||
|
|
||||
|
VARx(char, postfork) /* true if we need to recreate kernel state after fork */ |
||||
|
|
||||
|
#if EV_USE_SELECT || EV_GENWRAP |
||||
|
VARx(void *, vec_ri) |
||||
|
VARx(void *, vec_ro) |
||||
|
VARx(void *, vec_wi) |
||||
|
VARx(void *, vec_wo) |
||||
|
#if defined(_WIN32) || EV_GENWRAP |
||||
|
VARx(void *, vec_eo) |
||||
|
#endif |
||||
|
VARx(int, vec_max) |
||||
|
#endif |
||||
|
|
||||
|
#if EV_USE_POLL || EV_GENWRAP |
||||
|
VARx(struct pollfd *, polls) |
||||
|
VARx(int, pollmax) |
||||
|
VARx(int, pollcnt) |
||||
|
VARx(int *, pollidxs) /* maps fds into structure indices */ |
||||
|
VARx(int, pollidxmax) |
||||
|
#endif |
||||
|
|
||||
|
#if EV_USE_EPOLL || EV_GENWRAP |
||||
|
VARx(struct epoll_event *, epoll_events) |
||||
|
VARx(int, epoll_eventmax) |
||||
|
#endif |
||||
|
|
||||
|
#if EV_USE_KQUEUE || EV_GENWRAP |
||||
|
VARx(struct kevent *, kqueue_changes) |
||||
|
VARx(int, kqueue_changemax) |
||||
|
VARx(int, kqueue_changecnt) |
||||
|
VARx(struct kevent *, kqueue_events) |
||||
|
VARx(int, kqueue_eventmax) |
||||
|
#endif |
||||
|
|
||||
|
#if EV_USE_PORT || EV_GENWRAP |
||||
|
VARx(struct port_event *, port_events) |
||||
|
VARx(int, port_eventmax) |
||||
|
#endif |
||||
|
|
||||
|
VARx(ANFD *, anfds) |
||||
|
VARx(int, anfdmax) |
||||
|
|
||||
|
VAR (pendings, ANPENDING *pendings [NUMPRI]) |
||||
|
VAR (pendingmax, int pendingmax [NUMPRI]) |
||||
|
VAR (pendingcnt, int pendingcnt [NUMPRI]) |
||||
|
|
||||
|
VARx(int *, fdchanges) |
||||
|
VARx(int, fdchangemax) |
||||
|
VARx(int, fdchangecnt) |
||||
|
|
||||
|
VARx(ANHE *, timers) |
||||
|
VARx(int, timermax) |
||||
|
VARx(int, timercnt) |
||||
|
|
||||
|
#if EV_PERIODIC_ENABLE || EV_GENWRAP |
||||
|
VARx(ANHE *, periodics) |
||||
|
VARx(int, periodicmax) |
||||
|
VARx(int, periodiccnt) |
||||
|
#endif |
||||
|
|
||||
|
#if EV_IDLE_ENABLE || EV_GENWRAP |
||||
|
VAR (idles, ev_idle **idles [NUMPRI]) |
||||
|
VAR (idlemax, int idlemax [NUMPRI]) |
||||
|
VAR (idlecnt, int idlecnt [NUMPRI]) |
||||
|
#endif |
||||
|
VARx(int, idleall) /* total number */ |
||||
|
|
||||
|
VARx(struct ev_prepare **, prepares) |
||||
|
VARx(int, preparemax) |
||||
|
VARx(int, preparecnt) |
||||
|
|
||||
|
VARx(struct ev_check **, checks) |
||||
|
VARx(int, checkmax) |
||||
|
VARx(int, checkcnt) |
||||
|
|
||||
|
#if EV_FORK_ENABLE || EV_GENWRAP |
||||
|
VARx(struct ev_fork **, forks) |
||||
|
VARx(int, forkmax) |
||||
|
VARx(int, forkcnt) |
||||
|
#endif |
||||
|
|
||||
|
VARx(EV_ATOMIC_T, gotasync) |
||||
|
#if EV_ASYNC_ENABLE || EV_GENWRAP |
||||
|
VARx(struct ev_async **, asyncs) |
||||
|
VARx(int, asyncmax) |
||||
|
VARx(int, asynccnt) |
||||
|
#endif |
||||
|
|
||||
|
#if EV_USE_INOTIFY || EV_GENWRAP |
||||
|
VARx(int, fs_fd) |
||||
|
VARx(ev_io, fs_w) |
||||
|
VARx(char, fs_2625) /* whether we are running in linux 2.6.25 or newer */ |
||||
|
VAR (fs_hash, ANFS fs_hash [EV_INOTIFY_HASHSIZE]) |
||||
|
#endif |
||||
|
|
||||
|
#undef VARx |
||||
|
|
@ -0,0 +1,154 @@ |
|||||
|
/*
|
||||
|
* libev win32 compatibility cruft (_not_ a backend) |
||||
|
* |
||||
|
* Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de> |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without modifica- |
||||
|
* tion, 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 MER- |
||||
|
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- |
||||
|
* CIAL, 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 OTH- |
||||
|
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
* |
||||
|
* Alternatively, the contents of this file may be used under the terms of |
||||
|
* the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
* in which case the provisions of the GPL are applicable instead of |
||||
|
* the above. If you wish to allow the use of your version of this file |
||||
|
* only under the terms of the GPL and not to allow others to use your |
||||
|
* version of this file under the BSD license, indicate your decision |
||||
|
* by deleting the provisions above and replace them with the notice |
||||
|
* and other provisions required by the GPL. If you do not delete the |
||||
|
* provisions above, a recipient may use your version of this file under |
||||
|
* either the BSD or the GPL. |
||||
|
*/ |
||||
|
|
||||
|
#ifdef _WIN32 |
||||
|
|
||||
|
/* timeb.h is actually xsi legacy functionality */ |
||||
|
#include <sys/timeb.h> |
||||
|
|
||||
|
/* note: the comment below could not be substantiated, but what would I care */ |
||||
|
/* MSDN says this is required to handle SIGFPE */ |
||||
|
/* my wild guess would be that using something floating-pointy is required */ |
||||
|
/* for the crt to do something about it */ |
||||
|
volatile double SIGFPE_REQ = 0.0f; |
||||
|
|
||||
|
/* oh, the humanity! */ |
||||
|
static int |
||||
|
ev_pipe (int filedes [2]) |
||||
|
{ |
||||
|
struct sockaddr_in addr = { 0 }; |
||||
|
int addr_size = sizeof (addr); |
||||
|
struct sockaddr_in adr2; |
||||
|
int adr2_size = sizeof (adr2); |
||||
|
SOCKET listener; |
||||
|
SOCKET sock [2] = { -1, -1 }; |
||||
|
|
||||
|
if ((listener = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) |
||||
|
return -1; |
||||
|
|
||||
|
addr.sin_family = AF_INET; |
||||
|
addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); |
||||
|
addr.sin_port = 0; |
||||
|
|
||||
|
if (bind (listener, (struct sockaddr *)&addr, addr_size)) |
||||
|
goto fail; |
||||
|
|
||||
|
if (getsockname (listener, (struct sockaddr *)&addr, &addr_size)) |
||||
|
goto fail; |
||||
|
|
||||
|
if (listen (listener, 1)) |
||||
|
goto fail; |
||||
|
|
||||
|
if ((sock [0] = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) |
||||
|
goto fail; |
||||
|
|
||||
|
if (connect (sock [0], (struct sockaddr *)&addr, addr_size)) |
||||
|
goto fail; |
||||
|
|
||||
|
if ((sock [1] = accept (listener, 0, 0)) < 0) |
||||
|
goto fail; |
||||
|
|
||||
|
/* windows vista returns fantasy port numbers for sockets:
|
||||
|
* example for two interconnected tcp sockets: |
||||
|
* |
||||
|
* (Socket::unpack_sockaddr_in getsockname $sock0)[0] == 53364 |
||||
|
* (Socket::unpack_sockaddr_in getpeername $sock0)[0] == 53363 |
||||
|
* (Socket::unpack_sockaddr_in getsockname $sock1)[0] == 53363 |
||||
|
* (Socket::unpack_sockaddr_in getpeername $sock1)[0] == 53365 |
||||
|
* |
||||
|
* wow! tridirectional sockets! |
||||
|
* |
||||
|
* this way of checking ports seems to work: |
||||
|
*/ |
||||
|
if (getpeername (sock [0], (struct sockaddr *)&addr, &addr_size)) |
||||
|
goto fail; |
||||
|
|
||||
|
if (getsockname (sock [1], (struct sockaddr *)&adr2, &adr2_size)) |
||||
|
goto fail; |
||||
|
|
||||
|
errno = WSAEINVAL; |
||||
|
if (addr_size != adr2_size |
||||
|
|| addr.sin_addr.s_addr != adr2.sin_addr.s_addr /* just to be sure, I mean, it's windows */ |
||||
|
|| addr.sin_port != adr2.sin_port) |
||||
|
goto fail; |
||||
|
|
||||
|
closesocket (listener); |
||||
|
|
||||
|
#if EV_SELECT_IS_WINSOCKET |
||||
|
filedes [0] = _open_osfhandle (sock [0], 0); |
||||
|
filedes [1] = _open_osfhandle (sock [1], 0); |
||||
|
#else |
||||
|
/* when select isn't winsocket, we also expect socket, connect, accept etc.
|
||||
|
* to work on fds */ |
||||
|
filedes [0] = sock [0]; |
||||
|
filedes [1] = sock [1]; |
||||
|
#endif |
||||
|
|
||||
|
return 0; |
||||
|
|
||||
|
fail: |
||||
|
closesocket (listener); |
||||
|
|
||||
|
if (sock [0] != INVALID_SOCKET) closesocket (sock [0]); |
||||
|
if (sock [1] != INVALID_SOCKET) closesocket (sock [1]); |
||||
|
|
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
#undef pipe |
||||
|
#define pipe(filedes) ev_pipe (filedes) |
||||
|
|
||||
|
static int |
||||
|
ev_gettimeofday (struct timeval *tv, struct timezone *tz) |
||||
|
{ |
||||
|
struct _timeb tb; |
||||
|
|
||||
|
_ftime (&tb); |
||||
|
|
||||
|
tv->tv_sec = (long)tb.time; |
||||
|
tv->tv_usec = ((long)tb.millitm) * 1000; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
#undef gettimeofday |
||||
|
#define gettimeofday(tv,tz) ev_gettimeofday (tv, tz) |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,150 @@ |
|||||
|
/* DO NOT EDIT, automatically generated by update_ev_wrap */ |
||||
|
#ifndef EV_WRAP_H |
||||
|
#define EV_WRAP_H |
||||
|
#define now_floor ((loop)->now_floor) |
||||
|
#define mn_now ((loop)->mn_now) |
||||
|
#define rtmn_diff ((loop)->rtmn_diff) |
||||
|
#define io_blocktime ((loop)->io_blocktime) |
||||
|
#define timeout_blocktime ((loop)->timeout_blocktime) |
||||
|
#define backend ((loop)->backend) |
||||
|
#define activecnt ((loop)->activecnt) |
||||
|
#define loop_count ((loop)->loop_count) |
||||
|
#define backend_fd ((loop)->backend_fd) |
||||
|
#define backend_fudge ((loop)->backend_fudge) |
||||
|
#define backend_modify ((loop)->backend_modify) |
||||
|
#define backend_poll ((loop)->backend_poll) |
||||
|
#define evfd ((loop)->evfd) |
||||
|
#define evpipe ((loop)->evpipe) |
||||
|
#define pipeev ((loop)->pipeev) |
||||
|
#define curpid ((loop)->curpid) |
||||
|
#define postfork ((loop)->postfork) |
||||
|
#define vec_ri ((loop)->vec_ri) |
||||
|
#define vec_ro ((loop)->vec_ro) |
||||
|
#define vec_wi ((loop)->vec_wi) |
||||
|
#define vec_wo ((loop)->vec_wo) |
||||
|
#define vec_eo ((loop)->vec_eo) |
||||
|
#define vec_max ((loop)->vec_max) |
||||
|
#define polls ((loop)->polls) |
||||
|
#define pollmax ((loop)->pollmax) |
||||
|
#define pollcnt ((loop)->pollcnt) |
||||
|
#define pollidxs ((loop)->pollidxs) |
||||
|
#define pollidxmax ((loop)->pollidxmax) |
||||
|
#define epoll_events ((loop)->epoll_events) |
||||
|
#define epoll_eventmax ((loop)->epoll_eventmax) |
||||
|
#define kqueue_changes ((loop)->kqueue_changes) |
||||
|
#define kqueue_changemax ((loop)->kqueue_changemax) |
||||
|
#define kqueue_changecnt ((loop)->kqueue_changecnt) |
||||
|
#define kqueue_events ((loop)->kqueue_events) |
||||
|
#define kqueue_eventmax ((loop)->kqueue_eventmax) |
||||
|
#define port_events ((loop)->port_events) |
||||
|
#define port_eventmax ((loop)->port_eventmax) |
||||
|
#define anfds ((loop)->anfds) |
||||
|
#define anfdmax ((loop)->anfdmax) |
||||
|
#define pendings ((loop)->pendings) |
||||
|
#define pendingmax ((loop)->pendingmax) |
||||
|
#define pendingcnt ((loop)->pendingcnt) |
||||
|
#define fdchanges ((loop)->fdchanges) |
||||
|
#define fdchangemax ((loop)->fdchangemax) |
||||
|
#define fdchangecnt ((loop)->fdchangecnt) |
||||
|
#define timers ((loop)->timers) |
||||
|
#define timermax ((loop)->timermax) |
||||
|
#define timercnt ((loop)->timercnt) |
||||
|
#define periodics ((loop)->periodics) |
||||
|
#define periodicmax ((loop)->periodicmax) |
||||
|
#define periodiccnt ((loop)->periodiccnt) |
||||
|
#define idles ((loop)->idles) |
||||
|
#define idlemax ((loop)->idlemax) |
||||
|
#define idlecnt ((loop)->idlecnt) |
||||
|
#define idleall ((loop)->idleall) |
||||
|
#define prepares ((loop)->prepares) |
||||
|
#define preparemax ((loop)->preparemax) |
||||
|
#define preparecnt ((loop)->preparecnt) |
||||
|
#define checks ((loop)->checks) |
||||
|
#define checkmax ((loop)->checkmax) |
||||
|
#define checkcnt ((loop)->checkcnt) |
||||
|
#define forks ((loop)->forks) |
||||
|
#define forkmax ((loop)->forkmax) |
||||
|
#define forkcnt ((loop)->forkcnt) |
||||
|
#define gotasync ((loop)->gotasync) |
||||
|
#define asyncs ((loop)->asyncs) |
||||
|
#define asyncmax ((loop)->asyncmax) |
||||
|
#define asynccnt ((loop)->asynccnt) |
||||
|
#define fs_fd ((loop)->fs_fd) |
||||
|
#define fs_w ((loop)->fs_w) |
||||
|
#define fs_2625 ((loop)->fs_2625) |
||||
|
#define fs_hash ((loop)->fs_hash) |
||||
|
#else |
||||
|
#undef EV_WRAP_H |
||||
|
#undef now_floor |
||||
|
#undef mn_now |
||||
|
#undef rtmn_diff |
||||
|
#undef io_blocktime |
||||
|
#undef timeout_blocktime |
||||
|
#undef backend |
||||
|
#undef activecnt |
||||
|
#undef loop_count |
||||
|
#undef backend_fd |
||||
|
#undef backend_fudge |
||||
|
#undef backend_modify |
||||
|
#undef backend_poll |
||||
|
#undef evfd |
||||
|
#undef evpipe |
||||
|
#undef pipeev |
||||
|
#undef curpid |
||||
|
#undef postfork |
||||
|
#undef vec_ri |
||||
|
#undef vec_ro |
||||
|
#undef vec_wi |
||||
|
#undef vec_wo |
||||
|
#undef vec_eo |
||||
|
#undef vec_max |
||||
|
#undef polls |
||||
|
#undef pollmax |
||||
|
#undef pollcnt |
||||
|
#undef pollidxs |
||||
|
#undef pollidxmax |
||||
|
#undef epoll_events |
||||
|
#undef epoll_eventmax |
||||
|
#undef kqueue_changes |
||||
|
#undef kqueue_changemax |
||||
|
#undef kqueue_changecnt |
||||
|
#undef kqueue_events |
||||
|
#undef kqueue_eventmax |
||||
|
#undef port_events |
||||
|
#undef port_eventmax |
||||
|
#undef anfds |
||||
|
#undef anfdmax |
||||
|
#undef pendings |
||||
|
#undef pendingmax |
||||
|
#undef pendingcnt |
||||
|
#undef fdchanges |
||||
|
#undef fdchangemax |
||||
|
#undef fdchangecnt |
||||
|
#undef timers |
||||
|
#undef timermax |
||||
|
#undef timercnt |
||||
|
#undef periodics |
||||
|
#undef periodicmax |
||||
|
#undef periodiccnt |
||||
|
#undef idles |
||||
|
#undef idlemax |
||||
|
#undef idlecnt |
||||
|
#undef idleall |
||||
|
#undef prepares |
||||
|
#undef preparemax |
||||
|
#undef preparecnt |
||||
|
#undef checks |
||||
|
#undef checkmax |
||||
|
#undef checkcnt |
||||
|
#undef forks |
||||
|
#undef forkmax |
||||
|
#undef forkcnt |
||||
|
#undef gotasync |
||||
|
#undef asyncs |
||||
|
#undef asyncmax |
||||
|
#undef asynccnt |
||||
|
#undef fs_fd |
||||
|
#undef fs_w |
||||
|
#undef fs_2625 |
||||
|
#undef fs_hash |
||||
|
#endif |
@ -0,0 +1,401 @@ |
|||||
|
/*
|
||||
|
* libevent compatibility layer |
||||
|
* |
||||
|
* Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <libev@schmorp.de> |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without modifica- |
||||
|
* tion, 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 MER- |
||||
|
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- |
||||
|
* CIAL, 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 OTH- |
||||
|
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
* |
||||
|
* Alternatively, the contents of this file may be used under the terms of |
||||
|
* the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
* in which case the provisions of the GPL are applicable instead of |
||||
|
* the above. If you wish to allow the use of your version of this file |
||||
|
* only under the terms of the GPL and not to allow others to use your |
||||
|
* version of this file under the BSD license, indicate your decision |
||||
|
* by deleting the provisions above and replace them with the notice |
||||
|
* and other provisions required by the GPL. If you do not delete the |
||||
|
* provisions above, a recipient may use your version of this file under |
||||
|
* either the BSD or the GPL. |
||||
|
*/ |
||||
|
|
||||
|
#include <stddef.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <assert.h> |
||||
|
|
||||
|
#ifdef EV_EVENT_H |
||||
|
# include EV_EVENT_H |
||||
|
#else |
||||
|
# include "event.h" |
||||
|
#endif |
||||
|
|
||||
|
#if EV_MULTIPLICITY |
||||
|
# define dLOOPev struct ev_loop *loop = (struct ev_loop *)ev->ev_base |
||||
|
# define dLOOPbase struct ev_loop *loop = (struct ev_loop *)base |
||||
|
#else |
||||
|
# define dLOOPev |
||||
|
# define dLOOPbase |
||||
|
#endif |
||||
|
|
||||
|
/* never accessed, will always be cast from/to ev_loop */ |
||||
|
struct event_base |
||||
|
{ |
||||
|
int dummy; |
||||
|
}; |
||||
|
|
||||
|
static struct event_base *ev_x_cur; |
||||
|
|
||||
|
static void |
||||
|
ev_tv_set (struct timeval *tv, ev_tstamp at) |
||||
|
{ |
||||
|
tv->tv_sec = (long)at; |
||||
|
tv->tv_usec = (long)((at - (ev_tstamp)tv->tv_sec) * 1e6); |
||||
|
} |
||||
|
|
||||
|
static ev_tstamp |
||||
|
ev_tv_get (struct timeval *tv) |
||||
|
{ |
||||
|
if (tv) |
||||
|
return tv->tv_sec + tv->tv_usec * 1e-6; |
||||
|
else |
||||
|
return -1.; |
||||
|
} |
||||
|
|
||||
|
#define EVENT_STRINGIFY(s) # s |
||||
|
#define EVENT_VERSION(a,b) EVENT_STRINGIFY (a) "." EVENT_STRINGIFY (b) |
||||
|
|
||||
|
const char *event_get_version (void) |
||||
|
{ |
||||
|
/* returns ABI, not API or library, version */ |
||||
|
return EVENT_VERSION (EV_VERSION_MAJOR, EV_VERSION_MINOR); |
||||
|
} |
||||
|
|
||||
|
const char *event_get_method (void) |
||||
|
{ |
||||
|
return "libev"; |
||||
|
} |
||||
|
|
||||
|
void *event_init (void) |
||||
|
{ |
||||
|
#if EV_MULTIPLICITY |
||||
|
if (ev_x_cur) |
||||
|
ev_x_cur = (struct event_base *)ev_loop_new (EVFLAG_AUTO); |
||||
|
else |
||||
|
ev_x_cur = (struct event_base *)ev_default_loop (EVFLAG_AUTO); |
||||
|
#else |
||||
|
assert (("libev: multiple event bases not supported when not compiled with EV_MULTIPLICITY", !ev_x_cur)); |
||||
|
|
||||
|
ev_x_cur = (struct event_base *)(long)ev_default_loop (EVFLAG_AUTO); |
||||
|
#endif |
||||
|
|
||||
|
return ev_x_cur; |
||||
|
} |
||||
|
|
||||
|
void event_base_free (struct event_base *base) |
||||
|
{ |
||||
|
dLOOPbase; |
||||
|
|
||||
|
#if EV_MULTIPLICITY |
||||
|
if (ev_default_loop (EVFLAG_AUTO) != loop) |
||||
|
ev_loop_destroy (loop); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
int event_dispatch (void) |
||||
|
{ |
||||
|
return event_base_dispatch (ev_x_cur); |
||||
|
} |
||||
|
|
||||
|
#ifdef EV_STANDALONE |
||||
|
void event_set_log_callback (event_log_cb cb) |
||||
|
{ |
||||
|
/* nop */ |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
int event_loop (int flags) |
||||
|
{ |
||||
|
return event_base_loop (ev_x_cur, flags); |
||||
|
} |
||||
|
|
||||
|
int event_loopexit (struct timeval *tv) |
||||
|
{ |
||||
|
return event_base_loopexit (ev_x_cur, tv); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
ev_x_cb (struct event *ev, int revents) |
||||
|
{ |
||||
|
revents &= EV_READ | EV_WRITE | EV_TIMEOUT | EV_SIGNAL; |
||||
|
|
||||
|
ev->ev_res = revents; |
||||
|
ev->ev_callback (ev->ev_fd, (short)revents, ev->ev_arg); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
ev_x_cb_sig (EV_P_ struct ev_signal *w, int revents) |
||||
|
{ |
||||
|
struct event *ev = (struct event *)(((char *)w) - offsetof (struct event, iosig.sig)); |
||||
|
|
||||
|
if (revents & EV_ERROR) |
||||
|
event_del (ev); |
||||
|
|
||||
|
ev_x_cb (ev, revents); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
ev_x_cb_io (EV_P_ struct ev_io *w, int revents) |
||||
|
{ |
||||
|
struct event *ev = (struct event *)(((char *)w) - offsetof (struct event, iosig.io)); |
||||
|
|
||||
|
if ((revents & EV_ERROR) || !(ev->ev_events & EV_PERSIST)) |
||||
|
event_del (ev); |
||||
|
|
||||
|
ev_x_cb (ev, revents); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
ev_x_cb_to (EV_P_ struct ev_timer *w, int revents) |
||||
|
{ |
||||
|
struct event *ev = (struct event *)(((char *)w) - offsetof (struct event, to)); |
||||
|
|
||||
|
event_del (ev); |
||||
|
|
||||
|
ev_x_cb (ev, revents); |
||||
|
} |
||||
|
|
||||
|
void event_set (struct event *ev, int fd, short events, void (*cb)(int, short, void *), void *arg) |
||||
|
{ |
||||
|
if (events & EV_SIGNAL) |
||||
|
ev_init (&ev->iosig.sig, ev_x_cb_sig); |
||||
|
else |
||||
|
ev_init (&ev->iosig.io, ev_x_cb_io); |
||||
|
|
||||
|
ev_init (&ev->to, ev_x_cb_to); |
||||
|
|
||||
|
ev->ev_base = ev_x_cur; /* not threadsafe, but it's how libevent works */ |
||||
|
ev->ev_fd = fd; |
||||
|
ev->ev_events = events; |
||||
|
ev->ev_pri = 0; |
||||
|
ev->ev_callback = cb; |
||||
|
ev->ev_arg = arg; |
||||
|
ev->ev_res = 0; |
||||
|
ev->ev_flags = EVLIST_INIT; |
||||
|
} |
||||
|
|
||||
|
int event_once (int fd, short events, void (*cb)(int, short, void *), void *arg, struct timeval *tv) |
||||
|
{ |
||||
|
return event_base_once (ev_x_cur, fd, events, cb, arg, tv); |
||||
|
} |
||||
|
|
||||
|
int event_add (struct event *ev, struct timeval *tv) |
||||
|
{ |
||||
|
dLOOPev; |
||||
|
|
||||
|
if (ev->ev_events & EV_SIGNAL) |
||||
|
{ |
||||
|
if (!ev_is_active (&ev->iosig.sig)) |
||||
|
{ |
||||
|
ev_signal_set (&ev->iosig.sig, ev->ev_fd); |
||||
|
ev_signal_start (EV_A_ &ev->iosig.sig); |
||||
|
|
||||
|
ev->ev_flags |= EVLIST_SIGNAL; |
||||
|
} |
||||
|
} |
||||
|
else if (ev->ev_events & (EV_READ | EV_WRITE)) |
||||
|
{ |
||||
|
if (!ev_is_active (&ev->iosig.io)) |
||||
|
{ |
||||
|
ev_io_set (&ev->iosig.io, ev->ev_fd, ev->ev_events & (EV_READ | EV_WRITE)); |
||||
|
ev_io_start (EV_A_ &ev->iosig.io); |
||||
|
|
||||
|
ev->ev_flags |= EVLIST_INSERTED; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (tv) |
||||
|
{ |
||||
|
ev->to.repeat = ev_tv_get (tv); |
||||
|
ev_timer_again (EV_A_ &ev->to); |
||||
|
ev->ev_flags |= EVLIST_TIMEOUT; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
ev_timer_stop (EV_A_ &ev->to); |
||||
|
ev->ev_flags &= ~EVLIST_TIMEOUT; |
||||
|
} |
||||
|
|
||||
|
ev->ev_flags |= EVLIST_ACTIVE; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int event_del (struct event *ev) |
||||
|
{ |
||||
|
dLOOPev; |
||||
|
|
||||
|
if (ev->ev_events & EV_SIGNAL) |
||||
|
ev_signal_stop (EV_A_ &ev->iosig.sig); |
||||
|
else if (ev->ev_events & (EV_READ | EV_WRITE)) |
||||
|
ev_io_stop (EV_A_ &ev->iosig.io); |
||||
|
|
||||
|
if (ev_is_active (&ev->to)) |
||||
|
ev_timer_stop (EV_A_ &ev->to); |
||||
|
|
||||
|
ev->ev_flags = EVLIST_INIT; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void event_active (struct event *ev, int res, short ncalls) |
||||
|
{ |
||||
|
dLOOPev; |
||||
|
|
||||
|
if (res & EV_TIMEOUT) |
||||
|
ev_feed_event (EV_A_ &ev->to, res & EV_TIMEOUT); |
||||
|
|
||||
|
if (res & EV_SIGNAL) |
||||
|
ev_feed_event (EV_A_ &ev->iosig.sig, res & EV_SIGNAL); |
||||
|
|
||||
|
if (res & (EV_READ | EV_WRITE)) |
||||
|
ev_feed_event (EV_A_ &ev->iosig.io, res & (EV_READ | EV_WRITE)); |
||||
|
} |
||||
|
|
||||
|
int event_pending (struct event *ev, short events, struct timeval *tv) |
||||
|
{ |
||||
|
short revents = 0; |
||||
|
dLOOPev; |
||||
|
|
||||
|
if (ev->ev_events & EV_SIGNAL) |
||||
|
{ |
||||
|
/* sig */ |
||||
|
if (ev_is_active (&ev->iosig.sig) || ev_is_pending (&ev->iosig.sig)) |
||||
|
revents |= EV_SIGNAL; |
||||
|
} |
||||
|
else if (ev->ev_events & (EV_READ | EV_WRITE)) |
||||
|
{ |
||||
|
/* io */ |
||||
|
if (ev_is_active (&ev->iosig.io) || ev_is_pending (&ev->iosig.io)) |
||||
|
revents |= ev->ev_events & (EV_READ | EV_WRITE); |
||||
|
} |
||||
|
|
||||
|
if (ev->ev_events & EV_TIMEOUT || ev_is_active (&ev->to) || ev_is_pending (&ev->to)) |
||||
|
{ |
||||
|
revents |= EV_TIMEOUT; |
||||
|
|
||||
|
if (tv) |
||||
|
ev_tv_set (tv, ev_now (EV_A)); /* not sure if this is right :) */ |
||||
|
} |
||||
|
|
||||
|
return events & revents; |
||||
|
} |
||||
|
|
||||
|
int event_priority_init (int npri) |
||||
|
{ |
||||
|
return event_base_priority_init (ev_x_cur, npri); |
||||
|
} |
||||
|
|
||||
|
int event_priority_set (struct event *ev, int pri) |
||||
|
{ |
||||
|
ev->ev_pri = pri; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int event_base_set (struct event_base *base, struct event *ev) |
||||
|
{ |
||||
|
ev->ev_base = base; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int event_base_loop (struct event_base *base, int flags) |
||||
|
{ |
||||
|
dLOOPbase; |
||||
|
|
||||
|
ev_loop (EV_A_ flags); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int event_base_dispatch (struct event_base *base) |
||||
|
{ |
||||
|
return event_base_loop (base, 0); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
ev_x_loopexit_cb (int revents, void *base) |
||||
|
{ |
||||
|
dLOOPbase; |
||||
|
|
||||
|
ev_unloop (EV_A_ EVUNLOOP_ONE); |
||||
|
} |
||||
|
|
||||
|
int event_base_loopexit (struct event_base *base, struct timeval *tv) |
||||
|
{ |
||||
|
ev_tstamp after = ev_tv_get (tv); |
||||
|
dLOOPbase; |
||||
|
|
||||
|
ev_once (EV_A_ -1, 0, after >= 0. ? after : 0., ev_x_loopexit_cb, (void *)base); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
struct ev_x_once |
||||
|
{ |
||||
|
int fd; |
||||
|
void (*cb)(int, short, void *); |
||||
|
void *arg; |
||||
|
}; |
||||
|
|
||||
|
static void |
||||
|
ev_x_once_cb (int revents, void *arg) |
||||
|
{ |
||||
|
struct ev_x_once *once = (struct ev_x_once *)arg; |
||||
|
|
||||
|
once->cb (once->fd, (short)revents, once->arg); |
||||
|
free (once); |
||||
|
} |
||||
|
|
||||
|
int event_base_once (struct event_base *base, int fd, short events, void (*cb)(int, short, void *), void *arg, struct timeval *tv) |
||||
|
{ |
||||
|
struct ev_x_once *once = (struct ev_x_once *)malloc (sizeof (struct ev_x_once)); |
||||
|
dLOOPbase; |
||||
|
|
||||
|
if (!once) |
||||
|
return -1; |
||||
|
|
||||
|
once->fd = fd; |
||||
|
once->cb = cb; |
||||
|
once->arg = arg; |
||||
|
|
||||
|
ev_once (EV_A_ fd, events & (EV_READ | EV_WRITE), ev_tv_get (tv), ev_x_once_cb, (void *)once); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int event_base_priority_init (struct event_base *base, int npri) |
||||
|
{ |
||||
|
/*dLOOPbase;*/ |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
@ -0,0 +1,158 @@ |
|||||
|
/*
|
||||
|
* libevent compatibility header, only core events supported |
||||
|
* |
||||
|
* Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de> |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without modifica- |
||||
|
* tion, 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 MER- |
||||
|
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- |
||||
|
* CIAL, 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 OTH- |
||||
|
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
* |
||||
|
* Alternatively, the contents of this file may be used under the terms of |
||||
|
* the GNU General Public License ("GPL") version 2 or any later version, |
||||
|
* in which case the provisions of the GPL are applicable instead of |
||||
|
* the above. If you wish to allow the use of your version of this file |
||||
|
* only under the terms of the GPL and not to allow others to use your |
||||
|
* version of this file under the BSD license, indicate your decision |
||||
|
* by deleting the provisions above and replace them with the notice |
||||
|
* and other provisions required by the GPL. If you do not delete the |
||||
|
* provisions above, a recipient may use your version of this file under |
||||
|
* either the BSD or the GPL. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef EVENT_H__ |
||||
|
#define EVENT_H__ |
||||
|
|
||||
|
#ifdef EV_H |
||||
|
# include EV_H |
||||
|
#else |
||||
|
# include "ev.h" |
||||
|
#endif |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
/* we need sys/time.h for struct timeval only */ |
||||
|
#if !defined (WIN32) || defined (__MINGW32__) |
||||
|
# include <time.h> /* mingw seems to need this, for whatever reason */ |
||||
|
# include <sys/time.h> |
||||
|
#endif |
||||
|
|
||||
|
struct event_base; |
||||
|
|
||||
|
#define EVLIST_TIMEOUT 0x01 |
||||
|
#define EVLIST_INSERTED 0x02 |
||||
|
#define EVLIST_SIGNAL 0x04 |
||||
|
#define EVLIST_ACTIVE 0x08 |
||||
|
#define EVLIST_INTERNAL 0x10 |
||||
|
#define EVLIST_INIT 0x80 |
||||
|
|
||||
|
struct event |
||||
|
{ |
||||
|
/* libev watchers we map onto */ |
||||
|
union { |
||||
|
struct ev_io io; |
||||
|
struct ev_signal sig; |
||||
|
} iosig; |
||||
|
struct ev_timer to; |
||||
|
|
||||
|
/* compatibility slots */ |
||||
|
struct event_base *ev_base; |
||||
|
void (*ev_callback)(int, short, void *arg); |
||||
|
void *ev_arg; |
||||
|
int ev_fd; |
||||
|
int ev_pri; |
||||
|
int ev_res; |
||||
|
int ev_flags; |
||||
|
short ev_events; |
||||
|
}; |
||||
|
|
||||
|
#define EV_PERSIST 0x10 |
||||
|
|
||||
|
#define EVENT_SIGNAL(ev) ((int) (ev)->ev_fd) |
||||
|
#define EVENT_FD(ev) ((int) (ev)->ev_fd) |
||||
|
|
||||
|
#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) |
||||
|
|
||||
|
#define evtimer_add(ev,tv) event_add (ev, tv) |
||||
|
#define evtimer_set(ev,cb,data) event_set (ev, -1, 0, cb, data) |
||||
|
#define evtimer_del(ev) event_del (ev) |
||||
|
#define evtimer_pending(ev,tv) event_pending (ev, EV_TIMEOUT, tv) |
||||
|
#define evtimer_initialized(ev) event_initialized (ev) |
||||
|
|
||||
|
#define timeout_add(ev,tv) evtimer_add (ev, tv) |
||||
|
#define timeout_set(ev,cb,data) evtimer_set (ev, cb, data) |
||||
|
#define timeout_del(ev) evtimer_del (ev) |
||||
|
#define timeout_pending(ev,tv) evtimer_pending (ev, tv) |
||||
|
#define timeout_initialized(ev) evtimer_initialized (ev) |
||||
|
|
||||
|
#define signal_add(ev,tv) event_add (ev, tv) |
||||
|
#define signal_set(ev,sig,cb,data) event_set (ev, sig, EV_SIGNAL | EV_PERSIST, cb, data) |
||||
|
#define signal_del(ev) event_del (ev) |
||||
|
#define signal_pending(ev,tv) event_pending (ev, EV_SIGNAL, tv) |
||||
|
#define signal_initialized(ev) event_initialized (ev) |
||||
|
|
||||
|
const char *event_get_version (void); |
||||
|
const char *event_get_method (void); |
||||
|
|
||||
|
void *event_init (void); |
||||
|
void event_base_free (struct event_base *base); |
||||
|
|
||||
|
#define EVLOOP_ONCE EVLOOP_ONESHOT |
||||
|
int event_loop (int); |
||||
|
int event_loopexit (struct timeval *tv); |
||||
|
int event_dispatch (void); |
||||
|
|
||||
|
#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); |
||||
|
void event_set_log_callback(event_log_cb cb); |
||||
|
|
||||
|
void event_set (struct event *ev, int fd, short events, void (*cb)(int, short, void *), void *arg); |
||||
|
int event_once (int fd, short events, void (*cb)(int, short, void *), void *arg, struct timeval *tv); |
||||
|
|
||||
|
int event_add (struct event *ev, struct timeval *tv); |
||||
|
int event_del (struct event *ev); |
||||
|
void event_active (struct event *ev, int res, short ncalls); /* ncalls is being ignored */ |
||||
|
|
||||
|
int event_pending (struct event *ev, short, struct timeval *tv); |
||||
|
|
||||
|
int event_priority_init (int npri); |
||||
|
int event_priority_set (struct event *ev, int pri); |
||||
|
|
||||
|
int event_base_set (struct event_base *base, struct event *ev); |
||||
|
int event_base_loop (struct event_base *base, int); |
||||
|
int event_base_loopexit (struct event_base *base, struct timeval *tv); |
||||
|
int event_base_dispatch (struct event_base *base); |
||||
|
int event_base_once (struct event_base *base, int fd, short events, void (*cb)(int, short, void *), void *arg, struct timeval *tv); |
||||
|
int event_base_priority_init (struct event_base *base, int fd); |
||||
|
|
||||
|
/* next line is different in the libevent+libev version */ |
||||
|
/*libevent-include*/ |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,226 @@ |
|||||
|
/*
|
||||
|
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu> |
||||
|
* Copyright (c) 2008 Marc Alexander Lehmann <libev@schmorp.de> |
||||
|
* 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 __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#ifdef _WIN32 |
||||
|
# define WIN32_LEAN_AND_MEAN |
||||
|
# include <windows.h> |
||||
|
# undef WIN32_LEAN_AND_MEAN |
||||
|
typedef unsigned char u_char; |
||||
|
typedef unsigned short u_short; |
||||
|
#else |
||||
|
# include <sys/types.h> |
||||
|
# include <sys/time.h> |
||||
|
# include <inttypes.h> |
||||
|
#endif |
||||
|
|
||||
|
#include <stdarg.h> |
||||
|
|
||||
|
/* Fix so that ppl dont have to run with <sys/queue.h> */ |
||||
|
#ifndef TAILQ_ENTRY |
||||
|
#define _EVENT_DEFINED_TQENTRY |
||||
|
#define TAILQ_ENTRY(type) \ |
||||
|
struct { \ |
||||
|
struct type *tqe_next; /* next element */ \ |
||||
|
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 */ |
||||
|
|
||||
|
/*
|
||||
|
* 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 (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 eventop { |
||||
|
char *name; |
||||
|
void *(*init)(struct event_base *); |
||||
|
int (*add)(void *, struct event *); |
||||
|
int (*del)(void *, struct event *); |
||||
|
int (*recalc)(struct event_base *, void *, int); |
||||
|
int (*dispatch)(struct event_base *, void *, struct timeval *); |
||||
|
void (*dealloc)(struct event_base *, void *); |
||||
|
}; |
||||
|
|
||||
|
/* These functions deal with buffering input and output */ |
||||
|
|
||||
|
struct evbuffer { |
||||
|
u_char *buffer; |
||||
|
u_char *orig_buffer; |
||||
|
|
||||
|
size_t misalign; |
||||
|
size_t totallen; |
||||
|
size_t off; |
||||
|
|
||||
|
void (*cb)(struct evbuffer *, size_t, size_t, void *); |
||||
|
void *cbarg; |
||||
|
}; |
||||
|
|
||||
|
/* Just for error reporting - use other constants otherwise */ |
||||
|
#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 *); |
||||
|
typedef void (*everrorcb)(struct bufferevent *, short what, void *); |
||||
|
|
||||
|
struct event_watermark { |
||||
|
size_t low; |
||||
|
size_t high; |
||||
|
}; |
||||
|
|
||||
|
struct bufferevent { |
||||
|
struct event ev_read; |
||||
|
struct event ev_write; |
||||
|
|
||||
|
struct evbuffer *input; |
||||
|
struct evbuffer *output; |
||||
|
|
||||
|
struct event_watermark wm_read; |
||||
|
struct event_watermark wm_write; |
||||
|
|
||||
|
evbuffercb readcb; |
||||
|
evbuffercb writecb; |
||||
|
everrorcb errorcb; |
||||
|
void *cbarg; |
||||
|
|
||||
|
int timeout_read; /* in seconds */ |
||||
|
int timeout_write; /* in seconds */ |
||||
|
|
||||
|
short enabled; /* events that are currently enabled */ |
||||
|
}; |
||||
|
|
||||
|
struct bufferevent *bufferevent_new(int fd, |
||||
|
evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg); |
||||
|
int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev); |
||||
|
int bufferevent_priority_set(struct bufferevent *bufev, int pri); |
||||
|
void bufferevent_free(struct bufferevent *bufev); |
||||
|
int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size); |
||||
|
int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf); |
||||
|
size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size); |
||||
|
int bufferevent_enable(struct bufferevent *bufev, short event); |
||||
|
int bufferevent_disable(struct bufferevent *bufev, short event); |
||||
|
void bufferevent_settimeout(struct bufferevent *bufev, |
||||
|
int timeout_read, int timeout_write); |
||||
|
|
||||
|
#define EVBUFFER_LENGTH(x) (x)->off |
||||
|
#define EVBUFFER_DATA(x) (x)->buffer |
||||
|
#define EVBUFFER_INPUT(x) (x)->input |
||||
|
#define EVBUFFER_OUTPUT(x) (x)->output |
||||
|
|
||||
|
struct evbuffer *evbuffer_new(void); |
||||
|
void evbuffer_free(struct evbuffer *); |
||||
|
int evbuffer_expand(struct evbuffer *, size_t); |
||||
|
int evbuffer_add(struct evbuffer *, const void *, size_t); |
||||
|
int evbuffer_remove(struct evbuffer *, void *, size_t); |
||||
|
char *evbuffer_readline(struct evbuffer *); |
||||
|
int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *); |
||||
|
int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...); |
||||
|
int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap); |
||||
|
void evbuffer_drain(struct evbuffer *, size_t); |
||||
|
int evbuffer_write(struct evbuffer *, int); |
||||
|
int evbuffer_read(struct evbuffer *, int, int); |
||||
|
u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t); |
||||
|
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, uint32_t tag, const void *data, |
||||
|
uint32_t len); |
||||
|
|
||||
|
void encode_int(struct evbuffer *evbuf, uint32_t number); |
||||
|
|
||||
|
void evtag_marshal_int(struct evbuffer *evbuf, uint32_t tag, uint32_t integer); |
||||
|
|
||||
|
void evtag_marshal_string(struct evbuffer *buf, uint32_t tag, |
||||
|
const char *string); |
||||
|
|
||||
|
void evtag_marshal_timeval(struct evbuffer *evbuf, uint32_t tag, |
||||
|
struct timeval *tv); |
||||
|
|
||||
|
int evtag_unmarshal(struct evbuffer *src, uint32_t *ptag, struct evbuffer *dst); |
||||
|
int evtag_peek(struct evbuffer *evbuf, uint32_t *ptag); |
||||
|
int evtag_peek_length(struct evbuffer *evbuf, uint32_t *plength); |
||||
|
int evtag_payload_length(struct evbuffer *evbuf, uint32_t *plength); |
||||
|
int evtag_consume(struct evbuffer *evbuf); |
||||
|
|
||||
|
int evtag_unmarshal_int(struct evbuffer *evbuf, uint32_t need_tag, |
||||
|
uint32_t *pinteger); |
||||
|
|
||||
|
int evtag_unmarshal_fixed(struct evbuffer *src, uint32_t need_tag, void *data, |
||||
|
size_t len); |
||||
|
|
||||
|
int evtag_unmarshal_string(struct evbuffer *evbuf, uint32_t need_tag, |
||||
|
char **pstring); |
||||
|
|
||||
|
int evtag_unmarshal_timeval(struct evbuffer *evbuf, uint32_t need_tag, |
||||
|
struct timeval *ptv); |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
@ -0,0 +1,131 @@ |
|||||
|
#!/bin/sh |
||||
|
|
||||
|
LE=../libevent-1.4.3-stable |
||||
|
|
||||
|
if ! [ -e evbuffer.c ]; then |
||||
|
echo do not run this programm unless you know what you are doing |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
# this program combines libev and libevent into a single package |
||||
|
|
||||
|
cvs update -AdP libev |
||||
|
rsync -avP libev/. . --exclude CVS |
||||
|
|
||||
|
rm -f configure.ac |
||||
|
|
||||
|
cp $LE/evdns.h . |
||||
|
|
||||
|
perl -i -pe 's%^/.libevent-include./%#include "event_compat.h"%' event.h |
||||
|
|
||||
|
perl -ne ' |
||||
|
s/\s+char buf\[64\];/\tchar buf[96];/; |
||||
|
if (/#include "event.h"/) { |
||||
|
print "#ifndef EV_STANDALONE\n$_#endif\n"; |
||||
|
next; |
||||
|
} |
||||
|
if (/#include "misc.h"/) { |
||||
|
print "#ifndef EV_STANDALONE\n$_#endif\n"; |
||||
|
next; |
||||
|
} |
||||
|
if (/#include "(unistd.h|sys\/time.h)"/) { |
||||
|
print "#ifndef WIN32\n$_#endif\n"; |
||||
|
next; |
||||
|
} |
||||
|
next if /#include "log.h"/; |
||||
|
|
||||
|
print; |
||||
|
' <$LE/evdns.c >evdns.c |
||||
|
|
||||
|
cp $LE/autogen.sh . |
||||
|
cp $LE/epoll_sub.c . |
||||
|
cp $LE/evbuffer.c . |
||||
|
cp $LE/buffer.c . |
||||
|
cp $LE/evhttp.h . |
||||
|
cp $LE/evutil.h . |
||||
|
cp $LE/evutil.c . |
||||
|
cp $LE/event-config.h . |
||||
|
cp $LE/event-internal.h . |
||||
|
cp $LE/evrpc.h . |
||||
|
cp $LE/evrpc.c . |
||||
|
cp $LE/evrpc-internal.h . |
||||
|
cp $LE/http.c . |
||||
|
cp $LE/event_tagging.c . |
||||
|
cp $LE/http-internal.h . |
||||
|
cp $LE/strlcpy-internal.h . |
||||
|
cp $LE/log.c . |
||||
|
cp $LE/log.h . |
||||
|
cp $LE/strlcpy.c . |
||||
|
rsync -a $LE/WIN32* $LE/sample $LE/test $LE/compat . --del |
||||
|
#rename 's/libevent/libev/' WIN32-Prj/lib* |
||||
|
cp $LE/aclocal.m4 . |
||||
|
#cp $LE/acconfig.h . |
||||
|
cp $LE/config.h.in . |
||||
|
cp $LE/event_rpcgen.py . |
||||
|
cp $LE/*.3 . |
||||
|
|
||||
|
#perl -i -pe 's/libevent/libev/g' sample/Makefile.am |
||||
|
#perl -i -pe 's/libevent/libev/g' test/Makefile.am |
||||
|
|
||||
|
perl -i -pe 's/#include <event.h>$/#include "event.h"/' test/*.c |
||||
|
|
||||
|
perl -i -ne ' |
||||
|
next if /"event-internal.h"/; |
||||
|
s/base\d?->sig.ev_signal_added/0/; |
||||
|
s/base\d?->sig.ev_signal_pair\[0\]/-1/; |
||||
|
s/base->sig.evsignal_caught/0/; |
||||
|
next if /^\ttest_signal_(dealloc|pipeloss|switchbase|assert|restore)\(\)/; |
||||
|
next if /^\ttest_simplesignal\(\)/; # non-default-loop |
||||
|
next if /^\ttest_immediatesignal\(\)/; # non-default-loop |
||||
|
next if /test_priorities\(\d\)/; |
||||
|
print; |
||||
|
' test/regress.c |
||||
|
|
||||
|
perl -ne ' |
||||
|
s/\bmin_heap.h\b//g; |
||||
|
s/\bsignal.c\b//g; |
||||
|
s/\bevport.c\b//g; |
||||
|
s/\bkqueue.c\b//g; |
||||
|
s/\bdevpoll.c\b//g; |
||||
|
s/\brtsig.c\b//g; |
||||
|
s/\bselect.c\b//g; |
||||
|
s/\bpoll.c\b//g; |
||||
|
s/\bepoll.c\b//g; |
||||
|
s/\bepoll_sub.c\b//g; |
||||
|
s/\bevent-internal.h\b//g; |
||||
|
s/\bevsignal.h\b//g; |
||||
|
s/^(man_MANS\s*=)/$1 ev.3 /; |
||||
|
s/^(EXTRA_DIST\s*=)/$1 libev.m4 ev.h ev_vars.h ev_wrap.h event_compat.h ev++.h ev_epoll.c ev_select.c ev_poll.c ev_kqueue.c ev_port.c ev_win32.c ev.3 ev.pod /; |
||||
|
s/^(include_HEADERS\s*=)/$1 ev.h event_compat.h ev++.h /; |
||||
|
s/^(CORE_SRC\s*=)/$1 ev.c /; |
||||
|
s/^(SYS_LIBS\s*=)/$1 -lm /; |
||||
|
#s/libevent/libev/g; |
||||
|
print; |
||||
|
' <$LE/Makefile.am >Makefile.am |
||||
|
|
||||
|
perl -ne ' |
||||
|
#s/-Wall/-Wall -Wno-comment -Wunused-function -Wno-unused-value/; |
||||
|
s/-Wall//g; |
||||
|
#s/libevent/libev/g; |
||||
|
#VERSION |
||||
|
s/AM_INIT_AUTOMAKE\s*\(.*,(.*)\)/AM_INIT_AUTOMAKE(libevent-$1+libev,3.1)/; |
||||
|
s/AC_LIBOBJ\(select\)/: ;/g; |
||||
|
s/AC_LIBOBJ\(poll\)/: ;/g; |
||||
|
s/AC_LIBOBJ\(kqueue\)/: ;/g; |
||||
|
s/AC_LIBOBJ\(epoll\)/: ;/g; |
||||
|
s/AC_LIBOBJ\(devpoll\)/: ;/g; |
||||
|
s/AC_LIBOBJ\(evport\)/: ;/g; |
||||
|
s/AC_LIBOBJ\(signal\)/: ;/g; |
||||
|
s/AC_LIBOBJ\(rtsig\)/: ;/g; |
||||
|
print "m4_include([libev.m4])\n" if /^AC_OUTPUT/; |
||||
|
print; |
||||
|
' <$LE/configure.in >configure.in |
||||
|
|
||||
|
aclocal-1.7 |
||||
|
automake-1.7 --add-missing |
||||
|
autoconf |
||||
|
autoheader |
||||
|
libtoolize |
||||
|
CC="ccache gcc" ./configure --prefix=/opt/libev --disable-shared "$@" |
||||
|
|
||||
|
|
@ -0,0 +1,40 @@ |
|||||
|
dnl this file is part of libev, do not make local modifications |
||||
|
dnl http://software.schmorp.de/pkg/libev |
||||
|
|
||||
|
dnl libev support |
||||
|
AC_CHECK_HEADERS(sys/inotify.h sys/epoll.h sys/event.h sys/queue.h port.h poll.h sys/select.h sys/eventfd.h) |
||||
|
|
||||
|
AC_CHECK_FUNCS(inotify_init epoll_ctl kqueue port_create poll select eventfd) |
||||
|
|
||||
|
AC_CHECK_FUNC(clock_gettime, [], [ |
||||
|
dnl on linux, try syscall wrapper first |
||||
|
if test $(uname) = Linux; then |
||||
|
AC_MSG_CHECKING(for clock_gettime syscall) |
||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM( |
||||
|
[#include <syscall.h> |
||||
|
#include <time.h>], |
||||
|
[struct timespec ts; int status = syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts)])], |
||||
|
[ac_have_clock_syscall=1 |
||||
|
AC_DEFINE(HAVE_CLOCK_SYSCALL, 1, "use syscall interface for clock_gettime") |
||||
|
AC_MSG_RESULT(yes)], |
||||
|
[AC_MSG_RESULT(no)]) |
||||
|
fi |
||||
|
if test -z "$LIBEV_M4_AVOID_LIBRT" && test -z "$ac_have_clock_syscall"; then |
||||
|
AC_CHECK_LIB(rt, clock_gettime) |
||||
|
unset ac_cv_func_clock_gettime |
||||
|
AC_CHECK_FUNCS(clock_gettime) |
||||
|
fi |
||||
|
]) |
||||
|
|
||||
|
AC_CHECK_FUNC(nanosleep, [], [ |
||||
|
if test -z "$LIBEV_M4_AVOID_LIBRT"; then |
||||
|
AC_CHECK_LIB(rt, nanosleep) |
||||
|
unset ac_cv_func_nanosleep |
||||
|
AC_CHECK_FUNCS(nanosleep) |
||||
|
fi |
||||
|
]) |
||||
|
|
||||
|
AC_CHECK_LIB(m, ceil) |
||||
|
|
||||
|
|
||||
|
|
@ -0,0 +1,19 @@ |
|||||
|
#!/bin/sh |
||||
|
|
||||
|
( |
||||
|
echo '#define VAR(name,decl) name' |
||||
|
echo '#define EV_GENWRAP 1' |
||||
|
cat ev_vars.h |
||||
|
) | cc -E -o - - | perl -ne ' |
||||
|
while (<>) { |
||||
|
push @syms, $1 if /(^\w+)/; |
||||
|
} |
||||
|
print "/* DO NOT EDIT, automatically generated by update_ev_wrap */\n", |
||||
|
"#ifndef EV_WRAP_H\n", |
||||
|
"#define EV_WRAP_H\n", |
||||
|
(map "#define $_ ((loop)->$_)\n", @syms), |
||||
|
"#else\n", |
||||
|
"#undef EV_WRAP_H\n", |
||||
|
(map "#undef $_\n", @syms), |
||||
|
"#endif\n"; |
||||
|
' >ev_wrap.h |
@ -0,0 +1,7 @@ |
|||||
|
#!/bin/sh |
||||
|
|
||||
|
make ev.o event.o || exit |
||||
|
|
||||
|
nm ev.o | perl -ne 'print "$1\n" if /\S+ [A-Z] (\S+)/' > Symbols.ev |
||||
|
nm event.o | perl -ne 'print "$1\n" if /\S+ [A-Z] (\S+)/' > Symbols.event |
||||
|
|
Loading…
Reference in new issue