Commit 2bf1fb5d authored by Jason Madden's avatar Jason Madden

add the test directory back to libuv for windows.

parent ef9c0d14
......@@ -61,6 +61,7 @@ def prepare_windows_env(env):
env.pop('PYTHON', None)
if env.get('PYTHON'):
log.info("Using python from env %s", env['PYTHON'])
return # Already manually set by user.
if sys.version_info[:2] == (2, 7):
......
We distribute libuv with configure already created, by autogen.sh
^^^
XXX: We would like to do that, but it is going to take some tinkering
to make that work.
Do not remove the test/ directory; the windows build depends on it
being in place. Sigh.
/* 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);
}
/* 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);
}
/* 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;
}
/* 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;
}
/* 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
/* 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;
}
/* 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;
}
/* 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;
}
This diff is collapsed.
/* 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;
}
/* 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);
}
This diff is collapsed.
/* 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;
}
/* 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;
}
/* 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;
}
/* 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;
}
/* 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
/* 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;
}
/* 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;
}
/* 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;
}
/* 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);
}
/* 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);
}
/* 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);
}
/* 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 */
This diff is collapsed.
/* 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 write(), fileno() etc. being deprecated. */
#pragma warning(disable : 4996)
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
extern int snprintf(char*, size_t, const char*, ...);
#endif
typedef struct {
HANDLE process;
HANDLE stdio_in;
HANDLE stdio_out;
char *name;
} process_info_t;
This diff is collapsed.
/* 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_ */
This diff is collapsed.
/* 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;
}
/* 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;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment