-remove trailing whitespace
[oweals/gnunet.git] / src / util / scheduler.c
index 52824d8b343fa7ca48baf45897e90135f2027b0f..8652ee29769834bd9a4903da462ccfac2ebdca15 100644 (file)
@@ -1,10 +1,10 @@
 /*
       This file is part of GNUnet
-      (C) 2009, 2011 Christian Grothoff (and other contributing authors)
+      (C) 2009-2013 Christian Grothoff (and other contributing authors)
 
       GNUnet is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published
-      by the Free Software Foundation; either version 2, or (at your
+      by the Free Software Foundation; either version 3, or (at your
       option) any later version.
 
       GNUnet is distributed in the hope that it will be useful, but
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_os_lib.h"
-#include "gnunet_scheduler_lib.h"
-#include "gnunet_signal_lib.h"
-#include "gnunet_time_lib.h"
+#include "gnunet_util_lib.h"
 #include "disk.h"
-#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)
+
+
+#if HAVE_EXECINFO_H
+#include "execinfo.h"
 
 /**
  * Use lsof to generate file descriptor reports on select error?
@@ -56,8 +57,6 @@
 #define MAX_TRACE_DEPTH 50
 #endif
 
-#define DEBUG_TASKS GNUNET_NO
-
 /**
  * Should we figure out which tasks are delayed for a while
  * before they are run? (Consider using in combination with EXECINFO).
@@ -70,6 +69,7 @@
  */
 #define DELAY_THRESHOLD GNUNET_TIME_UNIT_SECONDS
 
+
 /**
  * Linked list of pending tasks.
  */
@@ -110,11 +110,6 @@ struct Task
    */
   GNUNET_SCHEDULER_TaskIdentifier id;
 
-  /**
-   * Identifier of a prerequisite task.
-   */
-  GNUNET_SCHEDULER_TaskIdentifier prereq_id;
-
   /**
    * Absolute timeout value for the task, or
    * GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout".
@@ -211,13 +206,6 @@ static struct Task *ready[GNUNET_SCHEDULER_PRIORITY_COUNT];
  */
 static GNUNET_SCHEDULER_TaskIdentifier last_id;
 
-/**
- * Highest number so that all tasks with smaller identifiers
- * have already completed.  Also the lowest number of a task
- * still waiting to be executed.
- */
-static GNUNET_SCHEDULER_TaskIdentifier lowest_pending_id;
-
 /**
  * Number of tasks on the ready list.
  */
@@ -247,7 +235,7 @@ static int current_lifeness;
 
 /**
  * Function to use as a select() in the scheduler.
- * If NULL, we use GNUNET_NETWORK_socket_select ().
+ * If NULL, we use GNUNET_NETWORK_socket_select().
  */
 static GNUNET_SCHEDULER_select scheduler_select;
 
@@ -260,6 +248,7 @@ static void *scheduler_select_cls;
  * Sets the select function to use in the scheduler (scheduler_select).
  *
  * @param new_select new select function to use
+ * @param new_select_cls closure for @a new_select
  * @return previously used select function, NULL for default
  */
 void
@@ -287,60 +276,6 @@ check_priority (enum GNUNET_SCHEDULER_Priority p)
 }
 
 
-/**
- * Is a task with this identifier still pending?  Also updates
- * "lowest_pending_id" as a side-effect (for faster checks in the
- * future), but only if the return value is "GNUNET_NO" (and
- * the "lowest_pending_id" check failed).
- *
- * @param id which task are we checking for
- * @return GNUNET_YES if so, GNUNET_NO if not
- */
-static int
-is_pending (GNUNET_SCHEDULER_TaskIdentifier id)
-{
-  struct Task *pos;
-  enum GNUNET_SCHEDULER_Priority p;
-  GNUNET_SCHEDULER_TaskIdentifier min;
-
-  if (id < lowest_pending_id)
-    return GNUNET_NO;
-  min = -1;                     /* maximum value */
-  pos = pending;
-  while (pos != NULL)
-  {
-    if (pos->id == id)
-      return GNUNET_YES;
-    if (pos->id < min)
-      min = pos->id;
-    pos = pos->next;
-  }
-  pos = pending_timeout;
-  while (pos != NULL)
-  {
-    if (pos->id == id)
-      return GNUNET_YES;
-    if (pos->id < min)
-      min = pos->id;
-    pos = pos->next;
-  }
-  for (p = 0; p < GNUNET_SCHEDULER_PRIORITY_COUNT; p++)
-  {
-    pos = ready[p];
-    while (pos != NULL)
-    {
-      if (pos->id == id)
-        return GNUNET_YES;
-      if (pos->id < min)
-        min = pos->id;
-      pos = pos->next;
-    }
-  }
-  lowest_pending_id = min;
-  return GNUNET_NO;
-}
-
-
 /**
  * Update all sets and timeout for select.
  *
@@ -361,7 +296,7 @@ update_sets (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws,
   if (pos != NULL)
   {
     to = GNUNET_TIME_absolute_get_difference (now, pos->timeout);
-    if (timeout->rel_value > to.rel_value)
+    if (timeout->rel_value_us > to.rel_value_us)
       *timeout = to;
     if (pos->reason != 0)
       *timeout = GNUNET_TIME_UNIT_ZERO;
@@ -369,16 +304,10 @@ update_sets (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws,
   pos = pending;
   while (pos != NULL)
   {
-    if ((pos->prereq_id != GNUNET_SCHEDULER_NO_TASK) &&
-        (GNUNET_YES == is_pending (pos->prereq_id)))
-    {
-      pos = pos->next;
-      continue;
-    }
-    if (pos->timeout.abs_value != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value)
+    if (pos->timeout.abs_value_us != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
     {
       to = GNUNET_TIME_absolute_get_difference (now, pos->timeout);
-      if (timeout->rel_value > to.rel_value)
+      if (timeout->rel_value_us > to.rel_value_us)
         *timeout = to;
     }
     if (pos->read_fd != -1)
@@ -430,7 +359,7 @@ set_overlaps (const struct GNUNET_NETWORK_FDSet *ready,
  * @param now the current time
  * @param rs set of FDs ready for reading
  * @param ws set of FDs ready for writing
- * @return GNUNET_YES if we can run it, GNUNET_NO if not.
+ * @return #GNUNET_YES if we can run it, #GNUNET_NO if not.
  */
 static int
 is_ready (struct Task *task, struct GNUNET_TIME_Absolute now,
@@ -440,7 +369,7 @@ is_ready (struct Task *task, struct GNUNET_TIME_Absolute now,
   enum GNUNET_SCHEDULER_Reason reason;
 
   reason = task->reason;
-  if (now.abs_value >= task->timeout.abs_value)
+  if (now.abs_value_us >= task->timeout.abs_value_us)
     reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
   if ((0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
       (((task->read_fd != -1) &&
@@ -454,15 +383,7 @@ is_ready (struct Task *task, struct GNUNET_TIME_Absolute now,
     reason |= GNUNET_SCHEDULER_REASON_WRITE_READY;
   if (reason == 0)
     return GNUNET_NO;           /* not ready */
-  if (task->prereq_id != GNUNET_SCHEDULER_NO_TASK)
-  {
-    if (GNUNET_YES == is_pending (task->prereq_id))
-    {
-      task->reason = reason;
-      return GNUNET_NO;         /* prereq waiting */
-    }
-    reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;
-  }
+  reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;
   task->reason = reason;
   return GNUNET_YES;
 }
@@ -508,7 +429,7 @@ check_ready (const struct GNUNET_NETWORK_FDSet *rs,
   while (pos != NULL)
   {
     next = pos->next;
-    if (now.abs_value >= pos->timeout.abs_value)
+    if (now.abs_value_us >= pos->timeout.abs_value_us)
       pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
     if (0 == pos->reason)
       break;
@@ -521,11 +442,9 @@ check_ready (const struct GNUNET_NETWORK_FDSet *rs,
   pos = pending;
   while (pos != NULL)
   {
-#if DEBUG_TASKS
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Checking readiness of task: %llu / %p\n", pos->id,
-                pos->callback_cls);
-#endif
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Checking readiness of task: %llu / %p\n",
+         pos->id, pos->callback_cls);
     next = pos->next;
     if (GNUNET_YES == is_ready (pos, now, rs, ws))
     {
@@ -613,7 +532,7 @@ destroy_task (struct Task *t)
  * empty.  Keep running tasks until we are either no longer running
  * "URGENT" tasks or until we have at least one "pending" task (which
  * may become ready, hence we should select on it).  Naturally, if
- * there are no more ready tasks, we also return.  
+ * there are no more ready tasks, we also return.
  *
  * @param rs FDs ready for reading
  * @param ws FDs ready for writing
@@ -642,23 +561,17 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws)
     GNUNET_assert (pos != NULL);        /* ready_count wrong? */
     ready[p] = pos->next;
     ready_count--;
-    if (current_priority != pos->priority)
-    {
-      current_priority = pos->priority;
-      (void) GNUNET_OS_set_process_priority (GNUNET_OS_process_current (),
-                                             pos->priority);
-    }
+    current_priority = pos->priority;
     current_lifeness = pos->lifeness;
     active_task = pos;
 #if PROFILE_DELAYS
-    if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value >
-        DELAY_THRESHOLD.rel_value)
+    if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us >
+        DELAY_THRESHOLD.rel_value_us)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Task %llu took %llums to be scheduled\n", pos->id,
-                  (unsigned long long)
-                  GNUNET_TIME_absolute_get_duration
-                  (pos->start_time).rel_value);
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+          "Task %llu took %s to be scheduled\n",
+           (unsigned long long) pos->id,
+           GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time), GNUNET_YES));
     }
 #endif
     tc.reason = pos->reason;
@@ -673,18 +586,17 @@ 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)))
-      abort ();                 // added to ready in previous select loop!
-#if DEBUG_TASKS
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running task: %llu / %p\n", pos->id,
-                pos->callback_cls);
-#endif
+      GNUNET_abort ();          // added to ready in previous select loop!
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Running task: %llu / %p\n", pos->id,
+         pos->callback_cls);
     pos->callback (pos->callback_cls, &tc);
 #if EXECINFO
     int i;
 
     for (i = 0; i < pos->num_backtrace_strings; i++)
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Task %llu trace %d: %s\n", pos->id,
-                  i, pos->backtrace_strings[i]);
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Task %llu trace %d: %s\n", pos->id, i,
+           pos->backtrace_strings[i]);
 #endif
     active_task = NULL;
     destroy_task (pos);
@@ -698,6 +610,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.
  */
@@ -708,6 +626,26 @@ sighandler_pipe ()
   return;
 }
 #endif
+
+
+/**
+ * Wait for a short time.
+ * Sleeps for @a ms ms (as that should be long enough for virtually all
+ * modern systems to context switch and allow another process to do
+ * some 'real' work).
+ *
+ * @param ms how many ms to wait
+ */
+static void
+short_wait (unsigned int ms)
+{
+  struct GNUNET_TIME_Relative timeout;
+
+  timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, ms);
+  (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
+}
+
+
 /**
  * Signal handler called for signals that should cause us to shutdown.
  */
@@ -717,6 +655,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));
@@ -726,10 +667,10 @@ sighandler_shutdown ()
 
 /**
  * Check if the system is still life. Trigger shutdown if we
- * have tasks, but none of them give us lifeness.  
+ * have tasks, but none of them give us lifeness.
  *
- * @return GNUNET_OK to continue the main loop,
- *         GNUNET_NO to exit
+ * @return #GNUNET_OK to continue the main loop,
+ *         #GNUNET_NO to exit
  */
 static int
 check_lifeness ()
@@ -791,11 +732,13 @@ 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 ();
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering signal handlers\n");
   shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown);
   shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown);
 #ifndef MINGW
@@ -807,13 +750,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 ())
@@ -837,7 +778,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
       if (errno == EINTR)
         continue;
 
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");
+      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "select");
 #ifndef MINGW
 #if USE_LSOF
       char lsof[512];
@@ -846,17 +787,16 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
       (void) close (1);
       (void) dup2 (2, 1);
       if (0 != system (lsof))
-        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "system");
+        LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "system");
 #endif
 #endif
-      abort ();
+      GNUNET_abort ();
       break;
     }
-    if ((ret == 0) && (timeout.rel_value == 0) && (busy_wait_warning > 16))
+    if ((0 == ret) && (0 == timeout.rel_value_us) && (busy_wait_warning > 16))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  _("Looks like we're busy waiting...\n"));
-      sleep (1);                /* mitigate */
+      LOG (GNUNET_ERROR_TYPE_WARNING, _("Looks like we're busy waiting...\n"));
+      short_wait (100);                /* mitigate */
     }
     check_ready (rs, ws);
     run_ready (rs, ws);
@@ -869,6 +809,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
     }
     if (last_tr == tasks_run)
     {
+      short_wait (1);
       busy_wait_warning++;
     }
     else
@@ -893,7 +834,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
 
 /**
  * Obtain the reason code for why the current task was
- * started.  Will return the same value as 
+ * started.  Will return the same value as
  * the GNUNET_SCHEDULER_TaskContext's reason field.
  *
  * @return reason(s) why the current task is run
@@ -985,9 +926,8 @@ GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_TaskIdentifier task)
     p++;
     if (p >= GNUNET_SCHEDULER_PRIORITY_COUNT)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _("Attempt to cancel dead task %llu!\n"),
-                  (unsigned long long) task);
+      LOG (GNUNET_ERROR_TYPE_ERROR, _("Attempt to cancel dead task %llu!\n"),
+           (unsigned long long) task);
       GNUNET_assert (0);
     }
     prev = NULL;
@@ -1026,10 +966,8 @@ GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_TaskIdentifier task)
     prev->next = t->next;
   }
   ret = t->callback_cls;
-#if DEBUG_TASKS
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Canceling task: %llu / %p\n", task,
-              t->callback_cls);
-#endif
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Canceling task: %llu / %p\n", task,
+       t->callback_cls);
   destroy_task (t);
   return ret;
 }
@@ -1043,10 +981,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;
 
@@ -1072,40 +1012,30 @@ 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
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding continuation task: %llu / %p\n",
-              t->id, t->callback_cls);
-#endif
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding continuation task: %llu / %p\n", t->id,
+       t->callback_cls);
   queue_ready_task (t);
 }
 
 
-
 /**
- * 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.
+ * 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 prerequisite_task run this task after the task with the given
- *        task identifier completes (and any of our other
- *        conditions, such as delay, read or write-readiness
- *        are satisfied).  Use  GNUNET_SCHEDULER_NO_TASK to not have any dependency
- *        on completion of other tasks (this will cause the task to run as
- *        soon as possible).
  * @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!
+ * @param task_cls closure for 'main'
+ * @param reason reason for task invocation
  */
-GNUNET_SCHEDULER_TaskIdentifier
-GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
-                            GNUNET_SCHEDULER_Task task, void *task_cls)
+void
+GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls,
+                                   enum GNUNET_SCHEDULER_Reason reason)
 {
-  return GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
-                                      prerequisite_task, GNUNET_TIME_UNIT_ZERO,
-                                      NULL, NULL, task, task_cls);
+  GNUNET_SCHEDULER_add_continuation_with_priority (task, task_cls,
+                                                  reason,
+                                                  GNUNET_SCHEDULER_PRIORITY_DEFAULT);
 }
 
 
@@ -1122,7 +1052,7 @@ GNUNET_SCHEDULER_TaskIdentifier
 GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio,
                                     GNUNET_SCHEDULER_Task task, void *task_cls)
 {
-  return GNUNET_SCHEDULER_add_select (prio, GNUNET_SCHEDULER_NO_TASK,
+  return GNUNET_SCHEDULER_add_select (prio,
                                       GNUNET_TIME_UNIT_ZERO, NULL, NULL, task,
                                       task_cls);
 }
@@ -1131,22 +1061,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 
+ * @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;
@@ -1172,14 +1101,14 @@ 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) */
   prev = pending_timeout_last;
   if (prev != NULL)
   {
-    if (prev->timeout.abs_value > t->timeout.abs_value)
+    if (prev->timeout.abs_value_us > t->timeout.abs_value_us)
       prev = NULL;
     else
       pos = prev->next;         /* heuristic success! */
@@ -1190,8 +1119,8 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
     pos = pending_timeout;
   }
   while ((pos != NULL) &&
-         ((pos->timeout.abs_value <= t->timeout.abs_value) ||
-          (pos->reason != 0)))
+         ((pos->timeout.abs_value_us <= t->timeout.abs_value_us) ||
+          (0 != pos->reason)))
   {
     prev = pos;
     pos = pos->next;
@@ -1204,45 +1133,60 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
   /* hyper-optimization... */
   pending_timeout_last = t;
 
-#if DEBUG_TASKS
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
-              t->callback_cls);
-#endif
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
+       t->callback_cls);
 #if EXECINFO
   int i;
 
   for (i = 0; i < t->num_backtrace_strings; i++)
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i,
-                t->backtrace_strings[i]);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i,
+         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 as soon as possible. The task
- * will be run with the priority of the calling task.
+ * 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.  Note that this
+ * does not guarantee that this will be the next task that is being
+ * run, as other tasks with higher priority (or that are already ready
+ * to run) might get to run first.  Just as with delays, clients must
+ * not rely on any particular order of execution between tasks
+ * scheduled concurrently.
+ *
+ * The task will be run with the DEFAULT priority.
+ *
+ * @param task main function of the task
+ * @param task_cls closure of @a task
+ * @return unique task identifier for the job
+ *         only valid until "task" is started!
+ */
+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);
 }
 
 
@@ -1268,8 +1212,7 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
   GNUNET_SCHEDULER_TaskIdentifier ret;
 
   ret =
-      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
-                                   GNUNET_SCHEDULER_NO_TASK,
+      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
                                    GNUNET_TIME_UNIT_ZERO, NULL, NULL, task,
                                    task_cls);
   GNUNET_assert (pending->id == ret);
@@ -1278,8 +1221,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
@@ -1299,6 +1240,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
@@ -1307,8 +1249,10 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
  *         only valid until "task" is started!
  */
 #ifndef MINGW
-GNUNET_SCHEDULER_TaskIdentifier
-add_without_sets (struct GNUNET_TIME_Relative delay, int rfd, int wfd,
+static GNUNET_SCHEDULER_TaskIdentifier
+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;
@@ -1332,16 +1276,14 @@ add_without_sets (struct GNUNET_TIME_Relative delay, int rfd, int wfd,
   {
     int flags = fcntl (rfd, F_GETFD);
 
-    if (flags == -1 && errno == EBADF)
+    if ((flags == -1) && (errno == EBADF))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n",
-                  rfd);
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n", rfd);
 #if EXECINFO
       int i;
 
       for (i = 0; i < t->num_backtrace_strings; i++)
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n",
-                    t->backtrace_strings[i]);
+        LOG (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n", t->backtrace_strings[i]);
 #endif
       GNUNET_assert (0);
     }
@@ -1352,14 +1294,12 @@ add_without_sets (struct GNUNET_TIME_Relative delay, int rfd, int wfd,
 
     if (flags == -1 && errno == EBADF)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n",
-                  wfd);
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n", wfd);
 #if EXECINFO
       int i;
 
       for (i = 0; i < t->num_backtrace_strings; i++)
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n",
-                    t->backtrace_strings[i]);
+        LOG (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n", t->backtrace_strings[i]);
 #endif
       GNUNET_assert (0);
     }
@@ -1372,23 +1312,20 @@ add_without_sets (struct GNUNET_TIME_Relative delay, int rfd, int wfd,
 #if PROFILE_DELAYS
   t->start_time = GNUNET_TIME_absolute_get ();
 #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
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
-              t->callback_cls);
-#endif
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
+       t->callback_cls);
 #if EXECINFO
   int i;
 
   for (i = 0; i < t->num_backtrace_strings; i++)
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i,
-                t->backtrace_strings[i]);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i,
+         t->backtrace_strings[i]);
 #endif
   return t->id;
 }
@@ -1401,10 +1338,9 @@ 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 
+ * @param delay when should this operation time out? Use
  *        GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
  * @param rfd read file-descriptor
  * @param task main function of the task
@@ -1416,6 +1352,35 @@ GNUNET_SCHEDULER_TaskIdentifier
 GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay,
                                struct GNUNET_NETWORK_Handle *rfd,
                                GNUNET_SCHEDULER_Task task, void *task_cls)
+{
+  return GNUNET_SCHEDULER_add_read_net_with_priority (delay,
+                                                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                                     rfd, task, task_cls);
+}
+
+
+/**
+ * Schedule a new task to be run with a specified priority and to be
+ * run after the specified delay or when the 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 DEFAULT priority.
+ *
+ * @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 rfd read file-descriptor
+ * @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_read_net_with_priority (struct GNUNET_TIME_Relative delay,
+                                            enum GNUNET_SCHEDULER_Priority priority,
+                                            struct GNUNET_NETWORK_Handle *rfd,
+                                            GNUNET_SCHEDULER_Task task, void *task_cls)
 {
 #if MINGW
   struct GNUNET_NETWORK_FDSet *rs;
@@ -1425,18 +1390,21 @@ 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 (priority,
+                                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,
+                          priority,
+                          GNUNET_NETWORK_get_fd (rfd), -1, task,
                            task_cls);
 #endif
 }
 
 
+
 /**
  * Schedule a new task to be run with a specified delay or when the
  * specified file descriptor is ready for writing.  The delay can be
@@ -1445,7 +1413,7 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay,
  * socket operation is ready.  It will be run with the priority of
  * the calling task.
  *
- * @param delay when should this operation time out? Use 
+ * @param delay when should this operation time out? Use
  *        GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
  * @param wfd write file-descriptor
  * @param task main function of the task
@@ -1466,14 +1434,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,
+                                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
 }
@@ -1484,10 +1454,9 @@ 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 
+ * @param delay when should this operation time out? Use
  *        GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
  * @param rfd read file-descriptor
  * @param task main function of the task
@@ -1508,8 +1477,8 @@ 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_NO_TASK, delay, rs, NULL,
+      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                   delay, rs, NULL,
                                    task, task_cls);
   GNUNET_NETWORK_fdset_destroy (rs);
   return ret;
@@ -1517,7 +1486,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
 }
@@ -1528,10 +1499,9 @@ 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 
+ * @param delay when should this operation time out? Use
  *        GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
  * @param wfd write file-descriptor
  * @param task main function of the task
@@ -1552,8 +1522,8 @@ 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_NO_TASK, delay, NULL, ws,
+      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                   delay, NULL, ws,
                                    task, task_cls);
   GNUNET_NETWORK_fdset_destroy (ws);
   return ret;
@@ -1562,7 +1532,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
 }
@@ -1587,11 +1559,6 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
  * </code>
  *
  * @param prio how important is this task?
- * @param prerequisite_task run this task after the task with the given
- *        task identifier completes (and any of our other
- *        conditions, such as delay, read or write-readiness
- *        are satisfied).  Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
- *        on completion of other tasks.
  * @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 rs set of file descriptors we want to read (can be NULL)
@@ -1603,7 +1570,6 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
  */
 GNUNET_SCHEDULER_TaskIdentifier
 GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
-                             GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
                              struct GNUNET_TIME_Relative delay,
                              const struct GNUNET_NETWORK_FDSet *rs,
                              const struct GNUNET_NETWORK_FDSet *ws,
@@ -1615,7 +1581,7 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
   void *backtrace_array[MAX_TRACE_DEPTH];
 #endif
 
-  GNUNET_assert (active_task != NULL);
+  GNUNET_assert (NULL != active_task);
   GNUNET_assert (NULL != task);
   t = GNUNET_malloc (sizeof (struct Task));
   t->callback = task;
@@ -1641,7 +1607,6 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
 #if PROFILE_DELAYS
   t->start_time = GNUNET_TIME_absolute_get ();
 #endif
-  t->prereq_id = prerequisite_task;
   t->timeout = GNUNET_TIME_relative_to_absolute (delay);
   t->priority =
       check_priority ((prio ==
@@ -1651,16 +1616,14 @@ 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
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
-              t->callback_cls);
-#endif
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id,
+       t->callback_cls);
 #if EXECINFO
   int i;
 
   for (i = 0; i < t->num_backtrace_strings; i++)
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i,
-                t->backtrace_strings[i]);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i,
+         t->backtrace_strings[i]);
 #endif
   return t->id;
 }