Commit 8ca9128a authored by Jason Madden's avatar Jason Madden

update libuv to 1.9

parent 12dd4d9e
......@@ -16,9 +16,11 @@ vgcore.*
/ar-lib
/autom4te.cache/
/compile
/config.guess
/config.log
/config.status
/config.sub
/configure
/depcomp
/install-sh
/libtool
......
......@@ -240,3 +240,16 @@ Yuval Brik <yuval@brik.org.il>
Joran Dirk Greef <joran@ronomon.com>
Andrey Mazo <andrey.mazo@fidelissecurity.com>
sztomi <hello.sztomi@gmail.com>
Martin Bark <martin@barkynet.com>
Dave <dave@jut.io>
Alexis Murzeau <amubtdx@gmail.com>
Didiet <lynxluna@gmail.com>
Nan Xiang <514580344@qq.com>
Samuel Lorétan <sloretan@riotgames.com>
Nándor István Krácser <bonifaido@gmail.com>
Katsutoshi Horie <mps299792458@gmail.com>
Lukasz Jagiello <lukasz@wikia-inc.com>
Robert Chiras <robert.chiras@intel.com>
Kári Tristan Helgason <kthelgason@gmail.com>
Krishnaraj Bhat <krrishnarraj@gmail.com>
Enno Boland <g@s01.de>
......@@ -23,8 +23,7 @@ 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][].
to the [libuv mailing list], or contact one of [project maintainers][] 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
......@@ -138,7 +137,10 @@ $ git rebase upstream/v1.x # 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`.
`test/` directory. Each new test needs to be registered in `test/test-list.h`. If you add a new test file, it needs to be registered in two places:
- `Makefile.am`: add the file's name to the `test_run_tests_SOURCES` list.
- `uv.gyp`: add the file's name to the `sources` list in the `run-tests` target.
Look at other tests to see how they should be structured (license boilerplate,
the way entry points are declared, etc.).
......@@ -164,3 +166,4 @@ not send out notifications when you add commits.
[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
[project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md
2015.12.15, Version 1.8.0 (Stable)
2016.04.08, Version 1.9.0 (Stable)
Changes since version 1.8.0:
* win: wait for full timeout duration (João Reis)
* unix: fix support for uClibc-ng (Martin Bark)
* doc: indicate where new test files need to be added (Dave)
* test,unix: fix logic error in test runner (Ben Noordhuis)
* fs: don't nullify req->bufs on EINTR (Dave)
* osx: set the default thread stack size to RLIMIT_STACK (Saúl Ibarra Corretgé)
* build: invoke libtoolize with --copy (Ben Noordhuis)
* test: fixup eintr_handling (Saúl Ibarra Corretgé)
* osx: avoid compilation warning with Clang (Saúl Ibarra Corretgé)
* test,win: fix compilation with shared lib (Alexis Murzeau)
* test: fix race condition in pipe-close-stdout (Imran Iqbal)
* unix,win: add uv_os_tmpdir() (cjihrig)
* ios: fix undefined PTHREAD_STACK_MIN (Didiet)
* test: fix threadpool_multiple_event_loops for AIX (Imran Iqbal)
* unix: report errors for unpollable fds (Ben Noordhuis)
* win: fix watching root files (Nicholas Vavilov)
* build,win: print the Visual Studio version in use (Saúl Ibarra Corretgé)
* build,win: remove unneeded condition from GYP file (Saúl Ibarra Corretgé)
* test,win: fix compilation warning (Saúl Ibarra Corretgé)
* test: use uv_loop_close and assert its result (Nan Xiang)
* build: map 'AMD64' host arch to 'x64' (Ben Noordhuis)
* osx: protected use of potentially undefined macro (Samuel Lorétan)
* linux: fix compilation with musl (Saúl Ibarra Corretgé)
* doc: describe how to make release builds on Unix (Saúl Ibarra Corretgé)
* doc: add missing link in README (Saúl Ibarra Corretgé)
* build: python 2.x/3.x consistent print usage (Rasmus Christian Pedersen)
* test: assume no IPv6 if interfaces cannot be listed (Nan Xiang)
* darwin: replace F_FULLFSYNC with fdatasync syscall (Saúl Ibarra Corretgé)
* doc: add missing write callback to example (Nándor István Krácser)
* build: compile with -D_THREAD_SAFE on AIX (Imran Iqbal)
* test: fix threadpool_multiple_event_loops on PPC (Imran Iqbal)
* test: reduce timeout in tcp_close_while_connecting (Imran Iqbal)
* unix, win: consistently null-terminate buffers (Saúl Ibarra Corretgé)
* unix, win: count null byte on UV_ENOBUFS (Saúl Ibarra Corretgé)
* test: fix deadlocks in uv_cond_wait (Katsutoshi Horie)
* linux: fix cpu count (Lukasz Jagiello)
* unix: fix uv__handle_type for AIX (Imran Iqbal)
* linux: call fclose(), fix fdopen() memory leak (Ben Noordhuis)
* win: remove unneeded condition (Saúl Ibarra Corretgé)
* unix: fix compile error in Android using bionic (Robert Chiras)
* linux: add braces to multi-statement if (Kári Tristan Helgason)
* doc: add @cjihrig as a maintainer (Saúl Ibarra Corretgé)
* unix: add fork-safe open file function (Kári Tristan Helgason)
* linux: replace calls to fopen with uv__open_file (Kári Tristan Helgason)
* linux: remove redundant call to rewind() (Krishnaraj Bhat)
* win: remove duplicated code when processing fsevents (Saúl Ibarra Corretgé)
* test: fix poll_bad_fdtype for AIX (Imran Iqbal)
* linux: fix error checking in uv__open_file (Saúl Ibarra Corretgé)
* poll: add UV_DISCONNECT event (Santiago Gimeno)
* fs: realpath: fix string size before converting (Yuval Brik)
* win: use native APIs for UTF conversions (cjihrig)
* doc: clarify uv_loop_close() (Ben Noordhuis)
* unix: retry ioctl(TIOCGWINSZ) on EINTR (Ben Noordhuis)
* win,build: remove unused build defines (Saúl Ibarra Corretgé)
* win: fix buffer overflow in fs events (Joran Dirk Greef)
* win: fix uv_relative_path and remove dead branch (Joran Dirk Greef)
* unix: use open(2) with O_CLOEXEC on OS X (Kári Tristan Helgason)
* test: add missing copyright header (cjihrig)
* aix: fix 'POLLRDHUP undeclared' build error (Ben Noordhuis)
* unix,win: add uv_get_passwd() (cjihrig)
* process: fix uv_spawn edge-case (Santiago Gimeno)
* test: use %ld for printing uid/gid (Ben Noordhuis)
* aix: fix ahafs implementation (Imran Iqbal)
* aix: do not store absolute path to ahafs (Imran Iqbal)
* process: close process pipes safely (Santiago Gimeno)
* unix: open ttyname instead of /dev/tty (Enno Boland)
* unix: remove outdated comment (Kári Tristan Helgason)
2015.12.15, Version 1.8.0 (Stable), 5467299450ecf61635657557b6e01aaaf6c3fdf4
Changes since version 1.7.5:
......
We distribute libuv with configure already created, by autogen.sh
^^^
XXX: We would like to do that, but it is going to take some tinkering
to make that work.
Do not remove the test/ directory; the windows build depends on it
being in place. Sigh.
......@@ -6,6 +6,7 @@ libuv is currently managed by the following individuals:
* **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis))
- GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis)
* **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus))
* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig))
* **Fedor Indutny** ([@indutny](https://github.com/indutny))
- GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny)
* **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul))
......
......@@ -43,7 +43,6 @@ if WINNT
include_HEADERS += include/uv-win.h include/tree.h
AM_CPPFLAGS += -I$(top_srcdir)/src/win \
-DWIN32_LEAN_AND_MEAN \
-D_WIN32_WINNT=0x0600
LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv
libuv_la_SOURCES += src/win/async.c \
......@@ -130,6 +129,7 @@ EXTRA_DIST = test/fixtures/empty_file \
TESTS = test/run-tests
check_PROGRAMS = test/run-tests
test_run_tests_CFLAGS =
test_run_tests_LDFLAGS =
test_run_tests_SOURCES = test/blackhole-server.c \
test/dns-server.c \
test/echo-server.c \
......@@ -151,6 +151,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-default-loop-close.c \
test/test-delayed-accept.c \
test/test-dlerror.c \
test/test-eintr-handling.c \
test/test-embed.c \
test/test-emfile.c \
test/test-error.c \
......@@ -161,6 +162,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-get-currentexe.c \
test/test-get-loadavg.c \
test/test-get-memory.c \
test/test-get-passwd.c \
test/test-getaddrinfo.c \
test/test-getnameinfo.c \
test/test-getsockname.c \
......@@ -242,6 +244,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-timer-again.c \
test/test-timer-from-check.c \
test/test-timer.c \
test/test-tmpdir.c \
test/test-tty.c \
test/test-udp-bind.c \
test/test-udp-create-socket-early.c \
......@@ -280,7 +283,7 @@ endif
if AIX
libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT
libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT -D_THREAD_SAFE
include_HEADERS += include/uv-aix.h
libuv_la_SOURCES += src/unix/aix.c
endif
......@@ -301,15 +304,18 @@ libuv_la_SOURCES += src/unix/darwin.c \
src/unix/fsevents.c \
src/unix/kqueue.c \
src/unix/proctitle.c
test_run_tests_LDFLAGS += -lutil
endif
if DRAGONFLY
include_HEADERS += include/uv-bsd.h
test_run_tests_LDFLAGS += -lutil
endif
if FREEBSD
include_HEADERS += include/uv-bsd.h
libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c
test_run_tests_LDFLAGS += -lutil
endif
if LINUX
......@@ -320,16 +326,19 @@ libuv_la_SOURCES += src/unix/linux-core.c \
src/unix/linux-syscalls.c \
src/unix/linux-syscalls.h \
src/unix/proctitle.c
test_run_tests_LDFLAGS += -lutil
endif
if NETBSD
include_HEADERS += include/uv-bsd.h
libuv_la_SOURCES += src/unix/kqueue.c src/unix/netbsd.c
test_run_tests_LDFLAGS += -lutil
endif
if OPENBSD
include_HEADERS += include/uv-bsd.h
libuv_la_SOURCES += src/unix/kqueue.c src/unix/openbsd.c
test_run_tests_LDFLAGS += -lutil
endif
if SUNOS
......
......@@ -20,7 +20,6 @@ CFLAGS += -Wall \
-Iinclude \
-Isrc \
-Isrc/win \
-DWIN32_LEAN_AND_MEAN \
-D_WIN32_WINNT=0x0600
INCLUDES = include/stdint-msvc2008.h \
......
......@@ -156,11 +156,16 @@ project tree manually:
### Unix
Run:
For Debug builds (recommended) run:
$ ./gyp_uv.py -f make
$ make -C out
For Release builds run:
$ ./gyp_uv.py -f make
$ BUILDTYPE=Release make -C out
Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries.
### OS X
......@@ -243,3 +248,4 @@ See the [guidelines for contributing][].
[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
[guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md
[libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png
[x32]: https://en.wikipedia.org/wiki/X32_ABI
version: v1.8.0.build{build}
version: v1.9.0.build{build}
install:
- cinst -y nsis
......
......@@ -40,7 +40,7 @@ echo "m4_define([UV_EXTRA_AUTOMAKE_FLAGS], [$UV_EXTRA_AUTOMAKE_FLAGS])" \
> m4/libuv-extra-automake-flags.m4
set -ex
"$LIBTOOLIZE"
"$LIBTOOLIZE" --copy
"$ACLOCAL" -I m4
"$AUTOCONF"
"$AUTOMAKE" --add-missing --copy
......@@ -101,6 +101,7 @@ test/test-fs.c
test/test-get-currentexe.c
test/test-get-loadavg.c
test/test-get-memory.c
test/test-get-passwd.c
test/test-getaddrinfo.c
test/test-getsockname.c
test/test-homedir.c
......@@ -155,6 +156,7 @@ test/test-threadpool-cancel.c
test/test-threadpool.c
test/test-timer-again.c
test/test-timer.c
test/test-tmpdir.c
test/test-tty.c
test/test-udp-dgram-too-big.c
test/test-udp-ipv6.c
......
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for libuv 1.8.0.
# Generated by GNU Autoconf 2.69 for libuv 1.9.0.
#
# Report bugs to <https://github.com/libuv/libuv/issues>.
#
......@@ -587,8 +587,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='libuv'
PACKAGE_TARNAME='libuv'
PACKAGE_VERSION='1.8.0'
PACKAGE_STRING='libuv 1.8.0'
PACKAGE_VERSION='1.9.0'
PACKAGE_STRING='libuv 1.9.0'
PACKAGE_BUGREPORT='https://github.com/libuv/libuv/issues'
PACKAGE_URL=''
......@@ -1333,7 +1333,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures libuv 1.8.0 to adapt to many kinds of systems.
\`configure' configures libuv 1.9.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
......@@ -1403,7 +1403,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of libuv 1.8.0:";;
short | recursive ) echo "Configuration of libuv 1.9.0:";;
esac
cat <<\_ACEOF
......@@ -1514,7 +1514,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
libuv configure 1.8.0
libuv configure 1.9.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
......@@ -1883,7 +1883,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by libuv $as_me 1.8.0, which was
It was created by libuv $as_me 1.9.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
......@@ -2810,7 +2810,7 @@ fi
# Define the identity of the package.
PACKAGE='libuv'
VERSION='1.8.0'
VERSION='1.9.0'
cat >>confdefs.h <<_ACEOF
......@@ -13923,7 +13923,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by libuv $as_me 1.8.0, which was
This file was extended by libuv $as_me 1.9.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
......@@ -13980,7 +13980,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
libuv config.status 1.8.0
libuv config.status 1.9.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
......
......@@ -13,7 +13,7 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_PREREQ(2.57)
AC_INIT([libuv], [1.8.0], [https://github.com/libuv/libuv/issues])
AC_INIT([libuv], [1.9.0], [https://github.com/libuv/libuv/issues])
AC_CONFIG_MACRO_DIR([m4])
m4_include([m4/libuv-extra-automake-flags.m4])
m4_include([m4/as_case.m4])
......
......@@ -71,9 +71,10 @@ API
.. c:function:: int uv_loop_close(uv_loop_t* loop)
Closes all internal loop resources. This function must only be called once
the loop has finished its execution or it will return UV_EBUSY. After this
function returns the user shall free the memory allocated for the loop.
Releases all internal loop resources. Call this function only when the loop
has finished executing and all open handles and requests have been closed,
or it will return UV_EBUSY. After this function returns, the user can free
the memory allocated for the loop.
.. c:function:: uv_loop_t* uv_default_loop(void)
......
......@@ -122,6 +122,20 @@ Data types
} netmask;
} uv_interface_address_t;
.. c:type:: uv_passwd_t
Data type for password file information.
::
typedef struct uv_passwd_s {
char* username;
long uid;
long gid;
char* shell;
char* homedir;
} uv_passwd_t;
API
---
......@@ -265,14 +279,50 @@ API
`uv_os_homedir()` first checks the `HOME` environment variable using
:man:`getenv(3)`. If `HOME` is not set, :man:`getpwuid_r(3)` is called. The
user's home directory is stored in `buffer`. When `uv_os_homedir()` is
called, `size` indicates the maximum size of `buffer`. On success or
`UV_ENOBUFS` failure, `size` is set to the string length of `buffer`.
called, `size` indicates the maximum size of `buffer`. On success `size` is set
to the string length of `buffer`. On `UV_ENOBUFS` failure `size` is set to the
required length for `buffer`, including the null byte.
.. warning::
`uv_os_homedir()` is not thread safe.
.. versionadded:: 1.6.0
.. c:function:: int uv_os_tmpdir(char* buffer, size_t* size)
Gets the temp directory. On Windows, `uv_os_tmpdir()` uses `GetTempPathW()`.
On all other operating systems, `uv_os_tmpdir()` uses the first environment
variable found in the ordered list `TMPDIR`, `TMP`, `TEMP`, and `TEMPDIR`.
If none of these are found, the path `"/tmp"` is used, or, on Android,
`"/data/local/tmp"` is used. The temp directory is stored in `buffer`. When
`uv_os_tmpdir()` is called, `size` indicates the maximum size of `buffer`.
On success `size` is set to the string length of `buffer` (which does not
include the terminating null). On `UV_ENOBUFS` failure `size` is set to the
required length for `buffer`, including the null byte.
.. warning::
`uv_os_tmpdir()` is not thread safe.
.. versionadded:: 1.9.0
.. c:function:: int uv_os_get_passwd(uv_passwd_t* pwd)
Gets a subset of the password file entry for the current effective uid (not
the real uid). The populated data includes the username, euid, gid, shell,
and home directory. On non-Windows systems, all data comes from
:man:`getpwuid_r(3)`. On Windows, uid and gid are set to -1 and have no
meaning, and shell is `NULL`. After successfully calling this function, the
memory allocated to `pwd` needs to be freed with
:c:func:`uv_os_free_passwd`.
.. versionadded:: 1.9.0
.. c:function:: void uv_os_free_passwd(uv_passwd_t* pwd)
Frees the `pwd` memory previously allocated with :c:func:`uv_os_get_passwd`.
.. versionadded:: 1.9.0
.. uint64_t uv_get_free_memory(void)
.. c:function:: uint64_t uv_get_total_memory(void)
......
......@@ -4,8 +4,8 @@
:c:type:`uv_poll_t` --- Poll handle
===================================
Poll handles are used to watch file descriptors for readability and
writability, similar to the purpose of :man:`poll(2)`.
Poll handles are used to watch file descriptors for readability,
writability and disconnection similar to the purpose of :man:`poll(2)`.
The purpose of poll handles is to enable integrating external libraries that
rely on the event loop to signal it about the socket status changes, like
......@@ -51,7 +51,8 @@ Data types
enum uv_poll_event {
UV_READABLE = 1,
UV_WRITABLE = 2
UV_WRITABLE = 2,
UV_DISCONNECT = 4
};
......@@ -82,10 +83,14 @@ API
.. c:function:: int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb)
Starts polling the file descriptor. `events` is a bitmask consisting made up
of UV_READABLE and UV_WRITABLE. As soon as an event is detected the callback
will be called with `status` set to 0, and the detected events set on the
of UV_READABLE, UV_WRITABLE and UV_DISCONNECT. As soon as an event is detected
the callback will be called with `status` set to 0, and the detected events set on the
`events` field.
The UV_DISCONNECT event is optional in the sense that it may not be
reported and the user is free to ignore it, but it can help optimize the shutdown
path because an extra read or write call might be avoided.
If an error happens while polling, `status` will be < 0 and corresponds
with one of the UV_E* error codes (see :ref:`errors`). The user should
not close the socket while the handle is active. If the user does that
......@@ -96,6 +101,8 @@ API
Calling :c:func:`uv_poll_start` on a handle that is already active is fine. Doing so
will update the events mask that is being watched for.
.. versionchanged:: 1.9.0 Added the UV_DISCONNECT event.
.. c:function:: int uv_poll_stop(uv_poll_t* poll)
Stop polling the file descriptor, the callback will no longer be called.
......
......@@ -148,6 +148,10 @@ API
::
void cb(uv_write_t* req, int status) {
/* Logic which handles the write result */
}
uv_buf_t a[] = {
{ .base = "1", .len = 1 },
{ .base = "2", .len = 1 }
......@@ -162,8 +166,8 @@ API
uv_write_t req2;
/* writes "1234" */
uv_write(&req1, stream, a, 2);
uv_write(&req2, stream, b, 2);
uv_write(&req1, stream, a, 2, cb);
uv_write(&req2, stream, b, 2, cb);
.. c:function:: int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb)
......
......@@ -58,14 +58,22 @@ API
`readable`, specifies if you plan on calling :c:func:`uv_read_start` with
this stream. stdin is readable, stdout is not.
On Unix this function will try to open ``/dev/tty`` and use it if the passed
file descriptor refers to a TTY. This lets libuv put the tty in non-blocking
mode without affecting other processes that share the tty.
On Unix this function will determine the path of the fd of the terminal
using :man:`ttyname_r(3)`, open it, and use it if the passed file descriptor
refers to a TTY. This lets libuv put the tty in non-blocking mode without
affecting other processes that share the tty.
This function is not thread safe on systems that don't support
ioctl TIOCGPTN or TIOCPTYGNAME, for instance OpenBSD and Solaris.
.. note::
If opening ``/dev/tty`` fails, libuv falls back to blocking writes for
If reopening the TTY fails, libuv falls back to blocking writes for
non-readable TTY streams.
.. versionchanged:: 1.9.0: the path of the TTY is determined by
:man:`ttyname_r(3)`. In earlier versions libuv opened
`/dev/tty` instead.
.. versionchanged:: 1.5.0: trying to initialize a TTY stream with a file
descriptor that refers to a file returns `UV_EINVAL`
on UNIX.
......
......@@ -27,6 +27,7 @@ except ImportError:
def host_arch():
machine = platform.machine()
if machine == 'i386': return 'ia32'
if machine == 'AMD64': return 'x64'
if machine == 'x86_64': return 'x64'
if machine.startswith('arm'): return 'arm'
if machine.startswith('mips'): return 'mips'
......@@ -36,7 +37,7 @@ def host_arch():
def run_gyp(args):
rc = gyp.main(args)
if rc != 0:
print 'Error running GYP'
print('Error running GYP')
sys.exit(rc)
......@@ -89,5 +90,5 @@ if __name__ == '__main__':
args.append('--no-parallel')
gyp_args = list(args)
print gyp_args
print(gyp_args)
run_gyp(gyp_args)
......@@ -31,7 +31,7 @@
*/
#define UV_VERSION_MAJOR 1
#define UV_VERSION_MINOR 8
#define UV_VERSION_MINOR 9
#define UV_VERSION_PATCH 0
#define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX ""
......
......@@ -634,11 +634,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
struct uv_req_s signal_req; \
unsigned long pending_signum;
int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
char* utf8Buffer, size_t utf8Size);
int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
size_t utf16Size);
#ifndef F_OK
#define F_OK 0
#endif
......
......@@ -230,6 +230,7 @@ typedef struct uv_work_s uv_work_t;
typedef struct uv_cpu_info_s uv_cpu_info_t;
typedef struct uv_interface_address_s uv_interface_address_t;
typedef struct uv_dirent_s uv_dirent_t;
typedef struct uv_passwd_s uv_passwd_t;
typedef enum {
UV_LOOP_BLOCK_SIGNAL
......@@ -714,7 +715,8 @@ struct uv_poll_s {
enum uv_poll_event {
UV_READABLE = 1,
UV_WRITABLE = 2
UV_WRITABLE = 2,
UV_DISCONNECT = 4
};
UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd);
......@@ -1000,6 +1002,14 @@ struct uv_interface_address_s {
} netmask;
};
struct uv_passwd_s {
char* username;
long uid;
long gid;
char* shell;
char* homedir;
};
typedef enum {
UV_DIRENT_UNKNOWN,
UV_DIRENT_FILE,
......@@ -1049,6 +1059,9 @@ typedef struct {
UV_EXTERN int uv_getrusage(uv_rusage_t* rusage);
UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size);
UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd);
UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
......
......@@ -138,13 +138,14 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) {
assert(ctx != NULL);
required_len = strlen(ctx->path);
if (required_len > *size) {
*size = required_len;
if (required_len >= *size) {
*size = required_len + 1;
return UV_ENOBUFS;
}
memcpy(buffer, ctx->path, required_len);
*size = required_len;
buffer[required_len] = '\0';
return 0;
}
......
......@@ -91,6 +91,24 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
struct poll_ctl pc;
pc.events = POLLIN;
pc.cmd = PS_MOD; /* Equivalent to PS_ADD if the fd is not in the pollset. */
pc.fd = fd;
if (pollset_ctl(loop->backend_fd, &pc, 1))
return -errno;
pc.cmd = PS_DELETE;
if (pollset_ctl(loop->backend_fd, &pc, 1))
abort();
return 0;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
struct pollfd events[1024];
struct pollfd pqry;
......@@ -506,7 +524,7 @@ static int uv__makedir_p(const char *dir) {
if (*p == '/') {
*p = 0;
err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if(err != 0)
if (err != 0 && errno != EEXIST)
return err;
*p = '/';
}
......@@ -707,59 +725,44 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int
int bytes, rc = 0;
uv_fs_event_t* handle;
int events = 0;
int i = 0;
char fname[PATH_MAX];
char *p;
handle = container_of(event_watch, uv_fs_event_t, event_watcher);
/* Clean all the buffers*/
for(i = 0; i < PATH_MAX; i++) {
fname[i] = 0;
}
i = 0;
/* At this point, we assume that polling has been done on the
* file descriptor, so we can just read the AHAFS event occurrence
* data and parse its results without having to block anything
*/
bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0);
assert((bytes <= 0) && "uv__ahafs_event - Error reading monitor file");
assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file");
/* Parse the data */
if(bytes > 0)
rc = uv__parse_data(result_data, &events, handle);
/* Unrecoverable error */
if (rc == -1)
return;
/* For directory changes, the name of the files that triggered the change
* are never absolute pathnames
*/
if (uv__path_is_a_directory(handle->path) == 0) {
p = handle->dir_filename;
while(*p != NULL){
fname[i]= *p;
i++;
p++;
}
} else {
/* For file changes, figure out whether filename is absolute or not */
if (handle->path[0] == '/') {
p = strrchr(handle->path, '/');
p = strrchr(handle->path, '/');
if (p == NULL)
p = handle->path;
else
p++;
while(*p != NULL) {
fname[i]= *p;
i++;
p++;
}
}
}
strncpy(fname, p, sizeof(fname) - 1);
/* Just in case */
fname[sizeof(fname) - 1] = '\0';
/* Unrecoverable error */
if (rc == -1)
return;
else /* Call the actual JavaScript callback function */
handle->cb(handle, (const char*)&fname, events, 0);
handle->cb(handle, fname, events, 0);
}
#endif
......@@ -839,7 +842,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
/* Setup/Initialize all the libuv routines */
uv__handle_start(handle);
uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
handle->path = uv__strdup((const char*)&absolute_path);
handle->path = uv__strdup(filename);
handle->cb = cb;
uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN);
......
......@@ -53,6 +53,9 @@
# include <mach-o/dyld.h> /* _NSGetExecutablePath */
# include <sys/filio.h>
# include <sys/ioctl.h>
# if defined(O_CLOEXEC)
# define UV__O_CLOEXEC O_CLOEXEC
# endif
#endif
#if defined(__FreeBSD__) || defined(__DragonFly__)
......@@ -427,6 +430,22 @@ int uv__socket(int domain, int type, int protocol) {
return sockfd;
}
/* get a file pointer to a file in read-only and close-on-exec mode */
FILE* uv__open_file(const char* path) {
int fd;
FILE* fp;
fd = uv__open_cloexec(path, O_RDONLY);
if (fd < 0)
return NULL;
fp = fdopen(fd, "r");
if (fp == NULL)
uv__close(fd);
return fp;
}
int uv__accept(int sockfd) {
int peerfd;
......@@ -435,7 +454,7 @@ int uv__accept(int sockfd) {
assert(sockfd >= 0);
while (1) {
#if defined(__linux__) || __FreeBSD__ >= 10
#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10)
static int no_accept4;
if (no_accept4)
......@@ -479,12 +498,11 @@ skip:
}
int uv__close(int fd) {
int uv__close_nocheckstdio(int fd) {
int saved_errno;
int rc;
assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */
assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */
saved_errno = errno;
rc = close(fd);
......@@ -499,6 +517,12 @@ int uv__close(int fd) {
}
int uv__close(int fd) {
assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */
return uv__close_nocheckstdio(fd);
}
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
defined(_AIX) || defined(__DragonFly__)
......@@ -809,7 +833,7 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT)));
assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP)));
assert(0 != events);
assert(w->fd >= 0);
assert(w->fd < INT_MAX);
......@@ -842,7 +866,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT)));
assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP)));
assert(0 != events);
if (w->fd == -1)
......@@ -874,7 +898,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT);
uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP);
QUEUE_REMOVE(&w->pending_queue);
/* Remove stale events for this file descriptor */
......@@ -889,7 +913,7 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
int uv__io_active(const uv__io_t* w, unsigned int events) {
assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT)));
assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP)));
assert(0 != events);
return 0 != (w->pevents & events);
}
......@@ -930,8 +954,7 @@ int uv__open_cloexec(const char* path, int flags) {
int err;
int fd;
#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9) || \
defined(__DragonFly__)
#if defined(UV__O_CLOEXEC)
static int no_cloexec;
if (!no_cloexec) {
......@@ -1014,17 +1037,10 @@ int uv__dup2_cloexec(int oldfd, int newfd) {
int uv_os_homedir(char* buffer, size_t* size) {
struct passwd pw;
struct passwd* result;
uv_passwd_t pwd;
char* buf;
uid_t uid;
size_t bufsize;
size_t len;
long initsize;
int r;
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**);
#endif
if (buffer == NULL || size == NULL || *size == 0)
return -EINVAL;
......@@ -1036,7 +1052,7 @@ int uv_os_homedir(char* buffer, size_t* size) {
len = strlen(buf);
if (len >= *size) {
*size = len;
*size = len + 1;
return -ENOBUFS;
}
......@@ -1046,13 +1062,102 @@ int uv_os_homedir(char* buffer, size_t* size) {
return 0;
}
/* HOME is not set, so call uv__getpwuid_r() */
r = uv__getpwuid_r(&pwd);
if (r != 0) {
return r;
}
len = strlen(pwd.homedir);
if (len >= *size) {
*size = len + 1;
uv_os_free_passwd(&pwd);
return -ENOBUFS;
}
memcpy(buffer, pwd.homedir, len + 1);
*size = len;
uv_os_free_passwd(&pwd);
return 0;
}
int uv_os_tmpdir(char* buffer, size_t* size) {
const char* buf;
size_t len;
if (buffer == NULL || size == NULL || *size == 0)
return -EINVAL;
#define CHECK_ENV_VAR(name) \
do { \
buf = getenv(name); \
if (buf != NULL) \
goto return_buffer; \
} \
while (0)
/* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */
CHECK_ENV_VAR("TMPDIR");
CHECK_ENV_VAR("TMP");
CHECK_ENV_VAR("TEMP");
CHECK_ENV_VAR("TEMPDIR");
#undef CHECK_ENV_VAR
/* No temp environment variables defined */
#if defined(__ANDROID__)
buf = "/data/local/tmp";
#else
buf = "/tmp";
#endif
return_buffer:
len = strlen(buf);
if (len >= *size) {
*size = len + 1;
return -ENOBUFS;
}
/* The returned directory should not have a trailing slash. */
if (len > 1 && buf[len - 1] == '/') {
len--;
}
memcpy(buffer, buf, len + 1);
buffer[len] = '\0';
*size = len;
return 0;
}
int uv__getpwuid_r(uv_passwd_t* pwd) {
struct passwd pw;
struct passwd* result;
char* buf;
uid_t uid;
size_t bufsize;
size_t name_size;
size_t homedir_size;
size_t shell_size;
long initsize;
int r;
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**);
getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r");
if (getpwuid_r == NULL)
return -ENOSYS;
#endif
/* HOME is not set, so call getpwuid() */
if (pwd == NULL)
return -EINVAL;
initsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (initsize <= 0)
......@@ -1060,7 +1165,7 @@ int uv_os_homedir(char* buffer, size_t* size) {
else
bufsize = (size_t) initsize;
uid = getuid();
uid = geteuid();
buf = NULL;
for (;;) {
......@@ -1088,17 +1193,54 @@ int uv_os_homedir(char* buffer, size_t* size) {
return -ENOENT;
}
len = strlen(pw.pw_dir);
/* Allocate memory for the username, shell, and home directory */
name_size = strlen(pw.pw_name) + 1;
homedir_size = strlen(pw.pw_dir) + 1;
shell_size = strlen(pw.pw_shell) + 1;
pwd->username = uv__malloc(name_size + homedir_size + shell_size);
if (len >= *size) {
*size = len;
if (pwd->username == NULL) {
uv__free(buf);
return -ENOBUFS;
return -ENOMEM;
}
memcpy(buffer, pw.pw_dir, len + 1);
*size = len;
/* Copy the username */
memcpy(pwd->username, pw.pw_name, name_size);
/* Copy the home directory */
pwd->homedir = pwd->username + name_size;
memcpy(pwd->homedir, pw.pw_dir, homedir_size);
/* Copy the shell */
pwd->shell = pwd->homedir + homedir_size;
memcpy(pwd->shell, pw.pw_shell, shell_size);
/* Copy the uid and gid */
pwd->uid = pw.pw_uid;
pwd->gid = pw.pw_gid;
uv__free(buf);
return 0;
}
void uv_os_free_passwd(uv_passwd_t* pwd) {
if (pwd == NULL)
return;
/*
The memory for name, shell, and homedir are allocated in a single
uv__malloc() call. The base of the pointer is stored in pwd->username, so
that is the field that needs to be freed.
*/
uv__free(pwd->username);
pwd->username = NULL;
pwd->shell = NULL;
pwd->homedir = NULL;
}
int uv_os_get_passwd(uv_passwd_t* pwd) {
return uv__getpwuid_r(pwd);
}
......@@ -127,8 +127,8 @@
static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
return fdatasync(req->file);
#elif defined(__APPLE__) && defined(F_FULLFSYNC)
return fcntl(req->file, F_FULLFSYNC);
#elif defined(__APPLE__) && defined(SYS_fdatasync)
return syscall(SYS_fdatasync, req->file);
#else
return fsync(req->file);
#endif
......@@ -749,13 +749,13 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_gen = src->st_gen;
#elif defined(__ANDROID__)
dst->st_atim.tv_sec = src->st_atime;
dst->st_atim.tv_nsec = src->st_atime_nsec;
dst->st_atim.tv_nsec = src->st_atimensec;
dst->st_mtim.tv_sec = src->st_mtime;
dst->st_mtim.tv_nsec = src->st_mtime_nsec;
dst->st_mtim.tv_nsec = src->st_mtimensec;
dst->st_ctim.tv_sec = src->st_ctime;
dst->st_ctim.tv_nsec = src->st_ctime_nsec;
dst->st_ctim.tv_nsec = src->st_ctimensec;
dst->st_birthtim.tv_sec = src->st_ctime;
dst->st_birthtim.tv_nsec = src->st_ctime_nsec;
dst->st_birthtim.tv_nsec = src->st_ctimensec;
dst->st_flags = 0;
dst->st_gen = 0;
#elif !defined(_AIX) && ( \
......@@ -858,9 +858,14 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process)
total += result;
}
if (errno == EINTR && total == -1)
return total;
if (bufs != req->bufsml)
uv__free(bufs);
req->bufs = NULL;
req->nbufs = 0;
return total;
}
......
......@@ -28,6 +28,7 @@
#include <stdlib.h> /* abort */
#include <string.h> /* strrchr */
#include <fcntl.h> /* O_CLOEXEC, may be */
#include <stdio.h>
#if defined(__STRICT_ANSI__)
# define inline __inline
......@@ -89,17 +90,18 @@
#endif
#if defined(__linux__)
# define UV__POLLIN UV__EPOLLIN
# define UV__POLLOUT UV__EPOLLOUT
# define UV__POLLERR UV__EPOLLERR
# define UV__POLLHUP UV__EPOLLHUP
# define UV__POLLIN UV__EPOLLIN
# define UV__POLLOUT UV__EPOLLOUT
# define UV__POLLERR UV__EPOLLERR
# define UV__POLLHUP UV__EPOLLHUP
# define UV__POLLRDHUP UV__EPOLLRDHUP
#endif
#if defined(__sun) || defined(_AIX)
# define UV__POLLIN POLLIN
# define UV__POLLOUT POLLOUT
# define UV__POLLERR POLLERR
# define UV__POLLHUP POLLHUP
# define UV__POLLIN POLLIN
# define UV__POLLOUT POLLOUT
# define UV__POLLERR POLLERR
# define UV__POLLHUP POLLHUP
#endif
#ifndef UV__POLLIN
......@@ -118,6 +120,14 @@
# define UV__POLLHUP 8
#endif
#ifndef UV__POLLRDHUP
# ifdef POLLRDHUP
# define UV__POLLRDHUP POLLRDHUP
# else
# define UV__POLLRDHUP 0x200
# endif
#endif
#if !defined(O_CLOEXEC) && defined(__FreeBSD__)
/*
* It may be that we are just missing `__POSIX_VISIBLE >= 200809`.
......@@ -167,6 +177,7 @@ struct uv__stream_queued_fds_s {
/* core */
int uv__nonblock(int fd, int set);
int uv__close(int fd);
int uv__close_nocheckstdio(int fd);
int uv__cloexec(int fd, int set);
int uv__socket(int domain, int type, int protocol);
int uv__dup(int fd);
......@@ -180,6 +191,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events);
void uv__io_close(uv_loop_t* loop, uv__io_t* w);
void uv__io_feed(uv_loop_t* loop, uv__io_t* w);
int uv__io_active(const uv__io_t* w, unsigned int events);
int uv__io_check_fd(uv_loop_t* loop, int fd);
void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
/* async */
......@@ -245,6 +257,9 @@ void uv__timer_close(uv_timer_t* handle);
void uv__udp_close(uv_udp_t* handle);
void uv__udp_finish_close(uv_udp_t* handle);
uv_handle_type uv__handle_type(int fd);
FILE* uv__open_file(const char* path);
int uv__getpwuid_r(uv_passwd_t* pwd);
#if defined(__APPLE__)
int uv___stream_fd(const uv_stream_t* handle);
......
......@@ -48,6 +48,24 @@ int uv__kqueue_init(uv_loop_t* loop) {
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
struct kevent ev;
int rc;
rc = 0;
EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
rc = -errno;
EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
if (rc == 0)
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
abort();
return rc;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
struct kevent events[1024];
struct kevent* ev;
......@@ -241,6 +259,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (ev->flags & EV_ERROR)
revents |= UV__POLLERR;
if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
revents |= UV__POLLRDHUP;
if (revents == 0)
continue;
......
......@@ -39,7 +39,7 @@
#define HAVE_IFADDRS_H 1
#ifdef __UCLIBC__
# if __UCLIBC_MAJOR__ < 0 || __UCLIBC_MINOR__ < 9 || __UCLIBC_SUBLEVEL__ < 32
# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32
# undef HAVE_IFADDRS_H
# endif
#endif
......@@ -52,7 +52,7 @@
# endif
# include <sys/socket.h>
# include <net/ethernet.h>
# include <linux/if_packet.h>
# include <netpacket/packet.h>
#endif /* HAVE_IFADDRS_H */
/* Available from 2.6.32 onwards. */
......@@ -69,7 +69,7 @@
#endif
static int read_models(unsigned int numcpus, uv_cpu_info_t* ci);
static int read_times(unsigned int numcpus, uv_cpu_info_t* ci);
static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci);
static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
static unsigned long read_cpufreq(unsigned int cpunum);
......@@ -140,6 +140,26 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
struct uv__epoll_event e;
int rc;
e.events = UV__EPOLLIN;
e.data = -1;
rc = 0;
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e))
if (errno != EEXIST)
rc = -errno;
if (rc == 0)
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e))
abort();
return rc;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
/* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
* effectively infinite on 32 bits architectures. To avoid blocking
......@@ -532,15 +552,42 @@ int uv_uptime(double* uptime) {
}
static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) {
unsigned int num;
char buf[1024];
if (!fgets(buf, sizeof(buf), statfile_fp))
abort();
num = 0;
while (fgets(buf, sizeof(buf), statfile_fp)) {
if (strncmp(buf, "cpu", 3))
break;
num++;
}
*numcpus = num;
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int numcpus;
uv_cpu_info_t* ci;
int err;
FILE* statfile_fp;
*cpu_infos = NULL;
*count = 0;
numcpus = sysconf(_SC_NPROCESSORS_ONLN);
statfile_fp = uv__open_file("/proc/stat");
if (statfile_fp == NULL)
return -errno;
err = uv__cpu_num(statfile_fp, &numcpus);
if (err < 0)
return err;
assert(numcpus != (unsigned int) -1);
assert(numcpus != 0);
......@@ -550,7 +597,11 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
err = read_models(numcpus, ci);
if (err == 0)
err = read_times(numcpus, ci);
err = read_times(statfile_fp, numcpus, ci);
if (fclose(statfile_fp))
if (errno != EINTR && errno != EINPROGRESS)
abort();
if (err) {
uv_free_cpu_info(ci, numcpus);
......@@ -608,7 +659,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
defined(__i386__) || \
defined(__mips__) || \
defined(__x86_64__)
fp = fopen("/proc/cpuinfo", "r");
fp = uv__open_file("/proc/cpuinfo");
if (fp == NULL)
return -errno;
......@@ -676,7 +727,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
}
static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) {
static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci) {
unsigned long clock_ticks;
struct uv_cpu_times_s ts;
unsigned long user;
......@@ -688,22 +739,19 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) {
unsigned int num;
unsigned int len;
char buf[1024];
FILE* fp;
clock_ticks = sysconf(_SC_CLK_TCK);
assert(clock_ticks != (unsigned long) -1);
assert(clock_ticks != 0);
fp = fopen("/proc/stat", "r");
if (fp == NULL)
return -errno;
rewind(statfile_fp);
if (!fgets(buf, sizeof(buf), fp))
if (!fgets(buf, sizeof(buf), statfile_fp))
abort();
num = 0;
while (fgets(buf, sizeof(buf), fp)) {
while (fgets(buf, sizeof(buf), statfile_fp)) {
if (num >= numcpus)
break;
......@@ -742,7 +790,6 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) {
ts.irq = clock_ticks * irq;
ci[num++].cpu_times = ts;
}
fclose(fp);
assert(num == numcpus);
return 0;
......@@ -759,7 +806,7 @@ static unsigned long read_cpufreq(unsigned int cpunum) {
"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq",
cpunum);
fp = fopen(buf, "r");
fp = uv__open_file(buf);
if (fp == NULL)
return 0;
......
......@@ -76,6 +76,7 @@
#define UV__EPOLLOUT 4
#define UV__EPOLLERR 8
#define UV__EPOLLHUP 16
#define UV__EPOLLRDHUP 0x2000
#define UV__EPOLLONESHOT 0x40000000
#define UV__EPOLLET 0x80000000
......
......@@ -200,9 +200,6 @@ out:
if (err)
uv__io_feed(handle->loop, &handle->io_watcher);
/* Mimic the Windows pipe implementation, always
* return 0 and let the callback handle errors.
*/
}
......@@ -234,14 +231,18 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
addrlen = strlen(sa.sun_path);
if (addrlen > *size) {
*size = addrlen;
if (addrlen >= *size) {
*size = addrlen + 1;
return UV_ENOBUFS;
}
memcpy(buffer, sa.sun_path, addrlen);
*size = addrlen;
/* only null-terminate if it's not an abstract socket */
if (buffer[0] != '\0')
buffer[addrlen] = '\0';
return 0;
}
......
......@@ -34,7 +34,7 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
handle = container_of(w, uv_poll_t, io_watcher);
if (events & UV__POLLERR) {
uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT);
uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP);
uv__handle_stop(handle);
handle->poll_cb(handle, -EBADF, 0);
return;
......@@ -45,6 +45,8 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
pevents |= UV_READABLE;
if (events & UV__POLLOUT)
pevents |= UV_WRITABLE;
if (events & UV__POLLRDHUP)
pevents |= UV_DISCONNECT;
handle->poll_cb(handle, 0, pevents);
}
......@@ -53,6 +55,10 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
int err;
err = uv__io_check_fd(loop, fd);
if (err)
return err;
err = uv__nonblock(fd, 1);
if (err)
return err;
......@@ -71,7 +77,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
static void uv__poll_stop(uv_poll_t* handle) {
uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT);
uv__io_stop(handle->loop,
&handle->io_watcher,
UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP);
uv__handle_stop(handle);
}
......@@ -86,7 +94,7 @@ int uv_poll_stop(uv_poll_t* handle) {
int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
int events;
assert((pevents & ~(UV_READABLE | UV_WRITABLE)) == 0);
assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
uv__poll_stop(handle);
......@@ -99,6 +107,8 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
events |= UV__POLLIN;
if (pevents & UV_WRITABLE)
events |= UV__POLLOUT;
if (pevents & UV_DISCONNECT)
events |= UV__POLLRDHUP;
uv__io_start(handle->loop, &handle->io_watcher, events);
uv__handle_start(handle);
......
......@@ -498,7 +498,7 @@ int uv_spawn(uv_loop_t* loop,
} else
abort();
uv__close(signal_pipe[0]);
uv__close_nocheckstdio(signal_pipe[0]);
for (i = 0; i < options->stdio_count; i++) {
err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0);
......@@ -530,9 +530,9 @@ error:
if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
continue;
if (pipes[i][0] != -1)
close(pipes[i][0]);
uv__close_nocheckstdio(pipes[i][0]);
if (pipes[i][1] != -1)
close(pipes[i][1]);
uv__close_nocheckstdio(pipes[i][1]);
}
uv__free(pipes);
}
......
......@@ -946,13 +946,14 @@ static void uv__write_callbacks(uv_stream_t* stream) {
uv_handle_type uv__handle_type(int fd) {
struct sockaddr_storage ss;
socklen_t sslen;
socklen_t len;
int type;
memset(&ss, 0, sizeof(ss));
len = sizeof(ss);
sslen = sizeof(ss);
if (getsockname(fd, (struct sockaddr*)&ss, &len))
if (getsockname(fd, (struct sockaddr*)&ss, &sslen))
return UV_UNKNOWN_HANDLE;
len = sizeof type;
......@@ -961,6 +962,14 @@ uv_handle_type uv__handle_type(int fd) {
return UV_UNKNOWN_HANDLE;
if (type == SOCK_STREAM) {
#if defined(_AIX)
/* on AIX the getsockname call returns an empty sa structure
* for sockets of type AF_UNIX. For all other types it will
* return a properly filled in structure.
*/
if (sslen == 0)
return UV_NAMED_PIPE;
#endif
switch (ss.ss_family) {
case AF_UNIX:
return UV_NAMED_PIPE;
......@@ -1082,6 +1091,11 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
}
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-folding-constant"
#endif
static void uv__read(uv_stream_t* stream) {
uv_buf_t buf;
ssize_t nread;
......@@ -1187,6 +1201,10 @@ static void uv__read(uv_stream_t* stream) {
}
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#undef UV__CMSG_FD_COUNT
#undef UV__CMSG_FD_SIZE
......
......@@ -116,6 +116,17 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0))
return -errno;
if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd))
abort();
return 0;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
struct port_event events[1024];
struct port_event* pe;
......
......@@ -27,6 +27,9 @@
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h> /* getrlimit() */
#include <limits.h>
#undef NANOSEC
#define NANOSEC ((uint64_t) 1e9)
......@@ -55,6 +58,11 @@ static void* uv__thread_start(void *arg)
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
struct thread_ctx* ctx;
int err;
pthread_attr_t* attr;
#if defined(__APPLE__)
pthread_attr_t attr_storage;
struct rlimit lim;
#endif
ctx = uv__malloc(sizeof(*ctx));
if (ctx == NULL)
......@@ -63,7 +71,30 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
ctx->entry = entry;
ctx->arg = arg;
err = pthread_create(tid, NULL, uv__thread_start, ctx);
/* On OSX threads other than the main thread are created with a reduced stack
* size by default, adjust it to RLIMIT_STACK.
*/
#if defined(__APPLE__)
if (getrlimit(RLIMIT_STACK, &lim))
abort();
attr = &attr_storage;
if (pthread_attr_init(attr))
abort();
if (lim.rlim_cur != RLIM_INFINITY &&
lim.rlim_cur >= PTHREAD_STACK_MIN) {
if (pthread_attr_setstacksize(attr, lim.rlim_cur))
abort();
}
#else
attr = NULL;
#endif
err = pthread_create(tid, attr, uv__thread_start, ctx);
if (attr != NULL)
pthread_attr_destroy(attr);
if (err)
uv__free(ctx);
......
......@@ -23,6 +23,7 @@
#include "internal.h"
#include "spinlock.h"
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <termios.h>
......@@ -33,12 +34,30 @@ static int orig_termios_fd = -1;
static struct termios orig_termios;
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
static int uv__tty_is_slave(const int fd) {
int result;
#if defined(__linux__) || defined(__FreeBSD__)
int dummy;
result = ioctl(fd, TIOCGPTN, &dummy) != 0;
#elif defined(__APPLE__)
char dummy[256];
result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
#else
/* Fallback to ptsname
*/
result = ptsname(fd) == NULL;
#endif
return result;
}
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
uv_handle_type type;
int flags;
int newfd;
int r;
char path[256];
/* File descriptors that refer to files cannot be monitored with epoll.
* That restriction also applies to character devices like /dev/random
......@@ -62,7 +81,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
* other processes.
*/
if (type == UV_TTY) {
r = uv__open_cloexec("/dev/tty", O_RDWR);
/* Reopening a pty in master mode won't work either because the reopened
* pty will be in slave mode (*BSD) or reopening will allocate a new
* master/slave pair (Linux). Therefore check if the fd points to a
* slave device.
*/
if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
r = uv__open_cloexec(path, O_RDWR);
else
r = -1;
if (r < 0) {
/* fallback to using blocking writes */
......@@ -185,8 +212,13 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
struct winsize ws;
int err;
do
err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws);
while (err == -1 && errno == EINTR);
if (ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws))
if (err == -1)
return -errno;
*width = ws.ws_col;
......
......@@ -451,13 +451,14 @@ int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
}
required_len = strlen(handle->path);
if (required_len > *size) {
*size = required_len;
if (required_len >= *size) {
*size = required_len + 1;
return UV_ENOBUFS;
}
memcpy(buffer, handle->path, required_len);
*size = required_len;
buffer[required_len] = '\0';
return 0;
}
......
......@@ -256,30 +256,48 @@ static void uv_poll(uv_loop_t* loop, DWORD timeout) {
ULONG_PTR key;
OVERLAPPED* overlapped;
uv_req_t* req;
int repeat;
uint64_t timeout_time;
GetQueuedCompletionStatus(loop->iocp,
&bytes,
&key,
&overlapped,
timeout);
timeout_time = loop->time + timeout;
if (overlapped) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlapped);
uv_insert_pending_req(loop, req);
for (repeat = 0; ; repeat++) {
GetQueuedCompletionStatus(loop->iocp,
&bytes,
&key,
&overlapped,
timeout);
/* Some time might have passed waiting for I/O,
* so update the loop time here.
*/
uv_update_time(loop);
} else if (GetLastError() != WAIT_TIMEOUT) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
} else if (timeout > 0) {
/* GetQueuedCompletionStatus can occasionally return a little early.
* Make sure that the desired timeout is reflected in the loop time.
*/
uv__time_forward(loop, timeout);
if (overlapped) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlapped);
uv_insert_pending_req(loop, req);
/* Some time might have passed waiting for I/O,
* so update the loop time here.
*/
uv_update_time(loop);
} else if (GetLastError() != WAIT_TIMEOUT) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
} else if (timeout > 0) {
/* GetQueuedCompletionStatus can occasionally return a little early.
* Make sure that the desired timeout target time is reached.
*/
uv_update_time(loop);
if (timeout_time > loop->time) {
timeout = (DWORD)(timeout_time - loop->time);
/* The first call to GetQueuedCompletionStatus should return very
* close to the target time and the second should reach it, but
* this is not stated in the documentation. To make sure a busy
* loop cannot happen, the timeout is increased exponentially
* starting on the third round.
*/
timeout += repeat ? (1 << (repeat - 1)) : 0;
continue;
}
}
break;
}
}
......@@ -290,33 +308,51 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
OVERLAPPED_ENTRY overlappeds[128];
ULONG count;
ULONG i;
success = pGetQueuedCompletionStatusEx(loop->iocp,
overlappeds,
ARRAY_SIZE(overlappeds),
&count,
timeout,
FALSE);
if (success) {
for (i = 0; i < count; i++) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
uv_insert_pending_req(loop, req);
int repeat;
uint64_t timeout_time;
timeout_time = loop->time + timeout;
for (repeat = 0; ; repeat++) {
success = pGetQueuedCompletionStatusEx(loop->iocp,
overlappeds,
ARRAY_SIZE(overlappeds),
&count,
timeout,
FALSE);
if (success) {
for (i = 0; i < count; i++) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
uv_insert_pending_req(loop, req);
}
/* Some time might have passed waiting for I/O,
* so update the loop time here.
*/
uv_update_time(loop);
} else if (GetLastError() != WAIT_TIMEOUT) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
} else if (timeout > 0) {
/* GetQueuedCompletionStatus can occasionally return a little early.
* Make sure that the desired timeout target time is reached.
*/
uv_update_time(loop);
if (timeout_time > loop->time) {
timeout = (DWORD)(timeout_time - loop->time);
/* The first call to GetQueuedCompletionStatus should return very
* close to the target time and the second should reach it, but
* this is not stated in the documentation. To make sure a busy
* loop cannot happen, the timeout is increased exponentially
* starting on the third round.
*/
timeout += repeat ? (1 << (repeat - 1)) : 0;
continue;
}
}
/* Some time might have passed waiting for I/O,
* so update the loop time here.
*/
uv_update_time(loop);
} else if (GetLastError() != WAIT_TIMEOUT) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
} else if (timeout > 0) {
/* GetQueuedCompletionStatus can occasionally return a little early.
* Make sure that the desired timeout is reflected in the loop time.
*/
uv__time_forward(loop, timeout);
break;
}
}
......
......@@ -31,7 +31,12 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) {
lib->handle = NULL;
lib->errmsg = NULL;
if (!uv_utf8_to_utf16(filename, filename_w, ARRAY_SIZE(filename_w))) {
if (!MultiByteToWideChar(CP_UTF8,
0,
filename,
-1,
filename_w,
ARRAY_SIZE(filename_w))) {
return uv__dlerror(lib, GetLastError());
}
......
......@@ -63,19 +63,19 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
handle->req_pending = 1;
}
static int uv_relative_path(const WCHAR* filename,
const WCHAR* dir,
WCHAR** relpath) {
int dirlen = wcslen(dir);
int filelen = wcslen(filename);
if (dir[dirlen - 1] == '\\')
static void uv_relative_path(const WCHAR* filename,
const WCHAR* dir,
WCHAR** relpath) {
size_t dirlen = wcslen(dir);
if (dirlen > 0 && dir[dirlen - 1] == '\\')
dirlen--;
*relpath = uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
size_t filenamelen = wcslen(filename);
size_t relpathlen = filenamelen - dirlen - 1;
*relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR));
if (!*relpath)
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
wcsncpy(*relpath, filename + dirlen + 1, filelen - dirlen - 1);
(*relpath)[filelen - dirlen - 1] = L'\0';
return 0;
wcsncpy(*relpath, filename + dirlen + 1, relpathlen);
(*relpath)[relpathlen] = L'\0';
}
static int uv_split_path(const WCHAR* filename, WCHAR** dir,
......@@ -101,12 +101,12 @@ static int uv_split_path(const WCHAR* filename, WCHAR** dir,
*file = wcsdup(filename);
} else {
if (dir) {
*dir = (WCHAR*)uv__malloc((i + 1) * sizeof(WCHAR));
*dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR));
if (!*dir) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
wcsncpy(*dir, filename, i);
(*dir)[i] = L'\0';
wcsncpy(*dir, filename, i + 1);
(*dir)[i + 1] = L'\0';
}
*file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
......@@ -159,14 +159,20 @@ int uv_fs_event_start(uv_fs_event_t* handle,
uv__handle_start(handle);
/* Convert name to UTF16. */
name_size = uv_utf8_to_utf16(path, NULL, 0) * sizeof(WCHAR);
name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) *
sizeof(WCHAR);
pathw = (WCHAR*)uv__malloc(name_size);
if (!pathw) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
if (!uv_utf8_to_utf16(path, pathw,
name_size / sizeof(WCHAR))) {
if (!MultiByteToWideChar(CP_UTF8,
0,
path,
-1,
pathw,
name_size / sizeof(WCHAR))) {
return uv_translate_sys_error(GetLastError());
}
......@@ -340,7 +346,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
uv_fs_event_t* handle) {
FILE_NOTIFY_INFORMATION* file_info;
int err, sizew, size, result;
int err, sizew, size;
char* filename = NULL;
WCHAR* filenamew, *long_filenamew = NULL;
DWORD offset = 0;
......@@ -425,39 +431,23 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
if (long_filenamew) {
/* Get the file name out of the long path. */
result = uv_relative_path(long_filenamew,
handle->dirw,
&filenamew);
uv_relative_path(long_filenamew,
handle->dirw,
&filenamew);
uv__free(long_filenamew);
if (result == 0) {
long_filenamew = filenamew;
sizew = -1;
} else {
long_filenamew = NULL;
}
}
/*
* We could not resolve the long form explicitly.
* We therefore use the name given by ReadDirectoryChangesW.
* This may be the long form or the 8.3 short name in some cases.
*/
if (!long_filenamew) {
filenamew = file_info->FileName;
sizew = file_info->FileNameLength / sizeof(WCHAR);
}
} else {
/*
* Removed or renamed events cannot be resolved to the long form.
* We therefore use the name given by ReadDirectoryChangesW.
* This may be the long form or the 8.3 short name in some cases.
*/
if (!long_filenamew) {
filenamew = file_info->FileName;
sizew = file_info->FileNameLength / sizeof(WCHAR);
long_filenamew = filenamew;
sizew = -1;
}
}
/*
* Removed or renamed events cannot be resolved to the long form.
* We therefore use the name given by ReadDirectoryChangesW.
* This may be the long form or the 8.3 short name in some cases.
*/
if (!long_filenamew) {
filenamew = file_info->FileName;
sizew = file_info->FileNameLength / sizeof(WCHAR);
}
} else {
/* We already have the long name of the file, so just use it. */
filenamew = handle->filew;
......@@ -466,20 +456,28 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
if (filenamew) {
/* Convert the filename to utf8. */
size = uv_utf16_to_utf8(filenamew,
sizew,
NULL,
0);
size = WideCharToMultiByte(CP_UTF8,
0,
filenamew,
sizew,
NULL,
0,
NULL,
NULL);
if (size) {
filename = (char*)uv__malloc(size + 1);
if (!filename) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
size = uv_utf16_to_utf8(filenamew,
sizew,
filename,
size);
size = WideCharToMultiByte(CP_UTF8,
0,
filenamew,
sizew,
filename,
size,
NULL,
NULL);
if (size) {
filename[size] = '\0';
} else {
......
......@@ -1717,25 +1717,26 @@ static void fs__readlink(uv_fs_t* req) {
static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
int r;
DWORD w_realpath_len;
WCHAR* w_realpath_ptr;
WCHAR* w_finalpath_ptr = NULL;
WCHAR* w_realpath_ptr = NULL;
WCHAR* w_realpath_buf;
w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
if (w_realpath_len == 0) {
return -1;
}
w_realpath_ptr = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR));
if (w_realpath_ptr == NULL) {
w_realpath_buf = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR));
if (w_realpath_buf == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return -1;
}
w_realpath_ptr = w_realpath_buf;
if (pGetFinalPathNameByHandleW(handle,
w_realpath_ptr,
w_realpath_len,
VOLUME_NAME_DOS) == 0) {
uv__free(w_realpath_ptr);
uv__free(w_realpath_buf);
SetLastError(ERROR_INVALID_HANDLE);
return -1;
}
......@@ -1744,20 +1745,22 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
if (wcsncmp(w_realpath_ptr,
UNC_PATH_PREFIX,
UNC_PATH_PREFIX_LEN) == 0) {
w_finalpath_ptr = w_realpath_ptr + 6;
*w_finalpath_ptr = L'\\';
w_realpath_ptr += 6;
*w_realpath_ptr = L'\\';
w_realpath_len -= 6;
} else if (wcsncmp(w_realpath_ptr,
LONG_PATH_PREFIX,
LONG_PATH_PREFIX_LEN) == 0) {
w_finalpath_ptr = w_realpath_ptr + 4;
w_realpath_ptr += 4;
w_realpath_len -= 4;
} else {
uv__free(w_realpath_ptr);
uv__free(w_realpath_buf);
SetLastError(ERROR_INVALID_HANDLE);
return -1;
}
r = fs__wide_to_utf8(w_finalpath_ptr, w_realpath_len, realpath_ptr, NULL);
uv__free(w_realpath_ptr);
r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL);
uv__free(w_realpath_buf);
return r;
}
......
......@@ -126,7 +126,14 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
addrinfo_len += addrinfo_struct_len +
ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
if (addrinfow_ptr->ai_canonname != NULL) {
name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0);
name_len = WideCharToMultiByte(CP_UTF8,
0,
addrinfow_ptr->ai_canonname,
-1,
NULL,
0,
NULL,
NULL);
if (name_len == 0) {
req->retcode = uv_translate_sys_error(GetLastError());
goto complete;
......@@ -170,16 +177,24 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
/* convert canonical name to UTF-8 */
if (addrinfow_ptr->ai_canonname != NULL) {
name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname,
-1,
NULL,
0);
name_len = WideCharToMultiByte(CP_UTF8,
0,
addrinfow_ptr->ai_canonname,
-1,
NULL,
0,
NULL,
NULL);
assert(name_len > 0);
assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname,
-1,
cur_ptr,
name_len);
name_len = WideCharToMultiByte(CP_UTF8,
0,
addrinfow_ptr->ai_canonname,
-1,
cur_ptr,
name_len,
NULL,
NULL);
assert(name_len > 0);
addrinfo_ptr->ai_canonname = cur_ptr;
cur_ptr += ALIGNED_SIZE(name_len);
......@@ -261,7 +276,8 @@ int uv_getaddrinfo(uv_loop_t* loop,
/* calculate required memory size for all input values */
if (node != NULL) {
nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(WCHAR));
nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) *
sizeof(WCHAR));
if (nodesize == 0) {
err = GetLastError();
goto error;
......@@ -269,7 +285,12 @@ int uv_getaddrinfo(uv_loop_t* loop,
}
if (service != NULL) {
servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) *
servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8,
0,
service,
-1,
NULL,
0) *
sizeof(WCHAR));
if (servicesize == 0) {
err = GetLastError();
......@@ -294,9 +315,12 @@ int uv_getaddrinfo(uv_loop_t* loop,
/* the request. */
if (node != NULL) {
req->node = (WCHAR*)alloc_ptr;
if (uv_utf8_to_utf16(node,
(WCHAR*) alloc_ptr,
nodesize / sizeof(WCHAR)) == 0) {
if (MultiByteToWideChar(CP_UTF8,
0,
node,
-1,
(WCHAR*) alloc_ptr,
nodesize / sizeof(WCHAR)) == 0) {
err = GetLastError();
goto error;
}
......@@ -309,9 +333,12 @@ int uv_getaddrinfo(uv_loop_t* loop,
/* in the req. */
if (service != NULL) {
req->service = (WCHAR*)alloc_ptr;
if (uv_utf8_to_utf16(service,
(WCHAR*) alloc_ptr,
servicesize / sizeof(WCHAR)) == 0) {
if (MultiByteToWideChar(CP_UTF8,
0,
service,
-1,
(WCHAR*) alloc_ptr,
servicesize / sizeof(WCHAR)) == 0) {
err = GetLastError();
goto error;
}
......
......@@ -246,7 +246,6 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle);
DWORD uv__next_timeout(const uv_loop_t* loop);
void uv__time_forward(uv_loop_t* loop, uint64_t msecs);
void uv_process_timers(uv_loop_t* loop);
......@@ -329,6 +328,8 @@ uint64_t uv__hrtime(double scale);
int uv_parent_pid();
int uv_current_pid();
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
int uv__getpwuid_r(uv_passwd_t* pwd);
int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8);
/*
......
......@@ -513,13 +513,18 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
}
/* Convert name to UTF16. */
nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR);
nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
handle->name = (WCHAR*)uv__malloc(nameSize);
if (!handle->name) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) {
if (!MultiByteToWideChar(CP_UTF8,
0,
name,
-1,
handle->name,
nameSize / sizeof(WCHAR))) {
err = GetLastError();
goto error;
}
......@@ -627,13 +632,18 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
req->cb = cb;
/* Convert name to UTF16. */
nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR);
nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
handle->name = (WCHAR*)uv__malloc(nameSize);
if (!handle->name) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) {
if (!MultiByteToWideChar(CP_UTF8,
0,
name,
-1,
handle->name,
nameSize / sizeof(WCHAR))) {
err = GetLastError();
goto error;
}
......@@ -2038,9 +2048,9 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size)
*size = 0;
err = uv_translate_sys_error(GetLastError());
goto error;
} else if (pipe_prefix_len + addrlen > *size) {
} else if (pipe_prefix_len + addrlen >= *size) {
/* "\\\\.\\pipe" + name */
*size = pipe_prefix_len + addrlen;
*size = pipe_prefix_len + addrlen + 1;
err = UV_ENOBUFS;
goto error;
}
......@@ -2062,6 +2072,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size)
addrlen += pipe_prefix_len;
*size = addrlen;
buffer[addrlen] = '\0';
err = 0;
goto cleanup;
......
......@@ -91,7 +91,11 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
handle->mask_events_1 = handle->events;
handle->mask_events_2 = 0;
} else {
assert(0);
/* Just wait until there's an unsubmitted req. */
/* This will happen almost immediately as one of the 2 outstanding */
/* requests is about to return. When this happens, */
/* uv__fast_poll_process_poll_req will be called, and the pending */
/* events, if needed, will be processed in a subsequent request. */
return;
}
......@@ -107,6 +111,10 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
if (handle->events & UV_READABLE) {
afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE |
AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT;
} else {
if (handle->events & UV_DISCONNECT) {
afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT;
}
}
if (handle->events & UV_WRITABLE) {
afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
......@@ -184,6 +192,9 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE |
AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) {
events |= UV_READABLE;
if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) {
events |= UV_DISCONNECT;
}
}
if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND |
AFD_POLL_CONNECT_FAIL)) != 0) {
......@@ -218,7 +229,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
assert(handle->type == UV_POLL);
assert(!(handle->flags & UV__HANDLE_CLOSING));
assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
handle->events = events;
......
......@@ -34,13 +34,8 @@
void uv_update_time(uv_loop_t* loop) {
uint64_t new_time = uv__hrtime(UV__MILLISEC);
if (new_time > loop->time) {
loop->time = new_time;
}
}
void uv__time_forward(uv_loop_t* loop, uint64_t msecs) {
loop->time += msecs;
assert(new_time >= loop->time);
loop->time = new_time;
}
......
......@@ -292,12 +292,9 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
was_reading = 1;
alloc_cb = tty->alloc_cb;
read_cb = tty->read_cb;
if (was_reading) {
err = uv_tty_read_stop(tty);
if (err) {
return uv_translate_sys_error(err);
}
err = uv_tty_read_stop(tty);
if (err) {
return uv_translate_sys_error(err);
}
} else {
was_reading = 0;
......
......@@ -87,30 +87,6 @@ void uv__util_init() {
}
int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
char* utf8Buffer, size_t utf8Size) {
return WideCharToMultiByte(CP_UTF8,
0,
utf16Buffer,
utf16Size,
utf8Buffer,
utf8Size,
NULL,
NULL);
}
int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
size_t utf16Size) {
return MultiByteToWideChar(CP_UTF8,
0,
utf8Buffer,
-1,
utf16Buffer,
utf16Size);
}
int uv_exepath(char* buffer, size_t* size_ptr) {
int utf8_len, utf16_buffer_len, utf16_len;
WCHAR* utf16_buffer;
......@@ -210,7 +186,7 @@ int uv_cwd(char* buffer, size_t* size) {
if (r == 0) {
return uv_translate_sys_error(GetLastError());
} else if (r > (int) *size) {
*size = r -1;
*size = r;
return UV_ENOBUFS;
}
......@@ -384,7 +360,7 @@ int uv_set_process_title(const char* title) {
uv__once_init();
/* Find out how big the buffer for the wide-char title must be */
length = uv_utf8_to_utf16(title, NULL, 0);
length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
if (!length) {
err = GetLastError();
goto done;
......@@ -396,7 +372,7 @@ int uv_set_process_title(const char* title) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
length = uv_utf8_to_utf16(title, title_w, length);
length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length);
if (!length) {
err = GetLastError();
goto done;
......@@ -434,7 +410,7 @@ static int uv__get_process_title() {
}
/* Find out what the size of the buffer is that we need */
length = uv_utf16_to_utf8(title_w, -1, NULL, 0);
length = WideCharToMultiByte(CP_UTF8, 0, title_w, -1, NULL, 0, NULL, NULL);
if (!length) {
return -1;
}
......@@ -446,7 +422,14 @@ static int uv__get_process_title() {
}
/* Do utf16 -> utf8 conversion here */
if (!uv_utf16_to_utf8(title_w, -1, process_title, length)) {
if (!WideCharToMultiByte(CP_UTF8,
0,
title_w,
-1,
process_title,
length,
NULL,
NULL)) {
uv__free(process_title);
return -1;
}
......@@ -1169,7 +1152,7 @@ int uv_getrusage(uv_rusage_t *uv_rusage) {
int uv_os_homedir(char* buffer, size_t* size) {
HANDLE token;
uv_passwd_t pwd;
wchar_t path[MAX_PATH];
DWORD bufsize;
size_t len;
......@@ -1183,6 +1166,7 @@ int uv_os_homedir(char* buffer, size_t* size) {
if (len == 0) {
r = GetLastError();
/* Don't return an error if USERPROFILE was not found */
if (r != ERROR_ENVVAR_NOT_FOUND)
return uv_translate_sys_error(r);
......@@ -1190,43 +1174,219 @@ int uv_os_homedir(char* buffer, size_t* size) {
/* This should not be possible */
return UV_EIO;
} else {
goto convert_buffer;
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
return uv_translate_sys_error(GetLastError());
} else if (bufsize > *size) {
*size = bufsize;
return UV_ENOBUFS;
}
/* Convert to UTF-8 */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
path,
-1,
buffer,
*size,
NULL,
NULL);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
*size = bufsize - 1;
return 0;
}
/* USERPROFILE is not set, so call GetUserProfileDirectoryW() */
if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
return uv_translate_sys_error(GetLastError());
/* USERPROFILE is not set, so call uv__getpwuid_r() */
r = uv__getpwuid_r(&pwd);
bufsize = MAX_PATH;
if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
r = GetLastError();
CloseHandle(token);
if (r != 0) {
return r;
}
/* This should not be possible */
if (r == ERROR_INSUFFICIENT_BUFFER)
return UV_EIO;
len = strlen(pwd.homedir);
return uv_translate_sys_error(r);
if (len >= *size) {
*size = len + 1;
uv_os_free_passwd(&pwd);
return UV_ENOBUFS;
}
CloseHandle(token);
memcpy(buffer, pwd.homedir, len + 1);
*size = len;
uv_os_free_passwd(&pwd);
return 0;
}
convert_buffer:
int uv_os_tmpdir(char* buffer, size_t* size) {
wchar_t path[MAX_PATH + 1];
DWORD bufsize;
size_t len;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
len = GetTempPathW(MAX_PATH + 1, path);
if (len == 0) {
return uv_translate_sys_error(GetLastError());
} else if (len > MAX_PATH + 1) {
/* This should not be possible */
return UV_EIO;
}
/* The returned directory should not have a trailing slash, unless it */
/* points at a drive root, like c:\. Remove it if needed.*/
if (path[len - 1] == L'\\' &&
!(len == 3 && path[1] == L':')) {
len--;
path[len] = L'\0';
}
/* Check how much space we need */
bufsize = uv_utf16_to_utf8(path, -1, NULL, 0);
bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
return uv_translate_sys_error(GetLastError());
} else if (bufsize > *size) {
*size = bufsize - 1;
*size = bufsize;
return UV_ENOBUFS;
}
/* Convert to UTF-8 */
bufsize = uv_utf16_to_utf8(path, -1, buffer, *size);
bufsize = WideCharToMultiByte(CP_UTF8,
0,
path,
-1,
buffer,
*size,
NULL,
NULL);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
*size = bufsize - 1;
return 0;
}
void uv_os_free_passwd(uv_passwd_t* pwd) {
if (pwd == NULL)
return;
uv__free(pwd->username);
uv__free(pwd->homedir);
pwd->username = NULL;
pwd->homedir = NULL;
}
int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) {
DWORD bufsize;
if (utf16 == NULL)
return UV_EINVAL;
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
/* Allocate the destination buffer */
*utf8 = uv__malloc(bufsize);
if (*utf8 == NULL)
return UV_ENOMEM;
/* Convert to UTF-8 */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
utf16,
-1,
*utf8,
bufsize,
NULL,
NULL);
if (bufsize == 0) {
uv__free(*utf8);
return uv_translate_sys_error(GetLastError());
}
return 0;
}
int uv__getpwuid_r(uv_passwd_t* pwd) {
HANDLE token;
wchar_t username[UNLEN + 1];
wchar_t path[MAX_PATH];
DWORD bufsize;
int r;
if (pwd == NULL)
return UV_EINVAL;
/* Get the home directory using GetUserProfileDirectoryW() */
if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
return uv_translate_sys_error(GetLastError());
bufsize = sizeof(path);
if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
r = GetLastError();
CloseHandle(token);
/* This should not be possible */
if (r == ERROR_INSUFFICIENT_BUFFER)
return UV_ENOMEM;
return uv_translate_sys_error(r);
}
CloseHandle(token);
/* Get the username using GetUserNameW() */
bufsize = sizeof(username);
if (!GetUserNameW(username, &bufsize)) {
r = GetLastError();
/* This should not be possible */
if (r == ERROR_INSUFFICIENT_BUFFER)
return UV_ENOMEM;
return uv_translate_sys_error(r);
}
pwd->homedir = NULL;
r = uv__convert_utf16_to_utf8(path, &pwd->homedir);
if (r != 0)
return r;
pwd->username = NULL;
r = uv__convert_utf16_to_utf8(username, &pwd->username);
if (r != 0) {
uv__free(pwd->homedir);
return r;
}
pwd->shell = NULL;
pwd->uid = -1;
pwd->gid = -1;
return 0;
}
int uv_os_get_passwd(uv_passwd_t* pwd) {
return uv__getpwuid_r(pwd);
}
......@@ -226,7 +226,7 @@ int process_wait(process_info_t* vec, int n, int timeout) {
tv = timebase;
for (;;) {
/* Check that gettimeofday() doesn't jump back in time. */
assert(tv.tv_sec == timebase.tv_sec ||
assert(tv.tv_sec > timebase.tv_sec ||
(tv.tv_sec == timebase.tv_sec && tv.tv_usec >= timebase.tv_usec));
elapsed_ms =
......
......@@ -108,10 +108,10 @@ typedef enum {
/* This macro cleans up the main loop. This is used to avoid valgrind
* warnings about memory being "leaked" by the main event loop.
*/
#define MAKE_VALGRIND_HAPPY() \
do { \
close_loop(uv_default_loop()); \
uv_loop_delete(uv_default_loop()); \
#define MAKE_VALGRIND_HAPPY() \
do { \
close_loop(uv_default_loop()); \
ASSERT(0 == uv_loop_close(uv_default_loop())); \
} while (0)
/* Just sugar for wrapping the main() for a task or helper. */
......@@ -207,7 +207,7 @@ UNUSED static int can_ipv6(void) {
int i;
if (uv_interface_addresses(&addr, &count))
return 1; /* Assume IPv6 support on failure. */
return 0; /* Assume no IPv6 support on failure. */
supported = 0;
for (i = 0; supported == 0 && i < count; i += 1)
......
......@@ -25,24 +25,33 @@
#include <string.h>
#include <errno.h>
typedef struct {
typedef struct worker_config {
uv_mutex_t mutex;
uv_cond_t cond;
int delay;
int signal_delay;
int wait_delay;
int use_broadcast;
volatile int posted;
volatile int posted_1;
volatile int posted_2;
void (*signal_cond)(struct worker_config* c, volatile int* flag);
void (*wait_cond)(struct worker_config* c, const volatile int* flag);
} worker_config;
static void worker(void* arg) {
worker_config* c = arg;
c->signal_cond(c, &c->posted_1);
c->wait_cond(c, &c->posted_2);
}
if (c->delay)
uv_sleep(c->delay);
static void condvar_signal(worker_config* c, volatile int* flag) {
if (c->signal_delay)
uv_sleep(c->signal_delay);
uv_mutex_lock(&c->mutex);
ASSERT(c->posted == 0);
c->posted = 1;
ASSERT(*flag == 0);
*flag = 1;
if (c->use_broadcast)
uv_cond_broadcast(&c->cond);
else
......@@ -51,21 +60,33 @@ static void worker(void* arg) {
}
static void condvar_wait(worker_config* c, const volatile int* flag) {
uv_mutex_lock(&c->mutex);
if (c->wait_delay)
uv_sleep(c->wait_delay);
while (*flag == 0) {
uv_cond_wait(&c->cond, &c->mutex);
}
ASSERT(*flag == 1);
uv_mutex_unlock(&c->mutex);
}
TEST_IMPL(condvar_1) {
uv_thread_t thread;
worker_config wc;
memset(&wc, 0, sizeof(wc));
wc.wait_delay = 100;
wc.signal_cond = condvar_signal;
wc.wait_cond = condvar_wait;
ASSERT(0 == uv_cond_init(&wc.cond));
ASSERT(0 == uv_mutex_init(&wc.mutex));
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
uv_mutex_lock(&wc.mutex);
uv_sleep(100);
uv_cond_wait(&wc.cond, &wc.mutex);
ASSERT(wc.posted == 1);
uv_mutex_unlock(&wc.mutex);
wc.wait_cond(&wc, &wc.posted_1);
wc.signal_cond(&wc, &wc.posted_2);
ASSERT(0 == uv_thread_join(&thread));
uv_mutex_destroy(&wc.mutex);
......@@ -80,15 +101,16 @@ TEST_IMPL(condvar_2) {
worker_config wc;
memset(&wc, 0, sizeof(wc));
wc.delay = 100;
wc.signal_delay = 100;
wc.signal_cond = condvar_signal;
wc.wait_cond = condvar_wait;
ASSERT(0 == uv_cond_init(&wc.cond));
ASSERT(0 == uv_mutex_init(&wc.mutex));
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
uv_mutex_lock(&wc.mutex);
uv_cond_wait(&wc.cond, &wc.mutex);
uv_mutex_unlock(&wc.mutex);
wc.wait_cond(&wc, &wc.posted_1);
wc.signal_cond(&wc, &wc.posted_2);
ASSERT(0 == uv_thread_join(&thread));
uv_mutex_destroy(&wc.mutex);
......@@ -98,22 +120,35 @@ TEST_IMPL(condvar_2) {
}
static void condvar_timedwait(worker_config* c, const volatile int* flag) {
int r;
uv_mutex_lock(&c->mutex);
if (c->wait_delay)
uv_sleep(c->wait_delay);
while (*flag == 0) {
r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(150 * 1e6));
ASSERT(r == 0);
}
uv_mutex_unlock(&c->mutex);
}
TEST_IMPL(condvar_3) {
uv_thread_t thread;
worker_config wc;
int r;
memset(&wc, 0, sizeof(wc));
wc.delay = 100;
wc.signal_delay = 100;
wc.signal_cond = condvar_signal;
wc.wait_cond = condvar_timedwait;
ASSERT(0 == uv_cond_init(&wc.cond));
ASSERT(0 == uv_mutex_init(&wc.mutex));
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
uv_mutex_lock(&wc.mutex);
r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(50 * 1e6));
ASSERT(r == UV_ETIMEDOUT);
uv_mutex_unlock(&wc.mutex);
wc.wait_cond(&wc, &wc.posted_1);
wc.signal_cond(&wc, &wc.posted_2);
ASSERT(0 == uv_thread_join(&thread));
uv_mutex_destroy(&wc.mutex);
......@@ -126,19 +161,18 @@ TEST_IMPL(condvar_3) {
TEST_IMPL(condvar_4) {
uv_thread_t thread;
worker_config wc;
int r;
memset(&wc, 0, sizeof(wc));
wc.delay = 100;
wc.signal_delay = 100;
wc.signal_cond = condvar_signal;
wc.wait_cond = condvar_timedwait;
ASSERT(0 == uv_cond_init(&wc.cond));
ASSERT(0 == uv_mutex_init(&wc.mutex));
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
uv_mutex_lock(&wc.mutex);
r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(150 * 1e6));
ASSERT(r == 0);
uv_mutex_unlock(&wc.mutex);
wc.wait_cond(&wc, &wc.posted_1);
wc.signal_cond(&wc, &wc.posted_2);
ASSERT(0 == uv_thread_join(&thread));
uv_mutex_destroy(&wc.mutex);
......@@ -154,16 +188,16 @@ TEST_IMPL(condvar_5) {
memset(&wc, 0, sizeof(wc));
wc.use_broadcast = 1;
wc.signal_delay = 100;
wc.signal_cond = condvar_signal;
wc.wait_cond = condvar_wait;
ASSERT(0 == uv_cond_init(&wc.cond));
ASSERT(0 == uv_mutex_init(&wc.mutex));
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
uv_mutex_lock(&wc.mutex);
uv_sleep(100);
uv_cond_wait(&wc.cond, &wc.mutex);
ASSERT(wc.posted == 1);
uv_mutex_unlock(&wc.mutex);
wc.wait_cond(&wc, &wc.posted_1);
wc.signal_cond(&wc, &wc.posted_2);
ASSERT(0 == uv_thread_join(&thread));
uv_mutex_destroy(&wc.mutex);
......
/* Copyright libuv project 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"
#ifdef _WIN32
TEST_IMPL(eintr_handling) {
RETURN_SKIP("Test not implemented on Windows.");
}
#else /* !_WIN32 */
#include <string.h>
#include <unistd.h>
static uv_loop_t* loop;
static uv_fs_t read_req;
static uv_buf_t iov;
static char buf[32];
static char test_buf[] = "test-buffer\n";
int pipe_fds[2];
struct thread_ctx {
uv_barrier_t barrier;
int fd;
};
static void thread_main(void* arg) {
int nwritten;
ASSERT(0 == kill(getpid(), SIGUSR1));
do
nwritten = write(pipe_fds[1], test_buf, sizeof(test_buf));
while (nwritten == -1 && errno == EINTR);
ASSERT(nwritten == sizeof(test_buf));
}
static void sig_func(uv_signal_t* handle, int signum) {
uv_signal_stop(handle);
}
TEST_IMPL(eintr_handling) {
struct thread_ctx ctx;
uv_thread_t thread;
uv_signal_t signal;
int nread;
iov = uv_buf_init(buf, sizeof(buf));
loop = uv_default_loop();
ASSERT(0 == uv_signal_init(loop, &signal));
ASSERT(0 == uv_signal_start(&signal, sig_func, SIGUSR1));
ASSERT(0 == pipe(pipe_fds));
ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx));
nread = uv_fs_read(loop, &read_req, pipe_fds[0], &iov, 1, -1, NULL);
ASSERT(nread == sizeof(test_buf));
ASSERT(0 == strcmp(buf, test_buf));
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
ASSERT(0 == close(pipe_fds[0]));
ASSERT(0 == close(pipe_fds[1]));
uv_close((uv_handle_t*) &signal, NULL);
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif /* !_WIN32 */
......@@ -531,6 +531,33 @@ TEST_IMPL(fs_event_watch_file_current_dir) {
return 0;
}
#ifdef _WIN32
TEST_IMPL(fs_event_watch_file_root_dir) {
uv_loop_t* loop;
int r;
const char* sys_drive = getenv("SystemDrive");
char path[] = "\\\\?\\X:\\bootsect.bak";
ASSERT(sys_drive != NULL);
strncpy(path + sizeof("\\\\?\\") - 1, sys_drive, 1);
loop = uv_default_loop();
r = uv_fs_event_init(loop, &fs_event);
ASSERT(r == 0);
r = uv_fs_event_start(&fs_event, fail_cb, path, 0);
if (r == UV_ENOENT)
RETURN_SKIP("bootsect.bak doesn't exist in system root.\n");
ASSERT(r == 0);
uv_close((uv_handle_t*) &fs_event, NULL);
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif
TEST_IMPL(fs_event_no_callback_after_close) {
uv_loop_t* loop = uv_default_loop();
int r;
......@@ -792,6 +819,7 @@ TEST_IMPL(fs_event_getpath) {
r = uv_fs_event_getpath(&fs_event, buf, &len);
ASSERT(r == 0);
ASSERT(buf[len - 1] != 0);
ASSERT(buf[len] == '\0');
ASSERT(memcmp(buf, "watch_dir", len) == 0);
r = uv_fs_event_stop(&fs_event);
ASSERT(r == 0);
......
......@@ -173,6 +173,7 @@ TEST_IMPL(fs_poll_getpath) {
len = sizeof buf;
ASSERT(0 == uv_fs_poll_getpath(&poll_handle, buf, &len));
ASSERT(buf[len - 1] != 0);
ASSERT(buf[len] == '\0');
ASSERT(0 == memcmp(buf, FIXTURE, len));
uv_close((uv_handle_t*) &poll_handle, close_cb);
......
/* Copyright libuv 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 <string.h>
TEST_IMPL(get_passwd) {
uv_passwd_t pwd;
size_t len;
int r;
/* Test the normal case */
r = uv_os_get_passwd(&pwd);
ASSERT(r == 0);
len = strlen(pwd.username);
ASSERT(len > 0);
#ifdef _WIN32
ASSERT(pwd.shell == NULL);
#else
len = strlen(pwd.shell);
ASSERT(len > 0);
#endif
len = strlen(pwd.homedir);
ASSERT(len > 0);
#ifdef _WIN32
ASSERT(pwd.homedir[len - 1] != '\\');
#else
ASSERT(pwd.homedir[len - 1] != '/');
#endif
#ifdef _WIN32
ASSERT(pwd.uid == -1);
ASSERT(pwd.gid == -1);
#else
ASSERT(pwd.uid >= 0);
ASSERT(pwd.gid >= 0);
#endif
/* Test uv_os_free_passwd() */
uv_os_free_passwd(&pwd);
ASSERT(pwd.username == NULL);
ASSERT(pwd.shell == NULL);
ASSERT(pwd.homedir == NULL);
/* Test a double free */
uv_os_free_passwd(&pwd);
ASSERT(pwd.username == NULL);
ASSERT(pwd.shell == NULL);
ASSERT(pwd.homedir == NULL);
/* Test invalid input */
r = uv_os_get_passwd(NULL);
ASSERT(r == UV_EINVAL);
return 0;
}
/* Copyright libuv project 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 <string.h>
......
......@@ -44,6 +44,7 @@ TEST_DECLARE (semaphore_2)
TEST_DECLARE (semaphore_3)
TEST_DECLARE (tty)
TEST_DECLARE (tty_file)
TEST_DECLARE (tty_pty)
TEST_DECLARE (stdio_over_pipes)
TEST_DECLARE (ip6_pton)
TEST_DECLARE (ipc_listen_before_write)
......@@ -154,6 +155,7 @@ TEST_DECLARE (timer_huge_repeat)
TEST_DECLARE (timer_run_once)
TEST_DECLARE (timer_from_check)
TEST_DECLARE (timer_null_callback)
TEST_DECLARE (timer_early_check)
TEST_DECLARE (idle_starvation)
TEST_DECLARE (loop_handles)
TEST_DECLARE (get_loadavg)
......@@ -191,12 +193,15 @@ TEST_DECLARE (active)
TEST_DECLARE (embed)
TEST_DECLARE (async)
TEST_DECLARE (async_null_cb)
TEST_DECLARE (eintr_handling)
TEST_DECLARE (get_currentexe)
TEST_DECLARE (process_title)
TEST_DECLARE (cwd_and_chdir)
TEST_DECLARE (get_memory)
TEST_DECLARE (get_passwd)
TEST_DECLARE (handle_fileno)
TEST_DECLARE (homedir)
TEST_DECLARE (tmpdir)
TEST_DECLARE (hrtime)
TEST_DECLARE (getaddrinfo_fail)
TEST_DECLARE (getaddrinfo_fail_sync)
......@@ -267,6 +272,9 @@ TEST_DECLARE (fs_event_watch_dir_recursive)
TEST_DECLARE (fs_event_watch_file)
TEST_DECLARE (fs_event_watch_file_twice)
TEST_DECLARE (fs_event_watch_file_current_dir)
#ifdef _WIN32
TEST_DECLARE (fs_event_watch_file_root_dir)
#endif
TEST_DECLARE (fs_event_no_callback_after_close)
TEST_DECLARE (fs_event_no_callback_on_close)
TEST_DECLARE (fs_event_immediate_close)
......@@ -292,6 +300,7 @@ TEST_DECLARE (threadpool_cancel_work)
TEST_DECLARE (threadpool_cancel_fs)
TEST_DECLARE (threadpool_cancel_single)
TEST_DECLARE (thread_local_storage)
TEST_DECLARE (thread_stack_size)
TEST_DECLARE (thread_mutex)
TEST_DECLARE (thread_rwlock)
TEST_DECLARE (thread_rwlock_trylock)
......@@ -301,6 +310,7 @@ TEST_DECLARE (dlerror)
TEST_DECLARE (poll_duplex)
TEST_DECLARE (poll_unidirectional)
TEST_DECLARE (poll_close)
TEST_DECLARE (poll_bad_fdtype)
TEST_DECLARE (ip4_addr)
TEST_DECLARE (ip6_addr_link_local)
......@@ -378,6 +388,7 @@ TASK_LIST_START
TEST_ENTRY (pipe_set_non_blocking)
TEST_ENTRY (tty)
TEST_ENTRY (tty_file)
TEST_ENTRY (tty_pty)
TEST_ENTRY (stdio_over_pipes)
TEST_ENTRY (ip6_pton)
TEST_ENTRY (ipc_listen_before_write)
......@@ -522,6 +533,7 @@ TASK_LIST_START
TEST_ENTRY (timer_run_once)
TEST_ENTRY (timer_from_check)
TEST_ENTRY (timer_null_callback)
TEST_ENTRY (timer_early_check)
TEST_ENTRY (idle_starvation)
......@@ -566,6 +578,7 @@ TASK_LIST_START
TEST_ENTRY (async)
TEST_ENTRY (async_null_cb)
TEST_ENTRY (eintr_handling)
TEST_ENTRY (get_currentexe)
......@@ -575,12 +588,16 @@ TASK_LIST_START
TEST_ENTRY (get_memory)
TEST_ENTRY (get_passwd)
TEST_ENTRY (get_loadavg)
TEST_ENTRY (handle_fileno)
TEST_ENTRY (homedir)
TEST_ENTRY (tmpdir)
TEST_ENTRY (hrtime)
TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000)
......@@ -600,6 +617,7 @@ TASK_LIST_START
TEST_ENTRY (poll_duplex)
TEST_ENTRY (poll_unidirectional)
TEST_ENTRY (poll_close)
TEST_ENTRY (poll_bad_fdtype)
TEST_ENTRY (socket_buffer_size)
......@@ -688,6 +706,9 @@ TASK_LIST_START
TEST_ENTRY (fs_event_watch_file)
TEST_ENTRY (fs_event_watch_file_twice)
TEST_ENTRY (fs_event_watch_file_current_dir)
#ifdef _WIN32
TEST_ENTRY (fs_event_watch_file_root_dir)
#endif
TEST_ENTRY (fs_event_no_callback_after_close)
TEST_ENTRY (fs_event_no_callback_on_close)
TEST_ENTRY (fs_event_immediate_close)
......@@ -706,13 +727,21 @@ TASK_LIST_START
TEST_ENTRY (fs_read_write_null_arguments)
TEST_ENTRY (threadpool_queue_work_simple)
TEST_ENTRY (threadpool_queue_work_einval)
#if defined(__PPC__) || defined(__PPC64__) /* For linux PPC and AIX */
/* pthread_join takes a while, especially on AIX.
* Therefore being gratuitous with timeout.
*/
TEST_ENTRY_CUSTOM (threadpool_multiple_event_loops, 0, 0, 120000)
#else
TEST_ENTRY (threadpool_multiple_event_loops)
#endif
TEST_ENTRY (threadpool_cancel_getaddrinfo)
TEST_ENTRY (threadpool_cancel_getnameinfo)
TEST_ENTRY (threadpool_cancel_work)
TEST_ENTRY (threadpool_cancel_fs)
TEST_ENTRY (threadpool_cancel_single)
TEST_ENTRY (thread_local_storage)
TEST_ENTRY (thread_stack_size)
TEST_ENTRY (thread_mutex)
TEST_ENTRY (thread_rwlock)
TEST_ENTRY (thread_rwlock_trylock)
......
......@@ -53,6 +53,7 @@ TEST_IMPL(pipe_close_stdout_read_stdin) {
int pid;
int fd[2];
int status;
char buf;
uv_pipe_t stdin_pipe;
r = pipe(fd);
......@@ -64,6 +65,8 @@ TEST_IMPL(pipe_close_stdout_read_stdin) {
* The write side will be closed by the parent process.
*/
close(fd[1]);
/* block until write end of pipe is closed */
read(fd[0], &buf, 1);
close(0);
r = dup(fd[0]);
ASSERT(r != -1);
......
......@@ -114,6 +114,7 @@ TEST_IMPL(pipe_getsockname) {
ASSERT(r == 0);
ASSERT(buf[len - 1] != 0);
ASSERT(buf[len] == '\0');
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
len = sizeof buf;
......
......@@ -32,6 +32,7 @@ TEST_IMPL(platform_output) {
uv_rusage_t rusage;
uv_cpu_info_t* cpus;
uv_interface_address_t* interfaces;
uv_passwd_t pwd;
int count;
int i;
int err;
......@@ -122,5 +123,15 @@ TEST_IMPL(platform_output) {
}
uv_free_interface_addresses(interfaces, count);
err = uv_os_get_passwd(&pwd);
ASSERT(err == 0);
printf("uv_os_get_passwd:\n");
printf(" euid: %ld\n", pwd.uid);
printf(" gid: %ld\n", pwd.gid);
printf(" username: %s\n", pwd.username);
printf(" shell: %s\n", pwd.shell);
printf(" home directory: %s\n", pwd.homedir);
return 0;
}
......@@ -21,7 +21,9 @@
#include <errno.h>
#ifndef _WIN32
#ifdef _WIN32
# include <fcntl.h>
#else
# include <sys/socket.h>
# include <unistd.h>
#endif
......@@ -49,7 +51,7 @@ typedef struct connection_context_s {
size_t read, sent;
int is_server_connection;
int open_handles;
int got_fin, sent_fin;
int got_fin, sent_fin, got_disconnect;
unsigned int events, delayed_events;
} connection_context_t;
......@@ -70,6 +72,8 @@ static int closed_connections = 0;
static int valid_writable_wakeups = 0;
static int spurious_writable_wakeups = 0;
static int disconnects = 0;
static int got_eagain(void) {
#ifdef _WIN32
......@@ -140,6 +144,7 @@ static connection_context_t* create_connection_context(
context->delayed_events = 0;
context->got_fin = 0;
context->sent_fin = 0;
context->got_disconnect = 0;
r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock);
context->open_handles++;
......@@ -373,7 +378,13 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) {
}
}
if (context->got_fin && context->sent_fin) {
if (events & UV_DISCONNECT) {
context->got_disconnect = 1;
++disconnects;
new_events &= ~UV_DISCONNECT;
}
if (context->got_fin && context->sent_fin && context->got_disconnect) {
/* Sent and received FIN. Close and destroy context. */
close_socket(context->sock);
destroy_connection_context(context);
......@@ -461,9 +472,9 @@ static void server_poll_cb(uv_poll_t* handle, int status, int events) {
#endif
connection_context = create_connection_context(sock, 1);
connection_context->events = UV_READABLE | UV_WRITABLE;
connection_context->events = UV_READABLE | UV_WRITABLE | UV_DISCONNECT;
r = uv_poll_start(&connection_context->poll_handle,
UV_READABLE | UV_WRITABLE,
UV_READABLE | UV_WRITABLE | UV_DISCONNECT,
connection_poll_cb);
ASSERT(r == 0);
......@@ -505,9 +516,9 @@ static void start_client(void) {
sock = create_bound_socket(addr);
context = create_connection_context(sock, 0);
context->events = UV_READABLE | UV_WRITABLE;
context->events = UV_READABLE | UV_WRITABLE | UV_DISCONNECT;
r = uv_poll_start(&context->poll_handle,
UV_READABLE | UV_WRITABLE,
UV_READABLE | UV_WRITABLE | UV_DISCONNECT,
connection_poll_cb);
ASSERT(r == 0);
......@@ -541,6 +552,7 @@ static void start_poll_test(void) {
spurious_writable_wakeups > 20);
ASSERT(closed_connections == NUM_CLIENTS * 2);
ASSERT(disconnects == NUM_CLIENTS * 2);
MAKE_VALGRIND_HAPPY();
}
......@@ -558,3 +570,29 @@ TEST_IMPL(poll_unidirectional) {
start_poll_test();
return 0;
}
/* Windows won't let you open a directory so we open a file instead.
* OS X lets you poll a file so open the $PWD instead. Both fail
* on Linux so it doesn't matter which one we pick. Both succeed
* on FreeBSD, Solaris and AIX so skip the test on those platforms.
*/
TEST_IMPL(poll_bad_fdtype) {
#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \
!defined(_AIX)
uv_poll_t poll_handle;
int fd;
#if defined(_WIN32)
fd = open("test/fixtures/empty_file", O_RDONLY);
#else
fd = open(".", O_RDONLY);
#endif
ASSERT(fd != -1);
ASSERT(0 != uv_poll_init(uv_default_loop(), &poll_handle, fd));
ASSERT(0 == close(fd));
#endif
MAKE_VALGRIND_HAPPY();
return 0;
}
......@@ -72,7 +72,7 @@ TEST_IMPL(tcp_close_while_connecting) {
RETURN_SKIP("Network unreachable.");
ASSERT(r == 0);
ASSERT(0 == uv_timer_init(loop, &timer1_handle));
ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 50, 0));
ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 1, 0));
ASSERT(0 == uv_timer_init(loop, &timer2_handle));
ASSERT(0 == uv_timer_start(&timer2_handle, timer2_cb, 86400 * 1000, 0));
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
......
......@@ -209,3 +209,24 @@ TEST_IMPL(thread_local_storage) {
uv_key_delete(&tls_key);
return 0;
}
#if defined(__APPLE__)
static void thread_check_stack(void* arg) {
/* 512KB is the default stack size of threads other than the main thread
* on OSX. */
ASSERT(pthread_get_stacksize_np(pthread_self()) > 512*1024);
}
#endif
TEST_IMPL(thread_stack_size) {
#if defined(__APPLE__)
uv_thread_t thread;
ASSERT(0 == uv_thread_create(&thread, thread_check_stack, NULL));
ASSERT(0 == uv_thread_join(&thread));
return 0;
#else
RETURN_SKIP("OSX only test");
#endif
}
......@@ -301,3 +301,30 @@ TEST_IMPL(timer_null_callback) {
MAKE_VALGRIND_HAPPY();
return 0;
}
static uint64_t timer_early_check_expected_time;
static void timer_early_check_cb(uv_timer_t* handle) {
uint64_t hrtime = uv_hrtime() / 1000000;
ASSERT(hrtime >= timer_early_check_expected_time);
}
TEST_IMPL(timer_early_check) {
uv_timer_t timer_handle;
const uint64_t timeout_ms = 10;
timer_early_check_expected_time = uv_now(uv_default_loop()) + timeout_ms;
ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle));
ASSERT(0 == uv_timer_start(&timer_handle, timer_early_check_cb, timeout_ms, 0));
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
uv_close((uv_handle_t*) &timer_handle, NULL);
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
MAKE_VALGRIND_HAPPY();
return 0;
}
/* Copyright libuv project 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 <string.h>
#define PATHMAX 1024
#define SMALLPATH 1
TEST_IMPL(tmpdir) {
char tmpdir[PATHMAX];
size_t len;
char last;
int r;
/* Test the normal case */
len = sizeof tmpdir;
tmpdir[0] = '\0';
ASSERT(strlen(tmpdir) == 0);
r = uv_os_tmpdir(tmpdir, &len);
ASSERT(r == 0);
ASSERT(strlen(tmpdir) == len);
ASSERT(len > 0);
ASSERT(tmpdir[len] == '\0');
if (len > 1) {
last = tmpdir[len - 1];
#ifdef _WIN32
ASSERT(last != '\\');
#else
ASSERT(last != '/');
#endif
}
/* Test the case where the buffer is too small */
len = SMALLPATH;
r = uv_os_tmpdir(tmpdir, &len);
ASSERT(r == UV_ENOBUFS);
ASSERT(len > SMALLPATH);
/* Test invalid inputs */
r = uv_os_tmpdir(NULL, &len);
ASSERT(r == UV_EINVAL);
r = uv_os_tmpdir(tmpdir, NULL);
ASSERT(r == UV_EINVAL);
len = 0;
r = uv_os_tmpdir(tmpdir, &len);
ASSERT(r == UV_EINVAL);
return 0;
}
......@@ -28,6 +28,13 @@
#else /* Unix */
# include <fcntl.h>
# include <unistd.h>
# if defined(__linux__)
# include <pty.h>
# elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
# include <util.h>
# elif defined(__FreeBSD__) || defined(__DragonFly__)
# include <libutil.h>
# endif
#endif
#include <string.h>
......@@ -182,3 +189,35 @@ TEST_IMPL(tty_file) {
#endif
return 0;
}
TEST_IMPL(tty_pty) {
# if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
int master_fd, slave_fd;
struct winsize w;
uv_loop_t loop;
uv_tty_t master_tty, slave_tty;
ASSERT(0 == uv_loop_init(&loop));
ASSERT(0 == openpty(&master_fd, &slave_fd, NULL, NULL, &w));
ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0));
ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0));
/* Check if the file descriptor was reopened. If it is,
* UV_STREAM_BLOCKING (value 0x80) isn't set on flags.
*/
ASSERT(0 == (slave_tty.flags & 0x80));
/* The master_fd of a pty should never be reopened.
*/
ASSERT(master_tty.flags & 0x80);
ASSERT(0 == close(slave_fd));
uv_close((uv_handle_t*) &slave_tty, NULL);
ASSERT(0 == close(master_fd));
uv_close((uv_handle_t*) &master_tty, NULL);
ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
MAKE_VALGRIND_HAPPY();
#endif
return 0;
}
......@@ -92,6 +92,7 @@
'src/win/req.c',
'src/win/req-inl.h',
'src/win/signal.c',
'src/win/snprintf.c',
'src/win/stream.c',
'src/win/stream-inl.h',
'src/win/tcp.c',
......@@ -104,13 +105,6 @@
'src/win/winsock.c',
'src/win/winsock.h',
],
'conditions': [
['MSVS_VERSION < "2015"', {
'sources': [
'src/win/snprintf.c'
]
}]
],
'link_settings': {
'libraries': [
'-ladvapi32',
......@@ -247,6 +241,7 @@
'_ALL_SOURCE',
'_XOPEN_SOURCE=500',
'_LINUX_SOURCE_COMPAT',
'_THREAD_SAFE',
],
'link_settings': {
'libraries': [
......@@ -300,6 +295,7 @@
'test/test-cwd-and-chdir.c',
'test/test-default-loop-close.c',
'test/test-delayed-accept.c',
'test/test-eintr-handling.c',
'test/test-error.c',
'test/test-embed.c',
'test/test-emfile.c',
......@@ -308,6 +304,7 @@
'test/test-fs-event.c',
'test/test-get-currentexe.c',
'test/test-get-memory.c',
'test/test-get-passwd.c',
'test/test-getaddrinfo.c',
'test/test-getnameinfo.c',
'test/test-getsockname.c',
......@@ -386,6 +383,7 @@
'test/test-threadpool.c',
'test/test-threadpool-cancel.c',
'test/test-thread-equal.c',
'test/test-tmpdir.c',
'test/test-mutexes.c',
'test/test-thread.c',
'test/test-barrier.c',
......@@ -417,7 +415,8 @@
[ 'OS=="win"', {
'sources': [
'test/runner-win.c',
'test/runner-win.h'
'test/runner-win.h',
'src/win/snprintf.c',
],
'libraries': [ '-lws2_32' ]
}, { # POSIX
......@@ -427,6 +426,11 @@
'test/runner-unix.h',
],
}],
[ 'OS in "mac dragonflybsd freebsd linux netbsd openbsd".split()', {
'link_settings': {
'libraries': [ '-lutil' ],
},
}],
[ 'OS=="solaris"', { # make test-fs.c compile, needs _POSIX_C_SOURCE
'defines': [
'__EXTENSIONS__',
......@@ -485,6 +489,7 @@
'sources': [
'test/runner-win.c',
'test/runner-win.h',
'src/win/snprintf.c',
],
'libraries': [ '-lws2_32' ]
}, { # POSIX
......
......@@ -49,6 +49,7 @@ if not defined VS140COMNTOOLS goto vc-set-2013
if not exist "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2013
call "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
set GYP_MSVS_VERSION=2015
echo Using Visual Studio 2015
goto select-target
:vc-set-2013
......@@ -57,6 +58,7 @@ if not defined VS120COMNTOOLS goto vc-set-2012
if not exist "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2012
call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
set GYP_MSVS_VERSION=2013
echo Using Visual Studio 2013
goto select-target
:vc-set-2012
......@@ -65,6 +67,7 @@ if not defined VS110COMNTOOLS goto vc-set-2010
if not exist "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2010
call "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
set GYP_MSVS_VERSION=2012
echo Using Visual Studio 2012
goto select-target
:vc-set-2010
......@@ -73,6 +76,7 @@ if not defined VS100COMNTOOLS goto vc-set-2008
if not exist "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2008
call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
set GYP_MSVS_VERSION=2010
echo Using Visual Studio 2010
goto select-target
:vc-set-2008
......@@ -81,6 +85,7 @@ if not defined VS90COMNTOOLS goto vc-set-notfound
if not exist "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-notfound
call "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
set GYP_MSVS_VERSION=2008
echo Using Visual Studio 2008
goto select-target
:vc-set-notfound
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment