unix, windows: add uv_walk()
Lets the libuv user iterate over the open handles. Mostly intended as a debugging tool or a post-hoc cleanup mechanism.
This commit is contained in:
parent
122cd94695
commit
171ad8567d
@ -301,6 +301,7 @@ typedef void (*uv_exit_cb)(uv_process_t*, int exit_status, int term_signal);
|
||||
typedef void (*uv_fs_cb)(uv_fs_t* req);
|
||||
typedef void (*uv_work_cb)(uv_work_t* req);
|
||||
typedef void (*uv_after_work_cb)(uv_work_t* req);
|
||||
typedef void (*uv_walk_cb)(uv_handle_t* handle, void* arg);
|
||||
|
||||
/*
|
||||
* This will be called repeatedly after the uv_fs_event_t is initialized.
|
||||
@ -382,6 +383,7 @@ struct uv_shutdown_s {
|
||||
/* read-only */ \
|
||||
uv_handle_type type; \
|
||||
/* private */ \
|
||||
ngx_queue_t handle_queue; \
|
||||
UV_HANDLE_PRIVATE_FIELDS \
|
||||
|
||||
/* The abstract base class of all handles. */
|
||||
@ -407,6 +409,12 @@ UV_EXTERN size_t uv_req_size(uv_req_type type);
|
||||
*/
|
||||
UV_EXTERN int uv_is_active(const uv_handle_t* handle);
|
||||
|
||||
/*
|
||||
* Walk the list of open handles.
|
||||
*/
|
||||
UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg);
|
||||
|
||||
|
||||
/*
|
||||
* Request handle to be closed. close_cb will be called asynchronously after
|
||||
* this call. This MUST be called on each handle before memory is released.
|
||||
@ -1668,6 +1676,7 @@ struct uv_loop_s {
|
||||
uv_err_t last_err;
|
||||
/* Loop reference counting */
|
||||
unsigned int active_handles;
|
||||
ngx_queue_t handle_queue;
|
||||
ngx_queue_t active_reqs;
|
||||
/* User data - use this for whatever. */
|
||||
void* data;
|
||||
|
||||
@ -159,12 +159,12 @@ static void uv__finish_close(uv_handle_t* handle) {
|
||||
break;
|
||||
}
|
||||
|
||||
uv__handle_unref(handle);
|
||||
ngx_queue_remove(&handle->handle_queue);
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb(handle);
|
||||
}
|
||||
|
||||
uv__handle_unref(handle);
|
||||
}
|
||||
|
||||
|
||||
@ -278,6 +278,7 @@ void uv__handle_init(uv_loop_t* loop, uv_handle_t* handle,
|
||||
handle->type = type;
|
||||
handle->flags = UV__HANDLE_REF; /* ref the loop when active */
|
||||
handle->next_closing = NULL;
|
||||
ngx_queue_insert_tail(&loop->handle_queue, &handle->handle_queue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -41,6 +41,7 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
|
||||
ngx_queue_init(&loop->idle_handles);
|
||||
ngx_queue_init(&loop->check_handles);
|
||||
ngx_queue_init(&loop->prepare_handles);
|
||||
ngx_queue_init(&loop->handle_queue);
|
||||
loop->closing_handles = NULL;
|
||||
loop->channel = NULL;
|
||||
loop->ev = (default_loop ? ev_default_loop : ev_loop_new)(flags);
|
||||
|
||||
@ -317,6 +317,18 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
}
|
||||
|
||||
|
||||
void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
|
||||
ngx_queue_t* q;
|
||||
uv_handle_t* h;
|
||||
|
||||
ngx_queue_foreach(q, &loop->handle_queue) {
|
||||
h = ngx_queue_data(q, uv_handle_t, handle_queue);
|
||||
if (h->flags & UV__HANDLE_INTERNAL) continue;
|
||||
walk_cb(h, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_ref(uv_handle_t* handle) {
|
||||
uv__handle_ref(handle);
|
||||
}
|
||||
|
||||
@ -49,12 +49,14 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
enum {
|
||||
UV__HANDLE_ACTIVE = 0x4000,
|
||||
UV__HANDLE_REF = 0x8000
|
||||
UV__HANDLE_INTERNAL = 0x8000,
|
||||
UV__HANDLE_ACTIVE = 0x4000,
|
||||
UV__HANDLE_REF = 0x2000
|
||||
};
|
||||
#else
|
||||
# define UV__HANDLE_ACTIVE 0x40
|
||||
# define UV__HANDLE_REF 0x20
|
||||
# define UV__HANDLE_INTERNAL 0x80
|
||||
# define UV__HANDLE_ACTIVE 0x40
|
||||
# define UV__HANDLE_REF 0x20
|
||||
#endif
|
||||
|
||||
extern const uv_err_t uv_ok_;
|
||||
|
||||
@ -58,12 +58,8 @@ void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
!handle->async_sent) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -479,7 +479,6 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
!handle->req_pending) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
if (handle->buffer) {
|
||||
@ -507,8 +506,6 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
handle->dirw = NULL;
|
||||
}
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,6 +65,7 @@ int uv_is_active(const uv_handle_t* handle) {
|
||||
void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle) {
|
||||
handle->loop = loop;
|
||||
handle->flags = UV__HANDLE_REF;
|
||||
ngx_queue_insert_tail(&loop->handle_queue, &handle->handle_queue);
|
||||
|
||||
loop->counters.handle_init++;
|
||||
}
|
||||
|
||||
@ -130,6 +130,14 @@ void uv_process_endgames(uv_loop_t* loop);
|
||||
uv__req_unregister((loop), (req)); \
|
||||
} while (0)
|
||||
|
||||
#define uv__handle_close(handle) \
|
||||
do { \
|
||||
ngx_queue_remove(&(handle)->handle_queue); \
|
||||
(handle)->flags |= UV_HANDLE_CLOSED; \
|
||||
if ((handle)->close_cb) { \
|
||||
(handle)->close_cb((uv_handle_t*)(handle)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Handles
|
||||
|
||||
@ -30,10 +30,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb(handle);
|
||||
}
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -358,7 +358,6 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
if (handle->flags & UV_HANDLE_CONNECTION) {
|
||||
@ -385,9 +384,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
handle->accept_reqs = NULL;
|
||||
}
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -611,10 +611,6 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
assert(handle->submitted_events_1 == 0);
|
||||
assert(handle->submitted_events_2 == 0);
|
||||
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
|
||||
@ -743,7 +743,6 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
|
||||
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
/* Clean-up the process handle. */
|
||||
@ -751,10 +750,7 @@ void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
|
||||
|
||||
/* Clean up the child stdio ends that may have been left open. */
|
||||
close_child_stdio(handle);
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -197,7 +197,6 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) {
|
||||
@ -236,10 +235,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
}
|
||||
}
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
|
||||
uv__handle_close(handle);
|
||||
loop->active_tcp_streams--;
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,12 +126,8 @@ int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
|
||||
void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1773,12 +1773,8 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
|
||||
assert(handle->read_raw_wait == NULL);
|
||||
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -155,12 +155,8 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -81,6 +81,7 @@ TEST_DECLARE (timer_start_twice)
|
||||
TEST_DECLARE (idle_starvation)
|
||||
TEST_DECLARE (loop_handles)
|
||||
TEST_DECLARE (get_loadavg)
|
||||
TEST_DECLARE (walk_handles)
|
||||
TEST_DECLARE (ref)
|
||||
TEST_DECLARE (idle_ref)
|
||||
TEST_DECLARE (async_ref)
|
||||
@ -300,6 +301,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (process_ref)
|
||||
|
||||
TEST_ENTRY (loop_handles)
|
||||
TEST_ENTRY (walk_handles)
|
||||
|
||||
TEST_ENTRY (async)
|
||||
|
||||
|
||||
77
test/test-walk-handles.c
Normal file
77
test/test-walk-handles.c
Normal file
@ -0,0 +1,77 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static char magic_cookie[] = "magic cookie";
|
||||
static int seen_timer_handle;
|
||||
static uv_timer_t timer;
|
||||
|
||||
|
||||
static void walk_cb(uv_handle_t* handle, void* arg) {
|
||||
ASSERT(arg == (void*)magic_cookie);
|
||||
|
||||
if (handle == (uv_handle_t*)&timer) {
|
||||
seen_timer_handle++;
|
||||
} else {
|
||||
ASSERT(0 && "unexpected handle");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* handle, int status) {
|
||||
ASSERT(handle == &timer);
|
||||
ASSERT(status == 0);
|
||||
|
||||
uv_walk(handle->loop, walk_cb, magic_cookie);
|
||||
uv_close((uv_handle_t*)handle, NULL);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(walk_handles) {
|
||||
uv_loop_t* loop;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
r = uv_timer_init(loop, &timer);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_timer_start(&timer, timer_cb, 1, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Start event loop, expect to see the timer handle in walk_cb. */
|
||||
ASSERT(seen_timer_handle == 0);
|
||||
r = uv_run(loop);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(seen_timer_handle == 1);
|
||||
|
||||
/* Loop is finished, walk_cb should not see our timer handle. */
|
||||
seen_timer_handle = 0;
|
||||
uv_walk(loop, walk_cb, magic_cookie);
|
||||
ASSERT(seen_timer_handle == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user