fixing parent_control_handler hack, adding lifeness attribute to tasks
authorChristian Grothoff <christian@grothoff.org>
Tue, 2 Aug 2011 14:35:29 +0000 (14:35 +0000)
committerChristian Grothoff <christian@grothoff.org>
Tue, 2 Aug 2011 14:35:29 +0000 (14:35 +0000)
src/include/gnunet_os_lib.h
src/include/gnunet_scheduler_lib.h
src/util/os_priority.c
src/util/scheduler.c

index 328f20c3594bd6995757fe8829fbd43ad8bbdf46..48027e9220b542e6b61f2fcaf333abb03b7c1661 100644 (file)
@@ -313,7 +313,8 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc,
 
 
 /**
- * Retrieve the status of a process
+ * Retrieve the status of a process.  Nonblocking version.
+ *
  * @param proc pointer to process structure
  * @param type status type
  * @param code return code/signal number
@@ -324,7 +325,12 @@ int GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
 
 
 /**
- * Wait for a process
+ * Wait for a process to terminate.  The return code is discarded.
+ * You must not use 'GNUNET_OS_process_status' on the same process
+ * after calling this function!  This function is blocking and should
+ * thus only be used if the child process is known to have terminated
+ * or to terminate very soon.
+ *
  * @param proc pointer to process structure of the process to wait for
  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
  */
@@ -339,13 +345,6 @@ GNUNET_OS_install_parent_control_handler (void *cls,
                                           const struct
                                           GNUNET_SCHEDULER_TaskContext * tc);
 
-/**
- * Called everty time the parent process sends a signal
- */
-void
-parent_control_handler (void *cls,
-                       const struct
-                       GNUNET_SCHEDULER_TaskContext * tc);
 
 /**
  * Check whether an executable exists and possibly
index 774f2f4bc7eade215bf0b3a42d4c83bcd2863429..ce3261f0a4cbe4d48f7941425880d20a51bf8006 100644 (file)
@@ -1,6 +1,6 @@
 /*
       This file is part of GNUnet
-      (C) 2009 Christian Grothoff (and other contributing authors)
+      (C) 2009, 2011 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
@@ -322,6 +322,26 @@ GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_Task task,
                          void *task_cls);
 
 
+/**
+ * Schedule a new task to be run as soon as possible with the
+ * (transitive) ignore-shutdown flag either explicitly set or
+ * explicitly enabled.  This task (and all tasks created from it,
+ * other than by another call to this function) will either count or
+ * not count for the 'lifeness' of the process.  This API is only
+ * useful in a few special cases.
+ *
+ * @param lifeness GNUNET_YES if the task counts for lifeness, GNUNET_NO if not.
+ * @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_now_with_lifeness (int lifeness,
+                                       GNUNET_SCHEDULER_Task task,
+                                       void *task_cls);
+
+
 /**
  * Schedule a new task to be run with a specified delay.  The task
  * will be scheduled for execution once the delay has expired. It
index c9458212ee2b96c5dbd6ab3275b4b77142c77a0f..f2e3f3c382fa54a89c418bd1267a04f3b1856289 100644 (file)
@@ -51,7 +51,7 @@ static struct GNUNET_OS_Process current_process;
  * @param cls the 'struct GNUNET_DISK_FileHandle' of the control pipe
  * @param tc scheduler context
  */
-void
+static void
 parent_control_handler (void *cls,
                        const struct
                        GNUNET_SCHEDULER_TaskContext * tc)
@@ -718,12 +718,12 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   cmdlen = 0;
   va_copy (ap, va);
   while (NULL != (arg = va_arg (ap, char *)))
-  {
+    {
       if (cmdlen == 0)
         cmdlen = cmdlen + strlen (path) + 3;
       else
         cmdlen = cmdlen + strlen (arg) + 3;
-  }
+    }
   va_end (ap);
 
   cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1));
@@ -1244,6 +1244,7 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
   return GNUNET_OK;
 }
 
+
 /**
  * Wait for a process
  * @param proc pointer to process structure
index eaf96589458372d198e4330e5f6ce806af255b93..429adafa31457cb6e30f7a91b1b5df8ed59ee8d9 100644 (file)
@@ -149,6 +149,12 @@ struct Task
    * Set if we only wait for writing to a single FD, otherwise -1.
    */
   int write_fd;
+  
+  /**
+   * Should the existence of this task in the queue be counted as
+   * reason to not shutdown the scheduler?
+   */
+  int lifeness;
 
 #if EXECINFO
   /**
@@ -234,6 +240,10 @@ static enum GNUNET_SCHEDULER_Priority current_priority;
  */
 static enum GNUNET_SCHEDULER_Priority max_priority_added;
 
+/**
+ * Value of the 'lifeness' flag for the current task.
+ */
+static int current_lifeness;
 
 /**
  * Check that the given priority is legal (and return it).
@@ -614,6 +624,7 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs,
          (void) GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), 
                                                 pos->priority);
        }
+      current_lifeness = pos->lifeness;
       active_task = pos;
 #if PROFILE_DELAYS
       if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value >
@@ -693,6 +704,34 @@ 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
+ */
+static int
+check_lifeness()
+{
+  struct Task *t;
+  if (ready_count > 0)
+    return GNUNET_OK;
+  for (t = pending; NULL != t; t = t->next)
+    if (t->lifeness == GNUNET_YES)
+      return GNUNET_OK;
+  for (t = pending_timeout; NULL != t; t = t->next)
+    if (t->lifeness == GNUNET_YES)
+       return GNUNET_OK;
+  if ( (NULL != pending) || (NULL != pending_timeout) )
+    {
+      GNUNET_SCHEDULER_shutdown ();
+      return GNUNET_OK;
+    }
+  return GNUNET_NO;
+}
+
+
 /**
  * Initialize and run scheduler.  This function will return when all
  * tasks have completed.  On systems with signals, receiving a SIGTERM
@@ -742,22 +781,18 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, &sighandler_shutdown);
 #endif
   current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
+  current_lifeness = GNUNET_YES;
   GNUNET_SCHEDULER_add_continuation (task,
                                      task_cls,
                                      GNUNET_SCHEDULER_REASON_STARTUP);
 #if ENABLE_WINDOWS_WORKAROUNDS
-  GNUNET_SCHEDULER_add_continuation (&GNUNET_OS_install_parent_control_handler,
-                                     NULL, GNUNET_SCHEDULER_REASON_STARTUP);
+  GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO,
+                                         &GNUNET_OS_install_parent_control_handler,
+                                         NULL, GNUNET_SCHEDULER_REASON_STARTUP);
 #endif
   last_tr = 0;
   busy_wait_warning = 0;
-  while ((pending != NULL
-#if ENABLE_WINDOWS_WORKAROUNDS
-          && (pending->callback != parent_control_handler || pending->next != NULL)
-#endif
-         ) ||
-        (pending_timeout != NULL) ||
-        (ready_count > 0))
+  while (GNUNET_OK == check_lifeness ())
     {
       GNUNET_NETWORK_fdset_zero (rs);
       GNUNET_NETWORK_fdset_zero (ws);
@@ -1008,6 +1043,7 @@ GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task,
 #endif
   t->reason = reason;
   t->priority = current_priority;
+  t->lifeness = current_lifeness;
 #if DEBUG_TASKS
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Adding continuation task: %llu / %p\n",
@@ -1109,6 +1145,7 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
 #endif
   t->timeout = GNUNET_TIME_relative_to_absolute (delay);
   t->priority = current_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;
@@ -1176,7 +1213,7 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
  */
 GNUNET_SCHEDULER_TaskIdentifier
 GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_Task task,
-                                                 void *task_cls)
+                         void *task_cls)
 {
   return GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
                                       GNUNET_SCHEDULER_NO_TASK,
@@ -1185,6 +1222,37 @@ GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_Task task,
 }
 
 
+/**
+ * Schedule a new task to be run as soon as possible with the
+ * (transitive) ignore-shutdown flag either explicitly set or
+ * explicitly enabled.  This task (and all tasks created from it,
+ * other than by another call to this function) will either count or
+ * not count for the 'lifeness' of the process.  This API is only
+ * useful in a few special cases.
+ *
+ * @param lifeness GNUNET_YES if the task counts for lifeness, GNUNET_NO if not.
+ * @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_now_with_lifeness (int lifeness,
+                                       GNUNET_SCHEDULER_Task task,
+                                       void *task_cls)
+{
+  GNUNET_SCHEDULER_TaskIdentifier ret;
+
+  ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP,
+                                    GNUNET_SCHEDULER_NO_TASK,
+                                    GNUNET_TIME_UNIT_ZERO,
+                                    NULL, NULL, task, task_cls);
+  GNUNET_assert (pending->id == ret);
+  pending->lifeness = lifeness;
+  return ret;
+}
+
+
 
 
 /**
@@ -1280,6 +1348,7 @@ add_without_sets (struct GNUNET_TIME_Relative delay,
   t->prereq_id = GNUNET_SCHEDULER_NO_TASK;
   t->timeout = GNUNET_TIME_relative_to_absolute (delay);
   t->priority = check_priority (current_priority);
+  t->lifeness = current_lifeness;
   t->next = pending;
   pending = t;
   max_priority_added = GNUNET_MAX (max_priority_added,
@@ -1564,10 +1633,11 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
     check_priority ((prio ==
                      GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority
                     : prio);
+  t->lifeness = current_lifeness;
   t->next = pending;
   pending = t;
   max_priority_added = GNUNET_MAX (max_priority_added,
-                                         t->priority);
+                                  t->priority);
 #if DEBUG_TASKS
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Adding task: %llu / %p\n", t->id, t->callback_cls);