+ struct GNUNET_SCHEDULER_Task *t;
+ struct GNUNET_SCHEDULER_Task *pos;
+ struct GNUNET_SCHEDULER_Task *prev;
+
+#if EXECINFO
+ void *backtrace_array[MAX_TRACE_DEPTH];
+#endif
+
+ GNUNET_assert (NULL != active_task);
+ GNUNET_assert (NULL != task);
+ t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
+ t->callback = task;
+ t->callback_cls = task_cls;
+#if EXECINFO
+ t->num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH);
+ t->backtrace_strings =
+ backtrace_symbols (backtrace_array, t->num_backtrace_strings);
+#endif
+ t->read_fd = -1;
+ t->write_fd = -1;
+#if PROFILE_DELAYS
+ t->start_time = GNUNET_TIME_absolute_get ();
+#endif
+ t->timeout = GNUNET_TIME_relative_to_absolute (delay);
+ 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 (0 == delay.rel_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);
+#if EXECINFO
+ unsigned int i;
+
+ for (i = 0; i < t->num_backtrace_strings; i++)
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Task %p trace %d: %s\n",
+ t,
+ i,
+ t->backtrace_strings[i]);
+#endif
+ return t;