static void uv__poll(uv_loop_t* loop, DWORD timeout) { BOOL success; uv_req_t* req; OVERLAPPED_ENTRY overlappeds[128]; ULONG count; ULONG i; int repeat; uint64_t timeout_time; timeout_time = loop->time + timeout; for (repeat = 0; ; repeat++) { success = GetQueuedCompletionStatusEx(loop->iocp, overlappeds, ARRAY_SIZE(overlappeds), &count, timeout, FALSE); if (success) { for (i = 0; i < count; i++) { /* Package was dequeued, but see if it is not a empty package * meant only to wake us up. */ if (overlappeds[i].lpOverlapped) { req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); uv_insert_pending_req(loop, req); } } /* Some time might have passed waiting for I/O, * so update the loop time here. */ uv_update_time(loop); } else if (GetLastError() != WAIT_TIMEOUT) { /* Serious error */ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); } else if (timeout > 0) { /* GetQueuedCompletionStatus can occasionally return a little early. * Make sure that the desired timeout target time is reached. */ uv_update_time(loop); if (timeout_time > loop->time) { timeout = (DWORD)(timeout_time - loop->time); /* The first call to GetQueuedCompletionStatus should return very * close to the target time and the second should reach it, but * this is not stated in the documentation. To make sure a busy * loop cannot happen, the timeout is increased exponentially * starting on the third round. */ timeout += repeat ? (1 << (repeat - 1)) : 0; continue; } } break; } }
int uv_run(uv_loop_t *loop, uv_run_mode mode) { DWORD timeout; int r; int ran_pending; void (*poll)(uv_loop_t* loop, DWORD timeout); if (pGetQueuedCompletionStatusEx) poll = &uv_poll_ex; else poll = &uv_poll; r = uv__loop_alive(loop); if (!r) uv_update_time(loop); while (r != 0 && loop->stop_flag == 0) { uv_update_time(loop); uv_process_timers(loop); ran_pending = uv_process_reqs(loop); uv_idle_invoke(loop); uv_prepare_invoke(loop); timeout = 0; if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) timeout = uv_backend_timeout(loop); (*poll)(loop, timeout); uv_check_invoke(loop); uv_process_endgames(loop); if (mode == UV_RUN_ONCE) { /* UV_RUN_ONCE implies forward progress: at least one callback must have * been invoked when it returns. uv__io_poll() can return without doing * I/O (meaning: no callbacks) when its timeout expires - which means we * have pending timers that satisfy the forward progress constraint. * * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from * the check. */ uv_process_timers(loop); } r = uv__loop_alive(loop); if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT) break; } /* The if statement lets the compiler compile it to a conditional store. * Avoids dirtying a cache line. */ if (loop->stop_flag != 0) loop->stop_flag = 0; return r; }
static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { DWORD bytes; ULONG_PTR key; OVERLAPPED* overlapped; uv_req_t* req; int repeat; uint64_t timeout_time; timeout_time = loop->time + timeout; for (repeat = 0; ; repeat++) { GetQueuedCompletionStatus(loop->iocp, &bytes, &key, &overlapped, timeout); if (overlapped) { /* Package was dequeued */ req = uv_overlapped_to_req(overlapped); uv_insert_pending_req(loop, req); /* Some time might have passed waiting for I/O, * so update the loop time here. */ uv_update_time(loop); } else if (GetLastError() != WAIT_TIMEOUT) { /* Serious error */ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); } else if (timeout > 0) { /* GetQueuedCompletionStatus can occasionally return a little early. * Make sure that the desired timeout target time is reached. */ uv_update_time(loop); if (timeout_time > loop->time) { timeout = (DWORD)(timeout_time - loop->time); /* The first call to GetQueuedCompletionStatus should return very * close to the target time and the second should reach it, but * this is not stated in the documentation. To make sure a busy * loop cannot happen, the timeout is increased exponentially * starting on the third round. */ timeout += repeat ? (1 << (repeat - 1)) : 0; continue; } } break; } }
static void show_stats(uv_handle_t *handle, int status) { int64_t diff; #if PRINT_STATS LOGF("connections: %d, read: %.1f gbit/s, write: %.1f gbit/s\n", read_sockets, gbit(nrecv, STATS_INTERVAL), gbit(nsent, STATS_INTERVAL)); #endif /* Exit if the show is over */ if (!--stats_left) { uv_update_time(); diff = uv_now() - start_time; LOGF("pump_%d: %.1f gbit/s\n", read_sockets, gbit(nrecv_total, diff)); exit(0); } /* Reset read and write counters */ nrecv = 0; nsent = 0; }
static void uv_loop_init(uv_loop_t* loop) { /* Create an I/O completion port */ loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); if (loop->iocp == NULL) { uv_fatal_error(GetLastError(), "CreateIoCompletionPort"); } loop->refs = 0; uv_update_time(loop); loop->pending_reqs_tail = NULL; loop->endgame_handles = NULL; RB_INIT(&loop->timers); loop->check_handles = NULL; loop->prepare_handles = NULL; loop->idle_handles = NULL; loop->next_prepare_handle = NULL; loop->next_check_handle = NULL; loop->next_idle_handle = NULL; loop->ares_active_sockets = 0; loop->ares_chan = NULL; loop->last_error = uv_ok_; }
int uv_run_prework(uv_run_state* state) { BOOL block; uv_update_time(state->loop); uv_process_timers(state->loop); // Call idle callbacks if nothing to do. if (state->loop->pending_reqs_tail == NULL && state->loop->endgame_handles == NULL) { uv_idle_invoke(state->loop); } uv_process_reqs(state->loop); uv_process_endgames(state->loop); if (!UV_LOOP_ALIVE(state->loop)) return FALSE; uv_prepare_invoke(state->loop); block = (state->loop->idle_handles == NULL && state->loop->pending_reqs_tail == NULL && state->loop->endgame_handles == NULL && UV_LOOP_ALIVE(state->loop)); if (block) state->timeout = uv_get_poll_timeout(state->loop); else state->timeout = 0; state->count = 0; return TRUE; }
static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { BOOL success; uv_req_t* req; OVERLAPPED_ENTRY overlappeds[128]; ULONG count; ULONG i; success = pGetQueuedCompletionStatusEx(loop->iocp, overlappeds, ARRAY_SIZE(overlappeds), &count, timeout, FALSE); if (success) { for (i = 0; i < count; i++) { /* Package was dequeued */ req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); uv_insert_pending_req(loop, req); } /* Some time might have passed waiting for I/O, * so update the loop time here. */ uv_update_time(loop); } else if (GetLastError() != WAIT_TIMEOUT) { /* Serious error */ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); } else if (timeout > 0) { /* GetQueuedCompletionStatus can occasionally return a little early. * Make sure that the desired timeout is reflected in the loop time. */ uv__time_forward(loop, timeout); } }
static void uv_poll(uv_loop_t* loop, DWORD timeout) { DWORD bytes; ULONG_PTR key; OVERLAPPED* overlapped; uv_req_t* req; GetQueuedCompletionStatus(loop->iocp, &bytes, &key, &overlapped, timeout); if (overlapped) { /* Package was dequeued */ req = uv_overlapped_to_req(overlapped); uv_insert_pending_req(loop, req); /* Some time might have passed waiting for I/O, * so update the loop time here. */ uv_update_time(loop); } else if (GetLastError() != WAIT_TIMEOUT) { /* Serious error */ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); } else if (timeout > 0) { /* GetQueuedCompletionStatus can occasionally return a little early. * Make sure that the desired timeout is reflected in the loop time. */ uv__time_forward(loop, timeout); } }
static void uv_loop_init() { /* Create an I/O completion port */ LOOP->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); if (LOOP->iocp == NULL) { uv_fatal_error(GetLastError(), "CreateIoCompletionPort"); } LOOP->refs = 0; uv_update_time(); LOOP->pending_reqs_tail = NULL; LOOP->endgame_handles = NULL; RB_INIT(&LOOP->timers); LOOP->check_handles = NULL; LOOP->prepare_handles = NULL; LOOP->idle_handles = NULL; LOOP->next_prepare_handle = NULL; LOOP->next_check_handle = NULL; LOOP->next_idle_handle = NULL; LOOP->last_error = uv_ok_; LOOP->err_str = NULL; }
static void show_stats(uv_timer_t* handle, int status) { int64_t diff; int i; #if PRINT_STATS LOGF("connections: %d, write: %.1f gbit/s\n", write_sockets, gbit(nsent, STATS_INTERVAL)); #endif /* Exit if the show is over */ if (!--stats_left) { uv_update_time(); diff = uv_now() - start_time; LOGF("%s_pump%d_client: %.1f gbit/s\n", type == TCP ? "tcp" : "pipe", write_sockets, gbit(nsent_total, diff)); for (i = 0; i < write_sockets; i++) { uv_close(type == TCP ? (uv_handle_t*)&tcp_write_handles[i] : (uv_handle_t*)&pipe_write_handles[i], NULL); } exit(0); } /* Reset read and write counters */ nrecv = 0; nsent = 0; }
/* * Class: com_oracle_libuv_handles_TimerHandle * Method: _now * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_com_oracle_libuv_handles_TimerHandle__1now (JNIEnv *env, jclass cls, jlong loop) { assert(loop); uv_loop_t* lp = reinterpret_cast<uv_loop_t*>(loop); uv_update_time(lp); return uv_now(lp); }
static void read_show_stats() { int64_t diff; uv_update_time(); diff = uv_now() - start_time; LOGF("%s_pump%d_server: %.1f gbit/s\n", type == TCP ? "tcp" : "pipe", max_read_sockets, gbit(nrecv_total, diff)); }
static int uv__run(uv_loop_t* loop) { uv_update_time(loop); uv__run_timers(loop); uv__run_idle(loop); uv__run_prepare(loop); uv__poll(loop); uv__run_check(loop); uv__run_closing_handles(loop); return uv__has_active_handles(loop) || uv__has_active_reqs(loop); }
static int LuaIO_process_uptime(lua_State* L) { uint64_t uptime; uv_loop_t* loop = uv_default_loop(); uv_update_time(loop); uptime = uv_now(loop) - LuaIO_get_start_time(); lua_pushinteger(L, uptime); return 1; }
static void once_cb(uv_timer_t* handle) { TUV_ASSERT(handle != NULL); TUV_ASSERT(0 == uv_is_active((uv_handle_t*) handle)); once_cb_called++; uv_close((uv_handle_t*)handle, once_close_cb); /* Just call this randomly for the code coverage. */ uv_update_time(uv_default_loop()); }
static bool uv_loop_source_check(void *data) { uv_loop_t *loop = data; uv_update_time(loop); bool returnValue = uv_loop_alive(loop); SOL_DBG("Returning %s", returnValue ? "true" : "false"); return returnValue; }
int uv_loop_init(uv_loop_t* loop) { /* Initialize libuv itself first */ uv__once_init(); /* Create an I/O completion port */ loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); if (loop->iocp == NULL) return uv_translate_sys_error(GetLastError()); /* To prevent uninitialized memory access, loop->time must be initialized * to zero before calling uv_update_time for the first time. */ loop->time = 0; uv_update_time(loop); QUEUE_INIT(&loop->wq); QUEUE_INIT(&loop->handle_queue); QUEUE_INIT(&loop->active_reqs); loop->active_handles = 0; loop->pending_reqs_tail = NULL; loop->endgame_handles = NULL; RB_INIT(&loop->timers); loop->check_handles = NULL; loop->prepare_handles = NULL; loop->idle_handles = NULL; loop->next_prepare_handle = NULL; loop->next_check_handle = NULL; loop->next_idle_handle = NULL; memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); loop->active_tcp_streams = 0; loop->active_udp_streams = 0; loop->timer_counter = 0; loop->stop_flag = 0; if (uv_mutex_init(&loop->wq_mutex)) abort(); if (uv_async_init(loop, &loop->wq_async, uv__work_done)) abort(); uv__handle_unref(&loop->wq_async); loop->wq_async.flags |= UV__HANDLE_INTERNAL; return 0; }
static void once_cb(uv_timer_t* handle, int status) { printf("ONCE_CB %d\n", once_cb_called); ASSERT(handle != NULL); ASSERT(status == 0); once_cb_called++; uv_close((uv_handle_t*)handle, once_close_cb); /* Just call this randomly for the code coverage. */ uv_update_time(uv_default_loop()); }
static void start_stats_collection() { int r; /* Show-stats timer */ stats_left = STATS_COUNT; r = uv_timer_init(loop, &timer_handle); ASSERT(r == 0); r = uv_timer_start(&timer_handle, show_stats, STATS_INTERVAL, STATS_INTERVAL); ASSERT(r == 0); uv_update_time(loop); start_time = uv_now(loop); }
static void start_stats_collection() { uv_req_t* req = req_alloc(); int r; /* Show-stats timer */ stats_left = STATS_COUNT; r = uv_timer_init(&timer_handle); ASSERT(r == 0); r = uv_timer_start(&timer_handle, show_stats, STATS_INTERVAL, STATS_INTERVAL); ASSERT(r == 0); uv_update_time(); start_time = uv_now(); }
int uv_run(uv_loop_t *loop, uv_run_mode mode) { int r; void (*poll)(uv_loop_t* loop, int block); if (pGetQueuedCompletionStatusEx) poll = &uv_poll_ex; else poll = &uv_poll; if (!uv__loop_alive(loop)) return 0; r = uv__loop_alive(loop); while (r != 0 && loop->stop_flag == 0) { uv_update_time(loop); uv_process_timers(loop); /* Call idle callbacks if nothing to do. */ if (loop->pending_reqs_tail == NULL && loop->endgame_handles == NULL) { uv_idle_invoke(loop); } uv_process_reqs(loop); uv_process_endgames(loop); uv_prepare_invoke(loop); (*poll)(loop, loop->idle_handles == NULL && loop->pending_reqs_tail == NULL && loop->endgame_handles == NULL && !loop->stop_flag && (loop->active_handles > 0 || !ngx_queue_empty(&loop->active_reqs)) && !(mode & UV_RUN_NOWAIT)); uv_check_invoke(loop); r = uv__loop_alive(loop); if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT)) break; } /* The if statement lets the compiler compile it to a conditional store. * Avoids dirtying a cache line. */ if (loop->stop_flag != 0) loop->stop_flag = 0; return r; }
static int _do_fork_fs_events_child(int file_or_dir) { /* basic fsevents work in the child after a fork */ pid_t child_pid; uv_loop_t loop; /* Watch in the parent, prime the loop and/or threads. */ assert_watch_file_current_dir(uv_default_loop(), file_or_dir); child_pid = fork(); ASSERT(child_pid != -1); if (child_pid != 0) { /* parent */ assert_wait_child(child_pid); } else { /* child */ /* Ee can watch in a new loop, but dirs only work if we're on linux. */ #if defined(__APPLE__) file_or_dir = FS_TEST_FILE; #endif printf("Running child\n"); uv_loop_init(&loop); printf("Child first watch\n"); assert_watch_file_current_dir(&loop, file_or_dir); ASSERT(0 == uv_loop_close(&loop)); printf("Child second watch default loop\n"); /* Ee can watch in the default loop. */ ASSERT(0 == uv_loop_fork(uv_default_loop())); /* On some platforms (OS X), if we don't update the time now, * the timer cb fires before the event loop enters uv__io_poll, * instead of after, meaning we don't see the change! This may be * a general race. */ uv_update_time(uv_default_loop()); assert_watch_file_current_dir(uv_default_loop(), file_or_dir); /* We can close the parent loop successfully too. This is especially important on Apple platforms where if we're not careful trying to touch the CFRunLoop, even just to shut it down, that we allocated in the FS_TEST_DIR case would crash. */ ASSERT(0 == uv_loop_close(uv_default_loop())); printf("Exiting child \n"); } MAKE_VALGRIND_HAPPY(); return 0; }
static void read_cb(uv_stream_t* stream, ssize_t bytes, uv_buf_t buf) { if (nrecv_total == 0) { ASSERT(start_time == 0); uv_update_time(); start_time = uv_now(); } if (bytes < 0) { uv_close((uv_handle_t*)stream, read_sockets_close_cb); return; } buf_free(buf); nrecv += bytes; nrecv_total += bytes; }
static void uv_loop_init(uv_loop_t* loop) { /* Create an I/O completion port */ loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); if (loop->iocp == NULL) { uv_fatal_error(GetLastError(), "CreateIoCompletionPort"); } uv_update_time(loop); #ifndef UV_LEAN_AND_MEAN ngx_queue_init(&loop->active_handles); ngx_queue_init(&loop->active_reqs); #else loop->active_handles = 0; loop->active_reqs = 0; #endif loop->pending_reqs_tail = NULL; loop->endgame_handles = NULL; RB_INIT(&loop->timers); loop->check_handles = NULL; loop->prepare_handles = NULL; loop->idle_handles = NULL; loop->next_prepare_handle = NULL; loop->next_check_handle = NULL; loop->next_idle_handle = NULL; memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); loop->channel = NULL; RB_INIT(&loop->ares_handles); loop->active_tcp_streams = 0; loop->active_udp_streams = 0; loop->last_err = uv_ok_; memset(&loop->counters, 0, sizeof loop->counters); }
static void uv_loop_init(uv_loop_t* loop) { /* Create an I/O completion port */ loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); if (loop->iocp == NULL) { uv_fatal_error(GetLastError(), "CreateIoCompletionPort"); } /* To prevent uninitialized memory access, loop->time must be intialized */ /* to zero before calling uv_update_time for the first time. */ loop->time = 0; uv_update_time(loop); ngx_queue_init(&loop->handle_queue); ngx_queue_init(&loop->active_reqs); loop->active_handles = 0; loop->pending_reqs_tail = NULL; loop->endgame_handles = NULL; RB_INIT(&loop->timers); loop->check_handles = NULL; loop->prepare_handles = NULL; loop->idle_handles = NULL; loop->next_prepare_handle = NULL; loop->next_check_handle = NULL; loop->next_idle_handle = NULL; memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); loop->channel = NULL; RB_INIT(&loop->ares_handles); loop->active_tcp_streams = 0; loop->active_udp_streams = 0; loop->last_err = uv_ok_; memset(&loop->counters, 0, sizeof loop->counters); }
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; }
int uv_loop_init(uv_loop_t* loop) { struct heap* timer_heap; int err; /* Initialize libuv itself first */ uv__once_init(); /* Create an I/O completion port */ loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); if (loop->iocp == NULL) return uv_translate_sys_error(GetLastError()); /* To prevent uninitialized memory access, loop->time must be initialized * to zero before calling uv_update_time for the first time. */ loop->time = 0; uv_update_time(loop); QUEUE_INIT(&loop->wq); QUEUE_INIT(&loop->handle_queue); loop->active_reqs.count = 0; loop->active_handles = 0; loop->pending_reqs_tail = NULL; loop->endgame_handles = NULL; loop->timer_heap = timer_heap = uv__malloc(sizeof(*timer_heap)); if (timer_heap == NULL) { err = UV_ENOMEM; goto fail_timers_alloc; } heap_init(timer_heap); loop->check_handles = NULL; loop->prepare_handles = NULL; loop->idle_handles = NULL; loop->next_prepare_handle = NULL; loop->next_check_handle = NULL; loop->next_idle_handle = NULL; memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); loop->active_tcp_streams = 0; loop->active_udp_streams = 0; loop->timer_counter = 0; loop->stop_flag = 0; err = uv_mutex_init(&loop->wq_mutex); if (err) goto fail_mutex_init; err = uv_async_init(loop, &loop->wq_async, uv__work_done); if (err) goto fail_async_init; uv__handle_unref(&loop->wq_async); loop->wq_async.flags |= UV_HANDLE_INTERNAL; err = uv__loops_add(loop); if (err) goto fail_async_init; return 0; fail_async_init: uv_mutex_destroy(&loop->wq_mutex); fail_mutex_init: uv__free(timer_heap); loop->timer_heap = NULL; fail_timers_alloc: CloseHandle(loop->iocp); loop->iocp = INVALID_HANDLE_VALUE; return err; }
///! /// ... /// Internally, this function just calls uv_update_time() function. /// void update_time() { uv_update_time(uv_loop_); }
int luv_update_time(lua_State* L) { uv_update_time(uv_default_loop()); return 0; }
int uv_run_jx(uv_loop_t* loop, uv_run_mode mode, void (*triggerSync)(const int), const int tid) { int r; void (*poll)(uv_loop_t * loop, int block); if (pGetQueuedCompletionStatusEx) poll = &uv_poll_ex; else poll = &uv_poll; if (tid != THREAD_ID_ALREADY_DEFINED) { if (tid != THREAD_ID_NOT_DEFINED) loop->loopId = tid; else loop->loopId = 63; } if (!uv__loop_alive(loop)) return 0; r = uv__loop_alive(loop); while (r != 0 && loop->stop_flag == 0) { uv_update_time(loop); uv_process_timers(loop); /* Call idle callbacks if nothing to do. */ if (loop->pending_reqs_tail == NULL && loop->endgame_handles == NULL) { uv_idle_invoke(loop); } uv_process_reqs(loop); uv_process_endgames(loop); uv_prepare_invoke(loop); if (loop->loopId >= 0 && mode == UV_RUN_DEFAULT) { if (threadMessages[loop->loopId] != 0 && triggerSync != NULL) { triggerSync(loop->loopId); } } if (mode != UV_RUN_PAUSE) { (*poll)(loop, loop->idle_handles == NULL && threadMessages[loop->loopId] == 0 && loop->pending_reqs_tail == NULL && loop->endgame_handles == NULL && !loop->stop_flag && (loop->active_handles > loop->fakeHandle || !QUEUE_EMPTY(&loop->active_reqs)) && !(mode & UV_RUN_NOWAIT)); } uv_check_invoke(loop); r = uv__loop_alive(loop); if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT | UV_RUN_PAUSE)) break; } if (loop->loopId >= 0 && mode == UV_RUN_DEFAULT && triggerSync != NULL) { triggerSync(loop->loopId); } // if we force thread shutdown, there will be some remaining tasks etc. // It is highly possible they might leak, below impl. tries to workaround // this problem by looping the handles for 500 ms. at max. // TODO(obastemur) make it configurable per thread / timer sensitive if (loop->stop_flag != 0) { loop->stop_flag = 0; if (mode != UV_RUN_DEFAULT || r == 0) return r; int force_close = uv__loop_alive(loop); if (force_close) { uint64_t start_time = uv_hrtime(); int ret_val = 1; while (ret_val) { ret_val = uv_run_jx(loop, UV_RUN_NOWAIT, triggerSync, THREAD_ID_ALREADY_DEFINED); uint64_t end_time = uv_hrtime(); if(end_time - start_time > 500 * 1024 * 1024) { break; } } } } return r; }