mirror of https://github.com/lukechilds/node.git
Ryan Dahl
14 years ago
48 changed files with 352 additions and 16287 deletions
@ -1,26 +0,0 @@ |
|||||
include(CheckFunctionExists) |
|
||||
include(FindThreads) |
|
||||
|
|
||||
if(!${CMAKE_USE_PTHREADS_INIT}) |
|
||||
message(FATAL_ERROR "Unable to find pthreads") |
|
||||
endif() |
|
||||
|
|
||||
add_definitions(-DHAVE_CONFIG_H=1 -D_GNU_SOURCE) |
|
||||
|
|
||||
check_function_exists(futimes HAVE_FUTIMES) |
|
||||
check_function_exists(readahead HAVE_READAHEAD) |
|
||||
check_function_exists(fdatasync HAVE_FDATASYNC) |
|
||||
check_function_exists(pread HAVE_PREAD) |
|
||||
check_function_exists(pwrite HAVE_PWRITE) |
|
||||
check_function_exists(sendfile HAVE_SENDFILE) |
|
||||
check_function_exists(sync_file_range HAVE_SYNC_FILE_RANGE) |
|
||||
|
|
||||
if(${HAVE_PREAD} AND ${HAVE_PWRITE}) |
|
||||
set(HAVE_PREADWRITE 1) |
|
||||
endif() |
|
||||
|
|
||||
configure_file(config.h.cmake ${PROJECT_BINARY_DIR}/deps/libeio/config.h) |
|
||||
include_directories(${PROJECT_BINARY_DIR}/deps/libeio) |
|
||||
|
|
||||
add_library(eio eio.c) |
|
||||
target_link_libraries(eio ${CMAKE_THREAD_LIBS_INIT}) |
|
@ -1,35 +0,0 @@ |
|||||
Revision history for libeio |
|
||||
|
|
||||
TODO: maybe add mincore support? available on at least darwin, solaris, linux, freebsd |
|
||||
TODO: openbsd requites stdint.h for intptr_t - why posix? |
|
||||
|
|
||||
1.0 |
|
||||
- readdir: correctly handle malloc failures. |
|
||||
- readdir: new flags argument, can return inode |
|
||||
and possibly filetype, can sort in various ways. |
|
||||
- readdir: stop immediately when cancelled, do |
|
||||
not continue reading the directory. |
|
||||
- fix return value of eio_sendfile_sync. |
|
||||
- include sys/mman.h for msync. |
|
||||
- added EIO_STACKSIZE. |
|
||||
- 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. |
|
||||
- eio_set_max_polltime did not properly convert time to ticks. |
|
||||
- tentatively support darwin in sendfile. |
|
||||
- fix freebsd/darwin sendfile. |
|
||||
- also use sendfile emulation for ENOTSUP and EOPNOTSUPP |
|
||||
error codes. |
|
||||
- add OS-independent EIO_MT_* and EIO_MS_* flag enums. |
|
||||
- add eio_statvfs/eio_fstatvfs. |
|
||||
- add eio_mlock/eio_mlockall and OS-independent MCL_* flag enums. |
|
||||
- no longer set errno to 0 before making syscalls, this only lures |
|
||||
people into the trap of believing errno shows success or failure. |
|
||||
- "fix" demo.c so that it works as non-root. |
|
||||
- suppoert utimes seperately from futimes, as some systems have |
|
||||
utimes but not futimes. |
|
||||
- use _POSIX_MEMLOCK_RANGE for mlock. |
|
||||
- do not (errornously) overwrite CFLAGS in configure.ac. |
|
||||
|
|
@ -1,36 +0,0 @@ |
|||||
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. |
|
@ -1,15 +0,0 @@ |
|||||
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
@ -1,5 +0,0 @@ |
|||||
libtoolize |
|
||||
aclocal |
|
||||
automake --add-missing |
|
||||
autoconf |
|
||||
autoheader |
|
@ -1,17 +0,0 @@ |
|||||
/* futimes(2) is available */ |
|
||||
#cmakedefine HAVE_FUTIMES 1 |
|
||||
|
|
||||
/* readahead(2) is available (linux) */ |
|
||||
#cmakedefine HAVE_READAHEAD 1 |
|
||||
|
|
||||
/* fdatasync(2) is available */ |
|
||||
#cmakedefine HAVE_FDATASYNC 1 |
|
||||
|
|
||||
/* pread(2) and pwrite(2) are available */ |
|
||||
#cmakedefine HAVE_PREADWRITE 1 |
|
||||
|
|
||||
/* sendfile(2) is available and supported */ |
|
||||
#cmakedefine HAVE_SENDFILE 1 |
|
||||
|
|
||||
/* sync_file_range(2) is available */ |
|
||||
#cmakedefine HAVE_SYNC_FILE_RANGE 1 |
|
@ -1,86 +0,0 @@ |
|||||
/* 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 |
|
||||
|
|
||||
/* posix_fadvise(2) is available */ |
|
||||
#undef HAVE_POSIX_FADVISE |
|
||||
|
|
||||
/* posix_madvise(2) is available */ |
|
||||
#undef HAVE_POSIX_MADVISE |
|
||||
|
|
||||
/* 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 |
|
||||
|
|
||||
/* utimes(2) is available */ |
|
||||
#undef HAVE_UTIMES |
|
||||
|
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
|
||||
*/ |
|
||||
#undef LT_OBJDIR |
|
||||
|
|
||||
/* 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 home page for this package. */ |
|
||||
#undef PACKAGE_URL |
|
||||
|
|
||||
/* Define to the version of this package. */ |
|
||||
#undef PACKAGE_VERSION |
|
||||
|
|
||||
/* Define to 1 if you have the ANSI C header files. */ |
|
||||
#undef STDC_HEADERS |
|
@ -1,22 +0,0 @@ |
|||||
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 $CFLAGS" |
|
||||
|
|
||||
m4_include([libeio.m4]) |
|
||||
|
|
||||
AC_CONFIG_FILES([Makefile]) |
|
||||
AC_OUTPUT |
|
@ -1,194 +0,0 @@ |
|||||
#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, 0723, 0, res_cb, "fchmod"); |
|
||||
eio_readdir ("eio-test-dir", 0, 0, readdir_cb, "readdir"); |
|
||||
eio_readdir ("/nonexistant", 0, 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
@ -1,356 +0,0 @@ |
|||||
/*
|
|
||||
* libeio API header |
|
||||
* |
|
||||
* Copyright (c) 2007,2008,2009,2010 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> |
|
||||
|
|
||||
#ifdef __OpenBSD__ |
|
||||
# include <inttypes.h> |
|
||||
#endif |
|
||||
|
|
||||
#ifdef _WIN32 |
|
||||
# define uid_t int |
|
||||
# define gid_t int |
|
||||
#endif |
|
||||
|
|
||||
typedef struct eio_req eio_req; |
|
||||
typedef struct eio_dirent eio_dirent; |
|
||||
|
|
||||
typedef int (*eio_cb)(eio_req *req); |
|
||||
|
|
||||
#ifndef EIO_REQ_MEMBERS |
|
||||
# define EIO_REQ_MEMBERS |
|
||||
#endif |
|
||||
|
|
||||
#ifndef EIO_STRUCT_STAT |
|
||||
# ifdef _WIN32 |
|
||||
# define EIO_STRUCT_STAT struct _stati64 |
|
||||
# else |
|
||||
# define EIO_STRUCT_STAT struct stat |
|
||||
# endif |
|
||||
#endif |
|
||||
|
|
||||
#ifndef EIO_STRUCT_STATVFS |
|
||||
# define EIO_STRUCT_STATVFS struct statvfs |
|
||||
#endif |
|
||||
|
|
||||
/* for readdir */ |
|
||||
|
|
||||
/* eio_readdir flags */ |
|
||||
enum |
|
||||
{ |
|
||||
EIO_READDIR_DENTS = 0x01, /* ptr2 contains eio_dirents, not just the (unsorted) names */ |
|
||||
EIO_READDIR_DIRS_FIRST = 0x02, /* dirents gets sorted into a good stat() ing order to find directories first */ |
|
||||
EIO_READDIR_STAT_ORDER = 0x04, /* dirents gets sorted into a good stat() ing order to quickly stat all files */ |
|
||||
EIO_READDIR_FOUND_UNKNOWN = 0x80, /* set by eio_readdir when *_ARRAY was set and any TYPE=UNKNOWN's were found */ |
|
||||
|
|
||||
EIO_READDIR_CUSTOM1 = 0x100, /* for use by apps */ |
|
||||
EIO_READDIR_CUSTOM2 = 0x200 /* for use by apps */ |
|
||||
}; |
|
||||
|
|
||||
/* using "typical" values in the hope that the compiler will do something sensible */ |
|
||||
enum eio_dtype |
|
||||
{ |
|
||||
EIO_DT_UNKNOWN = 0, |
|
||||
EIO_DT_FIFO = 1, |
|
||||
EIO_DT_CHR = 2, |
|
||||
EIO_DT_MPC = 3, /* multiplexed char device (v7+coherent) */ |
|
||||
EIO_DT_DIR = 4, |
|
||||
EIO_DT_NAM = 5, /* xenix special named file */ |
|
||||
EIO_DT_BLK = 6, |
|
||||
EIO_DT_MPB = 7, /* multiplexed block device (v7+coherent) */ |
|
||||
EIO_DT_REG = 8, |
|
||||
EIO_DT_NWK = 9, /* HP-UX network special */ |
|
||||
EIO_DT_CMP = 9, /* VxFS compressed */ |
|
||||
EIO_DT_LNK = 10, |
|
||||
/* DT_SHAD = 11,*/ |
|
||||
EIO_DT_SOCK = 12, |
|
||||
EIO_DT_DOOR = 13, /* solaris door */ |
|
||||
EIO_DT_WHT = 14, |
|
||||
EIO_DT_MAX = 15 /* highest DT_VALUE ever, hopefully */ |
|
||||
}; |
|
||||
|
|
||||
struct eio_dirent |
|
||||
{ |
|
||||
int nameofs; /* offset of null-terminated name string in (char *)req->ptr2 */ |
|
||||
unsigned short namelen; /* size of filename without trailing 0 */ |
|
||||
unsigned char type; /* one of EIO_DT_* */ |
|
||||
signed char score; /* internal use */ |
|
||||
ino_t inode; /* the inode number, if available, otherwise unspecified */ |
|
||||
}; |
|
||||
|
|
||||
/* eio_msync flags */ |
|
||||
enum |
|
||||
{ |
|
||||
EIO_MS_ASYNC = 1, |
|
||||
EIO_MS_INVALIDATE = 2, |
|
||||
EIO_MS_SYNC = 4 |
|
||||
}; |
|
||||
|
|
||||
/* eio_mtouch flags */ |
|
||||
|
|
||||
enum |
|
||||
{ |
|
||||
EIO_MT_MODIFY = 1 |
|
||||
}; |
|
||||
|
|
||||
/* 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 */ |
|
||||
|
|
||||
/* the eio request structure */ |
|
||||
|
|
||||
enum |
|
||||
{ |
|
||||
EIO_CUSTOM, |
|
||||
EIO_OPEN, EIO_CLOSE, EIO_DUP2, |
|
||||
EIO_READ, EIO_WRITE, |
|
||||
EIO_READAHEAD, EIO_SENDFILE, |
|
||||
EIO_STAT, EIO_LSTAT, EIO_FSTAT, |
|
||||
EIO_STATVFS, EIO_FSTATVFS, |
|
||||
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_MLOCK, EIO_MLOCKALL, |
|
||||
EIO_UNLINK, EIO_RMDIR, EIO_MKDIR, EIO_RENAME, |
|
||||
EIO_MKNOD, EIO_READDIR, |
|
||||
EIO_LINK, EIO_SYMLINK, EIO_READLINK, |
|
||||
EIO_GROUP, EIO_NOP, |
|
||||
EIO_BUSY |
|
||||
}; |
|
||||
|
|
||||
/* mlockall constants */ |
|
||||
enum |
|
||||
{ |
|
||||
EIO_MCL_CURRENT = 1, |
|
||||
EIO_MCL_FUTURE = 2, |
|
||||
}; |
|
||||
|
|
||||
/* request priorities */ |
|
||||
|
|
||||
enum { |
|
||||
EIO_PRI_MIN = -4, |
|
||||
EIO_PRI_MAX = 4, |
|
||||
EIO_PRI_DEFAULT = 0, |
|
||||
}; |
|
||||
|
|
||||
/* eio request structure */ |
|
||||
/* this structure is mostly read-only */ |
|
||||
/* when initialising it, all members must be zero-initialised */ |
|
||||
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, mlock, sync_file_range: length */ |
|
||||
void *ptr1; /* all applicable requests: pathname, old name; readdir: optional eio_dirents */ |
|
||||
void *ptr2; /* all applicable requests: new name or memory buffer; readdir: name strings */ |
|
||||
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, mlockall, readdir: 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_ request 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 */ |
|
||||
}; |
|
||||
|
|
||||
/* undocumented/unsupported/private helper */ |
|
||||
/*void eio_page_align (void **addr, size_t *length);*/ |
|
||||
|
|
||||
/* 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_mlock (void *addr, size_t length, int pri, eio_cb cb, void *data); |
|
||||
eio_req *eio_mlockall (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_fstatvfs (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 flags, 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_statvfs (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_STATVFS_BUF(req) ((EIO_STRUCT_STATVFS *)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); |
|
||||
|
|
||||
/*****************************************************************************/ |
|
||||
/* export these so node_file can use these function instead of pread/write */ |
|
||||
|
|
||||
#if !HAVE_PREADWRITE |
|
||||
ssize_t eio__pread (int fd, void *buf, size_t count, off_t offset); |
|
||||
ssize_t eio__pwrite (int fd, void *buf, size_t count, off_t offset); |
|
||||
#endif |
|
||||
|
|
||||
#ifdef __cplusplus |
|
||||
} |
|
||||
#endif |
|
||||
|
|
||||
#endif |
|
||||
|
|
@ -1,303 +0,0 @@ |
|||||
=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 enable 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 COMPILETIME CONFIGURATION |
|
||||
|
|
||||
These symbols, if used, must be defined when compiling F<eio.c>. |
|
||||
|
|
||||
=over 4 |
|
||||
|
|
||||
=item EIO_STACKSIZE |
|
||||
|
|
||||
This symbol governs the stack size for each eio thread. Libeio itself |
|
||||
was written to use very little stackspace, but when using C<EIO_CUSTOM> |
|
||||
requests, you might want to increase this. |
|
||||
|
|
||||
If this symbol is undefined (the default) then libeio will use its default |
|
||||
stack size (C<sizeof (long) * 4096> currently). If it is defined, but |
|
||||
C<0>, then the default operating system stack size will be used. In all |
|
||||
other cases, the value must be an expression that evaluates to the desired |
|
||||
stack size. |
|
||||
|
|
||||
=back |
|
||||
|
|
||||
|
|
||||
=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>. |
|
||||
|
|
@ -1,156 +0,0 @@ |
|||||
AC_SEARCH_LIBS( |
|
||||
pthread_create, |
|
||||
[pthread pthreads pthreadVC2], |
|
||||
, |
|
||||
[AC_MSG_ERROR(pthread functions not found)] |
|
||||
) |
|
||||
|
|
||||
AC_CACHE_CHECK(for utimes, ac_cv_utimes, [AC_LINK_IFELSE([[ |
|
||||
#include <sys/types.h> |
|
||||
#include <sys/time.h> |
|
||||
#include <utime.h> |
|
||||
struct timeval tv[2]; |
|
||||
int res; |
|
||||
int main (void) |
|
||||
{ |
|
||||
res = utimes ("/", tv); |
|
||||
return 0; |
|
||||
} |
|
||||
]],ac_cv_utimes=yes,ac_cv_utimes=no)]) |
|
||||
test $ac_cv_utimes = yes && AC_DEFINE(HAVE_UTIMES, 1, utimes(2) is available) |
|
||||
|
|
||||
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__ || defined __APPLE__ |
|
||||
# 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) |
|
||||
|
|
||||
dnl ############################################################################# |
|
||||
dnl # these checks exist for the benefit of IO::AIO |
|
||||
|
|
||||
dnl at least uclibc defines _POSIX_ADVISORY_INFO without *any* of the required |
|
||||
dnl functionality actually being present. ugh. |
|
||||
AC_CACHE_CHECK(for posix_madvise, ac_cv_posix_madvise, [AC_LINK_IFELSE([ |
|
||||
#include <sys/mman.h> |
|
||||
int main (void) |
|
||||
{ |
|
||||
int res = posix_madvise ((void *)0, (size_t)0, POSIX_MADV_NORMAL); |
|
||||
int a = POSIX_MADV_SEQUENTIAL; |
|
||||
int b = POSIX_MADV_RANDOM; |
|
||||
int c = POSIX_MADV_WILLNEED; |
|
||||
int d = POSIX_MADV_DONTNEED; |
|
||||
return 0; |
|
||||
} |
|
||||
],ac_cv_posix_madvise=yes,ac_cv_posix_madvise=no)]) |
|
||||
test $ac_cv_posix_madvise = yes && AC_DEFINE(HAVE_POSIX_MADVISE, 1, posix_madvise(2) is available) |
|
||||
|
|
||||
AC_CACHE_CHECK(for posix_fadvise, ac_cv_posix_fadvise, [AC_LINK_IFELSE([ |
|
||||
#define _XOPEN_SOURCE 600 |
|
||||
#include <fcntl.h> |
|
||||
int main (void) |
|
||||
{ |
|
||||
int res = posix_fadvise ((int)0, (off_t)0, (off_t)0, POSIX_FADV_NORMAL); |
|
||||
int a = POSIX_FADV_SEQUENTIAL; |
|
||||
int b = POSIX_FADV_NOREUSE; |
|
||||
int c = POSIX_FADV_RANDOM; |
|
||||
int d = POSIX_FADV_WILLNEED; |
|
||||
int e = POSIX_FADV_DONTNEED; |
|
||||
return 0; |
|
||||
} |
|
||||
],ac_cv_posix_fadvise=yes,ac_cv_posix_fadvise=no)]) |
|
||||
test $ac_cv_posix_fadvise = yes && AC_DEFINE(HAVE_POSIX_FADVISE, 1, posix_fadvise(2) is available) |
|
||||
|
|
@ -1,131 +0,0 @@ |
|||||
import Options |
|
||||
import sys |
|
||||
|
|
||||
def set_options(opt): |
|
||||
pass |
|
||||
#opt.tool_options('compiler_cc') |
|
||||
|
|
||||
def configure(conf): |
|
||||
print "--- libeio ---" |
|
||||
#conf.check_tool('compiler_cc') |
|
||||
|
|
||||
conf.check(lib='pthread', uselib_store='PTHREAD') |
|
||||
conf.check_cc(lib="pthread", header_name="pthread.h", function_name="pthread_create", mandatory=True) |
|
||||
if sys.platform.startswith("cygwin"): |
|
||||
conf.check_cc(lib="pthread", header_name="unistd.h", function_name="pthread_atfork", mandatory=True) |
|
||||
elif sys.platform.startswith("win32"): |
|
||||
conf.check_cc(lib="pthread", header_name="pthread.h", function_name="pthread_atfork") |
|
||||
else: |
|
||||
conf.check_cc(lib="pthread", header_name="pthread.h", function_name="pthread_atfork", mandatory=True) |
|
||||
|
|
||||
conf.check_cc(msg="Checking for futimes(2)", define_name="HAVE_FUTIMES", fragment=""" |
|
||||
#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; |
|
||||
} |
|
||||
""") |
|
||||
|
|
||||
conf.check_cc(msg="Checking for readahead(2)", define_name="HAVE_READAHEAD", fragment=""" |
|
||||
#include <fcntl.h> |
|
||||
int main(void) |
|
||||
{ |
|
||||
int fd = 0; |
|
||||
size_t count = 2; |
|
||||
ssize_t res; |
|
||||
res = readahead (fd, 0, count); |
|
||||
return 0; |
|
||||
} |
|
||||
""") |
|
||||
|
|
||||
conf.check_cc(msg="Checking for fdatasync(2)", define_name="HAVE_FDATASYNC", fragment=""" |
|
||||
#include <unistd.h> |
|
||||
int main(void) |
|
||||
{ |
|
||||
int fd = 0; |
|
||||
fdatasync (fd); |
|
||||
return 0; |
|
||||
} |
|
||||
""") |
|
||||
|
|
||||
conf.check_cc(msg="Checking for pread(2) and pwrite(2)", define_name="HAVE_PREADWRITE", fragment=""" |
|
||||
#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; |
|
||||
} |
|
||||
""") |
|
||||
|
|
||||
conf.check_cc(msg="Checking for sendfile(2)" , define_name="HAVE_SENDFILE" , fragment=""" |
|
||||
# include <sys/types.h> |
|
||||
#if __linux |
|
||||
# include <sys/sendfile.h> |
|
||||
#elif __FreeBSD__ || defined(__APPLE__) |
|
||||
# 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 __APPLE__ |
|
||||
res = sendfile (fd, fd, offset, &offset, 0, 0); |
|
||||
#elif __hpux |
|
||||
res = sendfile (fd, fd, offset, count, 0, 0); |
|
||||
#endif |
|
||||
return 0; |
|
||||
} |
|
||||
""") |
|
||||
|
|
||||
conf.env.append_value("CCFLAGS", "-D_GNU_SOURCE") |
|
||||
conf.check_cc(msg="Checking for sync_file_range(2) ", fragment=""" |
|
||||
#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; |
|
||||
} |
|
||||
""", define_name="HAVE_SYNC_FILE_RANGE") |
|
||||
|
|
||||
def build(bld): |
|
||||
libeio = bld.new_task_gen("cc") |
|
||||
libeio.source = "eio.c" |
|
||||
libeio.target = 'eio' |
|
||||
libeio.name = 'eio' |
|
||||
libeio.includes = '. ../..' |
|
||||
libeio.uselib = "PTHREAD" |
|
||||
libeio.install_path = None |
|
||||
if bld.env["USE_DEBUG"]: |
|
||||
libeio.clone("debug"); |
|
||||
if Options.options.product_type != 'program': |
|
||||
libeio.ccflags = "-fPIC" |
|
||||
bld.install_files('${PREFIX}/include/node/', 'eio.h'); |
|
||||
|
|
@ -1,159 +0,0 @@ |
|||||
#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 |
|
||||
|
|
||||
#ifndef __MINGW32__ |
|
||||
typedef int ssize_t |
|
||||
#endif |
|
||||
|
|
||||
#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 pthread_sigmask(a,b,c) |
|
||||
#define sigaddset(a,b) |
|
||||
#define sigemptyset(s) |
|
||||
#define sigfillset(s) |
|
||||
|
|
||||
typedef pthread_mutex_t xmutex_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 xcond_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 xthread_t; |
|
||||
#define X_THREAD_PROC(name) void *name (void *thr_arg) |
|
||||
#define X_THREAD_ATFORK(a,b,c) |
|
||||
|
|
||||
static int |
|
||||
thread_create (xthread_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 xmutex_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 xcond_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 xthread_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 |
|
||||
|
|
||||
#ifndef X_STACKSIZE |
|
||||
# define X_STACKSIZE sizeof (long) * 4096 |
|
||||
#endif |
|
||||
|
|
||||
static int |
|
||||
thread_create (xthread_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 < X_STACKSIZE ? X_STACKSIZE : 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 |
|
||||
|
|
Loading…
Reference in new issue