*.l[oa]
*.opensdf
*.orig
+*.pyc
*.sdf
*.suo
core
Isaac Z. Schlueter <i@izs.me>
Keno Fischer <kenof@stanford.edu> <kfischer+github@college.harvard.edu>
Keno Fischer <kenof@stanford.edu> <kfischer@college.harvard.edu>
+Maciej Małecki <maciej.malecki@notimplemented.org> <me@mmalecki.com>
+Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com>
Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org>
Ryan Dahl <ryan@joyent.com> <ry@tinyclouds.org>
Ryan Emery <seebees@gmail.com>
Sean Farrell <sean.farrell@rioki.org>
Chris Bank <cbank@adobe.com>
Geert Jansen <geertj@gmail.com>
+Alex Gaynor <alex.gaynor@gmail.com>
+huxingyi <huxingyi@msn.com>
+ci-innoq <christoph.iserlohn@innoq.com>
+Steven Kabbes <stevenkabbes@gmail.com>
+Tenor Biel <tenorbiel@gmail.com>
+Andrej Manduch <AManduch@gmail.com>
+Joshua Neuheisel <joshua@neuheisel.us>
+Alexis Campailla <alexis@janeasystems.com>
+Yorkie <yorkiefixer@gmail.com>
--- /dev/null
+# CONTRIBUTING
+
+The libuv project welcomes new contributors. This document will guide you
+through the process.
+
+
+### FORK
+
+Fork the project [on GitHub](https://github.com/joyent/libuv) and check out
+your copy.
+
+```
+$ git clone https://github.com/username/libuv.git
+$ cd libuv
+$ git remote add upstream https://github.com/joyent/libuv.git
+```
+
+Now decide if you want your feature or bug fix to go into the master branch
+or the stable branch. As a rule of thumb, bug fixes go into the stable branch
+while new features go into the master branch.
+
+The stable branch is effectively frozen; patches that change the libuv
+API/ABI or affect the run-time behavior of applications get rejected.
+
+In case of doubt, open an issue in the [issue tracker][], post your question
+to the [libuv mailing list], or contact one of project maintainers
+(@bnoordhuis, @piscisaureus, @indutny or @saghul) on [IRC][].
+
+Especially do so if you plan to work on something big. Nothing is more
+frustrating than seeing your hard work go to waste because your vision
+does not align with that of a project maintainers.
+
+
+### BRANCH
+
+Okay, so you have decided on the proper branch. Create a feature branch
+and start hacking:
+
+```
+$ git checkout -b my-feature-branch -t origin/v0.10
+```
+
+(Where v0.10 is the latest stable branch as of this writing.)
+
+### CODE
+
+Please adhere to libuv's code style. In general it follows the conventions from
+the [Google C/C++ style guide]. Some of the key points, as well as some
+additional guidelines, are enumerated below.
+
+* Code that is specific to unix-y platforms should be placed in `src/unix`, and
+ declarations go into `src/uv-unix.h`.
+
+* Source code that is Windows-specific goes into `src/win`, and related
+ publicly exported types, functions and macro declarations should generally
+ be declared in `include/uv-win.h`.
+
+* Names should be descriptive and concise.
+
+* All the symbols and types that libuv makes available publicly should be
+ prefixed with `uv_` (or `UV_` in case of macros).
+
+* Internal, non-static functions should be prefixed with `uv__`.
+
+* Use two spaces and no tabs.
+
+* Lines should be wrapped at 80 characters.
+
+* Ensure that lines have no trailing whitespace, and use unix-style (LF) line
+ endings.
+
+* Use C89-compliant syntax. In other words, variables can only be declared at
+ the top of a scope (function, if/for/while-block).
+
+* When writing comments, use properly constructed sentences, including
+ punctuation.
+
+* When documenting APIs and/or source code, don't make assumptions or make
+ implications about race, gender, religion, political orientation or anything
+ else that isn't relevant to the project.
+
+* Remember that source code usually gets written once and read often: ensure
+ the reader doesn't have to make guesses. Make sure that the purpose and inner
+ logic are either obvious to a reasonably skilled professional, or add a
+ comment that explains it.
+
+
+### COMMIT
+
+Make sure git knows your name and email address:
+
+```
+$ git config --global user.name "J. Random User"
+$ git config --global user.email "j.random.user@example.com"
+```
+
+Writing good commit logs is important. A commit log should describe what
+changed and why. Follow these guidelines when writing one:
+
+1. The first line should be 50 characters or less and contain a short
+ description of the change prefixed with the name of the changed
+ subsystem (e.g. "net: add localAddress and localPort to Socket").
+2. Keep the second line blank.
+3. Wrap all other lines at 72 columns.
+
+A good commit log looks like this:
+
+```
+subsystem: explaining the commit in one line
+
+Body of commit message is a few lines of text, explaining things
+in more detail, possibly giving some background about the issue
+being fixed, etc etc.
+
+The body of the commit message can be several paragraphs, and
+please do proper word-wrap and keep columns shorter than about
+72 characters or so. That way `git log` will show things
+nicely even when it is indented.
+```
+
+The header line should be meaningful; it is what other people see when they
+run `git shortlog` or `git log --oneline`.
+
+Check the output of `git log --oneline files_that_you_changed` to find out
+what subsystem (or subsystems) your changes touch.
+
+
+### REBASE
+
+Use `git rebase` (not `git merge`) to sync your work from time to time.
+
+```
+$ git fetch upstream
+$ git rebase upstream/v0.10 # or upstream/master
+```
+
+
+### TEST
+
+Bug fixes and features should come with tests. Add your tests in the
+`test/` directory. Tests also need to be registered in `test/test-list.h`.
+Look at other tests to see how they should be structured (license boilerplate,
+the way entry points are declared, etc.).
+
+```
+$ make test
+```
+
+Make sure that there are no test regressions.
+
+### PUSH
+
+```
+$ git push origin my-feature-branch
+```
+
+Go to https://github.com/username/libuv and select your feature branch. Click
+the 'Pull Request' button and fill out the form.
+
+Pull requests are usually reviewed within a few days. If there are comments
+to address, apply your changes in a separate commit and push that to your
+feature branch. Post a comment in the pull request afterwards; GitHub does
+not send out notifications when you add commits.
+
+
+### CONTRIBUTOR LICENSE AGREEMENT
+
+The current state of affairs is that, in order to get a patch accepted, you need
+to sign Node.js's [contributor license agreement][]. You only need to do that
+once.
+
+
+[issue tracker]: https://github.com/joyent/libuv/issues
+[libuv mailing list]: http://groups.google.com/group/libuv
+[IRC]: http://webchat.freelibuv.net/?channels=libuv
+[Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
+[contributor license agreement]: http://nodejs.org/cla.html
-2013.11.21, Version 0.11.15 (Unstable)
+2013.12.14, Version 0.11.16 (Unstable), ae0ed8c49d0d313c935c22077511148b6e8408a4
+
+Changes since version 0.11.15:
+
+* fsevents: remove kFSEventStreamCreateFlagNoDefer polyfill (ci-innoq)
+
+* libuv: add more getaddrinfo errors (Steven Kabbes)
+
+* unix: fix accept() EMFILE error handling (Ben Noordhuis)
+
+* linux: fix up SO_REUSEPORT back-port (Ben Noordhuis)
+
+* fsevents: fix subfolder check (Fedor Indutny)
+
+* fsevents: fix invalid memory access (huxingyi)
+
+* windows/timer: fix uv_hrtime discontinuity (Bert Belder)
+
+* unix: fix various memory leaks and undef behavior (Fedor Indutny)
+
+* unix, windows: always update loop time (Saúl Ibarra Corretgé)
+
+* windows: translate system errors in uv_spawn (Alexis Campailla)
+
+* windows: uv_spawn code refactor (Alexis Campailla)
+
+* unix, windows: detect errors in uv_ip4/6_addr (Yorkie)
+
+* stream: introduce uv_try_write(...) (Fedor Indutny)
+
+
+2013.12.13, Version 0.10.20 (Stable), 04141464dd0fba90ace9aa6f7003ce139b888a40
+
+Changes since version 0.10.19:
+
+* linux: fix up SO_REUSEPORT back-port (Ben Noordhuis)
+
+* fs-event: fix invalid memory access (huxingyi)
+
+
+2013.11.21, Version 0.11.15 (Unstable), bfe645ed7e99ca5670d9279ad472b604c129d2e5
Changes since version 0.11.14:
test/test-delayed-accept.c \
test/test-dlerror.c \
test/test-embed.c \
+ test/test-emfile.c \
test/test-error.c \
test/test-fail-always.c \
test/test-fs-event.c \
test/test-getsockname.c \
test/test-hrtime.c \
test/test-idle.c \
+ test/test-ip4-addr.c \
test/test-ip6-addr.c \
test/test-ipc-send-recv.c \
test/test-ipc.c \
test/test-list.h \
test/test-loop-handles.c \
test/test-loop-stop.c \
+ test/test-loop-time.c \
test/test-multiple-listen.c \
test/test-mutexes.c \
test/test-osx-select.c \
test/test-tcp-unexpected-read.c \
test/test-tcp-write-to-half-open-connection.c \
test/test-tcp-writealot.c \
+ test/test-tcp-try-write.c \
test/test-thread.c \
test/test-threadpool-cancel.c \
test/test-threadpool.c \
CLEANFILES += src/unix/uv-dtrace.o src/unix/uv-dtrace.lo
endif
-SUFFIXES = .d
+if HAVE_PKG_CONFIG
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = @PACKAGE_NAME@.pc
+endif
+if HAVE_DTRACE
include/uv-dtrace.h: src/unix/uv-dtrace.d
$(AM_V_GEN)$(DTRACE) $(DTRACEFLAGS) -h -xnolibs -s $< -o $(top_srcdir)/$@
+endif
+
+if DTRACE_NEEDS_OBJECTS
+SUFFIXES = .d
src/unix/uv-dtrace.o: src/unix/uv-dtrace.d ${libuv_la_OBJECTS}
"pic_object='uv-dtrace.o'" \
"non_pic_object='uv-dtrace.o'" \
> ${top_builddir}/uv-dtrace.lo
+endif
# libuv
libuv is a multi-platform support library with a focus on asynchronous I/O. It
-was primarily developed for use by [Node.js](http://node.js.org), but it's also
+was primarily developed for use by [Node.js](http://nodejs.org), but it's also
used by Mozilla's [Rust language](http://www.rust-lang.org/),
[Luvit](http://luvit.io/), [Julia](http://julialang.org/),
[pyuv](https://crate.io/packages/pyuv/), and others.
Note for UNIX users: compile your project with `-D_LARGEFILE_SOURCE` and
`-D_FILE_OFFSET_BITS=64`. GYP builds take care of that automatically.
+### Running tests
+
+Run:
+
+ $ ./gyp_uv.py -f make
+ $ make -C out
+ $ ./out/Debug/run-tests
+
## Supported Platforms
Microsoft Windows operating systems since Windows XP SP2. It can be built
Solaris 121 and later using GCC toolchain.
+## patches
+
+See the [guidelines for contributing][].
+
[node.js]: http://nodejs.org/
[GYP]: http://code.google.com/p/gyp/
[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
+[guidelines for contributing]: https://github.com/joyent/libuv/blob/master/CONTRIBUTING.md
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_PREREQ(2.57)
-AC_INIT([libuv], [0.11.15], [https://github.com/joyent/libuv/issues])
+AC_INIT([libuv], [0.11.17], [https://github.com/joyent/libuv/issues])
AC_CONFIG_MACRO_DIR([m4])
m4_include([m4/libuv-extra-automake-flags.m4])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS)
AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os], [solaris*], [true], [false])])
AM_CONDITIONAL([WINNT], [AS_CASE([$host_os], [mingw*], [true], [false])])
PANDORA_ENABLE_DTRACE
+AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes)
+AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" = "xyes"])
+AS_IF([test "x$PKG_CONFIG" = "xyes"], [
+ AC_CONFIG_FILES([libuv.pc])
+])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
if sys.platform != 'win32':
if '-f' not in args:
args.extend('-f make'.split())
- if 'ninja' not in args:
+ if 'eclipse' not in args and 'ninja' not in args:
args.extend(['-Goutput_dir=' + output_dir])
args.extend(['--generator-output', output_dir])
(major, minor), is_clang = compiler_version()
#define UV__EAI_SERVICE (-3010)
#define UV__EAI_SOCKTYPE (-3011)
#define UV__EAI_SYSTEM (-3012) /* TODO(bnoordhuis) Return system error. */
+#define UV__EAI_BADHINTS (-3013)
+#define UV__EAI_PROTOCOL (-3014)
/* Only map to the system errno on non-Windows platforms. It's apparently
* a fairly common practice for Windows programmers to redefine errno codes.
XX(EAI_ADDRFAMILY, "address family not supported") \
XX(EAI_AGAIN, "temporary failure") \
XX(EAI_BADFLAGS, "bad ai_flags value") \
+ XX(EAI_BADHINTS, "invalid value for hints") \
XX(EAI_CANCELED, "request canceled") \
XX(EAI_FAIL, "permanent failure") \
XX(EAI_FAMILY, "ai_family not supported") \
XX(EAI_MEMORY, "out of memory") \
XX(EAI_NODATA, "no address") \
XX(EAI_NONAME, "unknown node or service") \
+ XX(EAI_OVERFLOW, "argument buffer overflow") \
+ XX(EAI_PROTOCOL, "resolved protocol is unknown") \
XX(EAI_SERVICE, "service not available for socket type") \
XX(EAI_SOCKTYPE, "socket type not supported") \
XX(EAI_SYSTEM, "system error") \
uv_stream_t* send_handle,
uv_write_cb cb);
+/*
+ * Same as `uv_write()`, but won't queue write request if it can't be completed
+ * immediately.
+ * Will return either:
+ * - positive number of bytes written
+ * - zero - if queued write is needed
+ * - negative error code
+ */
+UV_EXTERN int uv_try_write(uv_stream_t* handle, const char* buf, size_t length);
+
/* uv_write_t is a subclass of uv_req_t */
struct uv_write_s {
UV_REQ_FIELDS
--- /dev/null
+prefix=@prefix@
+exec_prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @PACKAGE_NAME@
+Version: @PACKAGE_VERSION@
+Description: multi-platform support library with a focus on asynchronous I/O.
+
+Libs: -L${libdir} -luv
+Cflags: -I${includedir}
int r;
r = uv__loop_alive(loop);
+ if (!r)
+ uv__update_time(loop);
+
while (r != 0 && loop->stop_flag == 0) {
UV_TICK_START(loop, mode);
result = _NSGetExecutablePath(buffer, &usize);
if (result) return result;
- path = (char*)malloc(2 * PATH_MAX);
+ path = malloc(2 * PATH_MAX);
fullpath = realpath(buffer, path);
if (fullpath == NULL) {
SAVE_ERRNO(free(path));
*
* 1. Read errors are reported only if nsent==0, otherwise we return nsent.
* The user needs to know that some data has already been sent, to stop
- * him from sending it twice.
+ * them from sending it twice.
*
* 2. Write errors are always reported. Write errors are bad because they
* mean data loss: we've read data but now we can't write it out.
if (strncmp(path, handle->realpath, handle->realpath_len) != 0)
continue;
- path += handle->realpath_len;
- len -= handle->realpath_len;
-
- /* Skip back slash */
- if (*path != 0) {
- path++;
- len--;
+ if (handle->realpath_len > 1 || *handle->realpath != '/') {
+ path += handle->realpath_len;
+ len -= handle->realpath_len;
+
+ /* Skip forward slash */
+ if (*path != '\0') {
+ path++;
+ len--;
+ }
}
#ifdef MAC_OS_X_VERSION_10_7
#endif /* MAC_OS_X_VERSION_10_7 */
/* Do not emit events from subdirectories (without option set) */
- if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0) {
- pos = strchr(path, '/');
- if (pos != NULL && pos != path + 1)
+ if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) {
+ pos = strchr(path + 1, '/');
+ if (pos != NULL)
continue;
}
err = uv_mutex_init(&loop->cf_mutex);
if (err)
- return err;
+ goto fail_mutex_init;
err = uv_sem_init(&loop->cf_sem, 0);
if (err)
fail_sem_init:
uv_mutex_destroy(&loop->cf_mutex);
+
+fail_mutex_init:
free(state);
return err;
}
/* OSX < 10.7 has no file events, polyfill them */
#ifndef MAC_OS_X_VERSION_10_7
-static const int kFSEventStreamCreateFlagNoDefer = 0x00000002;
static const int kFSEventStreamCreateFlagFileEvents = 0x00000010;
static const int kFSEventStreamEventFlagItemCreated = 0x00000100;
static const int kFSEventStreamEventFlagItemRemoved = 0x00000200;
int r;
bytes = 0;
+ end = 0;
do {
r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes);
* calling close() and accept().
*/
static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
- int fd;
+ int err;
if (loop->emfile_fd == -1)
return -EMFILE;
uv__close(loop->emfile_fd);
+ loop->emfile_fd = -1;
- for (;;) {
- fd = uv__accept(accept_fd);
-
- if (fd != -1) {
- uv__close(fd);
- continue;
- }
-
- if (errno == EINTR)
- continue;
+ do {
+ err = uv__accept(accept_fd);
+ if (err >= 0)
+ uv__close(err);
+ } while (err >= 0 || err == -EINTR);
- SAVE_ERRNO(loop->emfile_fd = uv__open_cloexec("/", O_RDONLY));
- return -errno;
- }
+ SAVE_ERRNO(loop->emfile_fd = uv__open_cloexec("/", O_RDONLY));
+ return err;
}
/* Only free when there was no error. On error, we touch up write_queue_size
* right before making the callback. The reason we don't do that right away
* is that a write_queue_size > 0 is our only way to signal to the user that
- * he should stop writing - which he should if we got an error. Something to
- * revisit in future revisions of the libuv API.
+ * they should stop writing - which they should if we got an error. Something
+ * to revisit in future revisions of the libuv API.
*/
if (req->error == 0) {
if (req->bufs != req->bufsml)
}
+void uv_try_write_cb(uv_write_t* req, int status) {
+ /* Should not be called */
+ abort();
+}
+
+
+int uv_try_write(uv_stream_t* stream, const char* buf, size_t size) {
+ int r;
+ int has_pollout;
+ size_t written;
+ size_t req_size;
+ uv_write_t req;
+ uv_buf_t bufstruct;
+
+ /* Connecting or already writing some data */
+ if (stream->connect_req != NULL || stream->write_queue_size != 0)
+ return 0;
+
+ has_pollout = uv__io_active(&stream->io_watcher, UV__POLLOUT);
+
+ bufstruct = uv_buf_init((char*) buf, size);
+ r = uv_write(&req, stream, &bufstruct, 1, uv_try_write_cb);
+ if (r != 0)
+ return r;
+
+ /* Remove not written bytes from write queue size */
+ written = size;
+ if (req.bufs != NULL)
+ req_size = uv__write_req_size(&req);
+ else
+ req_size = 0;
+ written -= req_size;
+ stream->write_queue_size -= req_size;
+
+ /* Unqueue request, regardless of immediateness */
+ QUEUE_REMOVE(&req.queue);
+ uv__req_unregister(stream->loop, &req);
+ if (req.bufs != req.bufsml)
+ free(req.bufs);
+ req.bufs = NULL;
+
+ /* Do not poll for writable, if we wasn't before calling this */
+ if (!has_pollout)
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
+
+ return (int) written;
+}
+
+
static int uv__read_start_common(uv_stream_t* stream,
uv_alloc_cb alloc_cb,
uv_read_cb read_cb,
memset(addr, 0, sizeof(*addr));
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
- /* TODO(bnoordhuis) Don't use inet_addr(), no good way to detect errors. */
- addr->sin_addr.s_addr = inet_addr(ip);
- return 0;
+ return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr));
}
}
#endif
- /* TODO(bnoordhuis) Return an error when the address is bad. */
- uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
-
- return 0;
+ return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
}
#if defined(EAI_BADFLAGS)
case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
#endif
+#if defined(EAI_BADHINTS)
+ case EAI_BADHINTS: return UV_EAI_BADHINTS;
+#endif
#if defined(EAI_CANCELED)
case EAI_CANCELED: return UV_EAI_CANCELED;
#endif
case EAI_NONAME: return UV_EAI_NONAME;
# endif
#endif
+#if defined(EAI_OVERFLOW)
+ case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
+#endif
+#if defined(EAI_PROTOCOL)
+ case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
+#endif
#if defined(EAI_SERVICE)
case EAI_SERVICE: return UV_EAI_SERVICE;
#endif
#define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 11
-#define UV_VERSION_PATCH 15
-#define UV_VERSION_IS_RELEASE 1
+#define UV_VERSION_PATCH 17
+#define UV_VERSION_IS_RELEASE 0
#define UV_VERSION ((UV_VERSION_MAJOR << 16) | \
poll = &uv_poll;
r = uv__loop_alive(loop);
+ if (!r)
+ uv_update_time(loop);
+
while (r != 0 && loop->stop_flag == 0) {
uv_update_time(loop);
uv_process_timers(loop);
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
- _snwprintf(filenamew, size, L"%s\\%s", handle->dirw,
+ _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
+ file_info->FileNameLength / sizeof(WCHAR),
file_info->FileName);
filenamew[size - 1] = L'\0';
err = uv_utf8_to_utf16_alloc(options->file, &application);
if (err)
- goto immediate_failure;
+ goto done;
err = make_program_args(
options->args,
options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
&arguments);
if (err)
- goto immediate_failure;
+ goto done;
if (options->env) {
err = make_program_env(options->env, &env);
if (err)
- goto immediate_failure;
+ goto done;
}
if (options->cwd) {
/* Explicit cwd */
err = uv_utf8_to_utf16_alloc(options->cwd, &cwd);
if (err)
- goto immediate_failure;
+ goto done;
} else {
/* Inherit cwd */
cwd_len = GetCurrentDirectoryW(0, NULL);
if (!cwd_len) {
err = GetLastError();
- goto immediate_failure;
+ goto done;
}
cwd = (WCHAR*) malloc(cwd_len * sizeof(WCHAR));
if (cwd == NULL) {
err = ERROR_OUTOFMEMORY;
- goto immediate_failure;
+ goto done;
}
r = GetCurrentDirectoryW(cwd_len, cwd);
if (r == 0 || r >= cwd_len) {
err = GetLastError();
- goto immediate_failure;
+ goto done;
}
}
path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
if (path_len == 0) {
err = GetLastError();
- goto immediate_failure;
+ goto done;
}
path = (WCHAR*) malloc(path_len * sizeof(WCHAR));
if (path == NULL) {
err = ERROR_OUTOFMEMORY;
- goto immediate_failure;
+ goto done;
}
r = GetEnvironmentVariableW(L"PATH", path, path_len);
if (r == 0 || r >= path_len) {
err = GetLastError();
- goto immediate_failure;
+ goto done;
}
}
err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
if (err)
- goto immediate_failure;
-
- /* Beyond this point, failure is reported asynchronously. */
+ goto done;
application_path = search_path(application,
cwd,
if (application_path == NULL) {
/* Not found. */
err = ERROR_FILE_NOT_FOUND;
- goto success_or_async_failure;
+ goto done;
}
startup.cb = sizeof(startup);
process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
}
- if (CreateProcessW(application_path,
+ if (!CreateProcessW(application_path,
arguments,
NULL,
NULL,
cwd,
&startup,
&info)) {
- /* Spawn succeeded */
- process->process_handle = info.hProcess;
- process->pid = info.dwProcessId;
-
- /* If the process isn't spawned as detached, assign to the global job */
- /* object so windows will kill it when the parent process dies. */
- if (!(options->flags & UV_PROCESS_DETACHED)) {
- uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
-
- if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
- /* AssignProcessToJobObject might fail if this process is under job
- * control and the job doesn't have the
- * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version
- * that doesn't support nested jobs.
- *
- * When that happens we just swallow the error and continue without
- * establishing a kill-child-on-parent-exit relationship, otherwise
- * there would be no way for libuv applications run under job control
- * to spawn processes at all.
- */
- DWORD err = GetLastError();
- if (err != ERROR_ACCESS_DENIED)
- uv_fatal_error(err, "AssignProcessToJobObject");
- }
- }
+ /* CreateProcessW failed. */
+ err = GetLastError();
+ goto done;
+ }
- /* Set IPC pid to all IPC pipes. */
- for (i = 0; i < options->stdio_count; i++) {
- const uv_stdio_container_t* fdopt = &options->stdio[i];
- if (fdopt->flags & UV_CREATE_PIPE &&
- fdopt->data.stream->type == UV_NAMED_PIPE &&
- ((uv_pipe_t*) fdopt->data.stream)->ipc) {
- ((uv_pipe_t*) fdopt->data.stream)->ipc_pid = info.dwProcessId;
- }
+ /* Spawn succeeded */
+ /* Beyond this point, failure is reported asynchronously. */
+
+ process->process_handle = info.hProcess;
+ process->pid = info.dwProcessId;
+
+ /* If the process isn't spawned as detached, assign to the global job */
+ /* object so windows will kill it when the parent process dies. */
+ if (!(options->flags & UV_PROCESS_DETACHED)) {
+ uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
+
+ if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
+ /* AssignProcessToJobObject might fail if this process is under job
+ * control and the job doesn't have the
+ * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version
+ * that doesn't support nested jobs.
+ *
+ * When that happens we just swallow the error and continue without
+ * establishing a kill-child-on-parent-exit relationship, otherwise
+ * there would be no way for libuv applications run under job control
+ * to spawn processes at all.
+ */
+ DWORD err = GetLastError();
+ if (err != ERROR_ACCESS_DENIED)
+ uv_fatal_error(err, "AssignProcessToJobObject");
}
+ }
- /* Setup notifications for when the child process exits. */
- result = RegisterWaitForSingleObject(&process->wait_handle,
- process->process_handle, exit_wait_callback, (void*)process, INFINITE,
- WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
- if (!result) {
- uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
+ /* Set IPC pid to all IPC pipes. */
+ for (i = 0; i < options->stdio_count; i++) {
+ const uv_stdio_container_t* fdopt = &options->stdio[i];
+ if (fdopt->flags & UV_CREATE_PIPE &&
+ fdopt->data.stream->type == UV_NAMED_PIPE &&
+ ((uv_pipe_t*) fdopt->data.stream)->ipc) {
+ ((uv_pipe_t*) fdopt->data.stream)->ipc_pid = info.dwProcessId;
}
+ }
- CloseHandle(info.hThread);
-
- } else {
- /* CreateProcessW failed. */
- err = GetLastError();
+ /* Setup notifications for when the child process exits. */
+ result = RegisterWaitForSingleObject(&process->wait_handle,
+ process->process_handle, exit_wait_callback, (void*)process, INFINITE,
+ WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
+ if (!result) {
+ uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
}
- /* We get here if we successfully created a process, or when we */
- /* encountered failure that we want to report asynchronously. */
- success_or_async_failure:
+ CloseHandle(info.hThread);
+
+ assert(!err);
+
+ /* Make the handle active. It will remain active until the exit callback */
+ /* iis made or the handle is closed, whichever happens first. */
+ uv__handle_start(process);
+
+ /* Cleanup, whether we succeeded or failed. */
+ done:
free(application);
free(application_path);
free(arguments);
process->child_stdio_buffer = NULL;
}
- /* Make the handle active, but only if an error didn't happen. It will */
- /* remain active until the exit callback is made or the handle is closed, */
- /* whichever happens first. */
- if (err == 0) {
- uv__handle_start(process);
- }
-
- return err;
-
- /* This code path is taken when we run into an error that we want to */
- /* report immediately. */
- immediate_failure:
- free(application);
- free(application_path);
- free(arguments);
- free(cwd);
- free(env);
- free(path);
-
- assert(process->child_stdio_buffer == NULL);
-
return uv_translate_sys_error(err);
}
}
+int uv_try_write(uv_stream_t* handle, const char* buf, size_t length) {
+ /* NOTE: Won't work with overlapped writes */
+ return UV_ENOSYS;
+}
+
+
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
uv_loop_t* loop = handle->loop;
static char *process_title;
static CRITICAL_SECTION process_title_lock;
-/* The tick frequency of the high-resolution clock. */
-static uint64_t hrtime_frequency_ = 0;
+/* Frequency (ticks per nanosecond) of the high-resolution clock. */
+static double hrtime_frequency_ = 0;
/*
* One-time intialization code for functionality defined in util.c.
*/
void uv__util_init() {
+ LARGE_INTEGER perf_frequency;
+
/* Initialize process title access mutex. */
InitializeCriticalSection(&process_title_lock);
/* Retrieve high-resolution timer frequency. */
- if (!QueryPerformanceFrequency((LARGE_INTEGER*) &hrtime_frequency_))
- hrtime_frequency_ = 0;
+ if (QueryPerformanceFrequency(&perf_frequency))
+ hrtime_frequency_ = (double) perf_frequency.QuadPart / (double) NANOSEC;
+ else
+ hrtime_frequency_= 0;
}
uv__once_init();
/* If the performance frequency is zero, there's no support. */
- if (!hrtime_frequency_) {
+ if (hrtime_frequency_ == 0) {
/* uv__set_sys_error(loop, ERROR_NOT_SUPPORTED); */
return 0;
}
return 0;
}
- /* Because we have no guarantee about the order of magnitude of the */
- /* performance counter frequency, and there may not be much headroom to */
- /* multiply by NANOSEC without overflowing, we use 128-bit math instead. */
- return ((uint64_t) counter.LowPart * NANOSEC / hrtime_frequency_) +
- (((uint64_t) counter.HighPart * NANOSEC / hrtime_frequency_)
- << 32);
+ /* Because we have no guarantee about the order of magnitude of the
+ * performance counter frequency, integer math could cause this computation
+ * to overflow. Therefore we resort to floating point math.
+ */
+ return (uint64_t) ((double) counter.QuadPart / hrtime_frequency_);
}
--- /dev/null
+/* 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.
+ */
+
+#if !defined(_WIN32)
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+static void connection_cb(uv_stream_t* server_handle, int status);
+static void connect_cb(uv_connect_t* req, int status);
+
+static const int maxfd = 31;
+static unsigned connect_cb_called;
+static uv_tcp_t server_handle;
+static uv_tcp_t client_handle;
+
+
+TEST_IMPL(emfile) {
+ struct sockaddr_in addr;
+ struct rlimit limits;
+ uv_connect_t connect_req;
+ uv_loop_t* loop;
+ int first_fd;
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(0 == uv_tcp_init(loop, &server_handle));
+ ASSERT(0 == uv_tcp_init(loop, &client_handle));
+ ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr));
+ ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 8, connection_cb));
+
+ /* Lower the file descriptor limit and use up all fds save one. */
+ limits.rlim_cur = limits.rlim_max = maxfd + 1;
+ if (setrlimit(RLIMIT_NOFILE, &limits)) {
+ perror("setrlimit(RLIMIT_NOFILE)");
+ ASSERT(0);
+ }
+
+ /* Remember the first one so we can clean up afterwards. */
+ do
+ first_fd = dup(0);
+ while (first_fd == -1 && errno == EINTR);
+ ASSERT(first_fd > 0);
+
+ while (dup(0) != -1 || errno == EINTR);
+ ASSERT(errno == EMFILE);
+ close(maxfd);
+
+ /* Now connect and use up the last available file descriptor. The EMFILE
+ * handling logic in src/unix/stream.c should ensure that connect_cb() runs
+ * whereas connection_cb() should *not* run.
+ */
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &client_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == connect_cb_called);
+
+ /* Close the dups again. Ignore errors in the unlikely event that the
+ * file descriptors were not contiguous.
+ */
+ while (first_fd < maxfd) {
+ close(first_fd);
+ first_fd += 1;
+ }
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void connection_cb(uv_stream_t* server_handle, int status) {
+ ASSERT(0 && "connection_cb should not be called.");
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ /* |status| should equal 0 because the connection should have been accepted,
+ * it's just that the server immediately closes it again.
+ */
+ ASSERT(0 == status);
+ connect_cb_called += 1;
+ uv_close((uv_handle_t*) &server_handle, NULL);
+ uv_close((uv_handle_t*) &client_handle, NULL);
+}
+
+#endif /* !defined(_WIN32) */
--- /dev/null
+/* 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 "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <string.h>
+
+
+TEST_IMPL(ip4_addr) {
+
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(0 == uv_ip4_addr("255.255.255.255", TEST_PORT, &addr));
+ ASSERT(UV_EINVAL == uv_ip4_addr("255.255.255*000", TEST_PORT, &addr));
+ ASSERT(UV_EINVAL == uv_ip4_addr("255.255.255.256", TEST_PORT, &addr));
+ ASSERT(UV_EINVAL == uv_ip4_addr("2555.0.0.0", TEST_PORT, &addr));
+ ASSERT(UV_EINVAL == uv_ip4_addr("255", TEST_PORT, &addr));
+
+ // for broken address family
+ ASSERT(UV_EAFNOSUPPORT == uv_inet_pton(42, "127.0.0.1",
+ &addr.sin_addr.s_addr));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
TEST_DECLARE (run_once)
TEST_DECLARE (run_nowait)
TEST_DECLARE (loop_stop)
+TEST_DECLARE (loop_update_time)
TEST_DECLARE (barrier_1)
TEST_DECLARE (barrier_2)
TEST_DECLARE (barrier_3)
TEST_DECLARE (delayed_accept)
TEST_DECLARE (multiple_listen)
TEST_DECLARE (tcp_writealot)
+TEST_DECLARE (tcp_try_write)
TEST_DECLARE (tcp_open)
TEST_DECLARE (tcp_connect_error_after_write)
TEST_DECLARE (tcp_shutdown_after_write)
TEST_DECLARE (poll_duplex)
TEST_DECLARE (poll_unidirectional)
TEST_DECLARE (poll_close)
+TEST_DECLARE (ip4_addr)
TEST_DECLARE (ip6_addr_link_local)
#ifdef _WIN32
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
TEST_DECLARE (listen_no_simultaneous_accepts)
TEST_DECLARE (fs_stat_root)
#else
+TEST_DECLARE (emfile)
TEST_DECLARE (close_fd)
TEST_DECLARE (spawn_setuid_setgid)
TEST_DECLARE (we_get_signal)
TEST_ENTRY (run_once)
TEST_ENTRY (run_nowait)
TEST_ENTRY (loop_stop)
+ TEST_ENTRY (loop_update_time)
TEST_ENTRY (barrier_1)
TEST_ENTRY (barrier_2)
TEST_ENTRY (barrier_3)
TEST_ENTRY (tcp_writealot)
TEST_HELPER (tcp_writealot, tcp4_echo_server)
+ TEST_ENTRY (tcp_try_write)
+
TEST_ENTRY (tcp_open)
TEST_HELPER (tcp_open, tcp4_echo_server)
TEST_ENTRY (listen_no_simultaneous_accepts)
TEST_ENTRY (fs_stat_root)
#else
+ TEST_ENTRY (emfile)
TEST_ENTRY (close_fd)
TEST_ENTRY (spawn_setuid_setgid)
TEST_ENTRY (we_get_signal)
TEST_ENTRY (thread_rwlock)
TEST_ENTRY (thread_create)
TEST_ENTRY (dlerror)
+ TEST_ENTRY (ip4_addr)
TEST_ENTRY (ip6_addr_link_local)
#if 0
/* These are for testing the test runner. */
--- /dev/null
+/* 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 "uv.h"
+#include "task.h"
+
+
+TEST_IMPL(loop_update_time) {
+ uint64_t start;
+
+ start = uv_now(uv_default_loop());
+ while (uv_now(uv_default_loop()) - start < 1000)
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT));
+
+ return 0;
+}
--- /dev/null
+/* 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 "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAX_BYTES 1024 * 1024
+
+#ifdef _WIN32
+
+TEST_IMPL(tcp_try_write) {
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#else /* !_WIN32 */
+
+static uv_tcp_t server;
+static uv_tcp_t client;
+static uv_tcp_t incoming;
+static int connect_cb_called;
+static int close_cb_called;
+static int connection_cb_called;
+static int bytes_read;
+static int bytes_written;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ static char zeroes[1024];
+ int r;
+ uv_buf_t buf;
+ ASSERT(status == 0);
+ connect_cb_called++;
+
+ do {
+ r = uv_try_write((uv_stream_t*) &client, zeroes, sizeof(zeroes));
+ ASSERT(r >= 0);
+ bytes_written += r;
+
+ /* Partial write */
+ if (r != (int) sizeof(zeroes))
+ break;
+ } while (1);
+ uv_close((uv_handle_t*) &client, close_cb);
+}
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ static char base[1024];
+
+ buf->base = base;
+ buf->len = sizeof(base);
+}
+
+
+static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ if (nread < 0) {
+ uv_close((uv_handle_t*) tcp, close_cb);
+ uv_close((uv_handle_t*) &server, close_cb);
+ return;
+ }
+
+ bytes_read += nread;
+}
+
+
+static void connection_cb(uv_stream_t* tcp, int status) {
+ ASSERT(status == 0);
+
+ ASSERT(0 == uv_tcp_init(tcp->loop, &incoming));
+ ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming));
+
+ connection_cb_called++;
+ ASSERT(0 == uv_read_start((uv_stream_t*) &incoming, alloc_cb, read_cb));
+}
+
+
+static void start_server(void) {
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));
+ ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr));
+ ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb));
+}
+
+
+TEST_IMPL(tcp_try_write) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+
+ start_server();
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &client));
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &client,
+ (struct sockaddr*) &addr,
+ connect_cb));
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(close_cb_called == 3);
+ ASSERT(connection_cb_called == 1);
+ ASSERT(bytes_read == bytes_written);
+ ASSERT(bytes_written > 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* !_WIN32 */
'test/test-delayed-accept.c',
'test/test-error.c',
'test/test-embed.c',
+ 'test/test-emfile.c',
'test/test-fail-always.c',
'test/test-fs.c',
'test/test-fs-event.c',
'test/test-list.h',
'test/test-loop-handles.c',
'test/test-loop-stop.c',
+ 'test/test-loop-time.c',
'test/test-walk-handles.c',
'test/test-watcher-cross-stop.c',
'test/test-multiple-listen.c',
'test/test-tcp-open.c',
'test/test-tcp-write-to-half-open-connection.c',
'test/test-tcp-writealot.c',
+ 'test/test-tcp-try-write.c',
'test/test-tcp-unexpected-read.c',
'test/test-tcp-read-stop.c',
'test/test-threadpool.c',
'test/test-udp-multicast-join.c',
'test/test-dlerror.c',
'test/test-udp-multicast-ttl.c',
+ 'test/test-ip4-addr.c',
'test/test-ip6-addr.c',
],
'conditions': [