mirror of https://github.com/lukechilds/node.git
Browse Source
Fixes: https://github.com/nodejs/node/issues/12737 Fixes: https://github.com/nodejs/node/issues/13581 Fixes: https://github.com/nodejs/node/issues/15117 PR-URL: https://github.com/nodejs/node/pull/14866 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>canary-base
cjihrig
7 years ago
54 changed files with 1486 additions and 555 deletions
@ -1,121 +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. |
|||
*/ |
|||
#include "uv-common.h" |
|||
#include "pthread-barrier.h" |
|||
|
|||
#include <stdlib.h> |
|||
#include <assert.h> |
|||
|
|||
/* TODO: support barrier_attr */ |
|||
int pthread_barrier_init(pthread_barrier_t* barrier, |
|||
const void* barrier_attr, |
|||
unsigned count) { |
|||
int rc; |
|||
_uv_barrier* b; |
|||
|
|||
if (barrier == NULL || count == 0) |
|||
return EINVAL; |
|||
|
|||
if (barrier_attr != NULL) |
|||
return ENOTSUP; |
|||
|
|||
b = uv__malloc(sizeof(*b)); |
|||
if (b == NULL) |
|||
return ENOMEM; |
|||
|
|||
b->in = 0; |
|||
b->out = 0; |
|||
b->threshold = count; |
|||
|
|||
if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) |
|||
goto error2; |
|||
if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) |
|||
goto error; |
|||
|
|||
barrier->b = b; |
|||
return 0; |
|||
|
|||
error: |
|||
pthread_mutex_destroy(&b->mutex); |
|||
error2: |
|||
uv__free(b); |
|||
return rc; |
|||
} |
|||
|
|||
int pthread_barrier_wait(pthread_barrier_t* barrier) { |
|||
int rc; |
|||
_uv_barrier* b; |
|||
|
|||
if (barrier == NULL || barrier->b == NULL) |
|||
return EINVAL; |
|||
|
|||
b = barrier->b; |
|||
/* Lock the mutex*/ |
|||
if ((rc = pthread_mutex_lock(&b->mutex)) != 0) |
|||
return rc; |
|||
|
|||
/* 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 (++b->in == b->threshold) { |
|||
b->in = 0; |
|||
b->out = b->threshold - 1; |
|||
rc = pthread_cond_signal(&b->cond); |
|||
assert(rc == 0); |
|||
|
|||
pthread_mutex_unlock(&b->mutex); |
|||
return PTHREAD_BARRIER_SERIAL_THREAD; |
|||
} |
|||
/* 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(&b->cond, &b->mutex)) != 0) |
|||
break; |
|||
} while (b->in != 0); |
|||
|
|||
/* mark thread exit */ |
|||
b->out--; |
|||
pthread_cond_signal(&b->cond); |
|||
pthread_mutex_unlock(&b->mutex); |
|||
return rc; |
|||
} |
|||
|
|||
int pthread_barrier_destroy(pthread_barrier_t* barrier) { |
|||
int rc; |
|||
_uv_barrier* b; |
|||
|
|||
if (barrier == NULL || barrier->b == NULL) |
|||
return EINVAL; |
|||
|
|||
b = barrier->b; |
|||
|
|||
if ((rc = pthread_mutex_lock(&b->mutex)) != 0) |
|||
return rc; |
|||
|
|||
if (b->in > 0 || b->out > 0) |
|||
rc = EBUSY; |
|||
|
|||
pthread_mutex_unlock(&b->mutex); |
|||
|
|||
if (rc) |
|||
return rc; |
|||
|
|||
pthread_cond_destroy(&b->cond); |
|||
pthread_mutex_destroy(&b->mutex); |
|||
uv__free(barrier->b); |
|||
barrier->b = NULL; |
|||
return 0; |
|||
} |
@ -0,0 +1,150 @@ |
|||
/* Copyright libuv project contributors. All rights reserved.
|
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to |
|||
* deal in the Software without restriction, including without limitation the |
|||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
|||
* sell copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
|||
* IN THE SOFTWARE. |
|||
*/ |
|||
|
|||
#include "uv.h" |
|||
#include "task.h" |
|||
|
|||
#if defined(__unix__) || defined(__POSIX__) || \ |
|||
defined(__APPLE__) || defined(_AIX) || defined(__MVS__) |
|||
#include <unistd.h> /* unlink, etc. */ |
|||
#else |
|||
# include <direct.h> |
|||
# include <io.h> |
|||
# define unlink _unlink |
|||
#endif |
|||
|
|||
static const char fixture[] = "test/fixtures/load_error.node"; |
|||
static const char dst[] = "test_file_dst"; |
|||
static int result_check_count; |
|||
|
|||
|
|||
static void handle_result(uv_fs_t* req) { |
|||
uv_fs_t stat_req; |
|||
uint64_t size; |
|||
uint64_t mode; |
|||
int r; |
|||
|
|||
ASSERT(req->fs_type == UV_FS_COPYFILE); |
|||
ASSERT(req->result == 0); |
|||
|
|||
/* Verify that the file size and mode are the same. */ |
|||
r = uv_fs_stat(NULL, &stat_req, req->path, NULL); |
|||
ASSERT(r == 0); |
|||
size = stat_req.statbuf.st_size; |
|||
mode = stat_req.statbuf.st_mode; |
|||
uv_fs_req_cleanup(&stat_req); |
|||
r = uv_fs_stat(NULL, &stat_req, dst, NULL); |
|||
ASSERT(r == 0); |
|||
ASSERT(stat_req.statbuf.st_size == size); |
|||
ASSERT(stat_req.statbuf.st_mode == mode); |
|||
uv_fs_req_cleanup(&stat_req); |
|||
uv_fs_req_cleanup(req); |
|||
result_check_count++; |
|||
} |
|||
|
|||
|
|||
static void touch_file(const char* name, unsigned int size) { |
|||
uv_file file; |
|||
uv_fs_t req; |
|||
uv_buf_t buf; |
|||
int r; |
|||
unsigned int i; |
|||
|
|||
r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); |
|||
uv_fs_req_cleanup(&req); |
|||
ASSERT(r >= 0); |
|||
file = r; |
|||
|
|||
buf = uv_buf_init("a", 1); |
|||
|
|||
/* Inefficient but simple. */ |
|||
for (i = 0; i < size; i++) { |
|||
r = uv_fs_write(NULL, &req, file, &buf, 1, i, NULL); |
|||
uv_fs_req_cleanup(&req); |
|||
ASSERT(r >= 0); |
|||
} |
|||
|
|||
r = uv_fs_close(NULL, &req, file, NULL); |
|||
uv_fs_req_cleanup(&req); |
|||
ASSERT(r == 0); |
|||
} |
|||
|
|||
|
|||
TEST_IMPL(fs_copyfile) { |
|||
const char src[] = "test_file_src"; |
|||
uv_loop_t* loop; |
|||
uv_fs_t req; |
|||
int r; |
|||
|
|||
loop = uv_default_loop(); |
|||
|
|||
/* Fails with EINVAL if bad flags are passed. */ |
|||
r = uv_fs_copyfile(NULL, &req, src, dst, -1, NULL); |
|||
ASSERT(r == UV_EINVAL); |
|||
uv_fs_req_cleanup(&req); |
|||
|
|||
/* Fails with ENOENT if source does not exist. */ |
|||
unlink(src); |
|||
unlink(dst); |
|||
r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); |
|||
ASSERT(req.result == UV_ENOENT); |
|||
ASSERT(r == UV_ENOENT); |
|||
uv_fs_req_cleanup(&req); |
|||
/* The destination should not exist. */ |
|||
r = uv_fs_stat(NULL, &req, dst, NULL); |
|||
ASSERT(r != 0); |
|||
uv_fs_req_cleanup(&req); |
|||
|
|||
/* Copies file synchronously. Creates new file. */ |
|||
unlink(dst); |
|||
r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); |
|||
ASSERT(r == 0); |
|||
handle_result(&req); |
|||
|
|||
/* Copies file synchronously. Overwrites existing file. */ |
|||
r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); |
|||
ASSERT(r == 0); |
|||
handle_result(&req); |
|||
|
|||
/* Fails to overwrites existing file. */ |
|||
r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_EXCL, NULL); |
|||
ASSERT(r == UV_EEXIST); |
|||
uv_fs_req_cleanup(&req); |
|||
|
|||
/* Copies a larger file. */ |
|||
unlink(dst); |
|||
touch_file(src, 4096 * 2); |
|||
r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); |
|||
ASSERT(r == 0); |
|||
handle_result(&req); |
|||
unlink(src); |
|||
|
|||
/* Copies file asynchronously */ |
|||
unlink(dst); |
|||
r = uv_fs_copyfile(loop, &req, fixture, dst, 0, handle_result); |
|||
ASSERT(r == 0); |
|||
ASSERT(result_check_count == 3); |
|||
uv_run(loop, UV_RUN_DEFAULT); |
|||
ASSERT(result_check_count == 4); |
|||
unlink(dst); /* Cleanup */ |
|||
|
|||
return 0; |
|||
} |
@ -0,0 +1,205 @@ |
|||
/* Copyright libuv project contributors. All rights reserved.
|
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to |
|||
* deal in the Software without restriction, including without limitation the |
|||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
|||
* sell copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
|||
* IN THE SOFTWARE. |
|||
*/ |
|||
|
|||
#if !defined(_WIN32) |
|||
|
|||
#include "uv.h" |
|||
#include "task.h" |
|||
|
|||
#include <errno.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/ioctl.h> |
|||
#include <unistd.h> |
|||
#include <string.h> |
|||
|
|||
static uv_tcp_t server_handle; |
|||
static uv_tcp_t client_handle; |
|||
static uv_tcp_t peer_handle; |
|||
static uv_poll_t poll_req[2]; |
|||
static uv_idle_t idle; |
|||
static uv_os_fd_t client_fd; |
|||
static uv_os_fd_t server_fd; |
|||
static int ticks; |
|||
static const int kMaxTicks = 10; |
|||
static int cli_pr_check = 0; |
|||
static int cli_rd_check = 0; |
|||
static int srv_rd_check = 0; |
|||
|
|||
static int got_eagain(void) { |
|||
return errno == EAGAIN |
|||
|| errno == EINPROGRESS |
|||
#ifdef EWOULDBLOCK |
|||
|| errno == EWOULDBLOCK |
|||
#endif |
|||
; |
|||
} |
|||
|
|||
static void idle_cb(uv_idle_t* idle) { |
|||
uv_sleep(100); |
|||
if (++ticks < kMaxTicks) |
|||
return; |
|||
|
|||
uv_poll_stop(&poll_req[0]); |
|||
uv_poll_stop(&poll_req[1]); |
|||
uv_close((uv_handle_t*) &server_handle, NULL); |
|||
uv_close((uv_handle_t*) &client_handle, NULL); |
|||
uv_close((uv_handle_t*) &peer_handle, NULL); |
|||
uv_close((uv_handle_t*) idle, NULL); |
|||
} |
|||
|
|||
static void poll_cb(uv_poll_t* handle, int status, int events) { |
|||
char buffer[5]; |
|||
int n; |
|||
int fd; |
|||
|
|||
ASSERT(0 == uv_fileno((uv_handle_t*)handle, &fd)); |
|||
memset(buffer, 0, 5); |
|||
|
|||
if (events & UV_PRIORITIZED) { |
|||
do |
|||
n = recv(client_fd, &buffer, 5, MSG_OOB); |
|||
while (n == -1 && errno == EINTR); |
|||
ASSERT(n >= 0 || errno != EINVAL); |
|||
cli_pr_check = 1; |
|||
ASSERT(0 == uv_poll_stop(&poll_req[0])); |
|||
ASSERT(0 == uv_poll_start(&poll_req[0], |
|||
UV_READABLE | UV_WRITABLE, |
|||
poll_cb)); |
|||
} |
|||
if (events & UV_READABLE) { |
|||
if (fd == client_fd) { |
|||
do |
|||
n = recv(client_fd, &buffer, 5, 0); |
|||
while (n == -1 && errno == EINTR); |
|||
ASSERT(n >= 0 || errno != EINVAL); |
|||
if (cli_rd_check == 1) { |
|||
ASSERT(strncmp(buffer, "world", n) == 0); |
|||
ASSERT(5 == n); |
|||
cli_rd_check = 2; |
|||
} |
|||
if (cli_rd_check == 0) { |
|||
ASSERT(n == 4); |
|||
ASSERT(strncmp(buffer, "hello", n) == 0); |
|||
cli_rd_check = 1; |
|||
do { |
|||
do |
|||
n = recv(server_fd, &buffer, 5, 0); |
|||
while (n == -1 && errno == EINTR); |
|||
if (n > 0) { |
|||
ASSERT(n == 5); |
|||
ASSERT(strncmp(buffer, "world", n) == 0); |
|||
cli_rd_check = 2; |
|||
} |
|||
} while (n > 0); |
|||
|
|||
ASSERT(got_eagain()); |
|||
} |
|||
} |
|||
if (fd == server_fd) { |
|||
do |
|||
n = recv(server_fd, &buffer, 3, 0); |
|||
while (n == -1 && errno == EINTR); |
|||
ASSERT(n >= 0 || errno != EINVAL); |
|||
ASSERT(3 == n); |
|||
ASSERT(strncmp(buffer, "foo", n) == 0); |
|||
srv_rd_check = 1; |
|||
uv_poll_stop(&poll_req[1]); |
|||
} |
|||
} |
|||
if (events & UV_WRITABLE) { |
|||
do { |
|||
n = send(client_fd, "foo", 3, 0); |
|||
} while (n < 0 && errno == EINTR); |
|||
ASSERT(3 == n); |
|||
} |
|||
} |
|||
|
|||
static void connection_cb(uv_stream_t* handle, int status) { |
|||
int r; |
|||
|
|||
ASSERT(0 == status); |
|||
ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle)); |
|||
ASSERT(0 == uv_fileno((uv_handle_t*) &peer_handle, &server_fd)); |
|||
ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &poll_req[0], client_fd)); |
|||
ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &poll_req[1], server_fd)); |
|||
ASSERT(0 == uv_poll_start(&poll_req[0], |
|||
UV_PRIORITIZED | UV_READABLE | UV_WRITABLE, |
|||
poll_cb)); |
|||
ASSERT(0 == uv_poll_start(&poll_req[1], |
|||
UV_READABLE, |
|||
poll_cb)); |
|||
do { |
|||
r = send(server_fd, "hello", 5, MSG_OOB); |
|||
} while (r < 0 && errno == EINTR); |
|||
ASSERT(5 == r); |
|||
|
|||
do { |
|||
r = send(server_fd, "world", 5, 0); |
|||
} while (r < 0 && errno == EINTR); |
|||
ASSERT(5 == r); |
|||
|
|||
ASSERT(0 == uv_idle_start(&idle, idle_cb)); |
|||
} |
|||
|
|||
|
|||
TEST_IMPL(poll_oob) { |
|||
struct sockaddr_in addr; |
|||
int r = 0; |
|||
uv_loop_t* loop; |
|||
|
|||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); |
|||
loop = uv_default_loop(); |
|||
|
|||
ASSERT(0 == uv_tcp_init(loop, &server_handle)); |
|||
ASSERT(0 == uv_tcp_init(loop, &client_handle)); |
|||
ASSERT(0 == uv_tcp_init(loop, &peer_handle)); |
|||
ASSERT(0 == uv_idle_init(loop, &idle)); |
|||
ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); |
|||
ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); |
|||
|
|||
/* Ensure two separate packets */ |
|||
ASSERT(0 == uv_tcp_nodelay(&client_handle, 1)); |
|||
|
|||
client_fd = socket(PF_INET, SOCK_STREAM, 0); |
|||
ASSERT(client_fd >= 0); |
|||
do { |
|||
errno = 0; |
|||
r = connect(client_fd, (const struct sockaddr*)&addr, sizeof(addr)); |
|||
} while (r == -1 && errno == EINTR); |
|||
ASSERT(r == 0); |
|||
|
|||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); |
|||
|
|||
ASSERT(ticks == kMaxTicks); |
|||
|
|||
/* Did client receive the POLLPRI message */ |
|||
ASSERT(cli_pr_check == 1); |
|||
/* Did client receive the POLLIN message */ |
|||
ASSERT(cli_rd_check == 2); |
|||
/* Could we write with POLLOUT and did the server receive our POLLOUT message
|
|||
* through POLLIN. |
|||
*/ |
|||
ASSERT(srv_rd_check == 1); |
|||
|
|||
MAKE_VALGRIND_HAPPY(); |
|||
return 0; |
|||
} |
|||
#endif |
Loading…
Reference in new issue