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:
commit
f6b3c7420f
6
AUTHORS
6
AUTHORS
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
86
ChangeLog
86
ChangeLog
@ -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:
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 \
|
||||
|
||||
79
README.md
79
README.md
@ -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).
|
||||
|
||||
@ -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
23
android-configure-arm64
Executable 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
23
android-configure-x86
Executable 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
25
android-configure-x86_64
Executable 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
|
||||
@ -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)) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_ */
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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++;
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
228
src/unix/fs.c
228
src/unix/fs.c
@ -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, ×, &i);
|
||||
|
||||
return setattrlist(req->path, &attr_list, ×, 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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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. */
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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));
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
16
src/win/fs.c
16
src/win/fs.c
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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"
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
310
test/test-fs.c
310
test/test-fs.c
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user