Skip to content
Browse files

Fixed signal handling

- non-portable signal code moved to zsys
- zsys_handlers_set (NULL) to prevent CZMQ installing its handlers
- note: no longer a side-effect of setting zctx_interrupted to 1
- zsys_handlers_reset () at exit to restore default handlers
  • Loading branch information...
1 parent 8a7301f commit ff78651da27f72bf32bf79368be8a47a17dbe891 @hintjens committed Jan 3, 2013
Showing with 74 additions and 50 deletions.
  1. +11 −0 include/zsys.h
  2. +6 −49 src/zctx.c
  3. +57 −1 src/zsys.c
View
11 include/zsys.h
@@ -32,6 +32,17 @@ extern "C" {
#endif
// @interface
+// Callback for interrupt signal handler
+typedef void (zsys_handler_fn) (int signal_value);
+
+// Set interrupt handler (NULL means external handler)
+CZMQ_EXPORT void
+ zsys_handler_set (zsys_handler_fn *handler_fn);
+
+// Reset interrupt handler, call this at exit if needed
+CZMQ_EXPORT void
+ zsys_handler_reset (void);
+
// Return file mode
CZMQ_EXPORT mode_t
zsys_mode (const char *filename);
View
55 src/zctx.c
@@ -64,22 +64,21 @@ struct _zctx_t {
bool main; // True if we're the main thread
int iothreads; // Number of IO threads, default 1
int linger; // Linger timeout, default 0
- struct sigaction oacts[2]; // Current sigaction values
};
// ---------------------------------------------------------------------
// Signal handling
-//
-
// This is a global variable accessible to CZMQ application code
+
volatile int zctx_interrupted = 0;
-#if defined (__UNIX__)
-static void s_signal_handler (int signal_value)
+
+static void
+s_signal_handler (int signal_value)
{
zctx_interrupted = 1;
}
-#endif
+
// --------------------------------------------------------------------------
// Constructor
@@ -101,18 +100,7 @@ zctx_new (void)
}
self->iothreads = 1;
self->main = true;
-
-#if defined (__UNIX__)
- if (zctx_interrupted == 0) {
- // Install signal handler for SIGINT and SIGTERM
- struct sigaction action;
- action.sa_handler = s_signal_handler;
- action.sa_flags = 0;
- sigemptyset (&action.sa_mask);
- sigaction (SIGINT, &action, &self->oacts[0]);
- sigaction (SIGTERM, &action, &self->oacts[1]);
- }
-#endif
+ zsys_handler_set (s_signal_handler);
return self;
}
@@ -131,10 +119,6 @@ zctx_destroy (zctx_t **self_p)
zlist_destroy (&self->sockets);
if (self->main && self->context)
zmq_term (self->context);
-#if defined (__UNIX__)
- sigaction (SIGINT, &self->oacts[0], NULL);
- sigaction (SIGTERM, &self->oacts[1], NULL);
-#endif
free (self);
*self_p = NULL;
}
@@ -296,33 +280,6 @@ zctx_test (bool verbose)
zsocket_connect (s5, "tcp://127.0.0.1:5555");
zsocket_connect (s6, "tcp://127.0.0.1:5555");
assert (zctx_underlying (ctx));
-
-#if defined (__UNIX__)
- struct sigaction action;
- sigaction (SIGINT, NULL, &action);
- assert (action.sa_handler == s_signal_handler);
-
- sigaction (SIGTERM, NULL, &action);
- assert (action.sa_handler == s_signal_handler);
- // Everything should be cleanly closed now
- zctx_destroy (&ctx);
-
- sigaction (SIGINT, NULL, &action);
- sigaction (SIGTERM, NULL, &action);
- assert (action.sa_handler != s_signal_handler);
- assert (action.sa_handler != s_signal_handler);
-
- // Check if no signal handler is installed if zctx_interrupted
- zctx_interrupted = 1;
- bzero(&action, sizeof(struct sigaction));
- ctx = zctx_new ();
-
- sigaction (SIGINT, NULL, &action);
- assert (action.sa_handler != s_signal_handler);
-
- sigaction (SIGTERM, NULL, &action);
- assert (action.sa_handler != s_signal_handler);
-#endif
zctx_destroy (&ctx);
// @end
View
58 src/zsys.c
@@ -36,6 +36,57 @@
#include "../include/czmq.h"
+#if defined (__UNIX__)
+static bool s_first_time = true;
+static struct sigaction sigint_default;
+static struct sigaction sigterm_default;
+#endif
+
+// --------------------------------------------------------------------------
+// Set interrupt handler (NULL means external handler)
+// Idempotent; safe to call multiple times
+
+CZMQ_EXPORT void
+zsys_handler_set (zsys_handler_fn *handler_fn)
+{
+#if defined (__UNIX__)
+ // Install signal handler for SIGINT and SIGTERM if not NULL
+ // and if this is the first time we've been called
+ if (s_first_time) {
+ s_first_time = false;
+ if (handler_fn) {
+ struct sigaction action;
+ action.sa_handler = handler_fn;
+ action.sa_flags = 0;
+ sigemptyset (&action.sa_mask);
+ sigaction (SIGINT, &action, NULL);
+ sigaction (SIGTERM, &action, NULL);
+ }
+ // Save default handlers if not already done
+ sigaction (SIGINT, NULL, &sigint_default);
+ sigaction (SIGTERM, NULL, &sigterm_default);
+ }
+#endif
+}
+
+
+// --------------------------------------------------------------------------
+// Reset interrupt handler, call this at exit if needed
+// Idempotent; safe to call multiple times
+
+CZMQ_EXPORT void
+zsys_handler_reset (void)
+{
+ // Restore default handlers if not already done
+ if (sigint_default.sa_handler) {
+ sigaction (SIGINT, &sigint_default, NULL);
+ sigaction (SIGTERM, &sigterm_default, NULL);
+ sigint_default.sa_handler = NULL;
+ sigterm_default.sa_handler = NULL;
+ s_first_time = true;
+ }
+}
+
// --------------------------------------------------------------------------
// Return file mode
@@ -164,7 +215,12 @@ int
zsys_test (bool verbose)
{
printf (" * zsys: ");
-
+ zsys_handler_reset ();
+ zsys_handler_set (NULL);
+ zsys_handler_set (NULL);
+ zsys_handler_reset ();
+ zsys_handler_reset ();
printf ("OK\n");
return 0;
}
+

0 comments on commit ff78651

Please sign in to comment.
Something went wrong with that request. Please try again.