+/**
+ * Schedule a new task to be run at the specified time. The task
+ * will be scheduled for execution at time @a at.
+ *
+ * @param at time when the operation should run
+ * @param priority priority to use for the task
+ * @param task main function of the task
+ * @param task_cls closure of @a task
+ * @return unique task identifier for the job
+ * only valid until @a task is started!
+ */
+struct GNUNET_SCHEDULER_Task *
+GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at,
+ enum GNUNET_SCHEDULER_Priority priority,
+ GNUNET_SCHEDULER_TaskCallback task,
+ void *task_cls)
+{
+ struct GNUNET_SCHEDULER_Task *t;
+ struct GNUNET_SCHEDULER_Task *pos;
+ struct GNUNET_SCHEDULER_Task *prev;
+
+ GNUNET_assert (NULL != active_task);
+ GNUNET_assert (NULL != task);
+ t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
+ t->callback = task;
+ t->callback_cls = task_cls;
+ t->read_fd = -1;
+ t->write_fd = -1;
+#if PROFILE_DELAYS
+ t->start_time = GNUNET_TIME_absolute_get ();
+#endif
+ t->timeout = at;
+ t->priority = priority;
+ t->lifeness = current_lifeness;
+ /* try tail first (optimization in case we are
+ * appending to a long list of tasks with timeouts) */
+ if ( (NULL == pending_timeout_head) ||
+ (at.abs_value_us < pending_timeout_head->timeout.abs_value_us) )
+ {
+ GNUNET_CONTAINER_DLL_insert (pending_timeout_head,
+ pending_timeout_tail,
+ t);
+ }
+ else
+ {
+ /* first move from heuristic start backwards to before start time */
+ prev = pending_timeout_last;
+ while ( (NULL != prev) &&
+ (prev->timeout.abs_value_us > t->timeout.abs_value_us) )
+ prev = prev->prev;
+ /* now, move from heuristic start (or head of list) forward to insertion point */
+ if (NULL == prev)
+ pos = pending_timeout_head;
+ else
+ pos = prev->next;
+ while ( (NULL != pos) &&
+ ( (pos->timeout.abs_value_us <= t->timeout.abs_value_us) ||
+ (0 != pos->reason) ) )
+ {
+ prev = pos;
+ pos = pos->next;
+ }
+ GNUNET_CONTAINER_DLL_insert_after (pending_timeout_head,
+ pending_timeout_tail,
+ prev,
+ t);
+ }
+ /* finally, update heuristic insertion point to last insertion... */
+ pending_timeout_last = t;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Adding task: %p\n",
+ t);
+ init_backtrace (t);
+ return t;
+}
+