2018.10.09, Version 1.23.2 (Stable)

Changes since version 1.23.1:
 
 * unix: return 0 retrieving rss on cygwin (cjihrig)
 
 * unix: initialize uv_interface_address_t.phys_addr (cjihrig)
 
 * test: handle uv_os_setpriority() windows edge case (cjihrig)
 
 * tty, win: fix read stop for raw mode (Bartosz Sosnowski)
 
 * Revert "Revert "unix,fs: fix for potential partial reads/writes"" (Jameson
   Nash)
 
 * unix,readv: always permit partial reads to return (Jameson Nash)
 
 * win,tty: fix uv_tty_close() (Bartosz Sosnowski)
 
 * doc: remove extraneous "on" (Ben Noordhuis)
 
 * unix,win: fix threadpool race condition (Anna Henningsen)
 
 * unix: rework thread barrier implementation (Ben Noordhuis)
 
 * aix: switch to libuv's own thread barrier impl (Ben Noordhuis)
 
 * unix: signal done to last thread barrier waiter (Ben Noordhuis)
 
 * test: add uv_barrier_wait serial thread test (Ali Ijaz Sheikh)
 
 * unix: optimize uv_fs_readlink() memory allocation (Ben Noordhuis)
 
 * win: remove req.c and other cleanup (Carlo Marcelo Arenas Belón)
 
 * aix: don't EISDIR on read from directory fd (Ben Noordhuis)
 -----BEGIN PGP SIGNATURE-----
 Comment: GPGTools - https://gpgtools.org
 
 iQIzBAABCgAdFiEElK42Z1xGTWS6+mjddDQ5C9vpucUFAlu7i04ACgkQdDQ5C9vp
 ucVulxAApmLPfx+89/GC2u9Jcv5N9yHBNxFh1WGf+EC6qCtikjQuhz/FmTHP/pzg
 Z+QbLJ3XBob6HeE5oestn9pap2XIg/GhGhGH0unp5EBTGkzR9HTn1IyKquzvR0kh
 A/seLAMTnrDae7i4NmAnbwjwW61mUEtpe+yu3Zrk2jLLpbprcJ867W8Z2Z0jbCu0
 VPZpdULx/gMJ0HjJ/bWt8j7yb+Unegt/1J/WweTy61Q0yBGuJ6v7nm0/Me6MkAJL
 SPXZqDL4UhEMV/HD+VpEGp5lRlPDtze/f6RX2o41EW79W5Ev5la6Pj1Mvf9DIkLp
 H0AgJsYRh3M0iYI2uHZbw/OD5PanjbvR9O7A743BRjkjvByuOsZwpZLjhAKMpnuv
 RlVzxDc3Vy8QfazMbUZ9XqzGMEyvoSZcDKGNLOOuCjF/JVJr6SUIRO/TvzDYumbv
 +zJJjkkeP1KrMI0+fMNin3zKmPkz6i9F9NZRzES8V1UPKZ+WECGadAn0iVQ892P3
 MUqjQtwc1YGgI66qoAufNjjTqi+2zBiMbz/b9ZlVLsOQjbVY3nCUTxBaUXRSruFR
 H+oTdn8ky0z0hcP9rsGHmFRrRJT5YO8Y61DSye8VpyvrxmxxzHCdyWV99b/ewmbD
 NRZBVxOBTN93Iu6vNkaAZHmOF59iRKHBIfjAsOYdTJg5mdBF3vc=
 =dR1F
 -----END PGP SIGNATURE-----

Merge tag 'v1.23.2' into merge_1.23.2

PR-URL: https://github.com/libuv/libuv/pull/2067
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
Jameson Nash 2018-11-05 12:54:19 -05:00
commit f6b3c7420f
60 changed files with 1145 additions and 640 deletions

View File

@ -346,3 +346,9 @@ Paolo Greppi <paolo.greppi@libpf.com>
Shelley Vohr <shelley.vohr@gmail.com>
Ujjwal Sharma <usharma1998@gmail.com>
Michał Kozakiewicz <michalkozakiewicz3@gmail.com>
Emil Bay <github@tixz.dk>
Jeremiah Senkpiel <fishrock123@rocketmail.com>
Andy Zhang <zhangyong232@gmail.com>
dmabupt <dmabupt@gmail.com>
Ryan Liptak <squeek502@hotmail.com>
Ali Ijaz Sheikh <ofrobots@google.com>

View File

@ -195,7 +195,6 @@ if(WIN32)
src/win/poll.c
src/win/process.c
src/win/process-stdio.c
src/win/req.c
src/win/signal.c
src/win/snprintf.c
src/win/stream.c

View File

@ -1,4 +1,88 @@
2018.08.18, Version 1.23.0 (Stable)
2018.10.09, Version 1.23.2 (Stable)
Changes since version 1.23.1:
* unix: return 0 retrieving rss on cygwin (cjihrig)
* unix: initialize uv_interface_address_t.phys_addr (cjihrig)
* test: handle uv_os_setpriority() windows edge case (cjihrig)
* tty, win: fix read stop for raw mode (Bartosz Sosnowski)
* Revert "Revert "unix,fs: fix for potential partial reads/writes"" (Jameson
Nash)
* unix,readv: always permit partial reads to return (Jameson Nash)
* win,tty: fix uv_tty_close() (Bartosz Sosnowski)
* doc: remove extraneous "on" (Ben Noordhuis)
* unix,win: fix threadpool race condition (Anna Henningsen)
* unix: rework thread barrier implementation (Ben Noordhuis)
* aix: switch to libuv's own thread barrier impl (Ben Noordhuis)
* unix: signal done to last thread barrier waiter (Ben Noordhuis)
* test: add uv_barrier_wait serial thread test (Ali Ijaz Sheikh)
* unix: optimize uv_fs_readlink() memory allocation (Ben Noordhuis)
* win: remove req.c and other cleanup (Carlo Marcelo Arenas Belón)
* aix: don't EISDIR on read from directory fd (Ben Noordhuis)
2018.09.22, Version 1.23.1 (Stable), d2282b3d67821dc53c907c2155fa8c5c6ce25180
Changes since version 1.23.0:
* unix,win: limit concurrent DNS calls to nthreads/2 (Anna Henningsen)
* doc: add addaleax to maintainers (Anna Henningsen)
* doc: add missing slash in stream.rst (Emil Bay)
* unix,fs: use utimes & friends for uv_fs_utime (Jeremiah Senkpiel)
* unix,fs: remove linux fallback from utimesat() (Jeremiah Senkpiel)
* unix,fs: remove uv__utimesat() syscall fallback (Jeremiah Senkpiel)
* doc: fix argument name in tcp.rts (Emil Bay)
* doc: notes on running tests, benchmarks, tools (Jamie Davis)
* linux: remove epoll syscall wrappers (Ben Noordhuis)
* linux: drop code path for epoll_pwait-less kernels (Ben Noordhuis)
* Partially revert "win,code: remove GetQueuedCompletionStatus-based poller"
(Jameson Nash)
* build: add compile for android arm64/x86/x86-64 (Andy Zhang)
* doc: clarify that some remarks apply to windows (Bert Belder)
* test: fix compiler warnings (Jamie Davis)
* ibmi: return 0 from uv_resident_set_memory() (dmabupt)
* win: fix uv_udp_recv_start() error translation (Ryan Liptak)
* win,doc: improve uv_os_setpriority() documentation (Bartosz Sosnowski)
* test: increase upper bound in condvar_5 (Jamie Davis)
* win,tty: remove deadcode (Jameson Nash)
* stream: autodetect direction (Jameson Nash)
2018.08.18, Version 1.23.0 (Stable), 7ebb26225f2eaae6db22f4ef34ce76fa16ff89ec
Changes since version 1.22.0:

View File

@ -3,6 +3,7 @@
libuv is currently managed by the following individuals:
* **Anna Henningsen** ([@addaleax](https://github.com/addaleax))
* **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz))
* **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis))
- GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis)

View File

@ -67,7 +67,6 @@ libuv_la_SOURCES += src/win/async.c \
src/win/poll.c \
src/win/process-stdio.c \
src/win/process.c \
src/win/req.c \
src/win/req-inl.h \
src/win/signal.c \
src/win/stream.c \
@ -340,8 +339,7 @@ libuv_la_SOURCES += src/unix/aix.c src/unix/aix-common.c
endif
if ANDROID
uvinclude_HEADERS += include/uv/android-ifaddrs.h \
include/uv/pthread-barrier.h
uvinclude_HEADERS += include/uv/android-ifaddrs.h
libuv_la_SOURCES += src/unix/android-ifaddrs.c \
src/unix/pthread-fixes.c
endif
@ -361,8 +359,7 @@ libuv_la_SOURCES += src/unix/cygwin.c \
endif
if DARWIN
uvinclude_HEADERS += include/uv/darwin.h \
include/uv/pthread-barrier.h
uvinclude_HEADERS += include/uv/darwin.h
libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1
libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1
libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \
@ -445,7 +442,6 @@ libuv_la_SOURCES += src/unix/no-proctitle.c \
endif
if OS390
uvinclude_HEADERS += include/uv/pthread-barrier.h
libuv_la_CFLAGS += -D_UNIX03_THREADS \
-D_UNIX03_SOURCE \
-D_OPEN_SYS_IF_EXT=1 \

View File

@ -282,8 +282,31 @@ Make sure that you specify the architecture you wish to build for in the
Run:
For arm
```bash
$ source ./android-configure NDK_PATH gyp [API_LEVEL]
$ source ./android-configure-arm NDK_PATH gyp [API_LEVEL]
$ make -C out
```
or for arm64
```bash
$ source ./android-configure-arm64 NDK_PATH gyp [API_LEVEL]
$ make -C out
```
or for x86
```bash
$ source ./android-configure-x86 NDK_PATH gyp [API_LEVEL]
$ make -C out
```
or for x86_64
```bash
$ source ./android-configure-x86_64 NDK_PATH gyp [API_LEVEL]
$ make -C out
```
@ -310,14 +333,66 @@ $ ninja -C out/Release
### Running tests
Run:
#### Build
Build (includes tests):
```bash
$ ./gyp_uv.py -f make
$ make -C out
```
#### Run all tests
```bash
$ ./out/Debug/run-tests
```
#### Run one test
The list of all tests is in `test/test-list.h`.
This invocation will cause the `run-tests` driver to fork and execute `TEST_NAME` in a child process:
```bash
$ ./out/Debug/run-tests TEST_NAME
```
This invocation will cause the `run-tests` driver to execute the test within the `run-tests` process:
```bash
$ ./out/Debug/run-tests TEST_NAME TEST_NAME
```
#### Debugging tools
When running the test from within the `run-tests` process (`run-tests TEST_NAME TEST_NAME`), tools like gdb and valgrind work normally.
When running the test from a child of the `run-tests` process (`run-tests TEST_NAME`), use these tools in a fork-aware manner.
##### Fork-aware gdb
Use the [follow-fork-mode](https://sourceware.org/gdb/onlinedocs/gdb/Forks.html) setting:
```
$ gdb --args out/Debug/run-tests TEST_NAME
(gdb) set follow-fork-mode child
...
```
##### Fork-aware valgrind
Use the `--trace-children=yes` parameter:
```bash
$ valgrind --trace-children=yes -v --tool=memcheck --leak-check=full --track-origins=yes --leak-resolution=high --show-reachable=yes --log-file=memcheck.log out/Debug/run-tests TEST_NAME
```
### Running benchmarks
See the section on running tests.
The benchmark driver is `out/Debug/run-benchmarks` and the benchmarks are listed in `test/benchmark-list.h`.
## Supported Platforms
Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md).

View File

@ -1,6 +1,6 @@
#!/bin/bash
export TOOLCHAIN=$PWD/android-toolchain
export TOOLCHAIN=$PWD/android-toolchain-arm
mkdir -p $TOOLCHAIN
API=${3:-24}
$1/build/tools/make-standalone-toolchain.sh \

23
android-configure-arm64 Executable file
View File

@ -0,0 +1,23 @@
#!/bin/bash
export TOOLCHAIN=$PWD/android-toolchain-arm64
mkdir -p $TOOLCHAIN
API=${3:-24}
$1/build/tools/make-standalone-toolchain.sh \
--toolchain=aarch64-linux-android-4.9 \
--arch=arm64 \
--install-dir=$TOOLCHAIN \
--platform=android-$API \
--force
export PATH=$TOOLCHAIN/bin:$PATH
export AR=aarch64-linux-android-ar
export CC=aarch64-linux-android-gcc
export CXX=aarch64-linux-android-g++
export LINK=aarch64-linux-android-g++
export PLATFORM=android
export CFLAGS="-D__ANDROID_API__=$API"
if [[ $2 == 'gyp' ]]
then
./gyp_uv.py -Dtarget_arch=arm64 -DOS=android -f make-android
fi

23
android-configure-x86 Executable file
View File

@ -0,0 +1,23 @@
#!/bin/bash
export TOOLCHAIN=$PWD/android-toolchain-x86
mkdir -p $TOOLCHAIN
API=${3:-24}
$1/build/tools/make-standalone-toolchain.sh \
--toolchain=x86-4.9 \
--arch=x86 \
--install-dir=$TOOLCHAIN \
--platform=android-$API \
--force
export PATH=$TOOLCHAIN/bin:$PATH
export AR=i686-linux-android-ar
export CC=i686-linux-android-gcc
export CXX=i686-linux-android-g++
export LINK=i686-linux-android-g++
export PLATFORM=android
export CFLAGS="-D__ANDROID_API__=$API"
if [[ $2 == 'gyp' ]]
then
./gyp_uv.py -Dtarget_arch=x86 -DOS=android -f make-android
fi

25
android-configure-x86_64 Executable file
View File

@ -0,0 +1,25 @@
#!/bin/bash
export TOOLCHAIN=$PWD/android-toolchain-x86_64
mkdir -p $TOOLCHAIN
API=${3:-24}
$1/build/tools/make-standalone-toolchain.sh \
--toolchain=x86_64-4.9 \
--arch=x86_64 \
--install-dir=$TOOLCHAIN \
--platform=android-$API \
--force
export PATH=$TOOLCHAIN/bin:$PATH
export AR=x86_64-linux-android-ar
export CC=x86_64-linux-android-gcc
export CXX=x86_64-linux-android-g++
export LINK=x86_64-linux-android-g++
export PLATFORM=android
export CFLAGS="-D__ANDROID_API__=$API -fPIC"
export CXXFLAGS="-D__ANDROID_API__=$API -fPIC"
export LDFLAGS="-fPIC"
if [[ $2 == 'gyp' ]]
then
./gyp_uv.py -Dtarget_arch=x86_64 -DOS=android -f make-android
fi

View File

@ -32,7 +32,7 @@ void update(uv_timer_t *req) {
int main() {
loop = uv_default_loop();
uv_tty_init(loop, &tty, 1, 0);
uv_tty_init(loop, &tty, STDOUT_FILENO, 0);
uv_tty_set_mode(&tty, 0);
if (uv_tty_get_winsize(&tty, &width, &height)) {

View File

@ -8,7 +8,7 @@ uv_tty_t tty;
int main() {
loop = uv_default_loop();
uv_tty_init(loop, &tty, 1, 0);
uv_tty_init(loop, &tty, STDOUT_FILENO, 0);
uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL);
if (uv_guess_handle(1) == UV_TTY) {

View File

@ -126,7 +126,7 @@ so the current approach is to run blocking file I/O operations in a thread pool.
For a thorough explanation of the cross-platform file I/O landscape, checkout
`this post <http://blog.libtorrent.org/2012/10/asynchronous-disk-io/>`_.
libuv currently uses a global thread pool on which all loops can queue work on. 3 types of
libuv currently uses a global thread pool on which all loops can queue work. 3 types of
operations are currently run on this pool:
* File system operations

View File

@ -370,9 +370,10 @@ terminal information.
The first thing to do is to initialize a ``uv_tty_t`` with the file descriptor
it reads/writes from. This is achieved with::
int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_os_fd_t fd, int readable)
int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_os_fd_t fd, int unused)
Set ``readable`` to true if you plan to use ``uv_read_start()`` on the stream.
The ``unused`` parameter is now auto-detected and ignored. It previously needed
to be set to use ``uv_read_start()`` on the stream.
It is then best to use ``uv_tty_set_mode`` to set the mode to *normal*
which enables most TTY formatting, flow-control and other settings. Other_ modes
@ -423,6 +424,9 @@ can try `ncurses`_.
.. _ncurses: http://www.gnu.org/software/ncurses/ncurses.html
.. versionchanged:: 1.23.1: the `readable` parameter is now unused and ignored.
The appropriate value will now be auto-detected from the kernel.
----
.. [#] I was first introduced to the term baton in this context, in Konstantin

View File

@ -557,4 +557,8 @@ API
process priority, the result will equal one of the `UV_PRIORITY`
constants, and not necessarily the exact value of `priority`.
.. note::
On Windows, setting `PRIORITY_HIGHEST` will only work for elevated user,
for others it will be silently reduced to `PRIORITY_HIGH`.
.. versionadded:: 1.23.0

View File

@ -17,12 +17,12 @@ Reception of some signals is emulated on Windows:
program is given approximately 10 seconds to perform cleanup. After that
Windows will unconditionally terminate it.
Watchers for other signals can be successfully created, but these signals
are never received. These signals are: `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`,
`SIGTERM` and `SIGKILL.`
* Watchers for other signals can be successfully created, but these signals
are never received. These signals are: `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`,
`SIGTERM` and `SIGKILL.`
Calls to raise() or abort() to programmatically raise a signal are
not detected by libuv; these will not trigger a signal watcher.
* Calls to raise() or abort() to programmatically raise a signal are
not detected by libuv; these will not trigger a signal watcher.
.. note::
On Linux SIGRT0 and SIGRT1 (signals 32 and 33) are used by the NPTL pthreads library to

View File

@ -45,7 +45,7 @@ Data types
`nread` might be 0, which does *not* indicate an error or EOF. This
is equivalent to ``EAGAIN`` or ``EWOULDBLOCK`` under ``read(2)``.
The callee is responsible for stopping closing the stream when an error happens
The callee is responsible for stopping/closing the stream when an error happens
by calling :c:func:`uv_read_stop` or :c:func:`uv_close`. Trying to read
from the stream again is undefined.

View File

@ -86,13 +86,13 @@ API
.. c:function:: int uv_tcp_getsockname(const uv_tcp_t* handle, struct sockaddr* name, int* namelen)
Get the current address to which the handle is bound. `addr` must point to
Get the current address to which the handle is bound. `name` must point to
a valid and big enough chunk of memory, ``struct sockaddr_storage`` is
recommended for IPv4 and IPv6 support.
.. c:function:: int uv_tcp_getpeername(const uv_tcp_t* handle, struct sockaddr* name, int* namelen)
Get the address of the peer connected to the handle. `addr` must point to
Get the address of the peer connected to the handle. `name` must point to
a valid and big enough chunk of memory, ``struct sockaddr_storage`` is
recommended for IPv4 and IPv6 support.

View File

@ -46,7 +46,7 @@ N/A
API
---
.. c:function:: int uv_tty_init(uv_loop_t* loop, uv_tty_t* handle, uv_os_fd_t fd, int readable)
.. c:function:: int uv_tty_init(uv_loop_t* loop, uv_tty_t* handle, uv_os_fd_t fd, int unused)
Initialize a new TTY stream with the given file descriptor. Usually the
file descriptor will be:
@ -55,9 +55,6 @@ API
* 1 = stdout
* 2 = stderr
`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 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
@ -67,8 +64,10 @@ API
ioctl TIOCGPTN or TIOCPTYGNAME, for instance OpenBSD and Solaris.
.. note::
If reopening the TTY fails, libuv falls back to blocking writes for
non-readable TTY streams.
If reopening the TTY fails, libuv falls back to blocking writes.
.. versionchanged:: 1.23.1: the `readable` parameter is now unused and ignored.
The correct value will now be auto-detected from the kernel.
.. versionchanged:: 1.9.0: the path of the TTY is determined by
:man:`ttyname_r(3)`. In earlier versions libuv opened

View File

@ -1,40 +0,0 @@
/*
Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _UV_PTHREAD_BARRIER_
#define _UV_PTHREAD_BARRIER_
#include <errno.h>
#include <pthread.h>
#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345
#define UV__PTHREAD_BARRIER_FALLBACK 1
typedef struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
unsigned threshold;
unsigned in;
unsigned out;
} pthread_barrier_t;
int pthread_barrier_init(pthread_barrier_t* barrier,
const void* barrier_attr,
unsigned count);
int pthread_barrier_wait(pthread_barrier_t* barrier);
int pthread_barrier_destroy(pthread_barrier_t *barrier);
#endif /* _UV_PTHREAD_BARRIER_ */

View File

@ -66,10 +66,6 @@
# include "uv/posix.h"
#endif
#ifndef PTHREAD_BARRIER_SERIAL_THREAD
# include "uv/pthread-barrier.h"
#endif
#ifndef NI_MAXHOST
# define NI_MAXHOST 1025
#endif
@ -135,8 +131,19 @@ typedef pthread_rwlock_t uv_rwlock_t;
typedef UV_PLATFORM_SEM_T uv_sem_t;
typedef pthread_cond_t uv_cond_t;
typedef pthread_key_t uv_key_t;
typedef pthread_barrier_t uv_barrier_t;
/* Note: guard clauses should match uv_barrier_init's in src/unix/thread.c. */
#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD)
typedef struct {
uv_mutex_t mutex;
uv_cond_t cond;
unsigned threshold;
unsigned in;
unsigned out;
} uv_barrier_t;
#else
typedef pthread_barrier_t uv_barrier_t;
#endif
/* Platform-specific definitions for uv_spawn support. */
typedef gid_t uv_gid_t;

View File

@ -33,12 +33,18 @@ static uv_once_t once = UV_ONCE_INIT;
static uv_cond_t cond;
static uv_mutex_t mutex;
static unsigned int idle_threads;
static unsigned int slow_io_work_running;
static unsigned int nthreads;
static uv_thread_t* threads;
static uv_thread_t default_threads[4];
static QUEUE exit_message;
static QUEUE wq;
static QUEUE run_slow_work_message;
static QUEUE slow_io_pending_wq;
static unsigned int slow_work_thread_threshold(void) {
return (nthreads + 1) / 2;
}
static void uv__cancelled(struct uv__work* w) {
abort();
@ -51,34 +57,67 @@ static void uv__cancelled(struct uv__work* w) {
static void worker(void* arg) {
struct uv__work* w;
QUEUE* q;
int is_slow_work;
uv_sem_post((uv_sem_t*) arg);
arg = NULL;
uv_mutex_lock(&mutex);
for (;;) {
uv_mutex_lock(&mutex);
/* `mutex` should always be locked at this point. */
while (QUEUE_EMPTY(&wq)) {
/* Keep waiting while either no work is present or only slow I/O
and we're at the threshold for that. */
while (QUEUE_EMPTY(&wq) ||
(QUEUE_HEAD(&wq) == &run_slow_work_message &&
QUEUE_NEXT(&run_slow_work_message) == &wq &&
slow_io_work_running >= slow_work_thread_threshold())) {
idle_threads += 1;
uv_cond_wait(&cond, &mutex);
idle_threads -= 1;
}
q = QUEUE_HEAD(&wq);
if (q == &exit_message)
if (q == &exit_message) {
uv_cond_signal(&cond);
else {
uv_mutex_unlock(&mutex);
break;
}
QUEUE_REMOVE(q);
QUEUE_INIT(q); /* Signal uv_cancel() that the work req is executing. */
is_slow_work = 0;
if (q == &run_slow_work_message) {
/* If we're at the slow I/O threshold, re-schedule until after all
other work in the queue is done. */
if (slow_io_work_running >= slow_work_thread_threshold()) {
QUEUE_INSERT_TAIL(&wq, q);
continue;
}
/* If we encountered a request to run slow I/O work but there is none
to run, that means it's cancelled => Start over. */
if (QUEUE_EMPTY(&slow_io_pending_wq))
continue;
is_slow_work = 1;
slow_io_work_running++;
q = QUEUE_HEAD(&slow_io_pending_wq);
QUEUE_REMOVE(q);
QUEUE_INIT(q); /* Signal uv_cancel() that the work req is
executing. */
QUEUE_INIT(q);
/* If there is more slow I/O work, schedule it to be run as well. */
if (!QUEUE_EMPTY(&slow_io_pending_wq)) {
QUEUE_INSERT_TAIL(&wq, &run_slow_work_message);
if (idle_threads > 0)
uv_cond_signal(&cond);
}
}
uv_mutex_unlock(&mutex);
if (q == &exit_message)
break;
w = QUEUE_DATA(q, struct uv__work, wq);
w->work(w);
@ -88,12 +127,32 @@ static void worker(void* arg) {
QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
uv_async_send(&w->loop->wq_async);
uv_mutex_unlock(&w->loop->wq_mutex);
/* Lock `mutex` since that is expected at the start of the next
* iteration. */
uv_mutex_lock(&mutex);
if (is_slow_work) {
/* `slow_io_work_running` is protected by `mutex`. */
slow_io_work_running--;
}
}
}
static void post(QUEUE* q) {
static void post(QUEUE* q, enum uv__work_kind kind) {
uv_mutex_lock(&mutex);
if (kind == UV__WORK_SLOW_IO) {
/* Insert into a separate queue. */
QUEUE_INSERT_TAIL(&slow_io_pending_wq, q);
if (!QUEUE_EMPTY(&run_slow_work_message)) {
/* Running slow I/O tasks is already scheduled => Nothing to do here.
The worker that runs said other task will schedule this one as well. */
uv_mutex_unlock(&mutex);
return;
}
q = &run_slow_work_message;
}
QUEUE_INSERT_TAIL(&wq, q);
if (idle_threads > 0)
uv_cond_signal(&cond);
@ -108,7 +167,7 @@ UV_DESTRUCTOR(static void cleanup(void)) {
if (nthreads == 0)
return;
post(&exit_message);
post(&exit_message, UV__WORK_CPU);
for (i = 0; i < nthreads; i++)
if (uv_thread_join(threads + i))
@ -156,6 +215,8 @@ static void init_threads(void) {
abort();
QUEUE_INIT(&wq);
QUEUE_INIT(&slow_io_pending_wq);
QUEUE_INIT(&run_slow_work_message);
if (uv_sem_init(&sem, 0))
abort();
@ -194,13 +255,14 @@ static void init_once(void) {
void uv__work_submit(uv_loop_t* loop,
struct uv__work* w,
enum uv__work_kind kind,
void (*work)(struct uv__work* w),
void (*done)(struct uv__work* w, int status)) {
uv_once(&once, init_once);
w->loop = loop;
w->work = work;
w->done = done;
post(&w->wq);
post(&w->wq, kind);
}
@ -284,7 +346,11 @@ int uv_queue_work(uv_loop_t* loop,
req->loop = loop;
req->work_cb = work_cb;
req->after_work_cb = after_work_cb;
uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done);
uv__work_submit(loop,
&req->work_req,
UV__WORK_CPU,
uv__queue_work,
uv__queue_done);
return 0;
}

View File

@ -119,16 +119,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
continue;
address = *addresses;
memset(address->phys_addr, 0, sizeof(address->phys_addr));
for (i = 0; i < *count; i++) {
if (strcmp(address->name, ent->ifa_name) == 0) {
#if defined(__CYGWIN__) || defined(__MSYS__)
memset(address->phys_addr, 0, sizeof(address->phys_addr));
#else
struct sockaddr_dl* sa_addr;
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
#endif
}
address++;
}

View File

@ -38,7 +38,7 @@ int uv_uptime(double* uptime) {
int uv_resident_set_memory(size_t* rss) {
/* FIXME: read /proc/meminfo? */
*rss = 0;
return UV_ENOSYS;
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {

View File

@ -44,7 +44,6 @@
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <utime.h>
#include <poll.h>
#if defined(__DragonFly__) || \
@ -111,6 +110,10 @@ static void uv__prepare_setattrlist_args(uv_fs_t* req,
# define FICLONE _IOW(0x94, 9, int)
#endif
#if defined(_AIX) && !defined(_AIX71)
# include <utime.h>
#endif
#define INIT(subtype) \
do { \
if (req == NULL) \
@ -164,7 +167,11 @@ static void uv__prepare_setattrlist_args(uv_fs_t* req,
do { \
if (cb != NULL) { \
uv__req_register(loop, req); \
uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
uv__work_submit(loop, \
&req->work_req, \
UV__WORK_FAST_IO, \
uv__fs_work, \
uv__fs_done); \
return 0; \
} \
else { \
@ -178,7 +185,11 @@ static void uv__prepare_setattrlist_args(uv_fs_t* req,
do { \
if (cb != NULL) { \
uv__req_register(loop, req); \
uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
uv__work_submit(loop, \
&req->work_req, \
UV__WORK_FAST_IO, \
uv__fs_work, \
uv__fs_done); \
return 0; \
} \
else { \
@ -225,58 +236,17 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
static ssize_t uv__fs_futime(uv_fs_t* req) {
#if defined(__linux__)
#if defined(__linux__) \
|| defined(_AIX71)
/* utimesat() has nanosecond resolution but we stick to microseconds
* for the sake of consistency with other platforms.
*/
static int no_utimesat;
struct timespec ts[2];
struct timeval tv[2];
char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)];
int r;
if (no_utimesat)
goto skip;
ts[0].tv_sec = req->atime;
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
ts[1].tv_sec = req->mtime;
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
r = uv__utimesat(req->file, NULL, ts, 0);
if (r == 0)
return r;
if (errno != ENOSYS)
return r;
no_utimesat = 1;
skip:
tv[0].tv_sec = req->atime;
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
tv[1].tv_sec = req->mtime;
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file);
r = utimes(path, tv);
if (r == 0)
return r;
switch (errno) {
case ENOENT:
if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF)
break;
/* Fall through. */
case EACCES:
case ENOTDIR:
errno = ENOSYS;
break;
}
return r;
return futimens(req->file, ts);
#elif defined(__APPLE__)
struct attrlist attr_list;
unsigned i;
@ -301,13 +271,6 @@ skip:
# else
return futimes(req->file, tv);
# endif
#elif defined(_AIX71)
struct timespec ts[2];
ts[0].tv_sec = req->atime;
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
ts[1].tv_sec = req->mtime;
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
return futimens(req->file, ts);
#elif defined(__MVS__)
attrib_t atr;
memset(&atr, 0, sizeof(atr));
@ -370,17 +333,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
#if defined(__linux__)
static int no_preadv;
#endif
unsigned int iovmax;
ssize_t result;
#if defined(_AIX)
struct stat buf;
if(fstat(req->file, &buf))
return -1;
if(S_ISDIR(buf.st_mode)) {
errno = EISDIR;
return -1;
}
#endif /* defined(_AIX) */
iovmax = uv__getiovmax();
if (req->nbufs > iovmax)
req->nbufs = iovmax;
if (req->off < 0) {
if (req->nbufs == 1)
result = read(req->file, req->bufs[0].base, req->bufs[0].len);
@ -399,25 +358,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
if (no_preadv) retry:
# endif
{
off_t nread;
size_t index;
nread = 0;
index = 0;
result = 1;
do {
if (req->bufs[index].len > 0) {
result = pread(req->file,
req->bufs[index].base,
req->bufs[index].len,
req->off + nread);
if (result > 0)
nread += result;
}
index++;
} while (index < req->nbufs && result > 0);
if (nread > 0)
result = nread;
result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
}
# if defined(__linux__)
else {
@ -435,6 +376,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
}
done:
/* Early cleanup of bufs allocation, since we're done with it. */
if (req->bufs != req->bufsml)
uv__free(req->bufs);
req->bufs = NULL;
req->nbufs = 0;
return result;
}
@ -492,11 +440,13 @@ static ssize_t uv__fs_pathmax_size(const char* path) {
}
static ssize_t uv__fs_readlink(uv_fs_t* req) {
ssize_t maxlen;
ssize_t len;
char* buf;
char* newbuf;
len = uv__fs_pathmax_size(req->path);
buf = uv__malloc(len + 1);
maxlen = uv__fs_pathmax_size(req->path);
buf = uv__malloc(maxlen);
if (buf == NULL) {
errno = ENOMEM;
@ -504,17 +454,28 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
}
#if defined(__MVS__)
len = os390_readlink(req->path, buf, len);
len = os390_readlink(req->path, buf, maxlen);
#else
len = readlink(req->path, buf, len);
len = readlink(req->path, buf, maxlen);
#endif
if (len == -1) {
uv__free(buf);
return -1;
}
/* Uncommon case: resize to make room for the trailing nul byte. */
if (len == maxlen) {
newbuf = uv__realloc(buf, len + 1);
if (newbuf == NULL) {
uv__free(buf);
return -1;
}
buf = newbuf;
}
buf[len] = '\0';
req->ptr = buf;
@ -757,7 +718,19 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
static ssize_t uv__fs_utime(uv_fs_t* req) {
#if defined(__APPLE__)
#if defined(__linux__) \
|| defined(_AIX71) \
|| defined(__sun)
/* utimesat() has nanosecond resolution but we stick to microseconds
* for the sake of consistency with other platforms.
*/
struct timespec ts[2];
ts[0].tv_sec = req->atime;
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
ts[1].tv_sec = req->mtime;
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
return utimensat(AT_FDCWD, req->path, ts, 0);
#elif defined(__APPLE__)
struct attrlist attr_list;
unsigned i;
struct timespec times[3];
@ -765,11 +738,34 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
uv__prepare_setattrlist_args(req, &attr_list, &times, &i);
return setattrlist(req->path, &attr_list, &times, i * sizeof(times[0]), 0);
#else
#elif defined(__DragonFly__) \
|| defined(__FreeBSD__) \
|| defined(__FreeBSD_kernel__) \
|| defined(__NetBSD__) \
|| defined(__OpenBSD__)
struct timeval tv[2];
tv[0].tv_sec = req->atime;
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
tv[1].tv_sec = req->mtime;
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
return utimes(req->path, tv);
#elif defined(_AIX) \
&& !defined(_AIX71)
struct utimbuf buf;
buf.actime = req->atime;
buf.modtime = req->mtime;
return utime(req->path, &buf); /* TODO use utimes() where available */
return utime(req->path, &buf);
#elif defined(__MVS__)
attrib_t atr;
memset(&atr, 0, sizeof(atr));
atr.att_mtimechg = 1;
atr.att_atimechg = 1;
atr.att_mtime = req->mtime;
atr.att_atime = req->atime;
return __lchattr(req->path, &atr, sizeof(atr));
#else
errno = ENOSYS;
return -1;
#endif
}
@ -808,25 +804,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
if (no_pwritev) retry:
# endif
{
off_t written;
size_t index;
written = 0;
index = 0;
r = 0;
do {
if (req->bufs[index].len > 0) {
r = pwrite(req->file,
req->bufs[index].base,
req->bufs[index].len,
req->off + written);
if (r > 0)
written += r;
}
index++;
} while (index < req->nbufs && r >= 0);
if (written > 0)
r = written;
r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
}
# if defined(__linux__)
else {
@ -1120,9 +1098,21 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) {
return ret;
}
static size_t uv__fs_buf_offset(uv_buf_t* bufs, size_t size) {
size_t offset;
/* Figure out which bufs are done */
for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset)
size -= bufs[offset].len;
typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req);
static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) {
/* Fix a partial read/write */
if (size > 0) {
bufs[offset].base += size;
bufs[offset].len -= size;
}
return offset;
}
static ssize_t uv__fs_write_all(uv_fs_t* req) {
unsigned int iovmax;
unsigned int nbufs;
uv_buf_t* bufs;
@ -1139,7 +1129,10 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process)
if (req->nbufs > iovmax)
req->nbufs = iovmax;
result = process(req);
do
result = uv__fs_write(req);
while (result < 0 && errno == EINTR);
if (result <= 0) {
if (total == 0)
total = result;
@ -1149,14 +1142,12 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process)
if (req->off >= 0)
req->off += result;
req->nbufs = uv__fs_buf_offset(req->bufs, result);
req->bufs += req->nbufs;
nbufs -= req->nbufs;
total += result;
}
if (errno == EINTR && total == -1)
return total;
if (bufs != req->bufsml)
uv__free(bufs);
@ -1173,7 +1164,8 @@ static void uv__fs_work(struct uv__work* w) {
ssize_t r;
req = container_of(w, uv_fs_t, work_req);
retry_on_eintr = !(req->fs_type == UV_FS_CLOSE);
retry_on_eintr = !(req->fs_type == UV_FS_CLOSE ||
req->fs_type == UV_FS_READ);
do {
errno = 0;
@ -1202,7 +1194,7 @@ static void uv__fs_work(struct uv__work* w) {
X(MKDIR, mkdir(req->path, req->mode));
X(MKDTEMP, uv__fs_mkdtemp(req));
X(OPEN, uv__fs_open(req));
X(READ, uv__fs_buf_iter(req, uv__fs_read));
X(READ, uv__fs_read(req));
X(SCANDIR, uv__fs_scandir(req));
X(READLINK, uv__fs_readlink(req));
X(REALPATH, uv__fs_realpath(req));
@ -1213,7 +1205,7 @@ static void uv__fs_work(struct uv__work* w) {
X(SYMLINK, symlink(req->path, req->new_path));
X(UNLINK, unlink(req->path));
X(UTIME, uv__fs_utime(req));
X(WRITE, uv__fs_buf_iter(req, uv__fs_write));
X(WRITE, uv__fs_write_all(req));
default: abort();
}
#undef X

View File

@ -186,6 +186,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
if (cb) {
uv__work_submit(loop,
&req->work_req,
UV__WORK_SLOW_IO,
uv__getaddrinfo_work,
uv__getaddrinfo_done);
return 0;

View File

@ -109,6 +109,7 @@ int uv_getnameinfo(uv_loop_t* loop,
if (getnameinfo_cb) {
uv__work_submit(loop,
&req->work_req,
UV__WORK_SLOW_IO,
uv__getnameinfo_work,
uv__getnameinfo_done);
return 0;

View File

@ -72,7 +72,8 @@ void uv_loadavg(double avg[3]) {
int uv_resident_set_memory(size_t* rss) {
return UV_ENOSYS;
*rss = 0;
return 0;
}

View File

@ -20,7 +20,7 @@
/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their
* EPOLL* counterparts. We use the POLL* variants in this file because that
* is what libuv uses elsewhere and it avoids a dependency on <sys/epoll.h>.
* is what libuv uses elsewhere.
*/
#include "uv.h"
@ -34,6 +34,7 @@
#include <errno.h>
#include <net/if.h>
#include <sys/epoll.h>
#include <sys/param.h>
#include <sys/prctl.h>
#include <sys/sysinfo.h>
@ -84,13 +85,13 @@ static unsigned long read_cpufreq(unsigned int cpunum);
int uv__platform_loop_init(uv_loop_t* loop) {
int fd;
fd = uv__epoll_create1(UV__EPOLL_CLOEXEC);
fd = epoll_create1(EPOLL_CLOEXEC);
/* epoll_create1() can fail either because it's not implemented (old kernel)
* or because it doesn't understand the EPOLL_CLOEXEC flag.
*/
if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
fd = uv__epoll_create(256);
fd = epoll_create(256);
if (fd != -1)
uv__cloexec(fd, 1);
@ -134,20 +135,20 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct uv__epoll_event* events;
struct uv__epoll_event dummy;
struct epoll_event* events;
struct epoll_event dummy;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers];
events = (struct epoll_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events != NULL)
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].data == fd)
events[i].data = -1;
if (events[i].data.fd == fd)
events[i].data.fd = -1;
/* Remove the file descriptor from the epoll.
* This avoids a problem where the same file description remains open
@ -160,25 +161,25 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
* has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
*/
memset(&dummy, 0, sizeof(dummy));
uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy);
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
}
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
struct uv__epoll_event e;
struct epoll_event e;
int rc;
e.events = POLLIN;
e.data = -1;
e.data.fd = -1;
rc = 0;
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e))
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e))
if (errno != EEXIST)
rc = UV__ERR(errno);
if (rc == 0)
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e))
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e))
abort();
return rc;
@ -195,16 +196,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
* that being the largest value I have seen in the wild (and only once.)
*/
static const int max_safe_timeout = 1789569;
static int no_epoll_pwait;
static int no_epoll_wait;
struct uv__epoll_event events[1024];
struct uv__epoll_event* pe;
struct uv__epoll_event e;
struct epoll_event events[1024];
struct epoll_event* pe;
struct epoll_event e;
int real_timeout;
QUEUE* q;
uv__io_t* w;
sigset_t sigset;
uint64_t sigmask;
sigset_t* psigset;
uint64_t base;
int have_signals;
int nevents;
@ -230,35 +229,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
assert(w->fd < (int) loop->nwatchers);
e.events = w->pevents;
e.data = w->fd;
e.data.fd = w->fd;
if (w->events == 0)
op = UV__EPOLL_CTL_ADD;
op = EPOLL_CTL_ADD;
else
op = UV__EPOLL_CTL_MOD;
op = EPOLL_CTL_MOD;
/* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
* events, skip the syscall and squelch the events after epoll_wait().
*/
if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
if (errno != EEXIST)
abort();
assert(op == UV__EPOLL_CTL_ADD);
assert(op == EPOLL_CTL_ADD);
/* We've reactivated a file descriptor that's been watched before. */
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e))
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e))
abort();
}
w->events = w->pevents;
}
sigmask = 0;
psigset = NULL;
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
sigemptyset(&sigset);
sigaddset(&sigset, SIGPROF);
sigmask |= 1 << (SIGPROF - 1);
psigset = &sigset;
}
assert(timeout >= -1);
@ -273,30 +272,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
timeout = max_safe_timeout;
if (sigmask != 0 && no_epoll_pwait != 0)
if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
abort();
if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
nfds = uv__epoll_pwait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout,
sigmask);
if (nfds == -1 && errno == ENOSYS)
no_epoll_pwait = 1;
} else {
nfds = uv__epoll_wait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout);
if (nfds == -1 && errno == ENOSYS)
no_epoll_wait = 1;
}
if (sigmask != 0 && no_epoll_pwait != 0)
if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
abort();
nfds = epoll_pwait(loop->backend_fd,
events,
ARRAY_SIZE(events),
timeout,
psigset);
/* Update loop->time unconditionally. It's tempting to skip the update when
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
@ -317,12 +297,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
}
if (nfds == -1) {
if (errno == ENOSYS) {
/* epoll_wait() or epoll_pwait() failed, try the other system call. */
assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
continue;
}
if (errno != EINTR)
abort();
@ -344,7 +318,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) {
pe = events + i;
fd = pe->data;
fd = pe->data.fd;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
@ -361,7 +335,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
* Ignore all errors because we may be racing with another thread
* when the file descriptor is closed.
*/
uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe);
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe);
continue;
}
@ -916,6 +890,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
continue;
address = *addresses;
memset(address->phys_addr, 0, sizeof(address->phys_addr));
for (i = 0; i < (*count); i++) {
if (strcmp(address->name, ent->ifa_name) == 0) {

View File

@ -77,56 +77,6 @@
# endif
#endif /* __NR_eventfd2 */
#ifndef __NR_epoll_create
# if defined(__x86_64__)
# define __NR_epoll_create 213
# elif defined(__i386__)
# define __NR_epoll_create 254
# elif defined(__arm__)
# define __NR_epoll_create (UV_SYSCALL_BASE + 250)
# endif
#endif /* __NR_epoll_create */
#ifndef __NR_epoll_create1
# if defined(__x86_64__)
# define __NR_epoll_create1 291
# elif defined(__i386__)
# define __NR_epoll_create1 329
# elif defined(__arm__)
# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357)
# endif
#endif /* __NR_epoll_create1 */
#ifndef __NR_epoll_ctl
# if defined(__x86_64__)
# define __NR_epoll_ctl 233 /* used to be 214 */
# elif defined(__i386__)
# define __NR_epoll_ctl 255
# elif defined(__arm__)
# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251)
# endif
#endif /* __NR_epoll_ctl */
#ifndef __NR_epoll_wait
# if defined(__x86_64__)
# define __NR_epoll_wait 232 /* used to be 215 */
# elif defined(__i386__)
# define __NR_epoll_wait 256
# elif defined(__arm__)
# define __NR_epoll_wait (UV_SYSCALL_BASE + 252)
# endif
#endif /* __NR_epoll_wait */
#ifndef __NR_epoll_pwait
# if defined(__x86_64__)
# define __NR_epoll_pwait 281
# elif defined(__i386__)
# define __NR_epoll_pwait 319
# elif defined(__arm__)
# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346)
# endif
#endif /* __NR_epoll_pwait */
#ifndef __NR_inotify_init
# if defined(__x86_64__)
# define __NR_inotify_init 253
@ -285,76 +235,6 @@ int uv__eventfd2(unsigned int count, int flags) {
}
int uv__epoll_create(int size) {
#if defined(__NR_epoll_create)
return syscall(__NR_epoll_create, size);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__epoll_create1(int flags) {
#if defined(__NR_epoll_create1)
return syscall(__NR_epoll_create1, flags);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) {
#if defined(__NR_epoll_ctl)
return syscall(__NR_epoll_ctl, epfd, op, fd, events);
#else
return errno = ENOSYS, -1;
#endif
}
int uv__epoll_wait(int epfd,
struct uv__epoll_event* events,
int nevents,
int timeout) {
#if defined(__NR_epoll_wait)
int result;
result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout);
#if MSAN_ACTIVE
if (result > 0)
__msan_unpoison(events, sizeof(events[0]) * result);
#endif
return result;
#else
return errno = ENOSYS, -1;
#endif
}
int uv__epoll_pwait(int epfd,
struct uv__epoll_event* events,
int nevents,
int timeout,
uint64_t sigmask) {
#if defined(__NR_epoll_pwait)
int result;
result = syscall(__NR_epoll_pwait,
epfd,
events,
nevents,
timeout,
&sigmask,
sizeof(sigmask));
#if MSAN_ACTIVE
if (result > 0)
__msan_unpoison(events, sizeof(events[0]) * result);
#endif
return result;
#else
return errno = ENOSYS, -1;
#endif
}
int uv__inotify_init(void) {
#if defined(__NR_inotify_init)
return syscall(__NR_inotify_init);
@ -431,19 +311,6 @@ int uv__recvmmsg(int fd,
}
int uv__utimesat(int dirfd,
const char* path,
const struct timespec times[2],
int flags)
{
#if defined(__NR_utimensat)
return syscall(__NR_utimensat, dirfd, path, times, flags);
#else
return errno = ENOSYS, -1;
#endif
}
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
#if defined(__NR_preadv)
return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));

View File

@ -66,12 +66,6 @@
# define UV__SOCK_NONBLOCK UV__O_NONBLOCK
#endif
/* epoll flags */
#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC
#define UV__EPOLL_CTL_ADD 1
#define UV__EPOLL_CTL_DEL 2
#define UV__EPOLL_CTL_MOD 3
/* inotify flags */
#define UV__IN_ACCESS 0x001
#define UV__IN_MODIFY 0x002
@ -86,18 +80,6 @@
#define UV__IN_DELETE_SELF 0x400
#define UV__IN_MOVE_SELF 0x800
#if defined(__x86_64__)
struct uv__epoll_event {
uint32_t events;
uint64_t data;
} __attribute__((packed));
#else
struct uv__epoll_event {
uint32_t events;
uint64_t data;
};
#endif
struct uv__inotify_event {
int32_t wd;
uint32_t mask;
@ -113,18 +95,6 @@ struct uv__mmsghdr {
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
int uv__eventfd(unsigned int count);
int uv__epoll_create(int size);
int uv__epoll_create1(int flags);
int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev);
int uv__epoll_wait(int epfd,
struct uv__epoll_event* events,
int nevents,
int timeout);
int uv__epoll_pwait(int epfd,
struct uv__epoll_event* events,
int nevents,
int timeout,
uint64_t sigmask);
int uv__eventfd2(unsigned int count, int flags);
int uv__inotify_init(void);
int uv__inotify_init1(int flags);
@ -140,10 +110,6 @@ int uv__sendmmsg(int fd,
struct uv__mmsghdr* mmsg,
unsigned int vlen,
unsigned int flags);
int uv__utimesat(int dirfd,
const char* path,
const struct timespec times[2],
int flags);
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
int uv__dup3(int oldfd, int newfd, int flags);

View File

@ -36,10 +36,6 @@
#define MAX_ITEMS_PER_EPOLL 1024
#define UV__O_CLOEXEC 0x80000
#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC
#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD
#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL
#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD
struct epoll_event {
int events;

View File

@ -512,7 +512,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
/* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
memset(address->phys_addr, 0, sizeof(address->phys_addr));
address++;
}
@ -624,6 +624,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
}
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
memset(address->phys_addr, 0, sizeof(address->phys_addr));
address++;
}
@ -662,7 +663,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
/* Remove the file descriptor from the epoll. */
if (loop->ep != NULL)
epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy);
epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, &dummy);
}
@ -838,9 +839,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
e.fd = w->fd;
if (w->events == 0)
op = UV__EPOLL_CTL_ADD;
op = EPOLL_CTL_ADD;
else
op = UV__EPOLL_CTL_MOD;
op = EPOLL_CTL_MOD;
/* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
* events, skip the syscall and squelch the events after epoll_wait().
@ -849,10 +850,10 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (errno != EEXIST)
abort();
assert(op == UV__EPOLL_CTL_ADD);
assert(op == EPOLL_CTL_ADD);
/* We've reactivated a file descriptor that's been watched before. */
if (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e))
if (epoll_ctl(loop->ep, EPOLL_CTL_MOD, w->fd, &e))
abort();
}
@ -934,7 +935,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
* Ignore all errors because we may be racing with another thread
* when the file descriptor is closed.
*/
epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, pe);
epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, pe);
continue;
}

View File

@ -137,11 +137,21 @@ void uv__pipe_close(uv_pipe_t* handle) {
int uv_pipe_open(uv_pipe_t* handle, uv_os_fd_t fd) {
int flags;
int mode;
int err;
flags = 0;
if (uv__fd_exists(handle->loop, fd))
return UV_EEXIST;
do
mode = fcntl(fd, F_GETFL);
while (mode == -1 && errno == EINTR);
if (mode == -1)
return UV__ERR(errno); /* according to docs, must be EBADF */
err = uv__nonblock(fd, 1);
if (err)
return err;
@ -152,9 +162,13 @@ int uv_pipe_open(uv_pipe_t* handle, uv_os_fd_t fd) {
return err;
#endif /* defined(__APPLE__) */
return uv__stream_open((uv_stream_t*)handle,
fd,
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
mode &= O_ACCMODE;
if (mode != O_WRONLY)
flags |= UV_HANDLE_READABLE;
if (mode != O_RDONLY)
flags |= UV_HANDLE_WRITABLE;
return uv__stream_open((uv_stream_t*)handle, fd, flags);
}

View File

@ -1676,6 +1676,7 @@ void uv__stream_close(uv_stream_t* handle) {
uv__io_close(handle->loop, &handle->io_watcher);
uv_read_stop(handle);
uv__handle_stop(handle);
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
if (handle->io_watcher.fd != -1) {
/* Don't close stdio file descriptors. Nothing good comes from it. */

View File

@ -44,27 +44,24 @@
#undef NANOSEC
#define NANOSEC ((uint64_t) 1e9)
#if defined(UV__PTHREAD_BARRIER_FALLBACK)
/* TODO: support barrier_attr */
int pthread_barrier_init(pthread_barrier_t* barrier,
const void* barrier_attr,
unsigned count) {
/* Note: guard clauses should match uv_barrier_t's in include/uv/uv-unix.h. */
#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD)
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
int rc;
if (barrier == NULL || count == 0)
return EINVAL;
if (barrier_attr != NULL)
return ENOTSUP;
return UV_EINVAL;
barrier->in = 0;
barrier->out = 0;
barrier->threshold = count;
if ((rc = pthread_mutex_init(&barrier->mutex, NULL)) != 0)
rc = uv_mutex_init(&barrier->mutex);
if (rc != 0)
return rc;
if ((rc = pthread_cond_init(&barrier->cond, NULL)) != 0)
rc = uv_cond_init(&barrier->cond);
if (rc != 0)
goto error;
return 0;
@ -74,63 +71,72 @@ error:
return rc;
}
int pthread_barrier_wait(pthread_barrier_t* barrier) {
int rc;
int uv_barrier_wait(uv_barrier_t* barrier) {
int last;
if (barrier == NULL)
return EINVAL;
return UV_EINVAL;
/* Lock the mutex*/
if ((rc = pthread_mutex_lock(&barrier->mutex)) != 0)
return rc;
uv_mutex_lock(&barrier->mutex);
/* Increment the count. If this is the first thread to reach the threshold,
wake up waiters, unlock the mutex, then return
PTHREAD_BARRIER_SERIAL_THREAD. */
if (++barrier->in == barrier->threshold) {
barrier->in = 0;
barrier->out = barrier->threshold - 1;
rc = pthread_cond_signal(&barrier->cond);
assert(rc == 0);
pthread_mutex_unlock(&barrier->mutex);
return PTHREAD_BARRIER_SERIAL_THREAD;
barrier->out = barrier->threshold;
uv_cond_signal(&barrier->cond);
} else {
do
uv_cond_wait(&barrier->cond, &barrier->mutex);
while (barrier->in != 0);
}
/* Otherwise, wait for other threads until in is set to 0,
then return 0 to indicate this is not the first thread. */
do {
if ((rc = pthread_cond_wait(&barrier->cond, &barrier->mutex)) != 0)
break;
} while (barrier->in != 0);
/* mark thread exit */
barrier->out--;
pthread_cond_signal(&barrier->cond);
pthread_mutex_unlock(&barrier->mutex);
return rc;
last = (--barrier->out == 0);
if (!last)
uv_cond_signal(&barrier->cond); /* Not needed for last thread. */
uv_mutex_unlock(&barrier->mutex);
return last;
}
int pthread_barrier_destroy(pthread_barrier_t* barrier) {
void uv_barrier_destroy(uv_barrier_t* barrier) {
uv_mutex_lock(&barrier->mutex);
assert(barrier->in == 0);
assert(barrier->out == 0);
if (barrier->in != 0 || barrier->out != 0)
abort();
uv_mutex_unlock(&barrier->mutex);
uv_mutex_destroy(&barrier->mutex);
uv_cond_destroy(&barrier->cond);
}
#else
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
return UV__ERR(pthread_barrier_init(barrier, NULL, count));
}
int uv_barrier_wait(uv_barrier_t* barrier) {
int rc;
if (barrier == NULL)
return EINVAL;
rc = pthread_barrier_wait(barrier);
if (rc != 0)
if (rc != PTHREAD_BARRIER_SERIAL_THREAD)
abort();
if ((rc = pthread_mutex_lock(&barrier->mutex)) != 0)
return rc;
if (barrier->in > 0 || barrier->out > 0)
rc = EBUSY;
pthread_mutex_unlock(&barrier->mutex);
if (rc)
return rc;
pthread_cond_destroy(&barrier->cond);
pthread_mutex_destroy(&barrier->mutex);
return 0;
return rc == PTHREAD_BARRIER_SERIAL_THREAD;
}
void uv_barrier_destroy(uv_barrier_t* barrier) {
if (pthread_barrier_destroy(barrier))
abort();
}
#endif
@ -756,25 +762,6 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
}
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
return UV__ERR(pthread_barrier_init(barrier, NULL, count));
}
void uv_barrier_destroy(uv_barrier_t* barrier) {
if (pthread_barrier_destroy(barrier))
abort();
}
int uv_barrier_wait(uv_barrier_t* barrier) {
int r = pthread_barrier_wait(barrier);
if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
abort();
return r == PTHREAD_BARRIER_SERIAL_THREAD;
}
int uv_key_create(uv_key_t* key) {
return UV__ERR(pthread_key_create(key, NULL));
}

View File

@ -92,13 +92,15 @@ static int uv__tty_is_slave(const int fd) {
return result;
}
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
uv_handle_type type;
int flags;
int newfd;
int r;
int saved_flags;
int mode;
char path[256];
(void)unused; /* deprecated parameter is no longer needed */
/* File descriptors that refer to files cannot be monitored with epoll.
* That restriction also applies to character devices like /dev/random
@ -111,6 +113,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
flags = 0;
newfd = -1;
/* Save the fd flags in case we need to restore them due to an error. */
do
saved_flags = fcntl(fd, F_GETFL);
while (saved_flags == -1 && errno == EINTR);
if (saved_flags == -1)
return UV__ERR(errno);
mode = saved_flags & O_ACCMODE;
/* Reopen the file descriptor when it refers to a tty. This lets us put the
* tty in non-blocking mode without affecting other processes that share it
* with us.
@ -128,13 +139,13 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
* slave device.
*/
if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
r = uv__open_cloexec(path, O_RDWR);
r = uv__open_cloexec(path, mode);
else
r = -1;
if (r < 0) {
/* fallback to using blocking writes */
if (!readable)
if (mode != O_RDONLY)
flags |= UV_HANDLE_BLOCKING_WRITES;
goto skip;
}
@ -154,22 +165,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
fd = newfd;
}
#if defined(__APPLE__)
/* Save the fd flags in case we need to restore them due to an error. */
do
saved_flags = fcntl(fd, F_GETFL);
while (saved_flags == -1 && errno == EINTR);
if (saved_flags == -1) {
if (newfd != -1)
uv__close(newfd);
return UV__ERR(errno);
}
#endif
/* Pacify the compiler. */
(void) &saved_flags;
skip:
uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
@ -194,9 +189,9 @@ skip:
}
#endif
if (readable)
if (mode != O_WRONLY)
flags |= UV_HANDLE_READABLE;
else
if (mode != O_RDONLY)
flags |= UV_HANDLE_WRITABLE;
uv__stream_open((uv_stream_t*) tty, fd, flags);

View File

@ -164,8 +164,15 @@ void uv__fs_poll_close(uv_fs_poll_t* handle);
int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */
enum uv__work_kind {
UV__WORK_CPU,
UV__WORK_FAST_IO,
UV__WORK_SLOW_IO
};
void uv__work_submit(uv_loop_t* loop,
struct uv__work *w,
enum uv__work_kind kind,
void (*work)(struct uv__work *w),
void (*done)(struct uv__work *w, int status));

View File

@ -241,7 +241,58 @@ int uv_backend_timeout(const uv_loop_t* loop) {
}
static void uv__loop_poll(uv_loop_t* loop, int timeout) {
static void uv__poll_wine(uv_loop_t* loop, int timeout) {
DWORD bytes;
ULONG_PTR key;
OVERLAPPED* overlapped;
uv_req_t* req;
int repeat;
uint64_t timeout_time;
timeout_time = loop->time + timeout;
for (repeat = 0; ; repeat++) {
GetQueuedCompletionStatus(loop->iocp,
&bytes,
&key,
&overlapped,
timeout);
if (overlapped) {
/* Package was dequeued */
req = container_of(overlapped, uv_req_t, u.io.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;
}
}
static void uv__poll(uv_loop_t* loop, int timeout) {
BOOL success;
uv_req_t* req;
OVERLAPPED_ENTRY overlappeds[128];
@ -333,7 +384,12 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
timeout = uv_backend_timeout(loop);
uv__loop_poll(loop, timeout == -1 ? INFINITE : timeout);
if (timeout == -1)
timeout = INFINITE;
if (pGetQueuedCompletionStatusEx)
uv__poll(loop, timeout);
else
uv__poll_wine(loop, timeout);
uv__run_check(loop);
uv_process_endgames(loop);

View File

@ -81,7 +81,7 @@ static void uv_relative_path(const WCHAR* filename,
static int uv_split_path(const WCHAR* filename, WCHAR** dir,
WCHAR** file) {
size_t len, i;
if (filename == NULL) {
if (dir != NULL)
*dir = NULL;

View File

@ -57,7 +57,11 @@
do { \
if (cb != NULL) { \
uv__req_register(loop, req); \
uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
uv__work_submit(loop, \
&req->work_req, \
UV__WORK_FAST_IO, \
uv__fs_work, \
uv__fs_done); \
return 0; \
} else { \
uv__fs_work(&req->work_req); \
@ -70,7 +74,11 @@
do { \
if (cb != NULL) { \
uv__req_register(loop, req); \
uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
uv__work_submit(loop, \
&req->work_req, \
UV__WORK_FAST_IO, \
uv__fs_work, \
uv__fs_done); \
return 0; \
} \
else { \
@ -1491,10 +1499,10 @@ static void fs__fchmod(uv_fs_t* req) {
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
goto fchmod_cleanup;
}
/* Test if the Archive attribute is cleared */
if ((file_info.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == 0) {
/* Set Archive flag, otherwise setting or clearing the read-only
/* Set Archive flag, otherwise setting or clearing the read-only
flag will not work */
file_info.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
nt_status = pNtSetInformationFile(handle,

View File

@ -345,6 +345,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
if (getaddrinfo_cb) {
uv__work_submit(loop,
&req->work_req,
UV__WORK_SLOW_IO,
uv__getaddrinfo_work,
uv__getaddrinfo_done);
return 0;

View File

@ -144,6 +144,7 @@ int uv_getnameinfo(uv_loop_t* loop,
if (getnameinfo_cb) {
uv__work_submit(loop,
&req->work_req,
UV__WORK_SLOW_IO,
uv__getnameinfo_work,
uv__getnameinfo_done);
return 0;

View File

@ -1,25 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include "uv.h"
#include "internal.h"

View File

@ -165,8 +165,11 @@ void uv_console_init(void) {
}
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_os_fd_t handle, int readable) {
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_os_fd_t handle, int unused) {
BOOL readable;
DWORD NumberOfEvents;
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
(void)unused;
if (handle == INVALID_HANDLE_VALUE)
return UV_EBADF;
@ -180,6 +183,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_os_fd_t handle, int readable)
return dup_err;
}
readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents);
if (!readable) {
/* Obtain the screen buffer info with the output handle. */
if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
@ -360,12 +364,6 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
}
int uv_is_tty(uv_os_fd_t file) {
DWORD result;
return GetConsoleMode(file, &result) != 0;
}
int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
CONSOLE_SCREEN_BUFFER_INFO info;
@ -1013,6 +1011,7 @@ int uv_tty_read_stop(uv_tty_t* handle) {
/* Cancel raw read. Write some bullshit event to force the console wait to
* return. */
memset(&record, 0, sizeof record);
record.EventType = FOCUS_EVENT;
if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
return GetLastError();
}
@ -2158,11 +2157,10 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
void uv_tty_close(uv_tty_t* handle) {
CloseHandle(handle->handle);
if (handle->flags & UV_HANDLE_READING)
uv_tty_read_stop(handle);
CloseHandle(handle->handle);
handle->handle = INVALID_HANDLE_VALUE;
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
uv__handle_closing(handle);

View File

@ -321,7 +321,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
int err;
if (handle->flags & UV_HANDLE_READING) {
return WSAEALREADY;
return UV_EALREADY;
}
err = uv_udp_maybe_bind(handle,
@ -329,7 +329,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
sizeof(uv_addr_ip4_any_),
0);
if (err)
return err;
return uv_translate_sys_error(err);
handle->flags |= UV_HANDLE_READING;
INCREASE_ACTIVE_COUNT(loop, handle);

View File

@ -34,6 +34,9 @@ sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
sNtQueryDirectoryFile pNtQueryDirectoryFile;
sNtQuerySystemInformation pNtQuerySystemInformation;
/* Kernel32 function pointers */
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
/* Powrprof.dll function pointer */
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
@ -104,6 +107,10 @@ void uv_winapi_init(void) {
uv_fatal_error(GetLastError(), "GetModuleHandleA");
}
pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress(
kernel32_module,
"GetQueuedCompletionStatusEx");
powrprof_module = LoadLibraryA("powrprof.dll");
if (powrprof_module != NULL) {
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)

View File

@ -4628,6 +4628,14 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
# define ERROR_MUI_FILE_NOT_LOADED 15105
#endif
typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
(HANDLE CompletionPort,
LPOVERLAPPED_ENTRY lpCompletionPortEntries,
ULONG ulCount,
PULONG ulNumEntriesRemoved,
DWORD dwMilliseconds,
BOOL fAlertable);
/* from powerbase.h */
#ifndef DEVICE_NOTIFY_CALLBACK
# define DEVICE_NOTIFY_CALLBACK 2
@ -4690,6 +4698,9 @@ extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
extern sNtQuerySystemInformation pNtQuerySystemInformation;
/* Kernel32 function pointers */
extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
/* Powrprof.dll function pointer */
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;

View File

@ -217,7 +217,7 @@ int process_copy_output(process_info_t* p, FILE* stream) {
while (fgets(buf, sizeof(buf), f) != NULL)
print_lines(buf, strlen(buf), stream);
if (ferror(f))
return -1;

View File

@ -104,3 +104,45 @@ TEST_IMPL(barrier_3) {
return 0;
}
static void serial_worker(void* data) {
uv_barrier_t* barrier;
barrier = data;
if (uv_barrier_wait(barrier) > 0)
uv_barrier_destroy(barrier);
uv_sleep(100); /* Wait a bit before terminating. */
}
/* Ensure that uv_barrier_wait returns positive only after all threads have
* exited the barrier. If this value is returned too early and the barrier is
* destroyed prematurely, then this test may see a crash. */
TEST_IMPL(barrier_serial_thread) {
uv_thread_t threads[4];
uv_barrier_t barrier;
unsigned i;
ASSERT(0 == uv_barrier_init(&barrier, ARRAY_SIZE(threads) + 1));
for (i = 0; i < ARRAY_SIZE(threads); ++i)
ASSERT(0 == uv_thread_create(&threads[i], serial_worker, &barrier));
if (uv_barrier_wait(&barrier) > 0)
uv_barrier_destroy(&barrier);
for (i = 0; i < ARRAY_SIZE(threads); ++i)
ASSERT(0 == uv_thread_join(&threads[i]));
return 0;
}
/* Single thread uv_barrier_wait should return correct return value. */
TEST_IMPL(barrier_serial_thread_single) {
uv_barrier_t barrier;
ASSERT(0 == uv_barrier_init(&barrier, 1));
ASSERT(0 < uv_barrier_wait(&barrier));
uv_barrier_destroy(&barrier);
return 0;
}

View File

@ -259,7 +259,7 @@ TEST_IMPL(condvar_5) {
* https://msdn.microsoft.com/en-us/library/ms687069(VS.85).aspx */
elapsed = after - before;
ASSERT(0.75 * timeout <= elapsed); /* 1.0 too large for Windows. */
ASSERT(elapsed <= 1.5 * timeout); /* 1.1 too small for OSX. */
ASSERT(elapsed <= 5.0 * timeout); /* MacOS has reported failures up to 1.75. */
worker_config_destroy(&wc);

View File

@ -283,6 +283,7 @@ TEST_IMPL(fork_signal_to_child_closed) {
int sync_pipe[2];
int sync_pipe2[2];
char sync_buf[1];
int r;
fork_signal_cb_called = 0; /* reset */
@ -326,9 +327,10 @@ TEST_IMPL(fork_signal_to_child_closed) {
/* Don't run the loop. Wait for the parent to call us */
printf("Waiting on parent in child\n");
/* Wait for parent. read may fail if the parent tripped an ASSERT
and exited, so this isn't in an ASSERT.
and exited, so this ASSERT is generous.
*/
read(sync_pipe2[0], sync_buf, 1);
r = read(sync_pipe2[0], sync_buf, 1);
ASSERT(-1 <= r && r <= 1);
ASSERT(0 == fork_signal_cb_called);
printf("Exiting child \n");
/* Note that we're deliberately not running the loop

View File

@ -27,6 +27,7 @@
#include <math.h>
#include <string.h> /* memset */
#include <sys/stat.h>
#include <limits.h> /* INT_MAX, PATH_MAX, IOV_MAX */
/* FIXME we shouldn't need to branch in this file */
#if defined(__unix__) || defined(__POSIX__) || \
@ -122,6 +123,48 @@ static char test_buf[] = "test-buffer\n";
static char test_buf2[] = "second-buffer\n";
static uv_buf_t iov;
#ifdef _WIN32
int uv_test_getiovmax(void) {
return INT32_MAX; /* Emulated by libuv, so no real limit. */
}
off_t uv_test_lseek(HANDLE fd, off_t offset, int whence) {
LARGE_INTEGER offset_;
LARGE_INTEGER tell;
offset_.QuadPart = offset;
if (SetFilePointerEx(fd, offset_, &tell, whence))
return tell.QuadPart;
return -1;
}
#else
int uv_test_getiovmax(void) {
#if defined(IOV_MAX)
return IOV_MAX;
#elif defined(_SC_IOV_MAX)
static int iovmax = -1;
if (iovmax == -1) {
iovmax = sysconf(_SC_IOV_MAX);
/* On some embedded devices (arm-linux-uclibc based ip camera),
* sysconf(_SC_IOV_MAX) can not get the correct value. The return
* value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
*/
if (iovmax == -1) iovmax = 1;
}
return iovmax;
#else
return 1024;
#endif
}
int uv_test_lseek(int fd, off_t offset, int whence) {
return lseek(fd, offset, whence);
}
#endif
#ifdef _WIN32
/*
* This tag and guid have no special meaning, and don't conflict with
@ -2968,19 +3011,44 @@ TEST_IMPL(fs_write_multiple_bufs) {
memset(buf, 0, sizeof(buf));
memset(buf2, 0, sizeof(buf2));
/* Read the strings back to separate buffers. */
iovs[0] = uv_buf_init(buf, sizeof(test_buf));
iovs[1] = uv_buf_init(buf2, sizeof(test_buf2));
ASSERT(uv_test_lseek(file, 0, SEEK_CUR) == 0);
r = uv_fs_read(NULL, &read_req, file, iovs, 2, -1, NULL);
ASSERT(r >= 0);
ASSERT(read_req.result == sizeof(test_buf) + sizeof(test_buf2));
ASSERT(strcmp(buf, test_buf) == 0);
ASSERT(strcmp(buf2, test_buf2) == 0);
uv_fs_req_cleanup(&read_req);
iov = uv_buf_init(buf, sizeof(buf));
r = uv_fs_read(NULL, &read_req, file, &iov, 1, -1, NULL);
ASSERT(r == 0);
ASSERT(read_req.result == 0);
uv_fs_req_cleanup(&read_req);
/* Read the strings back to separate buffers. */
iovs[0] = uv_buf_init(buf, sizeof(test_buf));
iovs[1] = uv_buf_init(buf2, sizeof(test_buf2));
r = uv_fs_read(NULL, &read_req, file, iovs, 2, 0, NULL);
ASSERT(r >= 0);
ASSERT(read_req.result >= 0);
if (read_req.result == sizeof(test_buf)) {
/* Infer that preadv is not available. */
uv_fs_req_cleanup(&read_req);
r = uv_fs_read(NULL, &read_req, file, &iovs[1], 1, read_req.result, NULL);
ASSERT(r >= 0);
ASSERT(read_req.result == sizeof(test_buf2));
} else {
ASSERT(read_req.result == sizeof(test_buf) + sizeof(test_buf2));
}
ASSERT(strcmp(buf, test_buf) == 0);
ASSERT(strcmp(buf2, test_buf2) == 0);
uv_fs_req_cleanup(&read_req);
iov = uv_buf_init(buf, sizeof(buf));
r = uv_fs_read(NULL, &read_req, file, &iov, 1,
read_req.result, NULL);
sizeof(test_buf) + sizeof(test_buf2), NULL);
ASSERT(r == 0);
ASSERT(read_req.result == 0);
uv_fs_req_cleanup(&read_req);
@ -2999,13 +3067,16 @@ TEST_IMPL(fs_write_multiple_bufs) {
TEST_IMPL(fs_write_alotof_bufs) {
const size_t iovcount = 54321;
size_t iovcount;
size_t iovmax;
uv_buf_t* iovs;
char* buffer;
size_t index;
int r;
uv_os_fd_t file;
iovcount = 54321;
/* Setup. */
unlink("test_file");
@ -3013,6 +3084,7 @@ TEST_IMPL(fs_write_alotof_bufs) {
iovs = malloc(sizeof(*iovs) * iovcount);
ASSERT(iovs != NULL);
iovmax = uv_test_getiovmax();
r = uv_fs_open(NULL,
&open_req1,
@ -3047,7 +3119,10 @@ TEST_IMPL(fs_write_alotof_bufs) {
iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
sizeof(test_buf));
r = uv_fs_read(NULL, &read_req, file, iovs, iovcount, 0, NULL);
ASSERT(uv_test_lseek(file, 0, SEEK_SET) == 0);
r = uv_fs_read(NULL, &read_req, file, iovs, iovcount, -1, NULL);
if (iovcount > iovmax)
iovcount = iovmax;
ASSERT(r >= 0);
ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount);
@ -3059,13 +3134,14 @@ TEST_IMPL(fs_write_alotof_bufs) {
uv_fs_req_cleanup(&read_req);
free(buffer);
ASSERT(uv_test_lseek(file, write_req.result, SEEK_SET) == write_req.result);
iov = uv_buf_init(buf, sizeof(buf));
r = uv_fs_read(NULL,
&read_req,
file,
&iov,
1,
read_req.result,
-1,
NULL);
ASSERT(r == 0);
ASSERT(read_req.result == 0);
@ -3086,15 +3162,20 @@ TEST_IMPL(fs_write_alotof_bufs) {
TEST_IMPL(fs_write_alotof_bufs_with_offset) {
const size_t iovcount = 54321;
size_t iovcount;
size_t iovmax;
uv_buf_t* iovs;
char* buffer;
size_t index;
int r;
int64_t offset;
char* filler = "0123456789";
int filler_len = strlen(filler);
uv_os_fd_t file;
char* filler;
int filler_len;
filler = "0123456789";
filler_len = strlen(filler);
iovcount = 54321;
/* Setup. */
unlink("test_file");
@ -3103,6 +3184,7 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) {
iovs = malloc(sizeof(*iovs) * iovcount);
ASSERT(iovs != NULL);
iovmax = uv_test_getiovmax();
r = uv_fs_open(NULL,
&open_req1,
@ -3147,6 +3229,10 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) {
r = uv_fs_read(NULL, &read_req, file,
iovs, iovcount, offset, NULL);
ASSERT(r >= 0);
if (r == sizeof(test_buf))
iovcount = 1; /* Infer that preadv is not available. */
else if (iovcount > iovmax)
iovcount = iovmax;
ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount);
for (index = 0; index < iovcount; ++index)
@ -3160,7 +3246,7 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) {
r = uv_fs_stat(NULL, &stat_req, "test_file", NULL);
ASSERT(r == 0);
ASSERT((int64_t)((uv_stat_t*)stat_req.ptr)->st_size ==
offset + (int64_t)(iovcount * sizeof(test_buf)));
offset + (int64_t)write_req.result);
uv_fs_req_cleanup(&stat_req);
iov = uv_buf_init(buf, sizeof(buf));
@ -3169,7 +3255,7 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) {
file,
&iov,
1,
read_req.result + offset,
offset + write_req.result,
NULL);
ASSERT(r == 0);
ASSERT(read_req.result == 0);
@ -3189,6 +3275,175 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) {
}
#ifdef _WIN32
TEST_IMPL(fs_partial_read) {
RETURN_SKIP("Test not implemented on Windows.");
}
TEST_IMPL(fs_partial_write) {
RETURN_SKIP("Test not implemented on Windows.");
}
#else /* !_WIN32 */
struct thread_ctx {
pthread_t pid;
int fd;
char* data;
int size;
int interval;
int doread;
};
static void thread_main(void* arg) {
const struct thread_ctx* ctx;
int size;
char* data;
ctx = (struct thread_ctx*)arg;
size = ctx->size;
data = ctx->data;
while (size > 0) {
ssize_t result;
int nbytes;
nbytes = size < ctx->interval ? size : ctx->interval;
if (ctx->doread) {
result = write(ctx->fd, data, nbytes);
/* Should not see EINTR (or other errors) */
ASSERT(result == nbytes);
} else {
result = read(ctx->fd, data, nbytes);
/* Should not see EINTR (or other errors),
* but might get a partial read if we are faster than the writer
*/
ASSERT(result > 0 && result <= nbytes);
}
pthread_kill(ctx->pid, SIGUSR1);
size -= result;
data += result;
}
}
static void sig_func(uv_signal_t* handle, int signum) {
uv_signal_stop(handle);
}
static size_t uv_test_fs_buf_offset(uv_buf_t* bufs, size_t size) {
size_t offset;
/* Figure out which bufs are done */
for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset)
size -= bufs[offset].len;
/* Fix a partial read/write */
if (size > 0) {
bufs[offset].base += size;
bufs[offset].len -= size;
}
return offset;
}
static void test_fs_partial(int doread) {
struct thread_ctx ctx;
uv_thread_t thread;
uv_signal_t signal;
int pipe_fds[2];
size_t iovcount;
uv_buf_t* iovs;
char* buffer;
size_t index;
iovcount = 54321;
iovs = malloc(sizeof(*iovs) * iovcount);
ASSERT(iovs != NULL);
ctx.pid = pthread_self();
ctx.doread = doread;
ctx.interval = 1000;
ctx.size = sizeof(test_buf) * iovcount;
ctx.data = malloc(ctx.size);
ASSERT(ctx.data != NULL);
buffer = malloc(ctx.size);
ASSERT(buffer != NULL);
for (index = 0; index < iovcount; ++index)
iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf), sizeof(test_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));
ctx.fd = pipe_fds[doread];
ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx));
if (doread) {
uv_buf_t* read_iovs;
int nread;
read_iovs = iovs;
nread = 0;
while (nread < ctx.size) {
int result;
result = uv_fs_read(loop, &read_req, pipe_fds[0], read_iovs, iovcount, -1, NULL);
if (result > 0) {
size_t read_iovcount;
read_iovcount = uv_test_fs_buf_offset(read_iovs, result);
read_iovs += read_iovcount;
iovcount -= read_iovcount;
nread += result;
} else {
ASSERT(result == UV_EINTR);
}
uv_fs_req_cleanup(&read_req);
}
} else {
int result;
result = uv_fs_write(loop, &write_req, pipe_fds[1], iovs, iovcount, -1, NULL);
ASSERT(write_req.result == result);
ASSERT(result == ctx.size);
uv_fs_req_cleanup(&write_req);
}
ASSERT(0 == memcmp(buffer, ctx.data, ctx.size));
ASSERT(0 == uv_thread_join(&thread));
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
ASSERT(0 == close(pipe_fds[1]));
uv_close((uv_handle_t*) &signal, NULL);
{ /* Make sure we read everything that we wrote. */
int result;
result = uv_fs_read(loop, &read_req, pipe_fds[0], iovs, 1, -1, NULL);
ASSERT(result == 0);
uv_fs_req_cleanup(&read_req);
}
ASSERT(0 == close(pipe_fds[0]));
free(iovs);
free(buffer);
free(ctx.data);
MAKE_VALGRIND_HAPPY();
}
TEST_IMPL(fs_partial_read) {
test_fs_partial(1);
return 0;
}
TEST_IMPL(fs_partial_write) {
test_fs_partial(0);
return 0;
}
#endif/* _WIN32 */
TEST_IMPL(fs_read_write_null_arguments) {
int r;
@ -3286,20 +3541,7 @@ TEST_IMPL(fs_file_pos_after_op_with_offset) {
r = uv_fs_write(NULL, &write_req, file, &iov, 1, 0, NULL);
ASSERT(r == sizeof(test_buf));
#ifdef _WIN32
LARGE_INTEGER original_position;
LARGE_INTEGER zero_offset;
zero_offset.QuadPart = 0;
ASSERT(SetFilePointerEx(file,
zero_offset,
&original_position,
FILE_CURRENT) != 0);
ASSERT(original_position.QuadPart == 0);
#else
ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0);
#endif
ASSERT(uv_test_lseek(file, 0, SEEK_CUR) == 0);
uv_fs_req_cleanup(&write_req);
@ -3308,17 +3550,7 @@ TEST_IMPL(fs_file_pos_after_op_with_offset) {
ASSERT(r == sizeof(test_buf));
ASSERT(strcmp(buf, test_buf) == 0);
#ifdef _WIN32
zero_offset.QuadPart = 0;
ASSERT(SetFilePointerEx(file,
zero_offset,
&original_position,
FILE_CURRENT) != 0);
ASSERT(original_position.QuadPart == 0);
#else
ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0);
#endif
ASSERT(uv_test_lseek(file, 0, SEEK_CUR) == 0);
uv_fs_req_cleanup(&read_req);
@ -3491,7 +3723,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) {
int call_icacls(const char* command, ...) {
char icacls_command[1024];
va_list args;
va_start(args, command);
vsnprintf(icacls_command, ARRAYSIZE(icacls_command), command, args);
va_end(args);
@ -3513,7 +3745,7 @@ TEST_IMPL(fs_open_readonly_acl) {
attrib -r test_file_icacls
del test_file_icacls
*/
/* Setup - clear the ACL and remove the file */
loop = uv_default_loop();
r = uv_os_get_passwd(&pwd);
@ -3523,7 +3755,7 @@ TEST_IMPL(fs_open_readonly_acl) {
uv_fs_chmod(loop, &req, "test_file_icacls", S_IWUSR, NULL);
unlink("test_file_icacls");
/* Create the file */
/* Create the file */
r = uv_fs_open(loop,
&open_req1,
"test_file_icacls",
@ -3548,7 +3780,7 @@ TEST_IMPL(fs_open_readonly_acl) {
if (r != 0) {
goto acl_cleanup;
}
/* Try opening the file */
r = uv_fs_open(NULL, &open_req1, "test_file_icacls", O_RDONLY, 0, NULL);
if (r < 0) {

View File

@ -26,7 +26,7 @@
static uv_os_fd_t get_tty_fd(void) {
/* Make sure we have an FD that refers to a tty */
#ifdef _WIN32
return CreateFileA("conout$",
return CreateFileA("conin$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
@ -103,11 +103,15 @@ TEST_IMPL(handle_fileno) {
} else {
r = uv_tty_init(loop, &tty, tty_fd, 0);
ASSERT(r == 0);
ASSERT(uv_is_readable((uv_stream_t*) &tty));
ASSERT(!uv_is_writable((uv_stream_t*) &tty));
r = uv_fileno((uv_handle_t*) &tty, &fd);
ASSERT(r == 0);
uv_close((uv_handle_t*) &tty, NULL);
r = uv_fileno((uv_handle_t*) &tty, &fd);
ASSERT(r == UV_EBADF);
ASSERT(!uv_is_readable((uv_stream_t*) &tty));
ASSERT(!uv_is_writable((uv_stream_t*) &tty));
}
uv_run(loop, UV_RUN_DEFAULT);

View File

@ -38,6 +38,8 @@ TEST_DECLARE (barrier_1)
TEST_DECLARE (barrier_2)
TEST_DECLARE (barrier_3)
TEST_DECLARE (buf_large)
TEST_DECLARE (barrier_serial_thread)
TEST_DECLARE (barrier_serial_thread_single)
TEST_DECLARE (condvar_1)
TEST_DECLARE (condvar_2)
TEST_DECLARE (condvar_3)
@ -51,6 +53,7 @@ TEST_DECLARE (tty)
TEST_DECLARE (tty_raw)
TEST_DECLARE (tty_empty_write)
TEST_DECLARE (tty_large_write)
TEST_DECLARE (tty_raw_cancel)
#endif
TEST_DECLARE (tty_file)
TEST_DECLARE (tty_pty)
@ -357,6 +360,8 @@ TEST_DECLARE (fs_invalid_filename)
#endif
TEST_DECLARE (fs_write_alotof_bufs)
TEST_DECLARE (fs_write_alotof_bufs_with_offset)
TEST_DECLARE (fs_partial_read)
TEST_DECLARE (fs_partial_write)
TEST_DECLARE (fs_file_pos_after_op_with_offset)
TEST_DECLARE (fs_null_req)
#ifdef _WIN32
@ -475,6 +480,8 @@ TASK_LIST_START
TEST_ENTRY (barrier_2)
TEST_ENTRY (barrier_3)
TEST_ENTRY (buf_large)
TEST_ENTRY (barrier_serial_thread)
TEST_ENTRY (barrier_serial_thread_single)
TEST_ENTRY (condvar_1)
TEST_ENTRY (condvar_2)
TEST_ENTRY (condvar_3)
@ -502,6 +509,7 @@ TASK_LIST_START
TEST_ENTRY (tty_raw)
TEST_ENTRY (tty_empty_write)
TEST_ENTRY (tty_large_write)
TEST_ENTRY (tty_raw_cancel)
#endif
TEST_ENTRY (tty_file)
TEST_ENTRY (tty_pty)
@ -920,6 +928,8 @@ TASK_LIST_START
TEST_ENTRY (fs_write_multiple_bufs)
TEST_ENTRY (fs_write_alotof_bufs)
TEST_ENTRY (fs_write_alotof_bufs_with_offset)
TEST_ENTRY (fs_partial_read)
TEST_ENTRY (fs_partial_write)
TEST_ENTRY (fs_read_write_null_arguments)
#ifdef _WIN32
TEST_ENTRY (fs_invalid_filename)

View File

@ -66,7 +66,8 @@ TEST_IMPL(pipe_close_stdout_read_stdin) {
*/
close(fd[1]);
/* block until write end of pipe is closed */
read(fd[0], &buf, 1);
r = read(fd[0], &buf, 1);
ASSERT(-1 <= r && r <= 1);
close(0);
r = dup(fd[0]);
ASSERT(r != -1);

View File

@ -54,8 +54,10 @@ TEST_IMPL(process_priority) {
#ifndef _WIN32
ASSERT(priority == i);
#else
/* On Windows, only elevated users can set UV_PRIORITY_HIGHEST. Other
users will silently be set to UV_PRIORITY_HIGH. */
if (i < UV_PRIORITY_HIGH)
ASSERT(priority == UV_PRIORITY_HIGHEST);
ASSERT(priority == UV_PRIORITY_HIGHEST || priority == UV_PRIORITY_HIGH);
else if (i < UV_PRIORITY_ABOVE_NORMAL)
ASSERT(priority == UV_PRIORITY_HIGH);
else if (i < UV_PRIORITY_NORMAL)

View File

@ -1823,6 +1823,7 @@ TEST_IMPL(spawn_inherit_streams) {
uv_buf_t buf;
unsigned int i;
int r;
int bidir;
uv_write_t write_req;
uv_loop_t* loop;
@ -1841,6 +1842,15 @@ TEST_IMPL(spawn_inherit_streams) {
ASSERT(uv_pipe_open(&pipe_stdout_child, fds_stdout[1]) == 0);
ASSERT(uv_pipe_open(&pipe_stdin_parent, fds_stdin[1]) == 0);
ASSERT(uv_pipe_open(&pipe_stdout_parent, fds_stdout[0]) == 0);
ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_child));
ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_child));
ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdin_parent));
ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_parent));
/* Some systems (SVR4) open a bidirectional pipe, most don't. */
bidir = uv_is_writable((uv_stream_t*) &pipe_stdin_child);
ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_child) == bidir);
ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_parent) == bidir);
ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_parent) == bidir);
child_stdio[0].flags = UV_INHERIT_STREAM;
child_stdio[0].data.stream = (uv_stream_t *)&pipe_stdin_child;

View File

@ -93,9 +93,13 @@ TEST_IMPL(tty) {
r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */
ASSERT(r == 0);
ASSERT(uv_is_readable((uv_stream_t*) &tty_in));
ASSERT(!uv_is_writable((uv_stream_t*) &tty_in));
r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */
ASSERT(r == 0);
ASSERT(!uv_is_readable((uv_stream_t*) &tty_out));
ASSERT(uv_is_writable((uv_stream_t*) &tty_out));
r = uv_tty_get_winsize(&tty_out, &width, &height);
ASSERT(r == 0);
@ -180,6 +184,8 @@ TEST_IMPL(tty_raw) {
r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */
ASSERT(r == 0);
ASSERT(uv_is_readable((uv_stream_t*) &tty_in));
ASSERT(!uv_is_writable((uv_stream_t*) &tty_in));
r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read);
ASSERT(r == 0);
@ -231,6 +237,8 @@ TEST_IMPL(tty_empty_write) {
r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */
ASSERT(r == 0);
ASSERT(!uv_is_readable((uv_stream_t*) &tty_out));
ASSERT(uv_is_writable((uv_stream_t*) &tty_out));
bufs[0].len = 0;
bufs[0].base = &dummy[0];
@ -286,6 +294,38 @@ TEST_IMPL(tty_large_write) {
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(tty_raw_cancel) {
int r;
uv_tty_t tty_in;
uv_loop_t* loop;
HANDLE handle;
loop = uv_default_loop();
/* Make sure we have an FD that refers to a tty */
handle = CreateFileA("conin$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
ASSERT(handle != INVALID_HANDLE_VALUE);
ASSERT(UV_TTY == uv_guess_handle(handle));
r = uv_tty_init(uv_default_loop(), &tty_in, handle, 1); /* Readable. */
ASSERT(r == 0);
r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW);
ASSERT(r == 0);
r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read);
ASSERT(r == 0);
r = uv_read_stop((uv_stream_t*) &tty_in);
ASSERT(r == 0);
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif
@ -293,6 +333,8 @@ TEST_IMPL(tty_file) {
#ifndef _WIN32
uv_loop_t loop;
uv_tty_t tty;
uv_tty_t tty_ro;
uv_tty_t tty_wo;
int fd;
ASSERT(0 == uv_loop_init(&loop));
@ -318,13 +360,40 @@ TEST_IMPL(tty_file) {
ASSERT(0 == close(fd));
}
fd = open("/dev/tty", O_RDONLY);
fd = open("/dev/tty", O_RDWR);
if (fd != -1) {
ASSERT(0 == uv_tty_init(&loop, &tty, fd, 1));
ASSERT(0 == close(fd));
ASSERT(0 == close(fd)); /* TODO: it's indeterminate who owns fd now */
ASSERT(uv_is_readable((uv_stream_t*) &tty));
ASSERT(uv_is_writable((uv_stream_t*) &tty));
uv_close((uv_handle_t*) &tty, NULL);
ASSERT(!uv_is_readable((uv_stream_t*) &tty));
ASSERT(!uv_is_writable((uv_stream_t*) &tty));
}
fd = open("/dev/tty", O_RDONLY);
if (fd != -1) {
ASSERT(0 == uv_tty_init(&loop, &tty_ro, fd, 1));
ASSERT(0 == close(fd)); /* TODO: it's indeterminate who owns fd now */
ASSERT(uv_is_readable((uv_stream_t*) &tty_ro));
ASSERT(!uv_is_writable((uv_stream_t*) &tty_ro));
uv_close((uv_handle_t*) &tty_ro, NULL);
ASSERT(!uv_is_readable((uv_stream_t*) &tty_ro));
ASSERT(!uv_is_writable((uv_stream_t*) &tty_ro));
}
fd = open("/dev/tty", O_WRONLY);
if (fd != -1) {
ASSERT(0 == uv_tty_init(&loop, &tty_wo, fd, 0));
ASSERT(0 == close(fd)); /* TODO: it's indeterminate who owns fd now */
ASSERT(!uv_is_readable((uv_stream_t*) &tty_wo));
ASSERT(uv_is_writable((uv_stream_t*) &tty_wo));
uv_close((uv_handle_t*) &tty_wo, NULL);
ASSERT(!uv_is_readable((uv_stream_t*) &tty_wo));
ASSERT(!uv_is_writable((uv_stream_t*) &tty_wo));
}
ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
ASSERT(0 == uv_loop_close(&loop));
@ -354,6 +423,10 @@ TEST_IMPL(tty_pty) {
ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0));
ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0));
ASSERT(uv_is_readable((uv_stream_t*) &slave_tty));
ASSERT(uv_is_writable((uv_stream_t*) &slave_tty));
ASSERT(uv_is_readable((uv_stream_t*) &master_tty));
ASSERT(uv_is_writable((uv_stream_t*) &master_tty));
/* Check if the file descriptor was reopened. If it is,
* UV_HANDLE_BLOCKING_WRITES (value 0x100000) isn't set on flags.
*/

1
uv.gyp
View File

@ -115,7 +115,6 @@
'src/win/poll.c',
'src/win/process.c',
'src/win/process-stdio.c',
'src/win/req.c',
'src/win/req-inl.h',
'src/win/signal.c',
'src/win/stream.c',