uv_stop() doesn't stop the event loop right away, it just tells it to stop at the next iteration - i.e. until the timer expires. uv_stop() is also not guaranteed to be thread-safe, though the current implementation pretty much is.

The best way to do this is to have the watchdog initialize an uv_aync_t at construction time and later on have Destroy() call uv_async_send() with it to wake up the other thread's event loop.

If you call uv_run() with UV_RUN_ONCE, it will automatically drop out of the event loop when either the timer expires or the async handle is primed. uv_close() both handles and call `uv_run(loop_, UV_RUN_DEFAULT)` once more to give libuv a chance to clean up.