Merge branch 'v1.x'

This commit is contained in:
Saúl Ibarra Corretgé 2016-08-03 10:26:12 +01:00
commit 99438cf020
52 changed files with 665 additions and 363 deletions

View File

@ -165,5 +165,5 @@ not send out notifications when you add commits.
[issue tracker]: https://github.com/libuv/libuv/issues
[libuv mailing list]: http://groups.google.com/group/libuv
[IRC]: http://webchat.freelibuv.net/?channels=libuv
[Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
[Google C/C++ style guide]: https://google.github.io/styleguide/cppguide.html
[project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md

28
LICENSE
View File

@ -1,5 +1,29 @@
libuv is part of the Node project: http://nodejs.org/
libuv may be distributed alone under Node's license:
libuv is licensed for use as follows:
====
Copyright (c) 2015-present libuv project contributors.
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.
====
This license applies to parts of libuv originating from the
https://github.com/joyent/libuv repository:
====

View File

@ -7,8 +7,11 @@ libuv is currently managed by the following individuals:
- GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis)
* **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus))
* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig))
- GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig)
* **Fedor Indutny** ([@indutny](https://github.com/indutny))
- GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny)
* **Imran Iqbal** ([@iWuzHere](https://github.com/iWuzHere))
- GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere)
* **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul))
- GPG key: FDF5 1936 4458 319F A823 3DC9 410E 5553 AE9B C059 (pubkey-saghul)
@ -34,4 +37,3 @@ be garbage collected since nothing references it, so we'll create a tag for it:
Commit the changes and push:
$ git push origin pubkey-saghul

View File

@ -128,7 +128,7 @@ EXTRA_DIST = test/fixtures/empty_file \
TESTS = test/run-tests
check_PROGRAMS = test/run-tests
test_run_tests_CFLAGS =
test_run_tests_CFLAGS = -Wno-long-long
test_run_tests_LDFLAGS =
test_run_tests_SOURCES = test/blackhole-server.c \
test/dns-server.c \
@ -312,6 +312,7 @@ endif
if DRAGONFLY
include_HEADERS += include/uv-bsd.h
libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c
test_run_tests_LDFLAGS += -lutil
endif

View File

@ -39,6 +39,10 @@ Starting with version 1.0.0 libuv follows the [semantic versioning](http://semve
scheme. The API change and backwards compatibility rules are those indicated by
SemVer. libuv will keep a stable ABI across major releases.
## Licensing
libuv is licensed under the MIT license. Check the [LICENSE file](LICENSE).
## Community
* [Mailing list](http://groups.google.com/group/libuv)

View File

@ -24,7 +24,7 @@ AC_ENABLE_SHARED
AC_ENABLE_STATIC
AC_PROG_CC
AM_PROG_CC_C_O
CC_CHECK_CFLAGS_APPEND([-fvisibility=hidden])
CC_FLAG_VISIBILITY #[-fvisibility=hidden]
CC_CHECK_CFLAGS_APPEND([-g])
CC_CHECK_CFLAGS_APPEND([-std=gnu89])
CC_CHECK_CFLAGS_APPEND([-pedantic])

View File

@ -57,7 +57,7 @@ html:
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
livehtml:
livehtml: html
$(SPHINXAUTOBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
dirhtml:

View File

@ -8,6 +8,9 @@ In libuv errors are negative numbered constants. As a rule of thumb, whenever
there is a status parameter, or an API functions returns an integer, a negative
number will imply an error.
When a function which takes a callback returns an error, the callback will never
be called.
.. note::
Implementation detail: on Unix error codes are the negated `errno` (or `-errno`), while on
Windows they are defined by libuv to arbitrary negative numbers.

View File

@ -91,7 +91,8 @@ Data types
UV_FS_SYMLINK,
UV_FS_READLINK,
UV_FS_CHOWN,
UV_FS_FCHOWN
UV_FS_FCHOWN,
UV_FS_REALPATH
} uv_fs_type;
.. c:type:: uv_dirent_t
@ -258,6 +259,12 @@ API
Equivalent to :man:`utime(2)` and :man:`futime(2)` respectively.
.. note::
AIX: This function only works for AIX 7.1 and newer. It can still be called on older
versions but will return ``UV_ENOSYS``.
.. versionchanged:: 1.10.0 sub-second precission is supported on Windows
.. c:function:: int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb)
Equivalent to :man:`link(2)`.

View File

@ -8,6 +8,20 @@ FS Event handles allow the user to monitor a given path for changes, for example
if the file was renamed or there was a generic change in it. This handle uses
the best backend for the job on each platform.
.. note::
For AIX, the non default IBM bos.ahafs package has to be installed.
The AIX Event Infrastructure file system (ahafs) has some limitations:
- ahafs tracks monitoring per process and is not thread safe. A separate process
must be spawned for each monitor for the same event.
- Events for file modification (writing to a file) are not received if only the
containing folder is watched.
See documentation_ for more details.
.. _documentation: http://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/
Data types
----------

View File

@ -183,7 +183,9 @@ API
.. c:function:: int uv_get_process_title(char* buffer, size_t size)
Gets the title of the current process.
Gets the title of the current process. If `buffer` is `NULL` or `size` is
zero, `UV_EINVAL` is returned. If `size` cannot accommodate the process
title and terminating `NULL` character, the function returns `UV_ENOBUFS`.
.. c:function:: int uv_set_process_title(const char* title)

View File

@ -26,7 +26,11 @@ Data types
.. c:type:: uv_write_t
Write request type.
Write request type. Careful attention must be paid when reusing objects of
this type. When a stream is in non-blocking mode, write requests sent
with ``uv_write`` will be queued. Reusing objects at this point is undefined
behaviour. It is safe to reuse the ``uv_write_t`` object only after the
callback passed to ``uv_write`` is fired.
.. c:type:: void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
@ -61,7 +65,7 @@ Data types
.. c:type:: void (*uv_shutdown_cb)(uv_shutdown_t* req, int status)
Callback called after s shutdown request has been completed. `status` will
Callback called after a shutdown request has been completed. `status` will
be 0 in case of success, < 0 otherwise.
.. c:type:: void (*uv_connection_cb)(uv_stream_t* server, int status)
@ -92,7 +96,7 @@ Public members
.. c:member:: uv_stream_t* uv_write_t.send_handle
Pointer to the stream being sent using this write request..
Pointer to the stream being sent using this write request.
.. seealso:: The :c:type:`uv_handle_t` members also apply.

View File

@ -156,7 +156,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
pqry.fd = pc.fd;
rc = pollset_query(loop->backend_fd, &pqry);
switch (rc) {
case -1:
case -1:
assert(0 && "Failed to query pollset for file descriptor");
abort();
case 0:
@ -333,20 +333,20 @@ int uv_exepath(char* buffer, size_t* size) {
pi.pi_pid = getpid();
res = getargs(&pi, sizeof(pi), args, sizeof(args));
if (res < 0)
if (res < 0)
return -EINVAL;
/*
* Possibilities for args:
* i) an absolute path such as: /home/user/myprojects/nodejs/node
* ii) a relative path such as: ./node or ../myprojects/nodejs/node
* iii) a bare filename such as "node", after exporting PATH variable
* iii) a bare filename such as "node", after exporting PATH variable
* to its location.
*/
/* Case i) and ii) absolute or relative paths */
if (strchr(args, '/') != NULL) {
if (realpath(args, abspath) != abspath)
if (realpath(args, abspath) != abspath)
return -errno;
abspath_size = strlen(abspath);
@ -360,7 +360,7 @@ int uv_exepath(char* buffer, size_t* size) {
return 0;
} else {
/* Case iii). Search PATH environment variable */
/* Case iii). Search PATH environment variable */
char trypath[PATH_MAX];
char *clonedpath = NULL;
char *token = NULL;
@ -376,7 +376,7 @@ int uv_exepath(char* buffer, size_t* size) {
token = strtok(clonedpath, ":");
while (token != NULL) {
snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
if (realpath(trypath, abspath) == abspath) {
if (realpath(trypath, abspath) == abspath) {
/* Check the match is executable */
if (access(abspath, X_OK) == 0) {
abspath_size = strlen(abspath);
@ -452,7 +452,7 @@ static char *uv__rawname(char *cp) {
}
/*
/*
* Determine whether given pathname is a directory
* Returns 0 if the path is a directory, -1 if not
*
@ -472,7 +472,7 @@ static int uv__path_is_a_directory(char* filename) {
}
/*
/*
* Check whether AHAFS is mounted.
* Returns 0 if AHAFS is mounted, or an error code < 0 on failure
*/
@ -547,7 +547,7 @@ static int uv__makedir_p(const char *dir) {
return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
}
/*
/*
* Creates necessary subdirectories in the AIX Event Infrastructure
* file system for monitoring the object specified.
* Returns code from mkdir call
@ -665,7 +665,7 @@ static int uv__skip_lines(char **p, int n) {
/*
* Parse the event occurrence data to figure out what event just occurred
* and take proper action.
*
*
* The buf is a pointer to the buffer containing the event occurrence data
* Returns 0 on success, -1 if unrecoverable error in parsing
*
@ -891,9 +891,10 @@ int uv_set_process_title(const char* title) {
int uv_get_process_title(char* buffer, size_t size) {
if (size > 0) {
buffer[0] = '\0';
}
if (buffer == NULL || size == 0)
return -EINVAL;
buffer[0] = '\0';
return 0;
}

View File

@ -31,6 +31,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
@ -40,11 +41,8 @@
#include <sys/resource.h> /* getrusage */
#include <pwd.h>
#ifdef __linux__
# include <sys/ioctl.h>
#endif
#ifdef __sun
# include <sys/filio.h>
# include <sys/types.h>
# include <sys/wait.h>
#endif
@ -52,7 +50,6 @@
#ifdef __APPLE__
# include <mach-o/dyld.h> /* _NSGetExecutablePath */
# include <sys/filio.h>
# include <sys/ioctl.h>
# if defined(O_CLOEXEC)
# define UV__O_CLOEXEC O_CLOEXEC
# endif
@ -61,7 +58,6 @@
#if defined(__FreeBSD__) || defined(__DragonFly__)
# include <sys/sysctl.h>
# include <sys/filio.h>
# include <sys/ioctl.h>
# include <sys/wait.h>
# define UV__O_CLOEXEC O_CLOEXEC
# if defined(__FreeBSD__) && __FreeBSD__ >= 10
@ -74,10 +70,6 @@
# endif
#endif
#ifdef _AIX
#include <sys/ioctl.h>
#endif
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
# include <dlfcn.h> /* for dlsym */
#endif
@ -508,8 +500,8 @@ int uv__close_nocheckstdio(int fd) {
rc = close(fd);
if (rc == -1) {
rc = -errno;
if (rc == -EINTR)
rc = -EINPROGRESS; /* For platform/libc consistency. */
if (rc == -EINTR || rc == -EINPROGRESS)
rc = 0; /* The close is in progress, not an error. */
errno = saved_errno;
}
@ -523,10 +515,7 @@ int uv__close(int fd) {
}
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
defined(_AIX) || defined(__DragonFly__)
int uv__nonblock(int fd, int set) {
int uv__nonblock_ioctl(int fd, int set) {
int r;
do
@ -540,7 +529,7 @@ int uv__nonblock(int fd, int set) {
}
int uv__cloexec(int fd, int set) {
int uv__cloexec_ioctl(int fd, int set) {
int r;
do
@ -553,10 +542,8 @@ int uv__cloexec(int fd, int set) {
return 0;
}
#else /* !(defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
defined(_AIX) || defined(__DragonFly__)) */
int uv__nonblock(int fd, int set) {
int uv__nonblock_fcntl(int fd, int set) {
int flags;
int r;
@ -587,7 +574,7 @@ int uv__nonblock(int fd, int set) {
}
int uv__cloexec(int fd, int set) {
int uv__cloexec_fcntl(int fd, int set) {
int flags;
int r;
@ -617,9 +604,6 @@ int uv__cloexec(int fd, int set) {
return 0;
}
#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
defined(_AIX) || defined(__DragonFly__) */
/* This function is not execve-safe, there is a race window
* between the call to dup() and fcntl(FD_CLOEXEC).

View File

@ -196,14 +196,24 @@ int uv_set_process_title(const char* title) {
int uv_get_process_title(char* buffer, size_t size) {
size_t len;
if (buffer == NULL || size == 0)
return -EINVAL;
if (process_title) {
strncpy(buffer, process_title, size);
len = strlen(process_title) + 1;
if (size < len)
return -ENOBUFS;
memcpy(buffer, process_title, len);
} else {
if (size > 0) {
buffer[0] = '\0';
}
len = 0;
}
buffer[len] = '\0';
return 0;
}

View File

@ -151,9 +151,9 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
goto skip;
ts[0].tv_sec = req->atime;
ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000;
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
ts[1].tv_sec = req->mtime;
ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000;
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
r = uv__utimesat(req->file, NULL, ts, 0);
if (r == 0)
@ -167,9 +167,9 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
skip:
tv[0].tv_sec = req->atime;
tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
tv[1].tv_sec = req->mtime;
tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
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);
@ -198,9 +198,9 @@ skip:
|| defined(__sun)
struct timeval tv[2];
tv[0].tv_sec = req->atime;
tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
tv[1].tv_sec = req->mtime;
tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
# if defined(__sun)
return futimesat(req->file, NULL, tv);
# else
@ -209,9 +209,9 @@ skip:
#elif defined(_AIX71)
struct timespec ts[2];
ts[0].tv_sec = req->atime;
ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000;
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
ts[1].tv_sec = req->mtime;
ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000;
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
return futimens(req->file, ts);
#else
errno = ENOSYS;
@ -251,7 +251,7 @@ static ssize_t uv__fs_open(uv_fs_t* req) {
*/
if (r >= 0 && uv__cloexec(r, 1) != 0) {
r = uv__close(r);
if (r != 0 && r != -EINPROGRESS)
if (r != 0)
abort();
r = -1;
}
@ -810,8 +810,11 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
static int uv__fs_stat(const char *path, uv_stat_t *buf) {
struct stat pbuf;
int ret;
ret = stat(path, &pbuf);
uv__to_stat(&pbuf, buf);
if (ret == 0)
uv__to_stat(&pbuf, buf);
return ret;
}
@ -819,8 +822,11 @@ static int uv__fs_stat(const char *path, uv_stat_t *buf) {
static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
struct stat pbuf;
int ret;
ret = lstat(path, &pbuf);
uv__to_stat(&pbuf, buf);
if (ret == 0)
uv__to_stat(&pbuf, buf);
return ret;
}
@ -828,8 +834,11 @@ static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
static int uv__fs_fstat(int fd, uv_stat_t *buf) {
struct stat pbuf;
int ret;
ret = fstat(fd, &pbuf);
uv__to_stat(&pbuf, buf);
if (ret == 0)
uv__to_stat(&pbuf, buf);
return ret;
}

View File

@ -152,11 +152,25 @@ struct uv__stream_queued_fds_s {
};
#if defined(_AIX) || \
defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__linux__)
#define uv__cloexec uv__cloexec_ioctl
#define uv__nonblock uv__nonblock_ioctl
#else
#define uv__cloexec uv__cloexec_fcntl
#define uv__nonblock uv__nonblock_fcntl
#endif
/* core */
int uv__nonblock(int fd, int set);
int uv__cloexec_ioctl(int fd, int set);
int uv__cloexec_fcntl(int fd, int set);
int uv__nonblock_ioctl(int fd, int set);
int uv__nonblock_fcntl(int fd, int set);
int uv__close(int fd);
int uv__close_nocheckstdio(int fd);
int uv__cloexec(int fd, int set);
int uv__socket(int domain, int type, int protocol);
int uv__dup(int fd);
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);

View File

@ -289,11 +289,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (nfds == 0) {
assert(timeout != -1);
timeout = real_timeout - timeout;
if (timeout > 0)
continue;
if (timeout == 0)
return;
return;
/* We may have been inside the system call for longer than |timeout|
* milliseconds so we need to update the timestamp to avoid drift.
*/
goto update_timeout;
}
if (nfds == -1) {
@ -484,12 +486,20 @@ int uv_exepath(char* buffer, size_t* size) {
uint64_t uv_get_free_memory(void) {
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
struct sysinfo info;
if (sysinfo(&info) == 0)
return (uint64_t) info.freeram * info.mem_unit;
return 0;
}
uint64_t uv_get_total_memory(void) {
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
struct sysinfo info;
if (sysinfo(&info) == 0)
return (uint64_t) info.totalram * info.mem_unit;
return 0;
}

View File

@ -28,11 +28,15 @@
#include <unistd.h>
int uv_loop_init(uv_loop_t* loop) {
void* saved_data;
int err;
uv__signal_global_once_init();
saved_data = loop->data;
memset(loop, 0, sizeof(*loop));
loop->data = saved_data;
heap_init((struct heap*) &loop->timer_heap);
QUEUE_INIT(&loop->wq);
QUEUE_INIT(&loop->active_reqs);

View File

@ -147,14 +147,24 @@ int uv_set_process_title(const char* title) {
int uv_get_process_title(char* buffer, size_t size) {
size_t len;
if (buffer == NULL || size == 0)
return -EINVAL;
if (process_title) {
strncpy(buffer, process_title, size);
len = strlen(process_title) + 1;
if (size < len)
return -ENOBUFS;
memcpy(buffer, process_title, len);
} else {
if (size > 0) {
buffer[0] = '\0';
}
len = 0;
}
buffer[len] = '\0';
return 0;
}

View File

@ -169,14 +169,24 @@ int uv_set_process_title(const char* title) {
int uv_get_process_title(char* buffer, size_t size) {
size_t len;
if (buffer == NULL || size == 0)
return -EINVAL;
if (process_title) {
strncpy(buffer, process_title, size);
len = strlen(process_title) + 1;
if (size < len)
return -ENOBUFS;
memcpy(buffer, process_title, len);
} else {
if (size > 0) {
buffer[0] = '\0';
}
len = 0;
}
buffer[len] = '\0';
return 0;
}

View File

@ -59,7 +59,14 @@ int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
if (err)
return err;
/* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL).
* Workaround for e.g. kqueue fds not supporting ioctls.
*/
err = uv__nonblock(fd, 1);
if (err == -ENOTTY)
if (uv__nonblock == uv__nonblock_ioctl)
err = uv__nonblock_fcntl(fd, 1);
if (err)
return err;

View File

@ -232,7 +232,7 @@ static int uv__process_open_stream(uv_stdio_container_t* container,
return 0;
err = uv__close(pipefds[1]);
if (err != 0 && err != -EINPROGRESS)
if (err != 0)
abort();
pipefds[1] = -1;

View File

@ -87,10 +87,13 @@ int uv_set_process_title(const char* title) {
int uv_get_process_title(char* buffer, size_t size) {
if (process_title.len > 0)
strncpy(buffer, process_title.str, size);
else if (size > 0)
buffer[0] = '\0';
if (buffer == NULL || size == 0)
return -EINVAL;
else if (size <= process_title.len)
return -ENOBUFS;
memcpy(buffer, process_title.str, process_title.len + 1);
buffer[process_title.len] = '\0';
return 0;
}

View File

@ -571,7 +571,6 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
int uv_accept(uv_stream_t* server, uv_stream_t* client) {
int err;
/* TODO document this */
assert(server->loop == client->loop);
if (server->accepted_fd == -1)
@ -962,8 +961,8 @@ uv_handle_type uv__handle_type(int fd) {
return UV_UNKNOWN_HANDLE;
if (type == SOCK_STREAM) {
#if defined(_AIX)
/* on AIX the getsockname call returns an empty sa structure
#if defined(_AIX) || defined(__DragonFly__)
/* on AIX/DragonFly the getsockname call returns an empty sa structure
* for sockets of type AF_UNIX. For all other types it will
* return a properly filled in structure.
*/

View File

@ -33,6 +33,8 @@
#endif
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_arp.h>
#include <sys/sockio.h>
#include <sys/loadavg.h>
#include <sys/time.h>
@ -540,9 +542,10 @@ int uv_set_process_title(const char* title) {
int uv_get_process_title(char* buffer, size_t size) {
if (size > 0) {
buffer[0] = '\0';
}
if (buffer == NULL || size == 0)
return -EINVAL;
buffer[0] = '\0';
return 0;
}
@ -692,13 +695,57 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
uv__free(cpu_infos);
}
/*
* Inspired By:
* https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris
* http://www.pauliesworld.org/project/getmac.c
*/
static int uv__set_phys_addr(uv_interface_address_t* address,
struct ifaddrs* ent) {
struct sockaddr_dl* sa_addr;
int sockfd;
int i;
struct arpreq arpreq;
/* This appears to only work as root */
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
for (i = 0; i < sizeof(address->phys_addr); i++) {
if (address->phys_addr[i] != 0)
return 0;
}
memset(&arpreq, 0, sizeof(arpreq));
if (address->address.address4.sin_family == AF_INET) {
struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa);
sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr;
} else if (address->address.address4.sin_family == AF_INET6) {
struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa);
memcpy(sin->sin6_addr.s6_addr,
address->address.address6.sin6_addr.s6_addr,
sizeof(address->address.address6.sin6_addr.s6_addr));
} else {
return 0;
}
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
return -errno;
if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) {
uv__close(sockfd);
return -errno;
}
memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr));
uv__close(sockfd);
return 0;
}
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
#ifdef SUNOS_NO_IFADDRS
return -ENOSYS;
#else
uv_interface_address_t* address;
struct sockaddr_dl* sa_addr;
struct ifaddrs* addrs;
struct ifaddrs* ent;
int i;
@ -751,28 +798,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) ||
(ent->ifa_flags & IFF_LOOPBACK));
uv__set_phys_addr(address, ent);
address++;
}
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
(ent->ifa_addr == NULL) ||
(ent->ifa_addr->sa_family != AF_LINK)) {
continue;
}
address = *addresses;
for (i = 0; i < (*count); i++) {
if (strcmp(address->name, ent->ifa_name) == 0) {
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
}
address++;
}
}
freeifaddrs(addrs);
return 0;

View File

@ -158,11 +158,17 @@ int uv__tcp_connect(uv_connect_t* req,
handle->delayed_error = 0;
do
do {
errno = 0;
r = connect(uv__stream_fd(handle), addr, addrlen);
while (r == -1 && errno == EINTR);
} while (r == -1 && errno == EINTR);
if (r == -1) {
/* We not only check the return value, but also check the errno != 0.
* Because in rare cases connect() will return -1 but the errno
* is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227)
* and actually the tcp three-way handshake is completed.
*/
if (r == -1 && errno != 0) {
if (errno == EINPROGRESS)
; /* not an error */
else if (errno == ECONNREFUSED)

View File

@ -57,6 +57,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
int flags;
int newfd;
int r;
int saved_flags;
char path[256];
/* File descriptors that refer to files cannot be monitored with epoll.
@ -113,6 +114,22 @@ 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 -errno;
}
#endif
/* Pacify the compiler. */
(void) &saved_flags;
skip:
uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
@ -120,13 +137,20 @@ skip:
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
*/
if (!(flags & UV_STREAM_BLOCKING))
uv__nonblock(fd, 1);
#if defined(__APPLE__)
r = uv__stream_try_select((uv_stream_t*) tty, &fd);
if (r) {
int rc = r;
if (newfd != -1)
uv__close(newfd);
QUEUE_REMOVE(&tty->handle_queue);
return r;
do
r = fcntl(fd, F_SETFL, saved_flags);
while (r == -1 && errno == EINTR);
return rc;
}
#endif
@ -135,9 +159,6 @@ skip:
else
flags |= UV_STREAM_WRITABLE;
if (!(flags & UV_STREAM_BLOCKING))
uv__nonblock(fd, 1);
uv__stream_open((uv_stream_t*) tty, fd, flags);
tty->mode = UV_TTY_MODE_NORMAL;
@ -268,14 +289,14 @@ uv_handle_type uv_guess_handle(uv_file file) {
return UV_UDP;
if (type == SOCK_STREAM) {
#if defined(_AIX)
/* on AIX the getsockname call returns an empty sa structure
#if defined(_AIX) || defined(__DragonFly__)
/* on AIX/DragonFly the getsockname call returns an empty sa structure
* for sockets of type AF_UNIX. For all other types it will
* return a properly filled in structure.
*/
if (len == 0)
return UV_NAMED_PIPE;
#endif /* defined(_AIX) */
#endif /* defined(_AIX) || defined(__DragonFly__) */
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
return UV_TCP;

View File

@ -613,6 +613,7 @@ uv_loop_t* uv_loop_new(void) {
int uv_loop_close(uv_loop_t* loop) {
QUEUE* q;
uv_handle_t* h;
void* saved_data;
if (!QUEUE_EMPTY(&(loop)->active_reqs))
return UV_EBUSY;
@ -626,7 +627,9 @@ int uv_loop_close(uv_loop_t* loop) {
uv__loop_close(loop);
#ifndef NDEBUG
saved_data = loop->data;
memset(loop, -1, sizeof(*loop));
loop->data = saved_data;
#endif
if (loop == default_loop_ptr)
default_loop_ptr = NULL;

View File

@ -344,6 +344,22 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
}
static int file_info_cmp(WCHAR* str, WCHAR* file_name, int file_name_len) {
int str_len;
str_len = wcslen(str);
/*
Since we only care about equality, return early if the strings
aren't the same length
*/
if (str_len != (file_name_len / sizeof(WCHAR)))
return -1;
return _wcsnicmp(str, file_name, str_len);
}
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
uv_fs_event_t* handle) {
FILE_NOTIFY_INFORMATION* file_info;
@ -383,10 +399,12 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
* or if the filename filter matches.
*/
if (handle->dirw ||
_wcsnicmp(handle->filew, file_info->FileName,
file_info->FileNameLength / sizeof(WCHAR)) == 0 ||
_wcsnicmp(handle->short_filew, file_info->FileName,
file_info->FileNameLength / sizeof(WCHAR)) == 0) {
file_info_cmp(handle->filew,
file_info->FileName,
file_info->FileNameLength) == 0 ||
file_info_cmp(handle->short_filew,
file_info->FileName,
file_info->FileNameLength) == 0) {
if (handle->dirw) {
/*

View File

@ -94,7 +94,7 @@
#define TIME_T_TO_FILETIME(time, filetime_ptr) \
do { \
uint64_t bigtime = ((int64_t) (time) * 10000000LL) + \
uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \
116444736000000000ULL; \
(filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
(filetime_ptr)->dwHighDateTime = bigtime >> 32; \
@ -204,14 +204,11 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
req->fs.info.new_pathw = NULL;
}
if (!copy_path) {
req->path = path;
} else if (path) {
req->path = path;
if (path != NULL && copy_path) {
memcpy(pos, path, path_len);
assert(path_len == buf_sz - (pos - buf));
req->path = pos;
} else {
req->path = NULL;
}
req->flags |= UV_FS_FREE_PATHS;
@ -1429,8 +1426,8 @@ static void fs__fchmod(uv_fs_t* req) {
INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
FILETIME filetime_a, filetime_m;
TIME_T_TO_FILETIME((time_t) atime, &filetime_a);
TIME_T_TO_FILETIME((time_t) mtime, &filetime_m);
TIME_T_TO_FILETIME(atime, &filetime_a);
TIME_T_TO_FILETIME(mtime, &filetime_m);
if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
return -1;

View File

@ -85,7 +85,7 @@ static void eof_timer_close_cb(uv_handle_t* handle);
static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId());
snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId());
}

View File

@ -40,6 +40,9 @@
#include "stream-inl.h"
#include "req-inl.h"
#ifndef InterlockedOr
# define InterlockedOr _InterlockedOr
#endif
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
@ -294,6 +297,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
break;
case UV_TTY_MODE_IO:
return UV_ENOTSUP;
default:
return UV_EINVAL;
}
if (!SetConsoleMode(tty->handle, flags)) {

View File

@ -416,6 +416,11 @@ static int uv__get_process_title() {
int uv_get_process_title(char* buffer, size_t size) {
size_t len;
if (buffer == NULL || size == 0)
return UV_EINVAL;
uv__once_init();
EnterCriticalSection(&process_title_lock);
@ -429,7 +434,14 @@ int uv_get_process_title(char* buffer, size_t size) {
}
assert(process_title);
strncpy(buffer, process_title, size);
len = strlen(process_title) + 1;
if (size < len) {
LeaveCriticalSection(&process_title_lock);
return UV_ENOBUFS;
}
memcpy(buffer, process_title, len);
LeaveCriticalSection(&process_title_lock);
return 0;

View File

@ -43,11 +43,6 @@
/* Do platform-specific initialization. */
int platform_init(int argc, char **argv) {
const char* tap;
tap = getenv("UV_TAP_OUTPUT");
tap_output = (tap != NULL && atoi(tap) > 0);
/* Disable stdio output buffering. */
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
@ -294,8 +289,7 @@ long int process_output_size(process_info_t *p) {
/* Copy the contents of the stdio output buffer to `fd`. */
int process_copy_output(process_info_t *p, int fd) {
ssize_t nwritten;
int process_copy_output(process_info_t* p, FILE* stream) {
char buf[1024];
int r;
@ -306,20 +300,8 @@ int process_copy_output(process_info_t *p, int fd) {
}
/* TODO: what if the line is longer than buf */
while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) {
/* TODO: what if write doesn't write the whole buffer... */
nwritten = 0;
if (tap_output)
nwritten += write(fd, "#", 1);
nwritten += write(fd, buf, strlen(buf));
if (nwritten < 0) {
perror("write");
return -1;
}
}
while (fgets(buf, sizeof(buf), p->stdout_file) != NULL)
print_lines(buf, strlen(buf), stream);
if (ferror(p->stdout_file)) {
perror("read");

View File

@ -44,11 +44,6 @@
/* Do platform-specific initialization. */
int platform_init(int argc, char **argv) {
const char* tap;
tap = getenv("UV_TAP_OUTPUT");
tap_output = (tap != NULL && atoi(tap) > 0);
/* Disable the "application crashed" popup. */
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
@ -213,10 +208,9 @@ long int process_output_size(process_info_t *p) {
}
int process_copy_output(process_info_t *p, int fd) {
int process_copy_output(process_info_t* p, FILE* stream) {
DWORD read;
char buf[1024];
char *line, *start;
if (SetFilePointer(p->stdio_out,
0,
@ -225,29 +219,8 @@ int process_copy_output(process_info_t *p, int fd) {
return -1;
}
if (tap_output)
write(fd, "#", 1);
while (ReadFile(p->stdio_out, (void*)&buf, sizeof(buf), &read, NULL) &&
read > 0) {
if (tap_output) {
start = buf;
while ((line = strchr(start, '\n')) != NULL) {
write(fd, start, line - start + 1);
write(fd, "#", 1);
start = line + 1;
}
if (start < buf + read)
write(fd, start, buf + read - start);
} else {
write(fd, buf, read);
}
}
if (tap_output)
write(fd, "\n", 1);
while (ReadFile(p->stdio_out, &buf, sizeof(buf), &read, NULL) && read > 0)
print_lines(buf, read, stream);
if (GetLastError() != ERROR_HANDLE_EOF)
return -1;

View File

@ -28,31 +28,6 @@
char executable_path[sizeof(executable_path)];
int tap_output = 0;
static void log_progress(int total,
int passed,
int failed,
int todos,
int skipped,
const char* name) {
int progress;
if (total == 0)
total = 1;
progress = 100 * (passed + failed + skipped + todos) / total;
fprintf(stderr, "[%% %3d|+ %3d|- %3d|T %3d|S %3d]: %s",
progress,
passed,
failed,
todos,
skipped,
name);
fflush(stderr);
}
const char* fmt(double d) {
static char buf[1024];
@ -95,7 +70,6 @@ int run_tests(int benchmark_output) {
int total;
int passed;
int failed;
int todos;
int skipped;
int current;
int test_result;
@ -109,15 +83,12 @@ int run_tests(int benchmark_output) {
}
}
if (tap_output) {
fprintf(stderr, "1..%d\n", total);
fflush(stderr);
}
fprintf(stderr, "1..%d\n", total);
fflush(stderr);
/* Run all tests. */
passed = 0;
failed = 0;
todos = 0;
skipped = 0;
current = 1;
for (task = TASKS; task->main; task++) {
@ -125,30 +96,15 @@ int run_tests(int benchmark_output) {
continue;
}
if (!tap_output)
rewind_cursor();
if (!benchmark_output && !tap_output) {
log_progress(total, passed, failed, todos, skipped, task->task_name);
}
test_result = run_test(task->task_name, benchmark_output, current);
switch (test_result) {
case TEST_OK: passed++; break;
case TEST_TODO: todos++; break;
case TEST_SKIP: skipped++; break;
default: failed++;
}
current++;
}
if (!tap_output)
rewind_cursor();
if (!benchmark_output && !tap_output) {
log_progress(total, passed, failed, todos, skipped, "Done.\n");
}
return failed;
}
@ -166,10 +122,6 @@ void log_tap_result(int test_count,
result = "ok";
directive = "";
break;
case TEST_TODO:
result = "not ok";
directive = " # TODO ";
break;
case TEST_SKIP:
result = "ok";
directive = " # SKIP ";
@ -179,8 +131,7 @@ void log_tap_result(int test_count,
directive = "";
}
if ((status == TEST_SKIP || status == TEST_TODO) &&
process_output_size(process) > 0) {
if (status == TEST_SKIP && process_output_size(process) > 0) {
process_read_last_line(process, reason, sizeof reason);
} else {
reason[0] = '\0';
@ -319,22 +270,11 @@ out:
FATAL("process_wait failed");
}
if (tap_output)
log_tap_result(test_count, test, status, &processes[i]);
log_tap_result(test_count, test, status, &processes[i]);
/* Show error and output from processes if the test failed. */
if (status != 0 || task->show_output) {
if (tap_output) {
fprintf(stderr, "#");
} else if (status == TEST_TODO) {
fprintf(stderr, "\n`%s` todo\n", test);
} else if (status == TEST_SKIP) {
fprintf(stderr, "\n`%s` skipped\n", test);
} else if (status != 0) {
fprintf(stderr, "\n`%s` failed: %s\n", test, errmsg);
} else {
fprintf(stderr, "\n");
}
if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) {
fprintf(stderr, "# ");
fflush(stderr);
for (i = 0; i < process_count; i++) {
@ -354,15 +294,11 @@ out:
default:
fprintf(stderr, "Output from process `%s`:\n", process_get_name(&processes[i]));
fflush(stderr);
process_copy_output(&processes[i], fileno(stderr));
process_copy_output(&processes[i], stderr);
break;
}
}
if (!tap_output) {
fprintf(stderr, "=============================================================\n");
}
/* In benchmark mode show concise output from the main process. */
} else if (benchmark_output) {
switch (process_output_size(main_proc)) {
@ -378,7 +314,7 @@ out:
default:
for (i = 0; i < process_count; i++) {
process_copy_output(&processes[i], fileno(stderr));
process_copy_output(&processes[i], stderr);
}
break;
}
@ -464,3 +400,21 @@ void print_tests(FILE* stream) {
}
}
}
void print_lines(const char* buffer, size_t size, FILE* stream) {
const char* start;
const char* end;
start = buffer;
while ((end = memchr(start, '\n', &buffer[size] - start))) {
fprintf(stream, "# %.*s\n", (int) (end - start), start);
fflush(stream);
start = end + 1;
}
if (start < &buffer[size]) {
fprintf(stream, "# %s\n", start);
fflush(stream);
}
}

View File

@ -126,6 +126,8 @@ int run_test_part(const char* test, const char* part);
*/
void print_tests(FILE* stream);
/* Print lines in |buffer| as TAP diagnostics to |stream|. */
void print_lines(const char* buffer, size_t size, FILE* stream);
/*
* Stuff that should be implemented by test-runner-<platform>.h
@ -148,8 +150,8 @@ int process_wait(process_info_t *vec, int n, int timeout);
/* Returns the number of bytes in the stdio output buffer for process `p`. */
long int process_output_size(process_info_t *p);
/* Copy the contents of the stdio output buffer to `fd`. */
int process_copy_output(process_info_t *p, int fd);
/* Copy the contents of the stdio output buffer to `stream`. */
int process_copy_output(process_info_t* p, FILE* stream);
/* Copy the last line of the stdio output buffer to `buffer` */
int process_read_last_line(process_info_t *p,
@ -172,7 +174,4 @@ void process_cleanup(process_info_t *p);
/* Move the console cursor one line up and back to the first column. */
void rewind_cursor(void);
/* trigger output as tap */
extern int tap_output;
#endif /* RUNNER_H_ */

View File

@ -136,7 +136,6 @@ const char* fmt(double d);
/* Reserved test exit codes. */
enum test_status {
TEST_OK = 0,
TEST_TODO,
TEST_SKIP
};
@ -145,13 +144,6 @@ enum test_status {
return TEST_OK; \
} while (0)
#define RETURN_TODO(explanation) \
do { \
fprintf(stderr, "%s\n", explanation); \
fflush(stderr); \
return TEST_TODO; \
} while (0)
#define RETURN_SKIP(explanation) \
do { \
fprintf(stderr, "%s\n", explanation); \

View File

@ -53,6 +53,14 @@ static char fs_event_filename[PATH_MAX];
static char fs_event_filename[1024];
#endif /* defined(PATH_MAX) */
static int timer_cb_touch_called;
static int timer_cb_exact_called;
static void fs_event_fail(uv_fs_event_t* handle,
const char* filename,
int events,
int status) {
ASSERT(0 && "should never be called");
}
static void create_dir(const char* name) {
int r;
@ -345,6 +353,21 @@ static void timer_cb_touch(uv_timer_t* timer) {
timer_cb_touch_called++;
}
static void timer_cb_exact(uv_timer_t* handle) {
int r;
if (timer_cb_exact_called == 0) {
touch_file("watch_dir/file.js");
} else {
uv_close((uv_handle_t*)handle, NULL);
r = uv_fs_event_stop(&fs_event);
ASSERT(r == 0);
uv_close((uv_handle_t*) &fs_event, NULL);
}
++timer_cb_exact_called;
}
static void timer_cb_watch_twice(uv_timer_t* handle) {
uv_fs_event_t* handles = handle->data;
uv_close((uv_handle_t*) (handles + 0), NULL);
@ -467,6 +490,45 @@ TEST_IMPL(fs_event_watch_file) {
return 0;
}
TEST_IMPL(fs_event_watch_file_exact_path) {
/*
This test watches a file named "file.jsx" and modifies a file named
"file.js". The test verifies that no events occur for file.jsx.
*/
uv_loop_t* loop;
int r;
loop = uv_default_loop();
/* Setup */
remove("watch_dir/file.js");
remove("watch_dir/file.jsx");
remove("watch_dir/");
create_dir("watch_dir");
create_file("watch_dir/file.js");
create_file("watch_dir/file.jsx");
r = uv_fs_event_init(loop, &fs_event);
ASSERT(r == 0);
r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file.jsx", 0);
ASSERT(r == 0);
r = uv_timer_init(loop, &timer);
ASSERT(r == 0);
r = uv_timer_start(&timer, timer_cb_exact, 100, 100);
ASSERT(r == 0);
r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT(r == 0);
ASSERT(timer_cb_exact_called == 2);
/* Cleanup */
remove("watch_dir/file.js");
remove("watch_dir/file.jsx");
remove("watch_dir/");
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(fs_event_watch_file_twice) {
const char path[] = "test/fixtures/empty_file";
uv_fs_event_t watchers[2];
@ -626,12 +688,6 @@ TEST_IMPL(fs_event_no_callback_on_close) {
}
static void fs_event_fail(uv_fs_event_t* handle, const char* filename,
int events, int status) {
ASSERT(0 && "should never be called");
}
static void timer_cb(uv_timer_t* handle) {
int r;

View File

@ -662,8 +662,8 @@ static void check_utime(const char* path, double atime, double mtime) {
ASSERT(req.result == 0);
s = &req.statbuf;
ASSERT(s->st_atim.tv_sec == atime);
ASSERT(s->st_mtim.tv_sec == mtime);
ASSERT(s->st_atim.tv_sec + (s->st_atim.tv_nsec / 1000000000.0) == atime);
ASSERT(s->st_mtim.tv_sec + (s->st_mtim.tv_nsec / 1000000000.0) == mtime);
uv_fs_req_cleanup(&req);
}
@ -1968,6 +1968,15 @@ TEST_IMPL(fs_utime) {
atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
/*
* Test sub-second timestamps only on Windows (assuming NTFS). Some other
* platforms support sub-second timestamps, but that support is filesystem-
* dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps.
*/
#ifdef _WIN32
mtime += 0.444; /* 1982-09-10 11:22:33.444 */
#endif
r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
ASSERT(r == 0);
ASSERT(req.result == 0);
@ -2055,6 +2064,15 @@ TEST_IMPL(fs_futime) {
atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
/*
* Test sub-second timestamps only on Windows (assuming NTFS). Some other
* platforms support sub-second timestamps, but that support is filesystem-
* dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps.
*/
#ifdef _WIN32
mtime += 0.444; /* 1982-09-10 11:22:33.444 */
#endif
r = uv_fs_open(NULL, &req, path, O_RDWR, 0, NULL);
ASSERT(r >= 0);
ASSERT(req.result >= 0);

View File

@ -68,8 +68,8 @@ static struct echo_ctx ctx2;
/* Used in write2_cb to decide if we need to cleanup or not */
static int is_child_process;
static int is_in_process;
static int read_cb_called;
static int recv_cb_called;
static int read_cb_count;
static int recv_cb_count;
static int write2_cb_called;
@ -91,43 +91,46 @@ static void recv_cb(uv_stream_t* handle,
int r;
union handles* recv;
if (++recv_cb_called == 1) {
recv = &ctx.recv;
} else {
recv = &ctx.recv2;
}
pipe = (uv_pipe_t*) handle;
ASSERT(pipe == &ctx.channel);
/* Depending on the OS, the final recv_cb can be called after the child
* process has terminated which can result in nread being UV_EOF instead of
* the number of bytes read. Since the other end of the pipe has closed this
* UV_EOF is an acceptable value. */
if (nread == UV_EOF) {
/* UV_EOF is only acceptable for the final recv_cb call */
ASSERT(recv_cb_called == 2);
} else {
ASSERT(nread >= 0);
ASSERT(1 == uv_pipe_pending_count(pipe));
do {
if (++recv_cb_count == 1) {
recv = &ctx.recv;
} else {
recv = &ctx.recv2;
}
pending = uv_pipe_pending_type(pipe);
ASSERT(pending == ctx.expected_type);
/* Depending on the OS, the final recv_cb can be called after
* the child process has terminated which can result in nread
* being UV_EOF instead of the number of bytes read. Since
* the other end of the pipe has closed this UV_EOF is an
* acceptable value. */
if (nread == UV_EOF) {
/* UV_EOF is only acceptable for the final recv_cb call */
ASSERT(recv_cb_count == 2);
} else {
ASSERT(nread >= 0);
ASSERT(uv_pipe_pending_count(pipe) > 0);
if (pending == UV_NAMED_PIPE)
r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0);
else if (pending == UV_TCP)
r = uv_tcp_init(ctx.channel.loop, &recv->tcp);
else
abort();
ASSERT(r == 0);
pending = uv_pipe_pending_type(pipe);
ASSERT(pending == ctx.expected_type);
r = uv_accept(handle, &recv->stream);
ASSERT(r == 0);
}
if (pending == UV_NAMED_PIPE)
r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0);
else if (pending == UV_TCP)
r = uv_tcp_init(ctx.channel.loop, &recv->tcp);
else
abort();
ASSERT(r == 0);
r = uv_accept(handle, &recv->stream);
ASSERT(r == 0);
}
} while (uv_pipe_pending_count(pipe) > 0);
/* Close after two writes received */
if (recv_cb_called == 2) {
if (recv_cb_count == 2) {
uv_close((uv_handle_t*)&ctx.channel, NULL);
}
}
@ -186,7 +189,7 @@ static int run_test(int inprocess) {
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0);
ASSERT(recv_cb_called == 2);
ASSERT(recv_cb_count == 2);
if (inprocess) {
r = uv_thread_join(&tid);
@ -293,41 +296,43 @@ static void read_cb(uv_stream_t* handle,
return;
}
if (++read_cb_called == 2) {
recv = &ctx2.recv;
write_req = &ctx2.write_req;
} else {
recv = &ctx2.recv2;
write_req = &ctx2.write_req2;
}
pipe = (uv_pipe_t*) handle;
ASSERT(pipe == &ctx2.channel);
ASSERT(nread >= 0);
ASSERT(1 == uv_pipe_pending_count(pipe));
do {
if (++read_cb_count == 2) {
recv = &ctx2.recv;
write_req = &ctx2.write_req;
} else {
recv = &ctx2.recv2;
write_req = &ctx2.write_req2;
}
pending = uv_pipe_pending_type(pipe);
ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
ASSERT(pipe == &ctx2.channel);
ASSERT(nread >= 0);
ASSERT(uv_pipe_pending_count(pipe) > 0);
if (pending == UV_NAMED_PIPE)
r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0);
else if (pending == UV_TCP)
r = uv_tcp_init(ctx2.channel.loop, &recv->tcp);
else
abort();
ASSERT(r == 0);
pending = uv_pipe_pending_type(pipe);
ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
r = uv_accept(handle, &recv->stream);
ASSERT(r == 0);
if (pending == UV_NAMED_PIPE)
r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0);
else if (pending == UV_TCP)
r = uv_tcp_init(ctx2.channel.loop, &recv->tcp);
else
abort();
ASSERT(r == 0);
wrbuf = uv_buf_init(".", 1);
r = uv_write2(write_req,
(uv_stream_t*)&ctx2.channel,
&wrbuf,
1,
&recv->stream,
write2_cb);
ASSERT(r == 0);
r = uv_accept(handle, &recv->stream);
ASSERT(r == 0);
wrbuf = uv_buf_init(".", 1);
r = uv_write2(write_req,
(uv_stream_t*)&ctx2.channel,
&wrbuf,
1,
&recv->stream,
write2_cb);
ASSERT(r == 0);
} while (uv_pipe_pending_count(pipe) > 0);
}
static void send_recv_start() {

View File

@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
#include "uv.h"
TEST_DECLARE (platform_output)
TEST_DECLARE (callback_order)
TEST_DECLARE (close_order)
@ -273,6 +275,7 @@ TEST_DECLARE (fs_read_file_eof)
TEST_DECLARE (fs_event_watch_dir)
TEST_DECLARE (fs_event_watch_dir_recursive)
TEST_DECLARE (fs_event_watch_file)
TEST_DECLARE (fs_event_watch_file_exact_path)
TEST_DECLARE (fs_event_watch_file_twice)
TEST_DECLARE (fs_event_watch_file_current_dir)
#ifdef _WIN32
@ -314,13 +317,19 @@ TEST_DECLARE (poll_duplex)
TEST_DECLARE (poll_unidirectional)
TEST_DECLARE (poll_close)
TEST_DECLARE (poll_bad_fdtype)
#ifdef __linux__
TEST_DECLARE (poll_nested_epoll)
#endif
#ifdef UV_HAVE_KQUEUE
TEST_DECLARE (poll_nested_kqueue)
#endif
TEST_DECLARE (ip4_addr)
TEST_DECLARE (ip6_addr_link_local)
#ifdef _WIN32
TEST_DECLARE (poll_close_doesnt_corrupt_stack)
TEST_DECLARE (poll_closesocket)
#ifdef _WIN32
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
#if !defined(USING_UV_SHARED)
TEST_DECLARE (argument_escaping)
@ -624,6 +633,12 @@ TASK_LIST_START
TEST_ENTRY (poll_unidirectional)
TEST_ENTRY (poll_close)
TEST_ENTRY (poll_bad_fdtype)
#ifdef __linux__
TEST_ENTRY (poll_nested_epoll)
#endif
#ifdef UV_HAVE_KQUEUE
TEST_ENTRY (poll_nested_kqueue)
#endif
TEST_ENTRY (socket_buffer_size)
@ -655,9 +670,9 @@ TASK_LIST_START
TEST_ENTRY (fs_poll_getpath)
TEST_ENTRY (kill)
#ifdef _WIN32
TEST_ENTRY (poll_close_doesnt_corrupt_stack)
TEST_ENTRY (poll_closesocket)
#ifdef _WIN32
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
#if !defined(USING_UV_SHARED)
TEST_ENTRY (argument_escaping)
@ -710,6 +725,7 @@ TASK_LIST_START
TEST_ENTRY (fs_event_watch_dir)
TEST_ENTRY (fs_event_watch_dir_recursive)
TEST_ENTRY (fs_event_watch_file)
TEST_ENTRY (fs_event_watch_file_exact_path)
TEST_ENTRY (fs_event_watch_file_twice)
TEST_ENTRY (fs_event_watch_file_current_dir)
#ifdef _WIN32

View File

@ -34,7 +34,9 @@ TEST_IMPL(loop_close) {
int r;
uv_loop_t loop;
loop.data = &loop;
ASSERT(0 == uv_loop_init(&loop));
ASSERT(loop.data == (void*) &loop);
uv_timer_init(&loop, &timer_handle);
uv_timer_start(&timer_handle, timer_cb, 100, 100);
@ -47,7 +49,9 @@ TEST_IMPL(loop_close) {
r = uv_run(&loop, UV_RUN_DEFAULT);
ASSERT(r == 0);
ASSERT(loop.data == (void*) &loop);
ASSERT(0 == uv_loop_close(&loop));
ASSERT(loop.data == (void*) &loop);
return 0;
}

View File

@ -61,8 +61,6 @@ TEST_IMPL(platform_output) {
ASSERT(rusage.ru_utime.tv_usec >= 0);
ASSERT(rusage.ru_stime.tv_sec >= 0);
ASSERT(rusage.ru_stime.tv_usec >= 0);
ASSERT(rusage.ru_majflt >= 0);
ASSERT(rusage.ru_maxrss >= 0);
printf("uv_getrusage:\n");
printf(" user: %llu sec %llu microsec\n",
(unsigned long long) rusage.ru_utime.tv_sec,

View File

@ -19,8 +19,6 @@
* IN THE SOFTWARE.
*/
#ifdef _WIN32
#include <errno.h>
#include <stdio.h>
@ -37,6 +35,7 @@
uv_os_sock_t sock;
uv_poll_t handle;
#ifdef _WIN32
static int close_cb_called = 0;
@ -69,9 +68,13 @@ static void NO_INLINE close_socket_and_verify_stack() {
for (i = 0; i < ARRAY_SIZE(data); i++)
ASSERT(data[i] == MARKER);
}
#endif
TEST_IMPL(poll_close_doesnt_corrupt_stack) {
#ifndef _WIN32
RETURN_SKIP("Test only relevant on Windows");
#else
struct WSAData wsa_data;
int r;
unsigned long on;
@ -109,6 +112,5 @@ TEST_IMPL(poll_close_doesnt_corrupt_stack) {
MAKE_VALGRIND_HAPPY();
return 0;
#endif
}
#endif /* _WIN32 */

View File

@ -19,7 +19,6 @@
* IN THE SOFTWARE.
*/
#ifdef _WIN32
#include <errno.h>
@ -29,6 +28,7 @@
uv_os_sock_t sock;
uv_poll_t handle;
#ifdef _WIN32
static int close_cb_called = 0;
@ -50,9 +50,13 @@ static void poll_cb(uv_poll_t* h, int status, int events) {
uv_close((uv_handle_t*) &handle, close_cb);
}
#endif
TEST_IMPL(poll_closesocket) {
#ifndef _WIN32
RETURN_SKIP("Test only relevant on Windows");
#else
struct WSAData wsa_data;
int r;
unsigned long on;
@ -85,5 +89,5 @@ TEST_IMPL(poll_closesocket) {
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif
}

View File

@ -31,6 +31,16 @@
#include "uv.h"
#include "task.h"
#ifdef __linux__
# include <sys/epoll.h>
#endif
#ifdef UV_HAVE_KQUEUE
# include <sys/types.h>
# include <sys/event.h>
# include <sys/time.h>
#endif
#define NUM_CLIENTS 5
#define TRANSFER_BYTES (1 << 16)
@ -601,3 +611,47 @@ TEST_IMPL(poll_bad_fdtype) {
MAKE_VALGRIND_HAPPY();
return 0;
}
#ifdef __linux__
TEST_IMPL(poll_nested_epoll) {
uv_poll_t poll_handle;
int fd;
fd = epoll_create(1);
ASSERT(fd != -1);
ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd));
ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort));
ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT));
uv_close((uv_handle_t*) &poll_handle, NULL);
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT(0 == close(fd));
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif /* __linux__ */
#ifdef UV_HAVE_KQUEUE
TEST_IMPL(poll_nested_kqueue) {
uv_poll_t poll_handle;
int fd;
fd = kqueue();
ASSERT(fd != -1);
ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd));
ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort));
ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT));
uv_close((uv_handle_t*) &poll_handle, NULL);
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT(0 == close(fd));
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif /* UV_HAVE_KQUEUE */

View File

@ -41,6 +41,24 @@ static void set_title(const char* title) {
}
static void uv_get_process_title_edge_cases() {
char buffer[512];
int r;
/* Test a NULL buffer */
r = uv_get_process_title(NULL, 100);
ASSERT(r == UV_EINVAL);
/* Test size of zero */
r = uv_get_process_title(buffer, 0);
ASSERT(r == UV_EINVAL);
/* Test for insufficient buffer size */
r = uv_get_process_title(buffer, 1);
ASSERT(r == UV_ENOBUFS);
}
TEST_IMPL(process_title) {
#if defined(__sun) || defined(_AIX)
RETURN_SKIP("uv_(get|set)_process_title is not implemented.");
@ -48,6 +66,10 @@ TEST_IMPL(process_title) {
/* Check for format string vulnerabilities. */
set_title("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s");
set_title("new title");
/* Check uv_get_process_title() edge cases */
uv_get_process_title_edge_cases();
return 0;
#endif
}

View File

@ -40,6 +40,7 @@ static unsigned int got_connections;
static unsigned int close_cb_called;
static unsigned int write_cb_called;
static unsigned int read_cb_called;
static unsigned int pending_incoming;
static void close_cb(uv_handle_t* handle) {
close_cb_called++;
@ -58,8 +59,11 @@ static void connect_cb(uv_connect_t* req, int status) {
if (req == &tcp_check_req) {
ASSERT(status != 0);
/* Close check and incoming[0], time to finish test */
uv_close((uv_handle_t*) &tcp_incoming[0], close_cb);
/*
* Time to finish the test: close both the check and pending incoming
* connections
*/
uv_close((uv_handle_t*) &tcp_incoming[pending_incoming], close_cb);
uv_close((uv_handle_t*) &tcp_check, close_cb);
return;
}
@ -84,8 +88,8 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
uv_loop_t* loop;
unsigned int i;
/* Only first stream should receive read events */
ASSERT(stream == (uv_stream_t*) &tcp_incoming[0]);
pending_incoming = (uv_tcp_t*) stream - &tcp_incoming[0];
ASSERT(pending_incoming < got_connections);
ASSERT(0 == uv_read_stop(stream));
ASSERT(1 == nread);
@ -93,8 +97,13 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
read_cb_called++;
/* Close all active incomings, except current one */
for (i = 1; i < got_connections; i++)
uv_close((uv_handle_t*) &tcp_incoming[i], close_cb);
for (i = 0; i < got_connections; i++) {
if (i != pending_incoming)
uv_close((uv_handle_t*) &tcp_incoming[i], close_cb);
}
/* Close server, so no one will connect to it */
uv_close((uv_handle_t*) &tcp_server, close_cb);
/* Create new fd that should be one of the closed incomings */
ASSERT(0 == uv_tcp_init(loop, &tcp_check));
@ -103,9 +112,6 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
(const struct sockaddr*) &addr,
connect_cb));
ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb));
/* Close server, so no one will connect to it */
uv_close((uv_handle_t*) &tcp_server, close_cb);
}
static void connection_cb(uv_stream_t* server, int status) {

View File

@ -262,14 +262,17 @@ TEST_IMPL(tty_file) {
TEST_IMPL(tty_pty) {
# if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
int master_fd, slave_fd;
int master_fd, slave_fd, r;
struct winsize w;
uv_loop_t loop;
uv_tty_t master_tty, slave_tty;
ASSERT(0 == uv_loop_init(&loop));
ASSERT(0 == openpty(&master_fd, &slave_fd, NULL, NULL, &w));
r = openpty(&master_fd, &slave_fd, NULL, NULL, &w);
if (r != 0)
RETURN_SKIP("No pty available, skipping.");
ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0));
ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0));
/* Check if the file descriptor was reopened. If it is,

1
uv.gyp
View File

@ -426,6 +426,7 @@
'libraries': [ '-lws2_32' ]
}, { # POSIX
'defines': [ '_GNU_SOURCE' ],
'cflags': [ '-Wno-long-long' ],
'sources': [
'test/runner-unix.c',
'test/runner-unix.h',