-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
Description
The original issue is at #1264
The synopsis is that because of how uv_run works, unrefed handles show up as active still for the first run, and don't appear as no-longer active until the second run.
In the past, running an unrefed timer in beforeExit would infinitely loop, since the second run would always be in the next beforeExit, consequentially calling 'beforeExit' again and scheduling another time, looping infinitely. This was fixed in #3407 by making unrefed timers of the same timeout use the previous handle, which is then properly unreferenced.
As described, one would expect the event loop / beforeExit code to look something like so:
bool more;
uv_run_mode run_mode = UV_RUN_ONCE;
do {
more = uv_run(env->event_loop(), run_mode);
if (more == false) {
EmitBeforeExit(env);
// Emit `beforeExit` if the loop became alive either after emitting
// event, or after running some callbacks.
more = uv_loop_alive(env->event_loop());
run_mode = UV_RUN_NOWAIT;
} else {
run_mode = UV_RUN_ONCE;
}
} while (more == true);However in reality it looks more like this:
(
Lines 4063 to 4078 in 471aa5a
| bool more; | |
| do { | |
| v8::platform::PumpMessageLoop(default_platform, isolate); | |
| more = uv_run(env->event_loop(), UV_RUN_ONCE); | |
| if (more == false) { | |
| v8::platform::PumpMessageLoop(default_platform, isolate); | |
| EmitBeforeExit(env); | |
| // Emit `beforeExit` if the loop became alive either after emitting | |
| // event, or after running some callbacks. | |
| more = uv_loop_alive(env->event_loop()); | |
| if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0) | |
| more = true; | |
| } | |
| } while (more == true); |
bool more;
do {
more = uv_run(env->event_loop(), UV_RUN_ONCE);
if (more == false) {
EmitBeforeExit(env);
// Emit `beforeExit` if the loop became alive either after emitting
// event, or after running some callbacks.
more = uv_loop_alive(env->event_loop());
if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0)
more = true;
}
} while (more == true);If you look closely at the actual version, you'll notice that uv_run ends up actually being called at least 2 times on a beforeExit re-entry anyways, which logically register the timer and unref. However it does not seem to work like that.
Sniff test says it may be some discrepancy within uv_run modes?
cc @indutny, @trevnorris, @saghul