Browse Source

Upgrade libuv to 48877ed

v0.7.4-release
Ryan Dahl 14 years ago
parent
commit
88afc406ca
  1. 11
      deps/uv/.gitignore
  2. 24
      deps/uv/Makefile
  3. 19
      deps/uv/README
  4. 1
      deps/uv/build/all.gyp
  5. 17
      deps/uv/build/gyp_uv
  6. 11
      deps/uv/configure
  7. 14
      deps/uv/create-msvs-files.bat
  8. 116
      deps/uv/include/eio.h
  9. 2
      deps/uv/src/ares/ares_parse_a_reply.c
  10. 30
      deps/uv/src/eio/Changes
  11. 2
      deps/uv/src/eio/Makefile.am
  12. 8
      deps/uv/src/eio/autogen.sh
  13. 61
      deps/uv/src/eio/config_darwin.h
  14. 8
      deps/uv/src/eio/configure.ac
  15. 370
      deps/uv/src/eio/ecb.h
  16. 1478
      deps/uv/src/eio/eio.c
  17. 758
      deps/uv/src/eio/eio.pod
  18. 39
      deps/uv/src/eio/libeio.m4
  19. 41
      deps/uv/src/eio/xthread.h
  20. 3
      deps/uv/src/uv-unix.c
  21. 1
      deps/uv/src/win/internal.h
  22. 2
      deps/uv/src/win/pipe.c
  23. 16
      deps/uv/test/benchmark-list.h
  24. 237
      deps/uv/test/benchmark-pound.c
  25. 19
      deps/uv/test/echo-server.c

11
deps/uv/.gitignore

@ -7,12 +7,5 @@
*.orig
*.sdf
*.suo
Makefile
out/
build/gyp
build/all.Makefile
build/all.xcodeproj/
build/run-tests.target.mk
build/run-benchmarks.target.mk
build/uv.target.mk
gyp-mac-tool
/out/
/build/gyp

24
deps/uv/Makefile

@ -0,0 +1,24 @@
BUILDTYPE ?= Release
all: out/Makefile
$(MAKE) -C out BUILDTYPE=$(BUILDTYPE)
out/Makefile: build/gyp
build/gyp_uv -f make
build/gyp:
svn co http://gyp.googlecode.com/svn/trunk@983 build/gyp
clean:
rm -rf out
distclean:
rm -rf out
test: all
./out/$(BUILDTYPE)/run-tests
bench: all
./out/$(BUILDTYPE)/run-benchmarks
.PHONY: all clean distclean test bench

19
deps/uv/README

@ -4,12 +4,25 @@ all platform differences in this library.
http://nodejs.org/
(This was previously called liboio)
= Build Instructions
Supported Platforms:
The build system requires python and subversion.
On Unix systems just type
make
On Windows you can generate the MSVS solution files by running
create-msvs-files.bat
Open build/all.sln afterwards.
= Supported Platforms
Microsoft Windows operating systems since Windows XP sp2. It can be built
with either Visual Studio or MinGW.
with either Visual Studio.
Linux 2.6 and MacOS using the GCC toolchain.

1
deps/uv/build/all.gyp

@ -202,6 +202,7 @@
'../test/benchmark-ares.c',
'../test/benchmark-getaddrinfo.c',
'../test/benchmark-ping-pongs.c',
'../test/benchmark-pound.c',
'../test/benchmark-pump.c',
'../test/benchmark-sizes.c',
'../test/benchmark-spawn.c'

17
deps/uv/build/gyp_uv

@ -6,10 +6,15 @@ import sys
script_dir = os.path.dirname(__file__)
uv_root = os.path.normpath(os.path.join(script_dir, os.pardir))
print("uv_root " + uv_root)
sys.path.insert(0, os.path.join(uv_root, 'build', 'gyp', 'pylib'))
import gyp
# Directory within which we want all generated files (including Makefiles)
# to be written.
output_dir = os.path.join(os.path.abspath(uv_root), 'out')
def run_gyp(args):
rc = gyp.main(args)
@ -19,7 +24,19 @@ def run_gyp(args):
if __name__ == '__main__':
args = sys.argv[1:]
args.append(os.path.join(script_dir, 'all.gyp'))
args.append('--depth=' + uv_root)
# There's a bug with windows which doesn't allow this feature.
if sys.platform != 'win32':
# Tell gyp to write the Makefiles into output_dir
args.extend(['--generator-output', output_dir])
# Tell make to write its output into the same dir
args.extend(['-Goutput_dir=' + output_dir])
gyp_args = list(args)
run_gyp(gyp_args)

11
deps/uv/configure

@ -1,11 +0,0 @@
#!/bin/sh
# TODO write this script in python so that it works x-platform
set -e
if [ ! -d build/gyp ]; then
svn checkout http://gyp.googlecode.com/svn/trunk/ build/gyp
fi
python build/gyp_uv -f make

14
deps/uv/create-msvs-files.bat

@ -0,0 +1,14 @@
@REM Hello World
cd %~dp0
IF EXIST %~dp0build\gyp GOTO WINDIR
svn co http://gyp.googlecode.com/svn/trunk@983 build/gyp
:WINDIR
@python build\gyp_uv

116
deps/uv/include/eio.h

@ -1,7 +1,7 @@
/*
* libeio API header
*
* Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann <libeio@schmorp.de>
* Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libeio@schmorp.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
@ -45,17 +45,9 @@ extern "C" {
#endif
#include <stddef.h>
#include <signal.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;
@ -67,12 +59,33 @@ typedef int (*eio_cb)(eio_req *req);
#ifndef EIO_STRUCT_STAT
# ifdef _WIN32
# define EIO_STRUCT_STAT struct _stati64
# define EIO_STRUCT_STAT struct _stati64
# define EIO_STRUCT_STATI64
# else
# define EIO_STRUCT_STAT struct stat
# define EIO_STRUCT_STAT struct stat
# endif
#endif
#ifdef _WIN32
typedef int eio_uid_t;
typedef int eio_gid_t;
#ifdef __MINGW32__ /* no intptr_t */
typedef ssize_t eio_ssize_t;
#else
typedef intptr_t eio_ssize_t; /* or SSIZE_T */
#endif
#if __GNUC__
typedef long long eio_ino_t;
#else
typedef __int64 eio_ino_t; /* unsigned not supported by msvc */
#endif
#else
typedef uid_t eio_uid_t;
typedef gid_t eio_gid_t;
typedef ssize_t eio_ssize_t;
typedef ino_t eio_ino_t;
#endif
#ifndef EIO_STRUCT_STATVFS
# define EIO_STRUCT_STATVFS struct statvfs
#endif
@ -119,7 +132,7 @@ struct eio_dirent
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_ino_t inode; /* the inode number, if available, otherwise unspecified */
};
/* eio_msync flags */
@ -131,14 +144,12 @@ enum
};
/* eio_mtouch flags */
enum
{
EIO_MT_MODIFY = 1
};
/* eio_sync_file_range flags */
enum
{
EIO_SYNC_FILE_RANGE_WAIT_BEFORE = 1,
@ -146,10 +157,16 @@ enum
EIO_SYNC_FILE_RANGE_WAIT_AFTER = 4
};
typedef double eio_tstamp; /* feel free to use double in your code directly */
/* eio_fallocate flags */
enum
{
EIO_FALLOC_FL_KEEP_SIZE = 1 /* MUST match the value in linux/falloc.h */
};
/* the eio request structure */
/* timestamps and differences - feel free to use double in your code directly */
typedef double eio_tstamp;
/* the eio request structure */
enum
{
EIO_CUSTOM,
@ -162,12 +179,12 @@ enum
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_SYNC, EIO_FSYNC, EIO_FDATASYNC, EIO_SYNCFS,
EIO_MSYNC, EIO_MTOUCH, EIO_SYNC_FILE_RANGE, EIO_FALLOCATE,
EIO_MLOCK, EIO_MLOCKALL,
EIO_UNLINK, EIO_RMDIR, EIO_MKDIR, EIO_RENAME,
EIO_MKNOD, EIO_READDIR,
EIO_LINK, EIO_SYMLINK, EIO_READLINK,
EIO_LINK, EIO_SYMLINK, EIO_READLINK, EIO_REALPATH,
EIO_GROUP, EIO_NOP,
EIO_BUSY
};
@ -176,7 +193,7 @@ enum
enum
{
EIO_MCL_CURRENT = 1,
EIO_MCL_FUTURE = 2
EIO_MCL_FUTURE = 2,
};
/* request priorities */
@ -184,7 +201,7 @@ enum
enum {
EIO_PRI_MIN = -4,
EIO_PRI_MAX = 4,
EIO_PRI_DEFAULT = 0
EIO_PRI_DEFAULT = 0,
};
/* eio request structure */
@ -194,9 +211,9 @@ 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 */
eio_ssize_t result; /* result of syscall, e.g. result = read (... */
off_t offs; /* read, write, truncate, readahead, sync_file_range, fallocate: file offset, mknod: dev_t */
size_t size; /* read, write, readahead, sendfile, msync, mlock, sync_file_range, fallocate: 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 */
@ -204,16 +221,22 @@ struct eio_req
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 */
long int2; /* chown, fchown: uid; sendfile: input fd; open, chmod, mkdir, mknod: file mode, sync_file_range, fallocate: flags */
long int3; /* chown, fchown: gid */
int errorno; /* errno value on syscall return */
#if __i386 || __amd64
unsigned char cancelled;
#else
sig_atomic_t cancelled;
#endif
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 (*destroy)(eio_req *req); /* called when request no longer needed */
void (*feed)(eio_req *req); /* only used for group requests */
EIO_REQ_MEMBERS
@ -223,10 +246,9 @@ struct eio_req
/* _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 */
EIO_FLAG_PTR1_FREE = 0x01, /* need to free(ptr1) */
EIO_FLAG_PTR2_FREE = 0x02, /* need to free(ptr2) */
EIO_FLAG_GROUPADD = 0x04 /* some request was added to the group */
};
/* undocumented/unsupported/private helper */
@ -254,14 +276,15 @@ void eio_set_max_poll_reqs (unsigned int nreqs);
void eio_set_min_parallel (unsigned int nthreads);
void eio_set_max_parallel (unsigned int nthreads);
void eio_set_max_idle (unsigned int nthreads);
void eio_set_idle_timeout (unsigned int seconds);
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_npending (void); /* number of finished but unhandled requests */
unsigned int eio_nthreads (void); /* number of worker threads in use currently */
/*****************************************************************************/
/* convinience wrappers */
/* convenience wrappers */
#ifndef EIO_NO_WRAPPERS
eio_req *eio_nop (int pri, eio_cb cb, void *data); /* does nothing except go through the whole process */
@ -269,11 +292,13 @@ eio_req *eio_busy (eio_tstamp delay, int pri, eio_cb cb, void *data); /* ti
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_syncfs (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_fallocate (int fd, int mode, off_t offset, size_t len, 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);
@ -283,19 +308,20 @@ eio_req *eio_fstatvfs (int fd, int pri, eio_cb cb, void *data); /* stat buffer=
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_fchown (int fd, eio_uid_t uid, eio_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_chown (const char *path, eio_uid_t uid, eio_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_realpath (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 */
@ -303,7 +329,7 @@ eio_req *eio_mknod (const char *path, mode_t mode, dev_t dev, int pri, eio_c
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);
eio_req *eio_custom (void (*execute)(eio_req *), int pri, eio_cb cb, void *data);
#endif
/*****************************************************************************/
@ -319,7 +345,7 @@ void eio_grp_cancel (eio_req *grp); /* cancels all sub requests but not the g
/* request api */
/* true if the request was cancelled, useful in the invoke callback */
#define EIO_CANCELLED(req) ((req)->flags & EIO_FLAG_CANCELLED)
#define EIO_CANCELLED(req) ((req)->cancelled)
#define EIO_RESULT(req) ((req)->result)
/* returns a pointer to the result buffer allocated by eio */
@ -332,21 +358,11 @@ void eio_grp_cancel (eio_req *grp); /* cancels all sub requests but not the g
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);
/* convenience functions */
/*****************************************************************************/
/* 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
eio_ssize_t eio_sendfile_sync (int ofd, int ifd, off_t offset, size_t count);
#ifdef __cplusplus
}

2
deps/uv/src/ares/ares_parse_a_reply.c

@ -238,6 +238,8 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
for (i = 0; i < naddrs; i++)
hostent->h_addr_list[i] = (char *) &addrs[i];
hostent->h_addr_list[naddrs] = NULL;
if (!naddrs && addrs)
free(addrs);
*host = hostent;
return ARES_SUCCESS;
}

30
deps/uv/src/eio/Changes

@ -1,9 +1,19 @@
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?
TODO: openbsd requires stdint.h for intptr_t - why posix?
TODO: make mtouch/readdir maybe others cancellable in-request
TODO: fadvise request
1.0
- fix a deadlock where a wakeup signal could be missed when
a timeout occured at the same time.
- use nonstandard but maybe-working-on-bsd fork technique.
- use fewer time() syscalls when waiting for new requests.
- fix a path-memory-leak in readdir when using the wrappers
(reported by Thomas L. Shinnick).
- support a max_idle value of 0.
- support setting of idle timeout value (eio_set_idle_timeout).
- readdir: correctly handle malloc failures.
- readdir: new flags argument, can return inode
and possibly filetype, can sort in various ways.
@ -32,4 +42,22 @@ TODO: openbsd requites stdint.h for intptr_t - why posix?
utimes but not futimes.
- use _POSIX_MEMLOCK_RANGE for mlock.
- do not (errornously) overwrite CFLAGS in configure.ac.
- mknod used int3 for dev_t (§2 bit), not offs (64 bit).
- fix memory corruption in eio_readdirx for the flags
combination EIO_READDIR_STAT_ORDER | EIO_READDIR_DIRS_FIRST.
- port to openbsd (another blatantly broken non-UNIX/POSIX platform).
- fix eio_custom prototype.
- work around a Linux (and likely FreeBSD and other kernels) bug
where sendfile would not transfer all the requested bytes on
large transfers, using a heuristic.
- use libecb, and apply lots of minor space optimisations.
- disable sendfile on darwin, broken as everything else.
- add realpath request and implementation.
- cancelled requests will still invoke their request callbacks.
- add fallocate.
- do not acquire any locks when forking.
- incorporated some mingw32 changes by traviscline.
- added syncfs support, using direct syscall.
- set thread name on linux (ps -L/Hcx, top, gdb).
- remove useless use of volatile variables.

2
deps/uv/src/eio/Makefile.am

@ -10,6 +10,6 @@ include_HEADERS = eio.h
lib_LTLIBRARIES = libeio.la
libeio_la_SOURCES = eio.c xthread.h config.h
libeio_la_SOURCES = eio.c ecb.h xthread.h config.h
libeio_la_LDFLAGS = -version-info $(VERSION_INFO)

8
deps/uv/src/eio/autogen.sh

@ -1,5 +1,3 @@
libtoolize
aclocal
automake --add-missing
autoconf
autoheader
#!/bin/sh
autoreconf --install --symlink --force

61
deps/uv/src/eio/config_darwin.h

@ -4,9 +4,11 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* fdatasync(2) is not available on 10.5 but is on 10.6
* How should we deal with this? */
/* #define HAVE_FDATASYNC 0 */
/* fallocate(2) is available */
/* #undef HAVE_FALLOCATE */
/* fdatasync(2) is available */
#define HAVE_FDATASYNC 1
/* futimes(2) is available */
#define HAVE_FUTIMES 1
@ -17,6 +19,15 @@
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* posix_fadvise(2) is available */
/* #undef HAVE_POSIX_FADVISE */
/* posix_madvise(2) is available */
#define HAVE_POSIX_MADVISE 1
/* prctl(PR_SET_NAME) is available */
/* #undef HAVE_PRCTL_SET_NAME */
/* pread(2) and pwrite(2) are available */
#define HAVE_PREADWRITE 1
@ -41,15 +52,27 @@
/* sync_file_range(2) is available */
/* #undef HAVE_SYNC_FILE_RANGE */
/* Define to 1 if you have the <sys/prctl.h> header file. */
/* #undef HAVE_SYS_PRCTL_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* syscall(__NR_syncfs) is available */
/* #undef HAVE_SYS_SYNCFS */
/* Define to 1 if you have the <sys/syscall.h> header file. */
#define HAVE_SYS_SYSCALL_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* utimes(2) is available */
#define HAVE_UTIMES 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
@ -78,5 +101,37 @@
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# define _ALL_SOURCE 1
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
/* Version number of package */
#define VERSION "1.0"
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */

8
deps/uv/src/eio/configure.ac

@ -5,17 +5,17 @@ AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE(libeio,1.0)
AM_MAINTAINER_MODE
AC_GNU_SOURCE
AC_PROG_LIBTOOL
AC_PROG_CC
if test "x$GCC" = xyes ; then
CFLAGS="$CFLAGS -O3"
CFLAGS="-O3 $CFLAGS"
fi
dnl somebody will forgive me
CFLAGS="-D_GNU_SOURCE $CFLAGS"
m4_include([libeio.m4])
AC_CONFIG_FILES([Makefile])

370
deps/uv/src/eio/ecb.h

@ -0,0 +1,370 @@
/*
* libecb - http://software.schmorp.de/pkg/libecb
*
* Copyright (©) 2009-2011 Marc Alexander Lehmann <libecb@schmorp.de>
* Copyright (©) 2011 Emanuele Giaquinta
* 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.
*/
#ifndef ECB_H
#define ECB_H
#ifdef _WIN32
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
#if __GNUC__
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
#else /* _MSC_VER || __BORLANDC__ */
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#endif
#else
#include <inttypes.h>
#endif
/* many compilers define _GNUC_ to some versions but then only implement
* what their idiot authors think are the "more important" extensions,
* causing enourmous grief in return for some better fake benchmark numbers.
* or so.
* we try to detect these and simply assume they are not gcc - if they have
* an issue with that they should have done it right in the first place.
*/
#ifndef ECB_GCC_VERSION
#if !defined(__GNUC_MINOR__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__llvm__) || defined(__clang__)
#define ECB_GCC_VERSION(major,minor) 0
#else
#define ECB_GCC_VERSION(major,minor) (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
#endif
#endif
/*****************************************************************************/
#ifndef ECB_MEMORY_FENCE
#if ECB_GCC_VERSION(2,5)
#if __x86
#define ECB_MEMORY_FENCE __asm__ __volatile__ ("lock; orb $0, -1(%%esp)" : : : "memory")
#define ECB_MEMORY_FENCE_ACQUIRE ECB_MEMORY_FENCE /* non-lock xchg might be enough */
#define ECB_MEMORY_FENCE_RELEASE do { } while (0) /* unlikely to change in future cpus */
#elif __amd64
#define ECB_MEMORY_FENCE __asm__ __volatile__ ("mfence" : : : "memory")
#define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("lfence" : : : "memory")
#define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("sfence") /* play safe - not needed in any current cpu */
#endif
#endif
#endif
#ifndef ECB_MEMORY_FENCE
#if ECB_GCC_VERSION(4,4)
#define ECB_MEMORY_FENCE __sync_synchronize ()
#define ECB_MEMORY_FENCE_ACQUIRE ({ char dummy = 0; __sync_lock_test_and_set (&dummy, 1); })
#define ECB_MEMORY_FENCE_RELEASE ({ char dummy = 1; __sync_lock_release (&dummy ); })
#elif _MSC_VER >= 1400 /* VC++ 2005 */
#pragma intrinsic(_ReadBarrier,_WriteBarrier,_ReadWriteBarrier)
#define ECB_MEMORY_FENCE _ReadWriteBarrier ()
#define ECB_MEMORY_FENCE_ACQUIRE _ReadWriteBarrier () /* according to msdn, _ReadBarrier is not a load fence */
#define ECB_MEMORY_FENCE_RELEASE _WriteBarrier ()
#elif defined(_WIN32)
#include <WinNT.h>
#define ECB_MEMORY_FENCE MemoryBarrier () /* actually just xchg on x86... scary */
#define ECB_MEMORY_FENCE_ACQUIRE ECB_MEMORY_FENCE
#define ECB_MEMORY_FENCE_RELEASE ECB_MEMORY_FENCE
#endif
#endif
#ifndef ECB_MEMORY_FENCE
/*
* if you get undefined symbol references to pthread_mutex_lock,
* or failure to find pthread.h, then you should implement
* the ECB_MEMORY_FENCE operations for your cpu/compiler
* OR proide pthread.h and link against the posix thread library
* of your system.
*/
#include <pthread.h>
static pthread_mutex_t ecb_mf_lock = PTHREAD_MUTEX_INITIALIZER;
#define ECB_MEMORY_FENCE do { pthread_mutex_lock (&ecb_mf_lock); pthread_mutex_unlock (&ecb_mf_lock); } while (0)
#define ECB_MEMORY_FENCE_ACQUIRE ECB_MEMORY_FENCE
#define ECB_MEMORY_FENCE_RELEASE ECB_MEMORY_FENCE
#endif
/*****************************************************************************/
#define ECB_C99 (__STDC_VERSION__ >= 199901L)
#if __cplusplus
#define ecb_inline static inline
#elif ECB_GCC_VERSION(2,5)
#define ecb_inline static __inline__
#elif ECB_C99
#define ecb_inline static inline
#else
#define ecb_inline static
#endif
#if ECB_GCC_VERSION(3,3)
#define ecb_restrict __restrict__
#elif ECB_C99
#define ecb_restrict restrict
#else
#define ecb_restrict
#endif
typedef int ecb_bool;
#define ECB_CONCAT_(a, b) a ## b
#define ECB_CONCAT(a, b) ECB_CONCAT_(a, b)
#define ECB_STRINGIFY_(a) # a
#define ECB_STRINGIFY(a) ECB_STRINGIFY_(a)
#define ecb_function_ ecb_inline
#if ECB_GCC_VERSION(3,1)
#define ecb_attribute(attrlist) __attribute__(attrlist)
#define ecb_is_constant(expr) __builtin_constant_p (expr)
#define ecb_expect(expr,value) __builtin_expect ((expr),(value))
#define ecb_prefetch(addr,rw,locality) __builtin_prefetch (addr, rw, locality)
#else
#define ecb_attribute(attrlist)
#define ecb_is_constant(expr) 0
#define ecb_expect(expr,value) (expr)
#define ecb_prefetch(addr,rw,locality)
#endif
/* no emulation for ecb_decltype */
#if ECB_GCC_VERSION(4,5)
#define ecb_decltype(x) __decltype(x)
#elif ECB_GCC_VERSION(3,0)
#define ecb_decltype(x) __typeof(x)
#endif
#define ecb_noinline ecb_attribute ((__noinline__))
#define ecb_noreturn ecb_attribute ((__noreturn__))
#define ecb_unused ecb_attribute ((__unused__))
#define ecb_const ecb_attribute ((__const__))
#define ecb_pure ecb_attribute ((__pure__))
#if ECB_GCC_VERSION(4,3)
#define ecb_artificial ecb_attribute ((__artificial__))
#define ecb_hot ecb_attribute ((__hot__))
#define ecb_cold ecb_attribute ((__cold__))
#else
#define ecb_artificial
#define ecb_hot
#define ecb_cold
#endif
/* put around conditional expressions if you are very sure that the */
/* expression is mostly true or mostly false. note that these return */
/* booleans, not the expression. */
#define ecb_expect_false(expr) ecb_expect (!!(expr), 0)
#define ecb_expect_true(expr) ecb_expect (!!(expr), 1)
/* for compatibility to the rest of the world */
#define ecb_likely(expr) ecb_expect_true (expr)
#define ecb_unlikely(expr) ecb_expect_false (expr)
/* count trailing zero bits and count # of one bits */
#if ECB_GCC_VERSION(3,4)
/* we assume int == 32 bit, long == 32 or 64 bit and long long == 64 bit */
#define ecb_ld32(x) (__builtin_clz (x) ^ 31)
#define ecb_ld64(x) (__builtin_clzll (x) ^ 63)
#define ecb_ctz32(x) __builtin_ctz (x)
#define ecb_ctz64(x) __builtin_ctzll (x)
#define ecb_popcount32(x) __builtin_popcount (x)
/* no popcountll */
#else
ecb_function_ int ecb_ctz32 (uint32_t x) ecb_const;
ecb_function_ int
ecb_ctz32 (uint32_t x)
{
int r = 0;
x &= ~x + 1; /* this isolates the lowest bit */
#if ECB_branchless_on_i386
r += !!(x & 0xaaaaaaaa) << 0;
r += !!(x & 0xcccccccc) << 1;
r += !!(x & 0xf0f0f0f0) << 2;
r += !!(x & 0xff00ff00) << 3;
r += !!(x & 0xffff0000) << 4;
#else
if (x & 0xaaaaaaaa) r += 1;
if (x & 0xcccccccc) r += 2;
if (x & 0xf0f0f0f0) r += 4;
if (x & 0xff00ff00) r += 8;
if (x & 0xffff0000) r += 16;
#endif
return r;
}
ecb_function_ int ecb_ctz64 (uint64_t x) ecb_const;
ecb_function_ int
ecb_ctz64 (uint64_t x)
{
int shift = x & 0xffffffffU ? 0 : 32;
return ecb_ctz32 (x >> shift) + shift;
}
ecb_function_ int ecb_popcount32 (uint32_t x) ecb_const;
ecb_function_ int
ecb_popcount32 (uint32_t x)
{
x -= (x >> 1) & 0x55555555;
x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
x = ((x >> 4) + x) & 0x0f0f0f0f;
x *= 0x01010101;
return x >> 24;
}
/* you have the choice beetween something with a table lookup, */
/* something using lots of bit arithmetic and a simple loop */
/* we went for the loop */
ecb_function_ int ecb_ld32 (uint32_t x) ecb_const;
ecb_function_ int ecb_ld32 (uint32_t x)
{
int r = 0;
if (x >> 16) { x >>= 16; r += 16; }
if (x >> 8) { x >>= 8; r += 8; }
if (x >> 4) { x >>= 4; r += 4; }
if (x >> 2) { x >>= 2; r += 2; }
if (x >> 1) { r += 1; }
return r;
}
ecb_function_ int ecb_ld64 (uint64_t x) ecb_const;
ecb_function_ int ecb_ld64 (uint64_t x)
{
int r = 0;
if (x >> 32) { x >>= 32; r += 32; }
return r + ecb_ld32 (x);
}
#endif
/* popcount64 is only available on 64 bit cpus as gcc builtin */
/* so for this version we are lazy */
ecb_function_ int ecb_popcount64 (uint64_t x) ecb_const;
ecb_function_ int
ecb_popcount64 (uint64_t x)
{
return ecb_popcount32 (x) + ecb_popcount32 (x >> 32);
}
ecb_inline uint8_t ecb_rotl8 (uint8_t x, unsigned int count) ecb_const;
ecb_inline uint8_t ecb_rotr8 (uint8_t x, unsigned int count) ecb_const;
ecb_inline uint16_t ecb_rotl16 (uint16_t x, unsigned int count) ecb_const;
ecb_inline uint16_t ecb_rotr16 (uint16_t x, unsigned int count) ecb_const;
ecb_inline uint32_t ecb_rotl32 (uint32_t x, unsigned int count) ecb_const;
ecb_inline uint32_t ecb_rotr32 (uint32_t x, unsigned int count) ecb_const;
ecb_inline uint64_t ecb_rotl64 (uint64_t x, unsigned int count) ecb_const;
ecb_inline uint64_t ecb_rotr64 (uint64_t x, unsigned int count) ecb_const;
ecb_inline uint8_t ecb_rotl8 (uint8_t x, unsigned int count) { return (x >> ( 8 - count)) | (x << count); }
ecb_inline uint8_t ecb_rotr8 (uint8_t x, unsigned int count) { return (x << ( 8 - count)) | (x >> count); }
ecb_inline uint16_t ecb_rotl16 (uint16_t x, unsigned int count) { return (x >> (16 - count)) | (x << count); }
ecb_inline uint16_t ecb_rotr16 (uint16_t x, unsigned int count) { return (x << (16 - count)) | (x >> count); }
ecb_inline uint32_t ecb_rotl32 (uint32_t x, unsigned int count) { return (x >> (32 - count)) | (x << count); }
ecb_inline uint32_t ecb_rotr32 (uint32_t x, unsigned int count) { return (x << (32 - count)) | (x >> count); }
ecb_inline uint64_t ecb_rotl64 (uint64_t x, unsigned int count) { return (x >> (64 - count)) | (x << count); }
ecb_inline uint64_t ecb_rotr64 (uint64_t x, unsigned int count) { return (x << (64 - count)) | (x >> count); }
#if ECB_GCC_VERSION(4,3)
#define ecb_bswap16(x) (__builtin_bswap32 (x) >> 16)
#define ecb_bswap32(x) __builtin_bswap32 (x)
#define ecb_bswap64(x) __builtin_bswap64 (x)
#else
ecb_function_ uint16_t ecb_bswap16 (uint16_t x) ecb_const;
ecb_function_ uint16_t
ecb_bswap16 (uint16_t x)
{
return ecb_rotl16 (x, 8);
}
ecb_function_ uint32_t ecb_bswap32 (uint32_t x) ecb_const;
ecb_function_ uint32_t
ecb_bswap32 (uint32_t x)
{
return (((uint32_t)ecb_bswap16 (x)) << 16) | ecb_bswap16 (x >> 16);
}
ecb_function_ uint64_t ecb_bswap64 (uint64_t x) ecb_const;
ecb_function_ uint64_t
ecb_bswap64 (uint64_t x)
{
return (((uint64_t)ecb_bswap32 (x)) << 32) | ecb_bswap32 (x >> 32);
}
#endif
#if ECB_GCC_VERSION(4,5)
#define ecb_unreachable() __builtin_unreachable ()
#else
/* this seems to work fine, but gcc always emits a warning for it :/ */
ecb_function_ void ecb_unreachable (void) ecb_noreturn;
ecb_function_ void ecb_unreachable (void) { }
#endif
/* try to tell the compiler that some condition is definitely true */
#define ecb_assume(cond) do { if (!(cond)) ecb_unreachable (); } while (0)
ecb_function_ unsigned char ecb_byteorder_helper (void) ecb_const;
ecb_function_ unsigned char
ecb_byteorder_helper (void)
{
const uint32_t u = 0x11223344;
return *(unsigned char *)&u;
}
ecb_function_ ecb_bool ecb_big_endian (void) ecb_const;
ecb_function_ ecb_bool ecb_big_endian (void) { return ecb_byteorder_helper () == 0x11; }
ecb_function_ ecb_bool ecb_little_endian (void) ecb_const;
ecb_function_ ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == 0x44; }
#if ECB_GCC_VERSION(3,0) || ECB_C99
#define ecb_mod(m,n) ((m) % (n) + ((m) % (n) < 0 ? (n) : 0))
#else
#define ecb_mod(m,n) ((m) < 0 ? ((n) - 1 - ((-1 - (m)) % (n))) : ((m) % (n)))
#endif
#if ecb_cplusplus_does_not_suck
/* does not work for local types (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm) */
template<typename T, int N>
static inline int ecb_array_length (const T (&arr)[N])
{
return N;
}
#else
#define ecb_array_length(name) (sizeof (name) / sizeof (name [0]))
#endif
#endif

1478
deps/uv/src/eio/eio.c

File diff suppressed because it is too large

758
deps/uv/src/eio/eio.pod

@ -13,14 +13,14 @@ 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
module, and many of the subtler points regarding requests 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
dealing 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>.
@ -39,7 +39,7 @@ C<readdir>.
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
called C<eio_tstamp>, but it is guaranteed 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
@ -47,15 +47,24 @@ time differences throughout libeio.
=head2 FORK SUPPORT
Calling C<fork ()> is fully supported by this module. It is implemented in these steps:
Usage of pthreads in a program changes the semantics of fork
considerably. Specifically, only async-safe functions can be called after
fork. Libeio uses pthreads, so this applies, and makes using fork hard for
anything but relatively fork + exec uses.
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.
This library only works in the process that initialised it: Forking is
fully supported, but using libeio in any other process than the one that
called C<eio_init> is not.
You might get around by not I<using> libeio before (or after) forking in
the parent, and using it in the child afterwards. You could also try to
call the L<eio_init> function again in the child, which will brutally
reinitialise all data structures, which isn't POSIX conformant, but
typically works.
Otherwise, the only recommendation you should follow is: treat fork code
the same way you treat signal handlers, and only ever call C<eio_init> in
the process that uses it, and only once ever.
=head1 INITIALISATION/INTEGRATION
@ -75,6 +84,9 @@ 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.
There is currently no way to change these callbacks later, or to
"uninitialise" the library again.
=item want_poll callback
The C<want_poll> callback is invoked whenever libeio wants attention (i.e.
@ -99,7 +111,7 @@ 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,
As with C<want_poll>, this callback is called while locks are being held,
so you I<must not call any libeio functions form within this callback>.
=item int eio_poll ()
@ -121,19 +133,686 @@ returns C<-1>.
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.
()>.
If C<eio_poll ()> is configured to not handle all results in one go
(i.e. it returns C<-1>) then you should start an idle watcher that calls
C<eio_poll> until it returns something C<!= -1>.
A full-featured connector between libeio and libev would look as follows
(if C<eio_poll> is handling all requests, it can of course be simplified a
lot by removing the idle watcher logic):
static struct ev_loop *loop;
static ev_idle repeat_watcher;
static ev_async ready_watcher;
/* idle watcher callback, only used when eio_poll */
/* didn't handle all results in one call */
static void
repeat (EV_P_ ev_idle *w, int revents)
{
if (eio_poll () != -1)
ev_idle_stop (EV_A_ w);
}
/* eio has some results, process them */
static void
ready (EV_P_ ev_async *w, int revents)
{
if (eio_poll () == -1)
ev_idle_start (EV_A_ &repeat_watcher);
}
/* wake up the event loop */
static void
want_poll (void)
{
ev_async_send (loop, &ready_watcher)
}
void
my_init_eio ()
{
loop = EV_DEFAULT;
ev_idle_init (&repeat_watcher, repeat);
ev_async_init (&ready_watcher, ready);
ev_async_start (loop &watcher);
eio_init (want_poll, 0);
}
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
loop should be told to wait for read readiness 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>).
C<eio_poll>.
You don't have to take special care in the case C<eio_poll> doesn't handle
all requests, as the done callback will not be invoked, so the event loop
will still signal readiness for the pipe until I<all> results have been
processed.
=head1 HIGH LEVEL REQUEST API
Libeio has both a high-level API, which consists of calling a request
function with a callback to be called on completion, and a low-level API
where you fill out request structures and submit them.
This section describes the high-level API.
=head2 REQUEST SUBMISSION AND RESULT PROCESSING
You submit a request by calling the relevant C<eio_TYPE> function with the
required parameters, a callback of type C<int (*eio_cb)(eio_req *req)>
(called C<eio_cb> below) and a freely usable C<void *data> argument.
The return value will either be 0, in case something went really wrong
(which can basically only happen on very fatal errors, such as C<malloc>
returning 0, which is rather unlikely), or a pointer to the newly-created
and submitted C<eio_req *>.
The callback will be called with an C<eio_req *> which contains the
results of the request. The members you can access inside that structure
vary from request to request, except for:
=over 4
=item C<ssize_t result>
This contains the result value from the call (usually the same as the
syscall of the same name).
=item C<int errorno>
This contains the value of C<errno> after the call.
=item C<void *data>
The C<void *data> member simply stores the value of the C<data> argument.
=back
The return value of the callback is normally C<0>, which tells libeio to
continue normally. If a callback returns a nonzero value, libeio will
stop processing results (in C<eio_poll>) and will return the value to its
caller.
Memory areas passed to libeio must stay valid as long as a request
executes, with the exception of paths, which are being copied
internally. Any memory libeio itself allocates will be freed after the
finish callback has been called. If you want to manage all memory passed
to libeio yourself you can use the low-level API.
For example, to open a file, you could do this:
static int
file_open_done (eio_req *req)
{
if (req->result < 0)
{
/* open() returned -1 */
errno = req->errorno;
perror ("open");
}
else
{
int fd = req->result;
/* now we have the new fd in fd */
}
return 0;
}
/* the first three arguments are passed to open(2) */
/* the remaining are priority, callback and data */
if (!eio_open ("/etc/passwd", O_RDONLY, 0, 0, file_open_done, 0))
abort (); /* something went wrong, we will all die!!! */
Note that you additionally need to call C<eio_poll> when the C<want_cb>
indicates that requests are ready to be processed.
=head2 CANCELLING REQUESTS
Sometimes the need for a request goes away before the request is
finished. In that case, one can cancel the request by a call to
C<eio_cancel>:
=over 4
=item eio_cancel (eio_req *req)
Cancel the request (and all its subrequests). If the request is currently
executing it might still continue to execute, and in other cases it might
still take a while till the request is cancelled.
Even if cancelled, the finish callback will still be invoked - the
callbacks of all cancellable requests need to check whether the request
has been cancelled by calling C<EIO_CANCELLED (req)>:
static int
my_eio_cb (eio_req *req)
{
if (EIO_CANCELLED (req))
return 0;
}
In addition, cancelled requests will I<either> have C<< req->result >>
set to C<-1> and C<errno> to C<ECANCELED>, or I<otherwise> they were
successfully executed, despite being cancelled (e.g. when they have
already been executed at the time they were cancelled).
C<EIO_CANCELLED> is still true for requests that have successfully
executed, as long as C<eio_cancel> was called on them at some point.
=back
=head2 AVAILABLE REQUESTS
The following request functions are available. I<All> of them return the
C<eio_req *> on success and C<0> on failure, and I<all> of them have the
same three trailing arguments: C<pri>, C<cb> and C<data>. The C<cb> is
mandatory, but in most cases, you pass in C<0> as C<pri> and C<0> or some
custom data value as C<data>.
=head3 POSIX API WRAPPERS
These requests simply wrap the POSIX call of the same name, with the same
arguments. If a function is not implemented by the OS and cannot be emulated
in some way, then all of these return C<-1> and set C<errorno> to C<ENOSYS>.
=over 4
=item eio_open (const char *path, int flags, mode_t mode, int pri, eio_cb cb, void *data)
=item eio_truncate (const char *path, off_t offset, int pri, eio_cb cb, void *data)
=item eio_chown (const char *path, uid_t uid, gid_t gid, int pri, eio_cb cb, void *data)
=item eio_chmod (const char *path, mode_t mode, int pri, eio_cb cb, void *data)
=item eio_mkdir (const char *path, mode_t mode, int pri, eio_cb cb, void *data)
=item eio_rmdir (const char *path, int pri, eio_cb cb, void *data)
=item eio_unlink (const char *path, int pri, eio_cb cb, void *data)
=item eio_utime (const char *path, eio_tstamp atime, eio_tstamp mtime, int pri, eio_cb cb, void *data)
=item eio_mknod (const char *path, mode_t mode, dev_t dev, int pri, eio_cb cb, void *data)
=item eio_link (const char *path, const char *new_path, int pri, eio_cb cb, void *data)
=item eio_symlink (const char *path, const char *new_path, int pri, eio_cb cb, void *data)
=item eio_rename (const char *path, const char *new_path, int pri, eio_cb cb, void *data)
=item eio_mlock (void *addr, size_t length, int pri, eio_cb cb, void *data)
=item eio_close (int fd, int pri, eio_cb cb, void *data)
=item eio_sync (int pri, eio_cb cb, void *data)
=item eio_fsync (int fd, int pri, eio_cb cb, void *data)
=item eio_fdatasync (int fd, int pri, eio_cb cb, void *data)
=item eio_futime (int fd, eio_tstamp atime, eio_tstamp mtime, int pri, eio_cb cb, void *data)
=item eio_ftruncate (int fd, off_t offset, int pri, eio_cb cb, void *data)
=item eio_fchmod (int fd, mode_t mode, int pri, eio_cb cb, void *data)
=item eio_fchown (int fd, uid_t uid, gid_t gid, int pri, eio_cb cb, void *data)
=item eio_dup2 (int fd, int fd2, int pri, eio_cb cb, void *data)
These have the same semantics as the syscall of the same name, their
return value is available as C<< req->result >> later.
=item eio_read (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data)
=item eio_write (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data)
These two requests are called C<read> and C<write>, but actually wrap
C<pread> and C<pwrite>. On systems that lack these calls (such as cygwin),
libeio uses lseek/read_or_write/lseek and a mutex to serialise the
requests, so all these requests run serially and do not disturb each
other. However, they still disturb the file offset while they run, so it's
not safe to call these functions concurrently with non-libeio functions on
the same fd on these systems.
Not surprisingly, pread and pwrite are not thread-safe on Darwin (OS/X),
so it is advised not to submit multiple requests on the same fd on this
horrible pile of garbage.
=item eio_mlockall (int flags, int pri, eio_cb cb, void *data)
Like C<mlockall>, but the flag value constants are called
C<EIO_MCL_CURRENT> and C<EIO_MCL_FUTURE>.
=item eio_msync (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data)
Just like msync, except that the flag values are called C<EIO_MS_ASYNC>,
C<EIO_MS_INVALIDATE> and C<EIO_MS_SYNC>.
=item eio_readlink (const char *path, int pri, eio_cb cb, void *data)
If successful, the path read by C<readlink(2)> can be accessed via C<<
req->ptr2 >> and is I<NOT> null-terminated, with the length specified as
C<< req->result >>.
if (req->result >= 0)
{
char *target = strndup ((char *)req->ptr2, req->result);
free (target);
}
=item eio_realpath (const char *path, int pri, eio_cb cb, void *data)
Similar to the realpath libc function, but unlike that one, C<<
req->result >> is C<-1> on failure. On success, the result is the length
of the returned path in C<ptr2> (which is I<NOT> 0-terminated) - this is
similar to readlink.
=item eio_stat (const char *path, int pri, eio_cb cb, void *data)
=item eio_lstat (const char *path, int pri, eio_cb cb, void *data)
=item eio_fstat (int fd, int pri, eio_cb cb, void *data)
Stats a file - if C<< req->result >> indicates success, then you can
access the C<struct stat>-like structure via C<< req->ptr2 >>:
EIO_STRUCT_STAT *statdata = (EIO_STRUCT_STAT *)req->ptr2;
=item eio_statvfs (const char *path, int pri, eio_cb cb, void *data)
=item eio_fstatvfs (int fd, int pri, eio_cb cb, void *data)
Stats a filesystem - if C<< req->result >> indicates success, then you can
access the C<struct statvfs>-like structure via C<< req->ptr2 >>:
EIO_STRUCT_STATVFS *statdata = (EIO_STRUCT_STATVFS *)req->ptr2;
=back
=head3 READING DIRECTORIES
Reading directories sounds simple, but can be rather demanding, especially
if you want to do stuff such as traversing a directory hierarchy or
processing all files in a directory. Libeio can assist these complex tasks
with it's C<eio_readdir> call.
=over 4
=item eio_readdir (const char *path, int flags, int pri, eio_cb cb, void *data)
This is a very complex call. It basically reads through a whole directory
(via the C<opendir>, C<readdir> and C<closedir> calls) and returns either
the names or an array of C<struct eio_dirent>, depending on the C<flags>
argument.
The C<< req->result >> indicates either the number of files found, or
C<-1> on error. On success, null-terminated names can be found as C<< req->ptr2 >>,
and C<struct eio_dirents>, if requested by C<flags>, can be found via C<<
req->ptr1 >>.
Here is an example that prints all the names:
int i;
char *names = (char *)req->ptr2;
for (i = 0; i < req->result; ++i)
{
printf ("name #%d: %s\n", i, names);
/* move to next name */
names += strlen (names) + 1;
}
Pseudo-entries such as F<.> and F<..> are never returned by C<eio_readdir>.
C<flags> can be any combination of:
=over 4
=item EIO_READDIR_DENTS
If this flag is specified, then, in addition to the names in C<ptr2>,
also an array of C<struct eio_dirent> is returned, in C<ptr1>. A C<struct
eio_dirent> looks like this:
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 */
};
The only members you normally would access are C<nameofs>, which is the
byte-offset from C<ptr2> to the start of the name, C<namelen> and C<type>.
C<type> can be one of:
C<EIO_DT_UNKNOWN> - if the type is not known (very common) and you have to C<stat>
the name yourself if you need to know,
one of the "standard" POSIX file types (C<EIO_DT_REG>, C<EIO_DT_DIR>, C<EIO_DT_LNK>,
C<EIO_DT_FIFO>, C<EIO_DT_SOCK>, C<EIO_DT_CHR>, C<EIO_DT_BLK>)
or some OS-specific type (currently
C<EIO_DT_MPC> - multiplexed char device (v7+coherent),
C<EIO_DT_NAM> - xenix special named file,
C<EIO_DT_MPB> - multiplexed block device (v7+coherent),
C<EIO_DT_NWK> - HP-UX network special,
C<EIO_DT_CMP> - VxFS compressed,
C<EIO_DT_DOOR> - solaris door, or
C<EIO_DT_WHT>).
This example prints all names and their type:
int i;
struct eio_dirent *ents = (struct eio_dirent *)req->ptr1;
char *names = (char *)req->ptr2;
for (i = 0; i < req->result; ++i)
{
struct eio_dirent *ent = ents + i;
char *name = names + ent->nameofs;
printf ("name #%d: %s (type %d)\n", i, name, ent->type);
}
=item EIO_READDIR_DIRS_FIRST
When this flag is specified, then the names will be returned in an order
where likely directories come first, in optimal C<stat> order. This is
useful when you need to quickly find directories, or you want to find all
directories while avoiding to stat() each entry.
If the system returns type information in readdir, then this is used
to find directories directly. Otherwise, likely directories are names
beginning with ".", or otherwise names with no dots, of which names with
short names are tried first.
=item EIO_READDIR_STAT_ORDER
When this flag is specified, then the names will be returned in an order
suitable for stat()'ing each one. That is, when you plan to stat()
all files in the given directory, then the returned order will likely
be fastest.
If both this flag and C<EIO_READDIR_DIRS_FIRST> are specified, then the
likely directories come first, resulting in a less optimal stat order.
=item EIO_READDIR_FOUND_UNKNOWN
This flag should not be specified when calling C<eio_readdir>. Instead,
it is being set by C<eio_readdir> (you can access the C<flags> via C<<
req->int1 >>, when any of the C<type>'s found were C<EIO_DT_UNKNOWN>. The
absence of this flag therefore indicates that all C<type>'s are known,
which can be used to speed up some algorithms.
A typical use case would be to identify all subdirectories within a
directory - you would ask C<eio_readdir> for C<EIO_READDIR_DIRS_FIRST>. If
then this flag is I<NOT> set, then all the entries at the beginning of the
returned array of type C<EIO_DT_DIR> are the directories. Otherwise, you
should start C<stat()>'ing the entries starting at the beginning of the
array, stopping as soon as you found all directories (the count can be
deduced by the link count of the directory).
=back
=back
=head3 OS-SPECIFIC CALL WRAPPERS
These wrap OS-specific calls (usually Linux ones), and might or might not
be emulated on other operating systems. Calls that are not emulated will
return C<-1> and set C<errno> to C<ENOSYS>.
=over 4
=item eio_sendfile (int out_fd, int in_fd, off_t in_offset, size_t length, int pri, eio_cb cb, void *data)
Wraps the C<sendfile> syscall. The arguments follow the Linux version, but
libeio supports and will use similar calls on FreeBSD, HP/UX, Solaris and
Darwin.
If the OS doesn't support some sendfile-like call, or the call fails,
indicating support for the given file descriptor type (for example,
Linux's sendfile might not support file to file copies), then libeio will
emulate the call in userspace, so there are almost no limitations on its
use.
=item eio_readahead (int fd, off_t offset, size_t length, int pri, eio_cb cb, void *data)
Calls C<readahead(2)>. If the syscall is missing, then the call is
emulated by simply reading the data (currently in 64kiB chunks).
=item eio_syncfs (int fd, int pri, eio_cb cb, void *data)
Calls Linux' C<syncfs> syscall, if available. Returns C<-1> and sets
C<errno> to C<ENOSYS> if the call is missing I<but still calls sync()>,
if the C<fd> is C<< >= 0 >>, so you can probe for the availability of the
syscall with a negative C<fd> argument and checking for C<-1/ENOSYS>.
=item eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data)
Calls C<sync_file_range>. If the syscall is missing, then this is the same
as calling C<fdatasync>.
Flags can be any combination of C<EIO_SYNC_FILE_RANGE_WAIT_BEFORE>,
C<EIO_SYNC_FILE_RANGE_WRITE> and C<EIO_SYNC_FILE_RANGE_WAIT_AFTER>.
=item eio_fallocate (int fd, int mode, off_t offset, off_t len, int pri, eio_cb cb, void *data)
Calls C<fallocate> (note: I<NOT> C<posix_fallocate>!). If the syscall is
missing, then it returns failure and sets C<errno> to C<ENOSYS>.
The C<mode> argument can be C<0> (for behaviour similar to
C<posix_fallocate>), or C<EIO_FALLOC_FL_KEEP_SIZE>, which keeps the size
of the file unchanged (but still preallocates space beyond end of file).
=back
=head3 LIBEIO-SPECIFIC REQUESTS
These requests are specific to libeio and do not correspond to any OS call.
=over 4
=item eio_mtouch (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data)
Reads (C<flags == 0>) or modifies (C<flags == EIO_MT_MODIFY) the given
memory area, page-wise, that is, it reads (or reads and writes back) the
first octet of every page that spans the memory area.
This can be used to page in some mmapped file, or dirty some pages. Note
that dirtying is an unlocked read-write access, so races can ensue when
the some other thread modifies the data stored in that memory area.
=item eio_custom (void (*)(eio_req *) execute, int pri, eio_cb cb, void *data)
Executes a custom request, i.e., a user-specified callback.
The callback gets the C<eio_req *> as parameter and is expected to read
and modify any request-specific members. Specifically, it should set C<<
req->result >> to the result value, just like other requests.
Here is an example that simply calls C<open>, like C<eio_open>, but it
uses the C<data> member as filename and uses a hardcoded C<O_RDONLY>. If
you want to pass more/other parameters, you either need to pass some
struct or so via C<data> or provide your own wrapper using the low-level
API.
static int
my_open_done (eio_req *req)
{
int fd = req->result;
return 0;
}
static void
my_open (eio_req *req)
{
req->result = open (req->data, O_RDONLY);
}
eio_custom (my_open, 0, my_open_done, "/etc/passwd");
=item eio_busy (eio_tstamp delay, int pri, eio_cb cb, void *data)
This is a request that takes C<delay> seconds to execute, but otherwise
does nothing - it simply puts one of the worker threads to sleep for this
long.
This request can be used to artificially increase load, e.g. for debugging
or benchmarking reasons.
=item eio_nop (int pri, eio_cb cb, void *data)
This request does nothing, except go through the whole request cycle. This
can be used to measure latency or in some cases to simplify code, but is
not really of much use.
=back
=head3 GROUPING AND LIMITING REQUESTS
There is one more rather special request, C<eio_grp>. It is a very special
aio request: Instead of doing something, it is a container for other eio
requests.
There are two primary use cases for this: a) bundle many requests into a
single, composite, request with a definite callback and the ability to
cancel the whole request with its subrequests and b) limiting the number
of "active" requests.
Further below you will find more discussion of these topics - first
follows the reference section detailing the request generator and other
methods.
=over 4
=item eio_req *grp = eio_grp (eio_cb cb, void *data)
Creates, submits and returns a group request. Note that it doesn't have a
priority, unlike all other requests.
=item eio_grp_add (eio_req *grp, eio_req *req)
Adds a request to the request group.
=item eio_grp_cancel (eio_req *grp)
Cancels all requests I<in> the group, but I<not> the group request
itself. You can cancel the group request I<and> all subrequests via a
normal C<eio_cancel> call.
=back
=head4 GROUP REQUEST LIFETIME
Left alone, a group request will instantly move to the pending state and
will be finished at the next call of C<eio_poll>.
The usefulness stems from the fact that, if a subrequest is added to a
group I<before> a call to C<eio_poll>, via C<eio_grp_add>, then the group
will not finish until all the subrequests have finished.
So the usage cycle of a group request is like this: after it is created,
you normally instantly add a subrequest. If none is added, the group
request will finish on it's own. As long as subrequests are added before
the group request is finished it will be kept from finishing, that is the
callbacks of any subrequests can, in turn, add more requests to the group,
and as long as any requests are active, the group request itself will not
finish.
=head4 CREATING COMPOSITE REQUESTS
Imagine you wanted to create an C<eio_load> request that opens a file,
reads it and closes it. This means it has to execute at least three eio
requests, but for various reasons it might be nice if that request looked
like any other eio request.
This can be done with groups:
=over 4
=item 1) create the request object
Create a group that contains all further requests. This is the request you
can return as "the load request".
=item 2) open the file, maybe
Next, open the file with C<eio_open> and add the request to the group
request and you are finished setting up the request.
If, for some reason, you cannot C<eio_open> (path is a null ptr?) you
can set C<< grp->result >> to C<-1> to signal an error and let the group
request finish on its own.
=item 3) open callback adds more requests
In the open callback, if the open was not successful, copy C<<
req->errorno >> to C<< grp->errorno >> and set C<< grp->errorno >> to
C<-1> to signal an error.
Otherwise, malloc some memory or so and issue a read request, adding the
read request to the group.
=item 4) continue issuing requests till finished
In the real callback, check for errors and possibly continue with
C<eio_close> or any other eio request in the same way.
As soon as no new requests are added the group request will finish. Make
sure you I<always> set C<< grp->result >> to some sensible value.
=back
=head4 REQUEST LIMITING
#TODO
void eio_grp_limit (eio_req *grp, int limit);
=back
=head1 LOW LEVEL REQUEST API
#TODO
=head1 ANATOMY AND LIFETIME OF AN EIO REQUEST
A request is represented by a structure of type C<eio_req>. To initialise
it, clear it to all zero bytes:
eio_req req;
memset (&req, 0, sizeof (req));
A more common way to initialise a new C<eio_req> is to use C<calloc>:
eio_req *req = calloc (1, sizeof (*req));
In either case, libeio neither allocates, initialises or frees the
C<eio_req> structure for you - it merely uses it.
zero
#TODO
=head2 CONFIGURATION
@ -154,14 +833,18 @@ 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.
=over 4
=item 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.
=item b) this is implemented by calling C<gettimeofday> after each
request, which can be costly.
c) at least one request will be handled.
=item c) at least one request will be handled.
=back
=item eio_set_max_poll_reqs (unsigned int nreqs)
@ -187,7 +870,7 @@ Set the maximum number of threads that libeio will spawn.
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
work to do): libeio will keep some threads idle in preparation for more
requests, but never longer than C<nthreads> threads.
In addition to this, libeio will also stop threads when they are idle for
@ -216,23 +899,6 @@ 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
@ -258,7 +924,7 @@ 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
stack size (C<sizeof (void *) * 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.

39
deps/uv/src/eio/libeio.m4

@ -1,3 +1,7 @@
dnl openbsd in it's neverending brokenness requires stdint.h for intptr_t,
dnl but that header isn't very portable...
AC_CHECK_HEADERS([stdint.h sys/syscall.h sys/prctl.h])
AC_SEARCH_LIBS(
pthread_create,
[pthread pthreads pthreadVC2],
@ -119,6 +123,41 @@ int main (void)
],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)
AC_CACHE_CHECK(for fallocate, ac_cv_fallocate, [AC_LINK_IFELSE([
#include <fcntl.h>
int main (void)
{
int fd = 0;
int mode = 0;
off_t offset = 1;
off_t len = 1;
int res;
res = fallocate (fd, mode, offset, len);
return 0;
}
],ac_cv_fallocate=yes,ac_cv_fallocate=no)])
test $ac_cv_fallocate = yes && AC_DEFINE(HAVE_FALLOCATE, 1, fallocate(2) is available)
AC_CACHE_CHECK(for sys_syncfs, ac_cv_sys_syncfs, [AC_LINK_IFELSE([
#include <unistd.h>
#include <sys/syscall.h>
int main (void)
{
int res = syscall (__NR_syncfs, (int)0);
}
],ac_cv_sys_syncfs=yes,ac_cv_sys_syncfs=no)])
test $ac_cv_sys_syncfs = yes && AC_DEFINE(HAVE_SYS_SYNCFS, 1, syscall(__NR_syncfs) is available)
AC_CACHE_CHECK(for prctl_set_name, ac_cv_prctl_set_name, [AC_LINK_IFELSE([
#include <sys/prctl.h>
int main (void)
{
char name[] = "test123";
int res = prctl (PR_SET_NAME, (unsigned long)name, 0, 0, 0);
}
],ac_cv_prctl_set_name=yes,ac_cv_prctl_set_name=no)])
test $ac_cv_prctl_set_name = yes && AC_DEFINE(HAVE_PRCTL_SET_NAME, 1, prctl(PR_SET_NAME) is available)
dnl #############################################################################
dnl # these checks exist for the benefit of IO::AIO

41
deps/uv/src/eio/xthread.h

@ -2,7 +2,7 @@
#define XTHREAD_H_
/* whether word reads are potentially non-atomic.
* this is conservatice, likely most arches this runs
* this is conservative, likely most arches this runs
* on have atomic word read/writes.
*/
#ifndef WORDACCESS_UNSAFE
@ -17,14 +17,8 @@
#ifdef _WIN32
#ifndef __MINGW32__
typedef int ssize_t
#endif
#define NTDDI_VERSION NTDDI_WIN2K // needed to get win2000 api calls
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x400
#endif
#include <stdio.h>//D
#include <fcntl.h>
#include <io.h>
@ -34,18 +28,20 @@ typedef int ssize_t
#include <windows.h>
#include <pthread.h>
#define sigset_t int
#define sigfillset(a)
#define pthread_sigmask(a,b,c)
#define sigaddset(a,b)
#define sigemptyset(s)
#define sigfillset(s)
typedef pthread_mutex_t xmutex_t;
#define X_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
#define X_MUTEX_CREATE(mutex) pthread_mutex_init (&(mutex), 0)
#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_CREATE(cond) pthread_cond_init (&(cond), 0)
#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))
@ -100,18 +96,27 @@ thread_create (xthread_t *tid, void *(*proc)(void *), void *arg)
typedef pthread_mutex_t xmutex_t;
#if __linux && defined (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP)
# define X_MUTEX_INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
# define X_MUTEX_INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
# define X_MUTEX_CREATE(mutex) \
do { \
pthread_mutexattr_t attr; \
pthread_mutexattr_init (&attr); \
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ADAPTIVE_NP); \
pthread_mutex_init (&(mutex), &attr); \
} while (0)
#else
# define X_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
# define X_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
# define X_MUTEX_CREATE(mutex) pthread_mutex_init (&(mutex), 0)
#endif
#define X_LOCK(mutex) pthread_mutex_lock (&(mutex))
#define X_UNLOCK(mutex) pthread_mutex_unlock (&(mutex))
#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))
#define X_COND_INIT PTHREAD_COND_INITIALIZER
#define X_COND_CREATE(cond) pthread_cond_init (&(cond), 0)
#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)
@ -122,8 +127,8 @@ typedef pthread_t xthread_t;
# define PTHREAD_STACK_MIN 0
#endif
#ifndef X_STACKSIZE
# define X_STACKSIZE sizeof (long) * 4096
#ifndef XTHREAD_STACKSIZE
# define XTHREAD_STACKSIZE sizeof (void *) * 4096
#endif
static int

3
deps/uv/src/uv-unix.c

@ -62,6 +62,7 @@
#if defined(__FreeBSD__)
#include <sys/sysctl.h>
#include <sys/wait.h>
#endif
@ -2360,8 +2361,6 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) {
assert((status == 1)
&& "poll() on pipe read end failed");
assert((pfd.revents & POLLIN) == 0
&& "unexpected POLLIN on pipe read end");
assert((pfd.revents & POLLHUP) == POLLHUP
&& "no POLLHUP on pipe read end");

1
deps/uv/src/win/internal.h

@ -110,6 +110,7 @@ void uv_process_endgames();
#define DECREASE_PENDING_REQ_COUNT(handle) \
do { \
assert(handle->reqs_pending > 0); \
handle->reqs_pending--; \
\
if (handle->flags & UV_HANDLE_CLOSING && \

2
deps/uv/src/win/pipe.c

@ -317,6 +317,8 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
handle->reqs_pending++;
return 0;
}

16
deps/uv/test/benchmark-list.h

@ -21,6 +21,10 @@
BENCHMARK_DECLARE (sizes)
BENCHMARK_DECLARE (ping_pongs)
BENCHMARK_DECLARE (tcp4_pound_100)
BENCHMARK_DECLARE (tcp4_pound_1000)
BENCHMARK_DECLARE (pipe_pound_100)
BENCHMARK_DECLARE (pipe_pound_1000)
BENCHMARK_DECLARE (tcp_pump100_client)
BENCHMARK_DECLARE (tcp_pump1_client)
BENCHMARK_DECLARE (pipe_pump100_client)
@ -46,12 +50,24 @@ TASK_LIST_START
BENCHMARK_ENTRY (tcp_pump1_client)
BENCHMARK_HELPER (tcp_pump1_client, tcp_pump_server)
BENCHMARK_ENTRY (tcp4_pound_100)
BENCHMARK_HELPER (tcp4_pound_100, tcp4_echo_server)
BENCHMARK_ENTRY (tcp4_pound_1000)
BENCHMARK_HELPER (tcp4_pound_1000, tcp4_echo_server)
BENCHMARK_ENTRY (pipe_pump100_client)
BENCHMARK_HELPER (pipe_pump100_client, pipe_pump_server)
BENCHMARK_ENTRY (pipe_pump1_client)
BENCHMARK_HELPER (pipe_pump1_client, pipe_pump_server)
BENCHMARK_ENTRY (pipe_pound_100)
BENCHMARK_HELPER (pipe_pound_100, pipe_echo_server)
BENCHMARK_ENTRY (pipe_pound_1000)
BENCHMARK_HELPER (pipe_pound_1000, pipe_echo_server)
BENCHMARK_ENTRY (gethostbyname)
BENCHMARK_HELPER (gethostbyname, dns_server)

237
deps/uv/test/benchmark-pound.c

@ -0,0 +1,237 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "task.h"
#include "uv.h"
/* Base class for tcp_conn_rec and pipe_conn_rec.
* The ordering of fields matters!
*/
typedef struct {
uv_connect_t conn_req;
uv_write_t write_req;
uv_stream_t stream;
} conn_rec;
typedef struct {
uv_connect_t conn_req;
uv_write_t write_req;
uv_tcp_t stream;
} tcp_conn_rec;
typedef struct {
uv_connect_t conn_req;
uv_write_t write_req;
uv_pipe_t stream;
} pipe_conn_rec;
static char buffer[] = "QS";
static int64_t start_time, end_time;
static int closed_streams, concurrency;
typedef void *(*setup_fn)(int num, void* arg);
typedef int (*connect_fn)(int num, void* handles, void* arg);
static uv_buf_t alloc_cb(uv_stream_t* stream, size_t suggested_size);
static void connect_cb(uv_connect_t* conn_req, int status);
static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf);
static void close_cb(uv_handle_t* handle);
static uv_buf_t alloc_cb(uv_stream_t* stream, size_t suggested_size) {
static char slab[65536];
uv_buf_t buf;
buf.base = slab;
buf.len = sizeof(slab);
return buf;
}
static void connect_cb(uv_connect_t* req, int status) {
conn_rec* conn;
uv_buf_t buf;
int r;
ASSERT(req != NULL);
ASSERT(status == 0);
conn = req->data;
ASSERT(conn != NULL);
r = uv_read_start(&conn->stream, alloc_cb, read_cb);
ASSERT(r == 0);
buf.base = buffer;
buf.len = sizeof(buffer) - 1;
r = uv_write(&conn->write_req, &conn->stream, &buf, 1, NULL);
ASSERT(r == 0);
}
static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) {
ASSERT(stream != NULL);
ASSERT(nread == -1 && uv_last_error().code == UV_EOF);
uv_close((uv_handle_t*)stream, close_cb);
}
static void close_cb(uv_handle_t* handle) {
ASSERT(handle != NULL);
closed_streams++;
if (closed_streams == concurrency) {
uv_update_time();
end_time = uv_now();
}
}
static void* tcp_do_setup(int num, void* arg) {
tcp_conn_rec* conns;
tcp_conn_rec* pe;
tcp_conn_rec* p;
int r;
concurrency = num;
closed_streams = 0;
conns = calloc(num, sizeof(tcp_conn_rec));
ASSERT(conns != NULL);
for (p = conns, pe = p + num; p < pe; p++) {
r = uv_tcp_init(&p->stream);
ASSERT(r == 0);
p->stream.data = p;
p->conn_req.data = p;
p->write_req.data = p;
p->conn_req.handle = (uv_stream_t*)&p->stream;
p->write_req.handle = (uv_stream_t*)&p->stream;
}
return conns;
}
static void* pipe_do_setup(int num, void* arg) {
pipe_conn_rec* conns;
pipe_conn_rec* pe;
pipe_conn_rec* p;
int r;
concurrency = num;
closed_streams = 0;
conns = calloc(num, sizeof(pipe_conn_rec));
ASSERT(conns != NULL);
for (p = conns, pe = p + num; p < pe; p++) {
r = uv_pipe_init(&p->stream);
ASSERT(r == 0);
p->stream.data = p;
p->conn_req.data = p;
p->write_req.data = p;
p->conn_req.handle = (uv_stream_t*)&p->stream;
p->write_req.handle = (uv_stream_t*)&p->stream;
}
return conns;
}
static int tcp_do_connect(int num, void* conns, void* arg) {
struct sockaddr_in addr;
tcp_conn_rec* pe;
tcp_conn_rec* p;
int r;
addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
for (p = conns, pe = p + num; p < pe; p++) {
r = uv_tcp_connect(&p->conn_req, &p->stream, addr, connect_cb);
ASSERT(r == 0);
}
return 0;
}
static int pipe_do_connect(int num, void* conns, void* arg) {
pipe_conn_rec* pe;
pipe_conn_rec* p;
int r;
for (p = conns, pe = p + num; p < pe; p++) {
r = uv_pipe_connect(&p->conn_req, &p->stream, TEST_PIPENAME, connect_cb);
ASSERT(r == 0);
}
return 0;
}
static int pound_it(int concurrency,
const char* type,
setup_fn do_setup,
connect_fn do_connect,
void* arg) {
void* state;
int r;
uv_init();
state = do_setup(concurrency, arg);
ASSERT(state != NULL);
uv_update_time();
start_time = uv_now();
r = do_connect(concurrency, state, arg);
ASSERT(!r);
uv_run();
LOGF("%s-conn-pound-%d: %.0f accepts/s\n",
type, concurrency,
(double) concurrency / (double) (end_time - start_time) * 1000.0);
return 0;
}
BENCHMARK_IMPL(tcp4_pound_100) {
return pound_it(100, "tcp", tcp_do_setup, tcp_do_connect, NULL);
}
BENCHMARK_IMPL(tcp4_pound_1000) {
return pound_it(1000, "tcp", tcp_do_setup, tcp_do_connect, NULL);
}
BENCHMARK_IMPL(pipe_pound_100) {
return pound_it(100, "pipe", pipe_do_setup, pipe_do_connect, NULL);
}
BENCHMARK_IMPL(pipe_pound_1000) {
return pound_it(1000, "pipe", pipe_do_setup, pipe_do_connect, NULL);
}

19
deps/uv/test/echo-server.c

@ -90,12 +90,21 @@ static void after_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
return;
}
/* Scan for the letter Q which signals that we should quit. */
/*
* Scan for the letter Q which signals that we should quit the server.
* If we get QS it means close the stream.
*/
if (!server_closed) {
for (i = 0; i < nread; i++) {
if (buf.base[i] == 'Q') {
uv_close(server, on_server_close);
server_closed = 1;
if (i + 1 < nread && buf.base[i + 1] == 'S') {
free(buf.base);
uv_close((uv_handle_t*)handle, NULL);
return;
} else {
uv_close(server, on_server_close);
server_closed = 1;
}
}
}
}
@ -187,7 +196,7 @@ static int tcp4_echo_start(int port) {
return 1;
}
r = uv_listen((uv_stream_t*)&tcpServer, 128, on_connection);
r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
if (r) {
/* TODO: Error codes */
fprintf(stderr, "Listen error\n");
@ -220,7 +229,7 @@ static int tcp6_echo_start(int port) {
return 0;
}
r = uv_listen((uv_stream_t*)&tcpServer, 128, on_connection);
r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
if (r) {
/* TODO: Error codes */
fprintf(stderr, "Listen error\n");

Loading…
Cancel
Save