-eliminating duplicate code
[oweals/gnunet.git] / src / util / scheduler.c
index 7254b1700548f6c10029606b89dcc0437afe9522..c54672f5fa49a6d52be8b5c35930e94b18886f05 100644 (file)
 #include "gnunet_signal_lib.h"
 #include "gnunet_time_lib.h"
 #include "disk.h"
-#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
-#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
-#ifdef LINUX
-#include "execinfo.h"
+#define LOG(kind,...) GNUNET_log_from (kind, "util-scheduler", __VA_ARGS__)
+
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-scheduler", syscall)
 
 
+#ifdef LINUX
+#include "execinfo.h"
 
 /**
  * Use lsof to generate file descriptor reports on select error?
@@ -52,7 +53,7 @@
 /**
  * Check each file descriptor before adding
  */
-#define DEBUG_FDS GNUNET_EXTRA_LOGGING
+#define DEBUG_FDS GNUNET_NO
 
 /**
  * Depth of the traces collected via EXECINFO.
@@ -60,8 +61,6 @@
 #define MAX_TRACE_DEPTH 50
 #endif
 
-#define DEBUG_TASKS GNUNET_EXTRA_LOGGING
-
 /**
  * Should we figure out which tasks are delayed for a while
  * before they are run? (Consider using in combination with EXECINFO).
@@ -74,6 +73,7 @@
  */
 #define DELAY_THRESHOLD GNUNET_TIME_UNIT_SECONDS
 
+
 /**
  * Linked list of pending tasks.
  */
@@ -526,10 +526,9 @@ check_ready (const struct GNUNET_NETWORK_FDSet *rs,
   pos = pending;
   while (pos != NULL)
   {
-#if DEBUG_TASKS
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking readiness of task: %llu / %p\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG, 
+        "Checking readiness of task: %llu / %p\n",
          pos->id, pos->callback_cls);
-#endif
     next = pos->next;
     if (GNUNET_YES == is_ready (pos, now, rs, ws))
     {
@@ -676,11 +675,10 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws)
     if (((tc.reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0) &&
         (pos->write_fd != -1) &&
         (!GNUNET_NETWORK_fdset_test_native (ws, pos->write_fd)))
-      GNUNET_abort ();                 // added to ready in previous select loop!
-#if DEBUG_TASKS
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Running task: %llu / %p\n", pos->id,
+      GNUNET_abort ();          // added to ready in previous select loop!
+    LOG (GNUNET_ERROR_TYPE_DEBUG, 
+        "Running task: %llu / %p\n", pos->id,
          pos->callback_cls);
-#endif
     pos->callback (pos->callback_cls, &tc);
 #if EXECINFO
     int i;
@@ -701,6 +699,12 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws)
  */
 static struct GNUNET_DISK_PipeHandle *shutdown_pipe_handle;
 
+/**
+ * Process ID of this process at the time we installed the various
+ * signal handlers.
+ */
+static pid_t my_pid;
+
 /**
  * Signal handler called for SIGPIPE.
  */
@@ -720,6 +724,9 @@ sighandler_shutdown ()
   static char c;
   int old_errno = errno;        /* backup errno */
 
+  if (getpid () != my_pid)
+    exit (1);                   /* we have fork'ed since the signal handler was created,
+                                 * ignore the signal, see https://gnunet.org/vfork discussion */
   GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
                           (shutdown_pipe_handle, GNUNET_DISK_PIPE_END_WRITE),
                           &c, sizeof (c));
@@ -794,11 +801,12 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   rs = GNUNET_NETWORK_fdset_create ();
   ws = GNUNET_NETWORK_fdset_create ();
   GNUNET_assert (shutdown_pipe_handle == NULL);
-  shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO);
+  shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
   GNUNET_assert (shutdown_pipe_handle != NULL);
   pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle,
                                 GNUNET_DISK_PIPE_END_READ);
   GNUNET_assert (pr != NULL);
+  my_pid = getpid ();
   shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown);
   shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown);
 #ifndef MINGW
@@ -810,13 +818,11 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   current_lifeness = GNUNET_YES;
   GNUNET_SCHEDULER_add_continuation (task, task_cls,
                                      GNUNET_SCHEDULER_REASON_STARTUP);
-#if ENABLE_WINDOWS_WORKAROUNDS
   active_task = (void *) (long) -1;     /* force passing of sanity check */
   GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO,
                                           &GNUNET_OS_install_parent_control_handler,
                                           NULL);
   active_task = NULL;
-#endif
   last_tr = 0;
   busy_wait_warning = 0;
   while (GNUNET_OK == check_lifeness ())
@@ -1027,10 +1033,8 @@ GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_TaskIdentifier task)
     prev->next = t->next;
   }
   ret = t->callback_cls;
-#if DEBUG_TASKS
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Canceling task: %llu / %p\n", task,
        t->callback_cls);
-#endif
   destroy_task (t);
   return ret;
 }
@@ -1044,10 +1048,12 @@ GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_TaskIdentifier task)
  * @param task main function of the task
  * @param task_cls closure for 'main'
  * @param reason reason for task invocation
+ * @param priority priority to use for the task
  */
 void
-GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls,
-                                   enum GNUNET_SCHEDULER_Reason reason)
+GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_Task task, void *task_cls,
+                                                enum GNUNET_SCHEDULER_Reason reason,
+                                                enum GNUNET_SCHEDULER_Priority priority)
 {
   struct Task *t;
 
@@ -1073,21 +1079,36 @@ GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls,
   t->start_time = GNUNET_TIME_absolute_get ();
 #endif
   t->reason = reason;
-  t->priority = current_priority;
+  t->priority = priority;
   t->lifeness = current_lifeness;
-#if DEBUG_TASKS
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding continuation task: %llu / %p\n", t->id,
        t->callback_cls);
-#endif
   queue_ready_task (t);
 }
 
 
+/**
+ * Continue the current execution with the given function.  This is
+ * similar to the other "add" functions except that there is no delay
+ * and the reason code can be specified.
+ *
+ * @param task main function of the task
+ * @param task_cls closure for 'main'
+ * @param reason reason for task invocation
+ */
+void
+GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls,
+                                   enum GNUNET_SCHEDULER_Reason reason)
+{
+  GNUNET_SCHEDULER_add_continuation_with_priority (task, task_cls,
+                                                  reason,
+                                                  GNUNET_SCHEDULER_PRIORITY_DEFAULT);
+}
+
 
 /**
  * Schedule a new task to be run after the specified prerequisite task
- * has completed. It will be run with the priority of the calling
- * task.
+ * has completed. It will be run with the DEFAULT priority.
  *
  * @param prerequisite_task run this task after the task with the given
  *        task identifier completes (and any of our other
@@ -1104,7 +1125,7 @@ GNUNET_SCHEDULER_TaskIdentifier
 GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
                             GNUNET_SCHEDULER_Task task, void *task_cls)
 {
-  return GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
+  return GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
                                       prerequisite_task, GNUNET_TIME_UNIT_ZERO,
                                       NULL, NULL, task, task_cls);
 }
@@ -1132,22 +1153,21 @@ GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio,
 
 /**
  * Schedule a new task to be run with a specified delay.  The task
- * will be scheduled for execution once the delay has expired. It
- * will be run with the priority of the calling task.
+ * will be scheduled for execution once the delay has expired.
  *
  * @param delay when should this operation time out? Use
  *        GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
+ * @param priority priority to use for the task
  * @param task main function of the task
  * @param task_cls closure of task
  * @return unique task identifier for the job
  *         only valid until "task" is started!
  */
 GNUNET_SCHEDULER_TaskIdentifier
-GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
-                              GNUNET_SCHEDULER_Task task, void *task_cls)
+GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay,
+                                           enum GNUNET_SCHEDULER_Priority priority,
+                                           GNUNET_SCHEDULER_Task task, void *task_cls)
 {
-#if 1
-  /* new, optimized version */
   struct Task *t;
   struct Task *pos;
   struct Task *prev;
@@ -1173,7 +1193,7 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
   t->start_time = GNUNET_TIME_absolute_get ();
 #endif
   t->timeout = GNUNET_TIME_relative_to_absolute (delay);
-  t->priority = current_priority;
+  t->priority = priority;
   t->lifeness = current_lifeness;
   /* try tail first (optimization in case we are
    * appending to a long list of tasks with timeouts) */
@@ -1205,10 +1225,8 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
   /* hyper-optimization... */
   pending_timeout_last = t;
 
-#if DEBUG_TASKS
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
        t->callback_cls);
-#endif
 #if EXECINFO
   int i;
 
@@ -1217,20 +1235,34 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
          t->backtrace_strings[i]);
 #endif
   return t->id;
-
-#else
-  /* unoptimized version */
-  return GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
-                                      GNUNET_SCHEDULER_NO_TASK, delay, NULL,
-                                      NULL, task, task_cls);
-#endif
 }
 
 
+/**
+ * Schedule a new task to be run with a specified delay.  The task
+ * will be scheduled for execution once the delay has expired. It
+ * will be run with the DEFAULT priority.
+ *
+ * @param delay when should this operation time out? Use
+ *        GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
+ * @param task main function of the task
+ * @param task_cls closure of task
+ * @return unique task identifier for the job
+ *         only valid until "task" is started!
+ */
+GNUNET_SCHEDULER_TaskIdentifier
+GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
+                              GNUNET_SCHEDULER_Task task, void *task_cls)
+{
+  return GNUNET_SCHEDULER_add_delayed_with_priority (delay,
+                                                    GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                                    task, task_cls);
+}
+
 
 /**
  * Schedule a new task to be run as soon as possible. The task
- * will be run with the priority of the calling task.
+ * will be run with the DEFAULT priority.
  *
  * @param task main function of the task
  * @param task_cls closure of task
@@ -1240,10 +1272,7 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
 GNUNET_SCHEDULER_TaskIdentifier
 GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_Task task, void *task_cls)
 {
-  return GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
-                                      GNUNET_SCHEDULER_NO_TASK,
-                                      GNUNET_TIME_UNIT_ZERO, NULL, NULL, task,
-                                      task_cls);
+  return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO, task, task_cls);
 }
 
 
@@ -1269,7 +1298,7 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
   GNUNET_SCHEDULER_TaskIdentifier ret;
 
   ret =
-      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
+      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
                                    GNUNET_SCHEDULER_NO_TASK,
                                    GNUNET_TIME_UNIT_ZERO, NULL, NULL, task,
                                    task_cls);
@@ -1279,8 +1308,6 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
 }
 
 
-
-
 /**
  * Schedule a new task to be run with a specified delay or when any of
  * the specified file descriptor sets is ready.  The delay can be used
@@ -1300,6 +1327,7 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
  *
  * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever",
  *        which means that the task will only be run after we receive SIGTERM
+ * @param priority priority to use
  * @param rfd file descriptor we want to read (can be -1)
  * @param wfd file descriptors we want to write (can be -1)
  * @param task main function of the task
@@ -1309,7 +1337,9 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
  */
 #ifndef MINGW
 static GNUNET_SCHEDULER_TaskIdentifier
-add_without_sets (struct GNUNET_TIME_Relative delay, int rfd, int wfd,
+add_without_sets (struct GNUNET_TIME_Relative delay, 
+                 enum GNUNET_SCHEDULER_Priority priority,
+                 int rfd, int wfd,
                   GNUNET_SCHEDULER_Task task, void *task_cls)
 {
   struct Task *t;
@@ -1371,15 +1401,13 @@ add_without_sets (struct GNUNET_TIME_Relative delay, int rfd, int wfd,
 #endif
   t->prereq_id = GNUNET_SCHEDULER_NO_TASK;
   t->timeout = GNUNET_TIME_relative_to_absolute (delay);
-  t->priority = check_priority (current_priority);
+  t->priority = check_priority ((priority == GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority : priority);
   t->lifeness = current_lifeness;
   t->next = pending;
   pending = t;
   max_priority_added = GNUNET_MAX (max_priority_added, t->priority);
-#if DEBUG_TASKS
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
        t->callback_cls);
-#endif
 #if EXECINFO
   int i;
 
@@ -1398,8 +1426,7 @@ add_without_sets (struct GNUNET_TIME_Relative delay, int rfd, int wfd,
  * specified file descriptor is ready for reading.  The delay can be
  * used as a timeout on the socket being ready.  The task will be
  * scheduled for execution once either the delay has expired or the
- * socket operation is ready.  It will be run with the priority of
- * the calling task.
+ * socket operation is ready.  It will be run with the DEFAULT priority.
  *
  * @param delay when should this operation time out? Use
  *        GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
@@ -1422,13 +1449,15 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay,
   rs = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_set (rs, rfd);
   ret =
-      GNUNET_SCHEDULER_add_select (check_priority (current_priority),
-                                   GNUNET_SCHEDULER_NO_TASK, delay, rs, NULL,
-                                   task, task_cls);
+    GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                GNUNET_SCHEDULER_NO_TASK, delay, rs, NULL,
+                                task, task_cls);
   GNUNET_NETWORK_fdset_destroy (rs);
   return ret;
 #else
-  return add_without_sets (delay, GNUNET_NETWORK_get_fd (rfd), -1, task,
+  return add_without_sets (delay, 
+                          GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                          GNUNET_NETWORK_get_fd (rfd), -1, task,
                            task_cls);
 #endif
 }
@@ -1463,14 +1492,16 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay,
   ws = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_set (ws, wfd);
   ret =
-      GNUNET_SCHEDULER_add_select (check_priority (current_priority),
-                                   GNUNET_SCHEDULER_NO_TASK, delay, NULL, ws,
+    GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                GNUNET_SCHEDULER_NO_TASK, delay, NULL, ws,
                                    task, task_cls);
   GNUNET_NETWORK_fdset_destroy (ws);
   return ret;
 #else
   GNUNET_assert (GNUNET_NETWORK_get_fd (wfd) >= 0);
-  return add_without_sets (delay, -1, GNUNET_NETWORK_get_fd (wfd), task,
+  return add_without_sets (delay, 
+                          GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                          -1, GNUNET_NETWORK_get_fd (wfd), task,
                            task_cls);
 #endif
 }
@@ -1481,8 +1512,7 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay,
  * specified file descriptor is ready for reading.  The delay can be
  * used as a timeout on the socket being ready.  The task will be
  * scheduled for execution once either the delay has expired or the
- * socket operation is ready. It will be run with the priority of
- * the calling task.
+ * socket operation is ready. It will be run with the DEFAULT priority.
  *
  * @param delay when should this operation time out? Use
  *        GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
@@ -1505,7 +1535,7 @@ GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay,
   rs = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_handle_set (rs, rfd);
   ret =
-      GNUNET_SCHEDULER_add_select (check_priority (current_priority),
+      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
                                    GNUNET_SCHEDULER_NO_TASK, delay, rs, NULL,
                                    task, task_cls);
   GNUNET_NETWORK_fdset_destroy (rs);
@@ -1514,7 +1544,9 @@ GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay,
   int fd;
 
   GNUNET_DISK_internal_file_handle_ (rfd, &fd, sizeof (int));
-  return add_without_sets (delay, fd, -1, task, task_cls);
+  return add_without_sets (delay, 
+                          GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                          fd, -1, task, task_cls);
 
 #endif
 }
@@ -1525,8 +1557,7 @@ GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay,
  * specified file descriptor is ready for writing.  The delay can be
  * used as a timeout on the socket being ready.  The task will be
  * scheduled for execution once either the delay has expired or the
- * socket operation is ready. It will be run with the priority of
- * the calling task.
+ * socket operation is ready. It will be run with the DEFAULT priority.
  *
  * @param delay when should this operation time out? Use
  *        GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
@@ -1549,7 +1580,7 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
   ws = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_handle_set (ws, wfd);
   ret =
-      GNUNET_SCHEDULER_add_select (check_priority (current_priority),
+      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
                                    GNUNET_SCHEDULER_NO_TASK, delay, NULL, ws,
                                    task, task_cls);
   GNUNET_NETWORK_fdset_destroy (ws);
@@ -1559,7 +1590,9 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
 
   GNUNET_DISK_internal_file_handle_ (wfd, &fd, sizeof (int));
   GNUNET_assert (fd >= 0);
-  return add_without_sets (delay, -1, fd, task, task_cls);
+  return add_without_sets (delay, 
+                          GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                          -1, fd, task, task_cls);
 
 #endif
 }
@@ -1648,10 +1681,8 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
   t->next = pending;
   pending = t;
   max_priority_added = GNUNET_MAX (max_priority_added, t->priority);
-#if DEBUG_TASKS
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
        t->callback_cls);
-#endif
 #if EXECINFO
   int i;