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