libuv 1.46.0.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4336 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
2023-07-04 00:24:48 +00:00
parent f0452704a1
commit ae0a8b0a33
65 changed files with 1519 additions and 755 deletions

View File

@ -22,6 +22,7 @@
BENCHMARK_DECLARE (sizes)
BENCHMARK_DECLARE (loop_count)
BENCHMARK_DECLARE (loop_count_timed)
BENCHMARK_DECLARE (loop_alive)
BENCHMARK_DECLARE (ping_pongs)
BENCHMARK_DECLARE (ping_udp1)
BENCHMARK_DECLARE (ping_udp10)
@ -89,6 +90,7 @@ TASK_LIST_START
BENCHMARK_ENTRY (sizes)
BENCHMARK_ENTRY (loop_count)
BENCHMARK_ENTRY (loop_count_timed)
BENCHMARK_ENTRY (loop_alive)
BENCHMARK_ENTRY (ping_pongs)
BENCHMARK_HELPER (ping_pongs, tcp4_echo_server)

View File

@ -26,6 +26,7 @@
#include <stdlib.h>
#define NUM_TICKS (2 * 1000 * 1000)
#define NUM_TICKS2 (2 * 1000 * 1000 * 100)
static unsigned long ticks;
static uv_idle_t idle_handle;
@ -37,6 +38,19 @@ static void idle_cb(uv_idle_t* handle) {
uv_idle_stop(handle);
}
static void idle_alive_cb(uv_idle_t* handle) {
int ticks = 0;
while (++ticks < NUM_TICKS2) {
int r = uv_loop_alive(handle->loop);
if (r == 0)
abort();
}
*(int*)handle->data = ticks;
uv_idle_stop(handle);
}
static void idle2_cb(uv_idle_t* handle) {
ticks++;
@ -90,3 +104,31 @@ BENCHMARK_IMPL(loop_count_timed) {
MAKE_VALGRIND_HAPPY(loop);
return 0;
}
/* Measure the performance of running uv_loop_alive(). Adding this so we can get
* some sort of metric for the impact of switching active_reqs.count to use
* atomics. No other code sits in a hot path. */
BENCHMARK_IMPL(loop_alive) {
uv_loop_t* loop = uv_default_loop();
int ticks = 0;
uint64_t ns;
uv_idle_init(loop, &idle_handle);
idle_handle.data = &ticks;
uv_idle_start(&idle_handle, idle_alive_cb);
ns = uv_hrtime();
uv_run(loop, UV_RUN_DEFAULT);
ns = uv_hrtime() - ns;
ASSERT_EQ(ticks, NUM_TICKS2);
fprintf(stderr, "loop_alive: %d ticks in %.2fs (%.0f/s)\n",
NUM_TICKS2,
ns / 1e9,
NUM_TICKS2 / (ns / 1e9));
fflush(stderr);
MAKE_VALGRIND_HAPPY(loop);
return 0;
}

View File

@ -40,6 +40,10 @@
#include <sys/time.h>
#include <pthread.h>
#ifdef __APPLE__
#include <TargetConditionals.h>
#endif
extern char** environ;
static void closefd(int fd) {
@ -131,7 +135,11 @@ int process_start(char* name, char* part, process_info_t* p, int is_helper) {
p->terminated = 0;
p->status = 0;
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
pid = -1;
#else
pid = fork();
#endif
if (pid < 0) {
perror("fork");
@ -144,7 +152,9 @@ int process_start(char* name, char* part, process_info_t* p, int is_helper) {
closefd(pipefd[0]);
dup2(stdout_fd, STDOUT_FILENO);
dup2(stdout_fd, STDERR_FILENO);
#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
execve(args[0], args, environ);
#endif
perror("execve()");
_exit(127);
}

View File

@ -27,6 +27,10 @@
#include <sys/socket.h>
#include <string.h>
#ifdef __APPLE__
#include <TargetConditionals.h>
#endif
#include "uv.h"
#include "task.h"
@ -100,7 +104,11 @@ TEST_IMPL(fork_timer) {
pid_t child_pid;
run_timer_loop_once();
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
child_pid = -1;
#else
child_pid = fork();
#endif
ASSERT(child_pid != -1);
if (child_pid != 0) {
@ -132,7 +140,11 @@ TEST_IMPL(fork_socketpair) {
/* Create the server watcher in the parent, use it in the child. */
ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0]));
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
child_pid = -1;
#else
child_pid = fork();
#endif
ASSERT(child_pid != -1);
if (child_pid != 0) {
@ -181,7 +193,11 @@ TEST_IMPL(fork_socketpair_started) {
*/
ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_NOWAIT));
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
child_pid = -1;
#else
child_pid = fork();
#endif
ASSERT(child_pid != -1);
if (child_pid != 0) {
@ -245,7 +261,11 @@ TEST_IMPL(fork_signal_to_child) {
ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle));
ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1));
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
child_pid = -1;
#else
child_pid = fork();
#endif
ASSERT(child_pid != -1);
if (child_pid != 0) {
@ -297,7 +317,11 @@ TEST_IMPL(fork_signal_to_child_closed) {
ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle));
ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1));
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
child_pid = -1;
#else
child_pid = fork();
#endif
ASSERT(child_pid != -1);
if (child_pid != 0) {
@ -463,7 +487,11 @@ static int _do_fork_fs_events_child(int file_or_dir) {
/* Watch in the parent, prime the loop and/or threads. */
assert_watch_file_current_dir(uv_default_loop(), file_or_dir);
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
child_pid = -1;
#else
child_pid = fork();
#endif
ASSERT(child_pid != -1);
if (child_pid != 0) {
@ -569,7 +597,11 @@ TEST_IMPL(fork_fs_events_file_parent_child) {
r = uv_timer_init(loop, &timer);
ASSERT(r == 0);
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
child_pid = -1;
#else
child_pid = fork();
#endif
ASSERT(child_pid != -1);
if (child_pid != 0) {
/* parent */
@ -654,7 +686,11 @@ TEST_IMPL(fork_threadpool_queue_work_simple) {
/* Prime the pool and default loop. */
assert_run_work(uv_default_loop());
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
child_pid = -1;
#else
child_pid = fork();
#endif
ASSERT(child_pid != -1);
if (child_pid != 0) {

View File

@ -4550,6 +4550,7 @@ TEST_IMPL(fs_get_system_error) {
return 0;
}
TEST_IMPL(fs_stat_batch_multiple) {
uv_fs_t req[300];
int r;
@ -4573,3 +4574,55 @@ TEST_IMPL(fs_stat_batch_multiple) {
MAKE_VALGRIND_HAPPY(loop);
return 0;
}
#ifdef _WIN32
TEST_IMPL(fs_wtf) {
int r;
HANDLE file_handle;
uv_dirent_t dent;
static char test_file_buf[PATHMAX];
/* set-up */
_wunlink(L"test_dir/hi\xD801\x0037");
rmdir("test_dir");
loop = uv_default_loop();
r = uv_fs_mkdir(NULL, &mkdir_req, "test_dir", 0777, NULL);
ASSERT_EQ(r, 0);
uv_fs_req_cleanup(&mkdir_req);
file_handle = CreateFileW(L"test_dir/hi\xD801\x0037",
GENERIC_WRITE | FILE_WRITE_ATTRIBUTES,
0,
NULL,
CREATE_ALWAYS,
FILE_FLAG_OPEN_REPARSE_POINT |
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
ASSERT(file_handle != INVALID_HANDLE_VALUE);
CloseHandle(file_handle);
r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
ASSERT_EQ(r, 1);
ASSERT_EQ(scandir_req.result, 1);
ASSERT_NOT_NULL(scandir_req.ptr);
while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
snprintf(test_file_buf, sizeof(test_file_buf), "test_dir\\%s", dent.name);
printf("stat %s\n", test_file_buf);
r = uv_fs_stat(NULL, &stat_req, test_file_buf, NULL);
ASSERT_EQ(r, 0);
}
uv_fs_req_cleanup(&scandir_req);
ASSERT_NULL(scandir_req.ptr);
/* clean-up */
_wunlink(L"test_dir/hi\xD801\x0037");
rmdir("test_dir");
MAKE_VALGRIND_HAPPY(loop);
return 0;
}
#endif

View File

@ -120,6 +120,7 @@ TEST_IMPL(get_passwd2) {
#ifdef _WIN32
ASSERT_EQ(r, UV_ENOTSUP);
(void) &len;
#else
ASSERT_EQ(r, 0);
@ -179,6 +180,7 @@ TEST_IMPL(get_group) {
#ifdef _WIN32
ASSERT_EQ(r, UV_ENOTSUP);
(void) &len;
#else
ASSERT_EQ(r, 0);

View File

@ -29,6 +29,7 @@ TEST_DECLARE (loop_alive)
TEST_DECLARE (loop_close)
TEST_DECLARE (loop_instant_close)
TEST_DECLARE (loop_stop)
TEST_DECLARE (loop_stop_before_run)
TEST_DECLARE (loop_update_time)
TEST_DECLARE (loop_backend_timeout)
TEST_DECLARE (loop_configure)
@ -198,6 +199,7 @@ TEST_DECLARE (pipe_connect_close_multiple)
TEST_DECLARE (pipe_connect_multiple)
TEST_DECLARE (pipe_listen_without_bind)
TEST_DECLARE (pipe_bind_or_listen_error_after_close)
TEST_DECLARE (pipe_overlong_path)
TEST_DECLARE (pipe_connect_bad_name)
TEST_DECLARE (pipe_connect_to_file)
TEST_DECLARE (pipe_connect_on_prepare)
@ -232,6 +234,7 @@ TEST_DECLARE (timer_null_callback)
TEST_DECLARE (timer_early_check)
TEST_DECLARE (timer_no_double_call_once)
TEST_DECLARE (timer_no_double_call_nowait)
TEST_DECLARE (timer_no_run_on_unref)
TEST_DECLARE (idle_starvation)
TEST_DECLARE (idle_check)
TEST_DECLARE (loop_handles)
@ -437,6 +440,7 @@ TEST_DECLARE (fs_file_flag_no_buffering)
TEST_DECLARE (fs_open_readonly_acl)
TEST_DECLARE (fs_fchmod_archive_readonly)
TEST_DECLARE (fs_invalid_mkdir_name)
TEST_DECLARE (fs_wtf)
#endif
TEST_DECLARE (fs_get_system_error)
TEST_DECLARE (strscpy)
@ -450,6 +454,7 @@ TEST_DECLARE (threadpool_cancel_random)
TEST_DECLARE (threadpool_cancel_work)
TEST_DECLARE (threadpool_cancel_fs)
TEST_DECLARE (threadpool_cancel_single)
TEST_DECLARE (threadpool_cancel_when_busy)
TEST_DECLARE (thread_local_storage)
TEST_DECLARE (thread_stack_size)
TEST_DECLARE (thread_stack_size_explicit)
@ -571,6 +576,7 @@ TASK_LIST_START
TEST_ENTRY (loop_close)
TEST_ENTRY (loop_instant_close)
TEST_ENTRY (loop_stop)
TEST_ENTRY (loop_stop_before_run)
TEST_ENTRY (loop_update_time)
TEST_ENTRY (loop_backend_timeout)
TEST_ENTRY (loop_configure)
@ -798,6 +804,7 @@ TASK_LIST_START
TEST_ENTRY (pipe_connect_multiple)
TEST_ENTRY (pipe_listen_without_bind)
TEST_ENTRY (pipe_bind_or_listen_error_after_close)
TEST_ENTRY (pipe_overlong_path)
TEST_ENTRY (pipe_getsockname)
TEST_ENTRY (pipe_getsockname_abstract)
TEST_ENTRY (pipe_getsockname_blocking)
@ -843,6 +850,7 @@ TASK_LIST_START
TEST_ENTRY (timer_early_check)
TEST_ENTRY (timer_no_double_call_once)
TEST_ENTRY (timer_no_double_call_nowait)
TEST_ENTRY (timer_no_run_on_unref)
TEST_ENTRY (idle_starvation)
TEST_ENTRY (idle_check)
@ -1120,6 +1128,7 @@ TASK_LIST_START
TEST_ENTRY (fs_open_readonly_acl)
TEST_ENTRY (fs_fchmod_archive_readonly)
TEST_ENTRY (fs_invalid_mkdir_name)
TEST_ENTRY (fs_wtf)
#endif
TEST_ENTRY (fs_get_system_error)
TEST_ENTRY (get_osfhandle_valid_handle)
@ -1135,6 +1144,7 @@ TASK_LIST_START
TEST_ENTRY (threadpool_cancel_work)
TEST_ENTRY (threadpool_cancel_fs)
TEST_ENTRY (threadpool_cancel_single)
TEST_ENTRY (threadpool_cancel_when_busy)
TEST_ENTRY (thread_local_storage)
TEST_ENTRY (thread_stack_size)
TEST_ENTRY (thread_stack_size_explicit)

View File

@ -70,3 +70,14 @@ TEST_IMPL(loop_stop) {
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}
TEST_IMPL(loop_stop_before_run) {
ASSERT_OK(uv_timer_init(uv_default_loop(), &timer_handle));
ASSERT_OK(uv_timer_start(&timer_handle, (uv_timer_cb) abort, 0, 0));
uv_stop(uv_default_loop());
ASSERT_NE(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0);
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}

View File

@ -153,3 +153,27 @@ TEST_IMPL(pipe_bind_or_listen_error_after_close) {
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}
TEST_IMPL(pipe_overlong_path) {
char path[512];
uv_pipe_t pipe;
uv_connect_t req;
memset(path, '@', sizeof(path));
ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe, 0));
ASSERT_EQ(UV_EINVAL,
uv_pipe_bind2(&pipe, path, sizeof(path), UV_PIPE_NO_TRUNCATE));
ASSERT_EQ(UV_EINVAL,
uv_pipe_connect2(&req,
&pipe,
path,
sizeof(path),
UV_PIPE_NO_TRUNCATE,
(uv_connect_cb) abort));
uv_close((uv_handle_t*) &pipe, NULL);
ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}

View File

@ -26,6 +26,10 @@
#include <sys/wait.h>
#include <sys/types.h>
#ifdef __APPLE__
#include <TargetConditionals.h>
#endif
#include "uv.h"
#include "task.h"
@ -58,8 +62,14 @@ TEST_IMPL(pipe_close_stdout_read_stdin) {
r = pipe(fd);
ASSERT(r == 0);
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
pid = -1;
#else
pid = fork();
#endif
if ((pid = fork()) == 0) {
if (pid == 0) {
/*
* Make the read side of the pipe our stdin.
* The write side will be closed by the parent process.

View File

@ -25,11 +25,6 @@
#include <stdlib.h>
#include <string.h>
#if defined(__linux__)
#include <sys/socket.h>
#include <sys/un.h>
#endif
#ifndef _WIN32
# include <unistd.h> /* close */
#else
@ -63,8 +58,14 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) {
r = uv_pipe_getpeername(&pipe_client, buf, &len);
ASSERT(r == 0);
ASSERT(buf[len - 1] != 0);
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
if (*buf == '\0') { /* Linux abstract socket. */
const char expected[] = "\0" TEST_PIPENAME;
ASSERT_GE(len, sizeof(expected));
ASSERT_MEM_EQ(buf, expected, sizeof(expected));
} else {
ASSERT_NE(0, buf[len - 1]);
ASSERT_MEM_EQ(buf, TEST_PIPENAME, len);
}
len = sizeof buf;
r = uv_pipe_getsockname(&pipe_client, buf, &len);
@ -72,7 +73,6 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) {
pipe_client_connect_cb_called++;
uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
}
@ -162,47 +162,48 @@ TEST_IMPL(pipe_getsockname) {
TEST_IMPL(pipe_getsockname_abstract) {
/* TODO(bnoordhuis) Use unique name, susceptible to concurrent test runs. */
static const char name[] = "\0" TEST_PIPENAME;
#if defined(__linux__)
char buf[1024];
size_t len;
int r;
int sock;
struct sockaddr_un sun;
socklen_t sun_len;
char abstract_pipe[] = "\0test-pipe";
char buf[256];
size_t buflen;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
ASSERT(sock != -1);
sun_len = sizeof sun;
memset(&sun, 0, sun_len);
sun.sun_family = AF_UNIX;
memcpy(sun.sun_path, abstract_pipe, sizeof abstract_pipe);
r = bind(sock, (struct sockaddr*)&sun, sun_len);
ASSERT(r == 0);
r = uv_pipe_init(uv_default_loop(), &pipe_server, 0);
ASSERT(r == 0);
r = uv_pipe_open(&pipe_server, sock);
ASSERT(r == 0);
len = sizeof buf;
r = uv_pipe_getsockname(&pipe_server, buf, &len);
ASSERT(r == 0);
ASSERT(memcmp(buf, abstract_pipe, sizeof abstract_pipe) == 0);
uv_close((uv_handle_t*)&pipe_server, pipe_close_cb);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
close(sock);
ASSERT(pipe_close_cb_called == 1);
buflen = sizeof(buf);
memset(buf, 0, sizeof(buf));
ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0));
ASSERT_OK(uv_pipe_bind2(&pipe_server, name, sizeof(name), 0));
ASSERT_OK(uv_pipe_getsockname(&pipe_server, buf, &buflen));
ASSERT_MEM_EQ(name, buf, sizeof(name));
ASSERT_OK(uv_listen((uv_stream_t*) &pipe_server,
0,
pipe_server_connection_cb));
ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_client, 0));
ASSERT_OK(uv_pipe_connect2(&connect_req,
&pipe_client,
name,
sizeof(name),
0,
pipe_client_connect_cb));
ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT_EQ(1, pipe_client_connect_cb_called);
ASSERT_EQ(2, pipe_close_cb_called);
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
#else
/* On other platforms it should simply fail with UV_EINVAL. */
ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0));
ASSERT_EQ(UV_EINVAL, uv_pipe_bind2(&pipe_server, name, sizeof(name), 0));
ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_client, 0));
uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
ASSERT_EQ(UV_EINVAL, uv_pipe_connect2(&connect_req,
&pipe_client,
name,
sizeof(name),
0,
(uv_connect_cb) abort));
uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT_EQ(2, pipe_close_cb_called);
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
#endif

View File

@ -29,7 +29,7 @@
* The idea behind the test is as follows.
* Certain handle types are stored in a queue internally.
* Extra care should be taken for removal of a handle from the queue while iterating over the queue.
* (i.e., QUEUE_REMOVE() called within QUEUE_FOREACH())
* (i.e., uv__queue_remove() called within uv__queue_foreach())
* This usually happens when someone closes or stops a handle from within its callback.
* So we need to check that we haven't screwed the queue on close/stop.
* To do so we do the following (for each handle type):
@ -54,7 +54,8 @@
* wrong foreach "next" |
*
* 4. The callback for handle #1 shouldn't be called because the handle #1 is stopped in the previous step.
* However, if QUEUE_REMOVE() is not handled properly within QUEUE_FOREACH(), the callback _will_ be called.
* However, if uv__queue_remove() is not handled properly within uv__queue_foreach(), the callback _will_
* be called.
*/
static const unsigned first_handle_number_idle = 2;

View File

@ -1108,7 +1108,7 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
/* Create a pipe that'll cause a collision. */
snprintf(name,
sizeof(name),
"\\\\.\\pipe\\uv\\%p-%d",
"\\\\.\\pipe\\uv\\%p-%lu",
&out,
GetCurrentProcessId());
pipe_handle = CreateNamedPipeA(name,

View File

@ -78,10 +78,6 @@ static void getaddrinfo_do(struct getaddrinfo_req* req) {
static void getaddrinfo_cb(uv_getaddrinfo_t* handle,
int status,
struct addrinfo* res) {
/* TODO(gengjiawen): Fix test on QEMU. */
#if defined(__QEMU__)
RETURN_SKIP("Test does not currently work in QEMU");
#endif
struct getaddrinfo_req* req;
ASSERT(status == 0);

View File

@ -98,11 +98,16 @@ static int known_broken(uv_req_t* req) {
case UV_FS_FDATASYNC:
case UV_FS_FSTAT:
case UV_FS_FSYNC:
case UV_FS_LINK:
case UV_FS_LSTAT:
case UV_FS_MKDIR:
case UV_FS_OPEN:
case UV_FS_READ:
case UV_FS_RENAME:
case UV_FS_STAT:
case UV_FS_SYMLINK:
case UV_FS_WRITE:
case UV_FS_UNLINK:
return 1;
default: /* Squelch -Wswitch warnings. */
break;
@ -373,3 +378,36 @@ TEST_IMPL(threadpool_cancel_single) {
MAKE_VALGRIND_HAPPY(loop);
return 0;
}
static void after_busy_cb(uv_work_t* req, int status) {
ASSERT_OK(status);
done_cb_called++;
}
static void busy_cb(uv_work_t* req) {
uv_sem_post((uv_sem_t*) req->data);
/* Assume that calling uv_cancel() takes less than 10ms. */
uv_sleep(10);
}
TEST_IMPL(threadpool_cancel_when_busy) {
uv_sem_t sem_lock;
uv_work_t req;
req.data = &sem_lock;
ASSERT_OK(uv_sem_init(&sem_lock, 0));
ASSERT_OK(uv_queue_work(uv_default_loop(), &req, busy_cb, after_busy_cb));
uv_sem_wait(&sem_lock);
ASSERT_EQ(uv_cancel((uv_req_t*) &req), UV_EBUSY);
ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT_EQ(done_cb_called, 1);
uv_sem_destroy(&sem_lock);
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}

View File

@ -407,3 +407,15 @@ TEST_IMPL(timer_no_double_call_nowait) {
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}
TEST_IMPL(timer_no_run_on_unref) {
uv_timer_t timer_handle;
ASSERT_OK(uv_timer_init(uv_default_loop(), &timer_handle));
ASSERT_OK(uv_timer_start(&timer_handle, (uv_timer_cb) abort, 0, 0));
uv_unref((uv_handle_t*) &timer_handle);
ASSERT_EQ(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0);
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}