Update plibc header
[oweals/gnunet.git] / src / util / scheduler.c
index 9b49df79a3d007a761c0acfe44cfe3802b094b90..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"
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util-scheduler", __VA_ARGS__)
@@ -239,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;
 
@@ -252,7 +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 'new_select'
+ * @param new_select_cls closure for @a new_select
  * @return previously used select function, NULL for default
  */
 void
@@ -300,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;
@@ -308,10 +304,10 @@ update_sets (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws,
   pos = pending;
   while (pos != NULL)
   {
-    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)
@@ -363,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,
@@ -373,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) &&
@@ -387,7 +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 */
-  reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;  
+  reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;
   task->reason = reason;
   return GNUNET_YES;
 }
@@ -433,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;
@@ -446,7 +442,7 @@ check_ready (const struct GNUNET_NETWORK_FDSet *rs,
   pos = pending;
   while (pos != NULL)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, 
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Checking readiness of task: %llu / %p\n",
          pos->id, pos->callback_cls);
     next = pos->next;
@@ -569,10 +565,10 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws)
     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)
     {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, 
+      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));
@@ -591,7 +587,7 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws)
         (pos->write_fd != -1) &&
         (!GNUNET_NETWORK_fdset_test_native (ws, pos->write_fd)))
       GNUNET_abort ();          // added to ready in previous select loop!
-    LOG (GNUNET_ERROR_TYPE_DEBUG, 
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Running task: %llu / %p\n", pos->id,
          pos->callback_cls);
     pos->callback (pos->callback_cls, &tc);
@@ -630,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.
  */
@@ -642,8 +658,6 @@ sighandler_shutdown ()
   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 */
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got signal %d from parent, writing to shutdown pipe\n");
   GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
                           (shutdown_pipe_handle, GNUNET_DISK_PIPE_END_WRITE),
                           &c, sizeof (c));
@@ -655,8 +669,8 @@ sighandler_shutdown ()
  * Check if the system is still life. Trigger shutdown if we
  * 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 ()
@@ -779,10 +793,10 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
       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))
     {
       LOG (GNUNET_ERROR_TYPE_WARNING, _("Looks like we're busy waiting...\n"));
-      sleep (1);                /* mitigate */
+      short_wait (100);                /* mitigate */
     }
     check_ready (rs, ws);
     run_ready (rs, ws);
@@ -795,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
@@ -1037,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, 
+  return GNUNET_SCHEDULER_add_select (prio,
                                       GNUNET_TIME_UNIT_ZERO, NULL, NULL, task,
                                       task_cls);
 }
@@ -1093,7 +1108,7 @@ GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay,
   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! */
@@ -1104,8 +1119,8 @@ GNUNET_SCHEDULER_add_delayed_with_priority (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;
@@ -1154,11 +1169,17 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
 
 
 /**
- * Schedule a new task to be run as soon as possible. The task
- * will be run with the DEFAULT priority.
+ * 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 task
+ * @param task_cls closure of @a task
  * @return unique task identifier for the job
  *         only valid until "task" is started!
  */
@@ -1229,7 +1250,7 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
  */
 #ifndef MINGW
 static GNUNET_SCHEDULER_TaskIdentifier
-add_without_sets (struct GNUNET_TIME_Relative delay, 
+add_without_sets (struct GNUNET_TIME_Relative delay,
                  enum GNUNET_SCHEDULER_Priority priority,
                  int rfd, int wfd,
                   GNUNET_SCHEDULER_Task task, void *task_cls)
@@ -1375,7 +1396,7 @@ GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay,
   GNUNET_NETWORK_fdset_destroy (rs);
   return ret;
 #else
-  return add_without_sets (delay, 
+  return add_without_sets (delay,
                           priority,
                           GNUNET_NETWORK_get_fd (rfd), -1, task,
                            task_cls);
@@ -1420,7 +1441,7 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay,
   return ret;
 #else
   GNUNET_assert (GNUNET_NETWORK_get_fd (wfd) >= 0);
-  return add_without_sets (delay, 
+  return add_without_sets (delay,
                           GNUNET_SCHEDULER_PRIORITY_DEFAULT,
                           -1, GNUNET_NETWORK_get_fd (wfd), task,
                            task_cls);
@@ -1465,7 +1486,7 @@ 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, 
+  return add_without_sets (delay,
                           GNUNET_SCHEDULER_PRIORITY_DEFAULT,
                           fd, -1, task, task_cls);
 
@@ -1511,7 +1532,7 @@ 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, 
+  return add_without_sets (delay,
                           GNUNET_SCHEDULER_PRIORITY_DEFAULT,
                           -1, fd, task, task_cls);
 
@@ -1560,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;