I finally figured out how to stop the cycle and clear all the handles. I created a bunch of descriptors and SIGINT :
uv_signal_t *sigint = new uv_signal_t; uv_signal_init(uv_default_loop(), sigint); uv_signal_start(sigint, on_sigint_received, SIGINT);
When SIGINT is received (the keyboard shortcut Ctrl + C is pressed in the console), the on_sigint_received callback is called. on_sigint_received looks like this:
void on_sigint_received(uv_signal_t *handle, int signum) { int result = uv_loop_close(handle->loop); if (result == UV_EBUSY) { uv_walk(handle->loop, on_uv_walk, NULL); } }
It calls the on_uv_walk callback function:
void on_uv_walk(uv_handle_t* handle, void* arg) { uv_close(handle, on_uv_close); }
It tries to close every open libuv descriptor. Note: which I do not call uv_stop until uv_walk , as the mentioned sagul . After the on_sigint_received function is called the libuv loop, continuous execution at the next iteration calls on_uv_close for each open descriptor. If you call the uv_stop function, then the on_uv_close will not be called.
void on_uv_close(uv_handle_t* handle) { if (handle != NULL) { delete handle; } }
After that, libuv has no open descriptors and ends the loop (exits uv_run ):
uv_run(uv_default_loop(), UV_RUN_DEFAULT); int result = uv_loop_close(uv_default_loop()); if (result) { cerr << "failed to close libuv loop: " << uv_err_name(result) << endl; } else { cout << "libuv loop is closed successfully!\n"; }