From 3a38d9477ec1766ad01edd2bc7f12961d4832717 Mon Sep 17 00:00:00 2001 From: oko256 <139907514+oko256@users.noreply.github.com> Date: Fri, 5 Apr 2024 17:07:31 +0300 Subject: [PATCH 1/2] zloop: ignore EINTR from poll if nonstop is enabled If SIGINT signal arrives while poll is blocking, regardless of attached signal handler it will cause the poll to return with errno EINTR. Currently, this causes zloop to return from the event loop. For nonstop mode to work as intended, we have to ignore EINTR in this case. Added test cases that verify the functionality when catching an actual SIGINT signal with and without nonstop mode. Tested in Linux and Windows. --- src/zloop.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/zloop.c b/src/zloop.c index 9343e186e..7703b4021 100644 --- a/src/zloop.c +++ b/src/zloop.c @@ -723,6 +723,10 @@ zloop_start (zloop_t *self) } rc = zmq_poll (self->pollset, (int) self->poll_size, s_tickless (self)); if (rc == -1 || (zsys_interrupted && !self->nonstop)) { + if (errno == EINTR && self->nonstop) { + rc = 0; + continue; + } if (self->verbose) { if (rc == -1) zsys_debug ("zloop: interrupted: %s", strerror (errno)); @@ -915,6 +919,22 @@ s_timer_event5 (zloop_t *loop, int timer_id, void *arg) return 0; } +static void +s_raise_sigint_actor (zsock_t *pipe, void *args) +{ + zsock_signal (pipe, 0); + assert (zsys_interrupted == 0); + zsock_wait (pipe); + zclock_sleep (100); +#if defined (__WINDOWS__) + assert (GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0) != 0); +#else + assert (kill (getpid(), SIGINT) == 0); +#endif + zclock_sleep (100); + assert (zsys_interrupted != 0); +} + void zloop_test (bool verbose) { @@ -976,6 +996,34 @@ zloop_test (bool verbose) assert (timer_event_called); zsys_interrupted = 0; + // Check that SIGINT terminates loop if nonstop is not set + zloop_destroy (&loop); + zactor_t *raise_sigint_actor = zactor_new (s_raise_sigint_actor, NULL); + assert (raise_sigint_actor); + loop = zloop_new (); + zloop_set_nonstop (loop, false); + timer_event_called = false; + zloop_timer (loop, 1000, 1, s_timer_event3, &timer_event_called); + zsock_signal (raise_sigint_actor, 0); + zloop_start (loop); + zactor_destroy (&raise_sigint_actor); + assert (!timer_event_called); + zsys_interrupted = 0; + + // Check that SIGINT does not terminate the loop if nonstop is set + zloop_destroy (&loop); + raise_sigint_actor = zactor_new (s_raise_sigint_actor, NULL); + assert (raise_sigint_actor); + loop = zloop_new (); + zloop_set_nonstop (loop, true); + timer_event_called = false; + zloop_timer (loop, 500, 1, s_timer_event3, &timer_event_called); + zsock_signal (raise_sigint_actor, 0); + zloop_start (loop); + zactor_destroy (&raise_sigint_actor); + assert (timer_event_called); + zsys_interrupted = 0; + // Check if reader removed in timer is not called zloop_destroy (&loop); loop = zloop_new (); From e88e2116992c87623ad32bcd0d3271381703e19e Mon Sep 17 00:00:00 2001 From: oko256 <139907514+oko256@users.noreply.github.com> Date: Wed, 10 Apr 2024 12:17:08 +0300 Subject: [PATCH 2/2] zsock: fix STREAM test on macOS On macOS, in zsock STREAM test, when STREAM zsock was bound with `tcp://*:*`, the respective connect to `tcp://127.0.0.1:` was unable to connect and got stuck indefinitely. Fixed by binding to `tcp://127.0.0.1:*` instead like in other tests in zsock. --- src/zsock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/zsock.c b/src/zsock.c index 58d9201c7..3eaf1bc7b 100644 --- a/src/zsock.c +++ b/src/zsock.c @@ -942,7 +942,7 @@ zsock_vsend (void *self, const char *picture, va_list argptr) zframe_t *frame = zlistx_pack (list); zmsg_append (msg, &frame); } -#endif +#endif else if (*picture == 'm') { zframe_t *frame; @@ -1171,7 +1171,7 @@ zsock_vrecv (void *self, const char *picture, va_list argptr) } zframe_destroy (&frame); } -#ifdef CZMQ_BUILD_DRAFT_API +#ifdef CZMQ_BUILD_DRAFT_API else if (*picture == 'l') { zframe_t *frame = zmsg_pop (msg); @@ -2205,7 +2205,7 @@ zsock_test (bool verbose) #ifdef ZMQ_STREAM zsock_t *streamrecv = zsock_new(ZMQ_STREAM); assert (streamrecv); - port = zsock_bind(streamrecv, "tcp://*:*"); + port = zsock_bind(streamrecv, "tcp://127.0.0.1:*"); assert(port > 0); zsock_t *streamsender = zsock_new(ZMQ_STREAM); @@ -2398,7 +2398,7 @@ zsock_test (bool verbose) char* message; message = zstr_recv (gather); assert (streq(message, "HELLO")); - zstr_free (&message); + zstr_free (&message); zsock_destroy (&gather); zsock_destroy (&scatter);