Skip to content

Commit

Permalink
zloop: ignore EINTR from poll if nonstop is enabled
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
oko256 committed Apr 9, 2024
1 parent db94044 commit d9a4787
Showing 1 changed file with 48 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/zloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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 (20);
#if defined (__WINDOWS__)
assert (GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0) != 0);
#else
assert (kill (getpid(), SIGINT) == 0);
#endif
zclock_sleep (20);
assert (zsys_interrupted != 0);
}

void
zloop_test (bool verbose)
{
Expand Down Expand Up @@ -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, 50, 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, 50, 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 ();
Expand Down

0 comments on commit d9a4787

Please sign in to comment.