2 This file is part of GNUnet
3 (C) 2009 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file util/scheduler/scheduler.c
23 * @brief schedule computations using continuation passing style
24 * @author Christian Grothoff
27 #include "gnunet_common.h"
28 #include "gnunet_scheduler_lib.h"
29 #include "gnunet_signal_lib.h"
30 #include "gnunet_time_lib.h"
33 * Linked list of pending tasks.
38 * This is a linked list.
43 * Function to run when ready.
45 GNUNET_SCHEDULER_Task callback;
48 * Closure for the callback.
53 * Set of file descriptors this task is waiting
54 * for for reading. Once ready, this is updated
55 * to reflect the set of file descriptors ready
58 struct GNUNET_NETWORK_FDSet *read_set;
61 * Set of file descriptors this task is waiting
62 * for for writing. Once ready, this is updated
63 * to reflect the set of file descriptors ready
66 struct GNUNET_NETWORK_FDSet *write_set;
69 * Unique task identifier.
71 GNUNET_SCHEDULER_TaskIdentifier id;
74 * Identifier of a prerequisite task.
76 GNUNET_SCHEDULER_TaskIdentifier prereq_id;
79 * Absolute timeout value for the task, or
80 * GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout".
82 struct GNUNET_TIME_Absolute timeout;
85 * Why is the task ready? Set after task is added to ready queue.
86 * Initially set to zero. All reasons that have already been
87 * satisfied (i.e. read or write ready) will be set over time.
89 enum GNUNET_SCHEDULER_Reason reason;
94 enum GNUNET_SCHEDULER_Priority priority;
97 * Should this task be run on shutdown?
105 * Handle for the scheduling service.
107 struct GNUNET_SCHEDULER_Handle
111 * List of tasks waiting for an event.
113 struct Task *pending;
116 * List of tasks ready to run right now,
117 * grouped by importance.
119 struct Task *ready[GNUNET_SCHEDULER_PRIORITY_COUNT];
122 * Identity of the last task queued. Incremented for each task to
123 * generate a unique task ID (it is virtually impossible to start
124 * more than 2^64 tasks during the lifetime of a process).
126 GNUNET_SCHEDULER_TaskIdentifier last_id;
129 * Highest number so that all tasks with smaller identifiers
130 * have already completed. Also the lowest number of a task
131 * still waiting to be executed.
133 GNUNET_SCHEDULER_TaskIdentifier lowest_pending_id;
136 * GNUNET_NO if we are running normally,
137 * GNUNET_YES if we are in shutdown mode.
142 * Number of tasks on the ready list.
144 unsigned int ready_count;
147 * Priority of the task running right now. Only
148 * valid while a task is running.
150 enum GNUNET_SCHEDULER_Priority current_priority;
156 * Check that the given priority is legal (and return it).
158 static enum GNUNET_SCHEDULER_Priority
159 check_priority (enum GNUNET_SCHEDULER_Priority p)
161 if ((p >= 0) && (p < GNUNET_SCHEDULER_PRIORITY_COUNT))
164 return 0; /* make compiler happy */
169 * Is a task with this identifier still pending? Also updates
170 * "lowest_pending_id" as a side-effect (for faster checks in the
171 * future), but only if the return value is "GNUNET_NO" (and
172 * the "lowest_pending_id" check failed).
174 * @return GNUNET_YES if so, GNUNET_NO if not
177 is_pending (struct GNUNET_SCHEDULER_Handle *sched,
178 GNUNET_SCHEDULER_TaskIdentifier id)
181 enum GNUNET_SCHEDULER_Priority p;
182 GNUNET_SCHEDULER_TaskIdentifier min;
184 if (id < sched->lowest_pending_id)
186 min = -1; /* maximum value */
187 pos = sched->pending;
196 for (p = 0; p < GNUNET_SCHEDULER_PRIORITY_COUNT; p++)
198 pos = sched->ready[p];
208 sched->lowest_pending_id = min;
214 * Update all sets and timeout for select.
217 update_sets (struct GNUNET_SCHEDULER_Handle *sched,
218 struct GNUNET_NETWORK_FDSet * rs, struct GNUNET_NETWORK_FDSet * ws, struct GNUNET_TIME_Relative *timeout)
222 pos = sched->pending;
226 if ((pos->prereq_id != GNUNET_SCHEDULER_NO_TASK) &&
227 (GNUNET_YES == is_pending (sched, pos->prereq_id)))
233 if (pos->timeout.value != GNUNET_TIME_UNIT_FOREVER_ABS.value)
235 struct GNUNET_TIME_Relative to;
237 to = GNUNET_TIME_absolute_get_remaining (pos->timeout);
238 if (timeout->value > to.value)
242 GNUNET_NETWORK_fdset_add (rs, pos->read_set);
243 GNUNET_NETWORK_fdset_add (ws, pos->write_set);
250 * Check if the ready set overlaps with the set we want to have ready.
251 * If so, update the want set (set all FDs that are ready). If not,
254 * @param maxfd highest FD that needs to be checked.
255 * @return GNUNET_YES if there was some overlap
258 set_overlaps (const struct GNUNET_NETWORK_FDSet * ready, struct GNUNET_NETWORK_FDSet * want)
260 if (GNUNET_NETWORK_fdset_overlap (ready, want))
262 /* copy all over (yes, there maybe unrelated bits,
263 but this should not hurt well-written clients) */
264 GNUNET_NETWORK_fdset_copy (want, ready);
272 * Check if the given task is eligible to run now.
273 * Also set the reason why it is eligible.
275 * @return GNUNET_YES if we can run it, GNUNET_NO if not.
278 is_ready (struct GNUNET_SCHEDULER_Handle *sched,
280 struct GNUNET_TIME_Absolute now,
281 const struct GNUNET_NETWORK_FDSet * rs, const struct GNUNET_NETWORK_FDSet * ws)
283 if ((GNUNET_NO == task->run_on_shutdown) && (GNUNET_YES == sched->shutdown))
285 if ((GNUNET_YES == task->run_on_shutdown) &&
286 (GNUNET_YES == sched->shutdown))
287 task->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN;
288 if (now.value >= task->timeout.value)
289 task->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
290 if ((0 == (task->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
291 (rs != NULL) && (set_overlaps (rs, task->read_set)))
292 task->reason |= GNUNET_SCHEDULER_REASON_READ_READY;
293 if ((0 == (task->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
294 (ws != NULL) && (set_overlaps (ws, task->write_set)))
295 task->reason |= GNUNET_SCHEDULER_REASON_WRITE_READY;
296 if (task->reason == 0)
297 return GNUNET_NO; /* not ready */
298 if (task->prereq_id != GNUNET_SCHEDULER_NO_TASK)
300 if (GNUNET_YES == is_pending (sched, task->prereq_id))
301 return GNUNET_NO; /* prereq waiting */
302 task->reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;
309 * Put a task that is ready for execution into the ready queue.
312 queue_ready_task (struct GNUNET_SCHEDULER_Handle *handle, struct Task *task)
314 task->next = handle->ready[check_priority (task->priority)];
315 handle->ready[check_priority (task->priority)] = task;
316 handle->ready_count++;
321 * Check which tasks are ready and move them
322 * to the respective ready queue.
325 check_ready (struct GNUNET_SCHEDULER_Handle *handle,
326 const struct GNUNET_NETWORK_FDSet * rs, const struct GNUNET_NETWORK_FDSet * ws)
331 struct GNUNET_TIME_Absolute now;
333 now = GNUNET_TIME_absolute_get ();
335 pos = handle->pending;
339 if (GNUNET_YES == is_ready (handle, pos, now, rs, ws))
342 handle->pending = next;
345 queue_ready_task (handle, pos);
358 static void destroy_task (struct Task *t)
361 GNUNET_NETWORK_fdset_destroy (t->read_set);
363 GNUNET_NETWORK_fdset_destroy (t->write_set);
369 * Run at least one task in the highest-priority queue that is not
370 * empty. Keep running tasks until we are either no longer running
371 * "URGENT" tasks or until we have at least one "pending" task (which
372 * may become ready, hence we should select on it). Naturally, if
373 * there are no more ready tasks, we also return.
376 run_ready (struct GNUNET_SCHEDULER_Handle *sched)
378 enum GNUNET_SCHEDULER_Priority p;
380 struct GNUNET_SCHEDULER_TaskContext tc;
384 if (sched->ready_count == 0)
386 GNUNET_assert (sched->ready[GNUNET_SCHEDULER_PRIORITY_KEEP] == NULL);
387 /* yes, p>0 is correct, 0 is "KEEP" which should
388 always be an empty queue (see assertion)! */
389 for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--)
391 pos = sched->ready[p];
395 GNUNET_assert (pos != NULL); /* ready_count wrong? */
396 sched->ready[p] = pos->next;
397 sched->ready_count--;
398 sched->current_priority = p;
399 GNUNET_assert (pos->priority == p);
401 tc.reason = pos->reason;
402 tc.read_ready = pos->read_set;
403 tc.write_ready = pos->write_set;
404 pos->callback (pos->callback_cls, &tc);
407 while ((sched->pending == NULL) || (p == GNUNET_SCHEDULER_PRIORITY_URGENT));
412 * Have we (ever) received a SIGINT/TERM/QUIT/HUP?
414 static volatile int sig_shutdown;
418 * Signal handler called for signals that should cause us to shutdown.
421 sighandler_shutdown ()
428 * Initialize a scheduler using this thread. This function will
429 * return when either a shutdown was initiated (via signal) and all
430 * tasks marked to "run_on_shutdown" have been completed or when all
431 * tasks in general have been completed.
433 * @param task task to run immediately
434 * @param cls closure of task
437 GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *cls)
439 struct GNUNET_SCHEDULER_Handle sched;
440 struct GNUNET_NETWORK_FDSet *rs;
441 struct GNUNET_NETWORK_FDSet *ws;
442 struct GNUNET_TIME_Relative timeout;
444 struct GNUNET_SIGNAL_Context *shc_int;
445 struct GNUNET_SIGNAL_Context *shc_term;
446 struct GNUNET_SIGNAL_Context *shc_quit;
447 struct GNUNET_SIGNAL_Context *shc_hup;
451 rs = GNUNET_NETWORK_fdset_create ();
452 ws = GNUNET_NETWORK_fdset_create ();
454 shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown);
455 shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown);
456 shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, &sighandler_shutdown);
457 shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, &sighandler_shutdown);
459 memset (&sched, 0, sizeof (sched));
460 sched.current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
461 GNUNET_SCHEDULER_add_continuation (&sched,
464 cls, GNUNET_SCHEDULER_REASON_STARTUP);
465 while ((GNUNET_NO == sched.shutdown) &&
467 ((sched.pending != NULL) || (sched.ready_count > 0)))
469 GNUNET_NETWORK_fdset_zero (rs);
470 GNUNET_NETWORK_fdset_zero (ws);
471 timeout = GNUNET_TIME_relative_get_forever();
472 if (sched.ready_count > 0)
474 /* no blocking, more work already ready! */
475 timeout = GNUNET_TIME_relative_get_zero();
477 update_sets (&sched, rs, ws, &timeout);
478 ret = GNUNET_NETWORK_socket_select (rs, ws, NULL, GNUNET_TIME_relative_get_zero());
479 if (ret == GNUNET_SYSERR)
483 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");
486 check_ready (&sched, rs, ws);
490 sched.shutdown = GNUNET_YES;
491 GNUNET_SIGNAL_handler_uninstall (shc_int);
492 GNUNET_SIGNAL_handler_uninstall (shc_term);
493 GNUNET_SIGNAL_handler_uninstall (shc_quit);
494 GNUNET_SIGNAL_handler_uninstall (shc_hup);
498 check_ready (&sched, NULL, NULL);
500 while (sched.ready_count > 0);
501 while (NULL != (tpos = sched.pending))
503 sched.pending = tpos->next;
506 GNUNET_NETWORK_fdset_destroy (rs);
507 GNUNET_NETWORK_fdset_destroy (ws);
512 * Request the shutdown of a scheduler. This function can be used to
513 * stop a scheduling thread when created with the
514 * "GNUNET_SCHEDULER_init_thread" function or from within the signal
515 * handler for signals causing shutdowns.
518 GNUNET_SCHEDULER_shutdown (struct GNUNET_SCHEDULER_Handle *sched)
520 sched->shutdown = GNUNET_YES;
525 * Get information about the current load of this scheduler. Use this
526 * function to determine if an elective task should be added or simply
527 * dropped (if the decision should be made based on the number of
528 * tasks ready to run).
530 * @param sched scheduler to query
531 * @return number of tasks pending right now
534 GNUNET_SCHEDULER_get_load (struct GNUNET_SCHEDULER_Handle *sched,
535 enum GNUNET_SCHEDULER_Priority p)
540 if (p == GNUNET_SCHEDULER_PRIORITY_COUNT)
541 return sched->ready_count;
542 if (p == GNUNET_SCHEDULER_PRIORITY_KEEP)
543 p = sched->current_priority;
545 pos = sched->ready[p];
556 * Cancel the task with the specified identifier.
557 * The task must not yet have run.
559 * @param sched scheduler to use
560 * @param task id of the task to cancel
563 GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Handle *sched,
564 GNUNET_SCHEDULER_TaskIdentifier task)
568 enum GNUNET_SCHEDULER_Priority p;
584 GNUNET_assert (p < GNUNET_SCHEDULER_PRIORITY_COUNT);
591 sched->ready_count--;
601 sched->pending = t->next;
603 sched->ready[p] = t->next;
606 prev->next = t->next;
607 ret = t->callback_cls;
614 * Continue the current execution with the given function. This is
615 * similar to the other "add" functions except that there is no delay
616 * and the reason code can be specified.
618 * @param sched scheduler to use
619 * @param main main function of the task
620 * @param cls closure of task
621 * @param reason reason for task invocation
624 GNUNET_SCHEDULER_add_continuation (struct GNUNET_SCHEDULER_Handle *sched,
626 GNUNET_SCHEDULER_Task main,
628 enum GNUNET_SCHEDULER_Reason reason)
632 task = GNUNET_malloc (sizeof (struct Task));
633 task->callback = main;
634 task->callback_cls = cls;
635 task->id = ++sched->last_id;
636 task->reason = reason;
637 task->priority = sched->current_priority;
638 task->run_on_shutdown = run_on_shutdown;
639 queue_ready_task (sched, task);
644 * Schedule a new task to be run after the specified
645 * prerequisite task has completed.
647 * @param sched scheduler to use
648 * @param run_on_shutdown run on shutdown?
649 * @param prio how important is this task?
650 * @param prerequisite_task run this task after the task with the given
651 * task identifier completes (and any of our other
652 * conditions, such as delay, read or write-readyness
653 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
654 * on completion of other tasks.
655 * @param main main function of the task
656 * @param cls closure of task
657 * @return unique task identifier for the job
658 * only valid until "main" is started!
660 GNUNET_SCHEDULER_TaskIdentifier
661 GNUNET_SCHEDULER_add_after (struct GNUNET_SCHEDULER_Handle *sched,
663 enum GNUNET_SCHEDULER_Priority prio,
664 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
665 GNUNET_SCHEDULER_Task main, void *cls)
667 return GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
669 GNUNET_TIME_UNIT_ZERO,
670 NULL, NULL, main, cls);
675 * Schedule a new task to be run with a specified delay. The task
676 * will be scheduled for execution once the delay has expired and the
677 * prerequisite task has completed.
679 * @param sched scheduler to use
680 * @param run_on_shutdown run on shutdown? You can use this
681 * argument to run a function only during shutdown
682 * by setting delay to -1. Set this
683 * argument to GNUNET_NO to skip this task if
684 * the user requested process termination.
685 * @param prio how important is this task?
686 * @param prerequisite_task run this task after the task with the given
687 * task identifier completes (and any of our other
688 * conditions, such as delay, read or write-readyness
689 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
690 * on completion of other tasks.
691 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
692 * @param main main function of the task
693 * @param cls closure of task
694 * @return unique task identifier for the job
695 * only valid until "main" is started!
697 GNUNET_SCHEDULER_TaskIdentifier
698 GNUNET_SCHEDULER_add_delayed (struct GNUNET_SCHEDULER_Handle * sched,
700 enum GNUNET_SCHEDULER_Priority prio,
701 GNUNET_SCHEDULER_TaskIdentifier
703 struct GNUNET_TIME_Relative delay,
704 GNUNET_SCHEDULER_Task main, void *cls)
706 return GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
707 prerequisite_task, delay,
708 NULL, NULL, main, cls);
713 * Schedule a new task to be run with a specified delay or when the
714 * specified file descriptor is ready for reading. The delay can be
715 * used as a timeout on the socket being ready. The task will be
716 * scheduled for execution once either the delay has expired or the
717 * socket operation is ready.
719 * @param sched scheduler to use
720 * @param run_on_shutdown run on shutdown? Set this
721 * argument to GNUNET_NO to skip this task if
722 * the user requested process termination.
723 * @param prio how important is this task?
724 * @param prerequisite_task run this task after the task with the given
725 * task identifier completes (and any of our other
726 * conditions, such as delay, read or write-readyness
727 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
728 * on completion of other tasks.
729 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
730 * @param rfd read file-descriptor
731 * @param main main function of the task
732 * @param cls closure of task
733 * @return unique task identifier for the job
734 * only valid until "main" is started!
736 GNUNET_SCHEDULER_TaskIdentifier
737 GNUNET_SCHEDULER_add_read_net (struct GNUNET_SCHEDULER_Handle * sched,
739 enum GNUNET_SCHEDULER_Priority prio,
740 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
741 struct GNUNET_TIME_Relative delay,
742 struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_Task main, void *cls)
744 struct GNUNET_NETWORK_FDSet *rs;
745 GNUNET_SCHEDULER_TaskIdentifier ret;
747 GNUNET_assert (rfd != NULL);
748 rs = GNUNET_NETWORK_fdset_create ();
749 GNUNET_NETWORK_fdset_set (rs, rfd);
750 ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
751 prerequisite_task, delay,
752 rs, NULL, main, cls);
753 GNUNET_NETWORK_fdset_destroy (rs);
759 * Schedule a new task to be run with a specified delay or when the
760 * specified file descriptor is ready for writing. The delay can be
761 * used as a timeout on the socket being ready. The task will be
762 * scheduled for execution once either the delay has expired or the
763 * socket operation is ready.
765 * @param sched scheduler to use
766 * @param run_on_shutdown run on shutdown? Set this
767 * argument to GNUNET_NO to skip this task if
768 * the user requested process termination.
769 * @param prio how important is this task?
770 * @param prerequisite_task run this task after the task with the given
771 * task identifier completes (and any of our other
772 * conditions, such as delay, read or write-readyness
773 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
774 * on completion of other tasks.
775 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
776 * @param wfd write file-descriptor
777 * @param main main function of the task
778 * @param cls closure of task
779 * @return unique task identifier for the job
780 * only valid until "main" is started!
782 GNUNET_SCHEDULER_TaskIdentifier
783 GNUNET_SCHEDULER_add_write_net (struct GNUNET_SCHEDULER_Handle * sched,
785 enum GNUNET_SCHEDULER_Priority prio,
786 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
787 struct GNUNET_TIME_Relative delay,
788 struct GNUNET_NETWORK_Handle *wfd, GNUNET_SCHEDULER_Task main, void *cls)
790 struct GNUNET_NETWORK_FDSet *ws;
791 GNUNET_SCHEDULER_TaskIdentifier ret;
793 GNUNET_assert (wfd != NULL);
794 ws = GNUNET_NETWORK_fdset_create ();
795 GNUNET_NETWORK_fdset_set (ws, wfd);
796 ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
797 prerequisite_task, delay,
798 NULL, ws, main, cls);
799 GNUNET_NETWORK_fdset_destroy (ws);
805 * Schedule a new task to be run with a specified delay or when any of
806 * the specified file descriptor sets is ready. The delay can be used
807 * as a timeout on the socket(s) being ready. The task will be
808 * scheduled for execution once either the delay has expired or any of
809 * the socket operations is ready. This is the most general
810 * function of the "add" family. Note that the "prerequisite_task"
811 * must be satisfied in addition to any of the other conditions. In
812 * other words, the task will be started when
818 * || (shutdown-active && run-on-shutdown) )
821 * @param sched scheduler to use
822 * @param run_on_shutdown run on shutdown? Set this
823 * argument to GNUNET_NO to skip this task if
824 * the user requested process termination.
825 * @param prio how important is this task?
826 * @param prerequisite_task run this task after the task with the given
827 * task identifier completes (and any of our other
828 * conditions, such as delay, read or write-readyness
829 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
830 * on completion of other tasks.
831 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
832 * @param rs set of file descriptors we want to read (can be NULL)
833 * @param ws set of file descriptors we want to write (can be NULL)
834 * @param main main function of the task
835 * @param cls closure of task
836 * @return unique task identifier for the job
837 * only valid until "main" is started!
839 GNUNET_SCHEDULER_TaskIdentifier
840 GNUNET_SCHEDULER_add_select (struct GNUNET_SCHEDULER_Handle * sched,
842 enum GNUNET_SCHEDULER_Priority prio,
843 GNUNET_SCHEDULER_TaskIdentifier
845 struct GNUNET_TIME_Relative delay,
846 const struct GNUNET_NETWORK_FDSet * rs, const struct GNUNET_NETWORK_FDSet * ws,
847 GNUNET_SCHEDULER_Task main, void *cls)
851 task = GNUNET_malloc (sizeof (struct Task));
852 task->callback = main;
853 task->callback_cls = cls;
854 task->read_set = GNUNET_NETWORK_fdset_create ();
856 GNUNET_NETWORK_fdset_copy (task->read_set, rs);
857 task->write_set = GNUNET_NETWORK_fdset_create ();
859 GNUNET_NETWORK_fdset_copy (task->write_set, ws);
860 task->id = ++sched->last_id;
861 task->prereq_id = prerequisite_task;
862 task->timeout = GNUNET_TIME_relative_to_absolute (delay);
864 check_priority ((prio ==
865 GNUNET_SCHEDULER_PRIORITY_KEEP) ? sched->current_priority
867 task->run_on_shutdown = run_on_shutdown;
868 task->next = sched->pending;
869 sched->pending = task;
874 * Schedule a new task to be run with a specified delay or when the
875 * specified file descriptor is ready for reading. The delay can be
876 * used as a timeout on the socket being ready. The task will be
877 * scheduled for execution once either the delay has expired or the
878 * socket operation is ready.
880 * @param sched scheduler to use
881 * @param run_on_shutdown run on shutdown? Set this
882 * argument to GNUNET_NO to skip this task if
883 * the user requested process termination.
884 * @param prio how important is this task?
885 * @param prerequisite_task run this task after the task with the given
886 * task identifier completes (and any of our other
887 * conditions, such as delay, read or write-readyness
888 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
889 * on completion of other tasks.
890 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
891 * @param rfd read file-descriptor
892 * @param main main function of the task
893 * @param cls closure of task
894 * @return unique task identifier for the job
895 * only valid until "main" is started!
897 GNUNET_SCHEDULER_TaskIdentifier
898 GNUNET_SCHEDULER_add_read_file (struct GNUNET_SCHEDULER_Handle * sched,
900 enum GNUNET_SCHEDULER_Priority prio,
901 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
902 struct GNUNET_TIME_Relative delay,
903 struct GNUNET_DISK_FileHandle *rfd, GNUNET_SCHEDULER_Task main, void *cls)
905 struct GNUNET_NETWORK_FDSet *rs;
906 GNUNET_SCHEDULER_TaskIdentifier ret;
908 GNUNET_assert (rfd != NULL);
909 rs = GNUNET_NETWORK_fdset_create ();
910 GNUNET_NETWORK_fdset_handle_set (rs, rfd);
911 ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
912 prerequisite_task, delay,
913 rs, NULL, main, cls);
914 GNUNET_NETWORK_fdset_destroy (rs);
920 * Schedule a new task to be run with a specified delay or when the
921 * specified file descriptor is ready for writing. The delay can be
922 * used as a timeout on the socket being ready. The task will be
923 * scheduled for execution once either the delay has expired or the
924 * socket operation is ready.
926 * @param sched scheduler to use
927 * @param run_on_shutdown run on shutdown? Set this
928 * argument to GNUNET_NO to skip this task if
929 * the user requested process termination.
930 * @param prio how important is this task?
931 * @param prerequisite_task run this task after the task with the given
932 * task identifier completes (and any of our other
933 * conditions, such as delay, read or write-readyness
934 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
935 * on completion of other tasks.
936 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
937 * @param wfd write file-descriptor
938 * @param main main function of the task
939 * @param cls closure of task
940 * @return unique task identifier for the job
941 * only valid until "main" is started!
943 GNUNET_SCHEDULER_TaskIdentifier
944 GNUNET_SCHEDULER_add_write_file (struct GNUNET_SCHEDULER_Handle * sched,
946 enum GNUNET_SCHEDULER_Priority prio,
947 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
948 struct GNUNET_TIME_Relative delay,
949 struct GNUNET_DISK_FileHandle *wfd, GNUNET_SCHEDULER_Task main, void *cls)
951 struct GNUNET_NETWORK_FDSet *ws;
952 GNUNET_SCHEDULER_TaskIdentifier ret;
954 GNUNET_assert (wfd != NULL);
955 ws = GNUNET_NETWORK_fdset_create ();
956 GNUNET_NETWORK_fdset_handle_set (ws, wfd);
957 ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
958 prerequisite_task, delay,
959 NULL, ws, main, cls);
960 GNUNET_NETWORK_fdset_destroy (ws);
965 /* end of scheduler.c */