+ t->priority);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Adding task %p\n",
+ t);
+ init_backtrace (t);
+ return t;
+}
+
+
+/**
+ * Function used by event-loop implementations to signal the scheduler
+ * that a particular @a task is ready due to an event of type @a et.
+ *
+ * This function will then queue the task to notify the application
+ * that the task is ready (with the respective priority).
+ *
+ * @param task the task that is ready, NULL for wake up calls
+ * @param et information about why the task is ready
+ */
+void
+GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task,
+ enum GNUNET_SCHEDULER_EventType et)
+{
+ enum GNUNET_SCHEDULER_Reason reason;
+ struct GNUNET_TIME_Absolute now;
+
+ now = GNUNET_TIME_absolute_get ();
+ reason = task->reason;
+ if (now.abs_value_us >= task->timeout.abs_value_us)
+ reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
+ if ( (0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
+ (0 != (GNUNET_SCHEDULER_ET_IN & et)) )
+ reason |= GNUNET_SCHEDULER_REASON_READ_READY;
+ if ( (0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
+ (0 != (GNUNET_SCHEDULER_ET_OUT & et)) )
+ reason |= GNUNET_SCHEDULER_REASON_WRITE_READY;
+ reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;
+ task->reason = reason;
+ task->fds = &task->fdx;
+ task->fdx.et = et;
+ task->fds_len = 1;
+ queue_ready_task (task);
+}
+
+
+/**
+ * Function called by the driver to tell the scheduler to run some of
+ * the tasks that are ready. This function may return even though
+ * there are tasks left to run just to give other tasks a chance as
+ * well. If we return #GNUNET_YES, the driver should call this
+ * function again as soon as possible, while if we return #GNUNET_NO
+ * it must block until the operating system has more work as the
+ * scheduler has no more work to do right now.
+ *
+ * @param sh scheduler handle that was given to the `loop`
+ * @return #GNUNET_OK if there are more tasks that are ready,
+ * and thus we would like to run more (yield to avoid
+ * blocking other activities for too long)
+ * #GNUNET_NO if we are done running tasks (yield to block)
+ * #GNUNET_SYSERR on error
+ */
+int
+GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh)
+{
+ enum GNUNET_SCHEDULER_Priority p;
+ struct GNUNET_SCHEDULER_Task *pos;
+ struct GNUNET_TIME_Absolute now;
+
+ /* check for tasks that reached the timeout! */
+ now = GNUNET_TIME_absolute_get ();
+ while (NULL != (pos = pending_timeout_head))
+ {
+ if (now.abs_value_us >= pos->timeout.abs_value_us)
+ pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
+ if (0 == pos->reason)
+ break;
+ GNUNET_CONTAINER_DLL_remove (pending_timeout_head,
+ pending_timeout_tail,
+ pos);
+ if (pending_timeout_last == pos)
+ pending_timeout_last = NULL;
+ queue_ready_task (pos);
+ }
+
+ if (0 == ready_count)
+ return GNUNET_NO;
+
+ /* find out which task priority level we are going to
+ process this time */
+ max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP;
+ GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]);
+ /* yes, p>0 is correct, 0 is "KEEP" which should
+ * always be an empty queue (see assertion)! */
+ for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--)
+ {
+ pos = ready_head[p];
+ if (NULL != pos)
+ break;
+ }
+ GNUNET_assert (NULL != pos); /* ready_count wrong? */
+
+ /* process all tasks at this priority level, then yield */
+ while (NULL != (pos = ready_head[p]))
+ {
+ GNUNET_CONTAINER_DLL_remove (ready_head[p],
+ ready_tail[p],
+ pos);
+ ready_count--;
+ 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_us >
+ DELAY_THRESHOLD.rel_value_us)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Task %p took %s to be scheduled\n",
+ pos,
+ GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time),
+ GNUNET_YES));
+ }