Running with timer timeout of 50ms and simulated code execution of 1000ms:
$ ./issue5564 50 1000
000.000 main thread pre-create
000.000 main thread post-create
000.000 main cond pre-timedwait
000.000 run_cb pre-UV_RUN_ONCE 1
000.051 run_cb post-UV_RUN_ONCE 1
000.051 run_cb pre-UV_RUN_ONCE 2
000.051 timer_cb fired, cond pre-signal
000.051 main cond post-timedwait
000.051 main async pre-send
000.051 main async post-send
000.051 main thread pre-join
000.051 async_cb fired
000.051 run_cb post-UV_RUN_ONCE 2
000.051 run_cb pre-UV_RUN_DEFAULT
000.051 run_cb post-UV_RUN_DEFAULT
000.051 main thread post-join
Note that timer_cb was not fired until the second UV_RUN_ONCE pass.
Running with timer timeout of 1000ms and simulated code execution of 50ms:
$ ./issue5564 1000 50
000.000 main thread pre-create
000.000 main thread post-create
000.000 main cond pre-timedwait
000.000 run_cb pre-UV_RUN_ONCE 1
000.051 main cond post-timedwait
000.051 main async pre-send
000.051 main async post-send
000.051 main thread pre-join
000.051 async_cb fired
000.051 run_cb post-UV_RUN_ONCE 1
000.051 run_cb pre-UV_RUN_ONCE 2
001.001 run_cb post-UV_RUN_ONCE 2
001.001 run_cb pre-UV_RUN_DEFAULT
001.001 run_cb post-UV_RUN_DEFAULT
001.001 main thread post-join
Note that async_cb was fired in the first UV_RUN_ONCE pass like it should, so the second pass is unnecessary and made the program wait until the 1 second timer.
Running with a timer timeout of 0ms (code execution time does not matter):
$ ./issue5564 0 1000
000.000 main thread pre-create
000.000 main thread post-create
000.000 main cond pre-timedwait
000.000 run_cb pre-UV_RUN_ONCE 1
000.000 timer_cb fired, cond pre-signal
000.000 main cond post-timedwait
000.000 main async pre-send
000.000 main async post-send
000.000 main thread pre-join
000.000 async_cb fired
000.000 run_cb post-UV_RUN_ONCE 1
000.000 run_cb pre-UV_RUN_ONCE 2
*BLOCKED*
With a timer timeout of 0ms, timer_cb is fired in the first UV_RUN_ONCE, also triggering the async_cb, causing the second UV_RUN_ONCE pass to block forever.
In
uv_run(), timers are only run before polling, which is where the timeout is implemented. So in a singleUV_RUN_ONCErun, it is not possible to have your callback fired because it will only be run prior to the poll in the next pass. Ifuv_run()is modified like so, it works as expected in all 3 cases above with only oneUV_RUN_ONCEpass: