classifier: Improve comments.
[sliver-openvswitch.git] / lib / fatal-signal.c
index fc126ca..8180521 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include "shash.h"
 #include "util.h"
 
+#define THIS_MODULE VLM_fatal_signal
+#include "vlog.h"
+
 /* Signals to catch. */
 static const int fatal_signals[] = { SIGTERM, SIGINT, SIGHUP, SIGALRM };
 
@@ -56,7 +60,11 @@ static void call_hooks(int sig_nr);
 
 /* Registers 'hook' to be called when a process termination signal is raised.
  * If 'run_at_exit' is true, 'hook' is also called during normal process
- * termination, e.g. when exit() is called or when main() returns. */
+ * termination, e.g. when exit() is called or when main() returns.
+ *
+ * 'func' will be invoked from an asynchronous signal handler, so it must be
+ * written appropriately.  For example, it must not call most C library
+ * functions, including malloc() or free(). */
 void
 fatal_signal_add_hook(void (*func)(void *aux), void *aux, bool run_at_exit)
 {
@@ -165,8 +173,7 @@ call_hooks(int sig_nr)
     }
 }
 \f
-static char **files;
-static size_t n_files, max_files;
+static struct shash files = SHASH_INITIALIZER(&files);
 
 static void unlink_files(void *aux);
 static void do_unlink_files(void);
@@ -183,10 +190,9 @@ fatal_signal_add_file_to_unlink(const char *file)
     }
 
     fatal_signal_block();
-    if (n_files >= max_files) {
-        files = x2nrealloc(files, &max_files, sizeof *files);
+    if (!shash_find(&files, file)) {
+        shash_add(&files, file, NULL);
     }
-    files[n_files++] = xstrdup(file);
     fatal_signal_unblock();
 }
 
@@ -195,32 +201,50 @@ fatal_signal_add_file_to_unlink(const char *file)
 void
 fatal_signal_remove_file_to_unlink(const char *file)
 {
-    size_t i;
+    struct shash_node *node;
 
     fatal_signal_block();
-    for (i = 0; i < n_files; i++) {
-        if (!strcmp(files[i], file)) {
-            free(files[i]);
-            files[i] = files[--n_files];
-            break;
-        }
+    node = shash_find(&files, file);
+    if (node) {
+        shash_delete(&files, node);
     }
     fatal_signal_unblock();
 }
 
+/* Like fatal_signal_remove_file_to_unlink(), but also unlinks 'file'.
+ * Returns 0 if successful, otherwise a positive errno value. */
+int
+fatal_signal_unlink_file_now(const char *file)
+{
+    int error = unlink(file) ? errno : 0;
+    if (error) {
+        VLOG_WARN("could not unlink \"%s\" (%s)", file, strerror(error));
+    }
+
+    fatal_signal_remove_file_to_unlink(file);
+
+    return error;
+}
+
 static void
 unlink_files(void *aux UNUSED)
 {
     do_unlink_files(); 
 }
 
+/* This is a fatal_signal_add_hook() callback (via unlink_files()).  It will be
+ * invoked from an asynchronous signal handler, so it cannot call most C
+ * library functions (unlink() is an explicit exception, see
+ * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html).
+ * That includes free(), so it doesn't try to free the 'files' data
+ * structure. */
 static void
 do_unlink_files(void)
 {
-    size_t i;
+    struct shash_node *node;
 
-    for (i = 0; i < n_files; i++) {
-        unlink(files[i]);
+    SHASH_FOR_EACH (node, &files) {
+        unlink(node->name);
     }
 }
 \f