@@ -25,6 +25,7 @@ TEST_DECLARE (close_order)
TEST_DECLARE (run_once)
TEST_DECLARE (run_nowait)
TEST_DECLARE (loop_alive)
TEST_DECLARE (loop_close)
TEST_DECLARE (loop_stop)
TEST_DECLARE (loop_update_time)
TEST_DECLARE (barrier_1)
@@ -81,6 +82,7 @@ TEST_DECLARE (tcp_bind6_localhost_ok)
TEST_DECLARE (udp_send_and_recv)
TEST_DECLARE (udp_multicast_join)
TEST_DECLARE (udp_multicast_ttl)
TEST_DECLARE (udp_multicast_interface)
TEST_DECLARE (udp_dgram_too_big)
TEST_DECLARE (udp_dual_stack)
TEST_DECLARE (udp_ipv6_only)
@@ -92,12 +94,15 @@ TEST_DECLARE (pipe_bind_error_inval)
TEST_DECLARE (pipe_listen_without_bind)
TEST_DECLARE (pipe_connect_bad_name)
TEST_DECLARE (pipe_connect_to_file)
TEST_DECLARE (pipe_getsockname)
TEST_DECLARE (pipe_getsockname_abstract)
TEST_DECLARE (pipe_server_close)
TEST_DECLARE (connection_fail)
TEST_DECLARE (connection_fail_doesnt_auto_close)
TEST_DECLARE (shutdown_close_tcp)
TEST_DECLARE (shutdown_close_pipe)
TEST_DECLARE (shutdown_eof)
TEST_DECLARE (shutdown_twice)
TEST_DECLARE (callback_stack)
TEST_DECLARE (error_message)
TEST_DECLARE (timer)
@@ -171,12 +176,14 @@ TEST_DECLARE (spawn_stdout_to_file)
TEST_DECLARE (spawn_stdout_and_stderr_to_file)
TEST_DECLARE (spawn_auto_unref)
TEST_DECLARE (fs_poll)
TEST_DECLARE (fs_poll_getpath)
TEST_DECLARE (kill)
TEST_DECLARE (fs_file_noent)
TEST_DECLARE (fs_file_nametoolong)
TEST_DECLARE (fs_file_loop)
TEST_DECLARE (fs_file_async)
TEST_DECLARE (fs_file_sync)
TEST_DECLARE (fs_file_write_null_buffer)
TEST_DECLARE (fs_async_dir)
TEST_DECLARE (fs_async_sendfile)
TEST_DECLARE (fs_fstat)
@@ -202,6 +209,7 @@ TEST_DECLARE (fs_event_close_with_pending_event)
TEST_DECLARE (fs_event_close_in_callback)
TEST_DECLARE (fs_event_start_and_close)
TEST_DECLARE (fs_event_error_reporting)
TEST_DECLARE (fs_event_getpath)
TEST_DECLARE (fs_readdir_empty_dir)
TEST_DECLARE (fs_readdir_file)
TEST_DECLARE (fs_open_dir)
@@ -233,10 +241,12 @@ TEST_DECLARE (fs_stat_root)
#else
TEST_DECLARE (emfile)
TEST_DECLARE (close_fd)
TEST_DECLARE (spawn_fs_open)
TEST_DECLARE (spawn_setuid_setgid)
TEST_DECLARE (we_get_signal)
TEST_DECLARE (we_get_signals)
TEST_DECLARE (signal_multiple_loops)
TEST_DECLARE (closed_fd_events)
#endif
#ifdef __APPLE__
TEST_DECLARE (osx_select)
@@ -248,7 +258,7 @@ HELPER_DECLARE (pipe_echo_server)


TASK_LIST_START
TEST_OUTPUT_ENTRY (platform_output)
TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000)

#if 0
TEST_ENTRY (callback_order)
@@ -257,6 +267,7 @@ TASK_LIST_START
TEST_ENTRY (run_once)
TEST_ENTRY (run_nowait)
TEST_ENTRY (loop_alive)
TEST_ENTRY (loop_close)
TEST_ENTRY (loop_stop)
TEST_ENTRY (loop_update_time)
TEST_ENTRY (barrier_1)
@@ -349,6 +360,8 @@ TASK_LIST_START
TEST_ENTRY (pipe_bind_error_addrnotavail)
TEST_ENTRY (pipe_bind_error_inval)
TEST_ENTRY (pipe_listen_without_bind)
TEST_ENTRY (pipe_getsockname)
TEST_ENTRY (pipe_getsockname_abstract)

TEST_ENTRY (connection_fail)
TEST_ENTRY (connection_fail_doesnt_auto_close)
@@ -361,6 +374,9 @@ TASK_LIST_START
TEST_ENTRY (shutdown_eof)
TEST_HELPER (shutdown_eof, tcp4_echo_server)

TEST_ENTRY (shutdown_twice)
TEST_HELPER (shutdown_twice, tcp4_echo_server)

TEST_ENTRY (callback_stack)
TEST_HELPER (callback_stack, tcp4_echo_server)

@@ -432,7 +448,8 @@ TASK_LIST_START

TEST_ENTRY (hrtime)

TEST_ENTRY (getaddrinfo_fail)
TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000)

TEST_ENTRY (getaddrinfo_basic)
TEST_ENTRY (getaddrinfo_concurrent)

@@ -460,6 +477,7 @@ TASK_LIST_START
TEST_ENTRY (spawn_stdout_and_stderr_to_file)
TEST_ENTRY (spawn_auto_unref)
TEST_ENTRY (fs_poll)
TEST_ENTRY (fs_poll_getpath)
TEST_ENTRY (kill)

#ifdef _WIN32
@@ -472,10 +490,12 @@ TASK_LIST_START
#else
TEST_ENTRY (emfile)
TEST_ENTRY (close_fd)
TEST_ENTRY (spawn_fs_open)
TEST_ENTRY (spawn_setuid_setgid)
TEST_ENTRY (we_get_signal)
TEST_ENTRY (we_get_signals)
TEST_ENTRY (signal_multiple_loops)
TEST_ENTRY (closed_fd_events)
#endif

#ifdef __APPLE__
@@ -487,6 +507,7 @@ TASK_LIST_START
TEST_ENTRY (fs_file_loop)
TEST_ENTRY (fs_file_async)
TEST_ENTRY (fs_file_sync)
TEST_ENTRY (fs_file_write_null_buffer)
TEST_ENTRY (fs_async_dir)
TEST_ENTRY (fs_async_sendfile)
TEST_ENTRY (fs_fstat)
@@ -511,6 +532,7 @@ TASK_LIST_START
TEST_ENTRY (fs_event_close_in_callback)
TEST_ENTRY (fs_event_start_and_close)
TEST_ENTRY (fs_event_error_reporting)
TEST_ENTRY (fs_event_getpath)
TEST_ENTRY (fs_readdir_empty_dir)
TEST_ENTRY (fs_readdir_file)
TEST_ENTRY (fs_open_dir)
@@ -0,0 +1,54 @@
/* 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 "uv.h"
#include "task.h"

static uv_timer_t timer_handle;

static void timer_cb(uv_timer_t* handle, int status) {
ASSERT(handle);
ASSERT(status == 0);
uv_stop(handle->loop);
}


TEST_IMPL(loop_close) {
int r;
uv_loop_t loop;

ASSERT(0 == uv_loop_init(&loop));

uv_timer_init(&loop, &timer_handle);
uv_timer_start(&timer_handle, timer_cb, 100, 100);

ASSERT(UV_EBUSY == uv_loop_close(&loop));

uv_run(&loop, UV_RUN_DEFAULT);

uv_close((uv_handle_t*) &timer_handle, NULL);
r = uv_run(&loop, UV_RUN_DEFAULT);
ASSERT(r == 0);

ASSERT(0 == uv_loop_close(&loop));

return 0;
}
@@ -0,0 +1,122 @@
/* 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 "uv.h"
#include "task.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(__linux__)
#include <sys/socket.h>
#include <sys/un.h>
#endif

#ifndef _WIN32
# include <unistd.h> /* close */
#endif


static int close_cb_called = 0;


static void close_cb(uv_handle_t* handle) {
ASSERT(handle != NULL);
close_cb_called++;
}


TEST_IMPL(pipe_getsockname) {
uv_pipe_t server;
char buf[1024];
size_t len;
int r;

r = uv_pipe_init(uv_default_loop(), &server, 0);
ASSERT(r == 0);
r = uv_pipe_bind(&server, TEST_PIPENAME);
ASSERT(r == 0);

len = sizeof buf;
r = uv_pipe_getsockname(&server, buf, &len);
ASSERT(r == 0);

ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);

uv_close((uv_handle_t*)&server, close_cb);

uv_run(uv_default_loop(), UV_RUN_DEFAULT);

ASSERT(close_cb_called == 1);

MAKE_VALGRIND_HAPPY();
return 0;
}


TEST_IMPL(pipe_getsockname_abstract) {
#if defined(__linux__)
uv_pipe_t server;
char buf[1024];
size_t len;
int r;
int sock;
struct sockaddr_un sun;
socklen_t sun_len;
char abstract_pipe[] = "\0test-pipe";

sock = socket(AF_LOCAL, 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(), &server, 0);
ASSERT(r == 0);
r = uv_pipe_open(&server, sock);
ASSERT(r == 0);

len = sizeof buf;
r = uv_pipe_getsockname(&server, buf, &len);
ASSERT(r == 0);

ASSERT(memcmp(buf, abstract_pipe, sizeof abstract_pipe) == 0);

uv_close((uv_handle_t*)&server, close_cb);

uv_run(uv_default_loop(), UV_RUN_DEFAULT);

close(sock);

ASSERT(close_cb_called == 1);
MAKE_VALGRIND_HAPPY();
return 0;
#else
MAKE_VALGRIND_HAPPY();
return 0;
#endif
}

@@ -28,6 +28,7 @@ TEST_IMPL(platform_output) {
char buffer[512];
size_t rss;
double uptime;
uv_rusage_t rusage;
uv_cpu_info_t* cpus;
uv_interface_address_t* interfaces;
int count;
@@ -47,6 +48,20 @@ TEST_IMPL(platform_output) {
ASSERT(uptime > 0);
printf("uv_uptime: %f\n", uptime);

err = uv_getrusage(&rusage);
ASSERT(err == 0);
ASSERT(rusage.ru_utime.tv_sec >= 0);
ASSERT(rusage.ru_utime.tv_usec >= 0);
ASSERT(rusage.ru_stime.tv_sec >= 0);
ASSERT(rusage.ru_stime.tv_usec >= 0);
printf("uv_getrusage:\n");
printf(" user: %llu sec %llu microsec\n",
(unsigned long long) rusage.ru_utime.tv_sec,
(unsigned long long) rusage.ru_utime.tv_usec);
printf(" system: %llu sec %llu microsec\n",
(unsigned long long) rusage.ru_stime.tv_sec,
(unsigned long long) rusage.ru_stime.tv_usec);

err = uv_cpu_info(&cpus, &count);
ASSERT(err == 0);

@@ -0,0 +1,84 @@
/* 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.
*/

/*
* This is a regression test for issue #1113 (calling uv_shutdown twice will
* leave a ghost request in the system)
*/

#include "uv.h"
#include "task.h"

static uv_shutdown_t req1;
static uv_shutdown_t req2;

static int shutdown_cb_called = 0;

static void close_cb(uv_handle_t* handle) {

}

static void shutdown_cb(uv_shutdown_t* req, int status) {
ASSERT(req == &req1);
ASSERT(status == 0);
shutdown_cb_called++;
uv_close((uv_handle_t*) req->handle, close_cb);
}

static void connect_cb(uv_connect_t* req, int status) {
int r;

ASSERT(status == 0);

r = uv_shutdown(&req1, req->handle, shutdown_cb);
ASSERT(r == 0);
r = uv_shutdown(&req2, req->handle, shutdown_cb);
ASSERT(r != 0);

}

TEST_IMPL(shutdown_twice) {
struct sockaddr_in addr;
uv_loop_t* loop;
int r;
uv_tcp_t h;

uv_connect_t connect_req;

ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
loop = uv_default_loop();

r = uv_tcp_init(loop, &h);

r = uv_tcp_connect(&connect_req,
&h,
(const struct sockaddr*) &addr,
connect_cb);
ASSERT(r == 0);

r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0);

ASSERT(shutdown_cb_called == 1);

MAKE_VALGRIND_HAPPY();
return 0;
}
@@ -84,28 +84,27 @@ static void signal_handling_worker(void* context) {
uv_signal_t signal1a;
uv_signal_t signal1b;
uv_signal_t signal2;
uv_loop_t* loop;
uv_loop_t loop;
int r;

action = (enum signal_action) (uintptr_t) context;

loop = uv_loop_new();
ASSERT(loop != NULL);
ASSERT(0 == uv_loop_init(&loop));

/* Setup the signal watchers and start them. */
if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) {
r = uv_signal_init(loop, &signal1a);
r = uv_signal_init(&loop, &signal1a);
ASSERT(r == 0);
r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1);
ASSERT(r == 0);
r = uv_signal_init(loop, &signal1b);
r = uv_signal_init(&loop, &signal1b);
ASSERT(r == 0);
r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1);
ASSERT(r == 0);
}

if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) {
r = uv_signal_init(loop, &signal2);
r = uv_signal_init(&loop, &signal2);
ASSERT(r == 0);
r = uv_signal_start(&signal2, signal2_cb, SIGUSR2);
ASSERT(r == 0);
@@ -117,7 +116,7 @@ static void signal_handling_worker(void* context) {
/* Wait for all signals. The signal callbacks stop the watcher, so uv_run
* will return when all signal watchers caught a signal.
*/
r = uv_run(loop, UV_RUN_DEFAULT);
r = uv_run(&loop, UV_RUN_DEFAULT);
ASSERT(r == 0);

/* Restart the signal watchers. */
@@ -136,7 +135,7 @@ static void signal_handling_worker(void* context) {
/* Wait for signals once more. */
uv_sem_post(&sem);

r = uv_run(loop, UV_RUN_DEFAULT);
r = uv_run(&loop, UV_RUN_DEFAULT);
ASSERT(r == 0);

/* Close the watchers. */
@@ -150,10 +149,10 @@ static void signal_handling_worker(void* context) {
}

/* Wait for the signal watchers to close. */
r = uv_run(loop, UV_RUN_DEFAULT);
r = uv_run(&loop, UV_RUN_DEFAULT);
ASSERT(r == 0);

uv_loop_delete(loop);
uv_loop_close(&loop);
}


@@ -166,12 +165,13 @@ static void loop_creating_worker(void* context) {
(void) context;

do {
uv_loop_t* loop;
uv_loop_t *loop;
uv_signal_t signal;
int r;

loop = uv_loop_new();
loop = malloc(sizeof(*loop));
ASSERT(loop != NULL);
ASSERT(0 == uv_loop_init(loop));

r = uv_signal_init(loop, &signal);
ASSERT(r == 0);
@@ -184,7 +184,7 @@ static void loop_creating_worker(void* context) {
r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT(r == 0);

uv_loop_delete(loop);
uv_loop_close(loop);

increment_counter(&loop_creation_counter);
} while (!stop);
@@ -40,6 +40,7 @@ static char exepath[1024];
static size_t exepath_size = 1024;
static char* args[3];
static int no_term_signal;
static int timer_counter;

#define OUTPUT_SIZE 1024
static char output[OUTPUT_SIZE];
@@ -118,6 +119,12 @@ static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
}


static void on_read_once(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
uv_read_stop(tcp);
on_read(tcp, nread, buf);
}


static void write_cb(uv_write_t* req, int status) {
ASSERT(status == 0);
uv_close((uv_handle_t*)req->handle, close_cb);
@@ -145,6 +152,11 @@ static void timer_cb(uv_timer_t* handle, int status) {
}


static void timer_counter_cb(uv_timer_t* handle, int status) {
++timer_counter;
}


TEST_IMPL(spawn_fails) {
int r;

@@ -218,6 +230,7 @@ TEST_IMPL(spawn_stdout_to_file) {
uv_file file;
uv_fs_t fs_req;
uv_stdio_container_t stdio[2];
uv_buf_t buf;

/* Setup. */
unlink("stdout_file");
@@ -246,8 +259,8 @@ TEST_IMPL(spawn_stdout_to_file) {
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 1);

r = uv_fs_read(uv_default_loop(), &fs_req, file, output, sizeof(output),
0, NULL);
buf = uv_buf_init(output, sizeof(output));
r = uv_fs_read(uv_default_loop(), &fs_req, file, &buf, 1, 0, NULL);
ASSERT(r == 12);
uv_fs_req_cleanup(&fs_req);

@@ -271,14 +284,15 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) {
uv_file file;
uv_fs_t fs_req;
uv_stdio_container_t stdio[3];
uv_buf_t buf;

/* Setup. */
unlink("stdout_file");

init_process_options("spawn_helper6", exit_cb);

r = uv_fs_open(uv_default_loop(), &fs_req, "stdout_file", O_CREAT | O_RDWR,
S_IREAD | S_IWRITE, NULL);
S_IRUSR | S_IWUSR, NULL);
ASSERT(r != -1);
uv_fs_req_cleanup(&fs_req);

@@ -301,8 +315,8 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) {
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 1);

r = uv_fs_read(uv_default_loop(), &fs_req, file, output, sizeof(output),
0, NULL);
buf = uv_buf_init(output, sizeof(output));
r = uv_fs_read(uv_default_loop(), &fs_req, file, &buf, 1, 0, NULL);
ASSERT(r == 27);
uv_fs_req_cleanup(&fs_req);

@@ -1049,3 +1063,102 @@ TEST_IMPL(spawn_auto_unref) {
MAKE_VALGRIND_HAPPY();
return 0;
}


#ifndef _WIN32
TEST_IMPL(spawn_fs_open) {
int fd;
uv_fs_t fs_req;
uv_pipe_t in;
uv_write_t write_req;
uv_buf_t buf;
uv_stdio_container_t stdio[1];

fd = uv_fs_open(uv_default_loop(), &fs_req, "/dev/null", O_RDWR, 0, NULL);
ASSERT(fd >= 0);

init_process_options("spawn_helper8", exit_cb);

ASSERT(0 == uv_pipe_init(uv_default_loop(), &in, 0));

options.stdio = stdio;
options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
options.stdio[0].data.stream = (uv_stream_t*) &in;
options.stdio_count = 1;

ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));

buf = uv_buf_init((char*) &fd, sizeof(fd));
ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));

ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT(0 == uv_fs_close(uv_default_loop(), &fs_req, fd, NULL));

ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 2); /* One for `in`, one for process */

MAKE_VALGRIND_HAPPY();
return 0;
}
#endif /* !_WIN32 */


#ifndef _WIN32
TEST_IMPL(closed_fd_events) {
uv_stdio_container_t stdio[3];
uv_pipe_t pipe_handle;
int fd[2];

/* create a pipe and share it with a child process */
ASSERT(0 == pipe(fd));
ASSERT(0 == fcntl(fd[0], F_SETFL, O_NONBLOCK));

/* spawn_helper4 blocks indefinitely. */
init_process_options("spawn_helper4", exit_cb);
options.stdio_count = 3;
options.stdio = stdio;
options.stdio[0].flags = UV_INHERIT_FD;
options.stdio[0].data.fd = fd[0];
options.stdio[1].flags = UV_IGNORE;
options.stdio[2].flags = UV_IGNORE;

ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
uv_unref((uv_handle_t*) &process);

/* read from the pipe with uv */
ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
fd[0] = -1;

ASSERT(0 == uv_read_start((uv_stream_t*) &pipe_handle, on_alloc, on_read_once));

ASSERT(1 == write(fd[1], "", 1));

ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));

/* should have received just one byte */
ASSERT(output_used == 1);

/* close the pipe and see if we still get events */
uv_close((uv_handle_t*) &pipe_handle, close_cb);

ASSERT(1 == write(fd[1], "", 1));

ASSERT(0 == uv_timer_init(uv_default_loop(), &timer));
ASSERT(0 == uv_timer_start(&timer, timer_counter_cb, 10, 0));

/* see if any spurious events interrupt the timer */
if (1 == uv_run(uv_default_loop(), UV_RUN_ONCE))
/* have to run again to really trigger the timer */
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));

ASSERT(timer_counter == 1);

/* cleanup */
ASSERT(0 == uv_process_kill(&process, /* SIGTERM */ 15));
ASSERT(0 == close(fd[1]));

MAKE_VALGRIND_HAPPY();
return 0;
}
#endif /* !_WIN32 */
@@ -112,8 +112,9 @@ static void do_work(void* arg) {
int r;
struct test_thread* thread = arg;

loop = uv_loop_new();
loop = malloc(sizeof *loop);
ASSERT(loop != NULL);
ASSERT(0 == uv_loop_init(loop));

for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) {
struct getaddrinfo_req* req = getaddrinfo_reqs + i;
@@ -132,7 +133,8 @@ static void do_work(void* arg) {
r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT(r == 0);

uv_loop_delete(loop);
ASSERT(0 == uv_loop_close(loop));
free(loop);
thread->thread_called = 1;
}

@@ -86,7 +86,7 @@ static void saturate_threadpool(void) {
* the thread pool is saturated. As with any timing dependent test,
* this is obviously not ideal.
*/
if (uv_cond_timedwait(&signal_cond, &signal_mutex, 350 * 1e6)) {
if (uv_cond_timedwait(&signal_cond, &signal_mutex, (uint64_t)(350 * 1e6))) {
ASSERT(0 == uv_cancel((uv_req_t*) req));
break;
}
@@ -0,0 +1,96 @@
/* 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 "uv.h"
#include "task.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CHECK_HANDLE(handle) \
ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)

static uv_udp_t server;
static uv_udp_t client;

static int sv_send_cb_called;
static int close_cb_called;


static void close_cb(uv_handle_t* handle) {
CHECK_HANDLE(handle);
close_cb_called++;
}


static void sv_send_cb(uv_udp_send_t* req, int status) {
ASSERT(req != NULL);
ASSERT(status == 0);
CHECK_HANDLE(req->handle);

sv_send_cb_called++;

uv_close((uv_handle_t*) req->handle, close_cb);
}


TEST_IMPL(udp_multicast_interface) {
int r;
uv_udp_send_t req;
uv_buf_t buf;
struct sockaddr_in addr;
struct sockaddr_in baddr;

ASSERT(0 == uv_ip4_addr("239.255.0.1", TEST_PORT, &addr));

r = uv_udp_init(uv_default_loop(), &server);
ASSERT(r == 0);

ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &baddr));
r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0);
ASSERT(r == 0);

r = uv_udp_set_multicast_interface(&server, "0.0.0.0");
ASSERT(r == 0);

/* server sends "PING" */
buf = uv_buf_init("PING", 4);
r = uv_udp_send(&req,
&server,
&buf,
1,
(const struct sockaddr*)&addr,
sv_send_cb);
ASSERT(r == 0);

ASSERT(close_cb_called == 0);
ASSERT(sv_send_cb_called == 0);

/* run the loop till all events are processed */
uv_run(uv_default_loop(), UV_RUN_DEFAULT);

ASSERT(sv_send_cb_called == 1);
ASSERT(close_cb_called == 1);

MAKE_VALGRIND_HAPPY();
return 0;
}
@@ -31,7 +31,7 @@
'targets': [
{
'target_name': 'libuv',
'type': '<(library)',
'type': '<(uv_library)',
'include_dirs': [
'include',
'src/',
@@ -61,7 +61,9 @@
'include/uv.h',
'include/tree.h',
'include/uv-errno.h',
'include/uv-version.h',
'src/fs-poll.c',
'src/heap-inl.h',
'src/inet.c',
'src/queue.h',
'src/uv-common.c',
@@ -167,10 +169,10 @@
],
},
'conditions': [
['library=="shared_library"', {
['uv_library=="shared_library"', {
'cflags': [ '-fPIC' ],
}],
['library=="shared_library" and OS!="mac"', {
['uv_library=="shared_library" and OS!="mac"', {
'link_settings': {
# Must correspond with UV_VERSION_MAJOR and UV_VERSION_MINOR
# in src/version.c
@@ -265,7 +267,7 @@
[ 'OS in "mac freebsd dragonflybsd openbsd netbsd".split()', {
'sources': [ 'src/unix/kqueue.c' ],
}],
['library=="shared_library"', {
['uv_library=="shared_library"', {
'defines': [ 'BUILDING_UV_SHARED=1' ]
}],
# FIXME(bnoordhuis or tjfontaine) Unify this, it's extremely ugly.
@@ -324,6 +326,7 @@
'test/test-list.h',
'test/test-loop-handles.c',
'test/test-loop-alive.c',
'test/test-loop-close.c',
'test/test-loop-stop.c',
'test/test-loop-time.c',
'test/test-walk-handles.c',
@@ -334,6 +337,7 @@
'test/test-ping-pong.c',
'test/test-pipe-bind-error.c',
'test/test-pipe-connect-error.c',
'test/test-pipe-getsockname.c',
'test/test-pipe-server-close.c',
'test/test-platform-output.c',
'test/test-poll.c',
@@ -345,6 +349,7 @@
'test/test-semaphore.c',
'test/test-shutdown-close.c',
'test/test-shutdown-eof.c',
'test/test-shutdown-twice.c',
'test/test-signal.c',
'test/test-signal-multiple-loops.c',
'test/test-spawn.c',
@@ -387,6 +392,7 @@
'test/test-udp-multicast-ttl.c',
'test/test-ip4-addr.c',
'test/test-ip6-addr.c',
'test/test-udp-multicast-interface.c',
],
'conditions': [
[ 'OS=="win"', {
@@ -33,14 +33,17 @@ if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok
if /i "%1"=="nobuild" set nobuild=1&goto arg-ok
if /i "%1"=="x86" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok
if /i "%1"=="ia32" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok
if /i "%1"=="x64" set target_arch=x64&set platform=amd64&set vs_toolset=x64&goto arg-ok
if /i "%1"=="x64" set target_arch=x64&set platform=x64&set vs_toolset=x64&goto arg-ok
if /i "%1"=="shared" set library=shared_library&goto arg-ok
if /i "%1"=="static" set library=static_library&goto arg-ok
:arg-ok
shift
goto next-arg
:args-done

if defined WindowsSDKDir goto select-target
if defined VCINSTALLDIR goto select-target

@rem Look for Visual Studio 2013
if not defined VS120COMNTOOLS goto vc-set-2012
if not exist "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2012
@@ -99,7 +102,7 @@ exit /b 1

:have_gyp
if not defined PYTHON set PYTHON="python"
%PYTHON% gyp_uv.py -Dtarget_arch=%target_arch% -Dlibrary=%library%
%PYTHON% gyp_uv.py -Dtarget_arch=%target_arch% -Duv_library=%library%
if errorlevel 1 goto create-msvs-files-failed
if not exist uv.sln goto create-msvs-files-failed
echo Project files generated.
@@ -109,10 +112,8 @@ echo Project files generated.
if defined nobuild goto run

@rem Check if VS build env is available
if not defined VCINSTALLDIR goto msbuild-not-found
goto msbuild-found

:msbuild-not-found
if defined VCINSTALLDIR goto msbuild-found
if defined WindowsSDKDir goto msbuild-found
echo Build skipped. To build, this file needs to run from VS cmd prompt.
goto run

@@ -769,12 +769,14 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {

buf += off;

uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);

if (cb->IsFunction()) {
ASYNC_CALL(write, cb, fd, buf, len, pos)
ASYNC_CALL(write, cb, fd, &uvbuf, 1, pos)
return;
}

SYNC_CALL(write, NULL, fd, buf, len, pos)
SYNC_CALL(write, NULL, fd, &uvbuf, 1, pos)
args.GetReturnValue().Set(SYNC_RESULT);
}

@@ -818,8 +820,10 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
pos = GET_OFFSET(args[2]);
cb = args[4];

uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);

if (!cb->IsFunction()) {
SYNC_CALL(write, NULL, fd, buf, len, pos)
SYNC_CALL(write, NULL, fd, &uvbuf, 1, pos)
if (must_free)
delete[] buf;
return args.GetReturnValue().Set(SYNC_RESULT);
@@ -829,8 +833,8 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
int err = uv_fs_write(env->event_loop(),
&req_wrap->req_,
fd,
buf,
len,
&uvbuf,
1,
pos,
After);
req_wrap->object()->Set(env->oncomplete_string(), cb);
@@ -896,12 +900,14 @@ static void Read(const FunctionCallbackInfo<Value>& args) {

buf = buffer_data + off;

uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);

cb = args[5];

if (cb->IsFunction()) {
ASYNC_CALL(read, cb, fd, buf, len, pos);
ASYNC_CALL(read, cb, fd, &uvbuf, 1, pos);
} else {
SYNC_CALL(read, 0, fd, buf, len, pos)
SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
args.GetReturnValue().Set(SYNC_RESULT);
}
}
@@ -1025,6 +1025,7 @@ void SyncProcessRunner::ExitCallback(uv_process_t* handle,
int64_t exit_status,
int term_signal) {
SyncProcessRunner* self = reinterpret_cast<SyncProcessRunner*>(handle->data);
uv_close(reinterpret_cast<uv_handle_t*>(handle), NULL);
self->OnExit(exit_status, term_signal);
}