mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-03 03:50:40 +00:00
Basic relay link connection
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
/* 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 "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define NUM_PINGS (1000 * 1000)
|
||||
#define ACCESS_ONCE(type, var) (*(volatile type*) &(var))
|
||||
|
||||
static unsigned int callbacks;
|
||||
static volatile int done;
|
||||
|
||||
static const char running[] = "running";
|
||||
static const char stop[] = "stop";
|
||||
static const char stopped[] = "stopped";
|
||||
|
||||
|
||||
static void async_cb(uv_async_t* handle) {
|
||||
if (++callbacks == NUM_PINGS) {
|
||||
/* Tell the pummel thread to stop. */
|
||||
ACCESS_ONCE(const char*, handle->data) = stop;
|
||||
|
||||
/* Wait for for the pummel thread to acknowledge that it has stoppped. */
|
||||
while (ACCESS_ONCE(const char*, handle->data) != stopped)
|
||||
uv_sleep(0);
|
||||
|
||||
uv_close((uv_handle_t*) handle, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void pummel(void* arg) {
|
||||
uv_async_t* handle = (uv_async_t*) arg;
|
||||
|
||||
while (ACCESS_ONCE(const char*, handle->data) == running)
|
||||
uv_async_send(handle);
|
||||
|
||||
/* Acknowledge that we've seen handle->data change. */
|
||||
ACCESS_ONCE(const char*, handle->data) = stopped;
|
||||
}
|
||||
|
||||
|
||||
static int test_async_pummel(int nthreads) {
|
||||
uv_thread_t* tids;
|
||||
uv_async_t handle;
|
||||
uint64_t time;
|
||||
int i;
|
||||
|
||||
tids = calloc(nthreads, sizeof(tids[0]));
|
||||
ASSERT(tids != NULL);
|
||||
|
||||
ASSERT(0 == uv_async_init(uv_default_loop(), &handle, async_cb));
|
||||
ACCESS_ONCE(const char*, handle.data) = running;
|
||||
|
||||
for (i = 0; i < nthreads; i++)
|
||||
ASSERT(0 == uv_thread_create(tids + i, pummel, &handle));
|
||||
|
||||
time = uv_hrtime();
|
||||
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
|
||||
time = uv_hrtime() - time;
|
||||
done = 1;
|
||||
|
||||
for (i = 0; i < nthreads; i++)
|
||||
ASSERT(0 == uv_thread_join(tids + i));
|
||||
|
||||
printf("async_pummel_%d: %s callbacks in %.2f seconds (%s/sec)\n",
|
||||
nthreads,
|
||||
fmt(callbacks),
|
||||
time / 1e9,
|
||||
fmt(callbacks / (time / 1e9)));
|
||||
|
||||
free(tids);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(async_pummel_1) {
|
||||
return test_async_pummel(1);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(async_pummel_2) {
|
||||
return test_async_pummel(2);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(async_pummel_4) {
|
||||
return test_async_pummel(4);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(async_pummel_8) {
|
||||
return test_async_pummel(8);
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/* 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 "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define NUM_PINGS (1000 * 1000)
|
||||
|
||||
struct ctx {
|
||||
uv_loop_t loop;
|
||||
uv_thread_t thread;
|
||||
uv_async_t main_async; /* wake up main thread */
|
||||
uv_async_t worker_async; /* wake up worker */
|
||||
unsigned int nthreads;
|
||||
unsigned int main_sent;
|
||||
unsigned int main_seen;
|
||||
unsigned int worker_sent;
|
||||
unsigned int worker_seen;
|
||||
};
|
||||
|
||||
|
||||
static void worker_async_cb(uv_async_t* handle) {
|
||||
struct ctx* ctx = container_of(handle, struct ctx, worker_async);
|
||||
|
||||
ASSERT(0 == uv_async_send(&ctx->main_async));
|
||||
ctx->worker_sent++;
|
||||
ctx->worker_seen++;
|
||||
|
||||
if (ctx->worker_sent >= NUM_PINGS)
|
||||
uv_close((uv_handle_t*) &ctx->worker_async, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void main_async_cb(uv_async_t* handle) {
|
||||
struct ctx* ctx = container_of(handle, struct ctx, main_async);
|
||||
|
||||
ASSERT(0 == uv_async_send(&ctx->worker_async));
|
||||
ctx->main_sent++;
|
||||
ctx->main_seen++;
|
||||
|
||||
if (ctx->main_sent >= NUM_PINGS)
|
||||
uv_close((uv_handle_t*) &ctx->main_async, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void worker(void* arg) {
|
||||
struct ctx* ctx = arg;
|
||||
ASSERT(0 == uv_async_send(&ctx->main_async));
|
||||
ASSERT(0 == uv_run(&ctx->loop, UV_RUN_DEFAULT));
|
||||
uv_loop_close(&ctx->loop);
|
||||
}
|
||||
|
||||
|
||||
static int test_async(int nthreads) {
|
||||
struct ctx* threads;
|
||||
struct ctx* ctx;
|
||||
uint64_t time;
|
||||
int i;
|
||||
|
||||
threads = calloc(nthreads, sizeof(threads[0]));
|
||||
ASSERT(threads != NULL);
|
||||
|
||||
for (i = 0; i < nthreads; i++) {
|
||||
ctx = threads + i;
|
||||
ctx->nthreads = nthreads;
|
||||
ASSERT(0 == uv_loop_init(&ctx->loop));
|
||||
ASSERT(0 == uv_async_init(&ctx->loop, &ctx->worker_async, worker_async_cb));
|
||||
ASSERT(0 == uv_async_init(uv_default_loop(),
|
||||
&ctx->main_async,
|
||||
main_async_cb));
|
||||
ASSERT(0 == uv_thread_create(&ctx->thread, worker, ctx));
|
||||
}
|
||||
|
||||
time = uv_hrtime();
|
||||
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
|
||||
for (i = 0; i < nthreads; i++)
|
||||
ASSERT(0 == uv_thread_join(&threads[i].thread));
|
||||
|
||||
time = uv_hrtime() - time;
|
||||
|
||||
for (i = 0; i < nthreads; i++) {
|
||||
ctx = threads + i;
|
||||
ASSERT(ctx->worker_sent == NUM_PINGS);
|
||||
ASSERT(ctx->worker_seen == NUM_PINGS);
|
||||
ASSERT(ctx->main_sent == (unsigned int) NUM_PINGS);
|
||||
ASSERT(ctx->main_seen == (unsigned int) NUM_PINGS);
|
||||
}
|
||||
|
||||
printf("async%d: %.2f sec (%s/sec)\n",
|
||||
nthreads,
|
||||
time / 1e9,
|
||||
fmt(NUM_PINGS / (time / 1e9)));
|
||||
|
||||
free(threads);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(async1) {
|
||||
return test_async(1);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(async2) {
|
||||
return test_async(2);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(async4) {
|
||||
return test_async(4);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(async8) {
|
||||
return test_async(8);
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/* 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 "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define NUM_SYNC_REQS (10 * 1e5)
|
||||
#define NUM_ASYNC_REQS (1 * (int) 1e5)
|
||||
#define MAX_CONCURRENT_REQS 32
|
||||
|
||||
#define sync_stat(req, path) \
|
||||
do { \
|
||||
uv_fs_stat(NULL, (req), (path), NULL); \
|
||||
uv_fs_req_cleanup((req)); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
struct async_req {
|
||||
const char* path;
|
||||
uv_fs_t fs_req;
|
||||
int* count;
|
||||
};
|
||||
|
||||
|
||||
static void warmup(const char* path) {
|
||||
uv_fs_t reqs[MAX_CONCURRENT_REQS];
|
||||
unsigned int i;
|
||||
|
||||
/* warm up the thread pool */
|
||||
for (i = 0; i < ARRAY_SIZE(reqs); i++)
|
||||
uv_fs_stat(uv_default_loop(), reqs + i, path, uv_fs_req_cleanup);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
/* warm up the OS dirent cache */
|
||||
for (i = 0; i < 16; i++)
|
||||
sync_stat(reqs + 0, path);
|
||||
}
|
||||
|
||||
|
||||
static void sync_bench(const char* path) {
|
||||
uint64_t before;
|
||||
uint64_t after;
|
||||
uv_fs_t req;
|
||||
int i;
|
||||
|
||||
/* do the sync benchmark */
|
||||
before = uv_hrtime();
|
||||
|
||||
for (i = 0; i < NUM_SYNC_REQS; i++)
|
||||
sync_stat(&req, path);
|
||||
|
||||
after = uv_hrtime();
|
||||
|
||||
printf("%s stats (sync): %.2fs (%s/s)\n",
|
||||
fmt(1.0 * NUM_SYNC_REQS),
|
||||
(after - before) / 1e9,
|
||||
fmt((1.0 * NUM_SYNC_REQS) / ((after - before) / 1e9)));
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
static void stat_cb(uv_fs_t* fs_req) {
|
||||
struct async_req* req = container_of(fs_req, struct async_req, fs_req);
|
||||
uv_fs_req_cleanup(&req->fs_req);
|
||||
if (*req->count == 0) return;
|
||||
uv_fs_stat(uv_default_loop(), &req->fs_req, req->path, stat_cb);
|
||||
(*req->count)--;
|
||||
}
|
||||
|
||||
|
||||
static void async_bench(const char* path) {
|
||||
struct async_req reqs[MAX_CONCURRENT_REQS];
|
||||
struct async_req* req;
|
||||
uint64_t before;
|
||||
uint64_t after;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= MAX_CONCURRENT_REQS; i++) {
|
||||
count = NUM_ASYNC_REQS;
|
||||
|
||||
for (req = reqs; req < reqs + i; req++) {
|
||||
req->path = path;
|
||||
req->count = &count;
|
||||
uv_fs_stat(uv_default_loop(), &req->fs_req, req->path, stat_cb);
|
||||
}
|
||||
|
||||
before = uv_hrtime();
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
after = uv_hrtime();
|
||||
|
||||
printf("%s stats (%d concurrent): %.2fs (%s/s)\n",
|
||||
fmt(1.0 * NUM_ASYNC_REQS),
|
||||
i,
|
||||
(after - before) / 1e9,
|
||||
fmt((1.0 * NUM_ASYNC_REQS) / ((after - before) / 1e9)));
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This benchmark aims to measure the overhead of doing I/O syscalls from
|
||||
* the thread pool. The stat() syscall was chosen because its results are
|
||||
* easy for the operating system to cache, taking the actual I/O overhead
|
||||
* out of the equation.
|
||||
*/
|
||||
BENCHMARK_IMPL(fs_stat) {
|
||||
const char path[] = ".";
|
||||
warmup(path);
|
||||
sync_bench(path);
|
||||
async_bench(path);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/* 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 <stdlib.h>
|
||||
|
||||
#define CONCURRENT_CALLS 10
|
||||
#define TOTAL_CALLS 10000
|
||||
|
||||
static const char* name = "localhost";
|
||||
|
||||
static uv_loop_t* loop;
|
||||
|
||||
static uv_getaddrinfo_t handles[CONCURRENT_CALLS];
|
||||
|
||||
static int calls_initiated = 0;
|
||||
static int calls_completed = 0;
|
||||
static int64_t start_time;
|
||||
static int64_t end_time;
|
||||
|
||||
|
||||
static void getaddrinfo_initiate(uv_getaddrinfo_t* handle);
|
||||
|
||||
|
||||
static void getaddrinfo_cb(uv_getaddrinfo_t* handle, int status,
|
||||
struct addrinfo* res) {
|
||||
ASSERT(status == 0);
|
||||
calls_completed++;
|
||||
if (calls_initiated < TOTAL_CALLS) {
|
||||
getaddrinfo_initiate(handle);
|
||||
}
|
||||
|
||||
uv_freeaddrinfo(res);
|
||||
}
|
||||
|
||||
|
||||
static void getaddrinfo_initiate(uv_getaddrinfo_t* handle) {
|
||||
int r;
|
||||
|
||||
calls_initiated++;
|
||||
|
||||
r = uv_getaddrinfo(loop, handle, &getaddrinfo_cb, name, NULL, NULL);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(getaddrinfo) {
|
||||
int i;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
uv_update_time(loop);
|
||||
start_time = uv_now(loop);
|
||||
|
||||
for (i = 0; i < CONCURRENT_CALLS; i++) {
|
||||
getaddrinfo_initiate(&handles[i]);
|
||||
}
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
uv_update_time(loop);
|
||||
end_time = uv_now(loop);
|
||||
|
||||
ASSERT(calls_initiated == TOTAL_CALLS);
|
||||
ASSERT(calls_completed == TOTAL_CALLS);
|
||||
|
||||
fprintf(stderr, "getaddrinfo: %.0f req/s\n",
|
||||
(double) calls_completed / (double) (end_time - start_time) * 1000.0);
|
||||
fflush(stderr);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
BENCHMARK_DECLARE (sizes)
|
||||
BENCHMARK_DECLARE (loop_count)
|
||||
BENCHMARK_DECLARE (loop_count_timed)
|
||||
BENCHMARK_DECLARE (ping_pongs)
|
||||
BENCHMARK_DECLARE (tcp_write_batch)
|
||||
BENCHMARK_DECLARE (tcp4_pound_100)
|
||||
BENCHMARK_DECLARE (tcp4_pound_1000)
|
||||
BENCHMARK_DECLARE (pipe_pound_100)
|
||||
BENCHMARK_DECLARE (pipe_pound_1000)
|
||||
BENCHMARK_DECLARE (tcp_pump100_client)
|
||||
BENCHMARK_DECLARE (tcp_pump1_client)
|
||||
BENCHMARK_DECLARE (pipe_pump100_client)
|
||||
BENCHMARK_DECLARE (pipe_pump1_client)
|
||||
|
||||
BENCHMARK_DECLARE (tcp_multi_accept2)
|
||||
BENCHMARK_DECLARE (tcp_multi_accept4)
|
||||
BENCHMARK_DECLARE (tcp_multi_accept8)
|
||||
|
||||
/* Run until X packets have been sent/received. */
|
||||
BENCHMARK_DECLARE (udp_pummel_1v1)
|
||||
BENCHMARK_DECLARE (udp_pummel_1v10)
|
||||
BENCHMARK_DECLARE (udp_pummel_1v100)
|
||||
BENCHMARK_DECLARE (udp_pummel_1v1000)
|
||||
BENCHMARK_DECLARE (udp_pummel_10v10)
|
||||
BENCHMARK_DECLARE (udp_pummel_10v100)
|
||||
BENCHMARK_DECLARE (udp_pummel_10v1000)
|
||||
BENCHMARK_DECLARE (udp_pummel_100v100)
|
||||
BENCHMARK_DECLARE (udp_pummel_100v1000)
|
||||
BENCHMARK_DECLARE (udp_pummel_1000v1000)
|
||||
|
||||
/* Run until X seconds have elapsed. */
|
||||
BENCHMARK_DECLARE (udp_timed_pummel_1v1)
|
||||
BENCHMARK_DECLARE (udp_timed_pummel_1v10)
|
||||
BENCHMARK_DECLARE (udp_timed_pummel_1v100)
|
||||
BENCHMARK_DECLARE (udp_timed_pummel_1v1000)
|
||||
BENCHMARK_DECLARE (udp_timed_pummel_10v10)
|
||||
BENCHMARK_DECLARE (udp_timed_pummel_10v100)
|
||||
BENCHMARK_DECLARE (udp_timed_pummel_10v1000)
|
||||
BENCHMARK_DECLARE (udp_timed_pummel_100v100)
|
||||
BENCHMARK_DECLARE (udp_timed_pummel_100v1000)
|
||||
BENCHMARK_DECLARE (udp_timed_pummel_1000v1000)
|
||||
|
||||
BENCHMARK_DECLARE (getaddrinfo)
|
||||
BENCHMARK_DECLARE (fs_stat)
|
||||
BENCHMARK_DECLARE (async1)
|
||||
BENCHMARK_DECLARE (async2)
|
||||
BENCHMARK_DECLARE (async4)
|
||||
BENCHMARK_DECLARE (async8)
|
||||
BENCHMARK_DECLARE (async_pummel_1)
|
||||
BENCHMARK_DECLARE (async_pummel_2)
|
||||
BENCHMARK_DECLARE (async_pummel_4)
|
||||
BENCHMARK_DECLARE (async_pummel_8)
|
||||
BENCHMARK_DECLARE (spawn)
|
||||
BENCHMARK_DECLARE (thread_create)
|
||||
BENCHMARK_DECLARE (million_async)
|
||||
BENCHMARK_DECLARE (million_timers)
|
||||
HELPER_DECLARE (tcp4_blackhole_server)
|
||||
HELPER_DECLARE (tcp_pump_server)
|
||||
HELPER_DECLARE (pipe_pump_server)
|
||||
HELPER_DECLARE (tcp4_echo_server)
|
||||
HELPER_DECLARE (pipe_echo_server)
|
||||
HELPER_DECLARE (dns_server)
|
||||
|
||||
TASK_LIST_START
|
||||
BENCHMARK_ENTRY (sizes)
|
||||
BENCHMARK_ENTRY (loop_count)
|
||||
BENCHMARK_ENTRY (loop_count_timed)
|
||||
|
||||
BENCHMARK_ENTRY (ping_pongs)
|
||||
BENCHMARK_HELPER (ping_pongs, tcp4_echo_server)
|
||||
|
||||
BENCHMARK_ENTRY (tcp_write_batch)
|
||||
BENCHMARK_HELPER (tcp_write_batch, tcp4_blackhole_server)
|
||||
|
||||
BENCHMARK_ENTRY (tcp_pump100_client)
|
||||
BENCHMARK_HELPER (tcp_pump100_client, tcp_pump_server)
|
||||
|
||||
BENCHMARK_ENTRY (tcp_pump1_client)
|
||||
BENCHMARK_HELPER (tcp_pump1_client, tcp_pump_server)
|
||||
|
||||
BENCHMARK_ENTRY (tcp4_pound_100)
|
||||
BENCHMARK_HELPER (tcp4_pound_100, tcp4_echo_server)
|
||||
|
||||
BENCHMARK_ENTRY (tcp4_pound_1000)
|
||||
BENCHMARK_HELPER (tcp4_pound_1000, tcp4_echo_server)
|
||||
|
||||
BENCHMARK_ENTRY (pipe_pump100_client)
|
||||
BENCHMARK_HELPER (pipe_pump100_client, pipe_pump_server)
|
||||
|
||||
BENCHMARK_ENTRY (pipe_pump1_client)
|
||||
BENCHMARK_HELPER (pipe_pump1_client, pipe_pump_server)
|
||||
|
||||
BENCHMARK_ENTRY (pipe_pound_100)
|
||||
BENCHMARK_HELPER (pipe_pound_100, pipe_echo_server)
|
||||
|
||||
BENCHMARK_ENTRY (pipe_pound_1000)
|
||||
BENCHMARK_HELPER (pipe_pound_1000, pipe_echo_server)
|
||||
|
||||
BENCHMARK_ENTRY (tcp_multi_accept2)
|
||||
BENCHMARK_ENTRY (tcp_multi_accept4)
|
||||
BENCHMARK_ENTRY (tcp_multi_accept8)
|
||||
|
||||
BENCHMARK_ENTRY (udp_pummel_1v1)
|
||||
BENCHMARK_ENTRY (udp_pummel_1v10)
|
||||
BENCHMARK_ENTRY (udp_pummel_1v100)
|
||||
BENCHMARK_ENTRY (udp_pummel_1v1000)
|
||||
BENCHMARK_ENTRY (udp_pummel_10v10)
|
||||
BENCHMARK_ENTRY (udp_pummel_10v100)
|
||||
BENCHMARK_ENTRY (udp_pummel_10v1000)
|
||||
BENCHMARK_ENTRY (udp_pummel_100v100)
|
||||
BENCHMARK_ENTRY (udp_pummel_100v1000)
|
||||
BENCHMARK_ENTRY (udp_pummel_1000v1000)
|
||||
|
||||
BENCHMARK_ENTRY (udp_timed_pummel_1v1)
|
||||
BENCHMARK_ENTRY (udp_timed_pummel_1v10)
|
||||
BENCHMARK_ENTRY (udp_timed_pummel_1v100)
|
||||
BENCHMARK_ENTRY (udp_timed_pummel_1v1000)
|
||||
BENCHMARK_ENTRY (udp_timed_pummel_10v10)
|
||||
BENCHMARK_ENTRY (udp_timed_pummel_10v100)
|
||||
BENCHMARK_ENTRY (udp_timed_pummel_10v1000)
|
||||
BENCHMARK_ENTRY (udp_timed_pummel_100v100)
|
||||
BENCHMARK_ENTRY (udp_timed_pummel_100v1000)
|
||||
BENCHMARK_ENTRY (udp_timed_pummel_1000v1000)
|
||||
|
||||
BENCHMARK_ENTRY (getaddrinfo)
|
||||
|
||||
BENCHMARK_ENTRY (fs_stat)
|
||||
|
||||
BENCHMARK_ENTRY (async1)
|
||||
BENCHMARK_ENTRY (async2)
|
||||
BENCHMARK_ENTRY (async4)
|
||||
BENCHMARK_ENTRY (async8)
|
||||
BENCHMARK_ENTRY (async_pummel_1)
|
||||
BENCHMARK_ENTRY (async_pummel_2)
|
||||
BENCHMARK_ENTRY (async_pummel_4)
|
||||
BENCHMARK_ENTRY (async_pummel_8)
|
||||
|
||||
BENCHMARK_ENTRY (spawn)
|
||||
BENCHMARK_ENTRY (thread_create)
|
||||
BENCHMARK_ENTRY (million_async)
|
||||
BENCHMARK_ENTRY (million_timers)
|
||||
TASK_LIST_END
|
||||
@@ -0,0 +1,92 @@
|
||||
/* 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 "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define NUM_TICKS (2 * 1000 * 1000)
|
||||
|
||||
static unsigned long ticks;
|
||||
static uv_idle_t idle_handle;
|
||||
static uv_timer_t timer_handle;
|
||||
|
||||
|
||||
static void idle_cb(uv_idle_t* handle) {
|
||||
if (++ticks == NUM_TICKS)
|
||||
uv_idle_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
static void idle2_cb(uv_idle_t* handle) {
|
||||
ticks++;
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
uv_idle_stop(&idle_handle);
|
||||
uv_timer_stop(&timer_handle);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(loop_count) {
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
uint64_t ns;
|
||||
|
||||
uv_idle_init(loop, &idle_handle);
|
||||
uv_idle_start(&idle_handle, idle_cb);
|
||||
|
||||
ns = uv_hrtime();
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
ns = uv_hrtime() - ns;
|
||||
|
||||
ASSERT(ticks == NUM_TICKS);
|
||||
|
||||
fprintf(stderr, "loop_count: %d ticks in %.2fs (%.0f/s)\n",
|
||||
NUM_TICKS,
|
||||
ns / 1e9,
|
||||
NUM_TICKS / (ns / 1e9));
|
||||
fflush(stderr);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(loop_count_timed) {
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
|
||||
uv_idle_init(loop, &idle_handle);
|
||||
uv_idle_start(&idle_handle, idle2_cb);
|
||||
|
||||
uv_timer_init(loop, &timer_handle);
|
||||
uv_timer_start(&timer_handle, timer_cb, 5000, 0);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
fprintf(stderr, "loop_count: %lu ticks (%.0f ticks/s)\n", ticks, ticks / 5.0);
|
||||
fflush(stderr);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/* 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 "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
struct async_container {
|
||||
unsigned async_events;
|
||||
unsigned handles_seen;
|
||||
uv_async_t async_handles[1024 * 1024];
|
||||
};
|
||||
|
||||
static volatile int done;
|
||||
static uv_thread_t thread_id;
|
||||
static struct async_container* container;
|
||||
|
||||
|
||||
static unsigned fastrand(void) {
|
||||
static unsigned g = 0;
|
||||
g = g * 214013 + 2531011;
|
||||
return g;
|
||||
}
|
||||
|
||||
|
||||
static void thread_cb(void* arg) {
|
||||
unsigned i;
|
||||
|
||||
while (done == 0) {
|
||||
i = fastrand() % ARRAY_SIZE(container->async_handles);
|
||||
uv_async_send(container->async_handles + i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void async_cb(uv_async_t* handle) {
|
||||
container->async_events++;
|
||||
handle->data = handle;
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
unsigned i;
|
||||
|
||||
done = 1;
|
||||
ASSERT(0 == uv_thread_join(&thread_id));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(container->async_handles); i++) {
|
||||
uv_async_t* handle = container->async_handles + i;
|
||||
|
||||
if (handle->data != NULL)
|
||||
container->handles_seen++;
|
||||
|
||||
uv_close((uv_handle_t*) handle, NULL);
|
||||
}
|
||||
|
||||
uv_close((uv_handle_t*) handle, NULL);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(million_async) {
|
||||
uv_timer_t timer_handle;
|
||||
uv_async_t* handle;
|
||||
uv_loop_t* loop;
|
||||
int timeout;
|
||||
unsigned i;
|
||||
|
||||
loop = uv_default_loop();
|
||||
timeout = 5000;
|
||||
|
||||
container = malloc(sizeof(*container));
|
||||
ASSERT(container != NULL);
|
||||
container->async_events = 0;
|
||||
container->handles_seen = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(container->async_handles); i++) {
|
||||
handle = container->async_handles + i;
|
||||
ASSERT(0 == uv_async_init(loop, handle, async_cb));
|
||||
handle->data = NULL;
|
||||
}
|
||||
|
||||
ASSERT(0 == uv_timer_init(loop, &timer_handle));
|
||||
ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, timeout, 0));
|
||||
ASSERT(0 == uv_thread_create(&thread_id, thread_cb, NULL));
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
printf("%s async events in %.1f seconds (%s/s, %s unique handles seen)\n",
|
||||
fmt(container->async_events),
|
||||
timeout / 1000.,
|
||||
fmt(container->async_events / (timeout / 1000.)),
|
||||
fmt(container->handles_seen));
|
||||
free(container);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/* 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 "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
#define NUM_TIMERS (10 * 1000 * 1000)
|
||||
|
||||
static int timer_cb_called;
|
||||
static int close_cb_called;
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
timer_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(million_timers) {
|
||||
uv_timer_t* timers;
|
||||
uv_loop_t* loop;
|
||||
uint64_t before_all;
|
||||
uint64_t before_run;
|
||||
uint64_t after_run;
|
||||
uint64_t after_all;
|
||||
int timeout;
|
||||
int i;
|
||||
|
||||
timers = malloc(NUM_TIMERS * sizeof(timers[0]));
|
||||
ASSERT(timers != NULL);
|
||||
|
||||
loop = uv_default_loop();
|
||||
timeout = 0;
|
||||
|
||||
before_all = uv_hrtime();
|
||||
for (i = 0; i < NUM_TIMERS; i++) {
|
||||
if (i % 1000 == 0) timeout++;
|
||||
ASSERT(0 == uv_timer_init(loop, timers + i));
|
||||
ASSERT(0 == uv_timer_start(timers + i, timer_cb, timeout, 0));
|
||||
}
|
||||
|
||||
before_run = uv_hrtime();
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
after_run = uv_hrtime();
|
||||
|
||||
for (i = 0; i < NUM_TIMERS; i++)
|
||||
uv_close((uv_handle_t*) (timers + i), close_cb);
|
||||
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
after_all = uv_hrtime();
|
||||
|
||||
ASSERT(timer_cb_called == NUM_TIMERS);
|
||||
ASSERT(close_cb_called == NUM_TIMERS);
|
||||
free(timers);
|
||||
|
||||
fprintf(stderr, "%.2f seconds total\n", (after_all - before_all) / 1e9);
|
||||
fprintf(stderr, "%.2f seconds init\n", (before_run - before_all) / 1e9);
|
||||
fprintf(stderr, "%.2f seconds dispatch\n", (after_run - before_run) / 1e9);
|
||||
fprintf(stderr, "%.2f seconds cleanup\n", (after_all - after_run) / 1e9);
|
||||
fflush(stderr);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
/* 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 "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
#define IPC_PIPE_NAME TEST_PIPENAME
|
||||
#define NUM_CONNECTS (250 * 1000)
|
||||
|
||||
union stream_handle {
|
||||
uv_pipe_t pipe;
|
||||
uv_tcp_t tcp;
|
||||
};
|
||||
|
||||
/* Use as (uv_stream_t *) &handle_storage -- it's kind of clunky but it
|
||||
* avoids aliasing warnings.
|
||||
*/
|
||||
typedef unsigned char handle_storage_t[sizeof(union stream_handle)];
|
||||
|
||||
/* Used for passing around the listen handle, not part of the benchmark proper.
|
||||
* We have an overabundance of server types here. It works like this:
|
||||
*
|
||||
* 1. The main thread starts an IPC pipe server.
|
||||
* 2. The worker threads connect to the IPC server and obtain a listen handle.
|
||||
* 3. The worker threads start accepting requests on the listen handle.
|
||||
* 4. The main thread starts connecting repeatedly.
|
||||
*
|
||||
* Step #4 should perhaps be farmed out over several threads.
|
||||
*/
|
||||
struct ipc_server_ctx {
|
||||
handle_storage_t server_handle;
|
||||
unsigned int num_connects;
|
||||
uv_pipe_t ipc_pipe;
|
||||
};
|
||||
|
||||
struct ipc_peer_ctx {
|
||||
handle_storage_t peer_handle;
|
||||
uv_write_t write_req;
|
||||
};
|
||||
|
||||
struct ipc_client_ctx {
|
||||
uv_connect_t connect_req;
|
||||
uv_stream_t* server_handle;
|
||||
uv_pipe_t ipc_pipe;
|
||||
char scratch[16];
|
||||
};
|
||||
|
||||
/* Used in the actual benchmark. */
|
||||
struct server_ctx {
|
||||
handle_storage_t server_handle;
|
||||
unsigned int num_connects;
|
||||
uv_async_t async_handle;
|
||||
uv_thread_t thread_id;
|
||||
uv_sem_t semaphore;
|
||||
};
|
||||
|
||||
struct client_ctx {
|
||||
handle_storage_t client_handle;
|
||||
unsigned int num_connects;
|
||||
uv_connect_t connect_req;
|
||||
uv_idle_t idle_handle;
|
||||
};
|
||||
|
||||
static void ipc_connection_cb(uv_stream_t* ipc_pipe, int status);
|
||||
static void ipc_write_cb(uv_write_t* req, int status);
|
||||
static void ipc_close_cb(uv_handle_t* handle);
|
||||
static void ipc_connect_cb(uv_connect_t* req, int status);
|
||||
static void ipc_read_cb(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf);
|
||||
static void ipc_alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf);
|
||||
|
||||
static void sv_async_cb(uv_async_t* handle);
|
||||
static void sv_connection_cb(uv_stream_t* server_handle, int status);
|
||||
static void sv_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf);
|
||||
static void sv_alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf);
|
||||
|
||||
static void cl_connect_cb(uv_connect_t* req, int status);
|
||||
static void cl_idle_cb(uv_idle_t* handle);
|
||||
static void cl_close_cb(uv_handle_t* handle);
|
||||
|
||||
static struct sockaddr_in listen_addr;
|
||||
|
||||
|
||||
static void ipc_connection_cb(uv_stream_t* ipc_pipe, int status) {
|
||||
struct ipc_server_ctx* sc;
|
||||
struct ipc_peer_ctx* pc;
|
||||
uv_loop_t* loop;
|
||||
uv_buf_t buf;
|
||||
|
||||
loop = ipc_pipe->loop;
|
||||
buf = uv_buf_init("PING", 4);
|
||||
sc = container_of(ipc_pipe, struct ipc_server_ctx, ipc_pipe);
|
||||
pc = calloc(1, sizeof(*pc));
|
||||
ASSERT(pc != NULL);
|
||||
|
||||
if (ipc_pipe->type == UV_TCP)
|
||||
ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &pc->peer_handle));
|
||||
else if (ipc_pipe->type == UV_NAMED_PIPE)
|
||||
ASSERT(0 == uv_pipe_init(loop, (uv_pipe_t*) &pc->peer_handle, 1));
|
||||
else
|
||||
ASSERT(0);
|
||||
|
||||
ASSERT(0 == uv_accept(ipc_pipe, (uv_stream_t*) &pc->peer_handle));
|
||||
ASSERT(0 == uv_write2(&pc->write_req,
|
||||
(uv_stream_t*) &pc->peer_handle,
|
||||
&buf,
|
||||
1,
|
||||
(uv_stream_t*) &sc->server_handle,
|
||||
ipc_write_cb));
|
||||
|
||||
if (--sc->num_connects == 0)
|
||||
uv_close((uv_handle_t*) ipc_pipe, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void ipc_write_cb(uv_write_t* req, int status) {
|
||||
struct ipc_peer_ctx* ctx;
|
||||
ctx = container_of(req, struct ipc_peer_ctx, write_req);
|
||||
uv_close((uv_handle_t*) &ctx->peer_handle, ipc_close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void ipc_close_cb(uv_handle_t* handle) {
|
||||
struct ipc_peer_ctx* ctx;
|
||||
ctx = container_of(handle, struct ipc_peer_ctx, peer_handle);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
|
||||
static void ipc_connect_cb(uv_connect_t* req, int status) {
|
||||
struct ipc_client_ctx* ctx;
|
||||
ctx = container_of(req, struct ipc_client_ctx, connect_req);
|
||||
ASSERT(0 == status);
|
||||
ASSERT(0 == uv_read_start((uv_stream_t*) &ctx->ipc_pipe,
|
||||
ipc_alloc_cb,
|
||||
ipc_read_cb));
|
||||
}
|
||||
|
||||
|
||||
static void ipc_alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
struct ipc_client_ctx* ctx;
|
||||
ctx = container_of(handle, struct ipc_client_ctx, ipc_pipe);
|
||||
buf->base = ctx->scratch;
|
||||
buf->len = sizeof(ctx->scratch);
|
||||
}
|
||||
|
||||
|
||||
static void ipc_read_cb(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
struct ipc_client_ctx* ctx;
|
||||
uv_loop_t* loop;
|
||||
uv_handle_type type;
|
||||
uv_pipe_t* ipc_pipe;
|
||||
|
||||
ipc_pipe = (uv_pipe_t*) handle;
|
||||
ctx = container_of(ipc_pipe, struct ipc_client_ctx, ipc_pipe);
|
||||
loop = ipc_pipe->loop;
|
||||
|
||||
ASSERT(1 == uv_pipe_pending_count(ipc_pipe));
|
||||
type = uv_pipe_pending_type(ipc_pipe);
|
||||
if (type == UV_TCP)
|
||||
ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) ctx->server_handle));
|
||||
else if (type == UV_NAMED_PIPE)
|
||||
ASSERT(0 == uv_pipe_init(loop, (uv_pipe_t*) ctx->server_handle, 0));
|
||||
else
|
||||
ASSERT(0);
|
||||
|
||||
ASSERT(0 == uv_accept(handle, ctx->server_handle));
|
||||
uv_close((uv_handle_t*) &ctx->ipc_pipe, NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Set up an IPC pipe server that hands out listen sockets to the worker
|
||||
* threads. It's kind of cumbersome for such a simple operation, maybe we
|
||||
* should revive uv_import() and uv_export().
|
||||
*/
|
||||
static void send_listen_handles(uv_handle_type type,
|
||||
unsigned int num_servers,
|
||||
struct server_ctx* servers) {
|
||||
struct ipc_server_ctx ctx;
|
||||
uv_loop_t* loop;
|
||||
unsigned int i;
|
||||
|
||||
loop = uv_default_loop();
|
||||
ctx.num_connects = num_servers;
|
||||
|
||||
if (type == UV_TCP) {
|
||||
ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &ctx.server_handle));
|
||||
ASSERT(0 == uv_tcp_bind((uv_tcp_t*) &ctx.server_handle,
|
||||
(const struct sockaddr*) &listen_addr,
|
||||
0));
|
||||
}
|
||||
else
|
||||
ASSERT(0);
|
||||
|
||||
ASSERT(0 == uv_pipe_init(loop, &ctx.ipc_pipe, 1));
|
||||
ASSERT(0 == uv_pipe_bind(&ctx.ipc_pipe, IPC_PIPE_NAME));
|
||||
ASSERT(0 == uv_listen((uv_stream_t*) &ctx.ipc_pipe, 128, ipc_connection_cb));
|
||||
|
||||
for (i = 0; i < num_servers; i++)
|
||||
uv_sem_post(&servers[i].semaphore);
|
||||
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
uv_close((uv_handle_t*) &ctx.server_handle, NULL);
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
|
||||
for (i = 0; i < num_servers; i++)
|
||||
uv_sem_wait(&servers[i].semaphore);
|
||||
}
|
||||
|
||||
|
||||
static void get_listen_handle(uv_loop_t* loop, uv_stream_t* server_handle) {
|
||||
struct ipc_client_ctx ctx;
|
||||
|
||||
ctx.server_handle = server_handle;
|
||||
ctx.server_handle->data = "server handle";
|
||||
|
||||
ASSERT(0 == uv_pipe_init(loop, &ctx.ipc_pipe, 1));
|
||||
uv_pipe_connect(&ctx.connect_req,
|
||||
&ctx.ipc_pipe,
|
||||
IPC_PIPE_NAME,
|
||||
ipc_connect_cb);
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
}
|
||||
|
||||
|
||||
static void server_cb(void *arg) {
|
||||
struct server_ctx *ctx;
|
||||
uv_loop_t loop;
|
||||
|
||||
ctx = arg;
|
||||
ASSERT(0 == uv_loop_init(&loop));
|
||||
|
||||
ASSERT(0 == uv_async_init(&loop, &ctx->async_handle, sv_async_cb));
|
||||
uv_unref((uv_handle_t*) &ctx->async_handle);
|
||||
|
||||
/* Wait until the main thread is ready. */
|
||||
uv_sem_wait(&ctx->semaphore);
|
||||
get_listen_handle(&loop, (uv_stream_t*) &ctx->server_handle);
|
||||
uv_sem_post(&ctx->semaphore);
|
||||
|
||||
/* Now start the actual benchmark. */
|
||||
ASSERT(0 == uv_listen((uv_stream_t*) &ctx->server_handle,
|
||||
128,
|
||||
sv_connection_cb));
|
||||
ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
|
||||
|
||||
uv_loop_close(&loop);
|
||||
}
|
||||
|
||||
|
||||
static void sv_async_cb(uv_async_t* handle) {
|
||||
struct server_ctx* ctx;
|
||||
ctx = container_of(handle, struct server_ctx, async_handle);
|
||||
uv_close((uv_handle_t*) &ctx->server_handle, NULL);
|
||||
uv_close((uv_handle_t*) &ctx->async_handle, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void sv_connection_cb(uv_stream_t* server_handle, int status) {
|
||||
handle_storage_t* storage;
|
||||
struct server_ctx* ctx;
|
||||
|
||||
ctx = container_of(server_handle, struct server_ctx, server_handle);
|
||||
ASSERT(status == 0);
|
||||
|
||||
storage = malloc(sizeof(*storage));
|
||||
ASSERT(storage != NULL);
|
||||
|
||||
if (server_handle->type == UV_TCP)
|
||||
ASSERT(0 == uv_tcp_init(server_handle->loop, (uv_tcp_t*) storage));
|
||||
else if (server_handle->type == UV_NAMED_PIPE)
|
||||
ASSERT(0 == uv_pipe_init(server_handle->loop, (uv_pipe_t*) storage, 0));
|
||||
else
|
||||
ASSERT(0);
|
||||
|
||||
ASSERT(0 == uv_accept(server_handle, (uv_stream_t*) storage));
|
||||
ASSERT(0 == uv_read_start((uv_stream_t*) storage, sv_alloc_cb, sv_read_cb));
|
||||
ctx->num_connects++;
|
||||
}
|
||||
|
||||
|
||||
static void sv_alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
static char slab[32];
|
||||
buf->base = slab;
|
||||
buf->len = sizeof(slab);
|
||||
}
|
||||
|
||||
|
||||
static void sv_read_cb(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
ASSERT(nread == UV_EOF);
|
||||
uv_close((uv_handle_t*) handle, (uv_close_cb) free);
|
||||
}
|
||||
|
||||
|
||||
static void cl_connect_cb(uv_connect_t* req, int status) {
|
||||
struct client_ctx* ctx = container_of(req, struct client_ctx, connect_req);
|
||||
uv_idle_start(&ctx->idle_handle, cl_idle_cb);
|
||||
ASSERT(0 == status);
|
||||
}
|
||||
|
||||
|
||||
static void cl_idle_cb(uv_idle_t* handle) {
|
||||
struct client_ctx* ctx = container_of(handle, struct client_ctx, idle_handle);
|
||||
uv_close((uv_handle_t*) &ctx->client_handle, cl_close_cb);
|
||||
uv_idle_stop(&ctx->idle_handle);
|
||||
}
|
||||
|
||||
|
||||
static void cl_close_cb(uv_handle_t* handle) {
|
||||
struct client_ctx* ctx;
|
||||
|
||||
ctx = container_of(handle, struct client_ctx, client_handle);
|
||||
|
||||
if (--ctx->num_connects == 0) {
|
||||
uv_close((uv_handle_t*) &ctx->idle_handle, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(0 == uv_tcp_init(handle->loop, (uv_tcp_t*) &ctx->client_handle));
|
||||
ASSERT(0 == uv_tcp_connect(&ctx->connect_req,
|
||||
(uv_tcp_t*) &ctx->client_handle,
|
||||
(const struct sockaddr*) &listen_addr,
|
||||
cl_connect_cb));
|
||||
}
|
||||
|
||||
|
||||
static int test_tcp(unsigned int num_servers, unsigned int num_clients) {
|
||||
struct server_ctx* servers;
|
||||
struct client_ctx* clients;
|
||||
uv_loop_t* loop;
|
||||
uv_tcp_t* handle;
|
||||
unsigned int i;
|
||||
double time;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &listen_addr));
|
||||
loop = uv_default_loop();
|
||||
|
||||
servers = calloc(num_servers, sizeof(servers[0]));
|
||||
clients = calloc(num_clients, sizeof(clients[0]));
|
||||
ASSERT(servers != NULL);
|
||||
ASSERT(clients != NULL);
|
||||
|
||||
/* We're making the assumption here that from the perspective of the
|
||||
* OS scheduler, threads are functionally equivalent to and interchangeable
|
||||
* with full-blown processes.
|
||||
*/
|
||||
for (i = 0; i < num_servers; i++) {
|
||||
struct server_ctx* ctx = servers + i;
|
||||
ASSERT(0 == uv_sem_init(&ctx->semaphore, 0));
|
||||
ASSERT(0 == uv_thread_create(&ctx->thread_id, server_cb, ctx));
|
||||
}
|
||||
|
||||
send_listen_handles(UV_TCP, num_servers, servers);
|
||||
|
||||
for (i = 0; i < num_clients; i++) {
|
||||
struct client_ctx* ctx = clients + i;
|
||||
ctx->num_connects = NUM_CONNECTS / num_clients;
|
||||
handle = (uv_tcp_t*) &ctx->client_handle;
|
||||
handle->data = "client handle";
|
||||
ASSERT(0 == uv_tcp_init(loop, handle));
|
||||
ASSERT(0 == uv_tcp_connect(&ctx->connect_req,
|
||||
handle,
|
||||
(const struct sockaddr*) &listen_addr,
|
||||
cl_connect_cb));
|
||||
ASSERT(0 == uv_idle_init(loop, &ctx->idle_handle));
|
||||
}
|
||||
|
||||
{
|
||||
uint64_t t = uv_hrtime();
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
t = uv_hrtime() - t;
|
||||
time = t / 1e9;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_servers; i++) {
|
||||
struct server_ctx* ctx = servers + i;
|
||||
uv_async_send(&ctx->async_handle);
|
||||
ASSERT(0 == uv_thread_join(&ctx->thread_id));
|
||||
uv_sem_destroy(&ctx->semaphore);
|
||||
}
|
||||
|
||||
printf("accept%u: %.0f accepts/sec (%u total)\n",
|
||||
num_servers,
|
||||
NUM_CONNECTS / time,
|
||||
NUM_CONNECTS);
|
||||
|
||||
for (i = 0; i < num_servers; i++) {
|
||||
struct server_ctx* ctx = servers + i;
|
||||
printf(" thread #%u: %.0f accepts/sec (%u total, %.1f%%)\n",
|
||||
i,
|
||||
ctx->num_connects / time,
|
||||
ctx->num_connects,
|
||||
ctx->num_connects * 100.0 / NUM_CONNECTS);
|
||||
}
|
||||
|
||||
free(clients);
|
||||
free(servers);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(tcp_multi_accept2) {
|
||||
return test_tcp(2, 40);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(tcp_multi_accept4) {
|
||||
return test_tcp(4, 40);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(tcp_multi_accept8) {
|
||||
return test_tcp(8, 40);
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
/* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Run the benchmark for this many ms */
|
||||
#define TIME 5000
|
||||
|
||||
|
||||
typedef struct {
|
||||
int pongs;
|
||||
int state;
|
||||
uv_tcp_t tcp;
|
||||
uv_connect_t connect_req;
|
||||
uv_shutdown_t shutdown_req;
|
||||
} pinger_t;
|
||||
|
||||
typedef struct buf_s {
|
||||
uv_buf_t uv_buf_t;
|
||||
struct buf_s* next;
|
||||
} buf_t;
|
||||
|
||||
|
||||
static char PING[] = "PING\n";
|
||||
|
||||
static uv_loop_t* loop;
|
||||
|
||||
static buf_t* buf_freelist = NULL;
|
||||
static int pinger_shutdown_cb_called;
|
||||
static int completed_pingers = 0;
|
||||
static int64_t start_time;
|
||||
|
||||
|
||||
static void buf_alloc(uv_handle_t* tcp, size_t size, uv_buf_t* buf) {
|
||||
buf_t* ab;
|
||||
|
||||
ab = buf_freelist;
|
||||
if (ab != NULL)
|
||||
buf_freelist = ab->next;
|
||||
else {
|
||||
ab = malloc(size + sizeof(*ab));
|
||||
ab->uv_buf_t.len = size;
|
||||
ab->uv_buf_t.base = (char*) (ab + 1);
|
||||
}
|
||||
|
||||
*buf = ab->uv_buf_t;
|
||||
}
|
||||
|
||||
|
||||
static void buf_free(const uv_buf_t* buf) {
|
||||
buf_t* ab = (buf_t*) buf->base - 1;
|
||||
ab->next = buf_freelist;
|
||||
buf_freelist = ab;
|
||||
}
|
||||
|
||||
|
||||
static void pinger_close_cb(uv_handle_t* handle) {
|
||||
pinger_t* pinger;
|
||||
|
||||
pinger = (pinger_t*)handle->data;
|
||||
fprintf(stderr, "ping_pongs: %d roundtrips/s\n", (1000 * pinger->pongs) / TIME);
|
||||
fflush(stderr);
|
||||
|
||||
free(pinger);
|
||||
|
||||
completed_pingers++;
|
||||
}
|
||||
|
||||
|
||||
static void pinger_write_cb(uv_write_t* req, int status) {
|
||||
ASSERT(status == 0);
|
||||
|
||||
free(req);
|
||||
}
|
||||
|
||||
|
||||
static void pinger_write_ping(pinger_t* pinger) {
|
||||
uv_write_t* req;
|
||||
uv_buf_t buf;
|
||||
|
||||
buf = uv_buf_init(PING, sizeof(PING) - 1);
|
||||
|
||||
req = malloc(sizeof *req);
|
||||
if (uv_write(req, (uv_stream_t*) &pinger->tcp, &buf, 1, pinger_write_cb)) {
|
||||
FATAL("uv_write failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void pinger_shutdown_cb(uv_shutdown_t* req, int status) {
|
||||
ASSERT(status == 0);
|
||||
pinger_shutdown_cb_called++;
|
||||
|
||||
/*
|
||||
* The close callback has not been triggered yet. We must wait for EOF
|
||||
* until we close the connection.
|
||||
*/
|
||||
ASSERT(completed_pingers == 0);
|
||||
}
|
||||
|
||||
|
||||
static void pinger_read_cb(uv_stream_t* tcp,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
ssize_t i;
|
||||
pinger_t* pinger;
|
||||
|
||||
pinger = (pinger_t*)tcp->data;
|
||||
|
||||
if (nread < 0) {
|
||||
ASSERT(nread == UV_EOF);
|
||||
|
||||
if (buf->base) {
|
||||
buf_free(buf);
|
||||
}
|
||||
|
||||
ASSERT(pinger_shutdown_cb_called == 1);
|
||||
uv_close((uv_handle_t*)tcp, pinger_close_cb);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now we count the pings */
|
||||
for (i = 0; i < nread; i++) {
|
||||
ASSERT(buf->base[i] == PING[pinger->state]);
|
||||
pinger->state = (pinger->state + 1) % (sizeof(PING) - 1);
|
||||
if (pinger->state == 0) {
|
||||
pinger->pongs++;
|
||||
if (uv_now(loop) - start_time > TIME) {
|
||||
uv_shutdown(&pinger->shutdown_req,
|
||||
(uv_stream_t*) tcp,
|
||||
pinger_shutdown_cb);
|
||||
break;
|
||||
} else {
|
||||
pinger_write_ping(pinger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf_free(buf);
|
||||
}
|
||||
|
||||
|
||||
static void pinger_connect_cb(uv_connect_t* req, int status) {
|
||||
pinger_t *pinger = (pinger_t*)req->handle->data;
|
||||
|
||||
ASSERT(status == 0);
|
||||
|
||||
pinger_write_ping(pinger);
|
||||
|
||||
if (uv_read_start(req->handle, buf_alloc, pinger_read_cb)) {
|
||||
FATAL("uv_read_start failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void pinger_new(void) {
|
||||
struct sockaddr_in client_addr;
|
||||
struct sockaddr_in server_addr;
|
||||
pinger_t *pinger;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &client_addr));
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
|
||||
pinger = malloc(sizeof(*pinger));
|
||||
pinger->state = 0;
|
||||
pinger->pongs = 0;
|
||||
|
||||
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
|
||||
r = uv_tcp_init(loop, &pinger->tcp);
|
||||
ASSERT(!r);
|
||||
|
||||
pinger->tcp.data = pinger;
|
||||
|
||||
ASSERT(0 == uv_tcp_bind(&pinger->tcp,
|
||||
(const struct sockaddr*) &client_addr,
|
||||
0));
|
||||
|
||||
r = uv_tcp_connect(&pinger->connect_req,
|
||||
&pinger->tcp,
|
||||
(const struct sockaddr*) &server_addr,
|
||||
pinger_connect_cb);
|
||||
ASSERT(!r);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(ping_pongs) {
|
||||
loop = uv_default_loop();
|
||||
|
||||
start_time = uv_now(loop);
|
||||
|
||||
pinger_new();
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(completed_pingers == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
/* 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 "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
/* Update this is you're going to run > 1000 concurrent requests. */
|
||||
#define MAX_CONNS 1000
|
||||
|
||||
#undef NANOSEC
|
||||
#define NANOSEC ((uint64_t) 1e9)
|
||||
|
||||
#undef DEBUG
|
||||
#define DEBUG 0
|
||||
|
||||
struct conn_rec_s;
|
||||
|
||||
typedef void (*setup_fn)(int num, void* arg);
|
||||
typedef void (*make_connect_fn)(struct conn_rec_s* conn);
|
||||
typedef int (*connect_fn)(int num, make_connect_fn make_connect, void* arg);
|
||||
|
||||
/* Base class for tcp_conn_rec and pipe_conn_rec.
|
||||
* The ordering of fields matters!
|
||||
*/
|
||||
typedef struct conn_rec_s {
|
||||
int i;
|
||||
uv_connect_t conn_req;
|
||||
uv_write_t write_req;
|
||||
make_connect_fn make_connect;
|
||||
uv_stream_t stream;
|
||||
} conn_rec;
|
||||
|
||||
typedef struct {
|
||||
int i;
|
||||
uv_connect_t conn_req;
|
||||
uv_write_t write_req;
|
||||
make_connect_fn make_connect;
|
||||
uv_tcp_t stream;
|
||||
} tcp_conn_rec;
|
||||
|
||||
typedef struct {
|
||||
int i;
|
||||
uv_connect_t conn_req;
|
||||
uv_write_t write_req;
|
||||
make_connect_fn make_connect;
|
||||
uv_pipe_t stream;
|
||||
} pipe_conn_rec;
|
||||
|
||||
static char buffer[] = "QS";
|
||||
|
||||
static uv_loop_t* loop;
|
||||
|
||||
static tcp_conn_rec tcp_conns[MAX_CONNS];
|
||||
static pipe_conn_rec pipe_conns[MAX_CONNS];
|
||||
|
||||
static uint64_t start; /* in ms */
|
||||
static int closed_streams;
|
||||
static int conns_failed;
|
||||
|
||||
static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
|
||||
static void connect_cb(uv_connect_t* conn_req, int status);
|
||||
static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
|
||||
static void close_cb(uv_handle_t* handle);
|
||||
|
||||
|
||||
static void alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
static char slab[65536];
|
||||
buf->base = slab;
|
||||
buf->len = sizeof(slab);
|
||||
}
|
||||
|
||||
|
||||
static void after_write(uv_write_t* req, int status) {
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "write error %s\n", uv_err_name(status));
|
||||
uv_close((uv_handle_t*)req->handle, close_cb);
|
||||
conns_failed++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
conn_rec* conn;
|
||||
uv_buf_t buf;
|
||||
int r;
|
||||
|
||||
if (status != 0) {
|
||||
#if DEBUG
|
||||
fprintf(stderr, "connect error %s\n", uv_err_name(status));
|
||||
#endif
|
||||
uv_close((uv_handle_t*)req->handle, close_cb);
|
||||
conns_failed++;
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(req != NULL);
|
||||
ASSERT(status == 0);
|
||||
|
||||
conn = (conn_rec*)req->data;
|
||||
ASSERT(conn != NULL);
|
||||
|
||||
#if DEBUG
|
||||
printf("connect_cb %d\n", conn->i);
|
||||
#endif
|
||||
|
||||
r = uv_read_start(&conn->stream, alloc_cb, read_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
buf.base = buffer;
|
||||
buf.len = sizeof(buffer) - 1;
|
||||
|
||||
r = uv_write(&conn->write_req, &conn->stream, &buf, 1, after_write);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
|
||||
|
||||
ASSERT(stream != NULL);
|
||||
|
||||
#if DEBUG
|
||||
printf("read_cb %d\n", p->i);
|
||||
#endif
|
||||
|
||||
uv_close((uv_handle_t*)stream, close_cb);
|
||||
|
||||
if (nread < 0) {
|
||||
if (nread == UV_EOF) {
|
||||
;
|
||||
} else if (nread == UV_ECONNRESET) {
|
||||
conns_failed++;
|
||||
} else {
|
||||
fprintf(stderr, "read error %s\n", uv_err_name(nread));
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
conn_rec* p = (conn_rec*)handle->data;
|
||||
|
||||
ASSERT(handle != NULL);
|
||||
closed_streams++;
|
||||
|
||||
#if DEBUG
|
||||
printf("close_cb %d\n", p->i);
|
||||
#endif
|
||||
|
||||
if (uv_now(loop) - start < 10000) {
|
||||
p->make_connect(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void tcp_do_setup(int num, void* arg) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
tcp_conns[i].i = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void pipe_do_setup(int num, void* arg) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
pipe_conns[i].i = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void tcp_make_connect(conn_rec* p) {
|
||||
struct sockaddr_in addr;
|
||||
tcp_conn_rec* tp;
|
||||
int r;
|
||||
|
||||
tp = (tcp_conn_rec*) p;
|
||||
|
||||
r = uv_tcp_init(loop, (uv_tcp_t*)&p->stream);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
r = uv_tcp_connect(&tp->conn_req,
|
||||
(uv_tcp_t*) &p->stream,
|
||||
(const struct sockaddr*) &addr,
|
||||
connect_cb);
|
||||
if (r) {
|
||||
fprintf(stderr, "uv_tcp_connect error %s\n", uv_err_name(r));
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
printf("make connect %d\n", p->i);
|
||||
#endif
|
||||
|
||||
p->conn_req.data = p;
|
||||
p->write_req.data = p;
|
||||
p->stream.data = p;
|
||||
}
|
||||
|
||||
|
||||
static void pipe_make_connect(conn_rec* p) {
|
||||
int r;
|
||||
|
||||
r = uv_pipe_init(loop, (uv_pipe_t*)&p->stream, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_pipe_connect(&((pipe_conn_rec*) p)->conn_req,
|
||||
(uv_pipe_t*) &p->stream,
|
||||
TEST_PIPENAME,
|
||||
connect_cb);
|
||||
|
||||
#if DEBUG
|
||||
printf("make connect %d\n", p->i);
|
||||
#endif
|
||||
|
||||
p->conn_req.data = p;
|
||||
p->write_req.data = p;
|
||||
p->stream.data = p;
|
||||
}
|
||||
|
||||
|
||||
static int tcp_do_connect(int num, make_connect_fn make_connect, void* arg) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
tcp_make_connect((conn_rec*)&tcp_conns[i]);
|
||||
tcp_conns[i].make_connect = make_connect;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int pipe_do_connect(int num, make_connect_fn make_connect, void* arg) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
pipe_make_connect((conn_rec*)&pipe_conns[i]);
|
||||
pipe_conns[i].make_connect = make_connect;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int pound_it(int concurrency,
|
||||
const char* type,
|
||||
setup_fn do_setup,
|
||||
connect_fn do_connect,
|
||||
make_connect_fn make_connect,
|
||||
void* arg) {
|
||||
double secs;
|
||||
int r;
|
||||
uint64_t start_time; /* in ns */
|
||||
uint64_t end_time;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
uv_update_time(loop);
|
||||
start = uv_now(loop);
|
||||
|
||||
/* Run benchmark for at least five seconds. */
|
||||
start_time = uv_hrtime();
|
||||
|
||||
do_setup(concurrency, arg);
|
||||
|
||||
r = do_connect(concurrency, make_connect, arg);
|
||||
ASSERT(!r);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
end_time = uv_hrtime();
|
||||
|
||||
/* Number of fractional seconds it took to run the benchmark. */
|
||||
secs = (double)(end_time - start_time) / NANOSEC;
|
||||
|
||||
fprintf(stderr, "%s-conn-pound-%d: %.0f accepts/s (%d failed)\n",
|
||||
type,
|
||||
concurrency,
|
||||
closed_streams / secs,
|
||||
conns_failed);
|
||||
fflush(stderr);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(tcp4_pound_100) {
|
||||
return pound_it(100,
|
||||
"tcp",
|
||||
tcp_do_setup,
|
||||
tcp_do_connect,
|
||||
tcp_make_connect,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(tcp4_pound_1000) {
|
||||
return pound_it(1000,
|
||||
"tcp",
|
||||
tcp_do_setup,
|
||||
tcp_do_connect,
|
||||
tcp_make_connect,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(pipe_pound_100) {
|
||||
return pound_it(100,
|
||||
"pipe",
|
||||
pipe_do_setup,
|
||||
pipe_do_connect,
|
||||
pipe_make_connect,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(pipe_pound_1000) {
|
||||
return pound_it(1000,
|
||||
"pipe",
|
||||
pipe_do_setup,
|
||||
pipe_do_connect,
|
||||
pipe_make_connect,
|
||||
NULL);
|
||||
}
|
||||
@@ -0,0 +1,476 @@
|
||||
/* 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 "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
static int TARGET_CONNECTIONS;
|
||||
#define WRITE_BUFFER_SIZE 8192
|
||||
#define MAX_SIMULTANEOUS_CONNECTS 100
|
||||
|
||||
#define PRINT_STATS 0
|
||||
#define STATS_INTERVAL 1000 /* msec */
|
||||
#define STATS_COUNT 5
|
||||
|
||||
|
||||
static void do_write(uv_stream_t*);
|
||||
static void maybe_connect_some();
|
||||
|
||||
static uv_req_t* req_alloc();
|
||||
static void req_free(uv_req_t* uv_req);
|
||||
|
||||
static void buf_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf);
|
||||
static void buf_free(const uv_buf_t* buf);
|
||||
|
||||
static uv_loop_t* loop;
|
||||
|
||||
static uv_tcp_t tcpServer;
|
||||
static uv_pipe_t pipeServer;
|
||||
static uv_stream_t* server;
|
||||
static struct sockaddr_in listen_addr;
|
||||
static struct sockaddr_in connect_addr;
|
||||
|
||||
static int64_t start_time;
|
||||
|
||||
static int max_connect_socket = 0;
|
||||
static int max_read_sockets = 0;
|
||||
static int read_sockets = 0;
|
||||
static int write_sockets = 0;
|
||||
|
||||
static int64_t nrecv = 0;
|
||||
static int64_t nrecv_total = 0;
|
||||
static int64_t nsent = 0;
|
||||
static int64_t nsent_total = 0;
|
||||
|
||||
static int stats_left = 0;
|
||||
|
||||
static char write_buffer[WRITE_BUFFER_SIZE];
|
||||
|
||||
/* Make this as large as you need. */
|
||||
#define MAX_WRITE_HANDLES 1000
|
||||
|
||||
static stream_type type;
|
||||
|
||||
static uv_tcp_t tcp_write_handles[MAX_WRITE_HANDLES];
|
||||
static uv_pipe_t pipe_write_handles[MAX_WRITE_HANDLES];
|
||||
|
||||
static uv_timer_t timer_handle;
|
||||
|
||||
|
||||
static double gbit(int64_t bytes, int64_t passed_ms) {
|
||||
double gbits = ((double)bytes / (1024 * 1024 * 1024)) * 8;
|
||||
return gbits / ((double)passed_ms / 1000);
|
||||
}
|
||||
|
||||
|
||||
static void show_stats(uv_timer_t* handle) {
|
||||
int64_t diff;
|
||||
int i;
|
||||
|
||||
#if PRINT_STATS
|
||||
fprintf(stderr, "connections: %d, write: %.1f gbit/s\n",
|
||||
write_sockets,
|
||||
gbit(nsent, STATS_INTERVAL));
|
||||
fflush(stderr);
|
||||
#endif
|
||||
|
||||
/* Exit if the show is over */
|
||||
if (!--stats_left) {
|
||||
|
||||
uv_update_time(loop);
|
||||
diff = uv_now(loop) - start_time;
|
||||
|
||||
fprintf(stderr, "%s_pump%d_client: %.1f gbit/s\n",
|
||||
type == TCP ? "tcp" : "pipe",
|
||||
write_sockets,
|
||||
gbit(nsent_total, diff));
|
||||
fflush(stderr);
|
||||
|
||||
for (i = 0; i < write_sockets; i++) {
|
||||
if (type == TCP)
|
||||
uv_close((uv_handle_t*) &tcp_write_handles[i], NULL);
|
||||
else
|
||||
uv_close((uv_handle_t*) &pipe_write_handles[i], NULL);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Reset read and write counters */
|
||||
nrecv = 0;
|
||||
nsent = 0;
|
||||
}
|
||||
|
||||
|
||||
static void read_show_stats(void) {
|
||||
int64_t diff;
|
||||
|
||||
uv_update_time(loop);
|
||||
diff = uv_now(loop) - start_time;
|
||||
|
||||
fprintf(stderr, "%s_pump%d_server: %.1f gbit/s\n",
|
||||
type == TCP ? "tcp" : "pipe",
|
||||
max_read_sockets,
|
||||
gbit(nrecv_total, diff));
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void read_sockets_close_cb(uv_handle_t* handle) {
|
||||
free(handle);
|
||||
read_sockets--;
|
||||
|
||||
/* If it's past the first second and everyone has closed their connection
|
||||
* Then print stats.
|
||||
*/
|
||||
if (uv_now(loop) - start_time > 1000 && read_sockets == 0) {
|
||||
read_show_stats();
|
||||
uv_close((uv_handle_t*)server, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void start_stats_collection(void) {
|
||||
int r;
|
||||
|
||||
/* Show-stats timer */
|
||||
stats_left = STATS_COUNT;
|
||||
r = uv_timer_init(loop, &timer_handle);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_start(&timer_handle, show_stats, STATS_INTERVAL, STATS_INTERVAL);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_update_time(loop);
|
||||
start_time = uv_now(loop);
|
||||
}
|
||||
|
||||
|
||||
static void read_cb(uv_stream_t* stream, ssize_t bytes, const uv_buf_t* buf) {
|
||||
if (nrecv_total == 0) {
|
||||
ASSERT(start_time == 0);
|
||||
uv_update_time(loop);
|
||||
start_time = uv_now(loop);
|
||||
}
|
||||
|
||||
if (bytes < 0) {
|
||||
uv_close((uv_handle_t*)stream, read_sockets_close_cb);
|
||||
return;
|
||||
}
|
||||
|
||||
buf_free(buf);
|
||||
|
||||
nrecv += bytes;
|
||||
nrecv_total += bytes;
|
||||
}
|
||||
|
||||
|
||||
static void write_cb(uv_write_t* req, int status) {
|
||||
ASSERT(status == 0);
|
||||
|
||||
req_free((uv_req_t*) req);
|
||||
|
||||
nsent += sizeof write_buffer;
|
||||
nsent_total += sizeof write_buffer;
|
||||
|
||||
do_write((uv_stream_t*) req->handle);
|
||||
}
|
||||
|
||||
|
||||
static void do_write(uv_stream_t* stream) {
|
||||
uv_write_t* req;
|
||||
uv_buf_t buf;
|
||||
int r;
|
||||
|
||||
buf.base = (char*) &write_buffer;
|
||||
buf.len = sizeof write_buffer;
|
||||
|
||||
req = (uv_write_t*) req_alloc();
|
||||
r = uv_write(req, stream, &buf, 1, write_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
int i;
|
||||
|
||||
if (status) {
|
||||
fprintf(stderr, "%s", uv_strerror(status));
|
||||
fflush(stderr);
|
||||
}
|
||||
ASSERT(status == 0);
|
||||
|
||||
write_sockets++;
|
||||
req_free((uv_req_t*) req);
|
||||
|
||||
maybe_connect_some();
|
||||
|
||||
if (write_sockets == TARGET_CONNECTIONS) {
|
||||
start_stats_collection();
|
||||
|
||||
/* Yay! start writing */
|
||||
for (i = 0; i < write_sockets; i++) {
|
||||
if (type == TCP)
|
||||
do_write((uv_stream_t*) &tcp_write_handles[i]);
|
||||
else
|
||||
do_write((uv_stream_t*) &pipe_write_handles[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void maybe_connect_some(void) {
|
||||
uv_connect_t* req;
|
||||
uv_tcp_t* tcp;
|
||||
uv_pipe_t* pipe;
|
||||
int r;
|
||||
|
||||
while (max_connect_socket < TARGET_CONNECTIONS &&
|
||||
max_connect_socket < write_sockets + MAX_SIMULTANEOUS_CONNECTS) {
|
||||
if (type == TCP) {
|
||||
tcp = &tcp_write_handles[max_connect_socket++];
|
||||
|
||||
r = uv_tcp_init(loop, tcp);
|
||||
ASSERT(r == 0);
|
||||
|
||||
req = (uv_connect_t*) req_alloc();
|
||||
r = uv_tcp_connect(req,
|
||||
tcp,
|
||||
(const struct sockaddr*) &connect_addr,
|
||||
connect_cb);
|
||||
ASSERT(r == 0);
|
||||
} else {
|
||||
pipe = &pipe_write_handles[max_connect_socket++];
|
||||
|
||||
r = uv_pipe_init(loop, pipe, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
req = (uv_connect_t*) req_alloc();
|
||||
uv_pipe_connect(req, pipe, TEST_PIPENAME, connect_cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void connection_cb(uv_stream_t* s, int status) {
|
||||
uv_stream_t* stream;
|
||||
int r;
|
||||
|
||||
ASSERT(server == s);
|
||||
ASSERT(status == 0);
|
||||
|
||||
if (type == TCP) {
|
||||
stream = (uv_stream_t*)malloc(sizeof(uv_tcp_t));
|
||||
r = uv_tcp_init(loop, (uv_tcp_t*)stream);
|
||||
ASSERT(r == 0);
|
||||
} else {
|
||||
stream = (uv_stream_t*)malloc(sizeof(uv_pipe_t));
|
||||
r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
r = uv_accept(s, stream);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_read_start(stream, buf_alloc, read_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
read_sockets++;
|
||||
max_read_sockets++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Request allocator
|
||||
*/
|
||||
|
||||
typedef struct req_list_s {
|
||||
union uv_any_req uv_req;
|
||||
struct req_list_s* next;
|
||||
} req_list_t;
|
||||
|
||||
|
||||
static req_list_t* req_freelist = NULL;
|
||||
|
||||
|
||||
static uv_req_t* req_alloc(void) {
|
||||
req_list_t* req;
|
||||
|
||||
req = req_freelist;
|
||||
if (req != NULL) {
|
||||
req_freelist = req->next;
|
||||
return (uv_req_t*) req;
|
||||
}
|
||||
|
||||
req = (req_list_t*) malloc(sizeof *req);
|
||||
return (uv_req_t*) req;
|
||||
}
|
||||
|
||||
|
||||
static void req_free(uv_req_t* uv_req) {
|
||||
req_list_t* req = (req_list_t*) uv_req;
|
||||
|
||||
req->next = req_freelist;
|
||||
req_freelist = req;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Buffer allocator
|
||||
*/
|
||||
|
||||
typedef struct buf_list_s {
|
||||
uv_buf_t uv_buf_t;
|
||||
struct buf_list_s* next;
|
||||
} buf_list_t;
|
||||
|
||||
|
||||
static buf_list_t* buf_freelist = NULL;
|
||||
|
||||
|
||||
static void buf_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
|
||||
buf_list_t* ab;
|
||||
|
||||
ab = buf_freelist;
|
||||
if (ab != NULL)
|
||||
buf_freelist = ab->next;
|
||||
else {
|
||||
ab = malloc(size + sizeof(*ab));
|
||||
ab->uv_buf_t.len = size;
|
||||
ab->uv_buf_t.base = (char*) (ab + 1);
|
||||
}
|
||||
|
||||
*buf = ab->uv_buf_t;
|
||||
}
|
||||
|
||||
|
||||
static void buf_free(const uv_buf_t* buf) {
|
||||
buf_list_t* ab = (buf_list_t*) buf->base - 1;
|
||||
ab->next = buf_freelist;
|
||||
buf_freelist = ab;
|
||||
}
|
||||
|
||||
|
||||
HELPER_IMPL(tcp_pump_server) {
|
||||
int r;
|
||||
|
||||
type = TCP;
|
||||
loop = uv_default_loop();
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &listen_addr));
|
||||
|
||||
/* Server */
|
||||
server = (uv_stream_t*)&tcpServer;
|
||||
r = uv_tcp_init(loop, &tcpServer);
|
||||
ASSERT(r == 0);
|
||||
r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &listen_addr, 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_listen((uv_stream_t*)&tcpServer, MAX_WRITE_HANDLES, connection_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
HELPER_IMPL(pipe_pump_server) {
|
||||
int r;
|
||||
type = PIPE;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
/* Server */
|
||||
server = (uv_stream_t*)&pipeServer;
|
||||
r = uv_pipe_init(loop, &pipeServer, 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_pipe_bind(&pipeServer, TEST_PIPENAME);
|
||||
ASSERT(r == 0);
|
||||
r = uv_listen((uv_stream_t*)&pipeServer, MAX_WRITE_HANDLES, connection_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void tcp_pump(int n) {
|
||||
ASSERT(n <= MAX_WRITE_HANDLES);
|
||||
TARGET_CONNECTIONS = n;
|
||||
type = TCP;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &connect_addr));
|
||||
|
||||
/* Start making connections */
|
||||
maybe_connect_some();
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
}
|
||||
|
||||
|
||||
static void pipe_pump(int n) {
|
||||
ASSERT(n <= MAX_WRITE_HANDLES);
|
||||
TARGET_CONNECTIONS = n;
|
||||
type = PIPE;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
/* Start making connections */
|
||||
maybe_connect_some();
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(tcp_pump100_client) {
|
||||
tcp_pump(100);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(tcp_pump1_client) {
|
||||
tcp_pump(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(pipe_pump100_client) {
|
||||
pipe_pump(100);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(pipe_pump1_client) {
|
||||
pipe_pump(1);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* 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 "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
|
||||
BENCHMARK_IMPL(sizes) {
|
||||
fprintf(stderr, "uv_shutdown_t: %u bytes\n", (unsigned int) sizeof(uv_shutdown_t));
|
||||
fprintf(stderr, "uv_write_t: %u bytes\n", (unsigned int) sizeof(uv_write_t));
|
||||
fprintf(stderr, "uv_connect_t: %u bytes\n", (unsigned int) sizeof(uv_connect_t));
|
||||
fprintf(stderr, "uv_udp_send_t: %u bytes\n", (unsigned int) sizeof(uv_udp_send_t));
|
||||
fprintf(stderr, "uv_tcp_t: %u bytes\n", (unsigned int) sizeof(uv_tcp_t));
|
||||
fprintf(stderr, "uv_pipe_t: %u bytes\n", (unsigned int) sizeof(uv_pipe_t));
|
||||
fprintf(stderr, "uv_tty_t: %u bytes\n", (unsigned int) sizeof(uv_tty_t));
|
||||
fprintf(stderr, "uv_prepare_t: %u bytes\n", (unsigned int) sizeof(uv_prepare_t));
|
||||
fprintf(stderr, "uv_check_t: %u bytes\n", (unsigned int) sizeof(uv_check_t));
|
||||
fprintf(stderr, "uv_idle_t: %u bytes\n", (unsigned int) sizeof(uv_idle_t));
|
||||
fprintf(stderr, "uv_async_t: %u bytes\n", (unsigned int) sizeof(uv_async_t));
|
||||
fprintf(stderr, "uv_timer_t: %u bytes\n", (unsigned int) sizeof(uv_timer_t));
|
||||
fprintf(stderr, "uv_fs_poll_t: %u bytes\n", (unsigned int) sizeof(uv_fs_poll_t));
|
||||
fprintf(stderr, "uv_fs_event_t: %u bytes\n", (unsigned int) sizeof(uv_fs_event_t));
|
||||
fprintf(stderr, "uv_process_t: %u bytes\n", (unsigned int) sizeof(uv_process_t));
|
||||
fprintf(stderr, "uv_poll_t: %u bytes\n", (unsigned int) sizeof(uv_poll_t));
|
||||
fprintf(stderr, "uv_loop_t: %u bytes\n", (unsigned int) sizeof(uv_loop_t));
|
||||
fflush(stderr);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/* 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 benchmark spawns itself 1000 times. */
|
||||
|
||||
#include "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
static uv_loop_t* loop;
|
||||
|
||||
static int N = 1000;
|
||||
static int done;
|
||||
|
||||
static uv_process_t process;
|
||||
static uv_process_options_t options;
|
||||
static char exepath[1024];
|
||||
static size_t exepath_size = 1024;
|
||||
static char* args[3];
|
||||
static uv_pipe_t out;
|
||||
|
||||
#define OUTPUT_SIZE 1024
|
||||
static char output[OUTPUT_SIZE];
|
||||
static int output_used;
|
||||
|
||||
static int process_open;
|
||||
static int pipe_open;
|
||||
|
||||
|
||||
static void spawn(void);
|
||||
|
||||
|
||||
static void maybe_spawn(void) {
|
||||
if (process_open == 0 && pipe_open == 0) {
|
||||
done++;
|
||||
if (done < N) {
|
||||
spawn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void process_close_cb(uv_handle_t* handle) {
|
||||
ASSERT(process_open == 1);
|
||||
process_open = 0;
|
||||
maybe_spawn();
|
||||
}
|
||||
|
||||
|
||||
static void exit_cb(uv_process_t* process,
|
||||
int64_t exit_status,
|
||||
int term_signal) {
|
||||
ASSERT(exit_status == 42);
|
||||
ASSERT(term_signal == 0);
|
||||
uv_close((uv_handle_t*)process, process_close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void on_alloc(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
buf->base = output + output_used;
|
||||
buf->len = OUTPUT_SIZE - output_used;
|
||||
}
|
||||
|
||||
|
||||
static void pipe_close_cb(uv_handle_t* pipe) {
|
||||
ASSERT(pipe_open == 1);
|
||||
pipe_open = 0;
|
||||
maybe_spawn();
|
||||
}
|
||||
|
||||
|
||||
static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) {
|
||||
if (nread > 0) {
|
||||
ASSERT(pipe_open == 1);
|
||||
output_used += nread;
|
||||
} else if (nread < 0) {
|
||||
if (nread == UV_EOF) {
|
||||
uv_close((uv_handle_t*)pipe, pipe_close_cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void spawn(void) {
|
||||
uv_stdio_container_t stdio[2];
|
||||
int r;
|
||||
|
||||
ASSERT(process_open == 0);
|
||||
ASSERT(pipe_open == 0);
|
||||
|
||||
args[0] = exepath;
|
||||
args[1] = "spawn_helper";
|
||||
args[2] = NULL;
|
||||
options.file = exepath;
|
||||
options.args = args;
|
||||
options.exit_cb = exit_cb;
|
||||
|
||||
uv_pipe_init(loop, &out, 0);
|
||||
|
||||
options.stdio = stdio;
|
||||
options.stdio_count = 2;
|
||||
options.stdio[0].flags = UV_IGNORE;
|
||||
options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
|
||||
options.stdio[1].data.stream = (uv_stream_t*)&out;
|
||||
|
||||
r = uv_spawn(loop, &process, &options);
|
||||
ASSERT(r == 0);
|
||||
|
||||
process_open = 1;
|
||||
pipe_open = 1;
|
||||
output_used = 0;
|
||||
|
||||
r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(spawn) {
|
||||
int r;
|
||||
static int64_t start_time, end_time;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
r = uv_exepath(exepath, &exepath_size);
|
||||
ASSERT(r == 0);
|
||||
exepath[exepath_size] = '\0';
|
||||
|
||||
uv_update_time(loop);
|
||||
start_time = uv_now(loop);
|
||||
|
||||
spawn();
|
||||
|
||||
r = uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_update_time(loop);
|
||||
end_time = uv_now(loop);
|
||||
|
||||
fprintf(stderr, "spawn: %.0f spawns/s\n",
|
||||
(double) N / (double) (end_time - start_time) * 1000.0);
|
||||
fflush(stderr);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/* 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>
|
||||
|
||||
#define WRITE_REQ_DATA "Hello, world."
|
||||
#define NUM_WRITE_REQS (1000 * 1000)
|
||||
|
||||
typedef struct {
|
||||
uv_write_t req;
|
||||
uv_buf_t buf;
|
||||
} write_req;
|
||||
|
||||
|
||||
static write_req* write_reqs;
|
||||
static uv_tcp_t tcp_client;
|
||||
static uv_connect_t connect_req;
|
||||
static uv_shutdown_t shutdown_req;
|
||||
|
||||
static int shutdown_cb_called = 0;
|
||||
static int connect_cb_called = 0;
|
||||
static int write_cb_called = 0;
|
||||
static int close_cb_called = 0;
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status);
|
||||
static void write_cb(uv_write_t* req, int status);
|
||||
static void shutdown_cb(uv_shutdown_t* req, int status);
|
||||
static void close_cb(uv_handle_t* handle);
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
write_req* w;
|
||||
int i;
|
||||
int r;
|
||||
|
||||
ASSERT(req->handle == (uv_stream_t*)&tcp_client);
|
||||
|
||||
for (i = 0; i < NUM_WRITE_REQS; i++) {
|
||||
w = &write_reqs[i];
|
||||
r = uv_write(&w->req, req->handle, &w->buf, 1, write_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
connect_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void write_cb(uv_write_t* req, int status) {
|
||||
ASSERT(req != NULL);
|
||||
ASSERT(status == 0);
|
||||
write_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void shutdown_cb(uv_shutdown_t* req, int status) {
|
||||
ASSERT(req->handle == (uv_stream_t*)&tcp_client);
|
||||
ASSERT(req->handle->write_queue_size == 0);
|
||||
|
||||
uv_close((uv_handle_t*)req->handle, close_cb);
|
||||
free(write_reqs);
|
||||
|
||||
shutdown_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle == (uv_handle_t*)&tcp_client);
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(tcp_write_batch) {
|
||||
struct sockaddr_in addr;
|
||||
uv_loop_t* loop;
|
||||
uint64_t start;
|
||||
uint64_t stop;
|
||||
int i;
|
||||
int r;
|
||||
|
||||
write_reqs = malloc(sizeof(*write_reqs) * NUM_WRITE_REQS);
|
||||
ASSERT(write_reqs != NULL);
|
||||
|
||||
/* Prepare the data to write out. */
|
||||
for (i = 0; i < NUM_WRITE_REQS; i++) {
|
||||
write_reqs[i].buf = uv_buf_init(WRITE_REQ_DATA,
|
||||
sizeof(WRITE_REQ_DATA) - 1);
|
||||
}
|
||||
|
||||
loop = uv_default_loop();
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
r = uv_tcp_init(loop, &tcp_client);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_connect(&connect_req,
|
||||
&tcp_client,
|
||||
(const struct sockaddr*) &addr,
|
||||
connect_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
start = uv_hrtime();
|
||||
|
||||
r = uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
stop = uv_hrtime();
|
||||
|
||||
ASSERT(connect_cb_called == 1);
|
||||
ASSERT(write_cb_called == NUM_WRITE_REQS);
|
||||
ASSERT(shutdown_cb_called == 1);
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
printf("%ld write requests in %.2fs.\n",
|
||||
(long)NUM_WRITE_REQS,
|
||||
(stop - start) / 1e9);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/* 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>
|
||||
|
||||
#define NUM_THREADS (20 * 1000)
|
||||
|
||||
static volatile int num_threads;
|
||||
|
||||
|
||||
static void thread_entry(void* arg) {
|
||||
ASSERT(arg == (void *) 42);
|
||||
num_threads++;
|
||||
/* FIXME write barrier? */
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_IMPL(thread_create) {
|
||||
uint64_t start_time;
|
||||
double duration;
|
||||
uv_thread_t tid;
|
||||
int i, r;
|
||||
|
||||
start_time = uv_hrtime();
|
||||
|
||||
for (i = 0; i < NUM_THREADS; i++) {
|
||||
r = uv_thread_create(&tid, thread_entry, (void *) 42);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_thread_join(&tid);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
duration = (uv_hrtime() - start_time) / 1e9;
|
||||
|
||||
ASSERT(num_threads == NUM_THREADS);
|
||||
|
||||
printf("%d threads created in %.2f seconds (%.0f/s)\n",
|
||||
NUM_THREADS, duration, NUM_THREADS / duration);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/* 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 "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define EXPECTED "RANG TANG DING DONG I AM THE JAPANESE SANDMAN"
|
||||
|
||||
#define TEST_DURATION 5000 /* ms */
|
||||
|
||||
#define BASE_PORT 12345
|
||||
|
||||
struct sender_state {
|
||||
struct sockaddr_in addr;
|
||||
uv_udp_send_t send_req;
|
||||
uv_udp_t udp_handle;
|
||||
};
|
||||
|
||||
struct receiver_state {
|
||||
struct sockaddr_in addr;
|
||||
uv_udp_t udp_handle;
|
||||
};
|
||||
|
||||
/* not used in timed mode */
|
||||
static unsigned int packet_counter = (unsigned int) 1e6;
|
||||
|
||||
static int n_senders_;
|
||||
static int n_receivers_;
|
||||
static uv_buf_t bufs[5];
|
||||
static struct sender_state senders[1024];
|
||||
static struct receiver_state receivers[1024];
|
||||
|
||||
static unsigned int send_cb_called;
|
||||
static unsigned int recv_cb_called;
|
||||
static unsigned int close_cb_called;
|
||||
static int timed;
|
||||
static int exiting;
|
||||
|
||||
|
||||
static void alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
static char slab[65536];
|
||||
ASSERT(suggested_size <= sizeof(slab));
|
||||
buf->base = slab;
|
||||
buf->len = sizeof(slab);
|
||||
}
|
||||
|
||||
|
||||
static void send_cb(uv_udp_send_t* req, int status) {
|
||||
struct sender_state* s;
|
||||
|
||||
ASSERT(req != NULL);
|
||||
|
||||
if (status != 0) {
|
||||
ASSERT(status == UV_ECANCELED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (exiting)
|
||||
return;
|
||||
|
||||
s = container_of(req, struct sender_state, send_req);
|
||||
ASSERT(req->handle == &s->udp_handle);
|
||||
|
||||
if (timed)
|
||||
goto send;
|
||||
|
||||
if (packet_counter == 0) {
|
||||
uv_close((uv_handle_t*)&s->udp_handle, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
packet_counter--;
|
||||
|
||||
send:
|
||||
ASSERT(0 == uv_udp_send(&s->send_req,
|
||||
&s->udp_handle,
|
||||
bufs,
|
||||
ARRAY_SIZE(bufs),
|
||||
(const struct sockaddr*) &s->addr,
|
||||
send_cb));
|
||||
send_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void recv_cb(uv_udp_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf,
|
||||
const struct sockaddr* addr,
|
||||
unsigned flags) {
|
||||
if (nread == 0)
|
||||
return;
|
||||
|
||||
if (nread < 0) {
|
||||
ASSERT(nread == UV_ECANCELED);
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(addr->sa_family == AF_INET);
|
||||
ASSERT(!memcmp(buf->base, EXPECTED, nread));
|
||||
|
||||
recv_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle != NULL);
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void timeout_cb(uv_timer_t* timer) {
|
||||
int i;
|
||||
|
||||
exiting = 1;
|
||||
|
||||
for (i = 0; i < n_senders_; i++)
|
||||
uv_close((uv_handle_t*)&senders[i].udp_handle, close_cb);
|
||||
|
||||
for (i = 0; i < n_receivers_; i++)
|
||||
uv_close((uv_handle_t*)&receivers[i].udp_handle, close_cb);
|
||||
}
|
||||
|
||||
|
||||
static int pummel(unsigned int n_senders,
|
||||
unsigned int n_receivers,
|
||||
unsigned long timeout) {
|
||||
uv_timer_t timer_handle;
|
||||
uint64_t duration;
|
||||
uv_loop_t* loop;
|
||||
unsigned int i;
|
||||
|
||||
ASSERT(n_senders <= ARRAY_SIZE(senders));
|
||||
ASSERT(n_receivers <= ARRAY_SIZE(receivers));
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
n_senders_ = n_senders;
|
||||
n_receivers_ = n_receivers;
|
||||
|
||||
if (timeout) {
|
||||
ASSERT(0 == uv_timer_init(loop, &timer_handle));
|
||||
ASSERT(0 == uv_timer_start(&timer_handle, timeout_cb, timeout, 0));
|
||||
/* Timer should not keep loop alive. */
|
||||
uv_unref((uv_handle_t*)&timer_handle);
|
||||
timed = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_receivers; i++) {
|
||||
struct receiver_state* s = receivers + i;
|
||||
struct sockaddr_in addr;
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", BASE_PORT + i, &addr));
|
||||
ASSERT(0 == uv_udp_init(loop, &s->udp_handle));
|
||||
ASSERT(0 == uv_udp_bind(&s->udp_handle, (const struct sockaddr*) &addr, 0));
|
||||
ASSERT(0 == uv_udp_recv_start(&s->udp_handle, alloc_cb, recv_cb));
|
||||
uv_unref((uv_handle_t*)&s->udp_handle);
|
||||
}
|
||||
|
||||
bufs[0] = uv_buf_init(EXPECTED + 0, 10);
|
||||
bufs[1] = uv_buf_init(EXPECTED + 10, 10);
|
||||
bufs[2] = uv_buf_init(EXPECTED + 20, 10);
|
||||
bufs[3] = uv_buf_init(EXPECTED + 30, 10);
|
||||
bufs[4] = uv_buf_init(EXPECTED + 40, 5);
|
||||
|
||||
for (i = 0; i < n_senders; i++) {
|
||||
struct sender_state* s = senders + i;
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1",
|
||||
BASE_PORT + (i % n_receivers),
|
||||
&s->addr));
|
||||
ASSERT(0 == uv_udp_init(loop, &s->udp_handle));
|
||||
ASSERT(0 == uv_udp_send(&s->send_req,
|
||||
&s->udp_handle,
|
||||
bufs,
|
||||
ARRAY_SIZE(bufs),
|
||||
(const struct sockaddr*) &s->addr,
|
||||
send_cb));
|
||||
}
|
||||
|
||||
duration = uv_hrtime();
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
duration = uv_hrtime() - duration;
|
||||
/* convert from nanoseconds to milliseconds */
|
||||
duration = duration / (uint64_t) 1e6;
|
||||
|
||||
printf("udp_pummel_%dv%d: %.0f/s received, %.0f/s sent. "
|
||||
"%u received, %u sent in %.1f seconds.\n",
|
||||
n_receivers,
|
||||
n_senders,
|
||||
recv_cb_called / (duration / 1000.0),
|
||||
send_cb_called / (duration / 1000.0),
|
||||
recv_cb_called,
|
||||
send_cb_called,
|
||||
duration / 1000.0);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define X(a, b) \
|
||||
BENCHMARK_IMPL(udp_pummel_##a##v##b) { \
|
||||
return pummel(a, b, 0); \
|
||||
} \
|
||||
BENCHMARK_IMPL(udp_timed_pummel_##a##v##b) { \
|
||||
return pummel(a, b, TEST_DURATION); \
|
||||
}
|
||||
|
||||
X(1, 1)
|
||||
X(1, 10)
|
||||
X(1, 100)
|
||||
X(1, 1000)
|
||||
X(10, 10)
|
||||
X(10, 100)
|
||||
X(10, 1000)
|
||||
X(100, 10)
|
||||
X(100, 100)
|
||||
X(100, 1000)
|
||||
X(1000, 1000)
|
||||
|
||||
#undef X
|
||||
@@ -0,0 +1,121 @@
|
||||
/* 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>
|
||||
|
||||
typedef struct {
|
||||
uv_tcp_t handle;
|
||||
uv_shutdown_t shutdown_req;
|
||||
} conn_rec;
|
||||
|
||||
static uv_tcp_t tcp_server;
|
||||
|
||||
static void connection_cb(uv_stream_t* stream, int status);
|
||||
static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
|
||||
static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
|
||||
static void shutdown_cb(uv_shutdown_t* req, int status);
|
||||
static void close_cb(uv_handle_t* handle);
|
||||
|
||||
|
||||
static void connection_cb(uv_stream_t* stream, int status) {
|
||||
conn_rec* conn;
|
||||
int r;
|
||||
|
||||
ASSERT(status == 0);
|
||||
ASSERT(stream == (uv_stream_t*)&tcp_server);
|
||||
|
||||
conn = malloc(sizeof *conn);
|
||||
ASSERT(conn != NULL);
|
||||
|
||||
r = uv_tcp_init(stream->loop, &conn->handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept(stream, (uv_stream_t*)&conn->handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_read_start((uv_stream_t*)&conn->handle, alloc_cb, read_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
static char slab[65536];
|
||||
buf->base = slab;
|
||||
buf->len = sizeof(slab);
|
||||
}
|
||||
|
||||
|
||||
static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
|
||||
conn_rec* conn;
|
||||
int r;
|
||||
|
||||
if (nread >= 0)
|
||||
return;
|
||||
|
||||
ASSERT(nread == UV_EOF);
|
||||
|
||||
conn = container_of(stream, conn_rec, handle);
|
||||
|
||||
r = uv_shutdown(&conn->shutdown_req, stream, shutdown_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void shutdown_cb(uv_shutdown_t* req, int status) {
|
||||
conn_rec* conn = container_of(req, conn_rec, shutdown_req);
|
||||
uv_close((uv_handle_t*)&conn->handle, close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
conn_rec* conn = container_of(handle, conn_rec, handle);
|
||||
free(conn);
|
||||
}
|
||||
|
||||
|
||||
HELPER_IMPL(tcp4_blackhole_server) {
|
||||
struct sockaddr_in addr;
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
r = uv_tcp_init(loop, &tcp_server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&tcp_server, 128, connection_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(0 && "Blackhole server dropped out of event loop.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
/* 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>
|
||||
|
||||
|
||||
typedef struct {
|
||||
uv_write_t req;
|
||||
uv_buf_t buf;
|
||||
} write_req_t;
|
||||
|
||||
|
||||
/* used to track multiple DNS requests received */
|
||||
typedef struct {
|
||||
char* prevbuf_ptr;
|
||||
int prevbuf_pos;
|
||||
int prevbuf_rem;
|
||||
} dnsstate;
|
||||
|
||||
|
||||
/* modify handle to append dnsstate */
|
||||
typedef struct {
|
||||
uv_tcp_t handle;
|
||||
dnsstate state;
|
||||
} dnshandle;
|
||||
|
||||
|
||||
static uv_loop_t* loop;
|
||||
|
||||
|
||||
static uv_tcp_t server;
|
||||
|
||||
|
||||
static void after_write(uv_write_t* req, int status);
|
||||
static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf);
|
||||
static void on_close(uv_handle_t* peer);
|
||||
static void on_connection(uv_stream_t*, int status);
|
||||
|
||||
#define WRITE_BUF_LEN (64*1024)
|
||||
#define DNSREC_LEN (4)
|
||||
|
||||
#define LEN_OFFSET 0
|
||||
#define QUERYID_OFFSET 2
|
||||
|
||||
static unsigned char DNSRsp[] = {
|
||||
0, 43, 0, 0, 0x81, 0x80, 0, 1, 0, 1, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static unsigned char qrecord[] = {
|
||||
5, 'e', 'c', 'h', 'o', 's', 3, 's', 'r', 'v', 0, 0, 1, 0, 1
|
||||
};
|
||||
|
||||
static unsigned char arecord[] = {
|
||||
0xc0, 0x0c, 0, 1, 0, 1, 0, 0, 5, 0xbd, 0, 4, 10, 0, 1, 1
|
||||
};
|
||||
|
||||
|
||||
static void after_write(uv_write_t* req, int status) {
|
||||
write_req_t* wr;
|
||||
|
||||
if (status) {
|
||||
fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
wr = (write_req_t*) req;
|
||||
|
||||
/* Free the read/write buffer and the request */
|
||||
free(wr->buf.base);
|
||||
free(wr);
|
||||
}
|
||||
|
||||
|
||||
static void after_shutdown(uv_shutdown_t* req, int status) {
|
||||
uv_close((uv_handle_t*) req->handle, on_close);
|
||||
free(req);
|
||||
}
|
||||
|
||||
|
||||
static void addrsp(write_req_t* wr, char* hdr) {
|
||||
char * dnsrsp;
|
||||
short int rsplen;
|
||||
short int* reclen;
|
||||
|
||||
rsplen = sizeof(DNSRsp) + sizeof(qrecord) + sizeof(arecord);
|
||||
|
||||
ASSERT (rsplen + wr->buf.len < WRITE_BUF_LEN);
|
||||
|
||||
dnsrsp = wr->buf.base + wr->buf.len;
|
||||
|
||||
/* copy stock response */
|
||||
memcpy(dnsrsp, DNSRsp, sizeof(DNSRsp));
|
||||
memcpy(dnsrsp + sizeof(DNSRsp), qrecord, sizeof(qrecord));
|
||||
memcpy(dnsrsp + sizeof(DNSRsp) + sizeof(qrecord), arecord, sizeof(arecord));
|
||||
|
||||
/* overwrite with network order length and id from request header */
|
||||
reclen = (short int*)dnsrsp;
|
||||
*reclen = htons(rsplen-2);
|
||||
dnsrsp[QUERYID_OFFSET] = hdr[QUERYID_OFFSET];
|
||||
dnsrsp[QUERYID_OFFSET+1] = hdr[QUERYID_OFFSET+1];
|
||||
|
||||
wr->buf.len += rsplen;
|
||||
}
|
||||
|
||||
static void process_req(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
write_req_t* wr;
|
||||
dnshandle* dns = (dnshandle*)handle;
|
||||
char hdrbuf[DNSREC_LEN];
|
||||
int hdrbuf_remaining = DNSREC_LEN;
|
||||
int rec_remaining = 0;
|
||||
int readbuf_remaining;
|
||||
char* dnsreq;
|
||||
char* hdrstart;
|
||||
int usingprev = 0;
|
||||
|
||||
wr = (write_req_t*) malloc(sizeof *wr);
|
||||
wr->buf.base = (char*)malloc(WRITE_BUF_LEN);
|
||||
wr->buf.len = 0;
|
||||
|
||||
if (dns->state.prevbuf_ptr != NULL) {
|
||||
dnsreq = dns->state.prevbuf_ptr + dns->state.prevbuf_pos;
|
||||
readbuf_remaining = dns->state.prevbuf_rem;
|
||||
usingprev = 1;
|
||||
} else {
|
||||
dnsreq = buf->base;
|
||||
readbuf_remaining = nread;
|
||||
}
|
||||
hdrstart = dnsreq;
|
||||
|
||||
while (dnsreq != NULL) {
|
||||
/* something to process */
|
||||
while (readbuf_remaining > 0) {
|
||||
/* something to process in current buffer */
|
||||
if (hdrbuf_remaining > 0) {
|
||||
/* process len and id */
|
||||
if (readbuf_remaining < hdrbuf_remaining) {
|
||||
/* too little to get request header. save for next buffer */
|
||||
memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining],
|
||||
dnsreq,
|
||||
readbuf_remaining);
|
||||
hdrbuf_remaining = DNSREC_LEN - readbuf_remaining;
|
||||
break;
|
||||
} else {
|
||||
/* save header */
|
||||
memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining],
|
||||
dnsreq,
|
||||
hdrbuf_remaining);
|
||||
dnsreq += hdrbuf_remaining;
|
||||
readbuf_remaining -= hdrbuf_remaining;
|
||||
hdrbuf_remaining = 0;
|
||||
|
||||
/* get record length */
|
||||
rec_remaining = (unsigned) hdrbuf[0] * 256 + (unsigned) hdrbuf[1];
|
||||
rec_remaining -= (DNSREC_LEN - 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (rec_remaining <= readbuf_remaining) {
|
||||
/* prepare reply */
|
||||
addrsp(wr, hdrbuf);
|
||||
|
||||
/* move to next record */
|
||||
dnsreq += rec_remaining;
|
||||
hdrstart = dnsreq;
|
||||
readbuf_remaining -= rec_remaining;
|
||||
rec_remaining = 0;
|
||||
hdrbuf_remaining = DNSREC_LEN;
|
||||
} else {
|
||||
/* otherwise this buffer is done. */
|
||||
rec_remaining -= readbuf_remaining;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we had to use bytes from prev buffer, start processing the current
|
||||
* one.
|
||||
*/
|
||||
if (usingprev == 1) {
|
||||
/* free previous buffer */
|
||||
free(dns->state.prevbuf_ptr);
|
||||
dnsreq = buf->base;
|
||||
readbuf_remaining = nread;
|
||||
usingprev = 0;
|
||||
} else {
|
||||
dnsreq = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* send write buffer */
|
||||
if (wr->buf.len > 0) {
|
||||
if (uv_write((uv_write_t*) &wr->req, handle, &wr->buf, 1, after_write)) {
|
||||
FATAL("uv_write failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (readbuf_remaining > 0) {
|
||||
/* save start of record position, so we can continue on next read */
|
||||
dns->state.prevbuf_ptr = buf->base;
|
||||
dns->state.prevbuf_pos = hdrstart - buf->base;
|
||||
dns->state.prevbuf_rem = nread - dns->state.prevbuf_pos;
|
||||
} else {
|
||||
/* nothing left in this buffer */
|
||||
dns->state.prevbuf_ptr = NULL;
|
||||
dns->state.prevbuf_pos = 0;
|
||||
dns->state.prevbuf_rem = 0;
|
||||
free(buf->base);
|
||||
}
|
||||
}
|
||||
|
||||
static void after_read(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
uv_shutdown_t* req;
|
||||
|
||||
if (nread < 0) {
|
||||
/* Error or EOF */
|
||||
ASSERT(nread == UV_EOF);
|
||||
|
||||
if (buf->base) {
|
||||
free(buf->base);
|
||||
}
|
||||
|
||||
req = malloc(sizeof *req);
|
||||
uv_shutdown(req, handle, after_shutdown);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (nread == 0) {
|
||||
/* Everything OK, but nothing read. */
|
||||
free(buf->base);
|
||||
return;
|
||||
}
|
||||
/* process requests and send responses */
|
||||
process_req(handle, nread, buf);
|
||||
}
|
||||
|
||||
|
||||
static void on_close(uv_handle_t* peer) {
|
||||
free(peer);
|
||||
}
|
||||
|
||||
|
||||
static void buf_alloc(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
buf->base = malloc(suggested_size);
|
||||
buf->len = suggested_size;
|
||||
}
|
||||
|
||||
|
||||
static void on_connection(uv_stream_t* server, int status) {
|
||||
dnshandle* handle;
|
||||
int r;
|
||||
|
||||
ASSERT(status == 0);
|
||||
|
||||
handle = (dnshandle*) malloc(sizeof *handle);
|
||||
ASSERT(handle != NULL);
|
||||
|
||||
/* initialize read buffer state */
|
||||
handle->state.prevbuf_ptr = 0;
|
||||
handle->state.prevbuf_pos = 0;
|
||||
handle->state.prevbuf_rem = 0;
|
||||
|
||||
r = uv_tcp_init(loop, (uv_tcp_t*)handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept(server, (uv_stream_t*)handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_read_start((uv_stream_t*)handle, buf_alloc, after_read);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static int dns_start(int port) {
|
||||
struct sockaddr_in addr;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr));
|
||||
|
||||
r = uv_tcp_init(loop, &server);
|
||||
if (r) {
|
||||
/* TODO: Error codes */
|
||||
fprintf(stderr, "Socket creation error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
|
||||
if (r) {
|
||||
/* TODO: Error codes */
|
||||
fprintf(stderr, "Bind error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = uv_listen((uv_stream_t*)&server, 128, on_connection);
|
||||
if (r) {
|
||||
/* TODO: Error codes */
|
||||
fprintf(stderr, "Listen error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
HELPER_IMPL(dns_server) {
|
||||
loop = uv_default_loop();
|
||||
|
||||
if (dns_start(TEST_PORT_2))
|
||||
return 1;
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
/* 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>
|
||||
|
||||
typedef struct {
|
||||
uv_write_t req;
|
||||
uv_buf_t buf;
|
||||
} write_req_t;
|
||||
|
||||
static uv_loop_t* loop;
|
||||
|
||||
static int server_closed;
|
||||
static stream_type serverType;
|
||||
static uv_tcp_t tcpServer;
|
||||
static uv_udp_t udpServer;
|
||||
static uv_pipe_t pipeServer;
|
||||
static uv_handle_t* server;
|
||||
|
||||
static void after_write(uv_write_t* req, int status);
|
||||
static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf);
|
||||
static void on_close(uv_handle_t* peer);
|
||||
static void on_server_close(uv_handle_t* handle);
|
||||
static void on_connection(uv_stream_t*, int status);
|
||||
|
||||
|
||||
static void after_write(uv_write_t* req, int status) {
|
||||
write_req_t* wr;
|
||||
|
||||
/* Free the read/write buffer and the request */
|
||||
wr = (write_req_t*) req;
|
||||
free(wr->buf.base);
|
||||
free(wr);
|
||||
|
||||
if (status == 0)
|
||||
return;
|
||||
|
||||
fprintf(stderr,
|
||||
"uv_write error: %s - %s\n",
|
||||
uv_err_name(status),
|
||||
uv_strerror(status));
|
||||
}
|
||||
|
||||
|
||||
static void after_shutdown(uv_shutdown_t* req, int status) {
|
||||
uv_close((uv_handle_t*) req->handle, on_close);
|
||||
free(req);
|
||||
}
|
||||
|
||||
|
||||
static void after_read(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
int i;
|
||||
write_req_t *wr;
|
||||
uv_shutdown_t* sreq;
|
||||
|
||||
if (nread < 0) {
|
||||
/* Error or EOF */
|
||||
ASSERT(nread == UV_EOF);
|
||||
|
||||
free(buf->base);
|
||||
sreq = malloc(sizeof* sreq);
|
||||
ASSERT(0 == uv_shutdown(sreq, handle, after_shutdown));
|
||||
return;
|
||||
}
|
||||
|
||||
if (nread == 0) {
|
||||
/* Everything OK, but nothing read. */
|
||||
free(buf->base);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan for the letter Q which signals that we should quit the server.
|
||||
* If we get QS it means close the stream.
|
||||
*/
|
||||
if (!server_closed) {
|
||||
for (i = 0; i < nread; i++) {
|
||||
if (buf->base[i] == 'Q') {
|
||||
if (i + 1 < nread && buf->base[i + 1] == 'S') {
|
||||
free(buf->base);
|
||||
uv_close((uv_handle_t*)handle, on_close);
|
||||
return;
|
||||
} else {
|
||||
uv_close(server, on_server_close);
|
||||
server_closed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wr = (write_req_t*) malloc(sizeof *wr);
|
||||
ASSERT(wr != NULL);
|
||||
wr->buf = uv_buf_init(buf->base, nread);
|
||||
|
||||
if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) {
|
||||
FATAL("uv_write failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void on_close(uv_handle_t* peer) {
|
||||
free(peer);
|
||||
}
|
||||
|
||||
|
||||
static void echo_alloc(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
buf->base = malloc(suggested_size);
|
||||
buf->len = suggested_size;
|
||||
}
|
||||
|
||||
|
||||
static void on_connection(uv_stream_t* server, int status) {
|
||||
uv_stream_t* stream;
|
||||
int r;
|
||||
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "Connect error %s\n", uv_err_name(status));
|
||||
}
|
||||
ASSERT(status == 0);
|
||||
|
||||
switch (serverType) {
|
||||
case TCP:
|
||||
stream = malloc(sizeof(uv_tcp_t));
|
||||
ASSERT(stream != NULL);
|
||||
r = uv_tcp_init(loop, (uv_tcp_t*)stream);
|
||||
ASSERT(r == 0);
|
||||
break;
|
||||
|
||||
case PIPE:
|
||||
stream = malloc(sizeof(uv_pipe_t));
|
||||
ASSERT(stream != NULL);
|
||||
r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);
|
||||
ASSERT(r == 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(0 && "Bad serverType");
|
||||
abort();
|
||||
}
|
||||
|
||||
/* associate server with stream */
|
||||
stream->data = server;
|
||||
|
||||
r = uv_accept(server, stream);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_read_start(stream, echo_alloc, after_read);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void on_server_close(uv_handle_t* handle) {
|
||||
ASSERT(handle == server);
|
||||
}
|
||||
|
||||
|
||||
static void on_send(uv_udp_send_t* req, int status);
|
||||
|
||||
|
||||
static void on_recv(uv_udp_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* rcvbuf,
|
||||
const struct sockaddr* addr,
|
||||
unsigned flags) {
|
||||
uv_udp_send_t* req;
|
||||
uv_buf_t sndbuf;
|
||||
|
||||
ASSERT(nread > 0);
|
||||
ASSERT(addr->sa_family == AF_INET);
|
||||
|
||||
req = malloc(sizeof(*req));
|
||||
ASSERT(req != NULL);
|
||||
|
||||
sndbuf = *rcvbuf;
|
||||
ASSERT(0 == uv_udp_send(req, handle, &sndbuf, 1, addr, on_send));
|
||||
}
|
||||
|
||||
|
||||
static void on_send(uv_udp_send_t* req, int status) {
|
||||
ASSERT(status == 0);
|
||||
free(req);
|
||||
}
|
||||
|
||||
|
||||
static int tcp4_echo_start(int port) {
|
||||
struct sockaddr_in addr;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr));
|
||||
|
||||
server = (uv_handle_t*)&tcpServer;
|
||||
serverType = TCP;
|
||||
|
||||
r = uv_tcp_init(loop, &tcpServer);
|
||||
if (r) {
|
||||
/* TODO: Error codes */
|
||||
fprintf(stderr, "Socket creation error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0);
|
||||
if (r) {
|
||||
/* TODO: Error codes */
|
||||
fprintf(stderr, "Bind error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
|
||||
if (r) {
|
||||
/* TODO: Error codes */
|
||||
fprintf(stderr, "Listen error %s\n", uv_err_name(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tcp6_echo_start(int port) {
|
||||
struct sockaddr_in6 addr6;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip6_addr("::1", port, &addr6));
|
||||
|
||||
server = (uv_handle_t*)&tcpServer;
|
||||
serverType = TCP;
|
||||
|
||||
r = uv_tcp_init(loop, &tcpServer);
|
||||
if (r) {
|
||||
/* TODO: Error codes */
|
||||
fprintf(stderr, "Socket creation error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* IPv6 is optional as not all platforms support it */
|
||||
r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr6, 0);
|
||||
if (r) {
|
||||
/* show message but return OK */
|
||||
fprintf(stderr, "IPv6 not supported\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
|
||||
if (r) {
|
||||
/* TODO: Error codes */
|
||||
fprintf(stderr, "Listen error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int udp4_echo_start(int port) {
|
||||
int r;
|
||||
|
||||
server = (uv_handle_t*)&udpServer;
|
||||
serverType = UDP;
|
||||
|
||||
r = uv_udp_init(loop, &udpServer);
|
||||
if (r) {
|
||||
fprintf(stderr, "uv_udp_init: %s\n", uv_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = uv_udp_recv_start(&udpServer, echo_alloc, on_recv);
|
||||
if (r) {
|
||||
fprintf(stderr, "uv_udp_recv_start: %s\n", uv_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int pipe_echo_start(char* pipeName) {
|
||||
int r;
|
||||
|
||||
#ifndef _WIN32
|
||||
{
|
||||
uv_fs_t req;
|
||||
uv_fs_unlink(NULL, &req, pipeName, NULL);
|
||||
uv_fs_req_cleanup(&req);
|
||||
}
|
||||
#endif
|
||||
|
||||
server = (uv_handle_t*)&pipeServer;
|
||||
serverType = PIPE;
|
||||
|
||||
r = uv_pipe_init(loop, &pipeServer, 0);
|
||||
if (r) {
|
||||
fprintf(stderr, "uv_pipe_init: %s\n", uv_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = uv_pipe_bind(&pipeServer, pipeName);
|
||||
if (r) {
|
||||
fprintf(stderr, "uv_pipe_bind: %s\n", uv_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = uv_listen((uv_stream_t*)&pipeServer, SOMAXCONN, on_connection);
|
||||
if (r) {
|
||||
fprintf(stderr, "uv_pipe_listen: %s\n", uv_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
HELPER_IMPL(tcp4_echo_server) {
|
||||
loop = uv_default_loop();
|
||||
|
||||
if (tcp4_echo_start(TEST_PORT))
|
||||
return 1;
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
HELPER_IMPL(tcp6_echo_server) {
|
||||
loop = uv_default_loop();
|
||||
|
||||
if (tcp6_echo_start(TEST_PORT))
|
||||
return 1;
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
HELPER_IMPL(pipe_echo_server) {
|
||||
loop = uv_default_loop();
|
||||
|
||||
if (pipe_echo_start(TEST_PIPENAME))
|
||||
return 1;
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
HELPER_IMPL(udp4_echo_server) {
|
||||
loop = uv_default_loop();
|
||||
|
||||
if (udp4_echo_start(TEST_PORT))
|
||||
return 1;
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
foobar
|
||||
@@ -0,0 +1,65 @@
|
||||
/* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "runner.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Actual benchmarks and helpers are defined in benchmark-list.h */
|
||||
#include "benchmark-list.h"
|
||||
|
||||
|
||||
static int maybe_run_test(int argc, char **argv);
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (platform_init(argc, argv))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
switch (argc) {
|
||||
case 1: return run_tests(1);
|
||||
case 2: return maybe_run_test(argc, argv);
|
||||
case 3: return run_test_part(argv[1], argv[2]);
|
||||
default:
|
||||
fprintf(stderr, "Too many arguments.\n");
|
||||
fflush(stderr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int maybe_run_test(int argc, char **argv) {
|
||||
if (strcmp(argv[1], "--list") == 0) {
|
||||
print_tests(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "spawn_helper") == 0) {
|
||||
printf("hello world\n");
|
||||
return 42;
|
||||
}
|
||||
|
||||
return run_test(argv[1], 1, 1);
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/* 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 <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <io.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "uv.h"
|
||||
#include "runner.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Actual tests and helpers are defined in test-list.h */
|
||||
#include "test-list.h"
|
||||
|
||||
int ipc_helper(int listen_after_write);
|
||||
int ipc_helper_tcp_connection(void);
|
||||
int ipc_send_recv_helper(void);
|
||||
int ipc_helper_bind_twice(void);
|
||||
int stdio_over_pipes_helper(void);
|
||||
int spawn_stdin_stdout(void);
|
||||
|
||||
static int maybe_run_test(int argc, char **argv);
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (platform_init(argc, argv))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
argv = uv_setup_args(argc, argv);
|
||||
|
||||
switch (argc) {
|
||||
case 1: return run_tests(0);
|
||||
case 2: return maybe_run_test(argc, argv);
|
||||
case 3: return run_test_part(argv[1], argv[2]);
|
||||
default:
|
||||
fprintf(stderr, "Too many arguments.\n");
|
||||
fflush(stderr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int maybe_run_test(int argc, char **argv) {
|
||||
if (strcmp(argv[1], "--list") == 0) {
|
||||
print_tests(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "ipc_helper_listen_before_write") == 0) {
|
||||
return ipc_helper(0);
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "ipc_helper_listen_after_write") == 0) {
|
||||
return ipc_helper(1);
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "ipc_send_recv_helper") == 0) {
|
||||
return ipc_send_recv_helper();
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "ipc_helper_tcp_connection") == 0) {
|
||||
return ipc_helper_tcp_connection();
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "ipc_helper_bind_twice") == 0) {
|
||||
return ipc_helper_bind_twice();
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) {
|
||||
return stdio_over_pipes_helper();
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "spawn_helper1") == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "spawn_helper2") == 0) {
|
||||
printf("hello world\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "spawn_helper3") == 0) {
|
||||
char buffer[256];
|
||||
ASSERT(buffer == fgets(buffer, sizeof(buffer) - 1, stdin));
|
||||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
fputs(buffer, stdout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "spawn_helper4") == 0) {
|
||||
/* Never surrender, never return! */
|
||||
while (1) uv_sleep(10000);
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "spawn_helper5") == 0) {
|
||||
const char out[] = "fourth stdio!\n";
|
||||
#ifdef _WIN32
|
||||
DWORD bytes;
|
||||
WriteFile((HANDLE) _get_osfhandle(3), out, sizeof(out) - 1, &bytes, NULL);
|
||||
#else
|
||||
{
|
||||
ssize_t r;
|
||||
|
||||
do
|
||||
r = write(3, out, sizeof(out) - 1);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
fsync(3);
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "spawn_helper6") == 0) {
|
||||
int r;
|
||||
|
||||
r = fprintf(stdout, "hello world\n");
|
||||
ASSERT(r > 0);
|
||||
|
||||
r = fprintf(stderr, "hello errworld\n");
|
||||
ASSERT(r > 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "spawn_helper7") == 0) {
|
||||
int r;
|
||||
char *test;
|
||||
/* Test if the test value from the parent is still set */
|
||||
test = getenv("ENV_TEST");
|
||||
ASSERT(test != NULL);
|
||||
|
||||
r = fprintf(stdout, "%s", test);
|
||||
ASSERT(r > 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
if (strcmp(argv[1], "spawn_helper8") == 0) {
|
||||
int fd;
|
||||
ASSERT(sizeof(fd) == read(0, &fd, sizeof(fd)));
|
||||
ASSERT(fd > 2);
|
||||
ASSERT(-1 == write(fd, "x", 1));
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
if (strcmp(argv[1], "spawn_helper9") == 0) {
|
||||
return spawn_stdin_stdout();
|
||||
}
|
||||
|
||||
return run_test(argv[1], 0, 1);
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
/* 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 "runner-unix.h"
|
||||
#include "runner.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h> /* uintptr_t */
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h> /* readlink, usleep */
|
||||
#include <string.h> /* strdup */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
/* 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);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if (realpath(argv[0], executable_path) == NULL) {
|
||||
perror("realpath");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Invoke "argv[0] test-name [test-part]". Store process info in *p. */
|
||||
/* Make sure that all stdio output of the processes is buffered up. */
|
||||
int process_start(char* name, char* part, process_info_t* p, int is_helper) {
|
||||
FILE* stdout_file;
|
||||
const char* arg;
|
||||
char* args[16];
|
||||
int n;
|
||||
pid_t pid;
|
||||
|
||||
stdout_file = tmpfile();
|
||||
if (!stdout_file) {
|
||||
perror("tmpfile");
|
||||
return -1;
|
||||
}
|
||||
|
||||
p->terminated = 0;
|
||||
p->status = 0;
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
perror("fork");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
arg = getenv("UV_USE_VALGRIND");
|
||||
n = 0;
|
||||
|
||||
/* Disable valgrind for helpers, it complains about helpers leaking memory.
|
||||
* They're killed after the test and as such never get a chance to clean up.
|
||||
*/
|
||||
if (is_helper == 0 && arg != NULL && atoi(arg) != 0) {
|
||||
args[n++] = "valgrind";
|
||||
args[n++] = "--quiet";
|
||||
args[n++] = "--leak-check=full";
|
||||
args[n++] = "--show-reachable=yes";
|
||||
args[n++] = "--error-exitcode=125";
|
||||
}
|
||||
|
||||
args[n++] = executable_path;
|
||||
args[n++] = name;
|
||||
args[n++] = part;
|
||||
args[n++] = NULL;
|
||||
|
||||
dup2(fileno(stdout_file), STDOUT_FILENO);
|
||||
dup2(fileno(stdout_file), STDERR_FILENO);
|
||||
execvp(args[0], args);
|
||||
perror("execvp()");
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
/* parent */
|
||||
p->pid = pid;
|
||||
p->name = strdup(name);
|
||||
p->stdout_file = stdout_file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
int pipe[2];
|
||||
process_info_t* vec;
|
||||
int n;
|
||||
} dowait_args;
|
||||
|
||||
|
||||
/* This function is run inside a pthread. We do this so that we can possibly
|
||||
* timeout.
|
||||
*/
|
||||
static void* dowait(void* data) {
|
||||
dowait_args* args = data;
|
||||
|
||||
int i, r;
|
||||
process_info_t* p;
|
||||
|
||||
for (i = 0; i < args->n; i++) {
|
||||
p = (process_info_t*)(args->vec + i * sizeof(process_info_t));
|
||||
if (p->terminated) continue;
|
||||
r = waitpid(p->pid, &p->status, 0);
|
||||
if (r < 0) {
|
||||
perror("waitpid");
|
||||
return NULL;
|
||||
}
|
||||
p->terminated = 1;
|
||||
}
|
||||
|
||||
if (args->pipe[1] >= 0) {
|
||||
/* Write a character to the main thread to notify it about this. */
|
||||
ssize_t r;
|
||||
|
||||
do
|
||||
r = write(args->pipe[1], "", 1);
|
||||
while (r == -1 && errno == EINTR);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Wait for all `n` processes in `vec` to terminate. */
|
||||
/* Time out after `timeout` msec, or never if timeout == -1 */
|
||||
/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */
|
||||
int process_wait(process_info_t* vec, int n, int timeout) {
|
||||
int i;
|
||||
int r;
|
||||
int retval;
|
||||
process_info_t* p;
|
||||
dowait_args args;
|
||||
pthread_t tid;
|
||||
pthread_attr_t attr;
|
||||
unsigned int elapsed_ms;
|
||||
struct timeval timebase;
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
|
||||
args.vec = vec;
|
||||
args.n = n;
|
||||
args.pipe[0] = -1;
|
||||
args.pipe[1] = -1;
|
||||
|
||||
/* The simple case is where there is no timeout */
|
||||
if (timeout == -1) {
|
||||
dowait(&args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Hard case. Do the wait with a timeout.
|
||||
*
|
||||
* Assumption: we are the only ones making this call right now. Otherwise
|
||||
* we'd need to lock vec.
|
||||
*/
|
||||
|
||||
r = pipe((int*)&(args.pipe));
|
||||
if (r) {
|
||||
perror("pipe()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pthread_attr_init(&attr))
|
||||
abort();
|
||||
|
||||
if (pthread_attr_setstacksize(&attr, 256 * 1024))
|
||||
abort();
|
||||
|
||||
r = pthread_create(&tid, &attr, dowait, &args);
|
||||
|
||||
if (pthread_attr_destroy(&attr))
|
||||
abort();
|
||||
|
||||
if (r) {
|
||||
perror("pthread_create()");
|
||||
retval = -1;
|
||||
goto terminate;
|
||||
}
|
||||
|
||||
if (gettimeofday(&timebase, NULL))
|
||||
abort();
|
||||
|
||||
tv = timebase;
|
||||
for (;;) {
|
||||
/* Check that gettimeofday() doesn't jump back in time. */
|
||||
assert(tv.tv_sec == timebase.tv_sec ||
|
||||
(tv.tv_sec == timebase.tv_sec && tv.tv_usec >= timebase.tv_usec));
|
||||
|
||||
elapsed_ms =
|
||||
(tv.tv_sec - timebase.tv_sec) * 1000 +
|
||||
(tv.tv_usec / 1000) -
|
||||
(timebase.tv_usec / 1000);
|
||||
|
||||
r = 0; /* Timeout. */
|
||||
if (elapsed_ms >= (unsigned) timeout)
|
||||
break;
|
||||
|
||||
tv.tv_sec = (timeout - elapsed_ms) / 1000;
|
||||
tv.tv_usec = (timeout - elapsed_ms) % 1000 * 1000;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(args.pipe[0], &fds);
|
||||
|
||||
r = select(args.pipe[0] + 1, &fds, NULL, NULL, &tv);
|
||||
if (!(r == -1 && errno == EINTR))
|
||||
break;
|
||||
|
||||
if (gettimeofday(&tv, NULL))
|
||||
abort();
|
||||
}
|
||||
|
||||
if (r == -1) {
|
||||
perror("select()");
|
||||
retval = -1;
|
||||
|
||||
} else if (r) {
|
||||
/* The thread completed successfully. */
|
||||
retval = 0;
|
||||
|
||||
} else {
|
||||
/* Timeout. Kill all the children. */
|
||||
for (i = 0; i < n; i++) {
|
||||
p = (process_info_t*)(vec + i * sizeof(process_info_t));
|
||||
kill(p->pid, SIGTERM);
|
||||
}
|
||||
retval = -2;
|
||||
}
|
||||
|
||||
if (pthread_join(tid, NULL))
|
||||
abort();
|
||||
|
||||
terminate:
|
||||
close(args.pipe[0]);
|
||||
close(args.pipe[1]);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* Returns the number of bytes in the stdio output buffer for process `p`. */
|
||||
long int process_output_size(process_info_t *p) {
|
||||
/* Size of the p->stdout_file */
|
||||
struct stat buf;
|
||||
|
||||
int r = fstat(fileno(p->stdout_file), &buf);
|
||||
if (r < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (long)buf.st_size;
|
||||
}
|
||||
|
||||
|
||||
/* Copy the contents of the stdio output buffer to `fd`. */
|
||||
int process_copy_output(process_info_t *p, int fd) {
|
||||
ssize_t nwritten;
|
||||
char buf[1024];
|
||||
int r;
|
||||
|
||||
r = fseek(p->stdout_file, 0, SEEK_SET);
|
||||
if (r < 0) {
|
||||
perror("fseek");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (ferror(p->stdout_file)) {
|
||||
perror("read");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Copy the last line of the stdio output buffer to `buffer` */
|
||||
int process_read_last_line(process_info_t *p,
|
||||
char* buffer,
|
||||
size_t buffer_len) {
|
||||
char* ptr;
|
||||
|
||||
int r = fseek(p->stdout_file, 0, SEEK_SET);
|
||||
if (r < 0) {
|
||||
perror("fseek");
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
while (fgets(buffer, buffer_len, p->stdout_file) != NULL) {
|
||||
for (ptr = buffer; *ptr && *ptr != '\r' && *ptr != '\n'; ptr++);
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
if (ferror(p->stdout_file)) {
|
||||
perror("read");
|
||||
buffer[0] = '\0';
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return the name that was specified when `p` was started by process_start */
|
||||
char* process_get_name(process_info_t *p) {
|
||||
return p->name;
|
||||
}
|
||||
|
||||
|
||||
/* Terminate process `p`. */
|
||||
int process_terminate(process_info_t *p) {
|
||||
return kill(p->pid, SIGTERM);
|
||||
}
|
||||
|
||||
|
||||
/* Return the exit code of process p. */
|
||||
/* On error, return -1. */
|
||||
int process_reap(process_info_t *p) {
|
||||
if (WIFEXITED(p->status)) {
|
||||
return WEXITSTATUS(p->status);
|
||||
} else {
|
||||
return p->status; /* ? */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Clean up after terminating process `p` (e.g. free the output buffer etc.). */
|
||||
void process_cleanup(process_info_t *p) {
|
||||
fclose(p->stdout_file);
|
||||
free(p->name);
|
||||
}
|
||||
|
||||
|
||||
/* Move the console cursor one line up and back to the first column. */
|
||||
void rewind_cursor(void) {
|
||||
fprintf(stderr, "\033[2K\r");
|
||||
}
|
||||
|
||||
|
||||
/* Pause the calling thread for a number of milliseconds. */
|
||||
void uv_sleep(int msec) {
|
||||
usleep(msec * 1000);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef TEST_RUNNER_UNIX_H
|
||||
#define TEST_RUNNER_UNIX_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h> /* FILE */
|
||||
|
||||
typedef struct {
|
||||
FILE* stdout_file;
|
||||
pid_t pid;
|
||||
char* name;
|
||||
int status;
|
||||
int terminated;
|
||||
} process_info_t;
|
||||
|
||||
#endif /* TEST_RUNNER_UNIX_H */
|
||||
@@ -0,0 +1,371 @@
|
||||
/* 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 <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <process.h>
|
||||
#if !defined(__MINGW32__)
|
||||
# include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "task.h"
|
||||
#include "runner.h"
|
||||
|
||||
|
||||
/*
|
||||
* Define the stuff that MinGW doesn't have
|
||||
*/
|
||||
#ifndef GetFileSizeEx
|
||||
WINBASEAPI BOOL WINAPI GetFileSizeEx(HANDLE hFile,
|
||||
PLARGE_INTEGER lpFileSize);
|
||||
#endif
|
||||
|
||||
|
||||
/* 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);
|
||||
#if !defined(__MINGW32__)
|
||||
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
|
||||
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
|
||||
#endif
|
||||
|
||||
_setmode(0, _O_BINARY);
|
||||
_setmode(1, _O_BINARY);
|
||||
_setmode(2, _O_BINARY);
|
||||
|
||||
/* Disable stdio output buffering. */
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
strcpy(executable_path, argv[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int process_start(char *name, char *part, process_info_t *p, int is_helper) {
|
||||
HANDLE file = INVALID_HANDLE_VALUE;
|
||||
HANDLE nul = INVALID_HANDLE_VALUE;
|
||||
WCHAR path[MAX_PATH], filename[MAX_PATH];
|
||||
WCHAR image[MAX_PATH + 1];
|
||||
WCHAR args[MAX_PATH * 2];
|
||||
STARTUPINFOW si;
|
||||
PROCESS_INFORMATION pi;
|
||||
DWORD result;
|
||||
|
||||
if (GetTempPathW(sizeof(path) / sizeof(WCHAR), (WCHAR*)&path) == 0)
|
||||
goto error;
|
||||
if (GetTempFileNameW((WCHAR*)&path, L"uv", 0, (WCHAR*)&filename) == 0)
|
||||
goto error;
|
||||
|
||||
file = CreateFileW((WCHAR*)filename,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
|
||||
NULL);
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
goto error;
|
||||
|
||||
if (!SetHandleInformation(file, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
|
||||
goto error;
|
||||
|
||||
nul = CreateFileA("nul",
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (nul == INVALID_HANDLE_VALUE)
|
||||
goto error;
|
||||
|
||||
if (!SetHandleInformation(nul, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
|
||||
goto error;
|
||||
|
||||
result = GetModuleFileNameW(NULL,
|
||||
(WCHAR*) &image,
|
||||
sizeof(image) / sizeof(WCHAR));
|
||||
if (result == 0 || result == sizeof(image))
|
||||
goto error;
|
||||
|
||||
if (part) {
|
||||
if (_snwprintf((WCHAR*)args,
|
||||
sizeof(args) / sizeof(WCHAR),
|
||||
L"\"%s\" %S %S",
|
||||
image,
|
||||
name,
|
||||
part) < 0) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (_snwprintf((WCHAR*)args,
|
||||
sizeof(args) / sizeof(WCHAR),
|
||||
L"\"%s\" %S",
|
||||
image,
|
||||
name) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
memset((void*)&si, 0, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
si.hStdInput = nul;
|
||||
si.hStdOutput = file;
|
||||
si.hStdError = file;
|
||||
|
||||
if (!CreateProcessW(image, args, NULL, NULL, TRUE,
|
||||
0, NULL, NULL, &si, &pi))
|
||||
goto error;
|
||||
|
||||
CloseHandle(pi.hThread);
|
||||
|
||||
SetHandleInformation(nul, HANDLE_FLAG_INHERIT, 0);
|
||||
SetHandleInformation(file, HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
p->stdio_in = nul;
|
||||
p->stdio_out = file;
|
||||
p->process = pi.hProcess;
|
||||
p->name = part;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (file != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(file);
|
||||
if (nul != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(nul);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Timeout is is msecs. Set timeout < 0 to never time out. */
|
||||
/* Returns 0 when all processes are terminated, -2 on timeout. */
|
||||
int process_wait(process_info_t *vec, int n, int timeout) {
|
||||
int i;
|
||||
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
|
||||
DWORD timeout_api, result;
|
||||
|
||||
/* If there's nothing to wait for, return immediately. */
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
ASSERT(n <= MAXIMUM_WAIT_OBJECTS);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
handles[i] = vec[i].process;
|
||||
|
||||
if (timeout >= 0) {
|
||||
timeout_api = (DWORD)timeout;
|
||||
} else {
|
||||
timeout_api = INFINITE;
|
||||
}
|
||||
|
||||
result = WaitForMultipleObjects(n, handles, TRUE, timeout_api);
|
||||
|
||||
if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + n) {
|
||||
/* All processes are terminated. */
|
||||
return 0;
|
||||
}
|
||||
if (result == WAIT_TIMEOUT) {
|
||||
return -2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
long int process_output_size(process_info_t *p) {
|
||||
LARGE_INTEGER size;
|
||||
if (!GetFileSizeEx(p->stdio_out, &size))
|
||||
return -1;
|
||||
return (long int)size.QuadPart;
|
||||
}
|
||||
|
||||
|
||||
int process_copy_output(process_info_t *p, int fd) {
|
||||
DWORD read;
|
||||
char buf[1024];
|
||||
char *line, *start;
|
||||
|
||||
if (SetFilePointer(p->stdio_out,
|
||||
0,
|
||||
0,
|
||||
FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
|
||||
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);
|
||||
|
||||
if (GetLastError() != ERROR_HANDLE_EOF)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int process_read_last_line(process_info_t *p,
|
||||
char * buffer,
|
||||
size_t buffer_len) {
|
||||
DWORD size;
|
||||
DWORD read;
|
||||
DWORD start;
|
||||
OVERLAPPED overlapped;
|
||||
|
||||
ASSERT(buffer_len > 0);
|
||||
|
||||
size = GetFileSize(p->stdio_out, NULL);
|
||||
if (size == INVALID_FILE_SIZE)
|
||||
return -1;
|
||||
|
||||
if (size == 0) {
|
||||
buffer[0] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&overlapped, 0, sizeof overlapped);
|
||||
if (size >= buffer_len)
|
||||
overlapped.Offset = size - buffer_len - 1;
|
||||
|
||||
if (!ReadFile(p->stdio_out, buffer, buffer_len - 1, &read, &overlapped))
|
||||
return -1;
|
||||
|
||||
for (start = read - 1; start >= 0; start--) {
|
||||
if (buffer[start] == '\n' || buffer[start] == '\r')
|
||||
break;
|
||||
}
|
||||
|
||||
if (start > 0)
|
||||
memmove(buffer, buffer + start, read - start);
|
||||
|
||||
buffer[read - start] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char* process_get_name(process_info_t *p) {
|
||||
return p->name;
|
||||
}
|
||||
|
||||
|
||||
int process_terminate(process_info_t *p) {
|
||||
if (!TerminateProcess(p->process, 1))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int process_reap(process_info_t *p) {
|
||||
DWORD exitCode;
|
||||
if (!GetExitCodeProcess(p->process, &exitCode))
|
||||
return -1;
|
||||
return (int)exitCode;
|
||||
}
|
||||
|
||||
|
||||
void process_cleanup(process_info_t *p) {
|
||||
CloseHandle(p->process);
|
||||
CloseHandle(p->stdio_in);
|
||||
CloseHandle(p->stdio_out);
|
||||
}
|
||||
|
||||
|
||||
static int clear_line() {
|
||||
HANDLE handle;
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
COORD coord;
|
||||
DWORD written;
|
||||
|
||||
handle = (HANDLE)_get_osfhandle(fileno(stderr));
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(handle, &info))
|
||||
return -1;
|
||||
|
||||
coord = info.dwCursorPosition;
|
||||
if (coord.Y <= 0)
|
||||
return -1;
|
||||
|
||||
coord.X = 0;
|
||||
|
||||
if (!SetConsoleCursorPosition(handle, coord))
|
||||
return -1;
|
||||
|
||||
if (!FillConsoleOutputCharacterW(handle,
|
||||
0x20,
|
||||
info.dwSize.X,
|
||||
coord,
|
||||
&written)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void rewind_cursor() {
|
||||
if (clear_line() == -1) {
|
||||
/* If clear_line fails (stdout is not a console), print a newline. */
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Pause the calling thread for a number of milliseconds. */
|
||||
void uv_sleep(int msec) {
|
||||
Sleep(msec);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* Don't complain about _snprintf being insecure. */
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
/* Don't complain about write(), fileno() etc. being deprecated. */
|
||||
#pragma warning(disable : 4996)
|
||||
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
/* Windows has no snprintf, only _snprintf. */
|
||||
#define snprintf _snprintf
|
||||
|
||||
|
||||
typedef struct {
|
||||
HANDLE process;
|
||||
HANDLE stdio_in;
|
||||
HANDLE stdio_out;
|
||||
char *name;
|
||||
} process_info_t;
|
||||
@@ -0,0 +1,464 @@
|
||||
/* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "runner.h"
|
||||
#include "task.h"
|
||||
#include "uv.h"
|
||||
|
||||
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];
|
||||
static char* p;
|
||||
uint64_t v;
|
||||
|
||||
if (p == NULL)
|
||||
p = buf;
|
||||
|
||||
p += 31;
|
||||
|
||||
if (p >= buf + sizeof(buf))
|
||||
return "<buffer too small>";
|
||||
|
||||
v = (uint64_t) d;
|
||||
|
||||
#if 0 /* works but we don't care about fractional precision */
|
||||
if (d - v >= 0.01) {
|
||||
*--p = '0' + (uint64_t) (d * 100) % 10;
|
||||
*--p = '0' + (uint64_t) (d * 10) % 10;
|
||||
*--p = '.';
|
||||
}
|
||||
#endif
|
||||
|
||||
if (v == 0)
|
||||
*--p = '0';
|
||||
|
||||
while (v) {
|
||||
if (v) *--p = '0' + (v % 10), v /= 10;
|
||||
if (v) *--p = '0' + (v % 10), v /= 10;
|
||||
if (v) *--p = '0' + (v % 10), v /= 10;
|
||||
if (v) *--p = ',';
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
int run_tests(int benchmark_output) {
|
||||
int total;
|
||||
int passed;
|
||||
int failed;
|
||||
int todos;
|
||||
int skipped;
|
||||
int current;
|
||||
int test_result;
|
||||
task_entry_t* task;
|
||||
|
||||
/* Count the number of tests. */
|
||||
total = 0;
|
||||
for (task = TASKS; task->main; task++) {
|
||||
if (!task->is_helper) {
|
||||
total++;
|
||||
}
|
||||
}
|
||||
|
||||
if (tap_output) {
|
||||
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++) {
|
||||
if (task->is_helper) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void log_tap_result(int test_count,
|
||||
const char* test,
|
||||
int status,
|
||||
process_info_t* process) {
|
||||
const char* result;
|
||||
const char* directive;
|
||||
char reason[1024];
|
||||
|
||||
switch (status) {
|
||||
case TEST_OK:
|
||||
result = "ok";
|
||||
directive = "";
|
||||
break;
|
||||
case TEST_TODO:
|
||||
result = "not ok";
|
||||
directive = " # TODO ";
|
||||
break;
|
||||
case TEST_SKIP:
|
||||
result = "ok";
|
||||
directive = " # SKIP ";
|
||||
break;
|
||||
default:
|
||||
result = "not ok";
|
||||
directive = "";
|
||||
}
|
||||
|
||||
if ((status == TEST_SKIP || status == TEST_TODO) &&
|
||||
process_output_size(process) > 0) {
|
||||
process_read_last_line(process, reason, sizeof reason);
|
||||
} else {
|
||||
reason[0] = '\0';
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s %d - %s%s%s\n", result, test_count, test, directive, reason);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
int run_test(const char* test,
|
||||
int benchmark_output,
|
||||
int test_count) {
|
||||
char errmsg[1024] = "no error";
|
||||
process_info_t processes[1024];
|
||||
process_info_t *main_proc;
|
||||
task_entry_t* task;
|
||||
int process_count;
|
||||
int result;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
status = 255;
|
||||
main_proc = NULL;
|
||||
process_count = 0;
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Clean up stale socket from previous run. */
|
||||
remove(TEST_PIPENAME);
|
||||
#endif
|
||||
|
||||
/* If it's a helper the user asks for, start it directly. */
|
||||
for (task = TASKS; task->main; task++) {
|
||||
if (task->is_helper && strcmp(test, task->process_name) == 0) {
|
||||
return task->main();
|
||||
}
|
||||
}
|
||||
|
||||
/* Start the helpers first. */
|
||||
for (task = TASKS; task->main; task++) {
|
||||
if (strcmp(test, task->task_name) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip the test itself. */
|
||||
if (!task->is_helper) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (process_start(task->task_name,
|
||||
task->process_name,
|
||||
&processes[process_count],
|
||||
1 /* is_helper */) == -1) {
|
||||
snprintf(errmsg,
|
||||
sizeof errmsg,
|
||||
"Process `%s` failed to start.",
|
||||
task->process_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
process_count++;
|
||||
}
|
||||
|
||||
/* Give the helpers time to settle. Race-y, fix this. */
|
||||
uv_sleep(250);
|
||||
|
||||
/* Now start the test itself. */
|
||||
for (task = TASKS; task->main; task++) {
|
||||
if (strcmp(test, task->task_name) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (task->is_helper) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (process_start(task->task_name,
|
||||
task->process_name,
|
||||
&processes[process_count],
|
||||
0 /* !is_helper */) == -1) {
|
||||
snprintf(errmsg,
|
||||
sizeof errmsg,
|
||||
"Process `%s` failed to start.",
|
||||
task->process_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
main_proc = &processes[process_count];
|
||||
process_count++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (main_proc == NULL) {
|
||||
snprintf(errmsg,
|
||||
sizeof errmsg,
|
||||
"No test with that name: %s",
|
||||
test);
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = process_wait(main_proc, 1, task->timeout);
|
||||
if (result == -1) {
|
||||
FATAL("process_wait failed");
|
||||
} else if (result == -2) {
|
||||
/* Don't have to clean up the process, process_wait() has killed it. */
|
||||
snprintf(errmsg,
|
||||
sizeof errmsg,
|
||||
"timeout");
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = process_reap(main_proc);
|
||||
if (status != TEST_OK) {
|
||||
snprintf(errmsg,
|
||||
sizeof errmsg,
|
||||
"exit code %d",
|
||||
status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (benchmark_output) {
|
||||
/* Give the helpers time to clean up their act. */
|
||||
uv_sleep(1000);
|
||||
}
|
||||
|
||||
out:
|
||||
/* Reap running processes except the main process, it's already dead. */
|
||||
for (i = 0; i < process_count - 1; i++) {
|
||||
process_terminate(&processes[i]);
|
||||
}
|
||||
|
||||
if (process_count > 0 &&
|
||||
process_wait(processes, process_count - 1, -1) < 0) {
|
||||
FATAL("process_wait failed");
|
||||
}
|
||||
|
||||
if (tap_output)
|
||||
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");
|
||||
}
|
||||
fflush(stderr);
|
||||
|
||||
for (i = 0; i < process_count; i++) {
|
||||
switch (process_output_size(&processes[i])) {
|
||||
case -1:
|
||||
fprintf(stderr, "Output from process `%s`: (unavailable)\n",
|
||||
process_get_name(&processes[i]));
|
||||
fflush(stderr);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
fprintf(stderr, "Output from process `%s`: (no output)\n",
|
||||
process_get_name(&processes[i]));
|
||||
fflush(stderr);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Output from process `%s`:\n", process_get_name(&processes[i]));
|
||||
fflush(stderr);
|
||||
process_copy_output(&processes[i], fileno(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)) {
|
||||
case -1:
|
||||
fprintf(stderr, "%s: (unavailable)\n", test);
|
||||
fflush(stderr);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
fprintf(stderr, "%s: (no output)\n", test);
|
||||
fflush(stderr);
|
||||
break;
|
||||
|
||||
default:
|
||||
for (i = 0; i < process_count; i++) {
|
||||
process_copy_output(&processes[i], fileno(stderr));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up all process handles. */
|
||||
for (i = 0; i < process_count; i++) {
|
||||
process_cleanup(&processes[i]);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Returns the status code of the task part
|
||||
* or 255 if no matching task was not found.
|
||||
*/
|
||||
int run_test_part(const char* test, const char* part) {
|
||||
task_entry_t* task;
|
||||
int r;
|
||||
|
||||
for (task = TASKS; task->main; task++) {
|
||||
if (strcmp(test, task->task_name) == 0 &&
|
||||
strcmp(part, task->process_name) == 0) {
|
||||
r = task->main();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "No test part with that name: %s:%s\n", test, part);
|
||||
fflush(stderr);
|
||||
return 255;
|
||||
}
|
||||
|
||||
|
||||
static int compare_task(const void* va, const void* vb) {
|
||||
const task_entry_t* a = va;
|
||||
const task_entry_t* b = vb;
|
||||
return strcmp(a->task_name, b->task_name);
|
||||
}
|
||||
|
||||
|
||||
static int find_helpers(const task_entry_t* task,
|
||||
const task_entry_t** helpers) {
|
||||
const task_entry_t* helper;
|
||||
int n_helpers;
|
||||
|
||||
for (n_helpers = 0, helper = TASKS; helper->main; helper++) {
|
||||
if (helper->is_helper && strcmp(helper->task_name, task->task_name) == 0) {
|
||||
*helpers++ = helper;
|
||||
n_helpers++;
|
||||
}
|
||||
}
|
||||
|
||||
return n_helpers;
|
||||
}
|
||||
|
||||
|
||||
void print_tests(FILE* stream) {
|
||||
const task_entry_t* helpers[1024];
|
||||
const task_entry_t* task;
|
||||
int n_helpers;
|
||||
int n_tasks;
|
||||
int i;
|
||||
|
||||
for (n_tasks = 0, task = TASKS; task->main; n_tasks++, task++);
|
||||
qsort(TASKS, n_tasks, sizeof(TASKS[0]), compare_task);
|
||||
|
||||
for (task = TASKS; task->main; task++) {
|
||||
if (task->is_helper) {
|
||||
continue;
|
||||
}
|
||||
|
||||
n_helpers = find_helpers(task, helpers);
|
||||
if (n_helpers) {
|
||||
printf("%-25s (helpers:", task->task_name);
|
||||
for (i = 0; i < n_helpers; i++) {
|
||||
printf(" %s", helpers[i]->process_name);
|
||||
}
|
||||
printf(")\n");
|
||||
} else {
|
||||
printf("%s\n", task->task_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef RUNNER_H_
|
||||
#define RUNNER_H_
|
||||
|
||||
#include <limits.h> /* PATH_MAX */
|
||||
#include <stdio.h> /* FILE */
|
||||
|
||||
|
||||
/*
|
||||
* The maximum number of processes (main + helpers) that a test / benchmark
|
||||
* can have.
|
||||
*/
|
||||
#define MAX_PROCESSES 8
|
||||
|
||||
|
||||
/*
|
||||
* Struct to store both tests and to define helper processes for tasks.
|
||||
*/
|
||||
typedef struct {
|
||||
char *task_name;
|
||||
char *process_name;
|
||||
int (*main)(void);
|
||||
int is_helper;
|
||||
int show_output;
|
||||
|
||||
/*
|
||||
* The time in milliseconds after which a single test or benchmark times out.
|
||||
*/
|
||||
int timeout;
|
||||
} task_entry_t, bench_entry_t;
|
||||
|
||||
|
||||
/*
|
||||
* Macros used by test-list.h and benchmark-list.h.
|
||||
*/
|
||||
#define TASK_LIST_START \
|
||||
task_entry_t TASKS[] = {
|
||||
|
||||
#define TASK_LIST_END \
|
||||
{ 0, 0, 0, 0, 0, 0 } \
|
||||
};
|
||||
|
||||
#define TEST_DECLARE(name) \
|
||||
int run_test_##name(void);
|
||||
|
||||
#define TEST_ENTRY(name) \
|
||||
{ #name, #name, &run_test_##name, 0, 0, 5000 },
|
||||
|
||||
#define TEST_ENTRY_CUSTOM(name, is_helper, show_output, timeout) \
|
||||
{ #name, #name, &run_test_##name, is_helper, show_output, timeout },
|
||||
|
||||
#define BENCHMARK_DECLARE(name) \
|
||||
int run_benchmark_##name(void);
|
||||
|
||||
#define BENCHMARK_ENTRY(name) \
|
||||
{ #name, #name, &run_benchmark_##name, 0, 0, 60000 },
|
||||
|
||||
#define HELPER_DECLARE(name) \
|
||||
int run_helper_##name(void);
|
||||
|
||||
#define HELPER_ENTRY(task_name, name) \
|
||||
{ #task_name, #name, &run_helper_##name, 1, 0, 0 },
|
||||
|
||||
#define TEST_HELPER HELPER_ENTRY
|
||||
#define BENCHMARK_HELPER HELPER_ENTRY
|
||||
|
||||
#ifdef PATH_MAX
|
||||
extern char executable_path[PATH_MAX];
|
||||
#else
|
||||
extern char executable_path[4096];
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Include platform-dependent definitions
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
# include "runner-win.h"
|
||||
#else
|
||||
# include "runner-unix.h"
|
||||
#endif
|
||||
|
||||
|
||||
/* The array that is filled by test-list.h or benchmark-list.h */
|
||||
extern task_entry_t TASKS[];
|
||||
|
||||
/*
|
||||
* Run all tests.
|
||||
*/
|
||||
int run_tests(int benchmark_output);
|
||||
|
||||
/*
|
||||
* Run a single test. Starts up any helpers.
|
||||
*/
|
||||
int run_test(const char* test,
|
||||
int benchmark_output,
|
||||
int test_count);
|
||||
|
||||
/*
|
||||
* Run a test part, i.e. the test or one of its helpers.
|
||||
*/
|
||||
int run_test_part(const char* test, const char* part);
|
||||
|
||||
|
||||
/*
|
||||
* Print tests in sorted order to `stream`. Used by `./run-tests --list`.
|
||||
*/
|
||||
void print_tests(FILE* stream);
|
||||
|
||||
|
||||
/*
|
||||
* Stuff that should be implemented by test-runner-<platform>.h
|
||||
* All functions return 0 on success, -1 on failure, unless specified
|
||||
* otherwise.
|
||||
*/
|
||||
|
||||
/* Do platform-specific initialization. */
|
||||
int platform_init(int argc, char** argv);
|
||||
|
||||
/* Invoke "argv[0] test-name [test-part]". Store process info in *p. */
|
||||
/* Make sure that all stdio output of the processes is buffered up. */
|
||||
int process_start(char *name, char* part, process_info_t *p, int is_helper);
|
||||
|
||||
/* Wait for all `n` processes in `vec` to terminate. */
|
||||
/* Time out after `timeout` msec, or never if timeout == -1 */
|
||||
/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */
|
||||
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 last line of the stdio output buffer to `buffer` */
|
||||
int process_read_last_line(process_info_t *p,
|
||||
char * buffer,
|
||||
size_t buffer_len);
|
||||
|
||||
/* Return the name that was specified when `p` was started by process_start */
|
||||
char* process_get_name(process_info_t *p);
|
||||
|
||||
/* Terminate process `p`. */
|
||||
int process_terminate(process_info_t *p);
|
||||
|
||||
/* Return the exit code of process p. */
|
||||
/* On error, return -1. */
|
||||
int process_reap(process_info_t *p);
|
||||
|
||||
/* Clean up after terminating process `p` (e.g. free the output buffer etc.). */
|
||||
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_ */
|
||||
@@ -0,0 +1,250 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef TASK_H_
|
||||
#define TASK_H_
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||
# include "stdint-msvc2008.h"
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32)
|
||||
# include <sys/time.h>
|
||||
# include <sys/resource.h> /* setrlimit() */
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic ignored "-Wvariadic-macros"
|
||||
# pragma clang diagnostic ignored "-Wc99-extensions"
|
||||
#endif
|
||||
|
||||
#define TEST_PORT 9123
|
||||
#define TEST_PORT_2 9124
|
||||
|
||||
#ifdef _WIN32
|
||||
# define TEST_PIPENAME "\\\\?\\pipe\\uv-test"
|
||||
# define TEST_PIPENAME_2 "\\\\?\\pipe\\uv-test2"
|
||||
#else
|
||||
# define TEST_PIPENAME "/tmp/uv-test-sock"
|
||||
# define TEST_PIPENAME_2 "/tmp/uv-test-sock2"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <io.h>
|
||||
# ifndef S_IRUSR
|
||||
# define S_IRUSR _S_IREAD
|
||||
# endif
|
||||
# ifndef S_IWUSR
|
||||
# define S_IWUSR _S_IWRITE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define container_of(ptr, type, member) \
|
||||
((type *) ((char *) (ptr) - offsetof(type, member)))
|
||||
|
||||
typedef enum {
|
||||
TCP = 0,
|
||||
UDP,
|
||||
PIPE
|
||||
} stream_type;
|
||||
|
||||
/* Die with fatal error. */
|
||||
#define FATAL(msg) \
|
||||
do { \
|
||||
fprintf(stderr, \
|
||||
"Fatal error in %s on line %d: %s\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
msg); \
|
||||
fflush(stderr); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
|
||||
/* Have our own assert, so we are sure it does not get optimized away in
|
||||
* a release build.
|
||||
*/
|
||||
#define ASSERT(expr) \
|
||||
do { \
|
||||
if (!(expr)) { \
|
||||
fprintf(stderr, \
|
||||
"Assertion failed in %s on line %d: %s\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
#expr); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* This macro cleans up the main loop. This is used to avoid valgrind
|
||||
* warnings about memory being "leaked" by the main event loop.
|
||||
*/
|
||||
#define MAKE_VALGRIND_HAPPY() \
|
||||
do { \
|
||||
close_loop(uv_default_loop()); \
|
||||
uv_loop_delete(uv_default_loop()); \
|
||||
} while (0)
|
||||
|
||||
/* Just sugar for wrapping the main() for a task or helper. */
|
||||
#define TEST_IMPL(name) \
|
||||
int run_test_##name(void); \
|
||||
int run_test_##name(void)
|
||||
|
||||
#define BENCHMARK_IMPL(name) \
|
||||
int run_benchmark_##name(void); \
|
||||
int run_benchmark_##name(void)
|
||||
|
||||
#define HELPER_IMPL(name) \
|
||||
int run_helper_##name(void); \
|
||||
int run_helper_##name(void)
|
||||
|
||||
/* Pause the calling thread for a number of milliseconds. */
|
||||
void uv_sleep(int msec);
|
||||
|
||||
/* Format big numbers nicely. WARNING: leaks memory. */
|
||||
const char* fmt(double d);
|
||||
|
||||
/* Reserved test exit codes. */
|
||||
enum test_status {
|
||||
TEST_OK = 0,
|
||||
TEST_TODO,
|
||||
TEST_SKIP
|
||||
};
|
||||
|
||||
#define RETURN_OK() \
|
||||
do { \
|
||||
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); \
|
||||
fflush(stderr); \
|
||||
return TEST_SKIP; \
|
||||
} while (0)
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
||||
# define TEST_FILE_LIMIT(num) \
|
||||
do { \
|
||||
struct rlimit lim; \
|
||||
lim.rlim_cur = (num); \
|
||||
lim.rlim_max = lim.rlim_cur; \
|
||||
if (setrlimit(RLIMIT_NOFILE, &lim)) \
|
||||
RETURN_SKIP("File descriptor limit too low."); \
|
||||
} while (0)
|
||||
|
||||
#else /* defined(_WIN32) */
|
||||
|
||||
# define TEST_FILE_LIMIT(num) do {} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if defined _WIN32 && ! defined __GNUC__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Define inline for MSVC<2015 */
|
||||
# if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
# define inline __inline
|
||||
# endif
|
||||
|
||||
# if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer
|
||||
* on overflow...
|
||||
*/
|
||||
inline int snprintf(char* buf, size_t len, const char* fmt, ...) {
|
||||
va_list ap;
|
||||
int n;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = _vsprintf_p(buf, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* It's a sad fact of life that no one ever checks the return value of
|
||||
* snprintf(). Zero-terminating the buffer hopefully reduces the risk
|
||||
* of gaping security holes.
|
||||
*/
|
||||
if (n < 0)
|
||||
if (len > 0)
|
||||
buf[0] = '\0';
|
||||
|
||||
return n;
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || \
|
||||
defined(__GNUC__) || \
|
||||
defined(__INTEL_COMPILER) || \
|
||||
defined(__SUNPRO_C)
|
||||
# define UNUSED __attribute__((unused))
|
||||
#else
|
||||
# define UNUSED
|
||||
#endif
|
||||
|
||||
/* Fully close a loop */
|
||||
static void close_walk_cb(uv_handle_t* handle, void* arg) {
|
||||
if (!uv_is_closing(handle))
|
||||
uv_close(handle, NULL);
|
||||
}
|
||||
|
||||
UNUSED static void close_loop(uv_loop_t* loop) {
|
||||
uv_walk(loop, close_walk_cb, NULL);
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
UNUSED static int can_ipv6(void) {
|
||||
uv_interface_address_t* addr;
|
||||
int supported;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
if (uv_interface_addresses(&addr, &count))
|
||||
return 1; /* Assume IPv6 support on failure. */
|
||||
|
||||
supported = 0;
|
||||
for (i = 0; supported == 0 && i < count; i += 1)
|
||||
supported = (AF_INET6 == addr[i].address.address6.sin6_family);
|
||||
|
||||
uv_free_interface_addresses(addr, count);
|
||||
return supported;
|
||||
}
|
||||
|
||||
#endif /* TASK_H_ */
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
static int close_cb_called = 0;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle != NULL);
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
ASSERT(0 && "timer_cb should not have been called");
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(active) {
|
||||
int r;
|
||||
uv_timer_t timer;
|
||||
|
||||
r = uv_timer_init(uv_default_loop(), &timer);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* uv_is_active() and uv_is_closing() should always return either 0 or 1. */
|
||||
ASSERT(0 == uv_is_active((uv_handle_t*) &timer));
|
||||
ASSERT(0 == uv_is_closing((uv_handle_t*) &timer));
|
||||
|
||||
r = uv_timer_start(&timer, timer_cb, 1000, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(1 == uv_is_active((uv_handle_t*) &timer));
|
||||
ASSERT(0 == uv_is_closing((uv_handle_t*) &timer));
|
||||
|
||||
r = uv_timer_stop(&timer);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(0 == uv_is_active((uv_handle_t*) &timer));
|
||||
ASSERT(0 == uv_is_closing((uv_handle_t*) &timer));
|
||||
|
||||
r = uv_timer_start(&timer, timer_cb, 1000, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(1 == uv_is_active((uv_handle_t*) &timer));
|
||||
ASSERT(0 == uv_is_closing((uv_handle_t*) &timer));
|
||||
|
||||
uv_close((uv_handle_t*) &timer, close_cb);
|
||||
|
||||
ASSERT(0 == uv_is_active((uv_handle_t*) &timer));
|
||||
ASSERT(1 == uv_is_closing((uv_handle_t*) &timer));
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/* 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_async_t async_handle;
|
||||
static uv_check_t check_handle;
|
||||
static int check_cb_called;
|
||||
static uv_thread_t thread;
|
||||
|
||||
|
||||
static void thread_cb(void* dummy) {
|
||||
(void) &dummy;
|
||||
uv_async_send(&async_handle);
|
||||
}
|
||||
|
||||
|
||||
static void check_cb(uv_check_t* handle) {
|
||||
ASSERT(check_cb_called == 0);
|
||||
uv_close((uv_handle_t*) &async_handle, NULL);
|
||||
uv_close((uv_handle_t*) &check_handle, NULL);
|
||||
check_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(async_null_cb) {
|
||||
ASSERT(0 == uv_async_init(uv_default_loop(), &async_handle, NULL));
|
||||
ASSERT(0 == uv_check_init(uv_default_loop(), &check_handle));
|
||||
ASSERT(0 == uv_check_start(&check_handle, check_cb));
|
||||
ASSERT(0 == uv_thread_create(&thread, thread_cb, NULL));
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
ASSERT(1 == check_cb_called);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/* 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>
|
||||
|
||||
static uv_thread_t thread;
|
||||
static uv_mutex_t mutex;
|
||||
|
||||
static uv_prepare_t prepare;
|
||||
static uv_async_t async;
|
||||
|
||||
static volatile int async_cb_called;
|
||||
static int prepare_cb_called;
|
||||
static int close_cb_called;
|
||||
|
||||
|
||||
static void thread_cb(void *arg) {
|
||||
int n;
|
||||
int r;
|
||||
|
||||
for (;;) {
|
||||
uv_mutex_lock(&mutex);
|
||||
n = async_cb_called;
|
||||
uv_mutex_unlock(&mutex);
|
||||
|
||||
if (n == 3) {
|
||||
break;
|
||||
}
|
||||
|
||||
r = uv_async_send(&async);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Work around a bug in Valgrind.
|
||||
*
|
||||
* Valgrind runs threads not in parallel but sequentially, i.e. one after
|
||||
* the other. It also doesn't preempt them, instead it depends on threads
|
||||
* yielding voluntarily by making a syscall.
|
||||
*
|
||||
* That never happens here: the pipe that is associated with the async
|
||||
* handle is written to once but that's too early for Valgrind's scheduler
|
||||
* to kick in. Afterwards, the thread busy-loops, starving the main thread.
|
||||
* Therefore, we yield.
|
||||
*
|
||||
* This behavior has been observed with Valgrind 3.7.0 and 3.9.0.
|
||||
*/
|
||||
uv_sleep(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle != NULL);
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void async_cb(uv_async_t* handle) {
|
||||
int n;
|
||||
|
||||
ASSERT(handle == &async);
|
||||
|
||||
uv_mutex_lock(&mutex);
|
||||
n = ++async_cb_called;
|
||||
uv_mutex_unlock(&mutex);
|
||||
|
||||
if (n == 3) {
|
||||
uv_close((uv_handle_t*)&async, close_cb);
|
||||
uv_close((uv_handle_t*)&prepare, close_cb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void prepare_cb(uv_prepare_t* handle) {
|
||||
int r;
|
||||
|
||||
ASSERT(handle == &prepare);
|
||||
|
||||
if (prepare_cb_called++)
|
||||
return;
|
||||
|
||||
r = uv_thread_create(&thread, thread_cb, NULL);
|
||||
ASSERT(r == 0);
|
||||
uv_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(async) {
|
||||
int r;
|
||||
|
||||
r = uv_mutex_init(&mutex);
|
||||
ASSERT(r == 0);
|
||||
uv_mutex_lock(&mutex);
|
||||
|
||||
r = uv_prepare_init(uv_default_loop(), &prepare);
|
||||
ASSERT(r == 0);
|
||||
r = uv_prepare_start(&prepare, prepare_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_async_init(uv_default_loop(), &async, async_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(prepare_cb_called > 0);
|
||||
ASSERT(async_cb_called == 3);
|
||||
ASSERT(close_cb_called == 2);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/* 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 <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
typedef struct {
|
||||
uv_barrier_t barrier;
|
||||
int delay;
|
||||
volatile int posted;
|
||||
int main_barrier_wait_rval;
|
||||
int worker_barrier_wait_rval;
|
||||
} worker_config;
|
||||
|
||||
|
||||
static void worker(void* arg) {
|
||||
worker_config* c = arg;
|
||||
|
||||
if (c->delay)
|
||||
uv_sleep(c->delay);
|
||||
|
||||
c->worker_barrier_wait_rval = uv_barrier_wait(&c->barrier);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(barrier_1) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
|
||||
ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_sleep(100);
|
||||
wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_barrier_destroy(&wc.barrier);
|
||||
|
||||
ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(barrier_2) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.delay = 100;
|
||||
|
||||
ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_barrier_destroy(&wc.barrier);
|
||||
|
||||
ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(barrier_3) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
|
||||
ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_barrier_destroy(&wc.barrier);
|
||||
|
||||
ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/* 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 int idle_cb_called;
|
||||
static int timer_cb_called;
|
||||
|
||||
static uv_idle_t idle_handle;
|
||||
static uv_timer_t timer_handle;
|
||||
|
||||
|
||||
/* idle_cb should run before timer_cb */
|
||||
static void idle_cb(uv_idle_t* handle) {
|
||||
ASSERT(idle_cb_called == 0);
|
||||
ASSERT(timer_cb_called == 0);
|
||||
uv_idle_stop(handle);
|
||||
idle_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
ASSERT(idle_cb_called == 1);
|
||||
ASSERT(timer_cb_called == 0);
|
||||
uv_timer_stop(handle);
|
||||
timer_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void next_tick(uv_idle_t* handle) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
uv_idle_stop(handle);
|
||||
uv_idle_init(loop, &idle_handle);
|
||||
uv_idle_start(&idle_handle, idle_cb);
|
||||
uv_timer_init(loop, &timer_handle);
|
||||
uv_timer_start(&timer_handle, timer_cb, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(callback_order) {
|
||||
uv_loop_t* loop;
|
||||
uv_idle_t idle;
|
||||
|
||||
loop = uv_default_loop();
|
||||
uv_idle_init(loop, &idle);
|
||||
uv_idle_start(&idle, next_tick);
|
||||
|
||||
ASSERT(idle_cb_called == 0);
|
||||
ASSERT(timer_cb_called == 0);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(idle_cb_called == 1);
|
||||
ASSERT(timer_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: Add explanation of why we want on_close to be called from fresh
|
||||
* stack.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
|
||||
static const char MESSAGE[] = "Failure is for the weak. Everyone dies alone.";
|
||||
|
||||
static uv_tcp_t client;
|
||||
static uv_timer_t timer;
|
||||
static uv_connect_t connect_req;
|
||||
static uv_write_t write_req;
|
||||
static uv_shutdown_t shutdown_req;
|
||||
|
||||
static int nested = 0;
|
||||
static int close_cb_called = 0;
|
||||
static int connect_cb_called = 0;
|
||||
static int write_cb_called = 0;
|
||||
static int timer_cb_called = 0;
|
||||
static int bytes_received = 0;
|
||||
static int shutdown_cb_called = 0;
|
||||
|
||||
|
||||
static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
|
||||
buf->len = size;
|
||||
buf->base = malloc(size);
|
||||
ASSERT(buf->base != NULL);
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
ASSERT(nested == 0 && "close_cb must be called from a fresh stack");
|
||||
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void shutdown_cb(uv_shutdown_t* req, int status) {
|
||||
ASSERT(status == 0);
|
||||
ASSERT(nested == 0 && "shutdown_cb must be called from a fresh stack");
|
||||
|
||||
shutdown_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
|
||||
ASSERT(nested == 0 && "read_cb must be called from a fresh stack");
|
||||
|
||||
printf("Read. nread == %d\n", (int)nread);
|
||||
free(buf->base);
|
||||
|
||||
if (nread == 0) {
|
||||
return;
|
||||
|
||||
} else if (nread < 0) {
|
||||
ASSERT(nread == UV_EOF);
|
||||
|
||||
nested++;
|
||||
uv_close((uv_handle_t*)tcp, close_cb);
|
||||
nested--;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bytes_received += nread;
|
||||
|
||||
/* We call shutdown here because when bytes_received == sizeof MESSAGE */
|
||||
/* there will be no more data sent nor received, so here it would be */
|
||||
/* possible for a backend to to call shutdown_cb immediately and *not* */
|
||||
/* from a fresh stack. */
|
||||
if (bytes_received == sizeof MESSAGE) {
|
||||
nested++;
|
||||
|
||||
puts("Shutdown");
|
||||
|
||||
if (uv_shutdown(&shutdown_req, (uv_stream_t*)tcp, shutdown_cb)) {
|
||||
FATAL("uv_shutdown failed");
|
||||
}
|
||||
nested--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
ASSERT(handle == &timer);
|
||||
ASSERT(nested == 0 && "timer_cb must be called from a fresh stack");
|
||||
|
||||
puts("Timeout complete. Now read data...");
|
||||
|
||||
nested++;
|
||||
if (uv_read_start((uv_stream_t*)&client, alloc_cb, read_cb)) {
|
||||
FATAL("uv_read_start failed");
|
||||
}
|
||||
nested--;
|
||||
|
||||
timer_cb_called++;
|
||||
|
||||
uv_close((uv_handle_t*)handle, close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void write_cb(uv_write_t* req, int status) {
|
||||
int r;
|
||||
|
||||
ASSERT(status == 0);
|
||||
ASSERT(nested == 0 && "write_cb must be called from a fresh stack");
|
||||
|
||||
puts("Data written. 500ms timeout...");
|
||||
|
||||
/* After the data has been sent, we're going to wait for a while, then */
|
||||
/* start reading. This makes us certain that the message has been echoed */
|
||||
/* back to our receive buffer when we start reading. This maximizes the */
|
||||
/* temptation for the backend to use dirty stack for calling read_cb. */
|
||||
nested++;
|
||||
r = uv_timer_init(uv_default_loop(), &timer);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_start(&timer, timer_cb, 500, 0);
|
||||
ASSERT(r == 0);
|
||||
nested--;
|
||||
|
||||
write_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
uv_buf_t buf;
|
||||
|
||||
puts("Connected. Write some data to echo server...");
|
||||
|
||||
ASSERT(status == 0);
|
||||
ASSERT(nested == 0 && "connect_cb must be called from a fresh stack");
|
||||
|
||||
nested++;
|
||||
|
||||
buf.base = (char*) &MESSAGE;
|
||||
buf.len = sizeof MESSAGE;
|
||||
|
||||
if (uv_write(&write_req, (uv_stream_t*)req->handle, &buf, 1, write_cb)) {
|
||||
FATAL("uv_write failed");
|
||||
}
|
||||
|
||||
nested--;
|
||||
|
||||
connect_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(callback_stack) {
|
||||
struct sockaddr_in addr;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
if (uv_tcp_init(uv_default_loop(), &client)) {
|
||||
FATAL("uv_tcp_init failed");
|
||||
}
|
||||
|
||||
puts("Connecting...");
|
||||
|
||||
nested++;
|
||||
|
||||
if (uv_tcp_connect(&connect_req,
|
||||
&client,
|
||||
(const struct sockaddr*) &addr,
|
||||
connect_cb)) {
|
||||
FATAL("uv_tcp_connect failed");
|
||||
}
|
||||
nested--;
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(nested == 0);
|
||||
ASSERT(connect_cb_called == 1 && "connect_cb must be called exactly once");
|
||||
ASSERT(write_cb_called == 1 && "write_cb must be called exactly once");
|
||||
ASSERT(timer_cb_called == 1 && "timer_cb must be called exactly once");
|
||||
ASSERT(bytes_received == sizeof MESSAGE);
|
||||
ASSERT(shutdown_cb_called == 1 && "shutdown_cb must be called exactly once");
|
||||
ASSERT(close_cb_called == 2 && "close_cb must be called exactly twice");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static unsigned int read_cb_called;
|
||||
|
||||
static void alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
|
||||
static char slab[1];
|
||||
buf->base = slab;
|
||||
buf->len = sizeof(slab);
|
||||
}
|
||||
|
||||
static void read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) {
|
||||
switch (++read_cb_called) {
|
||||
case 1:
|
||||
ASSERT(nread == 1);
|
||||
uv_read_stop(handle);
|
||||
break;
|
||||
case 2:
|
||||
ASSERT(nread == UV_EOF);
|
||||
uv_close((uv_handle_t *) handle, NULL);
|
||||
break;
|
||||
default:
|
||||
ASSERT(!"read_cb_called > 2");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_IMPL(close_fd) {
|
||||
uv_pipe_t pipe_handle;
|
||||
int fd[2];
|
||||
|
||||
ASSERT(0 == pipe(fd));
|
||||
ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
|
||||
ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
|
||||
fd[0] = -1; /* uv_pipe_open() takes ownership of the file descriptor. */
|
||||
ASSERT(1 == write(fd[1], "", 1));
|
||||
ASSERT(0 == close(fd[1]));
|
||||
fd[1] = -1;
|
||||
ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb));
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
ASSERT(1 == read_cb_called);
|
||||
ASSERT(0 == uv_is_active((const uv_handle_t *) &pipe_handle));
|
||||
ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb));
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
ASSERT(2 == read_cb_called);
|
||||
ASSERT(0 != uv_is_closing((const uv_handle_t *) &pipe_handle));
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !defined(_WIN32) */
|
||||
@@ -0,0 +1,80 @@
|
||||
/* 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 int check_cb_called;
|
||||
static int timer_cb_called;
|
||||
static int close_cb_called;
|
||||
|
||||
static uv_check_t check_handle;
|
||||
static uv_timer_t timer_handle1;
|
||||
static uv_timer_t timer_handle2;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle != NULL);
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
/* check_cb should run before any close_cb */
|
||||
static void check_cb(uv_check_t* handle) {
|
||||
ASSERT(check_cb_called == 0);
|
||||
ASSERT(timer_cb_called == 1);
|
||||
ASSERT(close_cb_called == 0);
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
uv_close((uv_handle_t*) &timer_handle2, close_cb);
|
||||
check_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
timer_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(close_order) {
|
||||
uv_loop_t* loop;
|
||||
loop = uv_default_loop();
|
||||
|
||||
uv_check_init(loop, &check_handle);
|
||||
uv_check_start(&check_handle, check_cb);
|
||||
uv_timer_init(loop, &timer_handle1);
|
||||
uv_timer_start(&timer_handle1, timer_cb, 0, 0);
|
||||
uv_timer_init(loop, &timer_handle2);
|
||||
uv_timer_start(&timer_handle2, timer_cb, 100000, 0);
|
||||
|
||||
ASSERT(check_cb_called == 0);
|
||||
ASSERT(close_cb_called == 0);
|
||||
ASSERT(timer_cb_called == 0);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(check_cb_called == 1);
|
||||
ASSERT(close_cb_called == 3);
|
||||
ASSERT(timer_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/* 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 <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
typedef struct {
|
||||
uv_mutex_t mutex;
|
||||
uv_cond_t cond;
|
||||
int delay;
|
||||
int use_broadcast;
|
||||
volatile int posted;
|
||||
} worker_config;
|
||||
|
||||
|
||||
static void worker(void* arg) {
|
||||
worker_config* c = arg;
|
||||
|
||||
if (c->delay)
|
||||
uv_sleep(c->delay);
|
||||
|
||||
uv_mutex_lock(&c->mutex);
|
||||
ASSERT(c->posted == 0);
|
||||
c->posted = 1;
|
||||
if (c->use_broadcast)
|
||||
uv_cond_broadcast(&c->cond);
|
||||
else
|
||||
uv_cond_signal(&c->cond);
|
||||
uv_mutex_unlock(&c->mutex);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(condvar_1) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
|
||||
ASSERT(0 == uv_cond_init(&wc.cond));
|
||||
ASSERT(0 == uv_mutex_init(&wc.mutex));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_mutex_lock(&wc.mutex);
|
||||
uv_sleep(100);
|
||||
uv_cond_wait(&wc.cond, &wc.mutex);
|
||||
ASSERT(wc.posted == 1);
|
||||
uv_mutex_unlock(&wc.mutex);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_mutex_destroy(&wc.mutex);
|
||||
uv_cond_destroy(&wc.cond);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(condvar_2) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.delay = 100;
|
||||
|
||||
ASSERT(0 == uv_cond_init(&wc.cond));
|
||||
ASSERT(0 == uv_mutex_init(&wc.mutex));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_mutex_lock(&wc.mutex);
|
||||
uv_cond_wait(&wc.cond, &wc.mutex);
|
||||
uv_mutex_unlock(&wc.mutex);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_mutex_destroy(&wc.mutex);
|
||||
uv_cond_destroy(&wc.cond);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(condvar_3) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
int r;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.delay = 100;
|
||||
|
||||
ASSERT(0 == uv_cond_init(&wc.cond));
|
||||
ASSERT(0 == uv_mutex_init(&wc.mutex));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_mutex_lock(&wc.mutex);
|
||||
r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(50 * 1e6));
|
||||
ASSERT(r == UV_ETIMEDOUT);
|
||||
uv_mutex_unlock(&wc.mutex);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_mutex_destroy(&wc.mutex);
|
||||
uv_cond_destroy(&wc.cond);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(condvar_4) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
int r;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.delay = 100;
|
||||
|
||||
ASSERT(0 == uv_cond_init(&wc.cond));
|
||||
ASSERT(0 == uv_mutex_init(&wc.mutex));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_mutex_lock(&wc.mutex);
|
||||
r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(150 * 1e6));
|
||||
ASSERT(r == 0);
|
||||
uv_mutex_unlock(&wc.mutex);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_mutex_destroy(&wc.mutex);
|
||||
uv_cond_destroy(&wc.cond);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(condvar_5) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.use_broadcast = 1;
|
||||
|
||||
ASSERT(0 == uv_cond_init(&wc.cond));
|
||||
ASSERT(0 == uv_mutex_init(&wc.mutex));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_mutex_lock(&wc.mutex);
|
||||
uv_sleep(100);
|
||||
uv_cond_wait(&wc.cond, &wc.mutex);
|
||||
ASSERT(wc.posted == 1);
|
||||
uv_mutex_unlock(&wc.mutex);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_mutex_destroy(&wc.mutex);
|
||||
uv_cond_destroy(&wc.cond);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
static uv_tcp_t tcp;
|
||||
static uv_connect_t req;
|
||||
static int connect_cb_calls;
|
||||
static int close_cb_calls;
|
||||
|
||||
static uv_timer_t timer;
|
||||
static int timer_close_cb_calls;
|
||||
static int timer_cb_calls;
|
||||
|
||||
|
||||
static void on_close(uv_handle_t* handle) {
|
||||
close_cb_calls++;
|
||||
}
|
||||
|
||||
|
||||
static void timer_close_cb(uv_handle_t* handle) {
|
||||
timer_close_cb_calls++;
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
timer_cb_calls++;
|
||||
|
||||
/*
|
||||
* These are the important asserts. The connection callback has been made,
|
||||
* but libuv hasn't automatically closed the socket. The user must
|
||||
* uv_close the handle manually.
|
||||
*/
|
||||
ASSERT(close_cb_calls == 0);
|
||||
ASSERT(connect_cb_calls == 1);
|
||||
|
||||
/* Close the tcp handle. */
|
||||
uv_close((uv_handle_t*)&tcp, on_close);
|
||||
|
||||
/* Close the timer. */
|
||||
uv_close((uv_handle_t*)handle, timer_close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void on_connect_with_close(uv_connect_t *req, int status) {
|
||||
ASSERT((uv_stream_t*) &tcp == req->handle);
|
||||
ASSERT(status == UV_ECONNREFUSED);
|
||||
connect_cb_calls++;
|
||||
|
||||
ASSERT(close_cb_calls == 0);
|
||||
uv_close((uv_handle_t*)req->handle, on_close);
|
||||
}
|
||||
|
||||
|
||||
static void on_connect_without_close(uv_connect_t *req, int status) {
|
||||
ASSERT(status == UV_ECONNREFUSED);
|
||||
connect_cb_calls++;
|
||||
|
||||
uv_timer_start(&timer, timer_cb, 100, 0);
|
||||
|
||||
ASSERT(close_cb_calls == 0);
|
||||
}
|
||||
|
||||
|
||||
static void connection_fail(uv_connect_cb connect_cb) {
|
||||
struct sockaddr_in client_addr, server_addr;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &client_addr));
|
||||
|
||||
/* There should be no servers listening on this port. */
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
|
||||
|
||||
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp);
|
||||
ASSERT(!r);
|
||||
|
||||
/* We are never doing multiple reads/connects at a time anyway. */
|
||||
/* so these handles can be pre-initialized. */
|
||||
ASSERT(0 == uv_tcp_bind(&tcp, (const struct sockaddr*) &client_addr, 0));
|
||||
|
||||
r = uv_tcp_connect(&req,
|
||||
&tcp,
|
||||
(const struct sockaddr*) &server_addr,
|
||||
connect_cb);
|
||||
ASSERT(!r);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(connect_cb_calls == 1);
|
||||
ASSERT(close_cb_calls == 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This test attempts to connect to a port where no server is running. We
|
||||
* expect an error.
|
||||
*/
|
||||
TEST_IMPL(connection_fail) {
|
||||
connection_fail(on_connect_with_close);
|
||||
|
||||
ASSERT(timer_close_cb_calls == 0);
|
||||
ASSERT(timer_cb_calls == 0);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This test is the same as the first except it check that the close
|
||||
* callback of the tcp handle hasn't been made after the failed connection
|
||||
* attempt.
|
||||
*/
|
||||
TEST_IMPL(connection_fail_doesnt_auto_close) {
|
||||
int r;
|
||||
|
||||
r = uv_timer_init(uv_default_loop(), &timer);
|
||||
ASSERT(r == 0);
|
||||
|
||||
connection_fail(on_connect_without_close);
|
||||
|
||||
ASSERT(timer_close_cb_calls == 1);
|
||||
ASSERT(timer_cb_calls == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
#define PATHMAX 1024
|
||||
extern char executable_path[];
|
||||
|
||||
TEST_IMPL(cwd_and_chdir) {
|
||||
char buffer_orig[PATHMAX];
|
||||
char buffer_new[PATHMAX];
|
||||
size_t size1;
|
||||
size_t size2;
|
||||
int err;
|
||||
|
||||
size1 = sizeof buffer_orig;
|
||||
err = uv_cwd(buffer_orig, &size1);
|
||||
ASSERT(err == 0);
|
||||
|
||||
err = uv_chdir(buffer_orig);
|
||||
ASSERT(err == 0);
|
||||
|
||||
size2 = sizeof buffer_new;
|
||||
err = uv_cwd(buffer_new, &size2);
|
||||
ASSERT(err == 0);
|
||||
|
||||
ASSERT(size1 == size2);
|
||||
ASSERT(strcmp(buffer_orig, buffer_new) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/* 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 int timer_cb_called;
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* timer) {
|
||||
timer_cb_called++;
|
||||
uv_close((uv_handle_t*) timer, NULL);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(default_loop_close) {
|
||||
uv_loop_t* loop;
|
||||
uv_timer_t timer_handle;
|
||||
|
||||
loop = uv_default_loop();
|
||||
ASSERT(loop != NULL);
|
||||
|
||||
ASSERT(0 == uv_timer_init(loop, &timer_handle));
|
||||
ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0));
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
ASSERT(1 == timer_cb_called);
|
||||
ASSERT(0 == uv_loop_close(loop));
|
||||
|
||||
loop = uv_default_loop();
|
||||
ASSERT(loop != NULL);
|
||||
|
||||
ASSERT(0 == uv_timer_init(loop, &timer_handle));
|
||||
ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0));
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
ASSERT(2 == timer_cb_called);
|
||||
ASSERT(0 == uv_loop_close(loop));
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/* 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>
|
||||
|
||||
static int connection_cb_called = 0;
|
||||
static int do_accept_called = 0;
|
||||
static int close_cb_called = 0;
|
||||
static int connect_cb_called = 0;
|
||||
|
||||
|
||||
static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
|
||||
buf->base = malloc(size);
|
||||
buf->len = size;
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle != NULL);
|
||||
|
||||
free(handle);
|
||||
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void do_accept(uv_timer_t* timer_handle) {
|
||||
uv_tcp_t* server;
|
||||
uv_tcp_t* accepted_handle = (uv_tcp_t*)malloc(sizeof *accepted_handle);
|
||||
int r;
|
||||
|
||||
ASSERT(timer_handle != NULL);
|
||||
ASSERT(accepted_handle != NULL);
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), accepted_handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
server = (uv_tcp_t*)timer_handle->data;
|
||||
r = uv_accept((uv_stream_t*)server, (uv_stream_t*)accepted_handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
do_accept_called++;
|
||||
|
||||
/* Immediately close the accepted handle. */
|
||||
uv_close((uv_handle_t*)accepted_handle, close_cb);
|
||||
|
||||
/* After accepting the two clients close the server handle */
|
||||
if (do_accept_called == 2) {
|
||||
uv_close((uv_handle_t*)server, close_cb);
|
||||
}
|
||||
|
||||
/* Dispose the timer. */
|
||||
uv_close((uv_handle_t*)timer_handle, close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void connection_cb(uv_stream_t* tcp, int status) {
|
||||
int r;
|
||||
uv_timer_t* timer_handle;
|
||||
|
||||
ASSERT(status == 0);
|
||||
|
||||
timer_handle = (uv_timer_t*)malloc(sizeof *timer_handle);
|
||||
ASSERT(timer_handle != NULL);
|
||||
|
||||
/* Accept the client after 1 second */
|
||||
r = uv_timer_init(uv_default_loop(), timer_handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
timer_handle->data = tcp;
|
||||
|
||||
r = uv_timer_start(timer_handle, do_accept, 1000, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
connection_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void start_server(void) {
|
||||
struct sockaddr_in addr;
|
||||
uv_tcp_t* server = (uv_tcp_t*)malloc(sizeof *server);
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
ASSERT(server != NULL);
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), server);
|
||||
ASSERT(r == 0);
|
||||
r = uv_tcp_bind(server, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*)server, 128, connection_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
|
||||
/* The server will not send anything, it should close gracefully. */
|
||||
|
||||
if (buf->base) {
|
||||
free(buf->base);
|
||||
}
|
||||
|
||||
if (nread >= 0) {
|
||||
ASSERT(nread == 0);
|
||||
} else {
|
||||
ASSERT(tcp != NULL);
|
||||
ASSERT(nread == UV_EOF);
|
||||
uv_close((uv_handle_t*)tcp, close_cb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
int r;
|
||||
|
||||
ASSERT(req != NULL);
|
||||
ASSERT(status == 0);
|
||||
|
||||
/* Not that the server will send anything, but otherwise we'll never know */
|
||||
/* when the server closes the connection. */
|
||||
r = uv_read_start((uv_stream_t*)(req->handle), alloc_cb, read_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
connect_cb_called++;
|
||||
|
||||
free(req);
|
||||
}
|
||||
|
||||
|
||||
static void client_connect(void) {
|
||||
struct sockaddr_in addr;
|
||||
uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof *client);
|
||||
uv_connect_t* connect_req = malloc(sizeof *connect_req);
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
ASSERT(client != NULL);
|
||||
ASSERT(connect_req != NULL);
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), client);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_connect(connect_req,
|
||||
client,
|
||||
(const struct sockaddr*) &addr,
|
||||
connect_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_IMPL(delayed_accept) {
|
||||
start_server();
|
||||
|
||||
client_connect();
|
||||
client_connect();
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(connection_cb_called == 2);
|
||||
ASSERT(do_accept_called == 2);
|
||||
ASSERT(connect_cb_called == 2);
|
||||
ASSERT(close_cb_called == 7);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
|
||||
TEST_IMPL(dlerror) {
|
||||
const char* path = "test/fixtures/load_error.node";
|
||||
const char* dlerror_no_error = "no error";
|
||||
const char* msg;
|
||||
uv_lib_t lib;
|
||||
int r;
|
||||
|
||||
lib.errmsg = NULL;
|
||||
lib.handle = NULL;
|
||||
msg = uv_dlerror(&lib);
|
||||
ASSERT(msg != NULL);
|
||||
ASSERT(strstr(msg, dlerror_no_error) != NULL);
|
||||
|
||||
r = uv_dlopen(path, &lib);
|
||||
ASSERT(r == -1);
|
||||
|
||||
msg = uv_dlerror(&lib);
|
||||
ASSERT(msg != NULL);
|
||||
ASSERT(strstr(msg, dlerror_no_error) == NULL);
|
||||
|
||||
/* Should return the same error twice in a row. */
|
||||
msg = uv_dlerror(&lib);
|
||||
ASSERT(msg != NULL);
|
||||
ASSERT(strstr(msg, dlerror_no_error) == NULL);
|
||||
|
||||
uv_dlclose(&lib);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/* 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 <errno.h>
|
||||
|
||||
#ifndef HAVE_KQUEUE
|
||||
# if defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# define HAVE_KQUEUE 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_EPOLL
|
||||
# if defined(__linux__)
|
||||
# define HAVE_EPOLL 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
|
||||
|
||||
#if defined(HAVE_KQUEUE)
|
||||
# include <sys/types.h>
|
||||
# include <sys/event.h>
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_EPOLL)
|
||||
# include <sys/epoll.h>
|
||||
#endif
|
||||
|
||||
static uv_thread_t embed_thread;
|
||||
static uv_sem_t embed_sem;
|
||||
static uv_timer_t embed_timer;
|
||||
static uv_async_t embed_async;
|
||||
static volatile int embed_closed;
|
||||
|
||||
static int embed_timer_called;
|
||||
|
||||
|
||||
static void embed_thread_runner(void* arg) {
|
||||
int r;
|
||||
int fd;
|
||||
int timeout;
|
||||
|
||||
while (!embed_closed) {
|
||||
fd = uv_backend_fd(uv_default_loop());
|
||||
timeout = uv_backend_timeout(uv_default_loop());
|
||||
|
||||
do {
|
||||
#if defined(HAVE_KQUEUE)
|
||||
struct timespec ts;
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout % 1000) * 1000000;
|
||||
r = kevent(fd, NULL, 0, NULL, 0, &ts);
|
||||
#elif defined(HAVE_EPOLL)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
r = epoll_wait(fd, &ev, 1, timeout);
|
||||
}
|
||||
#endif
|
||||
} while (r == -1 && errno == EINTR);
|
||||
uv_async_send(&embed_async);
|
||||
uv_sem_wait(&embed_sem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void embed_cb(uv_async_t* async) {
|
||||
uv_run(uv_default_loop(), UV_RUN_ONCE);
|
||||
|
||||
uv_sem_post(&embed_sem);
|
||||
}
|
||||
|
||||
|
||||
static void embed_timer_cb(uv_timer_t* timer) {
|
||||
embed_timer_called++;
|
||||
embed_closed = 1;
|
||||
|
||||
uv_close((uv_handle_t*) &embed_async, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
TEST_IMPL(embed) {
|
||||
#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
|
||||
uv_loop_t external;
|
||||
|
||||
ASSERT(0 == uv_loop_init(&external));
|
||||
|
||||
embed_timer_called = 0;
|
||||
embed_closed = 0;
|
||||
|
||||
uv_async_init(&external, &embed_async, embed_cb);
|
||||
|
||||
/* Start timer in default loop */
|
||||
uv_timer_init(uv_default_loop(), &embed_timer);
|
||||
uv_timer_start(&embed_timer, embed_timer_cb, 250, 0);
|
||||
|
||||
/* Start worker that will interrupt external loop */
|
||||
uv_sem_init(&embed_sem, 0);
|
||||
uv_thread_create(&embed_thread, embed_thread_runner, NULL);
|
||||
|
||||
/* But run external loop */
|
||||
uv_run(&external, UV_RUN_DEFAULT);
|
||||
|
||||
uv_thread_join(&embed_thread);
|
||||
uv_loop_close(&external);
|
||||
|
||||
ASSERT(embed_timer_called == 1);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void connection_cb(uv_stream_t* server_handle, int status);
|
||||
static void connect_cb(uv_connect_t* req, int status);
|
||||
|
||||
static const int maxfd = 31;
|
||||
static unsigned connect_cb_called;
|
||||
static uv_tcp_t server_handle;
|
||||
static uv_tcp_t client_handle;
|
||||
|
||||
|
||||
TEST_IMPL(emfile) {
|
||||
struct sockaddr_in addr;
|
||||
struct rlimit limits;
|
||||
uv_connect_t connect_req;
|
||||
uv_loop_t* loop;
|
||||
int first_fd;
|
||||
|
||||
loop = uv_default_loop();
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
ASSERT(0 == uv_tcp_init(loop, &server_handle));
|
||||
ASSERT(0 == uv_tcp_init(loop, &client_handle));
|
||||
ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0));
|
||||
ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 8, connection_cb));
|
||||
|
||||
/* Lower the file descriptor limit and use up all fds save one. */
|
||||
limits.rlim_cur = limits.rlim_max = maxfd + 1;
|
||||
if (setrlimit(RLIMIT_NOFILE, &limits)) {
|
||||
perror("setrlimit(RLIMIT_NOFILE)");
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
/* Remember the first one so we can clean up afterwards. */
|
||||
do
|
||||
first_fd = dup(0);
|
||||
while (first_fd == -1 && errno == EINTR);
|
||||
ASSERT(first_fd > 0);
|
||||
|
||||
while (dup(0) != -1 || errno == EINTR);
|
||||
ASSERT(errno == EMFILE);
|
||||
close(maxfd);
|
||||
|
||||
/* Now connect and use up the last available file descriptor. The EMFILE
|
||||
* handling logic in src/unix/stream.c should ensure that connect_cb() runs
|
||||
* whereas connection_cb() should *not* run.
|
||||
*/
|
||||
ASSERT(0 == uv_tcp_connect(&connect_req,
|
||||
&client_handle,
|
||||
(const struct sockaddr*) &addr,
|
||||
connect_cb));
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
ASSERT(1 == connect_cb_called);
|
||||
|
||||
/* Close the dups again. Ignore errors in the unlikely event that the
|
||||
* file descriptors were not contiguous.
|
||||
*/
|
||||
while (first_fd < maxfd) {
|
||||
close(first_fd);
|
||||
first_fd += 1;
|
||||
}
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void connection_cb(uv_stream_t* server_handle, int status) {
|
||||
ASSERT(0 && "connection_cb should not be called.");
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
/* |status| should equal 0 because the connection should have been accepted,
|
||||
* it's just that the server immediately closes it again.
|
||||
*/
|
||||
ASSERT(0 == status);
|
||||
connect_cb_called += 1;
|
||||
uv_close((uv_handle_t*) &server_handle, NULL);
|
||||
uv_close((uv_handle_t*) &client_handle, NULL);
|
||||
}
|
||||
|
||||
#endif /* !defined(_WIN32) */
|
||||
@@ -0,0 +1,50 @@
|
||||
/* 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>
|
||||
|
||||
|
||||
/*
|
||||
* Synthetic errors (errors that originate from within libuv, not the system)
|
||||
* should produce sensible error messages when run through uv_strerror().
|
||||
*
|
||||
* See https://github.com/joyent/libuv/issues/210
|
||||
*/
|
||||
TEST_IMPL(error_message) {
|
||||
/* Cop out. Can't do proper checks on systems with
|
||||
* i18n-ized error messages...
|
||||
*/
|
||||
if (strcmp(uv_strerror(0), "Success") != 0) {
|
||||
printf("i18n error messages detected, skipping test.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ASSERT(strstr(uv_strerror(UV_EINVAL), "Success") == NULL);
|
||||
ASSERT(strcmp(uv_strerror(1337), "Unknown error") == 0);
|
||||
ASSERT(strcmp(uv_strerror(-1337), "Unknown error") == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/* 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 "task.h"
|
||||
|
||||
|
||||
TEST_IMPL(fail_always) {
|
||||
/* This test always fails. It is used to test the test runner. */
|
||||
FATAL("Yes, it always fails");
|
||||
return 2;
|
||||
}
|
||||
@@ -0,0 +1,883 @@
|
||||
/* 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 <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef HAVE_KQUEUE
|
||||
# if defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# define HAVE_KQUEUE 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static uv_fs_event_t fs_event;
|
||||
static const char file_prefix[] = "fsevent-";
|
||||
static const int fs_event_file_count = 16;
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
static const char file_prefix_in_subdir[] = "subdir";
|
||||
#endif
|
||||
static uv_timer_t timer;
|
||||
static int timer_cb_called;
|
||||
static int close_cb_called;
|
||||
static int fs_event_created;
|
||||
static int fs_event_removed;
|
||||
static int fs_event_cb_called;
|
||||
#if defined(PATH_MAX)
|
||||
static char fs_event_filename[PATH_MAX];
|
||||
#else
|
||||
static char fs_event_filename[1024];
|
||||
#endif /* defined(PATH_MAX) */
|
||||
static int timer_cb_touch_called;
|
||||
|
||||
static void create_dir(const char* name) {
|
||||
int r;
|
||||
uv_fs_t req;
|
||||
r = uv_fs_mkdir(NULL, &req, name, 0755, NULL);
|
||||
ASSERT(r == 0 || r == UV_EEXIST);
|
||||
uv_fs_req_cleanup(&req);
|
||||
}
|
||||
|
||||
static void create_file(const char* name) {
|
||||
int r;
|
||||
uv_file file;
|
||||
uv_fs_t req;
|
||||
|
||||
r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL);
|
||||
ASSERT(r >= 0);
|
||||
file = r;
|
||||
uv_fs_req_cleanup(&req);
|
||||
r = uv_fs_close(NULL, &req, file, NULL);
|
||||
ASSERT(r == 0);
|
||||
uv_fs_req_cleanup(&req);
|
||||
}
|
||||
|
||||
static void touch_file(const char* name) {
|
||||
int r;
|
||||
uv_file file;
|
||||
uv_fs_t req;
|
||||
uv_buf_t buf;
|
||||
|
||||
r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL);
|
||||
ASSERT(r >= 0);
|
||||
file = r;
|
||||
uv_fs_req_cleanup(&req);
|
||||
|
||||
buf = uv_buf_init("foo", 4);
|
||||
r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL);
|
||||
ASSERT(r >= 0);
|
||||
uv_fs_req_cleanup(&req);
|
||||
|
||||
r = uv_fs_close(NULL, &req, file, NULL);
|
||||
ASSERT(r == 0);
|
||||
uv_fs_req_cleanup(&req);
|
||||
}
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle != NULL);
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
static void fail_cb(uv_fs_event_t* handle,
|
||||
const char* path,
|
||||
int events,
|
||||
int status) {
|
||||
ASSERT(0 && "fail_cb called");
|
||||
}
|
||||
|
||||
static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
|
||||
int events, int status) {
|
||||
++fs_event_cb_called;
|
||||
ASSERT(handle == &fs_event);
|
||||
ASSERT(status == 0);
|
||||
ASSERT(events == UV_RENAME);
|
||||
ASSERT(filename == NULL || strcmp(filename, "file1") == 0);
|
||||
ASSERT(0 == uv_fs_event_stop(handle));
|
||||
uv_close((uv_handle_t*)handle, close_cb);
|
||||
}
|
||||
|
||||
static const char* fs_event_get_filename(int i) {
|
||||
snprintf(fs_event_filename,
|
||||
sizeof(fs_event_filename),
|
||||
"watch_dir/%s%d",
|
||||
file_prefix,
|
||||
i);
|
||||
return fs_event_filename;
|
||||
}
|
||||
|
||||
static void fs_event_create_files(uv_timer_t* handle) {
|
||||
/* Make sure we're not attempting to create files we do not intend */
|
||||
ASSERT(fs_event_created < fs_event_file_count);
|
||||
|
||||
/* Create the file */
|
||||
create_file(fs_event_get_filename(fs_event_created));
|
||||
|
||||
if (++fs_event_created < fs_event_file_count) {
|
||||
/* Create another file on a different event loop tick. We do it this way
|
||||
* to avoid fs events coalescing into one fs event. */
|
||||
ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 1, 0));
|
||||
}
|
||||
}
|
||||
|
||||
static void fs_event_unlink_files(uv_timer_t* handle) {
|
||||
int r;
|
||||
int i;
|
||||
|
||||
/* NOTE: handle might be NULL if invoked not as timer callback */
|
||||
if (handle == NULL) {
|
||||
/* Unlink all files */
|
||||
for (i = 0; i < 16; i++) {
|
||||
r = remove(fs_event_get_filename(i));
|
||||
if (handle != NULL)
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
} else {
|
||||
/* Make sure we're not attempting to remove files we do not intend */
|
||||
ASSERT(fs_event_removed < fs_event_file_count);
|
||||
|
||||
/* Remove the file */
|
||||
ASSERT(0 == remove(fs_event_get_filename(fs_event_removed)));
|
||||
|
||||
if (++fs_event_removed < fs_event_file_count) {
|
||||
/* Remove another file on a different event loop tick. We do it this way
|
||||
* to avoid fs events coalescing into one fs event. */
|
||||
ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
|
||||
const char* filename,
|
||||
int events,
|
||||
int status) {
|
||||
fs_event_cb_called++;
|
||||
ASSERT(handle == &fs_event);
|
||||
ASSERT(status == 0);
|
||||
ASSERT(events == UV_CHANGE || UV_RENAME);
|
||||
ASSERT(filename == NULL ||
|
||||
strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0);
|
||||
|
||||
if (fs_event_created + fs_event_removed == fs_event_file_count) {
|
||||
/* Once we've processed all create events, delete all files */
|
||||
ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
|
||||
} else if (fs_event_cb_called == 2 * fs_event_file_count) {
|
||||
/* Once we've processed all create and delete events, stop watching */
|
||||
uv_close((uv_handle_t*) &timer, close_cb);
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
static const char* fs_event_get_filename_in_subdir(int i) {
|
||||
snprintf(fs_event_filename,
|
||||
sizeof(fs_event_filename),
|
||||
"watch_dir/subdir/%s%d",
|
||||
file_prefix,
|
||||
i);
|
||||
return fs_event_filename;
|
||||
}
|
||||
|
||||
static void fs_event_create_files_in_subdir(uv_timer_t* handle) {
|
||||
/* Make sure we're not attempting to create files we do not intend */
|
||||
ASSERT(fs_event_created < fs_event_file_count);
|
||||
|
||||
/* Create the file */
|
||||
create_file(fs_event_get_filename_in_subdir(fs_event_created));
|
||||
|
||||
if (++fs_event_created < fs_event_file_count) {
|
||||
/* Create another file on a different event loop tick. We do it this way
|
||||
* to avoid fs events coalescing into one fs event. */
|
||||
ASSERT(0 == uv_timer_start(&timer, fs_event_create_files_in_subdir, 1, 0));
|
||||
}
|
||||
}
|
||||
|
||||
static void fs_event_unlink_files_in_subdir(uv_timer_t* handle) {
|
||||
int r;
|
||||
int i;
|
||||
|
||||
/* NOTE: handle might be NULL if invoked not as timer callback */
|
||||
if (handle == NULL) {
|
||||
/* Unlink all files */
|
||||
for (i = 0; i < 16; i++) {
|
||||
r = remove(fs_event_get_filename_in_subdir(i));
|
||||
if (handle != NULL)
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
} else {
|
||||
/* Make sure we're not attempting to remove files we do not intend */
|
||||
ASSERT(fs_event_removed < fs_event_file_count);
|
||||
|
||||
/* Remove the file */
|
||||
ASSERT(0 == remove(fs_event_get_filename_in_subdir(fs_event_removed)));
|
||||
|
||||
if (++fs_event_removed < fs_event_file_count) {
|
||||
/* Remove another file on a different event loop tick. We do it this way
|
||||
* to avoid fs events coalescing into one fs event. */
|
||||
ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files_in_subdir, 1, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle,
|
||||
const char* filename,
|
||||
int events,
|
||||
int status) {
|
||||
fs_event_cb_called++;
|
||||
ASSERT(handle == &fs_event);
|
||||
ASSERT(status == 0);
|
||||
ASSERT(events == UV_CHANGE || UV_RENAME);
|
||||
ASSERT(filename == NULL ||
|
||||
strncmp(filename, file_prefix_in_subdir, sizeof(file_prefix_in_subdir) - 1) == 0);
|
||||
|
||||
if (fs_event_created + fs_event_removed == fs_event_file_count) {
|
||||
/* Once we've processed all create events, delete all files */
|
||||
ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files_in_subdir, 1, 0));
|
||||
} else if (fs_event_cb_called == 2 * fs_event_file_count) {
|
||||
/* Once we've processed all create and delete events, stop watching */
|
||||
uv_close((uv_handle_t*) &timer, close_cb);
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
|
||||
int events, int status) {
|
||||
++fs_event_cb_called;
|
||||
ASSERT(handle == &fs_event);
|
||||
ASSERT(status == 0);
|
||||
ASSERT(events == UV_CHANGE);
|
||||
ASSERT(filename == NULL || strcmp(filename, "file2") == 0);
|
||||
ASSERT(0 == uv_fs_event_stop(handle));
|
||||
uv_close((uv_handle_t*)handle, close_cb);
|
||||
}
|
||||
|
||||
static void timer_cb_close_handle(uv_timer_t* timer) {
|
||||
uv_handle_t* handle;
|
||||
|
||||
ASSERT(timer != NULL);
|
||||
handle = timer->data;
|
||||
|
||||
uv_close((uv_handle_t*)timer, NULL);
|
||||
uv_close((uv_handle_t*)handle, close_cb);
|
||||
}
|
||||
|
||||
static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
|
||||
const char* filename, int events, int status) {
|
||||
ASSERT(fs_event_cb_called == 0);
|
||||
++fs_event_cb_called;
|
||||
|
||||
ASSERT(handle == &fs_event);
|
||||
ASSERT(status == 0);
|
||||
ASSERT(events == UV_CHANGE);
|
||||
ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
|
||||
|
||||
/* Regression test for SunOS: touch should generate just one event. */
|
||||
{
|
||||
static uv_timer_t timer;
|
||||
uv_timer_init(handle->loop, &timer);
|
||||
timer.data = handle;
|
||||
uv_timer_start(&timer, timer_cb_close_handle, 250, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void timer_cb_file(uv_timer_t* handle) {
|
||||
++timer_cb_called;
|
||||
|
||||
if (timer_cb_called == 1) {
|
||||
touch_file("watch_dir/file1");
|
||||
} else {
|
||||
touch_file("watch_dir/file2");
|
||||
uv_close((uv_handle_t*)handle, close_cb);
|
||||
}
|
||||
}
|
||||
|
||||
static void timer_cb_touch(uv_timer_t* timer) {
|
||||
uv_close((uv_handle_t*)timer, NULL);
|
||||
touch_file("watch_file");
|
||||
timer_cb_touch_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);
|
||||
uv_close((uv_handle_t*) (handles + 1), NULL);
|
||||
uv_close((uv_handle_t*) handle, NULL);
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_watch_dir) {
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
/* Setup */
|
||||
fs_event_unlink_files(NULL);
|
||||
remove("watch_dir/file2");
|
||||
remove("watch_dir/file1");
|
||||
remove("watch_dir/");
|
||||
create_dir("watch_dir");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file, "watch_dir", 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_init(loop, &timer);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(fs_event_cb_called == fs_event_created + fs_event_removed);
|
||||
ASSERT(close_cb_called == 2);
|
||||
|
||||
/* Cleanup */
|
||||
fs_event_unlink_files(NULL);
|
||||
remove("watch_dir/file2");
|
||||
remove("watch_dir/file1");
|
||||
remove("watch_dir/");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_watch_dir_recursive) {
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
/* Setup */
|
||||
loop = uv_default_loop();
|
||||
fs_event_unlink_files(NULL);
|
||||
remove("watch_dir/file2");
|
||||
remove("watch_dir/file1");
|
||||
remove("watch_dir/subdir");
|
||||
remove("watch_dir/");
|
||||
create_dir("watch_dir");
|
||||
create_dir("watch_dir/subdir");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file_in_subdir, "watch_dir", UV_FS_EVENT_RECURSIVE);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_init(loop, &timer);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(fs_event_cb_called == fs_event_created + fs_event_removed);
|
||||
ASSERT(close_cb_called == 2);
|
||||
|
||||
/* Cleanup */
|
||||
fs_event_unlink_files_in_subdir(NULL);
|
||||
remove("watch_dir/file2");
|
||||
remove("watch_dir/file1");
|
||||
remove("watch_dir/subdir");
|
||||
remove("watch_dir/");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
#else
|
||||
RETURN_SKIP("Recursive directory watching not supported on this platform.");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_watch_file) {
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
/* Setup */
|
||||
remove("watch_dir/file2");
|
||||
remove("watch_dir/file1");
|
||||
remove("watch_dir/");
|
||||
create_dir("watch_dir");
|
||||
create_file("watch_dir/file1");
|
||||
create_file("watch_dir/file2");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event, fs_event_cb_file, "watch_dir/file2", 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_init(loop, &timer);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_start(&timer, timer_cb_file, 100, 100);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(fs_event_cb_called == 1);
|
||||
ASSERT(timer_cb_called == 2);
|
||||
ASSERT(close_cb_called == 2);
|
||||
|
||||
/* Cleanup */
|
||||
remove("watch_dir/file2");
|
||||
remove("watch_dir/file1");
|
||||
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];
|
||||
uv_timer_t timer;
|
||||
uv_loop_t* loop;
|
||||
|
||||
loop = uv_default_loop();
|
||||
timer.data = watchers;
|
||||
|
||||
ASSERT(0 == uv_fs_event_init(loop, watchers + 0));
|
||||
ASSERT(0 == uv_fs_event_start(watchers + 0, fail_cb, path, 0));
|
||||
ASSERT(0 == uv_fs_event_init(loop, watchers + 1));
|
||||
ASSERT(0 == uv_fs_event_start(watchers + 1, fail_cb, path, 0));
|
||||
ASSERT(0 == uv_timer_init(loop, &timer));
|
||||
ASSERT(0 == uv_timer_start(&timer, timer_cb_watch_twice, 10, 0));
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_watch_file_current_dir) {
|
||||
uv_timer_t timer;
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
/* Setup */
|
||||
remove("watch_file");
|
||||
create_file("watch_file");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event,
|
||||
fs_event_cb_file_current_dir,
|
||||
"watch_file",
|
||||
0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
|
||||
r = uv_timer_init(loop, &timer);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_timer_start(&timer, timer_cb_touch, 1, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(timer_cb_touch_called == 0);
|
||||
ASSERT(fs_event_cb_called == 0);
|
||||
ASSERT(close_cb_called == 0);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(timer_cb_touch_called == 1);
|
||||
ASSERT(fs_event_cb_called == 1);
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
/* Cleanup */
|
||||
remove("watch_file");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_no_callback_after_close) {
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
/* Setup */
|
||||
remove("watch_dir/file1");
|
||||
remove("watch_dir/");
|
||||
create_dir("watch_dir");
|
||||
create_file("watch_dir/file1");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event,
|
||||
fs_event_cb_file,
|
||||
"watch_dir/file1",
|
||||
0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
|
||||
uv_close((uv_handle_t*)&fs_event, close_cb);
|
||||
touch_file("watch_dir/file1");
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(fs_event_cb_called == 0);
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
/* Cleanup */
|
||||
remove("watch_dir/file1");
|
||||
remove("watch_dir/");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_no_callback_on_close) {
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
|
||||
/* Setup */
|
||||
remove("watch_dir/file1");
|
||||
remove("watch_dir/");
|
||||
create_dir("watch_dir");
|
||||
create_file("watch_dir/file1");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event,
|
||||
fs_event_cb_file,
|
||||
"watch_dir/file1",
|
||||
0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_close((uv_handle_t*)&fs_event, close_cb);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(fs_event_cb_called == 0);
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
/* Cleanup */
|
||||
remove("watch_dir/file1");
|
||||
remove("watch_dir/");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
r = uv_fs_event_init(handle->loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event, fs_event_fail, ".", 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_close((uv_handle_t*)&fs_event, close_cb);
|
||||
uv_close((uv_handle_t*)handle, close_cb);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_immediate_close) {
|
||||
uv_timer_t timer;
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
r = uv_timer_init(loop, &timer);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_timer_start(&timer, timer_cb, 1, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(close_cb_called == 2);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_close_with_pending_event) {
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
create_dir("watch_dir");
|
||||
create_file("watch_dir/file");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir", 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Generate an fs event. */
|
||||
touch_file("watch_dir/file");
|
||||
|
||||
uv_close((uv_handle_t*)&fs_event, close_cb);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
/* Clean up */
|
||||
remove("watch_dir/file");
|
||||
remove("watch_dir/");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(HAVE_KQUEUE)
|
||||
|
||||
/* kqueue doesn't register fs events if you don't have an active watcher.
|
||||
* The file descriptor needs to be part of the kqueue set of interest and
|
||||
* that's not the case until we actually enter the event loop.
|
||||
*/
|
||||
TEST_IMPL(fs_event_close_in_callback) {
|
||||
fprintf(stderr, "Skipping test, doesn't work with kqueue.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !HAVE_KQUEUE */
|
||||
|
||||
static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename,
|
||||
int events, int status) {
|
||||
ASSERT(status == 0);
|
||||
|
||||
ASSERT(fs_event_cb_called < 3);
|
||||
++fs_event_cb_called;
|
||||
|
||||
if (fs_event_cb_called == 3) {
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_close_in_callback) {
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
create_dir("watch_dir");
|
||||
create_file("watch_dir/file1");
|
||||
create_file("watch_dir/file2");
|
||||
create_file("watch_dir/file3");
|
||||
create_file("watch_dir/file4");
|
||||
create_file("watch_dir/file5");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Generate a couple of fs events. */
|
||||
touch_file("watch_dir/file1");
|
||||
touch_file("watch_dir/file2");
|
||||
touch_file("watch_dir/file3");
|
||||
touch_file("watch_dir/file4");
|
||||
touch_file("watch_dir/file5");
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(close_cb_called == 1);
|
||||
ASSERT(fs_event_cb_called == 3);
|
||||
|
||||
/* Clean up */
|
||||
remove("watch_dir/file1");
|
||||
remove("watch_dir/file2");
|
||||
remove("watch_dir/file3");
|
||||
remove("watch_dir/file4");
|
||||
remove("watch_dir/file5");
|
||||
remove("watch_dir/");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_KQUEUE */
|
||||
|
||||
TEST_IMPL(fs_event_start_and_close) {
|
||||
uv_loop_t* loop;
|
||||
uv_fs_event_t fs_event1;
|
||||
uv_fs_event_t fs_event2;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
create_dir("watch_dir");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event1);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event1, fs_event_cb_dir, "watch_dir", 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event2);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fs_event_start(&fs_event2, fs_event_cb_dir, "watch_dir", 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_close((uv_handle_t*) &fs_event2, close_cb);
|
||||
uv_close((uv_handle_t*) &fs_event1, close_cb);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(close_cb_called == 2);
|
||||
|
||||
remove("watch_dir/");
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_event_getpath) {
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
int r;
|
||||
char buf[1024];
|
||||
size_t len;
|
||||
|
||||
create_dir("watch_dir");
|
||||
|
||||
r = uv_fs_event_init(loop, &fs_event);
|
||||
ASSERT(r == 0);
|
||||
len = sizeof buf;
|
||||
r = uv_fs_event_getpath(&fs_event, buf, &len);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
r = uv_fs_event_start(&fs_event, fail_cb, "watch_dir", 0);
|
||||
ASSERT(r == 0);
|
||||
len = sizeof buf;
|
||||
r = uv_fs_event_getpath(&fs_event, buf, &len);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(buf[len - 1] != 0);
|
||||
ASSERT(memcmp(buf, "watch_dir", len) == 0);
|
||||
r = uv_fs_event_stop(&fs_event);
|
||||
ASSERT(r == 0);
|
||||
uv_close((uv_handle_t*) &fs_event, close_cb);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
remove("watch_dir/");
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
static int fs_event_error_reported;
|
||||
|
||||
static void fs_event_error_report_cb(uv_fs_event_t* handle,
|
||||
const char* filename,
|
||||
int events,
|
||||
int status) {
|
||||
if (status != 0)
|
||||
fs_event_error_reported = status;
|
||||
}
|
||||
|
||||
static void timer_cb_nop(uv_timer_t* handle) {
|
||||
++timer_cb_called;
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
}
|
||||
|
||||
static void fs_event_error_report_close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle != NULL);
|
||||
close_cb_called++;
|
||||
|
||||
/* handle is allocated on-stack, no need to free it */
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_error_reporting) {
|
||||
unsigned int i;
|
||||
uv_loop_t loops[1024];
|
||||
uv_fs_event_t events[ARRAY_SIZE(loops)];
|
||||
uv_loop_t* loop;
|
||||
uv_fs_event_t* event;
|
||||
|
||||
TEST_FILE_LIMIT(ARRAY_SIZE(loops) * 3);
|
||||
|
||||
remove("watch_dir/");
|
||||
create_dir("watch_dir");
|
||||
|
||||
/* Create a lot of loops, and start FSEventStream in each of them.
|
||||
* Eventually, this should create enough streams to make FSEventStreamStart()
|
||||
* fail.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(loops); i++) {
|
||||
loop = &loops[i];
|
||||
ASSERT(0 == uv_loop_init(loop));
|
||||
event = &events[i];
|
||||
|
||||
timer_cb_called = 0;
|
||||
close_cb_called = 0;
|
||||
ASSERT(0 == uv_fs_event_init(loop, event));
|
||||
ASSERT(0 == uv_fs_event_start(event,
|
||||
fs_event_error_report_cb,
|
||||
"watch_dir",
|
||||
0));
|
||||
uv_unref((uv_handle_t*) event);
|
||||
|
||||
/* Let loop run for some time */
|
||||
ASSERT(0 == uv_timer_init(loop, &timer));
|
||||
ASSERT(0 == uv_timer_start(&timer, timer_cb_nop, 2, 0));
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(1 == timer_cb_called);
|
||||
ASSERT(1 == close_cb_called);
|
||||
if (fs_event_error_reported != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* At least one loop should fail */
|
||||
ASSERT(fs_event_error_reported == UV_EMFILE);
|
||||
|
||||
/* Stop and close all events, and destroy loops */
|
||||
do {
|
||||
loop = &loops[i];
|
||||
event = &events[i];
|
||||
|
||||
ASSERT(0 == uv_fs_event_stop(event));
|
||||
uv_ref((uv_handle_t*) event);
|
||||
uv_close((uv_handle_t*) event, fs_event_error_report_close_cb);
|
||||
|
||||
close_cb_called = 0;
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
uv_loop_close(loop);
|
||||
} while (i-- != 0);
|
||||
|
||||
remove("watch_dir/");
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !defined(__APPLE__) */
|
||||
|
||||
TEST_IMPL(fs_event_error_reporting) {
|
||||
/* No-op, needed only for FSEvents backend */
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* defined(__APPLE__) */
|
||||
@@ -0,0 +1,186 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
#define FIXTURE "testfile"
|
||||
|
||||
static void timer_cb(uv_timer_t* handle);
|
||||
static void close_cb(uv_handle_t* handle);
|
||||
static void poll_cb(uv_fs_poll_t* handle,
|
||||
int status,
|
||||
const uv_stat_t* prev,
|
||||
const uv_stat_t* curr);
|
||||
|
||||
static void poll_cb_fail(uv_fs_poll_t* handle,
|
||||
int status,
|
||||
const uv_stat_t* prev,
|
||||
const uv_stat_t* curr);
|
||||
|
||||
static uv_fs_poll_t poll_handle;
|
||||
static uv_timer_t timer_handle;
|
||||
static uv_loop_t* loop;
|
||||
|
||||
static int poll_cb_called;
|
||||
static int timer_cb_called;
|
||||
static int close_cb_called;
|
||||
|
||||
|
||||
static void touch_file(const char* path) {
|
||||
static int count;
|
||||
FILE* fp;
|
||||
int i;
|
||||
|
||||
ASSERT((fp = fopen(FIXTURE, "w+")));
|
||||
|
||||
/* Need to change the file size because the poller may not pick up
|
||||
* sub-second mtime changes.
|
||||
*/
|
||||
i = ++count;
|
||||
|
||||
while (i--)
|
||||
fputc('*', fp);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
touch_file(FIXTURE);
|
||||
timer_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void poll_cb_fail(uv_fs_poll_t* handle,
|
||||
int status,
|
||||
const uv_stat_t* prev,
|
||||
const uv_stat_t* curr) {
|
||||
ASSERT(0 && "fail_cb called");
|
||||
}
|
||||
|
||||
|
||||
static void poll_cb(uv_fs_poll_t* handle,
|
||||
int status,
|
||||
const uv_stat_t* prev,
|
||||
const uv_stat_t* curr) {
|
||||
uv_stat_t zero_statbuf;
|
||||
|
||||
memset(&zero_statbuf, 0, sizeof(zero_statbuf));
|
||||
|
||||
ASSERT(handle == &poll_handle);
|
||||
ASSERT(1 == uv_is_active((uv_handle_t*) handle));
|
||||
ASSERT(prev != NULL);
|
||||
ASSERT(curr != NULL);
|
||||
|
||||
switch (poll_cb_called++) {
|
||||
case 0:
|
||||
ASSERT(status == UV_ENOENT);
|
||||
ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
|
||||
ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
|
||||
touch_file(FIXTURE);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ASSERT(status == 0);
|
||||
ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
|
||||
ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
|
||||
ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 20, 0));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ASSERT(status == 0);
|
||||
ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
|
||||
ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
|
||||
ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 200, 0));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
ASSERT(status == 0);
|
||||
ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
|
||||
ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
|
||||
remove(FIXTURE);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
ASSERT(status == UV_ENOENT);
|
||||
ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
|
||||
ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
|
||||
uv_close((uv_handle_t*)handle, close_cb);
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_poll) {
|
||||
loop = uv_default_loop();
|
||||
|
||||
remove(FIXTURE);
|
||||
|
||||
ASSERT(0 == uv_timer_init(loop, &timer_handle));
|
||||
ASSERT(0 == uv_fs_poll_init(loop, &poll_handle));
|
||||
ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb, FIXTURE, 100));
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
|
||||
ASSERT(poll_cb_called == 5);
|
||||
ASSERT(timer_cb_called == 2);
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_poll_getpath) {
|
||||
char buf[1024];
|
||||
size_t len;
|
||||
loop = uv_default_loop();
|
||||
|
||||
remove(FIXTURE);
|
||||
|
||||
ASSERT(0 == uv_fs_poll_init(loop, &poll_handle));
|
||||
len = sizeof buf;
|
||||
ASSERT(UV_EINVAL == uv_fs_poll_getpath(&poll_handle, buf, &len));
|
||||
ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100));
|
||||
len = sizeof buf;
|
||||
ASSERT(0 == uv_fs_poll_getpath(&poll_handle, buf, &len));
|
||||
ASSERT(buf[len - 1] != 0);
|
||||
ASSERT(0 == memcmp(buf, FIXTURE, len));
|
||||
|
||||
uv_close((uv_handle_t*) &poll_handle, close_cb);
|
||||
|
||||
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
|
||||
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,86 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
#define PATHMAX 1024
|
||||
extern char executable_path[];
|
||||
|
||||
TEST_IMPL(get_currentexe) {
|
||||
char buffer[PATHMAX];
|
||||
size_t size;
|
||||
char* match;
|
||||
char* path;
|
||||
int r;
|
||||
|
||||
size = sizeof(buffer) / sizeof(buffer[0]);
|
||||
r = uv_exepath(buffer, &size);
|
||||
ASSERT(!r);
|
||||
|
||||
/* uv_exepath can return an absolute path on darwin, so if the test runner
|
||||
* was run with a relative prefix of "./", we need to strip that prefix off
|
||||
* executable_path or we'll fail. */
|
||||
if (executable_path[0] == '.' && executable_path[1] == '/') {
|
||||
path = executable_path + 2;
|
||||
} else {
|
||||
path = executable_path;
|
||||
}
|
||||
|
||||
match = strstr(buffer, path);
|
||||
/* Verify that the path returned from uv_exepath is a subdirectory of
|
||||
* executable_path.
|
||||
*/
|
||||
ASSERT(match && !strcmp(match, path));
|
||||
ASSERT(size == strlen(buffer));
|
||||
|
||||
/* Negative tests */
|
||||
size = sizeof(buffer) / sizeof(buffer[0]);
|
||||
r = uv_exepath(NULL, &size);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
r = uv_exepath(buffer, NULL);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
size = 0;
|
||||
r = uv_exepath(buffer, &size);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
memset(buffer, -1, sizeof(buffer));
|
||||
|
||||
size = 1;
|
||||
r = uv_exepath(buffer, &size);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(size == 0);
|
||||
ASSERT(buffer[0] == '\0');
|
||||
|
||||
memset(buffer, -1, sizeof(buffer));
|
||||
|
||||
size = 2;
|
||||
r = uv_exepath(buffer, &size);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(size == 1);
|
||||
ASSERT(buffer[0] != '\0');
|
||||
ASSERT(buffer[1] == '\0');
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/* 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"
|
||||
|
||||
TEST_IMPL(get_loadavg) {
|
||||
|
||||
double avg[3];
|
||||
uv_loadavg(avg);
|
||||
|
||||
ASSERT(avg != NULL);
|
||||
ASSERT(avg[0] >= 0);
|
||||
ASSERT(avg[1] >= 0);
|
||||
ASSERT(avg[2] >= 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* 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"
|
||||
|
||||
TEST_IMPL(get_memory) {
|
||||
uint64_t free_mem = uv_get_free_memory();
|
||||
uint64_t total_mem = uv_get_total_memory();
|
||||
|
||||
printf("free_mem=%llu, total_mem=%llu\n",
|
||||
(unsigned long long) free_mem,
|
||||
(unsigned long long) total_mem);
|
||||
|
||||
ASSERT(free_mem > 0);
|
||||
ASSERT(total_mem > 0);
|
||||
ASSERT(total_mem > free_mem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/* 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 <stdlib.h>
|
||||
|
||||
#define CONCURRENT_COUNT 10
|
||||
|
||||
static const char* name = "localhost";
|
||||
|
||||
static int getaddrinfo_cbs = 0;
|
||||
|
||||
/* data used for running multiple calls concurrently */
|
||||
static uv_getaddrinfo_t* getaddrinfo_handle;
|
||||
static uv_getaddrinfo_t getaddrinfo_handles[CONCURRENT_COUNT];
|
||||
static int callback_counts[CONCURRENT_COUNT];
|
||||
static int fail_cb_called;
|
||||
|
||||
|
||||
static void getaddrinfo_fail_cb(uv_getaddrinfo_t* req,
|
||||
int status,
|
||||
struct addrinfo* res) {
|
||||
ASSERT(fail_cb_called == 0);
|
||||
ASSERT(status < 0);
|
||||
ASSERT(res == NULL);
|
||||
uv_freeaddrinfo(res); /* Should not crash. */
|
||||
fail_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void getaddrinfo_basic_cb(uv_getaddrinfo_t* handle,
|
||||
int status,
|
||||
struct addrinfo* res) {
|
||||
ASSERT(handle == getaddrinfo_handle);
|
||||
getaddrinfo_cbs++;
|
||||
free(handle);
|
||||
uv_freeaddrinfo(res);
|
||||
}
|
||||
|
||||
|
||||
static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle,
|
||||
int status,
|
||||
struct addrinfo* res) {
|
||||
int i;
|
||||
int* data = (int*)handle->data;
|
||||
|
||||
for (i = 0; i < CONCURRENT_COUNT; i++) {
|
||||
if (&getaddrinfo_handles[i] == handle) {
|
||||
ASSERT(i == *data);
|
||||
|
||||
callback_counts[i]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT (i < CONCURRENT_COUNT);
|
||||
|
||||
free(data);
|
||||
uv_freeaddrinfo(res);
|
||||
|
||||
getaddrinfo_cbs++;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(getaddrinfo_fail) {
|
||||
uv_getaddrinfo_t req;
|
||||
|
||||
ASSERT(0 == uv_getaddrinfo(uv_default_loop(),
|
||||
&req,
|
||||
getaddrinfo_fail_cb,
|
||||
"xyzzy.xyzzy.xyzzy",
|
||||
NULL,
|
||||
NULL));
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
ASSERT(fail_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(getaddrinfo_fail_sync) {
|
||||
uv_getaddrinfo_t req;
|
||||
|
||||
ASSERT(0 > uv_getaddrinfo(uv_default_loop(),
|
||||
&req,
|
||||
NULL,
|
||||
"xyzzy.xyzzy.xyzzy",
|
||||
NULL,
|
||||
NULL));
|
||||
uv_freeaddrinfo(req.addrinfo);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(getaddrinfo_basic) {
|
||||
int r;
|
||||
getaddrinfo_handle = (uv_getaddrinfo_t*)malloc(sizeof(uv_getaddrinfo_t));
|
||||
|
||||
r = uv_getaddrinfo(uv_default_loop(),
|
||||
getaddrinfo_handle,
|
||||
&getaddrinfo_basic_cb,
|
||||
name,
|
||||
NULL,
|
||||
NULL);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(getaddrinfo_cbs == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(getaddrinfo_basic_sync) {
|
||||
uv_getaddrinfo_t req;
|
||||
|
||||
ASSERT(0 == uv_getaddrinfo(uv_default_loop(),
|
||||
&req,
|
||||
NULL,
|
||||
name,
|
||||
NULL,
|
||||
NULL));
|
||||
uv_freeaddrinfo(req.addrinfo);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(getaddrinfo_concurrent) {
|
||||
int i, r;
|
||||
int* data;
|
||||
|
||||
for (i = 0; i < CONCURRENT_COUNT; i++) {
|
||||
callback_counts[i] = 0;
|
||||
|
||||
data = (int*)malloc(sizeof(int));
|
||||
ASSERT(data != NULL);
|
||||
*data = i;
|
||||
getaddrinfo_handles[i].data = data;
|
||||
|
||||
r = uv_getaddrinfo(uv_default_loop(),
|
||||
&getaddrinfo_handles[i],
|
||||
&getaddrinfo_cuncurrent_cb,
|
||||
name,
|
||||
NULL,
|
||||
NULL);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
for (i = 0; i < CONCURRENT_COUNT; i++) {
|
||||
ASSERT(callback_counts[i] == 1);
|
||||
}
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/* 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>
|
||||
|
||||
|
||||
static const char* address_ip4 = "127.0.0.1";
|
||||
static const char* address_ip6 = "::1";
|
||||
static const int port = 80;
|
||||
|
||||
static struct sockaddr_in addr4;
|
||||
static struct sockaddr_in6 addr6;
|
||||
static uv_getnameinfo_t req;
|
||||
|
||||
static void getnameinfo_req(uv_getnameinfo_t* handle,
|
||||
int status,
|
||||
const char* hostname,
|
||||
const char* service) {
|
||||
ASSERT(handle != NULL);
|
||||
ASSERT(status == 0);
|
||||
ASSERT(hostname != NULL);
|
||||
ASSERT(service != NULL);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(getnameinfo_basic_ip4) {
|
||||
int r;
|
||||
|
||||
r = uv_ip4_addr(address_ip4, port, &addr4);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_getnameinfo(uv_default_loop(),
|
||||
&req,
|
||||
&getnameinfo_req,
|
||||
(const struct sockaddr*)&addr4,
|
||||
0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(getnameinfo_basic_ip4_sync) {
|
||||
ASSERT(0 == uv_ip4_addr(address_ip4, port, &addr4));
|
||||
|
||||
ASSERT(0 == uv_getnameinfo(uv_default_loop(),
|
||||
&req,
|
||||
NULL,
|
||||
(const struct sockaddr*)&addr4,
|
||||
0));
|
||||
ASSERT(req.host != NULL);
|
||||
ASSERT(req.service != NULL);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(getnameinfo_basic_ip6) {
|
||||
int r;
|
||||
|
||||
r = uv_ip6_addr(address_ip6, port, &addr6);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_getnameinfo(uv_default_loop(),
|
||||
&req,
|
||||
&getnameinfo_req,
|
||||
(const struct sockaddr*)&addr6,
|
||||
0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
/* 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>
|
||||
|
||||
static const int server_port = TEST_PORT;
|
||||
/* Will be updated right after making the uv_connect_call */
|
||||
static int connect_port = -1;
|
||||
|
||||
static int getsocknamecount = 0;
|
||||
static int getpeernamecount = 0;
|
||||
|
||||
static uv_loop_t* loop;
|
||||
static uv_tcp_t tcp;
|
||||
static uv_udp_t udp;
|
||||
static uv_connect_t connect_req;
|
||||
static uv_tcp_t tcpServer;
|
||||
static uv_udp_t udpServer;
|
||||
static uv_udp_send_t send_req;
|
||||
|
||||
|
||||
static void alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
|
||||
buf->base = malloc(suggested_size);
|
||||
buf->len = suggested_size;
|
||||
}
|
||||
|
||||
|
||||
static void on_close(uv_handle_t* peer) {
|
||||
free(peer);
|
||||
uv_close((uv_handle_t*)&tcpServer, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void after_shutdown(uv_shutdown_t* req, int status) {
|
||||
uv_close((uv_handle_t*) req->handle, on_close);
|
||||
free(req);
|
||||
}
|
||||
|
||||
|
||||
static void after_read(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
uv_shutdown_t* req;
|
||||
int r;
|
||||
|
||||
if (buf->base) {
|
||||
free(buf->base);
|
||||
}
|
||||
|
||||
req = (uv_shutdown_t*) malloc(sizeof *req);
|
||||
r = uv_shutdown(req, handle, after_shutdown);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void check_sockname(struct sockaddr* addr, const char* compare_ip,
|
||||
int compare_port, const char* context) {
|
||||
struct sockaddr_in check_addr = *(struct sockaddr_in*) addr;
|
||||
struct sockaddr_in compare_addr;
|
||||
char check_ip[17];
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr(compare_ip, compare_port, &compare_addr));
|
||||
|
||||
/* Both addresses should be ipv4 */
|
||||
ASSERT(check_addr.sin_family == AF_INET);
|
||||
ASSERT(compare_addr.sin_family == AF_INET);
|
||||
|
||||
/* Check if the ip matches */
|
||||
ASSERT(memcmp(&check_addr.sin_addr,
|
||||
&compare_addr.sin_addr,
|
||||
sizeof compare_addr.sin_addr) == 0);
|
||||
|
||||
/* Check if the port matches. If port == 0 anything goes. */
|
||||
ASSERT(compare_port == 0 || check_addr.sin_port == compare_addr.sin_port);
|
||||
|
||||
r = uv_ip4_name(&check_addr, (char*) check_ip, sizeof check_ip);
|
||||
ASSERT(r == 0);
|
||||
|
||||
printf("%s: %s:%d\n", context, check_ip, ntohs(check_addr.sin_port));
|
||||
}
|
||||
|
||||
|
||||
static void on_connection(uv_stream_t* server, int status) {
|
||||
struct sockaddr sockname, peername;
|
||||
int namelen;
|
||||
uv_tcp_t* handle;
|
||||
int r;
|
||||
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "Connect error %s\n", uv_err_name(status));
|
||||
}
|
||||
ASSERT(status == 0);
|
||||
|
||||
handle = malloc(sizeof(*handle));
|
||||
ASSERT(handle != NULL);
|
||||
|
||||
r = uv_tcp_init(loop, handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* associate server with stream */
|
||||
handle->data = server;
|
||||
|
||||
r = uv_accept(server, (uv_stream_t*)handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
namelen = sizeof sockname;
|
||||
r = uv_tcp_getsockname(handle, &sockname, &namelen);
|
||||
ASSERT(r == 0);
|
||||
check_sockname(&sockname, "127.0.0.1", server_port, "accepted socket");
|
||||
getsocknamecount++;
|
||||
|
||||
namelen = sizeof peername;
|
||||
r = uv_tcp_getpeername(handle, &peername, &namelen);
|
||||
ASSERT(r == 0);
|
||||
check_sockname(&peername, "127.0.0.1", connect_port, "accepted socket peer");
|
||||
getpeernamecount++;
|
||||
|
||||
r = uv_read_start((uv_stream_t*)handle, alloc, after_read);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void on_connect(uv_connect_t* req, int status) {
|
||||
struct sockaddr sockname, peername;
|
||||
int r, namelen;
|
||||
|
||||
ASSERT(status == 0);
|
||||
|
||||
namelen = sizeof sockname;
|
||||
r = uv_tcp_getsockname((uv_tcp_t*) req->handle, &sockname, &namelen);
|
||||
ASSERT(r == 0);
|
||||
check_sockname(&sockname, "127.0.0.1", 0, "connected socket");
|
||||
getsocknamecount++;
|
||||
|
||||
namelen = sizeof peername;
|
||||
r = uv_tcp_getpeername((uv_tcp_t*) req->handle, &peername, &namelen);
|
||||
ASSERT(r == 0);
|
||||
check_sockname(&peername, "127.0.0.1", server_port, "connected socket peer");
|
||||
getpeernamecount++;
|
||||
|
||||
uv_close((uv_handle_t*)&tcp, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int tcp_listener(void) {
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr sockname, peername;
|
||||
int namelen;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", server_port, &addr));
|
||||
|
||||
r = uv_tcp_init(loop, &tcpServer);
|
||||
if (r) {
|
||||
fprintf(stderr, "Socket creation error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0);
|
||||
if (r) {
|
||||
fprintf(stderr, "Bind error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = uv_listen((uv_stream_t*)&tcpServer, 128, on_connection);
|
||||
if (r) {
|
||||
fprintf(stderr, "Listen error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&sockname, -1, sizeof sockname);
|
||||
namelen = sizeof sockname;
|
||||
r = uv_tcp_getsockname(&tcpServer, &sockname, &namelen);
|
||||
ASSERT(r == 0);
|
||||
check_sockname(&sockname, "0.0.0.0", server_port, "server socket");
|
||||
getsocknamecount++;
|
||||
|
||||
namelen = sizeof sockname;
|
||||
r = uv_tcp_getpeername(&tcpServer, &peername, &namelen);
|
||||
ASSERT(r == UV_ENOTCONN);
|
||||
getpeernamecount++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void tcp_connector(void) {
|
||||
struct sockaddr_in server_addr;
|
||||
struct sockaddr sockname;
|
||||
int r, namelen;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", server_port, &server_addr));
|
||||
|
||||
r = uv_tcp_init(loop, &tcp);
|
||||
tcp.data = &connect_req;
|
||||
ASSERT(!r);
|
||||
|
||||
r = uv_tcp_connect(&connect_req,
|
||||
&tcp,
|
||||
(const struct sockaddr*) &server_addr,
|
||||
on_connect);
|
||||
ASSERT(!r);
|
||||
|
||||
/* Fetch the actual port used by the connecting socket. */
|
||||
namelen = sizeof sockname;
|
||||
r = uv_tcp_getsockname(&tcp, &sockname, &namelen);
|
||||
ASSERT(!r);
|
||||
ASSERT(sockname.sa_family == AF_INET);
|
||||
connect_port = ntohs(((struct sockaddr_in*) &sockname)->sin_port);
|
||||
ASSERT(connect_port > 0);
|
||||
}
|
||||
|
||||
|
||||
static void udp_recv(uv_udp_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf,
|
||||
const struct sockaddr* addr,
|
||||
unsigned flags) {
|
||||
struct sockaddr sockname;
|
||||
int namelen;
|
||||
int r;
|
||||
|
||||
ASSERT(nread >= 0);
|
||||
free(buf->base);
|
||||
|
||||
if (nread == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&sockname, -1, sizeof sockname);
|
||||
namelen = sizeof(sockname);
|
||||
r = uv_udp_getsockname(&udp, &sockname, &namelen);
|
||||
ASSERT(r == 0);
|
||||
check_sockname(&sockname, "0.0.0.0", 0, "udp receiving socket");
|
||||
getsocknamecount++;
|
||||
|
||||
uv_close((uv_handle_t*) &udp, NULL);
|
||||
uv_close((uv_handle_t*) handle, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void udp_send(uv_udp_send_t* req, int status) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int udp_listener(void) {
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr sockname;
|
||||
int namelen;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", server_port, &addr));
|
||||
|
||||
r = uv_udp_init(loop, &udpServer);
|
||||
if (r) {
|
||||
fprintf(stderr, "Socket creation error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = uv_udp_bind(&udpServer, (const struct sockaddr*) &addr, 0);
|
||||
if (r) {
|
||||
fprintf(stderr, "Bind error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&sockname, -1, sizeof sockname);
|
||||
namelen = sizeof sockname;
|
||||
r = uv_udp_getsockname(&udpServer, &sockname, &namelen);
|
||||
ASSERT(r == 0);
|
||||
check_sockname(&sockname, "0.0.0.0", server_port, "udp listener socket");
|
||||
getsocknamecount++;
|
||||
|
||||
r = uv_udp_recv_start(&udpServer, alloc, udp_recv);
|
||||
ASSERT(r == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void udp_sender(void) {
|
||||
struct sockaddr_in server_addr;
|
||||
uv_buf_t buf;
|
||||
int r;
|
||||
|
||||
r = uv_udp_init(loop, &udp);
|
||||
ASSERT(!r);
|
||||
|
||||
buf = uv_buf_init("PING", 4);
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", server_port, &server_addr));
|
||||
|
||||
r = uv_udp_send(&send_req,
|
||||
&udp,
|
||||
&buf,
|
||||
1,
|
||||
(const struct sockaddr*) &server_addr,
|
||||
udp_send);
|
||||
ASSERT(!r);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(getsockname_tcp) {
|
||||
loop = uv_default_loop();
|
||||
|
||||
if (tcp_listener())
|
||||
return 1;
|
||||
|
||||
tcp_connector();
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(getsocknamecount == 3);
|
||||
ASSERT(getpeernamecount == 3);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(getsockname_udp) {
|
||||
loop = uv_default_loop();
|
||||
|
||||
if (udp_listener())
|
||||
return 1;
|
||||
|
||||
udp_sender();
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(getsocknamecount == 2);
|
||||
|
||||
ASSERT(udp.send_queue_size == 0);
|
||||
ASSERT(udpServer.send_queue_size == 0);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/* 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 int get_tty_fd(void) {
|
||||
/* Make sure we have an FD that refers to a tty */
|
||||
#ifdef _WIN32
|
||||
HANDLE handle;
|
||||
handle = CreateFileA("conout$",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
return _open_osfhandle((intptr_t) handle, 0);
|
||||
#else /* unix */
|
||||
return open("/dev/tty", O_RDONLY, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(handle_fileno) {
|
||||
int r;
|
||||
int tty_fd;
|
||||
struct sockaddr_in addr;
|
||||
uv_os_fd_t fd;
|
||||
uv_tcp_t tcp;
|
||||
uv_udp_t udp;
|
||||
uv_pipe_t pipe;
|
||||
uv_tty_t tty;
|
||||
uv_idle_t idle;
|
||||
uv_loop_t* loop;
|
||||
|
||||
loop = uv_default_loop();
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
r = uv_idle_init(loop, &idle);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fileno((uv_handle_t*) &idle, &fd);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
uv_close((uv_handle_t*) &idle, NULL);
|
||||
|
||||
r = uv_tcp_init(loop, &tcp);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fileno((uv_handle_t*) &tcp, &fd);
|
||||
ASSERT(r == UV_EBADF);
|
||||
r = uv_tcp_bind(&tcp, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fileno((uv_handle_t*) &tcp, &fd);
|
||||
ASSERT(r == 0);
|
||||
uv_close((uv_handle_t*) &tcp, NULL);
|
||||
r = uv_fileno((uv_handle_t*) &tcp, &fd);
|
||||
ASSERT(r == UV_EBADF);
|
||||
|
||||
r = uv_udp_init(loop, &udp);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fileno((uv_handle_t*) &udp, &fd);
|
||||
ASSERT(r == UV_EBADF);
|
||||
r = uv_udp_bind(&udp, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fileno((uv_handle_t*) &udp, &fd);
|
||||
ASSERT(r == 0);
|
||||
uv_close((uv_handle_t*) &udp, NULL);
|
||||
r = uv_fileno((uv_handle_t*) &udp, &fd);
|
||||
ASSERT(r == UV_EBADF);
|
||||
|
||||
r = uv_pipe_init(loop, &pipe, 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fileno((uv_handle_t*) &pipe, &fd);
|
||||
ASSERT(r == UV_EBADF);
|
||||
r = uv_pipe_bind(&pipe, TEST_PIPENAME);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fileno((uv_handle_t*) &pipe, &fd);
|
||||
ASSERT(r == 0);
|
||||
uv_close((uv_handle_t*) &pipe, NULL);
|
||||
r = uv_fileno((uv_handle_t*) &pipe, &fd);
|
||||
ASSERT(r == UV_EBADF);
|
||||
|
||||
tty_fd = get_tty_fd();
|
||||
if (tty_fd < 0) {
|
||||
fprintf(stderr, "Cannot open a TTY fd");
|
||||
fflush(stderr);
|
||||
} else {
|
||||
r = uv_tty_init(loop, &tty, tty_fd, 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_fileno((uv_handle_t*) &tty, &fd);
|
||||
ASSERT(r == 0);
|
||||
uv_close((uv_handle_t*) &tty, NULL);
|
||||
r = uv_fileno((uv_handle_t*) &tty, &fd);
|
||||
ASSERT(r == UV_EBADF);
|
||||
}
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
#include <string.h>
|
||||
|
||||
#define PATHMAX 1024
|
||||
#define SMALLPATH 1
|
||||
|
||||
TEST_IMPL(homedir) {
|
||||
char homedir[PATHMAX];
|
||||
size_t len;
|
||||
char last;
|
||||
int r;
|
||||
|
||||
/* Test the normal case */
|
||||
len = sizeof homedir;
|
||||
homedir[0] = '\0';
|
||||
ASSERT(strlen(homedir) == 0);
|
||||
r = uv_os_homedir(homedir, &len);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(strlen(homedir) == len);
|
||||
ASSERT(len > 0);
|
||||
ASSERT(homedir[len] == '\0');
|
||||
|
||||
if (len > 1) {
|
||||
last = homedir[len - 1];
|
||||
#ifdef _WIN32
|
||||
ASSERT(last != '\\');
|
||||
#else
|
||||
ASSERT(last != '/');
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Test the case where the buffer is too small */
|
||||
len = SMALLPATH;
|
||||
r = uv_os_homedir(homedir, &len);
|
||||
ASSERT(r == UV_ENOBUFS);
|
||||
ASSERT(len > SMALLPATH);
|
||||
|
||||
/* Test invalid inputs */
|
||||
r = uv_os_homedir(NULL, &len);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
r = uv_os_homedir(homedir, NULL);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
len = 0;
|
||||
r = uv_os_homedir(homedir, &len);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
#ifndef MILLISEC
|
||||
# define MILLISEC 1000
|
||||
#endif
|
||||
|
||||
#ifndef NANOSEC
|
||||
# define NANOSEC ((uint64_t) 1e9)
|
||||
#endif
|
||||
|
||||
|
||||
TEST_IMPL(hrtime) {
|
||||
uint64_t a, b, diff;
|
||||
int i = 75;
|
||||
while (i > 0) {
|
||||
a = uv_hrtime();
|
||||
uv_sleep(45);
|
||||
b = uv_hrtime();
|
||||
|
||||
diff = b - a;
|
||||
|
||||
/* printf("i= %d diff = %llu\n", i, (unsigned long long int) diff); */
|
||||
|
||||
/* The windows Sleep() function has only a resolution of 10-20 ms. */
|
||||
/* Check that the difference between the two hrtime values is somewhat in */
|
||||
/* the range we expect it to be. */
|
||||
ASSERT(diff > (uint64_t) 25 * NANOSEC / MILLISEC);
|
||||
ASSERT(diff < (uint64_t) 80 * NANOSEC / MILLISEC);
|
||||
--i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/* 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_idle_t idle_handle;
|
||||
static uv_check_t check_handle;
|
||||
static uv_timer_t timer_handle;
|
||||
|
||||
static int idle_cb_called = 0;
|
||||
static int check_cb_called = 0;
|
||||
static int timer_cb_called = 0;
|
||||
static int close_cb_called = 0;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
ASSERT(handle == &timer_handle);
|
||||
|
||||
uv_close((uv_handle_t*) &idle_handle, close_cb);
|
||||
uv_close((uv_handle_t*) &check_handle, close_cb);
|
||||
uv_close((uv_handle_t*) &timer_handle, close_cb);
|
||||
|
||||
timer_cb_called++;
|
||||
fprintf(stderr, "timer_cb %d\n", timer_cb_called);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
static void idle_cb(uv_idle_t* handle) {
|
||||
ASSERT(handle == &idle_handle);
|
||||
|
||||
idle_cb_called++;
|
||||
fprintf(stderr, "idle_cb %d\n", idle_cb_called);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
static void check_cb(uv_check_t* handle) {
|
||||
ASSERT(handle == &check_handle);
|
||||
|
||||
check_cb_called++;
|
||||
fprintf(stderr, "check_cb %d\n", check_cb_called);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(idle_starvation) {
|
||||
int r;
|
||||
|
||||
r = uv_idle_init(uv_default_loop(), &idle_handle);
|
||||
ASSERT(r == 0);
|
||||
r = uv_idle_start(&idle_handle, idle_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_check_init(uv_default_loop(), &check_handle);
|
||||
ASSERT(r == 0);
|
||||
r = uv_check_start(&check_handle, check_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_timer_init(uv_default_loop(), &timer_handle);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_start(&timer_handle, timer_cb, 50, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(idle_cb_called > 0);
|
||||
ASSERT(timer_cb_called == 1);
|
||||
ASSERT(close_cb_called == 3);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
|
||||
TEST_IMPL(ip4_addr) {
|
||||
|
||||
struct sockaddr_in addr;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
ASSERT(0 == uv_ip4_addr("255.255.255.255", TEST_PORT, &addr));
|
||||
ASSERT(UV_EINVAL == uv_ip4_addr("255.255.255*000", TEST_PORT, &addr));
|
||||
ASSERT(UV_EINVAL == uv_ip4_addr("255.255.255.256", TEST_PORT, &addr));
|
||||
ASSERT(UV_EINVAL == uv_ip4_addr("2555.0.0.0", TEST_PORT, &addr));
|
||||
ASSERT(UV_EINVAL == uv_ip4_addr("255", TEST_PORT, &addr));
|
||||
|
||||
/* for broken address family */
|
||||
ASSERT(UV_EAFNOSUPPORT == uv_inet_pton(42, "127.0.0.1",
|
||||
&addr.sin_addr.s_addr));
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
#ifdef __linux__
|
||||
# include <sys/socket.h>
|
||||
# include <net/if.h>
|
||||
#endif
|
||||
|
||||
|
||||
TEST_IMPL(ip6_addr_link_local) {
|
||||
char string_address[INET6_ADDRSTRLEN];
|
||||
uv_interface_address_t* addresses;
|
||||
uv_interface_address_t* address;
|
||||
struct sockaddr_in6 addr;
|
||||
unsigned int iface_index;
|
||||
const char* device_name;
|
||||
/* 40 bytes address, 16 bytes device name, plus reserve. */
|
||||
char scoped_addr[128];
|
||||
int count;
|
||||
int ix;
|
||||
|
||||
ASSERT(0 == uv_interface_addresses(&addresses, &count));
|
||||
|
||||
for (ix = 0; ix < count; ix++) {
|
||||
address = addresses + ix;
|
||||
|
||||
if (address->address.address6.sin6_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
ASSERT(0 == uv_inet_ntop(AF_INET6,
|
||||
&address->address.address6.sin6_addr,
|
||||
string_address,
|
||||
sizeof(string_address)));
|
||||
|
||||
/* Skip addresses that are not link-local. */
|
||||
if (strncmp(string_address, "fe80::", 6) != 0)
|
||||
continue;
|
||||
|
||||
iface_index = address->address.address6.sin6_scope_id;
|
||||
device_name = address->name;
|
||||
|
||||
#ifdef _WIN32
|
||||
snprintf(scoped_addr,
|
||||
sizeof(scoped_addr),
|
||||
"%s%%%d",
|
||||
string_address,
|
||||
iface_index);
|
||||
#else
|
||||
snprintf(scoped_addr,
|
||||
sizeof(scoped_addr),
|
||||
"%s%%%s",
|
||||
string_address,
|
||||
device_name);
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "Testing link-local address %s "
|
||||
"(iface_index: 0x%02x, device_name: %s)\n",
|
||||
scoped_addr,
|
||||
iface_index,
|
||||
device_name);
|
||||
fflush(stderr);
|
||||
|
||||
ASSERT(0 == uv_ip6_addr(scoped_addr, TEST_PORT, &addr));
|
||||
fprintf(stderr, "Got scope_id 0x%02x\n", addr.sin6_scope_id);
|
||||
fflush(stderr);
|
||||
ASSERT(iface_index == addr.sin6_scope_id);
|
||||
}
|
||||
|
||||
uv_free_interface_addresses(addresses, count);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define GOOD_ADDR_LIST(X) \
|
||||
X("::") \
|
||||
X("::1") \
|
||||
X("fe80::1") \
|
||||
X("fe80::") \
|
||||
X("fe80::2acf:daff:fedd:342a") \
|
||||
X("fe80:0:0:0:2acf:daff:fedd:342a") \
|
||||
X("fe80:0:0:0:2acf:daff:1.2.3.4") \
|
||||
X("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") \
|
||||
|
||||
#define BAD_ADDR_LIST(X) \
|
||||
X(":::1") \
|
||||
X("abcde::1") \
|
||||
X("fe80:0:0:0:2acf:daff:fedd:342a:5678") \
|
||||
X("fe80:0:0:0:2acf:daff:abcd:1.2.3.4") \
|
||||
X("fe80:0:0:2acf:daff:1.2.3.4.5") \
|
||||
X("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255.255") \
|
||||
|
||||
#define TEST_GOOD(ADDR) \
|
||||
ASSERT(0 == uv_inet_pton(AF_INET6, ADDR, &addr)); \
|
||||
ASSERT(0 == uv_inet_pton(AF_INET6, ADDR "%en1", &addr)); \
|
||||
ASSERT(0 == uv_inet_pton(AF_INET6, ADDR "%%%%", &addr)); \
|
||||
ASSERT(0 == uv_inet_pton(AF_INET6, ADDR "%en1:1.2.3.4", &addr)); \
|
||||
|
||||
#define TEST_BAD(ADDR) \
|
||||
ASSERT(0 != uv_inet_pton(AF_INET6, ADDR, &addr)); \
|
||||
ASSERT(0 != uv_inet_pton(AF_INET6, ADDR "%en1", &addr)); \
|
||||
ASSERT(0 != uv_inet_pton(AF_INET6, ADDR "%%%%", &addr)); \
|
||||
ASSERT(0 != uv_inet_pton(AF_INET6, ADDR "%en1:1.2.3.4", &addr)); \
|
||||
|
||||
TEST_IMPL(ip6_pton) {
|
||||
struct in6_addr addr;
|
||||
|
||||
GOOD_ADDR_LIST(TEST_GOOD)
|
||||
BAD_ADDR_LIST(TEST_BAD)
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef GOOD_ADDR_LIST
|
||||
#undef BAD_ADDR_LIST
|
||||
@@ -0,0 +1,236 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
/* See test-ipc.ctx */
|
||||
void spawn_helper(uv_pipe_t* channel,
|
||||
uv_process_t* process,
|
||||
const char* helper);
|
||||
|
||||
union handles {
|
||||
uv_handle_t handle;
|
||||
uv_stream_t stream;
|
||||
uv_pipe_t pipe;
|
||||
uv_tcp_t tcp;
|
||||
uv_tty_t tty;
|
||||
};
|
||||
|
||||
struct echo_ctx {
|
||||
uv_pipe_t channel;
|
||||
uv_write_t write_req;
|
||||
uv_handle_type expected_type;
|
||||
union handles send;
|
||||
union handles recv;
|
||||
};
|
||||
|
||||
static struct echo_ctx ctx;
|
||||
static int num_recv_handles;
|
||||
|
||||
|
||||
static void alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
/* we're not actually reading anything so a small buffer is okay */
|
||||
static char slab[8];
|
||||
buf->base = slab;
|
||||
buf->len = sizeof(slab);
|
||||
}
|
||||
|
||||
|
||||
static void recv_cb(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
uv_handle_type pending;
|
||||
uv_pipe_t* pipe;
|
||||
int r;
|
||||
|
||||
pipe = (uv_pipe_t*) handle;
|
||||
ASSERT(pipe == &ctx.channel);
|
||||
ASSERT(nread >= 0);
|
||||
ASSERT(1 == uv_pipe_pending_count(pipe));
|
||||
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
ASSERT(pending == ctx.expected_type);
|
||||
|
||||
if (pending == UV_NAMED_PIPE)
|
||||
r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0);
|
||||
else if (pending == UV_TCP)
|
||||
r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp);
|
||||
else
|
||||
abort();
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept(handle, &ctx.recv.stream);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_close((uv_handle_t*)&ctx.channel, NULL);
|
||||
uv_close(&ctx.send.handle, NULL);
|
||||
uv_close(&ctx.recv.handle, NULL);
|
||||
num_recv_handles++;
|
||||
}
|
||||
|
||||
|
||||
static int run_test(void) {
|
||||
uv_process_t process;
|
||||
uv_buf_t buf;
|
||||
int r;
|
||||
|
||||
spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper");
|
||||
|
||||
buf = uv_buf_init(".", 1);
|
||||
r = uv_write2(&ctx.write_req,
|
||||
(uv_stream_t*)&ctx.channel,
|
||||
&buf, 1,
|
||||
&ctx.send.stream,
|
||||
NULL);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(num_recv_handles == 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(ipc_send_recv_pipe) {
|
||||
int r;
|
||||
|
||||
ctx.expected_type = UV_NAMED_PIPE;
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &ctx.send.pipe, 1);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_pipe_bind(&ctx.send.pipe, TEST_PIPENAME);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = run_test();
|
||||
ASSERT(r == 0);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(ipc_send_recv_tcp) {
|
||||
struct sockaddr_in addr;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
ctx.expected_type = UV_TCP;
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &ctx.send.tcp);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_bind(&ctx.send.tcp, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = run_test();
|
||||
ASSERT(r == 0);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Everything here runs in a child process. */
|
||||
|
||||
static void write2_cb(uv_write_t* req, int status) {
|
||||
ASSERT(status == 0);
|
||||
uv_close(&ctx.recv.handle, NULL);
|
||||
uv_close((uv_handle_t*)&ctx.channel, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void read_cb(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* rdbuf) {
|
||||
uv_buf_t wrbuf;
|
||||
uv_pipe_t* pipe;
|
||||
uv_handle_type pending;
|
||||
int r;
|
||||
|
||||
pipe = (uv_pipe_t*) handle;
|
||||
ASSERT(pipe == &ctx.channel);
|
||||
ASSERT(nread >= 0);
|
||||
ASSERT(1 == uv_pipe_pending_count(pipe));
|
||||
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
|
||||
|
||||
wrbuf = uv_buf_init(".", 1);
|
||||
|
||||
if (pending == UV_NAMED_PIPE)
|
||||
r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0);
|
||||
else if (pending == UV_TCP)
|
||||
r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp);
|
||||
else
|
||||
abort();
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept(handle, &ctx.recv.stream);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_write2(&ctx.write_req,
|
||||
(uv_stream_t*)&ctx.channel,
|
||||
&wrbuf,
|
||||
1,
|
||||
&ctx.recv.stream,
|
||||
write2_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
/* stdin is a duplex channel over which a handle is sent.
|
||||
* We receive it and send it back where it came from.
|
||||
*/
|
||||
int ipc_send_recv_helper(void) {
|
||||
int r;
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_pipe_open(&ctx.channel, 0);
|
||||
ASSERT(1 == uv_is_readable((uv_stream_t*)&ctx.channel));
|
||||
ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx.channel));
|
||||
ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx.channel));
|
||||
|
||||
r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, read_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,779 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
static uv_pipe_t channel;
|
||||
static uv_tcp_t tcp_server;
|
||||
static uv_tcp_t tcp_server2;
|
||||
static uv_tcp_t tcp_connection;
|
||||
|
||||
static int exit_cb_called;
|
||||
static int read_cb_called;
|
||||
static int tcp_write_cb_called;
|
||||
static int tcp_read_cb_called;
|
||||
static int on_pipe_read_called;
|
||||
static int local_conn_accepted;
|
||||
static int remote_conn_accepted;
|
||||
static int tcp_server_listening;
|
||||
static uv_write_t write_req;
|
||||
static uv_write_t conn_notify_req;
|
||||
static int close_cb_called;
|
||||
static int connection_accepted;
|
||||
static int tcp_conn_read_cb_called;
|
||||
static int tcp_conn_write_cb_called;
|
||||
|
||||
typedef struct {
|
||||
uv_connect_t conn_req;
|
||||
uv_write_t tcp_write_req;
|
||||
uv_tcp_t conn;
|
||||
} tcp_conn;
|
||||
|
||||
#define CONN_COUNT 100
|
||||
#define BACKLOG 128
|
||||
|
||||
|
||||
static void close_server_conn_cb(uv_handle_t* handle) {
|
||||
free(handle);
|
||||
}
|
||||
|
||||
|
||||
static void on_connection(uv_stream_t* server, int status) {
|
||||
uv_tcp_t* conn;
|
||||
int r;
|
||||
|
||||
if (!local_conn_accepted) {
|
||||
/* Accept the connection and close it. Also and close the server. */
|
||||
ASSERT(status == 0);
|
||||
ASSERT((uv_stream_t*)&tcp_server == server);
|
||||
|
||||
conn = malloc(sizeof(*conn));
|
||||
ASSERT(conn);
|
||||
r = uv_tcp_init(server->loop, conn);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept(server, (uv_stream_t*)conn);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_close((uv_handle_t*)conn, close_server_conn_cb);
|
||||
uv_close((uv_handle_t*)server, NULL);
|
||||
local_conn_accepted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void exit_cb(uv_process_t* process,
|
||||
int64_t exit_status,
|
||||
int term_signal) {
|
||||
printf("exit_cb\n");
|
||||
exit_cb_called++;
|
||||
ASSERT(exit_status == 0);
|
||||
uv_close((uv_handle_t*)process, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void on_alloc(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
buf->base = malloc(suggested_size);
|
||||
buf->len = suggested_size;
|
||||
}
|
||||
|
||||
|
||||
static void close_client_conn_cb(uv_handle_t* handle) {
|
||||
tcp_conn* p = (tcp_conn*)handle->data;
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
uv_close((uv_handle_t*)req->handle, close_client_conn_cb);
|
||||
}
|
||||
|
||||
|
||||
static void make_many_connections(void) {
|
||||
tcp_conn* conn;
|
||||
struct sockaddr_in addr;
|
||||
int r, i;
|
||||
|
||||
for (i = 0; i < CONN_COUNT; i++) {
|
||||
conn = malloc(sizeof(*conn));
|
||||
ASSERT(conn);
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &conn->conn);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
r = uv_tcp_connect(&conn->conn_req,
|
||||
(uv_tcp_t*) &conn->conn,
|
||||
(const struct sockaddr*) &addr,
|
||||
connect_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
conn->conn.data = conn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void on_read(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
int r;
|
||||
uv_pipe_t* pipe;
|
||||
uv_handle_type pending;
|
||||
uv_buf_t outbuf;
|
||||
|
||||
pipe = (uv_pipe_t*) handle;
|
||||
|
||||
if (nread == 0) {
|
||||
/* Everything OK, but nothing read. */
|
||||
free(buf->base);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nread < 0) {
|
||||
if (nread == UV_EOF) {
|
||||
free(buf->base);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("error recving on channel: %s\n", uv_strerror(nread));
|
||||
abort();
|
||||
}
|
||||
|
||||
fprintf(stderr, "got %d bytes\n", (int)nread);
|
||||
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
if (!tcp_server_listening) {
|
||||
ASSERT(1 == uv_pipe_pending_count(pipe));
|
||||
ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
|
||||
read_cb_called++;
|
||||
|
||||
/* Accept the pending TCP server, and start listening on it. */
|
||||
ASSERT(pending == UV_TCP);
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp_server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, on_connection);
|
||||
ASSERT(r == 0);
|
||||
|
||||
tcp_server_listening = 1;
|
||||
|
||||
/* Make sure that the expected data is correctly multiplexed. */
|
||||
ASSERT(memcmp("hello\n", buf->base, nread) == 0);
|
||||
|
||||
outbuf = uv_buf_init("world\n", 6);
|
||||
r = uv_write(&write_req, (uv_stream_t*)pipe, &outbuf, 1, NULL);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Create a bunch of connections to get both servers to accept. */
|
||||
make_many_connections();
|
||||
} else if (memcmp("accepted_connection\n", buf->base, nread) == 0) {
|
||||
/* Remote server has accepted a connection. Close the channel. */
|
||||
ASSERT(0 == uv_pipe_pending_count(pipe));
|
||||
ASSERT(pending == UV_UNKNOWN_HANDLE);
|
||||
remote_conn_accepted = 1;
|
||||
uv_close((uv_handle_t*)&channel, NULL);
|
||||
}
|
||||
|
||||
free(buf->base);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static void on_read_listen_after_bound_twice(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
int r;
|
||||
uv_pipe_t* pipe;
|
||||
uv_handle_type pending;
|
||||
|
||||
pipe = (uv_pipe_t*) handle;
|
||||
|
||||
if (nread == 0) {
|
||||
/* Everything OK, but nothing read. */
|
||||
free(buf->base);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nread < 0) {
|
||||
if (nread == UV_EOF) {
|
||||
free(buf->base);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("error recving on channel: %s\n", uv_strerror(nread));
|
||||
abort();
|
||||
}
|
||||
|
||||
fprintf(stderr, "got %d bytes\n", (int)nread);
|
||||
|
||||
ASSERT(uv_pipe_pending_count(pipe) > 0);
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
|
||||
read_cb_called++;
|
||||
|
||||
if (read_cb_called == 1) {
|
||||
/* Accept the first TCP server, and start listening on it. */
|
||||
ASSERT(pending == UV_TCP);
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp_server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, on_connection);
|
||||
ASSERT(r == 0);
|
||||
} else if (read_cb_called == 2) {
|
||||
/* Accept the second TCP server, and start listening on it. */
|
||||
ASSERT(pending == UV_TCP);
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp_server2);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server2);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&tcp_server2, BACKLOG, on_connection);
|
||||
ASSERT(r == UV_EADDRINUSE);
|
||||
|
||||
uv_close((uv_handle_t*)&tcp_server, NULL);
|
||||
uv_close((uv_handle_t*)&tcp_server2, NULL);
|
||||
ASSERT(0 == uv_pipe_pending_count(pipe));
|
||||
uv_close((uv_handle_t*)&channel, NULL);
|
||||
}
|
||||
|
||||
free(buf->base);
|
||||
}
|
||||
#endif
|
||||
|
||||
void spawn_helper(uv_pipe_t* channel,
|
||||
uv_process_t* process,
|
||||
const char* helper) {
|
||||
uv_process_options_t options;
|
||||
size_t exepath_size;
|
||||
char exepath[1024];
|
||||
char* args[3];
|
||||
int r;
|
||||
uv_stdio_container_t stdio[1];
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), channel, 1);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(channel->ipc);
|
||||
|
||||
exepath_size = sizeof(exepath);
|
||||
r = uv_exepath(exepath, &exepath_size);
|
||||
ASSERT(r == 0);
|
||||
|
||||
exepath[exepath_size] = '\0';
|
||||
args[0] = exepath;
|
||||
args[1] = (char*)helper;
|
||||
args[2] = NULL;
|
||||
|
||||
memset(&options, 0, sizeof(options));
|
||||
options.file = exepath;
|
||||
options.args = args;
|
||||
options.exit_cb = exit_cb;
|
||||
|
||||
options.stdio = stdio;
|
||||
options.stdio[0].flags = UV_CREATE_PIPE |
|
||||
UV_READABLE_PIPE | UV_WRITABLE_PIPE;
|
||||
options.stdio[0].data.stream = (uv_stream_t*)channel;
|
||||
options.stdio_count = 1;
|
||||
|
||||
r = uv_spawn(uv_default_loop(), process, &options);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void on_tcp_write(uv_write_t* req, int status) {
|
||||
ASSERT(status == 0);
|
||||
ASSERT(req->handle == (uv_stream_t*)&tcp_connection);
|
||||
tcp_write_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void on_read_alloc(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
buf->base = malloc(suggested_size);
|
||||
buf->len = suggested_size;
|
||||
}
|
||||
|
||||
|
||||
static void on_tcp_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
|
||||
ASSERT(nread > 0);
|
||||
ASSERT(memcmp("hello again\n", buf->base, nread) == 0);
|
||||
ASSERT(tcp == (uv_stream_t*)&tcp_connection);
|
||||
free(buf->base);
|
||||
|
||||
tcp_read_cb_called++;
|
||||
|
||||
uv_close((uv_handle_t*)tcp, NULL);
|
||||
uv_close((uv_handle_t*)&channel, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void on_read_connection(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
int r;
|
||||
uv_buf_t outbuf;
|
||||
uv_pipe_t* pipe;
|
||||
uv_handle_type pending;
|
||||
|
||||
pipe = (uv_pipe_t*) handle;
|
||||
if (nread == 0) {
|
||||
/* Everything OK, but nothing read. */
|
||||
free(buf->base);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nread < 0) {
|
||||
if (nread == UV_EOF) {
|
||||
free(buf->base);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("error recving on channel: %s\n", uv_strerror(nread));
|
||||
abort();
|
||||
}
|
||||
|
||||
fprintf(stderr, "got %d bytes\n", (int)nread);
|
||||
|
||||
ASSERT(1 == uv_pipe_pending_count(pipe));
|
||||
pending = uv_pipe_pending_type(pipe);
|
||||
|
||||
ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
|
||||
read_cb_called++;
|
||||
|
||||
/* Accept the pending TCP connection */
|
||||
ASSERT(pending == UV_TCP);
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp_connection);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept(handle, (uv_stream_t*)&tcp_connection);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Make sure that the expected data is correctly multiplexed. */
|
||||
ASSERT(memcmp("hello\n", buf->base, nread) == 0);
|
||||
|
||||
/* Write/read to/from the connection */
|
||||
outbuf = uv_buf_init("world\n", 6);
|
||||
r = uv_write(&write_req, (uv_stream_t*)&tcp_connection, &outbuf, 1,
|
||||
on_tcp_write);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_read_start((uv_stream_t*)&tcp_connection, on_read_alloc, on_tcp_read);
|
||||
ASSERT(r == 0);
|
||||
|
||||
free(buf->base);
|
||||
}
|
||||
|
||||
|
||||
static int run_ipc_test(const char* helper, uv_read_cb read_cb) {
|
||||
uv_process_t process;
|
||||
int r;
|
||||
|
||||
spawn_helper(&channel, &process, helper);
|
||||
uv_read_start((uv_stream_t*)&channel, on_alloc, read_cb);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(ipc_listen_before_write) {
|
||||
int r = run_ipc_test("ipc_helper_listen_before_write", on_read);
|
||||
ASSERT(local_conn_accepted == 1);
|
||||
ASSERT(remote_conn_accepted == 1);
|
||||
ASSERT(read_cb_called == 1);
|
||||
ASSERT(exit_cb_called == 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(ipc_listen_after_write) {
|
||||
int r = run_ipc_test("ipc_helper_listen_after_write", on_read);
|
||||
ASSERT(local_conn_accepted == 1);
|
||||
ASSERT(remote_conn_accepted == 1);
|
||||
ASSERT(read_cb_called == 1);
|
||||
ASSERT(exit_cb_called == 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(ipc_tcp_connection) {
|
||||
int r = run_ipc_test("ipc_helper_tcp_connection", on_read_connection);
|
||||
ASSERT(read_cb_called == 1);
|
||||
ASSERT(tcp_write_cb_called == 1);
|
||||
ASSERT(tcp_read_cb_called == 1);
|
||||
ASSERT(exit_cb_called == 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST_IMPL(listen_with_simultaneous_accepts) {
|
||||
uv_tcp_t server;
|
||||
int r;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_simultaneous_accepts(&server, 1);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(server.reqs_pending == 32);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(listen_no_simultaneous_accepts) {
|
||||
uv_tcp_t server;
|
||||
int r;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_simultaneous_accepts(&server, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(server.reqs_pending == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_IMPL(ipc_listen_after_bind_twice) {
|
||||
int r = run_ipc_test("ipc_helper_bind_twice", on_read_listen_after_bound_twice);
|
||||
ASSERT(read_cb_called == 2);
|
||||
ASSERT(exit_cb_called == 1);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Everything here runs in a child process. */
|
||||
|
||||
static tcp_conn conn;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void conn_notify_write_cb(uv_write_t* req, int status) {
|
||||
uv_close((uv_handle_t*)&tcp_server, close_cb);
|
||||
uv_close((uv_handle_t*)&channel, close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void tcp_connection_write_cb(uv_write_t* req, int status) {
|
||||
ASSERT((uv_handle_t*)&conn.conn == (uv_handle_t*)req->handle);
|
||||
uv_close((uv_handle_t*)req->handle, close_cb);
|
||||
uv_close((uv_handle_t*)&channel, close_cb);
|
||||
uv_close((uv_handle_t*)&tcp_server, close_cb);
|
||||
tcp_conn_write_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void on_tcp_child_process_read(uv_stream_t* tcp,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
uv_buf_t outbuf;
|
||||
int r;
|
||||
|
||||
if (nread < 0) {
|
||||
if (nread == UV_EOF) {
|
||||
free(buf->base);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("error recving on tcp connection: %s\n", uv_strerror(nread));
|
||||
abort();
|
||||
}
|
||||
|
||||
ASSERT(nread > 0);
|
||||
ASSERT(memcmp("world\n", buf->base, nread) == 0);
|
||||
on_pipe_read_called++;
|
||||
free(buf->base);
|
||||
|
||||
/* Write to the socket */
|
||||
outbuf = uv_buf_init("hello again\n", 12);
|
||||
r = uv_write(&conn.tcp_write_req, tcp, &outbuf, 1, tcp_connection_write_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
tcp_conn_read_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void connect_child_process_cb(uv_connect_t* req, int status) {
|
||||
int r;
|
||||
|
||||
ASSERT(status == 0);
|
||||
r = uv_read_start(req->handle, on_read_alloc, on_tcp_child_process_read);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void ipc_on_connection(uv_stream_t* server, int status) {
|
||||
int r;
|
||||
uv_buf_t buf;
|
||||
|
||||
if (!connection_accepted) {
|
||||
/*
|
||||
* Accept the connection and close it. Also let the other
|
||||
* side know.
|
||||
*/
|
||||
ASSERT(status == 0);
|
||||
ASSERT((uv_stream_t*)&tcp_server == server);
|
||||
|
||||
r = uv_tcp_init(server->loop, &conn.conn);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept(server, (uv_stream_t*)&conn.conn);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_close((uv_handle_t*)&conn.conn, close_cb);
|
||||
|
||||
buf = uv_buf_init("accepted_connection\n", 20);
|
||||
r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1,
|
||||
NULL, conn_notify_write_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
connection_accepted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ipc_on_connection_tcp_conn(uv_stream_t* server, int status) {
|
||||
int r;
|
||||
uv_buf_t buf;
|
||||
uv_tcp_t* conn;
|
||||
|
||||
ASSERT(status == 0);
|
||||
ASSERT((uv_stream_t*)&tcp_server == server);
|
||||
|
||||
conn = malloc(sizeof(*conn));
|
||||
ASSERT(conn);
|
||||
|
||||
r = uv_tcp_init(server->loop, conn);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept(server, (uv_stream_t*)conn);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Send the accepted connection to the other process */
|
||||
buf = uv_buf_init("hello\n", 6);
|
||||
r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1,
|
||||
(uv_stream_t*)conn, NULL);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_read_start((uv_stream_t*) conn,
|
||||
on_read_alloc,
|
||||
on_tcp_child_process_read);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_close((uv_handle_t*)conn, close_cb);
|
||||
}
|
||||
|
||||
|
||||
int ipc_helper(int listen_after_write) {
|
||||
/*
|
||||
* This is launched from test-ipc.c. stdin is a duplex channel that we
|
||||
* over which a handle will be transmitted.
|
||||
*/
|
||||
struct sockaddr_in addr;
|
||||
uv_write_t write_req;
|
||||
int r;
|
||||
uv_buf_t buf;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &channel, 1);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_pipe_open(&channel, 0);
|
||||
|
||||
ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
|
||||
ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
|
||||
ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp_server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
if (!listen_after_write) {
|
||||
r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
buf = uv_buf_init("hello\n", 6);
|
||||
r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1,
|
||||
(uv_stream_t*)&tcp_server, NULL);
|
||||
ASSERT(r == 0);
|
||||
|
||||
if (listen_after_write) {
|
||||
r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(connection_accepted == 1);
|
||||
ASSERT(close_cb_called == 3);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ipc_helper_tcp_connection(void) {
|
||||
/*
|
||||
* This is launched from test-ipc.c. stdin is a duplex channel
|
||||
* over which a handle will be transmitted.
|
||||
*/
|
||||
|
||||
int r;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &channel, 1);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_pipe_open(&channel, 0);
|
||||
|
||||
ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
|
||||
ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
|
||||
ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp_server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
|
||||
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection_tcp_conn);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Make a connection to the server */
|
||||
r = uv_tcp_init(uv_default_loop(), &conn.conn);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
r = uv_tcp_connect(&conn.conn_req,
|
||||
(uv_tcp_t*) &conn.conn,
|
||||
(const struct sockaddr*) &addr,
|
||||
connect_child_process_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(tcp_conn_read_cb_called == 1);
|
||||
ASSERT(tcp_conn_write_cb_called == 1);
|
||||
ASSERT(close_cb_called == 4);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipc_helper_bind_twice(void) {
|
||||
/*
|
||||
* This is launched from test-ipc.c. stdin is a duplex channel
|
||||
* over which two handles will be transmitted.
|
||||
*/
|
||||
struct sockaddr_in addr;
|
||||
uv_write_t write_req;
|
||||
uv_write_t write_req2;
|
||||
int r;
|
||||
uv_buf_t buf;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &channel, 1);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_pipe_open(&channel, 0);
|
||||
|
||||
ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
|
||||
ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
|
||||
ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
|
||||
|
||||
buf = uv_buf_init("hello\n", 6);
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp_server);
|
||||
ASSERT(r == 0);
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp_server2);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_tcp_bind(&tcp_server2, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1,
|
||||
(uv_stream_t*)&tcp_server, NULL);
|
||||
ASSERT(r == 0);
|
||||
r = uv_write2(&write_req2, (uv_stream_t*)&channel, &buf, 1,
|
||||
(uv_stream_t*)&tcp_server2, NULL);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,722 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
TEST_DECLARE (platform_output)
|
||||
TEST_DECLARE (callback_order)
|
||||
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 (loop_backend_timeout)
|
||||
TEST_DECLARE (loop_configure)
|
||||
TEST_DECLARE (default_loop_close)
|
||||
TEST_DECLARE (barrier_1)
|
||||
TEST_DECLARE (barrier_2)
|
||||
TEST_DECLARE (barrier_3)
|
||||
TEST_DECLARE (condvar_1)
|
||||
TEST_DECLARE (condvar_2)
|
||||
TEST_DECLARE (condvar_3)
|
||||
TEST_DECLARE (condvar_4)
|
||||
TEST_DECLARE (condvar_5)
|
||||
TEST_DECLARE (semaphore_1)
|
||||
TEST_DECLARE (semaphore_2)
|
||||
TEST_DECLARE (semaphore_3)
|
||||
TEST_DECLARE (tty)
|
||||
TEST_DECLARE (tty_file)
|
||||
TEST_DECLARE (stdio_over_pipes)
|
||||
TEST_DECLARE (ip6_pton)
|
||||
TEST_DECLARE (ipc_listen_before_write)
|
||||
TEST_DECLARE (ipc_listen_after_write)
|
||||
#ifndef _WIN32
|
||||
TEST_DECLARE (ipc_send_recv_pipe)
|
||||
#endif
|
||||
TEST_DECLARE (ipc_send_recv_tcp)
|
||||
TEST_DECLARE (ipc_tcp_connection)
|
||||
TEST_DECLARE (tcp_ping_pong)
|
||||
TEST_DECLARE (tcp_ping_pong_v6)
|
||||
TEST_DECLARE (pipe_ping_pong)
|
||||
TEST_DECLARE (delayed_accept)
|
||||
TEST_DECLARE (multiple_listen)
|
||||
#ifndef _WIN32
|
||||
TEST_DECLARE (tcp_write_after_connect)
|
||||
#endif
|
||||
TEST_DECLARE (tcp_writealot)
|
||||
TEST_DECLARE (tcp_write_fail)
|
||||
TEST_DECLARE (tcp_try_write)
|
||||
TEST_DECLARE (tcp_write_queue_order)
|
||||
TEST_DECLARE (tcp_open)
|
||||
TEST_DECLARE (tcp_open_twice)
|
||||
TEST_DECLARE (tcp_connect_error_after_write)
|
||||
TEST_DECLARE (tcp_shutdown_after_write)
|
||||
TEST_DECLARE (tcp_bind_error_addrinuse)
|
||||
TEST_DECLARE (tcp_bind_error_addrnotavail_1)
|
||||
TEST_DECLARE (tcp_bind_error_addrnotavail_2)
|
||||
TEST_DECLARE (tcp_bind_error_fault)
|
||||
TEST_DECLARE (tcp_bind_error_inval)
|
||||
TEST_DECLARE (tcp_bind_localhost_ok)
|
||||
TEST_DECLARE (tcp_bind_invalid_flags)
|
||||
TEST_DECLARE (tcp_listen_without_bind)
|
||||
TEST_DECLARE (tcp_connect_error_fault)
|
||||
TEST_DECLARE (tcp_connect_timeout)
|
||||
TEST_DECLARE (tcp_close_while_connecting)
|
||||
TEST_DECLARE (tcp_close)
|
||||
TEST_DECLARE (tcp_create_early)
|
||||
TEST_DECLARE (tcp_create_early_bad_bind)
|
||||
TEST_DECLARE (tcp_create_early_bad_domain)
|
||||
TEST_DECLARE (tcp_create_early_accept)
|
||||
#ifndef _WIN32
|
||||
TEST_DECLARE (tcp_close_accept)
|
||||
TEST_DECLARE (tcp_oob)
|
||||
#endif
|
||||
TEST_DECLARE (tcp_flags)
|
||||
TEST_DECLARE (tcp_write_to_half_open_connection)
|
||||
TEST_DECLARE (tcp_unexpected_read)
|
||||
TEST_DECLARE (tcp_read_stop)
|
||||
TEST_DECLARE (tcp_bind6_error_addrinuse)
|
||||
TEST_DECLARE (tcp_bind6_error_addrnotavail)
|
||||
TEST_DECLARE (tcp_bind6_error_fault)
|
||||
TEST_DECLARE (tcp_bind6_error_inval)
|
||||
TEST_DECLARE (tcp_bind6_localhost_ok)
|
||||
TEST_DECLARE (udp_bind)
|
||||
TEST_DECLARE (udp_bind_reuseaddr)
|
||||
TEST_DECLARE (udp_create_early)
|
||||
TEST_DECLARE (udp_create_early_bad_bind)
|
||||
TEST_DECLARE (udp_create_early_bad_domain)
|
||||
TEST_DECLARE (udp_send_and_recv)
|
||||
TEST_DECLARE (udp_send_immediate)
|
||||
TEST_DECLARE (udp_send_unreachable)
|
||||
TEST_DECLARE (udp_multicast_join)
|
||||
TEST_DECLARE (udp_multicast_join6)
|
||||
TEST_DECLARE (udp_multicast_ttl)
|
||||
TEST_DECLARE (udp_multicast_interface)
|
||||
TEST_DECLARE (udp_multicast_interface6)
|
||||
TEST_DECLARE (udp_dgram_too_big)
|
||||
TEST_DECLARE (udp_dual_stack)
|
||||
TEST_DECLARE (udp_ipv6_only)
|
||||
TEST_DECLARE (udp_options)
|
||||
TEST_DECLARE (udp_options6)
|
||||
TEST_DECLARE (udp_no_autobind)
|
||||
TEST_DECLARE (udp_open)
|
||||
TEST_DECLARE (udp_open_twice)
|
||||
TEST_DECLARE (udp_try_send)
|
||||
TEST_DECLARE (pipe_bind_error_addrinuse)
|
||||
TEST_DECLARE (pipe_bind_error_addrnotavail)
|
||||
TEST_DECLARE (pipe_bind_error_inval)
|
||||
TEST_DECLARE (pipe_connect_multiple)
|
||||
TEST_DECLARE (pipe_listen_without_bind)
|
||||
TEST_DECLARE (pipe_connect_bad_name)
|
||||
TEST_DECLARE (pipe_connect_to_file)
|
||||
TEST_DECLARE (pipe_connect_on_prepare)
|
||||
TEST_DECLARE (pipe_getsockname)
|
||||
TEST_DECLARE (pipe_getsockname_abstract)
|
||||
TEST_DECLARE (pipe_getsockname_blocking)
|
||||
TEST_DECLARE (pipe_pending_instances)
|
||||
TEST_DECLARE (pipe_sendmsg)
|
||||
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)
|
||||
TEST_DECLARE (timer_init)
|
||||
TEST_DECLARE (timer_again)
|
||||
TEST_DECLARE (timer_start_twice)
|
||||
TEST_DECLARE (timer_order)
|
||||
TEST_DECLARE (timer_huge_timeout)
|
||||
TEST_DECLARE (timer_huge_repeat)
|
||||
TEST_DECLARE (timer_run_once)
|
||||
TEST_DECLARE (timer_from_check)
|
||||
TEST_DECLARE (timer_null_callback)
|
||||
TEST_DECLARE (idle_starvation)
|
||||
TEST_DECLARE (loop_handles)
|
||||
TEST_DECLARE (get_loadavg)
|
||||
TEST_DECLARE (walk_handles)
|
||||
TEST_DECLARE (watcher_cross_stop)
|
||||
TEST_DECLARE (ref)
|
||||
TEST_DECLARE (idle_ref)
|
||||
TEST_DECLARE (async_ref)
|
||||
TEST_DECLARE (prepare_ref)
|
||||
TEST_DECLARE (check_ref)
|
||||
TEST_DECLARE (unref_in_prepare_cb)
|
||||
TEST_DECLARE (timer_ref)
|
||||
TEST_DECLARE (timer_ref2)
|
||||
TEST_DECLARE (fs_event_ref)
|
||||
TEST_DECLARE (fs_poll_ref)
|
||||
TEST_DECLARE (tcp_ref)
|
||||
TEST_DECLARE (tcp_ref2)
|
||||
TEST_DECLARE (tcp_ref2b)
|
||||
TEST_DECLARE (tcp_ref3)
|
||||
TEST_DECLARE (tcp_ref4)
|
||||
TEST_DECLARE (udp_ref)
|
||||
TEST_DECLARE (udp_ref2)
|
||||
TEST_DECLARE (udp_ref3)
|
||||
TEST_DECLARE (pipe_ref)
|
||||
TEST_DECLARE (pipe_ref2)
|
||||
TEST_DECLARE (pipe_ref3)
|
||||
TEST_DECLARE (pipe_ref4)
|
||||
#ifndef _WIN32
|
||||
TEST_DECLARE (pipe_close_stdout_read_stdin)
|
||||
#endif
|
||||
TEST_DECLARE (pipe_set_non_blocking)
|
||||
TEST_DECLARE (process_ref)
|
||||
TEST_DECLARE (has_ref)
|
||||
TEST_DECLARE (active)
|
||||
TEST_DECLARE (embed)
|
||||
TEST_DECLARE (async)
|
||||
TEST_DECLARE (async_null_cb)
|
||||
TEST_DECLARE (get_currentexe)
|
||||
TEST_DECLARE (process_title)
|
||||
TEST_DECLARE (cwd_and_chdir)
|
||||
TEST_DECLARE (get_memory)
|
||||
TEST_DECLARE (handle_fileno)
|
||||
TEST_DECLARE (homedir)
|
||||
TEST_DECLARE (hrtime)
|
||||
TEST_DECLARE (getaddrinfo_fail)
|
||||
TEST_DECLARE (getaddrinfo_fail_sync)
|
||||
TEST_DECLARE (getaddrinfo_basic)
|
||||
TEST_DECLARE (getaddrinfo_basic_sync)
|
||||
TEST_DECLARE (getaddrinfo_concurrent)
|
||||
TEST_DECLARE (getnameinfo_basic_ip4)
|
||||
TEST_DECLARE (getnameinfo_basic_ip4_sync)
|
||||
TEST_DECLARE (getnameinfo_basic_ip6)
|
||||
TEST_DECLARE (getsockname_tcp)
|
||||
TEST_DECLARE (getsockname_udp)
|
||||
TEST_DECLARE (fail_always)
|
||||
TEST_DECLARE (pass_always)
|
||||
TEST_DECLARE (socket_buffer_size)
|
||||
TEST_DECLARE (spawn_fails)
|
||||
#ifndef _WIN32
|
||||
TEST_DECLARE (spawn_fails_check_for_waitpid_cleanup)
|
||||
#endif
|
||||
TEST_DECLARE (spawn_exit_code)
|
||||
TEST_DECLARE (spawn_stdout)
|
||||
TEST_DECLARE (spawn_stdin)
|
||||
TEST_DECLARE (spawn_stdio_greater_than_3)
|
||||
TEST_DECLARE (spawn_ignored_stdio)
|
||||
TEST_DECLARE (spawn_and_kill)
|
||||
TEST_DECLARE (spawn_detached)
|
||||
TEST_DECLARE (spawn_and_kill_with_std)
|
||||
TEST_DECLARE (spawn_and_ping)
|
||||
TEST_DECLARE (spawn_preserve_env)
|
||||
TEST_DECLARE (spawn_setuid_fails)
|
||||
TEST_DECLARE (spawn_setgid_fails)
|
||||
TEST_DECLARE (spawn_stdout_to_file)
|
||||
TEST_DECLARE (spawn_stdout_and_stderr_to_file)
|
||||
TEST_DECLARE (spawn_stdout_and_stderr_to_file2)
|
||||
TEST_DECLARE (spawn_stdout_and_stderr_to_file_swap)
|
||||
TEST_DECLARE (spawn_auto_unref)
|
||||
TEST_DECLARE (spawn_closed_process_io)
|
||||
TEST_DECLARE (spawn_reads_child_path)
|
||||
TEST_DECLARE (spawn_inherit_streams)
|
||||
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_mkdtemp)
|
||||
TEST_DECLARE (fs_fstat)
|
||||
TEST_DECLARE (fs_access)
|
||||
TEST_DECLARE (fs_chmod)
|
||||
TEST_DECLARE (fs_unlink_readonly)
|
||||
TEST_DECLARE (fs_chown)
|
||||
TEST_DECLARE (fs_link)
|
||||
TEST_DECLARE (fs_readlink)
|
||||
TEST_DECLARE (fs_symlink)
|
||||
TEST_DECLARE (fs_symlink_dir)
|
||||
TEST_DECLARE (fs_utime)
|
||||
TEST_DECLARE (fs_futime)
|
||||
TEST_DECLARE (fs_file_open_append)
|
||||
TEST_DECLARE (fs_stat_missing_path)
|
||||
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_twice)
|
||||
TEST_DECLARE (fs_event_watch_file_current_dir)
|
||||
TEST_DECLARE (fs_event_no_callback_after_close)
|
||||
TEST_DECLARE (fs_event_no_callback_on_close)
|
||||
TEST_DECLARE (fs_event_immediate_close)
|
||||
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_scandir_empty_dir)
|
||||
TEST_DECLARE (fs_scandir_file)
|
||||
TEST_DECLARE (fs_open_dir)
|
||||
TEST_DECLARE (fs_rename_to_existing_file)
|
||||
TEST_DECLARE (fs_write_multiple_bufs)
|
||||
TEST_DECLARE (fs_read_write_null_arguments)
|
||||
TEST_DECLARE (fs_write_alotof_bufs)
|
||||
TEST_DECLARE (fs_write_alotof_bufs_with_offset)
|
||||
TEST_DECLARE (threadpool_queue_work_simple)
|
||||
TEST_DECLARE (threadpool_queue_work_einval)
|
||||
TEST_DECLARE (threadpool_multiple_event_loops)
|
||||
TEST_DECLARE (threadpool_cancel_getaddrinfo)
|
||||
TEST_DECLARE (threadpool_cancel_getnameinfo)
|
||||
TEST_DECLARE (threadpool_cancel_work)
|
||||
TEST_DECLARE (threadpool_cancel_fs)
|
||||
TEST_DECLARE (threadpool_cancel_single)
|
||||
TEST_DECLARE (thread_local_storage)
|
||||
TEST_DECLARE (thread_mutex)
|
||||
TEST_DECLARE (thread_rwlock)
|
||||
TEST_DECLARE (thread_rwlock_trylock)
|
||||
TEST_DECLARE (thread_create)
|
||||
TEST_DECLARE (thread_equal)
|
||||
TEST_DECLARE (dlerror)
|
||||
TEST_DECLARE (poll_duplex)
|
||||
TEST_DECLARE (poll_unidirectional)
|
||||
TEST_DECLARE (poll_close)
|
||||
|
||||
TEST_DECLARE (ip4_addr)
|
||||
TEST_DECLARE (ip6_addr_link_local)
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST_DECLARE (poll_close_doesnt_corrupt_stack)
|
||||
TEST_DECLARE (poll_closesocket)
|
||||
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
|
||||
#if !defined(USING_UV_SHARED)
|
||||
TEST_DECLARE (argument_escaping)
|
||||
TEST_DECLARE (environment_creation)
|
||||
#endif
|
||||
TEST_DECLARE (listen_with_simultaneous_accepts)
|
||||
TEST_DECLARE (listen_no_simultaneous_accepts)
|
||||
TEST_DECLARE (fs_stat_root)
|
||||
TEST_DECLARE (spawn_with_an_odd_path)
|
||||
TEST_DECLARE (ipc_listen_after_bind_twice)
|
||||
#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)
|
||||
TEST_DECLARE (osx_select_many_fds)
|
||||
#endif
|
||||
HELPER_DECLARE (tcp4_echo_server)
|
||||
HELPER_DECLARE (tcp6_echo_server)
|
||||
HELPER_DECLARE (udp4_echo_server)
|
||||
HELPER_DECLARE (pipe_echo_server)
|
||||
|
||||
|
||||
TASK_LIST_START
|
||||
TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000)
|
||||
|
||||
#if 0
|
||||
TEST_ENTRY (callback_order)
|
||||
#endif
|
||||
TEST_ENTRY (close_order)
|
||||
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 (loop_backend_timeout)
|
||||
TEST_ENTRY (loop_configure)
|
||||
TEST_ENTRY (default_loop_close)
|
||||
TEST_ENTRY (barrier_1)
|
||||
TEST_ENTRY (barrier_2)
|
||||
TEST_ENTRY (barrier_3)
|
||||
TEST_ENTRY (condvar_1)
|
||||
TEST_ENTRY (condvar_2)
|
||||
TEST_ENTRY (condvar_3)
|
||||
TEST_ENTRY (condvar_4)
|
||||
TEST_ENTRY (condvar_5)
|
||||
TEST_ENTRY (semaphore_1)
|
||||
TEST_ENTRY (semaphore_2)
|
||||
TEST_ENTRY (semaphore_3)
|
||||
|
||||
TEST_ENTRY (pipe_connect_bad_name)
|
||||
TEST_ENTRY (pipe_connect_to_file)
|
||||
TEST_ENTRY (pipe_connect_on_prepare)
|
||||
|
||||
TEST_ENTRY (pipe_server_close)
|
||||
#ifndef _WIN32
|
||||
TEST_ENTRY (pipe_close_stdout_read_stdin)
|
||||
#endif
|
||||
TEST_ENTRY (pipe_set_non_blocking)
|
||||
TEST_ENTRY (tty)
|
||||
TEST_ENTRY (tty_file)
|
||||
TEST_ENTRY (stdio_over_pipes)
|
||||
TEST_ENTRY (ip6_pton)
|
||||
TEST_ENTRY (ipc_listen_before_write)
|
||||
TEST_ENTRY (ipc_listen_after_write)
|
||||
#ifndef _WIN32
|
||||
TEST_ENTRY (ipc_send_recv_pipe)
|
||||
#endif
|
||||
TEST_ENTRY (ipc_send_recv_tcp)
|
||||
TEST_ENTRY (ipc_tcp_connection)
|
||||
|
||||
TEST_ENTRY (tcp_ping_pong)
|
||||
TEST_HELPER (tcp_ping_pong, tcp4_echo_server)
|
||||
|
||||
TEST_ENTRY (tcp_ping_pong_v6)
|
||||
TEST_HELPER (tcp_ping_pong_v6, tcp6_echo_server)
|
||||
|
||||
TEST_ENTRY (pipe_ping_pong)
|
||||
TEST_HELPER (pipe_ping_pong, pipe_echo_server)
|
||||
|
||||
TEST_ENTRY (delayed_accept)
|
||||
TEST_ENTRY (multiple_listen)
|
||||
|
||||
#ifndef _WIN32
|
||||
TEST_ENTRY (tcp_write_after_connect)
|
||||
#endif
|
||||
|
||||
TEST_ENTRY (tcp_writealot)
|
||||
TEST_HELPER (tcp_writealot, tcp4_echo_server)
|
||||
|
||||
TEST_ENTRY (tcp_write_fail)
|
||||
TEST_HELPER (tcp_write_fail, tcp4_echo_server)
|
||||
|
||||
TEST_ENTRY (tcp_try_write)
|
||||
|
||||
TEST_ENTRY (tcp_write_queue_order)
|
||||
|
||||
TEST_ENTRY (tcp_open)
|
||||
TEST_HELPER (tcp_open, tcp4_echo_server)
|
||||
TEST_ENTRY (tcp_open_twice)
|
||||
|
||||
TEST_ENTRY (tcp_shutdown_after_write)
|
||||
TEST_HELPER (tcp_shutdown_after_write, tcp4_echo_server)
|
||||
|
||||
TEST_ENTRY (tcp_connect_error_after_write)
|
||||
TEST_ENTRY (tcp_bind_error_addrinuse)
|
||||
TEST_ENTRY (tcp_bind_error_addrnotavail_1)
|
||||
TEST_ENTRY (tcp_bind_error_addrnotavail_2)
|
||||
TEST_ENTRY (tcp_bind_error_fault)
|
||||
TEST_ENTRY (tcp_bind_error_inval)
|
||||
TEST_ENTRY (tcp_bind_localhost_ok)
|
||||
TEST_ENTRY (tcp_bind_invalid_flags)
|
||||
TEST_ENTRY (tcp_listen_without_bind)
|
||||
TEST_ENTRY (tcp_connect_error_fault)
|
||||
TEST_ENTRY (tcp_connect_timeout)
|
||||
TEST_ENTRY (tcp_close_while_connecting)
|
||||
TEST_ENTRY (tcp_close)
|
||||
TEST_ENTRY (tcp_create_early)
|
||||
TEST_ENTRY (tcp_create_early_bad_bind)
|
||||
TEST_ENTRY (tcp_create_early_bad_domain)
|
||||
TEST_ENTRY (tcp_create_early_accept)
|
||||
#ifndef _WIN32
|
||||
TEST_ENTRY (tcp_close_accept)
|
||||
TEST_ENTRY (tcp_oob)
|
||||
#endif
|
||||
TEST_ENTRY (tcp_flags)
|
||||
TEST_ENTRY (tcp_write_to_half_open_connection)
|
||||
TEST_ENTRY (tcp_unexpected_read)
|
||||
|
||||
TEST_ENTRY (tcp_read_stop)
|
||||
TEST_HELPER (tcp_read_stop, tcp4_echo_server)
|
||||
|
||||
TEST_ENTRY (tcp_bind6_error_addrinuse)
|
||||
TEST_ENTRY (tcp_bind6_error_addrnotavail)
|
||||
TEST_ENTRY (tcp_bind6_error_fault)
|
||||
TEST_ENTRY (tcp_bind6_error_inval)
|
||||
TEST_ENTRY (tcp_bind6_localhost_ok)
|
||||
|
||||
TEST_ENTRY (udp_bind)
|
||||
TEST_ENTRY (udp_bind_reuseaddr)
|
||||
TEST_ENTRY (udp_create_early)
|
||||
TEST_ENTRY (udp_create_early_bad_bind)
|
||||
TEST_ENTRY (udp_create_early_bad_domain)
|
||||
TEST_ENTRY (udp_send_and_recv)
|
||||
TEST_ENTRY (udp_send_immediate)
|
||||
TEST_ENTRY (udp_send_unreachable)
|
||||
TEST_ENTRY (udp_dgram_too_big)
|
||||
TEST_ENTRY (udp_dual_stack)
|
||||
TEST_ENTRY (udp_ipv6_only)
|
||||
TEST_ENTRY (udp_options)
|
||||
TEST_ENTRY (udp_options6)
|
||||
TEST_ENTRY (udp_no_autobind)
|
||||
TEST_ENTRY (udp_multicast_interface)
|
||||
TEST_ENTRY (udp_multicast_interface6)
|
||||
TEST_ENTRY (udp_multicast_join)
|
||||
TEST_ENTRY (udp_multicast_join6)
|
||||
TEST_ENTRY (udp_multicast_ttl)
|
||||
TEST_ENTRY (udp_try_send)
|
||||
|
||||
TEST_ENTRY (udp_open)
|
||||
TEST_HELPER (udp_open, udp4_echo_server)
|
||||
TEST_ENTRY (udp_open_twice)
|
||||
|
||||
TEST_ENTRY (pipe_bind_error_addrinuse)
|
||||
TEST_ENTRY (pipe_bind_error_addrnotavail)
|
||||
TEST_ENTRY (pipe_bind_error_inval)
|
||||
TEST_ENTRY (pipe_connect_multiple)
|
||||
TEST_ENTRY (pipe_listen_without_bind)
|
||||
TEST_ENTRY (pipe_getsockname)
|
||||
TEST_ENTRY (pipe_getsockname_abstract)
|
||||
TEST_ENTRY (pipe_getsockname_blocking)
|
||||
TEST_ENTRY (pipe_pending_instances)
|
||||
TEST_ENTRY (pipe_sendmsg)
|
||||
|
||||
TEST_ENTRY (connection_fail)
|
||||
TEST_ENTRY (connection_fail_doesnt_auto_close)
|
||||
|
||||
TEST_ENTRY (shutdown_close_tcp)
|
||||
TEST_HELPER (shutdown_close_tcp, tcp4_echo_server)
|
||||
TEST_ENTRY (shutdown_close_pipe)
|
||||
TEST_HELPER (shutdown_close_pipe, pipe_echo_server)
|
||||
|
||||
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)
|
||||
|
||||
TEST_ENTRY (error_message)
|
||||
|
||||
TEST_ENTRY (timer)
|
||||
TEST_ENTRY (timer_init)
|
||||
TEST_ENTRY (timer_again)
|
||||
TEST_ENTRY (timer_start_twice)
|
||||
TEST_ENTRY (timer_order)
|
||||
TEST_ENTRY (timer_huge_timeout)
|
||||
TEST_ENTRY (timer_huge_repeat)
|
||||
TEST_ENTRY (timer_run_once)
|
||||
TEST_ENTRY (timer_from_check)
|
||||
TEST_ENTRY (timer_null_callback)
|
||||
|
||||
TEST_ENTRY (idle_starvation)
|
||||
|
||||
TEST_ENTRY (ref)
|
||||
TEST_ENTRY (idle_ref)
|
||||
TEST_ENTRY (fs_poll_ref)
|
||||
TEST_ENTRY (async_ref)
|
||||
TEST_ENTRY (prepare_ref)
|
||||
TEST_ENTRY (check_ref)
|
||||
TEST_ENTRY (unref_in_prepare_cb)
|
||||
TEST_ENTRY (timer_ref)
|
||||
TEST_ENTRY (timer_ref2)
|
||||
TEST_ENTRY (fs_event_ref)
|
||||
TEST_ENTRY (tcp_ref)
|
||||
TEST_ENTRY (tcp_ref2)
|
||||
TEST_ENTRY (tcp_ref2b)
|
||||
TEST_ENTRY (tcp_ref3)
|
||||
TEST_HELPER (tcp_ref3, tcp4_echo_server)
|
||||
TEST_ENTRY (tcp_ref4)
|
||||
TEST_HELPER (tcp_ref4, tcp4_echo_server)
|
||||
TEST_ENTRY (udp_ref)
|
||||
TEST_ENTRY (udp_ref2)
|
||||
TEST_ENTRY (udp_ref3)
|
||||
TEST_HELPER (udp_ref3, udp4_echo_server)
|
||||
TEST_ENTRY (pipe_ref)
|
||||
TEST_ENTRY (pipe_ref2)
|
||||
TEST_ENTRY (pipe_ref3)
|
||||
TEST_HELPER (pipe_ref3, pipe_echo_server)
|
||||
TEST_ENTRY (pipe_ref4)
|
||||
TEST_HELPER (pipe_ref4, pipe_echo_server)
|
||||
TEST_ENTRY (process_ref)
|
||||
TEST_ENTRY (has_ref)
|
||||
|
||||
TEST_ENTRY (loop_handles)
|
||||
TEST_ENTRY (walk_handles)
|
||||
|
||||
TEST_ENTRY (watcher_cross_stop)
|
||||
|
||||
TEST_ENTRY (active)
|
||||
|
||||
TEST_ENTRY (embed)
|
||||
|
||||
TEST_ENTRY (async)
|
||||
TEST_ENTRY (async_null_cb)
|
||||
|
||||
TEST_ENTRY (get_currentexe)
|
||||
|
||||
TEST_ENTRY (process_title)
|
||||
|
||||
TEST_ENTRY (cwd_and_chdir)
|
||||
|
||||
TEST_ENTRY (get_memory)
|
||||
|
||||
TEST_ENTRY (get_loadavg)
|
||||
|
||||
TEST_ENTRY (handle_fileno)
|
||||
|
||||
TEST_ENTRY (homedir)
|
||||
|
||||
TEST_ENTRY (hrtime)
|
||||
|
||||
TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000)
|
||||
TEST_ENTRY (getaddrinfo_fail_sync)
|
||||
|
||||
TEST_ENTRY (getaddrinfo_basic)
|
||||
TEST_ENTRY (getaddrinfo_basic_sync)
|
||||
TEST_ENTRY (getaddrinfo_concurrent)
|
||||
|
||||
TEST_ENTRY (getnameinfo_basic_ip4)
|
||||
TEST_ENTRY (getnameinfo_basic_ip4_sync)
|
||||
TEST_ENTRY (getnameinfo_basic_ip6)
|
||||
|
||||
TEST_ENTRY (getsockname_tcp)
|
||||
TEST_ENTRY (getsockname_udp)
|
||||
|
||||
TEST_ENTRY (poll_duplex)
|
||||
TEST_ENTRY (poll_unidirectional)
|
||||
TEST_ENTRY (poll_close)
|
||||
|
||||
TEST_ENTRY (socket_buffer_size)
|
||||
|
||||
TEST_ENTRY (spawn_fails)
|
||||
#ifndef _WIN32
|
||||
TEST_ENTRY (spawn_fails_check_for_waitpid_cleanup)
|
||||
#endif
|
||||
TEST_ENTRY (spawn_exit_code)
|
||||
TEST_ENTRY (spawn_stdout)
|
||||
TEST_ENTRY (spawn_stdin)
|
||||
TEST_ENTRY (spawn_stdio_greater_than_3)
|
||||
TEST_ENTRY (spawn_ignored_stdio)
|
||||
TEST_ENTRY (spawn_and_kill)
|
||||
TEST_ENTRY (spawn_detached)
|
||||
TEST_ENTRY (spawn_and_kill_with_std)
|
||||
TEST_ENTRY (spawn_and_ping)
|
||||
TEST_ENTRY (spawn_preserve_env)
|
||||
TEST_ENTRY (spawn_setuid_fails)
|
||||
TEST_ENTRY (spawn_setgid_fails)
|
||||
TEST_ENTRY (spawn_stdout_to_file)
|
||||
TEST_ENTRY (spawn_stdout_and_stderr_to_file)
|
||||
TEST_ENTRY (spawn_stdout_and_stderr_to_file2)
|
||||
TEST_ENTRY (spawn_stdout_and_stderr_to_file_swap)
|
||||
TEST_ENTRY (spawn_auto_unref)
|
||||
TEST_ENTRY (spawn_closed_process_io)
|
||||
TEST_ENTRY (spawn_reads_child_path)
|
||||
TEST_ENTRY (spawn_inherit_streams)
|
||||
TEST_ENTRY (fs_poll)
|
||||
TEST_ENTRY (fs_poll_getpath)
|
||||
TEST_ENTRY (kill)
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST_ENTRY (poll_close_doesnt_corrupt_stack)
|
||||
TEST_ENTRY (poll_closesocket)
|
||||
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
|
||||
#if !defined(USING_UV_SHARED)
|
||||
TEST_ENTRY (argument_escaping)
|
||||
TEST_ENTRY (environment_creation)
|
||||
# endif
|
||||
TEST_ENTRY (listen_with_simultaneous_accepts)
|
||||
TEST_ENTRY (listen_no_simultaneous_accepts)
|
||||
TEST_ENTRY (fs_stat_root)
|
||||
TEST_ENTRY (spawn_with_an_odd_path)
|
||||
TEST_ENTRY (ipc_listen_after_bind_twice)
|
||||
#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__
|
||||
TEST_ENTRY (osx_select)
|
||||
TEST_ENTRY (osx_select_many_fds)
|
||||
#endif
|
||||
|
||||
TEST_ENTRY (fs_file_noent)
|
||||
TEST_ENTRY (fs_file_nametoolong)
|
||||
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_mkdtemp)
|
||||
TEST_ENTRY (fs_fstat)
|
||||
TEST_ENTRY (fs_access)
|
||||
TEST_ENTRY (fs_chmod)
|
||||
TEST_ENTRY (fs_unlink_readonly)
|
||||
TEST_ENTRY (fs_chown)
|
||||
TEST_ENTRY (fs_utime)
|
||||
TEST_ENTRY (fs_futime)
|
||||
TEST_ENTRY (fs_readlink)
|
||||
TEST_ENTRY (fs_symlink)
|
||||
TEST_ENTRY (fs_symlink_dir)
|
||||
TEST_ENTRY (fs_stat_missing_path)
|
||||
TEST_ENTRY (fs_read_file_eof)
|
||||
TEST_ENTRY (fs_file_open_append)
|
||||
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_twice)
|
||||
TEST_ENTRY (fs_event_watch_file_current_dir)
|
||||
TEST_ENTRY (fs_event_no_callback_after_close)
|
||||
TEST_ENTRY (fs_event_no_callback_on_close)
|
||||
TEST_ENTRY (fs_event_immediate_close)
|
||||
TEST_ENTRY (fs_event_close_with_pending_event)
|
||||
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_scandir_empty_dir)
|
||||
TEST_ENTRY (fs_scandir_file)
|
||||
TEST_ENTRY (fs_open_dir)
|
||||
TEST_ENTRY (fs_rename_to_existing_file)
|
||||
TEST_ENTRY (fs_write_multiple_bufs)
|
||||
TEST_ENTRY (fs_write_alotof_bufs)
|
||||
TEST_ENTRY (fs_write_alotof_bufs_with_offset)
|
||||
TEST_ENTRY (fs_read_write_null_arguments)
|
||||
TEST_ENTRY (threadpool_queue_work_simple)
|
||||
TEST_ENTRY (threadpool_queue_work_einval)
|
||||
TEST_ENTRY (threadpool_multiple_event_loops)
|
||||
TEST_ENTRY (threadpool_cancel_getaddrinfo)
|
||||
TEST_ENTRY (threadpool_cancel_getnameinfo)
|
||||
TEST_ENTRY (threadpool_cancel_work)
|
||||
TEST_ENTRY (threadpool_cancel_fs)
|
||||
TEST_ENTRY (threadpool_cancel_single)
|
||||
TEST_ENTRY (thread_local_storage)
|
||||
TEST_ENTRY (thread_mutex)
|
||||
TEST_ENTRY (thread_rwlock)
|
||||
TEST_ENTRY (thread_rwlock_trylock)
|
||||
TEST_ENTRY (thread_create)
|
||||
TEST_ENTRY (thread_equal)
|
||||
TEST_ENTRY (dlerror)
|
||||
TEST_ENTRY (ip4_addr)
|
||||
TEST_ENTRY (ip6_addr_link_local)
|
||||
#if 0
|
||||
/* These are for testing the test runner. */
|
||||
TEST_ENTRY (fail_always)
|
||||
TEST_ENTRY (pass_always)
|
||||
#endif
|
||||
TASK_LIST_END
|
||||
@@ -0,0 +1,67 @@
|
||||
/* 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) {
|
||||
ASSERT(handle);
|
||||
}
|
||||
|
||||
|
||||
static uv_work_t work_req;
|
||||
|
||||
static void work_cb(uv_work_t* req) {
|
||||
ASSERT(req);
|
||||
}
|
||||
|
||||
static void after_work_cb(uv_work_t* req, int status) {
|
||||
ASSERT(req);
|
||||
ASSERT(status == 0);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(loop_alive) {
|
||||
int r;
|
||||
ASSERT(!uv_loop_alive(uv_default_loop()));
|
||||
|
||||
/* loops with handles are alive */
|
||||
uv_timer_init(uv_default_loop(), &timer_handle);
|
||||
uv_timer_start(&timer_handle, timer_cb, 100, 0);
|
||||
ASSERT(uv_loop_alive(uv_default_loop()));
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(!uv_loop_alive(uv_default_loop()));
|
||||
|
||||
/* loops with requests are alive */
|
||||
r = uv_queue_work(uv_default_loop(), &work_req, work_cb, after_work_cb);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(uv_loop_alive(uv_default_loop()));
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(!uv_loop_alive(uv_default_loop()));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/* 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) {
|
||||
ASSERT(handle);
|
||||
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,38 @@
|
||||
/* Copyright (c) 2014, Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* 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.h"
|
||||
#include "task.h"
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
uv_close((uv_handle_t*) handle, NULL);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(loop_configure) {
|
||||
uv_timer_t timer_handle;
|
||||
uv_loop_t loop;
|
||||
ASSERT(0 == uv_loop_init(&loop));
|
||||
#ifdef _WIN32
|
||||
ASSERT(UV_ENOSYS == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, 0));
|
||||
#else
|
||||
ASSERT(0 == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, SIGPROF));
|
||||
#endif
|
||||
ASSERT(0 == uv_timer_init(&loop, &timer_handle));
|
||||
ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 10, 0));
|
||||
ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
|
||||
ASSERT(0 == uv_loop_close(&loop));
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* Tests commented out with XXX are ones that are failing on Linux */
|
||||
|
||||
/*
|
||||
* Purpose of this test is to check semantics of starting and stopping
|
||||
* prepare, check and idle watchers.
|
||||
*
|
||||
* - A watcher must be able to safely stop or close itself;
|
||||
* - Once a watcher is stopped or closed its callback should never be called.
|
||||
* - If a watcher is closed, it is implicitly stopped and its close_cb should
|
||||
* be called exactly once.
|
||||
* - A watcher can safely start and stop other watchers of the same type.
|
||||
* - Prepare and check watchers are called once per event loop iterations.
|
||||
* - All active idle watchers are queued when the event loop has no more work
|
||||
* to do. This is done repeatedly until all idle watchers are inactive.
|
||||
* - If a watcher starts another watcher of the same type its callback is not
|
||||
* immediately queued. For check and prepare watchers, that means that if
|
||||
* a watcher makes another of the same type active, it'll not be called until
|
||||
* the next event loop iteration. For idle. watchers this means that the
|
||||
* newly activated idle watcher might not be queued immediately.
|
||||
* - Prepare, check, idle watchers keep the event loop alive even when they're
|
||||
* not active.
|
||||
*
|
||||
* This is what the test globally does:
|
||||
*
|
||||
* - prepare_1 is always active and counts event loop iterations. It also
|
||||
* creates and starts prepare_2 every other iteration. Finally it verifies
|
||||
* that no idle watchers are active before polling.
|
||||
* - prepare_2 is started by prepare_1 every other iteration. It immediately
|
||||
* stops itself. It verifies that a watcher is not queued immediately
|
||||
* if created by another watcher of the same type.
|
||||
* - There's a check watcher that stops the event loop after a certain number
|
||||
* of iterations. It starts a varying number of idle_1 watchers.
|
||||
* - Idle_1 watchers stop themselves after being called a few times. All idle_1
|
||||
* watchers try to start the idle_2 watcher if it is not already started or
|
||||
* awaiting its close callback.
|
||||
* - The idle_2 watcher always exists but immediately closes itself after
|
||||
* being started by a check_1 watcher. It verifies that a watcher is
|
||||
* implicitly stopped when closed, and that a watcher can close itself
|
||||
* safely.
|
||||
* - There is a repeating timer. It does not keep the event loop alive
|
||||
* (ev_unref) but makes sure that the loop keeps polling the system for
|
||||
* events.
|
||||
*/
|
||||
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
#define IDLE_COUNT 7
|
||||
#define ITERATIONS 21
|
||||
#define TIMEOUT 100
|
||||
|
||||
|
||||
static uv_prepare_t prepare_1_handle;
|
||||
static uv_prepare_t prepare_2_handle;
|
||||
|
||||
static uv_check_t check_handle;
|
||||
|
||||
static uv_idle_t idle_1_handles[IDLE_COUNT];
|
||||
static uv_idle_t idle_2_handle;
|
||||
|
||||
static uv_timer_t timer_handle;
|
||||
|
||||
|
||||
static int loop_iteration = 0;
|
||||
|
||||
static int prepare_1_cb_called = 0;
|
||||
static int prepare_1_close_cb_called = 0;
|
||||
|
||||
static int prepare_2_cb_called = 0;
|
||||
static int prepare_2_close_cb_called = 0;
|
||||
|
||||
static int check_cb_called = 0;
|
||||
static int check_close_cb_called = 0;
|
||||
|
||||
static int idle_1_cb_called = 0;
|
||||
static int idle_1_close_cb_called = 0;
|
||||
static int idles_1_active = 0;
|
||||
|
||||
static int idle_2_cb_called = 0;
|
||||
static int idle_2_close_cb_called = 0;
|
||||
static int idle_2_cb_started = 0;
|
||||
static int idle_2_is_active = 0;
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
ASSERT(handle == &timer_handle);
|
||||
}
|
||||
|
||||
|
||||
static void idle_2_close_cb(uv_handle_t* handle) {
|
||||
fprintf(stderr, "%s", "IDLE_2_CLOSE_CB\n");
|
||||
fflush(stderr);
|
||||
|
||||
ASSERT(handle == (uv_handle_t*)&idle_2_handle);
|
||||
|
||||
ASSERT(idle_2_is_active);
|
||||
|
||||
idle_2_close_cb_called++;
|
||||
idle_2_is_active = 0;
|
||||
}
|
||||
|
||||
|
||||
static void idle_2_cb(uv_idle_t* handle) {
|
||||
fprintf(stderr, "%s", "IDLE_2_CB\n");
|
||||
fflush(stderr);
|
||||
|
||||
ASSERT(handle == &idle_2_handle);
|
||||
|
||||
idle_2_cb_called++;
|
||||
|
||||
uv_close((uv_handle_t*)handle, idle_2_close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void idle_1_cb(uv_idle_t* handle) {
|
||||
int r;
|
||||
|
||||
fprintf(stderr, "%s", "IDLE_1_CB\n");
|
||||
fflush(stderr);
|
||||
|
||||
ASSERT(handle != NULL);
|
||||
ASSERT(idles_1_active > 0);
|
||||
|
||||
/* Init idle_2 and make it active */
|
||||
if (!idle_2_is_active && !uv_is_closing((uv_handle_t*)&idle_2_handle)) {
|
||||
r = uv_idle_init(uv_default_loop(), &idle_2_handle);
|
||||
ASSERT(r == 0);
|
||||
r = uv_idle_start(&idle_2_handle, idle_2_cb);
|
||||
ASSERT(r == 0);
|
||||
idle_2_is_active = 1;
|
||||
idle_2_cb_started++;
|
||||
}
|
||||
|
||||
idle_1_cb_called++;
|
||||
|
||||
if (idle_1_cb_called % 5 == 0) {
|
||||
r = uv_idle_stop((uv_idle_t*)handle);
|
||||
ASSERT(r == 0);
|
||||
idles_1_active--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void idle_1_close_cb(uv_handle_t* handle) {
|
||||
fprintf(stderr, "%s", "IDLE_1_CLOSE_CB\n");
|
||||
fflush(stderr);
|
||||
|
||||
ASSERT(handle != NULL);
|
||||
|
||||
idle_1_close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void prepare_1_close_cb(uv_handle_t* handle) {
|
||||
fprintf(stderr, "%s", "PREPARE_1_CLOSE_CB");
|
||||
fflush(stderr);
|
||||
ASSERT(handle == (uv_handle_t*)&prepare_1_handle);
|
||||
|
||||
prepare_1_close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void check_close_cb(uv_handle_t* handle) {
|
||||
fprintf(stderr, "%s", "CHECK_CLOSE_CB\n");
|
||||
fflush(stderr);
|
||||
ASSERT(handle == (uv_handle_t*)&check_handle);
|
||||
|
||||
check_close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void prepare_2_close_cb(uv_handle_t* handle) {
|
||||
fprintf(stderr, "%s", "PREPARE_2_CLOSE_CB\n");
|
||||
fflush(stderr);
|
||||
ASSERT(handle == (uv_handle_t*)&prepare_2_handle);
|
||||
|
||||
prepare_2_close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void check_cb(uv_check_t* handle) {
|
||||
int i, r;
|
||||
|
||||
fprintf(stderr, "%s", "CHECK_CB\n");
|
||||
fflush(stderr);
|
||||
ASSERT(handle == &check_handle);
|
||||
|
||||
if (loop_iteration < ITERATIONS) {
|
||||
/* Make some idle watchers active */
|
||||
for (i = 0; i < 1 + (loop_iteration % IDLE_COUNT); i++) {
|
||||
r = uv_idle_start(&idle_1_handles[i], idle_1_cb);
|
||||
ASSERT(r == 0);
|
||||
idles_1_active++;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* End of the test - close all handles */
|
||||
uv_close((uv_handle_t*)&prepare_1_handle, prepare_1_close_cb);
|
||||
uv_close((uv_handle_t*)&check_handle, check_close_cb);
|
||||
uv_close((uv_handle_t*)&prepare_2_handle, prepare_2_close_cb);
|
||||
|
||||
for (i = 0; i < IDLE_COUNT; i++) {
|
||||
uv_close((uv_handle_t*)&idle_1_handles[i], idle_1_close_cb);
|
||||
}
|
||||
|
||||
/* This handle is closed/recreated every time, close it only if it is */
|
||||
/* active.*/
|
||||
if (idle_2_is_active) {
|
||||
uv_close((uv_handle_t*)&idle_2_handle, idle_2_close_cb);
|
||||
}
|
||||
}
|
||||
|
||||
check_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void prepare_2_cb(uv_prepare_t* handle) {
|
||||
int r;
|
||||
|
||||
fprintf(stderr, "%s", "PREPARE_2_CB\n");
|
||||
fflush(stderr);
|
||||
ASSERT(handle == &prepare_2_handle);
|
||||
|
||||
/* prepare_2 gets started by prepare_1 when (loop_iteration % 2 == 0), */
|
||||
/* and it stops itself immediately. A started watcher is not queued */
|
||||
/* until the next round, so when this callback is made */
|
||||
/* (loop_iteration % 2 == 0) cannot be true. */
|
||||
ASSERT(loop_iteration % 2 != 0);
|
||||
|
||||
r = uv_prepare_stop((uv_prepare_t*)handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
prepare_2_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void prepare_1_cb(uv_prepare_t* handle) {
|
||||
int r;
|
||||
|
||||
fprintf(stderr, "%s", "PREPARE_1_CB\n");
|
||||
fflush(stderr);
|
||||
ASSERT(handle == &prepare_1_handle);
|
||||
|
||||
if (loop_iteration % 2 == 0) {
|
||||
r = uv_prepare_start(&prepare_2_handle, prepare_2_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
prepare_1_cb_called++;
|
||||
loop_iteration++;
|
||||
|
||||
printf("Loop iteration %d of %d.\n", loop_iteration, ITERATIONS);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(loop_handles) {
|
||||
int i;
|
||||
int r;
|
||||
|
||||
r = uv_prepare_init(uv_default_loop(), &prepare_1_handle);
|
||||
ASSERT(r == 0);
|
||||
r = uv_prepare_start(&prepare_1_handle, prepare_1_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_check_init(uv_default_loop(), &check_handle);
|
||||
ASSERT(r == 0);
|
||||
r = uv_check_start(&check_handle, check_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* initialize only, prepare_2 is started by prepare_1_cb */
|
||||
r = uv_prepare_init(uv_default_loop(), &prepare_2_handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
for (i = 0; i < IDLE_COUNT; i++) {
|
||||
/* initialize only, idle_1 handles are started by check_cb */
|
||||
r = uv_idle_init(uv_default_loop(), &idle_1_handles[i]);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
/* don't init or start idle_2, both is done by idle_1_cb */
|
||||
|
||||
/* the timer callback is there to keep the event loop polling */
|
||||
/* unref it as it is not supposed to keep the loop alive */
|
||||
r = uv_timer_init(uv_default_loop(), &timer_handle);
|
||||
ASSERT(r == 0);
|
||||
r = uv_timer_start(&timer_handle, timer_cb, TIMEOUT, TIMEOUT);
|
||||
ASSERT(r == 0);
|
||||
uv_unref((uv_handle_t*)&timer_handle);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(loop_iteration == ITERATIONS);
|
||||
|
||||
ASSERT(prepare_1_cb_called == ITERATIONS);
|
||||
ASSERT(prepare_1_close_cb_called == 1);
|
||||
|
||||
ASSERT(prepare_2_cb_called == floor(ITERATIONS / 2.0));
|
||||
ASSERT(prepare_2_close_cb_called == 1);
|
||||
|
||||
ASSERT(check_cb_called == ITERATIONS);
|
||||
ASSERT(check_close_cb_called == 1);
|
||||
|
||||
/* idle_1_cb should be called a lot */
|
||||
ASSERT(idle_1_close_cb_called == IDLE_COUNT);
|
||||
|
||||
ASSERT(idle_2_close_cb_called == idle_2_cb_started);
|
||||
ASSERT(idle_2_is_active == 0);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/* 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_prepare_t prepare_handle;
|
||||
static uv_timer_t timer_handle;
|
||||
static int prepare_called = 0;
|
||||
static int timer_called = 0;
|
||||
static int num_ticks = 10;
|
||||
|
||||
|
||||
static void prepare_cb(uv_prepare_t* handle) {
|
||||
ASSERT(handle == &prepare_handle);
|
||||
prepare_called++;
|
||||
if (prepare_called == num_ticks)
|
||||
uv_prepare_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
ASSERT(handle == &timer_handle);
|
||||
timer_called++;
|
||||
if (timer_called == 1)
|
||||
uv_stop(uv_default_loop());
|
||||
else if (timer_called == num_ticks)
|
||||
uv_timer_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(loop_stop) {
|
||||
int r;
|
||||
uv_prepare_init(uv_default_loop(), &prepare_handle);
|
||||
uv_prepare_start(&prepare_handle, prepare_cb);
|
||||
uv_timer_init(uv_default_loop(), &timer_handle);
|
||||
uv_timer_start(&timer_handle, timer_cb, 100, 100);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r != 0);
|
||||
ASSERT(timer_called == 1);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_NOWAIT);
|
||||
ASSERT(r != 0);
|
||||
ASSERT(prepare_called > 1);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(timer_called == 10);
|
||||
ASSERT(prepare_called == 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/* 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"
|
||||
|
||||
|
||||
TEST_IMPL(loop_update_time) {
|
||||
uint64_t start;
|
||||
|
||||
start = uv_now(uv_default_loop());
|
||||
while (uv_now(uv_default_loop()) - start < 1000)
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT));
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cb(uv_timer_t* timer) {
|
||||
uv_close((uv_handle_t*)timer, NULL);
|
||||
}
|
||||
|
||||
TEST_IMPL(loop_backend_timeout) {
|
||||
uv_loop_t *loop = uv_default_loop();
|
||||
uv_timer_t timer;
|
||||
int r;
|
||||
|
||||
r = uv_timer_init(loop, &timer);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(!uv_loop_alive(loop));
|
||||
ASSERT(uv_backend_timeout(loop) == 0);
|
||||
|
||||
r = uv_timer_start(&timer, cb, 1000, 0); /* 1 sec */
|
||||
ASSERT(r == 0);
|
||||
ASSERT(uv_backend_timeout(loop) > 100); /* 0.1 sec */
|
||||
ASSERT(uv_backend_timeout(loop) <= 1000); /* 1 sec */
|
||||
|
||||
r = uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(uv_backend_timeout(loop) == 0);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/* 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>
|
||||
|
||||
static int connection_cb_called = 0;
|
||||
static int close_cb_called = 0;
|
||||
static int connect_cb_called = 0;
|
||||
static uv_tcp_t server;
|
||||
static uv_tcp_t client;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle != NULL);
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void connection_cb(uv_stream_t* tcp, int status) {
|
||||
ASSERT(status == 0);
|
||||
uv_close((uv_handle_t*)&server, close_cb);
|
||||
connection_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void start_server(void) {
|
||||
struct sockaddr_in addr;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&server, 128, connection_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&server, 128, connection_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
ASSERT(req != NULL);
|
||||
ASSERT(status == 0);
|
||||
free(req);
|
||||
uv_close((uv_handle_t*)&client, close_cb);
|
||||
connect_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void client_connect(void) {
|
||||
struct sockaddr_in addr;
|
||||
uv_connect_t* connect_req = malloc(sizeof *connect_req);
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
ASSERT(connect_req != NULL);
|
||||
|
||||
r = uv_tcp_init(uv_default_loop(), &client);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_tcp_connect(connect_req,
|
||||
&client,
|
||||
(const struct sockaddr*) &addr,
|
||||
connect_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_IMPL(multiple_listen) {
|
||||
start_server();
|
||||
|
||||
client_connect();
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(connection_cb_called == 1);
|
||||
ASSERT(connect_cb_called == 1);
|
||||
ASSERT(close_cb_called == 2);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
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>
|
||||
|
||||
|
||||
/* The mutex and rwlock tests are really poor.
|
||||
* They're very basic sanity checks and nothing more.
|
||||
* Apologies if that rhymes.
|
||||
*/
|
||||
|
||||
TEST_IMPL(thread_mutex) {
|
||||
uv_mutex_t mutex;
|
||||
int r;
|
||||
|
||||
r = uv_mutex_init(&mutex);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_mutex_lock(&mutex);
|
||||
uv_mutex_unlock(&mutex);
|
||||
uv_mutex_destroy(&mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(thread_rwlock) {
|
||||
uv_rwlock_t rwlock;
|
||||
int r;
|
||||
|
||||
r = uv_rwlock_init(&rwlock);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_rwlock_rdlock(&rwlock);
|
||||
uv_rwlock_rdunlock(&rwlock);
|
||||
uv_rwlock_wrlock(&rwlock);
|
||||
uv_rwlock_wrunlock(&rwlock);
|
||||
uv_rwlock_destroy(&rwlock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(thread_rwlock_trylock) {
|
||||
uv_rwlock_t rwlock;
|
||||
int r;
|
||||
|
||||
r = uv_rwlock_init(&rwlock);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* No locks held. */
|
||||
|
||||
r = uv_rwlock_trywrlock(&rwlock);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Write lock held. */
|
||||
|
||||
r = uv_rwlock_tryrdlock(&rwlock);
|
||||
ASSERT(r == UV_EBUSY);
|
||||
r = uv_rwlock_trywrlock(&rwlock);
|
||||
ASSERT(r == UV_EBUSY);
|
||||
|
||||
uv_rwlock_wrunlock(&rwlock);
|
||||
|
||||
/* No locks held. */
|
||||
|
||||
r = uv_rwlock_tryrdlock(&rwlock);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* One read lock held. */
|
||||
|
||||
r = uv_rwlock_tryrdlock(&rwlock);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Two read locks held. */
|
||||
|
||||
r = uv_rwlock_trywrlock(&rwlock);
|
||||
ASSERT(r == UV_EBUSY);
|
||||
|
||||
uv_rwlock_rdunlock(&rwlock);
|
||||
|
||||
/* One read lock held. */
|
||||
|
||||
uv_rwlock_rdunlock(&rwlock);
|
||||
|
||||
/* No read locks held. */
|
||||
|
||||
r = uv_rwlock_trywrlock(&rwlock);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Write lock held. */
|
||||
|
||||
uv_rwlock_wrunlock(&rwlock);
|
||||
|
||||
/* No locks held. */
|
||||
|
||||
uv_rwlock_destroy(&rwlock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/* 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"
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
|
||||
static int read_count;
|
||||
|
||||
|
||||
static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
|
||||
static char slab[1024];
|
||||
buf->base = slab;
|
||||
buf->len = sizeof(slab);
|
||||
}
|
||||
|
||||
|
||||
static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
|
||||
fprintf(stdout, "got data %d\n", ++read_count);
|
||||
fflush(stdout);
|
||||
|
||||
if (read_count == 3)
|
||||
uv_close((uv_handle_t*) stream, NULL);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(osx_select) {
|
||||
int r;
|
||||
int fd;
|
||||
size_t i;
|
||||
size_t len;
|
||||
const char* str;
|
||||
uv_tty_t tty;
|
||||
|
||||
fd = open("/dev/tty", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Cannot open /dev/tty as read-only: %s\n", strerror(errno));
|
||||
fflush(stderr);
|
||||
return TEST_SKIP;
|
||||
}
|
||||
|
||||
r = uv_tty_init(uv_default_loop(), &tty, fd, 1);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb);
|
||||
|
||||
/* Emulate user-input */
|
||||
str = "got some input\n"
|
||||
"with a couple of lines\n"
|
||||
"feel pretty happy\n";
|
||||
for (i = 0, len = strlen(str); i < len; i++) {
|
||||
r = ioctl(fd, TIOCSTI, str + i);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(read_count == 3);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(osx_select_many_fds) {
|
||||
int r;
|
||||
int fd;
|
||||
size_t i;
|
||||
size_t len;
|
||||
const char* str;
|
||||
struct sockaddr_in addr;
|
||||
uv_tty_t tty;
|
||||
uv_tcp_t tcps[1500];
|
||||
|
||||
TEST_FILE_LIMIT(ARRAY_SIZE(tcps) + 100);
|
||||
|
||||
r = uv_ip4_addr("127.0.0.1", 0, &addr);
|
||||
ASSERT(r == 0);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tcps); i++) {
|
||||
r = uv_tcp_init(uv_default_loop(), &tcps[i]);
|
||||
ASSERT(r == 0);
|
||||
r = uv_tcp_bind(&tcps[i], (const struct sockaddr *) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
uv_unref((uv_handle_t*) &tcps[i]);
|
||||
}
|
||||
|
||||
fd = open("/dev/tty", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Cannot open /dev/tty as read-only: %s\n", strerror(errno));
|
||||
fflush(stderr);
|
||||
return TEST_SKIP;
|
||||
}
|
||||
|
||||
r = uv_tty_init(uv_default_loop(), &tty, fd, 1);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Emulate user-input */
|
||||
str = "got some input\n"
|
||||
"with a couple of lines\n"
|
||||
"feel pretty happy\n";
|
||||
for (i = 0, len = strlen(str); i < len; i++) {
|
||||
r = ioctl(fd, TIOCSTI, str + i);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(read_count == 3);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __APPLE__ */
|
||||
@@ -0,0 +1,28 @@
|
||||
/* 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 "task.h"
|
||||
|
||||
|
||||
TEST_IMPL(pass_always) {
|
||||
/* This test always passes. It is used to test the test runner. */
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
/* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static int completed_pingers = 0;
|
||||
|
||||
#define NUM_PINGS 1000
|
||||
|
||||
/* 64 bytes is enough for a pinger */
|
||||
#define BUFSIZE 10240
|
||||
|
||||
static char PING[] = "PING\n";
|
||||
static int pinger_on_connect_count;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int pongs;
|
||||
int state;
|
||||
union {
|
||||
uv_tcp_t tcp;
|
||||
uv_pipe_t pipe;
|
||||
} stream;
|
||||
uv_connect_t connect_req;
|
||||
char read_buffer[BUFSIZE];
|
||||
} pinger_t;
|
||||
|
||||
|
||||
static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
|
||||
buf->base = malloc(size);
|
||||
buf->len = size;
|
||||
}
|
||||
|
||||
|
||||
static void pinger_on_close(uv_handle_t* handle) {
|
||||
pinger_t* pinger = (pinger_t*)handle->data;
|
||||
|
||||
ASSERT(NUM_PINGS == pinger->pongs);
|
||||
|
||||
free(pinger);
|
||||
|
||||
completed_pingers++;
|
||||
}
|
||||
|
||||
|
||||
static void pinger_after_write(uv_write_t *req, int status) {
|
||||
ASSERT(status == 0);
|
||||
free(req);
|
||||
}
|
||||
|
||||
|
||||
static void pinger_write_ping(pinger_t* pinger) {
|
||||
uv_write_t *req;
|
||||
uv_buf_t buf;
|
||||
|
||||
buf = uv_buf_init(PING, sizeof(PING) - 1);
|
||||
|
||||
req = malloc(sizeof(*req));
|
||||
if (uv_write(req,
|
||||
(uv_stream_t*) &pinger->stream.tcp,
|
||||
&buf,
|
||||
1,
|
||||
pinger_after_write)) {
|
||||
FATAL("uv_write failed");
|
||||
}
|
||||
|
||||
puts("PING");
|
||||
}
|
||||
|
||||
|
||||
static void pinger_read_cb(uv_stream_t* stream,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
ssize_t i;
|
||||
pinger_t* pinger;
|
||||
|
||||
pinger = (pinger_t*)stream->data;
|
||||
|
||||
if (nread < 0) {
|
||||
ASSERT(nread == UV_EOF);
|
||||
|
||||
puts("got EOF");
|
||||
free(buf->base);
|
||||
|
||||
uv_close((uv_handle_t*)(&pinger->stream.tcp), pinger_on_close);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now we count the pings */
|
||||
for (i = 0; i < nread; i++) {
|
||||
ASSERT(buf->base[i] == PING[pinger->state]);
|
||||
pinger->state = (pinger->state + 1) % (sizeof(PING) - 1);
|
||||
|
||||
if (pinger->state != 0)
|
||||
continue;
|
||||
|
||||
printf("PONG %d\n", pinger->pongs);
|
||||
pinger->pongs++;
|
||||
|
||||
if (pinger->pongs < NUM_PINGS) {
|
||||
pinger_write_ping(pinger);
|
||||
} else {
|
||||
uv_close((uv_handle_t*)(&pinger->stream.tcp), pinger_on_close);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf->base);
|
||||
}
|
||||
|
||||
|
||||
static void pinger_on_connect(uv_connect_t *req, int status) {
|
||||
pinger_t *pinger = (pinger_t*)req->handle->data;
|
||||
|
||||
pinger_on_connect_count++;
|
||||
|
||||
ASSERT(status == 0);
|
||||
|
||||
ASSERT(1 == uv_is_readable(req->handle));
|
||||
ASSERT(1 == uv_is_writable(req->handle));
|
||||
ASSERT(0 == uv_is_closing((uv_handle_t *) req->handle));
|
||||
|
||||
pinger_write_ping(pinger);
|
||||
|
||||
uv_read_start((uv_stream_t*)(req->handle), alloc_cb, pinger_read_cb);
|
||||
}
|
||||
|
||||
|
||||
/* same ping-pong test, but using IPv6 connection */
|
||||
static void tcp_pinger_v6_new(void) {
|
||||
int r;
|
||||
struct sockaddr_in6 server_addr;
|
||||
pinger_t *pinger;
|
||||
|
||||
|
||||
ASSERT(0 ==uv_ip6_addr("::1", TEST_PORT, &server_addr));
|
||||
pinger = malloc(sizeof(*pinger));
|
||||
ASSERT(pinger != NULL);
|
||||
pinger->state = 0;
|
||||
pinger->pongs = 0;
|
||||
|
||||
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
|
||||
r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
|
||||
pinger->stream.tcp.data = pinger;
|
||||
ASSERT(!r);
|
||||
|
||||
/* We are never doing multiple reads/connects at a time anyway. */
|
||||
/* so these handles can be pre-initialized. */
|
||||
r = uv_tcp_connect(&pinger->connect_req,
|
||||
&pinger->stream.tcp,
|
||||
(const struct sockaddr*) &server_addr,
|
||||
pinger_on_connect);
|
||||
ASSERT(!r);
|
||||
|
||||
/* Synchronous connect callbacks are not allowed. */
|
||||
ASSERT(pinger_on_connect_count == 0);
|
||||
}
|
||||
|
||||
|
||||
static void tcp_pinger_new(void) {
|
||||
int r;
|
||||
struct sockaddr_in server_addr;
|
||||
pinger_t *pinger;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
|
||||
pinger = malloc(sizeof(*pinger));
|
||||
ASSERT(pinger != NULL);
|
||||
pinger->state = 0;
|
||||
pinger->pongs = 0;
|
||||
|
||||
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
|
||||
r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
|
||||
pinger->stream.tcp.data = pinger;
|
||||
ASSERT(!r);
|
||||
|
||||
/* We are never doing multiple reads/connects at a time anyway. */
|
||||
/* so these handles can be pre-initialized. */
|
||||
r = uv_tcp_connect(&pinger->connect_req,
|
||||
&pinger->stream.tcp,
|
||||
(const struct sockaddr*) &server_addr,
|
||||
pinger_on_connect);
|
||||
ASSERT(!r);
|
||||
|
||||
/* Synchronous connect callbacks are not allowed. */
|
||||
ASSERT(pinger_on_connect_count == 0);
|
||||
}
|
||||
|
||||
|
||||
static void pipe_pinger_new(void) {
|
||||
int r;
|
||||
pinger_t *pinger;
|
||||
|
||||
pinger = (pinger_t*)malloc(sizeof(*pinger));
|
||||
ASSERT(pinger != NULL);
|
||||
pinger->state = 0;
|
||||
pinger->pongs = 0;
|
||||
|
||||
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
|
||||
r = uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0);
|
||||
pinger->stream.pipe.data = pinger;
|
||||
ASSERT(!r);
|
||||
|
||||
/* We are never doing multiple reads/connects at a time anyway. */
|
||||
/* so these handles can be pre-initialized. */
|
||||
|
||||
uv_pipe_connect(&pinger->connect_req, &pinger->stream.pipe, TEST_PIPENAME,
|
||||
pinger_on_connect);
|
||||
|
||||
/* Synchronous connect callbacks are not allowed. */
|
||||
ASSERT(pinger_on_connect_count == 0);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(tcp_ping_pong) {
|
||||
tcp_pinger_new();
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(completed_pingers == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(tcp_ping_pong_v6) {
|
||||
if (!can_ipv6())
|
||||
RETURN_SKIP("IPv6 not supported");
|
||||
|
||||
tcp_pinger_v6_new();
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(completed_pingers == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_ping_pong) {
|
||||
pipe_pinger_new();
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(completed_pingers == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/* 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>
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
# define BAD_PIPENAME "bad-pipe"
|
||||
#else
|
||||
# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
|
||||
#endif
|
||||
|
||||
|
||||
static int close_cb_called = 0;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle != NULL);
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_bind_error_addrinuse) {
|
||||
uv_pipe_t server1, server2;
|
||||
int r;
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &server1, 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_pipe_bind(&server1, TEST_PIPENAME);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &server2, 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_pipe_bind(&server2, TEST_PIPENAME);
|
||||
ASSERT(r == UV_EADDRINUSE);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&server1, SOMAXCONN, NULL);
|
||||
ASSERT(r == 0);
|
||||
r = uv_listen((uv_stream_t*)&server2, SOMAXCONN, NULL);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
uv_close((uv_handle_t*)&server1, close_cb);
|
||||
uv_close((uv_handle_t*)&server2, close_cb);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(close_cb_called == 2);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_bind_error_addrnotavail) {
|
||||
uv_pipe_t server;
|
||||
int r;
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &server, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_pipe_bind(&server, BAD_PIPENAME);
|
||||
ASSERT(r == UV_EACCES);
|
||||
|
||||
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_bind_error_inval) {
|
||||
uv_pipe_t server;
|
||||
int r;
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &server, 0);
|
||||
ASSERT(r == 0);
|
||||
r = uv_pipe_bind(&server, TEST_PIPENAME);
|
||||
ASSERT(r == 0);
|
||||
r = uv_pipe_bind(&server, TEST_PIPENAME_2);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
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_listen_without_bind) {
|
||||
uv_pipe_t server;
|
||||
int r;
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &server, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t* buf)
|
||||
{
|
||||
static char buffer[1024];
|
||||
|
||||
buf->base = buffer;
|
||||
buf->len = sizeof(buffer);
|
||||
}
|
||||
|
||||
void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t* buf)
|
||||
{
|
||||
if (nread < 0) {
|
||||
uv_close((uv_handle_t*)stream, NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This test is a reproduction of joyent/libuv#1419 .
|
||||
*/
|
||||
TEST_IMPL(pipe_close_stdout_read_stdin) {
|
||||
int r = -1;
|
||||
int pid;
|
||||
int fd[2];
|
||||
int status;
|
||||
uv_pipe_t stdin_pipe;
|
||||
|
||||
r = pipe(fd);
|
||||
ASSERT(r == 0);
|
||||
|
||||
if ((pid = fork()) == 0) {
|
||||
/*
|
||||
* Make the read side of the pipe our stdin.
|
||||
* The write side will be closed by the parent process.
|
||||
*/
|
||||
close(fd[1]);
|
||||
close(0);
|
||||
r = dup(fd[0]);
|
||||
ASSERT(r != -1);
|
||||
|
||||
/* Create a stream that reads from the pipe. */
|
||||
r = uv_pipe_init(uv_default_loop(), (uv_pipe_t *)&stdin_pipe, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_pipe_open((uv_pipe_t *)&stdin_pipe, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_read_start((uv_stream_t *)&stdin_pipe, alloc_buffer, read_stdin);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/*
|
||||
* Because the other end of the pipe was closed, there should
|
||||
* be no event left to process after one run of the event loop.
|
||||
* Otherwise, it means that events were not processed correctly.
|
||||
*/
|
||||
ASSERT(uv_run(uv_default_loop(), UV_RUN_NOWAIT) == 0);
|
||||
} else {
|
||||
/*
|
||||
* Close both ends of the pipe so that the child
|
||||
* get a POLLHUP event when it tries to read from
|
||||
* the other end.
|
||||
*/
|
||||
close(fd[1]);
|
||||
close(fd[0]);
|
||||
|
||||
waitpid(pid, &status, 0);
|
||||
ASSERT(WIFEXITED(status) && WEXITSTATUS(status) == 0);
|
||||
}
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* ifndef _WIN32 */
|
||||
@@ -0,0 +1,95 @@
|
||||
/* 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>
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
# define BAD_PIPENAME "bad-pipe"
|
||||
#else
|
||||
# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
|
||||
#endif
|
||||
|
||||
|
||||
static int close_cb_called = 0;
|
||||
static int connect_cb_called = 0;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle != NULL);
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* connect_req, int status) {
|
||||
ASSERT(status == UV_ENOENT);
|
||||
uv_close((uv_handle_t*)connect_req->handle, close_cb);
|
||||
connect_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb_file(uv_connect_t* connect_req, int status) {
|
||||
ASSERT(status == UV_ENOTSOCK || status == UV_ECONNREFUSED);
|
||||
uv_close((uv_handle_t*)connect_req->handle, close_cb);
|
||||
connect_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_connect_bad_name) {
|
||||
uv_pipe_t client;
|
||||
uv_connect_t req;
|
||||
int r;
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &client, 0);
|
||||
ASSERT(r == 0);
|
||||
uv_pipe_connect(&req, &client, BAD_PIPENAME, connect_cb);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(close_cb_called == 1);
|
||||
ASSERT(connect_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_connect_to_file) {
|
||||
const char* path = "test/fixtures/empty_file";
|
||||
uv_pipe_t client;
|
||||
uv_connect_t req;
|
||||
int r;
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &client, 0);
|
||||
ASSERT(r == 0);
|
||||
uv_pipe_connect(&req, &client, path, connect_cb_file);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(close_cb_called == 1);
|
||||
ASSERT(connect_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
|
||||
* 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>
|
||||
|
||||
|
||||
static int connection_cb_called = 0;
|
||||
static int connect_cb_called = 0;
|
||||
|
||||
#define NUM_CLIENTS 4
|
||||
|
||||
typedef struct {
|
||||
uv_pipe_t pipe_handle;
|
||||
uv_connect_t conn_req;
|
||||
} client_t;
|
||||
|
||||
static uv_pipe_t server_handle;
|
||||
static client_t clients[NUM_CLIENTS];
|
||||
static uv_pipe_t connections[NUM_CLIENTS];
|
||||
|
||||
|
||||
static void connection_cb(uv_stream_t* server, int status) {
|
||||
int r;
|
||||
uv_pipe_t* conn;
|
||||
ASSERT(status == 0);
|
||||
|
||||
conn = &connections[connection_cb_called];
|
||||
r = uv_pipe_init(server->loop, conn, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_accept(server, (uv_stream_t*)conn);
|
||||
ASSERT(r == 0);
|
||||
|
||||
if (++connection_cb_called == NUM_CLIENTS &&
|
||||
connect_cb_called == NUM_CLIENTS) {
|
||||
uv_stop(server->loop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* connect_req, int status) {
|
||||
ASSERT(status == 0);
|
||||
if (++connect_cb_called == NUM_CLIENTS &&
|
||||
connection_cb_called == NUM_CLIENTS) {
|
||||
uv_stop(connect_req->handle->loop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_connect_multiple) {
|
||||
int i;
|
||||
int r;
|
||||
uv_loop_t* loop;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
r = uv_pipe_init(loop, &server_handle, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_pipe_bind(&server_handle, TEST_PIPENAME);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&server_handle, 128, connection_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
for (i = 0; i < NUM_CLIENTS; i++) {
|
||||
r = uv_pipe_init(loop, &clients[i].pipe_handle, 0);
|
||||
ASSERT(r == 0);
|
||||
uv_pipe_connect(&clients[i].conn_req,
|
||||
&clients[i].pipe_handle,
|
||||
TEST_PIPENAME,
|
||||
connect_cb);
|
||||
}
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(connection_cb_called == NUM_CLIENTS);
|
||||
ASSERT(connect_cb_called == NUM_CLIENTS);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
|
||||
* 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>
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
# define BAD_PIPENAME "bad-pipe"
|
||||
#else
|
||||
# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
|
||||
#endif
|
||||
|
||||
|
||||
static int close_cb_called = 0;
|
||||
static int connect_cb_called = 0;
|
||||
|
||||
static uv_pipe_t pipe_handle;
|
||||
static uv_prepare_t prepare_handle;
|
||||
static uv_connect_t conn_req;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle != NULL);
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* connect_req, int status) {
|
||||
ASSERT(status == UV_ENOENT);
|
||||
connect_cb_called++;
|
||||
uv_close((uv_handle_t*)&prepare_handle, close_cb);
|
||||
uv_close((uv_handle_t*)&pipe_handle, close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void prepare_cb(uv_prepare_t* handle) {
|
||||
ASSERT(handle == &prepare_handle);
|
||||
uv_pipe_connect(&conn_req, &pipe_handle, BAD_PIPENAME, connect_cb);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_connect_on_prepare) {
|
||||
int r;
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &pipe_handle, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_prepare_init(uv_default_loop(), &prepare_handle);
|
||||
ASSERT(r == 0);
|
||||
r = uv_prepare_start(&prepare_handle, prepare_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(close_cb_called == 2);
|
||||
ASSERT(connect_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/* 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 */
|
||||
#else
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
|
||||
static uv_pipe_t pipe_client;
|
||||
static uv_pipe_t pipe_server;
|
||||
static uv_connect_t connect_req;
|
||||
|
||||
static int pipe_close_cb_called = 0;
|
||||
static int pipe_client_connect_cb_called = 0;
|
||||
|
||||
|
||||
static void pipe_close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle == (uv_handle_t*) &pipe_client ||
|
||||
handle == (uv_handle_t*) &pipe_server);
|
||||
pipe_close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void pipe_client_connect_cb(uv_connect_t* req, int status) {
|
||||
char buf[1024];
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
ASSERT(req == &connect_req);
|
||||
ASSERT(status == 0);
|
||||
|
||||
len = sizeof buf;
|
||||
r = uv_pipe_getpeername(&pipe_client, buf, &len);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(buf[len - 1] != 0);
|
||||
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
|
||||
|
||||
len = sizeof buf;
|
||||
r = uv_pipe_getsockname(&pipe_client, buf, &len);
|
||||
ASSERT(r == 0 && len == 0);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static void pipe_server_connection_cb(uv_stream_t* handle, int status) {
|
||||
/* This function *may* be called, depending on whether accept or the
|
||||
* connection callback is called first.
|
||||
*/
|
||||
ASSERT(status == 0);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_getsockname) {
|
||||
uv_loop_t* loop;
|
||||
char buf[1024];
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
ASSERT(loop != NULL);
|
||||
|
||||
r = uv_pipe_init(loop, &pipe_server, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
len = sizeof buf;
|
||||
r = uv_pipe_getsockname(&pipe_server, buf, &len);
|
||||
ASSERT(r == UV_EBADF);
|
||||
|
||||
len = sizeof buf;
|
||||
r = uv_pipe_getpeername(&pipe_server, buf, &len);
|
||||
ASSERT(r == UV_EBADF);
|
||||
|
||||
r = uv_pipe_bind(&pipe_server, TEST_PIPENAME);
|
||||
ASSERT(r == 0);
|
||||
|
||||
len = sizeof buf;
|
||||
r = uv_pipe_getsockname(&pipe_server, buf, &len);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(buf[len - 1] != 0);
|
||||
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
|
||||
|
||||
len = sizeof buf;
|
||||
r = uv_pipe_getpeername(&pipe_server, buf, &len);
|
||||
ASSERT(r == UV_ENOTCONN);
|
||||
|
||||
r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_pipe_init(loop, &pipe_client, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
len = sizeof buf;
|
||||
r = uv_pipe_getsockname(&pipe_client, buf, &len);
|
||||
ASSERT(r == UV_EBADF);
|
||||
|
||||
len = sizeof buf;
|
||||
r = uv_pipe_getpeername(&pipe_client, buf, &len);
|
||||
ASSERT(r == UV_EBADF);
|
||||
|
||||
uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb);
|
||||
|
||||
len = sizeof buf;
|
||||
r = uv_pipe_getsockname(&pipe_client, buf, &len);
|
||||
ASSERT(r == 0 && len == 0);
|
||||
|
||||
len = sizeof buf;
|
||||
r = uv_pipe_getpeername(&pipe_client, buf, &len);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(buf[len - 1] != 0);
|
||||
ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
|
||||
|
||||
r = uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(pipe_client_connect_cb_called == 1);
|
||||
ASSERT(pipe_close_cb_called == 2);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_getsockname_abstract) {
|
||||
#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";
|
||||
|
||||
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(), &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);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
#else
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_IMPL(pipe_getsockname_blocking) {
|
||||
#ifdef _WIN32
|
||||
HANDLE readh, writeh;
|
||||
int readfd;
|
||||
char buf1[1024], buf2[1024];
|
||||
size_t len1, len2;
|
||||
int r;
|
||||
|
||||
r = CreatePipe(&readh, &writeh, NULL, 65536);
|
||||
ASSERT(r != 0);
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &pipe_client, 0);
|
||||
ASSERT(r == 0);
|
||||
readfd = _open_osfhandle((intptr_t)readh, _O_RDONLY);
|
||||
ASSERT(r != -1);
|
||||
r = uv_pipe_open(&pipe_client, readfd);
|
||||
ASSERT(r == 0);
|
||||
r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
|
||||
ASSERT(r == 0);
|
||||
Sleep(100);
|
||||
r = uv_read_stop((uv_stream_t*)&pipe_client);
|
||||
ASSERT(r == 0);
|
||||
|
||||
len1 = sizeof buf1;
|
||||
r = uv_pipe_getsockname(&pipe_client, buf1, &len1);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(buf1[len1 - 1] != 0);
|
||||
|
||||
r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
|
||||
ASSERT(r == 0);
|
||||
Sleep(100);
|
||||
|
||||
len2 = sizeof buf2;
|
||||
r = uv_pipe_getsockname(&pipe_client, buf2, &len2);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(buf2[len2 - 1] != 0);
|
||||
|
||||
r = uv_read_stop((uv_stream_t*)&pipe_client);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(len1 == len2);
|
||||
ASSERT(memcmp(buf1, buf2, len1) == 0);
|
||||
|
||||
pipe_close_cb_called = 0;
|
||||
uv_close((uv_handle_t*)&pipe_client, pipe_close_cb);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(pipe_close_cb_called == 1);
|
||||
|
||||
_close(readfd);
|
||||
CloseHandle(writeh);
|
||||
#endif
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
|
||||
* 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 void connection_cb(uv_stream_t* server, int status) {
|
||||
ASSERT(0 && "this will never be called");
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_pending_instances) {
|
||||
int r;
|
||||
uv_pipe_t pipe_handle;
|
||||
uv_loop_t* loop;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
r = uv_pipe_init(loop, &pipe_handle, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_pipe_pending_instances(&pipe_handle, 8);
|
||||
|
||||
r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_pipe_pending_instances(&pipe_handle, 16);
|
||||
|
||||
r = uv_listen((uv_stream_t*)&pipe_handle, 128, connection_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_close((uv_handle_t*)&pipe_handle, NULL);
|
||||
|
||||
r = uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/* 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"
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
/* NOTE: size should be divisible by 2 */
|
||||
static uv_pipe_t incoming[4];
|
||||
static unsigned int incoming_count;
|
||||
static unsigned int close_called;
|
||||
|
||||
|
||||
static void set_nonblocking(uv_os_sock_t sock) {
|
||||
int r;
|
||||
#ifdef _WIN32
|
||||
unsigned long on = 1;
|
||||
r = ioctlsocket(sock, FIONBIO, &on);
|
||||
ASSERT(r == 0);
|
||||
#else
|
||||
int flags = fcntl(sock, F_GETFL, 0);
|
||||
ASSERT(flags >= 0);
|
||||
r = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
|
||||
ASSERT(r >= 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
close_called++;
|
||||
}
|
||||
|
||||
|
||||
static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
|
||||
static char base[1];
|
||||
|
||||
buf->base = base;
|
||||
buf->len = sizeof(base);
|
||||
}
|
||||
|
||||
|
||||
static void read_cb(uv_stream_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
uv_pipe_t* p;
|
||||
uv_pipe_t* inc;
|
||||
uv_handle_type pending;
|
||||
unsigned int i;
|
||||
|
||||
p = (uv_pipe_t*) handle;
|
||||
ASSERT(nread >= 0);
|
||||
|
||||
while (uv_pipe_pending_count(p) != 0) {
|
||||
pending = uv_pipe_pending_type(p);
|
||||
ASSERT(pending == UV_NAMED_PIPE);
|
||||
|
||||
ASSERT(incoming_count < ARRAY_SIZE(incoming));
|
||||
inc = &incoming[incoming_count++];
|
||||
ASSERT(0 == uv_pipe_init(p->loop, inc, 0));
|
||||
ASSERT(0 == uv_accept(handle, (uv_stream_t*) inc));
|
||||
}
|
||||
|
||||
if (incoming_count != ARRAY_SIZE(incoming))
|
||||
return;
|
||||
|
||||
ASSERT(0 == uv_read_stop((uv_stream_t*) p));
|
||||
uv_close((uv_handle_t*) p, close_cb);
|
||||
for (i = 0; i < ARRAY_SIZE(incoming); i++)
|
||||
uv_close((uv_handle_t*) &incoming[i], close_cb);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_sendmsg) {
|
||||
uv_pipe_t p;
|
||||
int r;
|
||||
int fds[2];
|
||||
int send_fds[ARRAY_SIZE(incoming)];
|
||||
struct msghdr msg;
|
||||
char scratch[64];
|
||||
struct cmsghdr *cmsg;
|
||||
unsigned int i;
|
||||
uv_buf_t buf;
|
||||
|
||||
ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
|
||||
for (i = 0; i < ARRAY_SIZE(send_fds); i += 2)
|
||||
ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, send_fds + i));
|
||||
ASSERT(i == ARRAY_SIZE(send_fds));
|
||||
ASSERT(0 == uv_pipe_init(uv_default_loop(), &p, 1));
|
||||
ASSERT(0 == uv_pipe_open(&p, fds[1]));
|
||||
|
||||
buf = uv_buf_init("X", 1);
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_iov = (struct iovec*) &buf;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
msg.msg_control = (void*) scratch;
|
||||
msg.msg_controllen = CMSG_LEN(sizeof(send_fds));
|
||||
ASSERT(sizeof(scratch) >= msg.msg_controllen);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = msg.msg_controllen;
|
||||
|
||||
/* silence aliasing warning */
|
||||
{
|
||||
void* pv = CMSG_DATA(cmsg);
|
||||
int* pi = pv;
|
||||
for (i = 0; i < ARRAY_SIZE(send_fds); i++)
|
||||
pi[i] = send_fds[i];
|
||||
}
|
||||
|
||||
set_nonblocking(fds[1]);
|
||||
ASSERT(0 == uv_read_start((uv_stream_t*) &p, alloc_cb, read_cb));
|
||||
|
||||
do
|
||||
r = sendmsg(fds[0], &msg, 0);
|
||||
while (r == -1 && errno == EINTR);
|
||||
ASSERT(r == 1);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(ARRAY_SIZE(incoming) == incoming_count);
|
||||
ASSERT(ARRAY_SIZE(incoming) + 1 == close_called);
|
||||
close(fds[0]);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !_WIN32 */
|
||||
|
||||
TEST_IMPL(pipe_sendmsg) {
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
@@ -0,0 +1,91 @@
|
||||
/* 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 <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
static uv_pipe_t pipe_client;
|
||||
static uv_pipe_t pipe_server;
|
||||
static uv_connect_t connect_req;
|
||||
|
||||
static int pipe_close_cb_called = 0;
|
||||
static int pipe_client_connect_cb_called = 0;
|
||||
|
||||
|
||||
static void pipe_close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle == (uv_handle_t*) &pipe_client ||
|
||||
handle == (uv_handle_t*) &pipe_server);
|
||||
pipe_close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void pipe_client_connect_cb(uv_connect_t* req, int status) {
|
||||
ASSERT(req == &connect_req);
|
||||
ASSERT(status == 0);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static void pipe_server_connection_cb(uv_stream_t* handle, int status) {
|
||||
/* This function *may* be called, depending on whether accept or the
|
||||
* connection callback is called first.
|
||||
*/
|
||||
ASSERT(status == 0);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_server_close) {
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
ASSERT(loop != NULL);
|
||||
|
||||
r = uv_pipe_init(loop, &pipe_server, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_pipe_bind(&pipe_server, TEST_PIPENAME);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_pipe_init(loop, &pipe_client, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb);
|
||||
|
||||
r = uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(pipe_client_connect_cb_called == 1);
|
||||
ASSERT(pipe_close_cb_called == 2);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/* Copyright (c) 2015, Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* 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.h"
|
||||
#include "task.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
TEST_IMPL(pipe_set_non_blocking) {
|
||||
RETURN_SKIP("Test not implemented on Windows.");
|
||||
}
|
||||
|
||||
#else /* !_WIN32 */
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct thread_ctx {
|
||||
uv_barrier_t barrier;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static void thread_main(void* arg) {
|
||||
struct thread_ctx* ctx;
|
||||
char buf[4096];
|
||||
ssize_t n;
|
||||
|
||||
ctx = arg;
|
||||
uv_barrier_wait(&ctx->barrier);
|
||||
|
||||
do
|
||||
n = read(ctx->fd, buf, sizeof(buf));
|
||||
while (n > 0 || (n == -1 && errno == EINTR));
|
||||
|
||||
ASSERT(n == 0);
|
||||
}
|
||||
|
||||
TEST_IMPL(pipe_set_non_blocking) {
|
||||
struct thread_ctx ctx;
|
||||
uv_pipe_t pipe_handle;
|
||||
uv_thread_t thread;
|
||||
size_t nwritten;
|
||||
char data[4096];
|
||||
uv_buf_t buf;
|
||||
int fd[2];
|
||||
int n;
|
||||
|
||||
ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
|
||||
ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fd));
|
||||
ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
|
||||
ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &pipe_handle, 1));
|
||||
|
||||
ctx.fd = fd[1];
|
||||
ASSERT(0 == uv_barrier_init(&ctx.barrier, 2));
|
||||
ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx));
|
||||
uv_barrier_wait(&ctx.barrier);
|
||||
|
||||
buf.len = sizeof(data);
|
||||
buf.base = data;
|
||||
memset(data, '.', sizeof(data));
|
||||
|
||||
nwritten = 0;
|
||||
while (nwritten < 10 << 20) {
|
||||
/* The stream is in blocking mode so uv_try_write() should always succeed
|
||||
* with the exact number of bytes that we wanted written.
|
||||
*/
|
||||
n = uv_try_write((uv_stream_t*) &pipe_handle, &buf, 1);
|
||||
ASSERT(n == sizeof(data));
|
||||
nwritten += n;
|
||||
}
|
||||
|
||||
uv_close((uv_handle_t*) &pipe_handle, NULL);
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
ASSERT(0 == close(fd[1])); /* fd[0] is closed by uv_close(). */
|
||||
uv_barrier_destroy(&ctx.barrier);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !_WIN32 */
|
||||
@@ -0,0 +1,126 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
|
||||
TEST_IMPL(platform_output) {
|
||||
char buffer[512];
|
||||
size_t rss;
|
||||
size_t size;
|
||||
double uptime;
|
||||
uv_rusage_t rusage;
|
||||
uv_cpu_info_t* cpus;
|
||||
uv_interface_address_t* interfaces;
|
||||
int count;
|
||||
int i;
|
||||
int err;
|
||||
|
||||
err = uv_get_process_title(buffer, sizeof(buffer));
|
||||
ASSERT(err == 0);
|
||||
printf("uv_get_process_title: %s\n", buffer);
|
||||
|
||||
size = sizeof(buffer);
|
||||
err = uv_cwd(buffer, &size);
|
||||
ASSERT(err == 0);
|
||||
printf("uv_cwd: %s\n", buffer);
|
||||
|
||||
err = uv_resident_set_memory(&rss);
|
||||
ASSERT(err == 0);
|
||||
printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss);
|
||||
|
||||
err = uv_uptime(&uptime);
|
||||
ASSERT(err == 0);
|
||||
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);
|
||||
|
||||
printf("uv_cpu_info:\n");
|
||||
for (i = 0; i < count; i++) {
|
||||
printf(" model: %s\n", cpus[i].model);
|
||||
printf(" speed: %d\n", cpus[i].speed);
|
||||
printf(" times.sys: %llu\n", (unsigned long long) cpus[i].cpu_times.sys);
|
||||
printf(" times.user: %llu\n",
|
||||
(unsigned long long) cpus[i].cpu_times.user);
|
||||
printf(" times.idle: %llu\n",
|
||||
(unsigned long long) cpus[i].cpu_times.idle);
|
||||
printf(" times.irq: %llu\n", (unsigned long long) cpus[i].cpu_times.irq);
|
||||
printf(" times.nice: %llu\n",
|
||||
(unsigned long long) cpus[i].cpu_times.nice);
|
||||
}
|
||||
uv_free_cpu_info(cpus, count);
|
||||
|
||||
err = uv_interface_addresses(&interfaces, &count);
|
||||
ASSERT(err == 0);
|
||||
|
||||
printf("uv_interface_addresses:\n");
|
||||
for (i = 0; i < count; i++) {
|
||||
printf(" name: %s\n", interfaces[i].name);
|
||||
printf(" internal: %d\n", interfaces[i].is_internal);
|
||||
printf(" physical address: ");
|
||||
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
(unsigned char)interfaces[i].phys_addr[0],
|
||||
(unsigned char)interfaces[i].phys_addr[1],
|
||||
(unsigned char)interfaces[i].phys_addr[2],
|
||||
(unsigned char)interfaces[i].phys_addr[3],
|
||||
(unsigned char)interfaces[i].phys_addr[4],
|
||||
(unsigned char)interfaces[i].phys_addr[5]);
|
||||
|
||||
if (interfaces[i].address.address4.sin_family == AF_INET) {
|
||||
uv_ip4_name(&interfaces[i].address.address4, buffer, sizeof(buffer));
|
||||
} else if (interfaces[i].address.address4.sin_family == AF_INET6) {
|
||||
uv_ip6_name(&interfaces[i].address.address6, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
printf(" address: %s\n", buffer);
|
||||
|
||||
if (interfaces[i].netmask.netmask4.sin_family == AF_INET) {
|
||||
uv_ip4_name(&interfaces[i].netmask.netmask4, buffer, sizeof(buffer));
|
||||
printf(" netmask: %s\n", buffer);
|
||||
} else if (interfaces[i].netmask.netmask4.sin_family == AF_INET6) {
|
||||
uv_ip6_name(&interfaces[i].netmask.netmask6, buffer, sizeof(buffer));
|
||||
printf(" netmask: %s\n", buffer);
|
||||
} else {
|
||||
printf(" netmask: none\n");
|
||||
}
|
||||
}
|
||||
uv_free_interface_addresses(interfaces, count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/* Copyright Bert Belder, and other libuv 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.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
#ifdef _MSC_VER /* msvc */
|
||||
# define NO_INLINE __declspec(noinline)
|
||||
#else /* gcc */
|
||||
# define NO_INLINE __attribute__ ((noinline))
|
||||
#endif
|
||||
|
||||
|
||||
uv_os_sock_t sock;
|
||||
uv_poll_t handle;
|
||||
|
||||
static int close_cb_called = 0;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* h) {
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void poll_cb(uv_poll_t* h, int status, int events) {
|
||||
ASSERT(0 && "should never get here");
|
||||
}
|
||||
|
||||
|
||||
static void NO_INLINE close_socket_and_verify_stack() {
|
||||
const uint32_t MARKER = 0xDEADBEEF;
|
||||
const int VERIFY_AFTER = 10; /* ms */
|
||||
int r;
|
||||
|
||||
volatile uint32_t data[65536];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data); i++)
|
||||
data[i] = MARKER;
|
||||
|
||||
r = closesocket(sock);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_sleep(VERIFY_AFTER);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data); i++)
|
||||
ASSERT(data[i] == MARKER);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(poll_close_doesnt_corrupt_stack) {
|
||||
struct WSAData wsa_data;
|
||||
int r;
|
||||
unsigned long on;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
|
||||
ASSERT(r == 0);
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
ASSERT(sock != INVALID_SOCKET);
|
||||
on = 1;
|
||||
r = ioctlsocket(sock, FIONBIO, &on);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = connect(sock, (const struct sockaddr*) &addr, sizeof addr);
|
||||
ASSERT(r != 0);
|
||||
ASSERT(WSAGetLastError() == WSAEWOULDBLOCK);
|
||||
|
||||
r = uv_poll_init_socket(uv_default_loop(), &handle, sock);
|
||||
ASSERT(r == 0);
|
||||
r = uv_poll_start(&handle, UV_READABLE | UV_WRITABLE, poll_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_close((uv_handle_t*) &handle, close_cb);
|
||||
|
||||
close_socket_and_verify_stack();
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
@@ -0,0 +1,73 @@
|
||||
/* 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 <errno.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <fcntl.h>
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
#define NUM_SOCKETS 64
|
||||
|
||||
|
||||
static int close_cb_called = 0;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(poll_close) {
|
||||
uv_os_sock_t sockets[NUM_SOCKETS];
|
||||
uv_poll_t poll_handles[NUM_SOCKETS];
|
||||
int i;
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
struct WSAData wsa_data;
|
||||
int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < NUM_SOCKETS; i++) {
|
||||
sockets[i] = socket(AF_INET, SOCK_STREAM, 0);
|
||||
uv_poll_init_socket(uv_default_loop(), &poll_handles[i], sockets[i]);
|
||||
uv_poll_start(&poll_handles[i], UV_READABLE | UV_WRITABLE, NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_SOCKETS; i++) {
|
||||
uv_close((uv_handle_t*) &poll_handles[i], close_cb);
|
||||
}
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(close_cb_called == NUM_SOCKETS);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
uv_os_sock_t sock;
|
||||
uv_poll_t handle;
|
||||
|
||||
static int close_cb_called = 0;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* h) {
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void poll_cb(uv_poll_t* h, int status, int events) {
|
||||
int r;
|
||||
|
||||
ASSERT(status == 0);
|
||||
ASSERT(h == &handle);
|
||||
|
||||
r = uv_poll_start(&handle, UV_READABLE, poll_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
closesocket(sock);
|
||||
uv_close((uv_handle_t*) &handle, close_cb);
|
||||
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(poll_closesocket) {
|
||||
struct WSAData wsa_data;
|
||||
int r;
|
||||
unsigned long on;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
|
||||
ASSERT(r == 0);
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
ASSERT(sock != INVALID_SOCKET);
|
||||
on = 1;
|
||||
r = ioctlsocket(sock, FIONBIO, &on);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = connect(sock, (const struct sockaddr*) &addr, sizeof addr);
|
||||
ASSERT(r != 0);
|
||||
ASSERT(WSAGetLastError() == WSAEWOULDBLOCK);
|
||||
|
||||
r = uv_poll_init_socket(uv_default_loop(), &handle, sock);
|
||||
ASSERT(r == 0);
|
||||
r = uv_poll_start(&handle, UV_WRITABLE, poll_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,560 @@
|
||||
/* 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 <errno.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
|
||||
#define NUM_CLIENTS 5
|
||||
#define TRANSFER_BYTES (1 << 16)
|
||||
|
||||
#undef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b));
|
||||
|
||||
|
||||
typedef enum {
|
||||
UNIDIRECTIONAL,
|
||||
DUPLEX
|
||||
} test_mode_t;
|
||||
|
||||
typedef struct connection_context_s {
|
||||
uv_poll_t poll_handle;
|
||||
uv_timer_t timer_handle;
|
||||
uv_os_sock_t sock;
|
||||
size_t read, sent;
|
||||
int is_server_connection;
|
||||
int open_handles;
|
||||
int got_fin, sent_fin;
|
||||
unsigned int events, delayed_events;
|
||||
} connection_context_t;
|
||||
|
||||
typedef struct server_context_s {
|
||||
uv_poll_t poll_handle;
|
||||
uv_os_sock_t sock;
|
||||
int connections;
|
||||
} server_context_t;
|
||||
|
||||
|
||||
static void delay_timer_cb(uv_timer_t* timer);
|
||||
|
||||
|
||||
static test_mode_t test_mode = DUPLEX;
|
||||
|
||||
static int closed_connections = 0;
|
||||
|
||||
static int valid_writable_wakeups = 0;
|
||||
static int spurious_writable_wakeups = 0;
|
||||
|
||||
|
||||
static int got_eagain(void) {
|
||||
#ifdef _WIN32
|
||||
return WSAGetLastError() == WSAEWOULDBLOCK;
|
||||
#else
|
||||
return errno == EAGAIN
|
||||
|| errno == EINPROGRESS
|
||||
#ifdef EWOULDBLOCK
|
||||
|| errno == EWOULDBLOCK;
|
||||
#endif
|
||||
;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static uv_os_sock_t create_bound_socket (struct sockaddr_in bind_addr) {
|
||||
uv_os_sock_t sock;
|
||||
int r;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
#ifdef _WIN32
|
||||
ASSERT(sock != INVALID_SOCKET);
|
||||
#else
|
||||
ASSERT(sock >= 0);
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
{
|
||||
/* Allow reuse of the port. */
|
||||
int yes = 1;
|
||||
r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
r = bind(sock, (const struct sockaddr*) &bind_addr, sizeof bind_addr);
|
||||
ASSERT(r == 0);
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
static void close_socket(uv_os_sock_t sock) {
|
||||
int r;
|
||||
#ifdef _WIN32
|
||||
r = closesocket(sock);
|
||||
#else
|
||||
r = close(sock);
|
||||
#endif
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static connection_context_t* create_connection_context(
|
||||
uv_os_sock_t sock, int is_server_connection) {
|
||||
int r;
|
||||
connection_context_t* context;
|
||||
|
||||
context = (connection_context_t*) malloc(sizeof *context);
|
||||
ASSERT(context != NULL);
|
||||
|
||||
context->sock = sock;
|
||||
context->is_server_connection = is_server_connection;
|
||||
context->read = 0;
|
||||
context->sent = 0;
|
||||
context->open_handles = 0;
|
||||
context->events = 0;
|
||||
context->delayed_events = 0;
|
||||
context->got_fin = 0;
|
||||
context->sent_fin = 0;
|
||||
|
||||
r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock);
|
||||
context->open_handles++;
|
||||
context->poll_handle.data = context;
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_timer_init(uv_default_loop(), &context->timer_handle);
|
||||
context->open_handles++;
|
||||
context->timer_handle.data = context;
|
||||
ASSERT(r == 0);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
static void connection_close_cb(uv_handle_t* handle) {
|
||||
connection_context_t* context = (connection_context_t*) handle->data;
|
||||
|
||||
if (--context->open_handles == 0) {
|
||||
if (test_mode == DUPLEX || context->is_server_connection) {
|
||||
ASSERT(context->read == TRANSFER_BYTES);
|
||||
} else {
|
||||
ASSERT(context->read == 0);
|
||||
}
|
||||
|
||||
if (test_mode == DUPLEX || !context->is_server_connection) {
|
||||
ASSERT(context->sent == TRANSFER_BYTES);
|
||||
} else {
|
||||
ASSERT(context->sent == 0);
|
||||
}
|
||||
|
||||
closed_connections++;
|
||||
|
||||
free(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void destroy_connection_context(connection_context_t* context) {
|
||||
uv_close((uv_handle_t*) &context->poll_handle, connection_close_cb);
|
||||
uv_close((uv_handle_t*) &context->timer_handle, connection_close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void connection_poll_cb(uv_poll_t* handle, int status, int events) {
|
||||
connection_context_t* context = (connection_context_t*) handle->data;
|
||||
unsigned int new_events;
|
||||
int r;
|
||||
|
||||
ASSERT(status == 0);
|
||||
ASSERT(events & context->events);
|
||||
ASSERT(!(events & ~context->events));
|
||||
|
||||
new_events = context->events;
|
||||
|
||||
if (events & UV_READABLE) {
|
||||
int action = rand() % 7;
|
||||
|
||||
switch (action) {
|
||||
case 0:
|
||||
case 1: {
|
||||
/* Read a couple of bytes. */
|
||||
static char buffer[74];
|
||||
r = recv(context->sock, buffer, sizeof buffer, 0);
|
||||
ASSERT(r >= 0);
|
||||
|
||||
if (r > 0) {
|
||||
context->read += r;
|
||||
} else {
|
||||
/* Got FIN. */
|
||||
context->got_fin = 1;
|
||||
new_events &= ~UV_READABLE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
case 3: {
|
||||
/* Read until EAGAIN. */
|
||||
static char buffer[931];
|
||||
r = recv(context->sock, buffer, sizeof buffer, 0);
|
||||
ASSERT(r >= 0);
|
||||
|
||||
while (r > 0) {
|
||||
context->read += r;
|
||||
r = recv(context->sock, buffer, sizeof buffer, 0);
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
/* Got FIN. */
|
||||
context->got_fin = 1;
|
||||
new_events &= ~UV_READABLE;
|
||||
} else {
|
||||
ASSERT(got_eagain());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
/* Ignore. */
|
||||
break;
|
||||
|
||||
case 5:
|
||||
/* Stop reading for a while. Restart in timer callback. */
|
||||
new_events &= ~UV_READABLE;
|
||||
if (!uv_is_active((uv_handle_t*) &context->timer_handle)) {
|
||||
context->delayed_events = UV_READABLE;
|
||||
uv_timer_start(&context->timer_handle, delay_timer_cb, 10, 0);
|
||||
} else {
|
||||
context->delayed_events |= UV_READABLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
/* Fudge with the event mask. */
|
||||
uv_poll_start(&context->poll_handle, UV_WRITABLE, connection_poll_cb);
|
||||
uv_poll_start(&context->poll_handle, UV_READABLE, connection_poll_cb);
|
||||
context->events = UV_READABLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (events & UV_WRITABLE) {
|
||||
if (context->sent < TRANSFER_BYTES &&
|
||||
!(test_mode == UNIDIRECTIONAL && context->is_server_connection)) {
|
||||
/* We have to send more bytes. */
|
||||
int action = rand() % 7;
|
||||
|
||||
switch (action) {
|
||||
case 0:
|
||||
case 1: {
|
||||
/* Send a couple of bytes. */
|
||||
static char buffer[103];
|
||||
|
||||
int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer);
|
||||
ASSERT(send_bytes > 0);
|
||||
|
||||
r = send(context->sock, buffer, send_bytes, 0);
|
||||
|
||||
if (r < 0) {
|
||||
ASSERT(got_eagain());
|
||||
spurious_writable_wakeups++;
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERT(r > 0);
|
||||
context->sent += r;
|
||||
valid_writable_wakeups++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
case 3: {
|
||||
/* Send until EAGAIN. */
|
||||
static char buffer[1234];
|
||||
|
||||
int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer);
|
||||
ASSERT(send_bytes > 0);
|
||||
|
||||
r = send(context->sock, buffer, send_bytes, 0);
|
||||
|
||||
if (r < 0) {
|
||||
ASSERT(got_eagain());
|
||||
spurious_writable_wakeups++;
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERT(r > 0);
|
||||
valid_writable_wakeups++;
|
||||
context->sent += r;
|
||||
|
||||
while (context->sent < TRANSFER_BYTES) {
|
||||
send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer);
|
||||
ASSERT(send_bytes > 0);
|
||||
|
||||
r = send(context->sock, buffer, send_bytes, 0);
|
||||
|
||||
if (r <= 0) break;
|
||||
context->sent += r;
|
||||
}
|
||||
ASSERT(r > 0 || got_eagain());
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
/* Ignore. */
|
||||
break;
|
||||
|
||||
case 5:
|
||||
/* Stop sending for a while. Restart in timer callback. */
|
||||
new_events &= ~UV_WRITABLE;
|
||||
if (!uv_is_active((uv_handle_t*) &context->timer_handle)) {
|
||||
context->delayed_events = UV_WRITABLE;
|
||||
uv_timer_start(&context->timer_handle, delay_timer_cb, 100, 0);
|
||||
} else {
|
||||
context->delayed_events |= UV_WRITABLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
/* Fudge with the event mask. */
|
||||
uv_poll_start(&context->poll_handle,
|
||||
UV_READABLE,
|
||||
connection_poll_cb);
|
||||
uv_poll_start(&context->poll_handle,
|
||||
UV_WRITABLE,
|
||||
connection_poll_cb);
|
||||
context->events = UV_WRITABLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Nothing more to write. Send FIN. */
|
||||
int r;
|
||||
#ifdef _WIN32
|
||||
r = shutdown(context->sock, SD_SEND);
|
||||
#else
|
||||
r = shutdown(context->sock, SHUT_WR);
|
||||
#endif
|
||||
ASSERT(r == 0);
|
||||
context->sent_fin = 1;
|
||||
new_events &= ~UV_WRITABLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->got_fin && context->sent_fin) {
|
||||
/* Sent and received FIN. Close and destroy context. */
|
||||
close_socket(context->sock);
|
||||
destroy_connection_context(context);
|
||||
context->events = 0;
|
||||
|
||||
} else if (new_events != context->events) {
|
||||
/* Poll mask changed. Call uv_poll_start again. */
|
||||
context->events = new_events;
|
||||
uv_poll_start(handle, new_events, connection_poll_cb);
|
||||
}
|
||||
|
||||
/* Assert that uv_is_active works correctly for poll handles. */
|
||||
if (context->events != 0) {
|
||||
ASSERT(1 == uv_is_active((uv_handle_t*) handle));
|
||||
} else {
|
||||
ASSERT(0 == uv_is_active((uv_handle_t*) handle));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void delay_timer_cb(uv_timer_t* timer) {
|
||||
connection_context_t* context = (connection_context_t*) timer->data;
|
||||
int r;
|
||||
|
||||
/* Timer should auto stop. */
|
||||
ASSERT(0 == uv_is_active((uv_handle_t*) timer));
|
||||
|
||||
/* Add the requested events to the poll mask. */
|
||||
ASSERT(context->delayed_events != 0);
|
||||
context->events |= context->delayed_events;
|
||||
context->delayed_events = 0;
|
||||
|
||||
r = uv_poll_start(&context->poll_handle,
|
||||
context->events,
|
||||
connection_poll_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static server_context_t* create_server_context(
|
||||
uv_os_sock_t sock) {
|
||||
int r;
|
||||
server_context_t* context;
|
||||
|
||||
context = (server_context_t*) malloc(sizeof *context);
|
||||
ASSERT(context != NULL);
|
||||
|
||||
context->sock = sock;
|
||||
context->connections = 0;
|
||||
|
||||
r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock);
|
||||
context->poll_handle.data = context;
|
||||
ASSERT(r == 0);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
static void server_close_cb(uv_handle_t* handle) {
|
||||
server_context_t* context = (server_context_t*) handle->data;
|
||||
free(context);
|
||||
}
|
||||
|
||||
|
||||
static void destroy_server_context(server_context_t* context) {
|
||||
uv_close((uv_handle_t*) &context->poll_handle, server_close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void server_poll_cb(uv_poll_t* handle, int status, int events) {
|
||||
server_context_t* server_context = (server_context_t*)
|
||||
handle->data;
|
||||
connection_context_t* connection_context;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len;
|
||||
uv_os_sock_t sock;
|
||||
int r;
|
||||
|
||||
addr_len = sizeof addr;
|
||||
sock = accept(server_context->sock, (struct sockaddr*) &addr, &addr_len);
|
||||
#ifdef _WIN32
|
||||
ASSERT(sock != INVALID_SOCKET);
|
||||
#else
|
||||
ASSERT(sock >= 0);
|
||||
#endif
|
||||
|
||||
connection_context = create_connection_context(sock, 1);
|
||||
connection_context->events = UV_READABLE | UV_WRITABLE;
|
||||
r = uv_poll_start(&connection_context->poll_handle,
|
||||
UV_READABLE | UV_WRITABLE,
|
||||
connection_poll_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
if (++server_context->connections == NUM_CLIENTS) {
|
||||
close_socket(server_context->sock);
|
||||
destroy_server_context(server_context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void start_server(void) {
|
||||
server_context_t* context;
|
||||
struct sockaddr_in addr;
|
||||
uv_os_sock_t sock;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
sock = create_bound_socket(addr);
|
||||
context = create_server_context(sock);
|
||||
|
||||
r = listen(sock, 100);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_poll_start(&context->poll_handle, UV_READABLE, server_poll_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void start_client(void) {
|
||||
uv_os_sock_t sock;
|
||||
connection_context_t* context;
|
||||
struct sockaddr_in server_addr;
|
||||
struct sockaddr_in addr;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &addr));
|
||||
|
||||
sock = create_bound_socket(addr);
|
||||
context = create_connection_context(sock, 0);
|
||||
|
||||
context->events = UV_READABLE | UV_WRITABLE;
|
||||
r = uv_poll_start(&context->poll_handle,
|
||||
UV_READABLE | UV_WRITABLE,
|
||||
connection_poll_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = connect(sock, (struct sockaddr*) &server_addr, sizeof server_addr);
|
||||
ASSERT(r == 0 || got_eagain());
|
||||
}
|
||||
|
||||
|
||||
static void start_poll_test(void) {
|
||||
int i, r;
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
struct WSAData wsa_data;
|
||||
int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
start_server();
|
||||
|
||||
for (i = 0; i < NUM_CLIENTS; i++)
|
||||
start_client();
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Assert that at most five percent of the writable wakeups was spurious. */
|
||||
ASSERT(spurious_writable_wakeups == 0 ||
|
||||
(valid_writable_wakeups + spurious_writable_wakeups) /
|
||||
spurious_writable_wakeups > 20);
|
||||
|
||||
ASSERT(closed_connections == NUM_CLIENTS * 2);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(poll_duplex) {
|
||||
test_mode = DUPLEX;
|
||||
start_poll_test();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(poll_unidirectional) {
|
||||
test_mode = UNIDIRECTIONAL;
|
||||
start_poll_test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
|
||||
static void set_title(const char* title) {
|
||||
char buffer[512];
|
||||
int err;
|
||||
|
||||
err = uv_get_process_title(buffer, sizeof(buffer));
|
||||
ASSERT(err == 0);
|
||||
|
||||
err = uv_set_process_title(title);
|
||||
ASSERT(err == 0);
|
||||
|
||||
err = uv_get_process_title(buffer, sizeof(buffer));
|
||||
ASSERT(err == 0);
|
||||
|
||||
ASSERT(strcmp(buffer, title) == 0);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(process_title) {
|
||||
#if defined(__sun)
|
||||
RETURN_SKIP("uv_(get|set)_process_title is not implemented.");
|
||||
#else
|
||||
/* 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");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
/* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static uv_write_t write_req;
|
||||
static uv_shutdown_t shutdown_req;
|
||||
static uv_connect_t connect_req;
|
||||
|
||||
static char buffer[32767];
|
||||
|
||||
static int req_cb_called;
|
||||
static int connect_cb_called;
|
||||
static int write_cb_called;
|
||||
static int shutdown_cb_called;
|
||||
static int close_cb_called;
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void do_close(void* handle) {
|
||||
close_cb_called = 0;
|
||||
uv_close((uv_handle_t*)handle, close_cb);
|
||||
ASSERT(close_cb_called == 0);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(close_cb_called == 1);
|
||||
}
|
||||
|
||||
|
||||
static void fail_cb(void) {
|
||||
FATAL("fail_cb should not have been called");
|
||||
}
|
||||
|
||||
|
||||
static void fail_cb2(void) {
|
||||
ASSERT(0 && "fail_cb2 should not have been called");
|
||||
}
|
||||
|
||||
|
||||
static void req_cb(uv_handle_t* req, int status) {
|
||||
req_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void shutdown_cb(uv_shutdown_t* req, int status) {
|
||||
ASSERT(req == &shutdown_req);
|
||||
shutdown_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void write_cb(uv_write_t* req, int status) {
|
||||
ASSERT(req == &write_req);
|
||||
uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
|
||||
write_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void connect_and_write(uv_connect_t* req, int status) {
|
||||
uv_buf_t buf = uv_buf_init(buffer, sizeof buffer);
|
||||
ASSERT(req == &connect_req);
|
||||
ASSERT(status == 0);
|
||||
uv_write(&write_req, req->handle, &buf, 1, write_cb);
|
||||
connect_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void connect_and_shutdown(uv_connect_t* req, int status) {
|
||||
ASSERT(req == &connect_req);
|
||||
ASSERT(status == 0);
|
||||
uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
|
||||
connect_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(ref) {
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(idle_ref) {
|
||||
uv_idle_t h;
|
||||
uv_idle_init(uv_default_loop(), &h);
|
||||
uv_idle_start(&h, (uv_idle_cb) fail_cb2);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(async_ref) {
|
||||
uv_async_t h;
|
||||
uv_async_init(uv_default_loop(), &h, NULL);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(prepare_ref) {
|
||||
uv_prepare_t h;
|
||||
uv_prepare_init(uv_default_loop(), &h);
|
||||
uv_prepare_start(&h, (uv_prepare_cb) fail_cb2);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(check_ref) {
|
||||
uv_check_t h;
|
||||
uv_check_init(uv_default_loop(), &h);
|
||||
uv_check_start(&h, (uv_check_cb) fail_cb2);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void prepare_cb(uv_prepare_t* h) {
|
||||
ASSERT(h != NULL);
|
||||
uv_unref((uv_handle_t*)h);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(unref_in_prepare_cb) {
|
||||
uv_prepare_t h;
|
||||
uv_prepare_init(uv_default_loop(), &h);
|
||||
uv_prepare_start(&h, prepare_cb);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(timer_ref) {
|
||||
uv_timer_t h;
|
||||
uv_timer_init(uv_default_loop(), &h);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(timer_ref2) {
|
||||
uv_timer_t h;
|
||||
uv_timer_init(uv_default_loop(), &h);
|
||||
uv_timer_start(&h, (uv_timer_cb)fail_cb, 42, 42);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_event_ref) {
|
||||
uv_fs_event_t h;
|
||||
uv_fs_event_init(uv_default_loop(), &h);
|
||||
uv_fs_event_start(&h, (uv_fs_event_cb)fail_cb, ".", 0);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_poll_ref) {
|
||||
uv_fs_poll_t h;
|
||||
uv_fs_poll_init(uv_default_loop(), &h);
|
||||
uv_fs_poll_start(&h, NULL, ".", 999);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(tcp_ref) {
|
||||
uv_tcp_t h;
|
||||
uv_tcp_init(uv_default_loop(), &h);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(tcp_ref2) {
|
||||
uv_tcp_t h;
|
||||
uv_tcp_init(uv_default_loop(), &h);
|
||||
uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(tcp_ref2b) {
|
||||
uv_tcp_t h;
|
||||
uv_tcp_init(uv_default_loop(), &h);
|
||||
uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_close((uv_handle_t*)&h, close_cb);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(close_cb_called == 1);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(tcp_ref3) {
|
||||
struct sockaddr_in addr;
|
||||
uv_tcp_t h;
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
uv_tcp_init(uv_default_loop(), &h);
|
||||
uv_tcp_connect(&connect_req,
|
||||
&h,
|
||||
(const struct sockaddr*) &addr,
|
||||
connect_and_shutdown);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(connect_cb_called == 1);
|
||||
ASSERT(shutdown_cb_called == 1);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(tcp_ref4) {
|
||||
struct sockaddr_in addr;
|
||||
uv_tcp_t h;
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
uv_tcp_init(uv_default_loop(), &h);
|
||||
uv_tcp_connect(&connect_req,
|
||||
&h,
|
||||
(const struct sockaddr*) &addr,
|
||||
connect_and_write);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(connect_cb_called == 1);
|
||||
ASSERT(write_cb_called == 1);
|
||||
ASSERT(shutdown_cb_called == 1);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(udp_ref) {
|
||||
uv_udp_t h;
|
||||
uv_udp_init(uv_default_loop(), &h);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(udp_ref2) {
|
||||
struct sockaddr_in addr;
|
||||
uv_udp_t h;
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
uv_udp_init(uv_default_loop(), &h);
|
||||
uv_udp_bind(&h, (const struct sockaddr*) &addr, 0);
|
||||
uv_udp_recv_start(&h, (uv_alloc_cb)fail_cb, (uv_udp_recv_cb)fail_cb);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(udp_ref3) {
|
||||
struct sockaddr_in addr;
|
||||
uv_buf_t buf = uv_buf_init("PING", 4);
|
||||
uv_udp_send_t req;
|
||||
uv_udp_t h;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
uv_udp_init(uv_default_loop(), &h);
|
||||
uv_udp_send(&req,
|
||||
&h,
|
||||
&buf,
|
||||
1,
|
||||
(const struct sockaddr*) &addr,
|
||||
(uv_udp_send_cb) req_cb);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(req_cb_called == 1);
|
||||
do_close(&h);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_ref) {
|
||||
uv_pipe_t h;
|
||||
uv_pipe_init(uv_default_loop(), &h, 0);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_ref2) {
|
||||
uv_pipe_t h;
|
||||
uv_pipe_init(uv_default_loop(), &h, 0);
|
||||
uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_ref3) {
|
||||
uv_pipe_t h;
|
||||
uv_pipe_init(uv_default_loop(), &h, 0);
|
||||
uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_shutdown);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(connect_cb_called == 1);
|
||||
ASSERT(shutdown_cb_called == 1);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_ref4) {
|
||||
uv_pipe_t h;
|
||||
uv_pipe_init(uv_default_loop(), &h, 0);
|
||||
uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_write);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(connect_cb_called == 1);
|
||||
ASSERT(write_cb_called == 1);
|
||||
ASSERT(shutdown_cb_called == 1);
|
||||
do_close(&h);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(process_ref) {
|
||||
/* spawn_helper4 blocks indefinitely. */
|
||||
char *argv[] = { NULL, "spawn_helper4", NULL };
|
||||
uv_process_options_t options;
|
||||
size_t exepath_size;
|
||||
char exepath[256];
|
||||
uv_process_t h;
|
||||
int r;
|
||||
|
||||
memset(&options, 0, sizeof(options));
|
||||
exepath_size = sizeof(exepath);
|
||||
|
||||
r = uv_exepath(exepath, &exepath_size);
|
||||
ASSERT(r == 0);
|
||||
|
||||
argv[0] = exepath;
|
||||
options.file = exepath;
|
||||
options.args = argv;
|
||||
options.exit_cb = NULL;
|
||||
|
||||
r = uv_spawn(uv_default_loop(), &h, &options);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
r = uv_process_kill(&h, /* SIGTERM */ 15);
|
||||
ASSERT(r == 0);
|
||||
|
||||
do_close(&h);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(has_ref) {
|
||||
uv_idle_t h;
|
||||
uv_idle_init(uv_default_loop(), &h);
|
||||
uv_ref((uv_handle_t*)&h);
|
||||
ASSERT(uv_has_ref((uv_handle_t*)&h) == 1);
|
||||
uv_unref((uv_handle_t*)&h);
|
||||
ASSERT(uv_has_ref((uv_handle_t*)&h) == 0);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/* 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 int timer_called = 0;
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
ASSERT(handle == &timer_handle);
|
||||
timer_called = 1;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(run_nowait) {
|
||||
int r;
|
||||
uv_timer_init(uv_default_loop(), &timer_handle);
|
||||
uv_timer_start(&timer_handle, timer_cb, 100, 100);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_NOWAIT);
|
||||
ASSERT(r != 0);
|
||||
ASSERT(timer_called == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/* 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"
|
||||
|
||||
#define NUM_TICKS 64
|
||||
|
||||
static uv_idle_t idle_handle;
|
||||
static int idle_counter;
|
||||
|
||||
|
||||
static void idle_cb(uv_idle_t* handle) {
|
||||
ASSERT(handle == &idle_handle);
|
||||
|
||||
if (++idle_counter == NUM_TICKS)
|
||||
uv_idle_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(run_once) {
|
||||
uv_idle_init(uv_default_loop(), &idle_handle);
|
||||
uv_idle_start(&idle_handle, idle_cb);
|
||||
|
||||
while (uv_run(uv_default_loop(), UV_RUN_ONCE));
|
||||
ASSERT(idle_counter == NUM_TICKS);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
uv_mutex_t mutex;
|
||||
uv_sem_t sem;
|
||||
int delay;
|
||||
volatile int posted;
|
||||
} worker_config;
|
||||
|
||||
|
||||
static void worker(void* arg) {
|
||||
worker_config* c = arg;
|
||||
|
||||
if (c->delay)
|
||||
uv_sleep(c->delay);
|
||||
|
||||
uv_mutex_lock(&c->mutex);
|
||||
ASSERT(c->posted == 0);
|
||||
uv_sem_post(&c->sem);
|
||||
c->posted = 1;
|
||||
uv_mutex_unlock(&c->mutex);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(semaphore_1) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
|
||||
ASSERT(0 == uv_sem_init(&wc.sem, 0));
|
||||
ASSERT(0 == uv_mutex_init(&wc.mutex));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_sleep(100);
|
||||
uv_mutex_lock(&wc.mutex);
|
||||
ASSERT(wc.posted == 1);
|
||||
uv_sem_wait(&wc.sem); /* should not block */
|
||||
uv_mutex_unlock(&wc.mutex); /* ergo, it should be ok to unlock after wait */
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_mutex_destroy(&wc.mutex);
|
||||
uv_sem_destroy(&wc.sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(semaphore_2) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.delay = 100;
|
||||
|
||||
ASSERT(0 == uv_sem_init(&wc.sem, 0));
|
||||
ASSERT(0 == uv_mutex_init(&wc.mutex));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_sem_wait(&wc.sem);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_mutex_destroy(&wc.mutex);
|
||||
uv_sem_destroy(&wc.sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(semaphore_3) {
|
||||
uv_sem_t sem;
|
||||
|
||||
ASSERT(0 == uv_sem_init(&sem, 3));
|
||||
uv_sem_wait(&sem); /* should not block */
|
||||
uv_sem_wait(&sem); /* should not block */
|
||||
ASSERT(0 == uv_sem_trywait(&sem));
|
||||
ASSERT(UV_EAGAIN == uv_sem_trywait(&sem));
|
||||
|
||||
uv_sem_post(&sem);
|
||||
ASSERT(0 == uv_sem_trywait(&sem));
|
||||
ASSERT(UV_EAGAIN == uv_sem_trywait(&sem));
|
||||
|
||||
uv_sem_destroy(&sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* These tests verify that the uv_shutdown callback is always made, even when
|
||||
* it is immediately followed by an uv_close call.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
|
||||
static uv_shutdown_t shutdown_req;
|
||||
static uv_connect_t connect_req;
|
||||
|
||||
static int connect_cb_called = 0;
|
||||
static int shutdown_cb_called = 0;
|
||||
static int close_cb_called = 0;
|
||||
|
||||
|
||||
static void shutdown_cb(uv_shutdown_t* req, int status) {
|
||||
ASSERT(req == &shutdown_req);
|
||||
ASSERT(status == 0 || status == UV_ECANCELED);
|
||||
shutdown_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
int r;
|
||||
|
||||
ASSERT(req == &connect_req);
|
||||
ASSERT(status == 0);
|
||||
|
||||
r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(0 == uv_is_closing((uv_handle_t*) req->handle));
|
||||
uv_close((uv_handle_t*) req->handle, close_cb);
|
||||
ASSERT(1 == uv_is_closing((uv_handle_t*) req->handle));
|
||||
|
||||
connect_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(shutdown_close_tcp) {
|
||||
struct sockaddr_in addr;
|
||||
uv_tcp_t h;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
r = uv_tcp_init(uv_default_loop(), &h);
|
||||
ASSERT(r == 0);
|
||||
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(connect_cb_called == 1);
|
||||
ASSERT(shutdown_cb_called == 1);
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(shutdown_close_pipe) {
|
||||
uv_pipe_t h;
|
||||
int r;
|
||||
|
||||
r = uv_pipe_init(uv_default_loop(), &h, 0);
|
||||
ASSERT(r == 0);
|
||||
uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_cb);
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(connect_cb_called == 1);
|
||||
ASSERT(shutdown_cb_called == 1);
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/* 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>
|
||||
|
||||
static uv_timer_t timer;
|
||||
static uv_tcp_t tcp;
|
||||
static uv_connect_t connect_req;
|
||||
static uv_write_t write_req;
|
||||
static uv_shutdown_t shutdown_req;
|
||||
static uv_buf_t qbuf;
|
||||
static int got_q;
|
||||
static int got_eof;
|
||||
static int called_connect_cb;
|
||||
static int called_shutdown_cb;
|
||||
static int called_tcp_close_cb;
|
||||
static int called_timer_close_cb;
|
||||
static int called_timer_cb;
|
||||
|
||||
|
||||
static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
|
||||
buf->base = malloc(size);
|
||||
buf->len = size;
|
||||
}
|
||||
|
||||
|
||||
static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) {
|
||||
ASSERT((uv_tcp_t*)t == &tcp);
|
||||
|
||||
if (nread == 0) {
|
||||
free(buf->base);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!got_q) {
|
||||
ASSERT(nread == 1);
|
||||
ASSERT(!got_eof);
|
||||
ASSERT(buf->base[0] == 'Q');
|
||||
free(buf->base);
|
||||
got_q = 1;
|
||||
puts("got Q");
|
||||
} else {
|
||||
ASSERT(nread == UV_EOF);
|
||||
if (buf->base) {
|
||||
free(buf->base);
|
||||
}
|
||||
got_eof = 1;
|
||||
puts("got EOF");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void shutdown_cb(uv_shutdown_t *req, int status) {
|
||||
ASSERT(req == &shutdown_req);
|
||||
|
||||
ASSERT(called_connect_cb == 1);
|
||||
ASSERT(!got_eof);
|
||||
ASSERT(called_tcp_close_cb == 0);
|
||||
ASSERT(called_timer_close_cb == 0);
|
||||
ASSERT(called_timer_cb == 0);
|
||||
|
||||
called_shutdown_cb++;
|
||||
}
|
||||
|
||||
|
||||
static void connect_cb(uv_connect_t *req, int status) {
|
||||
ASSERT(status == 0);
|
||||
ASSERT(req == &connect_req);
|
||||
|
||||
/* Start reading from our connection so we can receive the EOF. */
|
||||
uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb);
|
||||
|
||||
/*
|
||||
* Write the letter 'Q' to gracefully kill the echo-server. This will not
|
||||
* effect our connection.
|
||||
*/
|
||||
uv_write(&write_req, (uv_stream_t*) &tcp, &qbuf, 1, NULL);
|
||||
|
||||
/* Shutdown our end of the connection. */
|
||||
uv_shutdown(&shutdown_req, (uv_stream_t*) &tcp, shutdown_cb);
|
||||
|
||||
called_connect_cb++;
|
||||
ASSERT(called_shutdown_cb == 0);
|
||||
}
|
||||
|
||||
|
||||
static void tcp_close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle == (uv_handle_t*) &tcp);
|
||||
|
||||
ASSERT(called_connect_cb == 1);
|
||||
ASSERT(got_q);
|
||||
ASSERT(got_eof);
|
||||
ASSERT(called_timer_cb == 1);
|
||||
|
||||
called_tcp_close_cb++;
|
||||
}
|
||||
|
||||
|
||||
static void timer_close_cb(uv_handle_t* handle) {
|
||||
ASSERT(handle == (uv_handle_t*) &timer);
|
||||
called_timer_close_cb++;
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
ASSERT(handle == &timer);
|
||||
uv_close((uv_handle_t*) handle, timer_close_cb);
|
||||
|
||||
/*
|
||||
* The most important assert of the test: we have not received
|
||||
* tcp_close_cb yet.
|
||||
*/
|
||||
ASSERT(called_tcp_close_cb == 0);
|
||||
uv_close((uv_handle_t*) &tcp, tcp_close_cb);
|
||||
|
||||
called_timer_cb++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This test has a client which connects to the echo_server and immediately
|
||||
* issues a shutdown. The echo-server, in response, will also shutdown their
|
||||
* connection. We check, with a timer, that libuv is not automatically
|
||||
* calling uv_close when the client receives the EOF from echo-server.
|
||||
*/
|
||||
TEST_IMPL(shutdown_eof) {
|
||||
struct sockaddr_in server_addr;
|
||||
int r;
|
||||
|
||||
qbuf.base = "Q";
|
||||
qbuf.len = 1;
|
||||
|
||||
r = uv_timer_init(uv_default_loop(), &timer);
|
||||
ASSERT(r == 0);
|
||||
|
||||
uv_timer_start(&timer, timer_cb, 100, 0);
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp);
|
||||
ASSERT(!r);
|
||||
|
||||
r = uv_tcp_connect(&connect_req,
|
||||
&tcp,
|
||||
(const struct sockaddr*) &server_addr,
|
||||
connect_cb);
|
||||
ASSERT(!r);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(called_connect_cb == 1);
|
||||
ASSERT(called_shutdown_cb == 1);
|
||||
ASSERT(got_eof);
|
||||
ASSERT(got_q);
|
||||
ASSERT(called_tcp_close_cb == 1);
|
||||
ASSERT(called_timer_close_cb == 1);
|
||||
ASSERT(called_timer_cb == 1);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user