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.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 * @param p priority value to check
159 * @return p on success, 0 on error
161 static enum GNUNET_SCHEDULER_Priority
162 check_priority (enum GNUNET_SCHEDULER_Priority p)
164 if ((p >= 0) && (p < GNUNET_SCHEDULER_PRIORITY_COUNT))
167 return 0; /* make compiler happy */
172 * Is a task with this identifier still pending? Also updates
173 * "lowest_pending_id" as a side-effect (for faster checks in the
174 * future), but only if the return value is "GNUNET_NO" (and
175 * the "lowest_pending_id" check failed).
177 * @param sched the scheduler
178 * @param id which task are we checking for
179 * @return GNUNET_YES if so, GNUNET_NO if not
182 is_pending (struct GNUNET_SCHEDULER_Handle *sched,
183 GNUNET_SCHEDULER_TaskIdentifier id)
186 enum GNUNET_SCHEDULER_Priority p;
187 GNUNET_SCHEDULER_TaskIdentifier min;
189 if (id < sched->lowest_pending_id)
191 min = -1; /* maximum value */
192 pos = sched->pending;
201 for (p = 0; p < GNUNET_SCHEDULER_PRIORITY_COUNT; p++)
203 pos = sched->ready[p];
213 sched->lowest_pending_id = min;
219 * Update all sets and timeout for select.
221 * @param sched the scheduler
222 * @param rs read-set, set to all FDs we would like to read (updated)
223 * @param ws write-set, set to all FDs we would like to write (updated)
224 * @param timeout next timeout (updated)
227 update_sets (struct GNUNET_SCHEDULER_Handle *sched,
228 struct GNUNET_NETWORK_FDSet * rs,
229 struct GNUNET_NETWORK_FDSet * ws,
230 struct GNUNET_TIME_Relative *timeout)
234 pos = sched->pending;
238 if ((pos->prereq_id != GNUNET_SCHEDULER_NO_TASK) &&
239 (GNUNET_YES == is_pending (sched, pos->prereq_id)))
245 if (pos->timeout.value != GNUNET_TIME_UNIT_FOREVER_ABS.value)
247 struct GNUNET_TIME_Relative to;
249 to = GNUNET_TIME_absolute_get_remaining (pos->timeout);
250 if (timeout->value > to.value)
254 GNUNET_NETWORK_fdset_add (rs, pos->read_set);
255 GNUNET_NETWORK_fdset_add (ws, pos->write_set);
262 * Check if the ready set overlaps with the set we want to have ready.
263 * If so, update the want set (set all FDs that are ready). If not,
266 * @param ready set that is ready
267 * @param want set that we want to be ready
268 * @return GNUNET_YES if there was some overlap
271 set_overlaps (const struct GNUNET_NETWORK_FDSet * ready,
272 struct GNUNET_NETWORK_FDSet * want)
274 if (GNUNET_NETWORK_fdset_overlap (ready, want))
276 /* copy all over (yes, there maybe unrelated bits,
277 but this should not hurt well-written clients) */
278 GNUNET_NETWORK_fdset_copy (want, ready);
286 * Check if the given task is eligible to run now.
287 * Also set the reason why it is eligible.
289 * @param sched the scheduler
290 * @param task task to check if it is ready
291 * @param now the current time
292 * @param rs set of FDs ready for reading
293 * @param ws set of FDs ready for writing
294 * @return GNUNET_YES if we can run it, GNUNET_NO if not.
297 is_ready (struct GNUNET_SCHEDULER_Handle *sched,
299 struct GNUNET_TIME_Absolute now,
300 const struct GNUNET_NETWORK_FDSet *rs,
301 const struct GNUNET_NETWORK_FDSet * ws)
303 if ((GNUNET_NO == task->run_on_shutdown) && (GNUNET_YES == sched->shutdown))
305 if ((GNUNET_YES == task->run_on_shutdown) &&
306 (GNUNET_YES == sched->shutdown))
307 task->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN;
308 if (now.value >= task->timeout.value)
309 task->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
310 if ((0 == (task->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
311 (rs != NULL) && (set_overlaps (rs, task->read_set)))
312 task->reason |= GNUNET_SCHEDULER_REASON_READ_READY;
313 if ((0 == (task->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
314 (ws != NULL) && (set_overlaps (ws, task->write_set)))
315 task->reason |= GNUNET_SCHEDULER_REASON_WRITE_READY;
316 if (task->reason == 0)
317 return GNUNET_NO; /* not ready */
318 if (task->prereq_id != GNUNET_SCHEDULER_NO_TASK)
320 if (GNUNET_YES == is_pending (sched, task->prereq_id))
321 return GNUNET_NO; /* prereq waiting */
322 task->reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;
329 * Put a task that is ready for execution into the ready queue.
331 * @param handle the scheduler
332 * @param task task ready for execution
335 queue_ready_task (struct GNUNET_SCHEDULER_Handle *handle,
338 task->next = handle->ready[check_priority (task->priority)];
339 handle->ready[check_priority (task->priority)] = task;
340 handle->ready_count++;
345 * Check which tasks are ready and move them
346 * to the respective ready queue.
348 * @param handle the scheduler
349 * @param rs FDs ready for reading
350 * @param ws FDs ready for writing
353 check_ready (struct GNUNET_SCHEDULER_Handle *handle,
354 const struct GNUNET_NETWORK_FDSet * rs,
355 const struct GNUNET_NETWORK_FDSet * ws)
360 struct GNUNET_TIME_Absolute now;
362 now = GNUNET_TIME_absolute_get ();
364 pos = handle->pending;
368 if (GNUNET_YES == is_ready (handle, pos, now, rs, ws))
371 handle->pending = next;
374 queue_ready_task (handle, pos);
385 * Destroy a task (release associated resources)
387 * @param t task to destroy
389 static void destroy_task (struct Task *t)
392 GNUNET_NETWORK_fdset_destroy (t->read_set);
394 GNUNET_NETWORK_fdset_destroy (t->write_set);
400 * Run at least one task in the highest-priority queue that is not
401 * empty. Keep running tasks until we are either no longer running
402 * "URGENT" tasks or until we have at least one "pending" task (which
403 * may become ready, hence we should select on it). Naturally, if
404 * there are no more ready tasks, we also return.
406 * @param sched the scheduler
409 run_ready (struct GNUNET_SCHEDULER_Handle *sched)
411 enum GNUNET_SCHEDULER_Priority p;
413 struct GNUNET_SCHEDULER_TaskContext tc;
417 if (sched->ready_count == 0)
419 GNUNET_assert (sched->ready[GNUNET_SCHEDULER_PRIORITY_KEEP] == NULL);
420 /* yes, p>0 is correct, 0 is "KEEP" which should
421 always be an empty queue (see assertion)! */
422 for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--)
424 pos = sched->ready[p];
428 GNUNET_assert (pos != NULL); /* ready_count wrong? */
429 sched->ready[p] = pos->next;
430 sched->ready_count--;
431 sched->current_priority = p;
432 GNUNET_assert (pos->priority == p);
434 tc.reason = pos->reason;
435 tc.read_ready = pos->read_set;
436 tc.write_ready = pos->write_set;
437 pos->callback (pos->callback_cls, &tc);
440 while ((sched->pending == NULL) || (p == GNUNET_SCHEDULER_PRIORITY_URGENT));
445 * Have we (ever) received a SIGINT/TERM/QUIT/HUP?
447 static volatile int sig_shutdown;
451 * Signal handler called for signals that should cause us to shutdown.
454 sighandler_shutdown ()
461 * Initialize a scheduler using this thread. This function will
462 * return when either a shutdown was initiated (via signal) and all
463 * tasks marked to "run_on_shutdown" have been completed or when all
464 * tasks in general have been completed.
466 * @param task task to run immediately
467 * @param cls closure of task
470 GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *cls)
472 struct GNUNET_SCHEDULER_Handle sched;
473 struct GNUNET_NETWORK_FDSet *rs;
474 struct GNUNET_NETWORK_FDSet *ws;
475 struct GNUNET_TIME_Relative timeout;
477 struct GNUNET_SIGNAL_Context *shc_int;
478 struct GNUNET_SIGNAL_Context *shc_term;
479 struct GNUNET_SIGNAL_Context *shc_quit;
480 struct GNUNET_SIGNAL_Context *shc_hup;
484 rs = GNUNET_NETWORK_fdset_create ();
485 ws = GNUNET_NETWORK_fdset_create ();
487 shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown);
488 shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown);
489 shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, &sighandler_shutdown);
490 shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, &sighandler_shutdown);
492 memset (&sched, 0, sizeof (sched));
493 sched.current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
494 GNUNET_SCHEDULER_add_continuation (&sched,
497 cls, GNUNET_SCHEDULER_REASON_STARTUP);
498 while ((GNUNET_NO == sched.shutdown) &&
500 ((sched.pending != NULL) || (sched.ready_count > 0)))
502 GNUNET_NETWORK_fdset_zero (rs);
503 GNUNET_NETWORK_fdset_zero (ws);
504 timeout = GNUNET_TIME_relative_get_forever();
505 if (sched.ready_count > 0)
507 /* no blocking, more work already ready! */
508 timeout = GNUNET_TIME_relative_get_zero();
510 update_sets (&sched, rs, ws, &timeout);
511 ret = GNUNET_NETWORK_socket_select (rs, ws, NULL, GNUNET_TIME_relative_get_zero());
512 if (ret == GNUNET_SYSERR)
516 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");
519 check_ready (&sched, rs, ws);
523 sched.shutdown = GNUNET_YES;
524 GNUNET_SIGNAL_handler_uninstall (shc_int);
525 GNUNET_SIGNAL_handler_uninstall (shc_term);
526 GNUNET_SIGNAL_handler_uninstall (shc_quit);
527 GNUNET_SIGNAL_handler_uninstall (shc_hup);
531 check_ready (&sched, NULL, NULL);
533 while (sched.ready_count > 0);
534 while (NULL != (tpos = sched.pending))
536 sched.pending = tpos->next;
539 GNUNET_NETWORK_fdset_destroy (rs);
540 GNUNET_NETWORK_fdset_destroy (ws);
545 * Request the shutdown of a scheduler. This function can be used to
546 * stop a scheduling thread when created with the
547 * "GNUNET_SCHEDULER_init_thread" function or from within the signal
548 * handler for signals causing shutdowns.
550 * @param sched the scheduler
553 GNUNET_SCHEDULER_shutdown (struct GNUNET_SCHEDULER_Handle *sched)
555 sched->shutdown = GNUNET_YES;
560 * Get information about the current load of this scheduler. Use this
561 * function to determine if an elective task should be added or simply
562 * dropped (if the decision should be made based on the number of
563 * tasks ready to run).
565 * @param sched scheduler to query
566 * @param p priority level to look at
567 * @return number of tasks pending right now
570 GNUNET_SCHEDULER_get_load (struct GNUNET_SCHEDULER_Handle *sched,
571 enum GNUNET_SCHEDULER_Priority p)
576 if (p == GNUNET_SCHEDULER_PRIORITY_COUNT)
577 return sched->ready_count;
578 if (p == GNUNET_SCHEDULER_PRIORITY_KEEP)
579 p = sched->current_priority;
581 pos = sched->ready[p];
592 * Cancel the task with the specified identifier.
593 * The task must not yet have run.
595 * @param sched scheduler to use
596 * @param task id of the task to cancel
597 * @return original closure of the task
600 GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Handle *sched,
601 GNUNET_SCHEDULER_TaskIdentifier task)
605 enum GNUNET_SCHEDULER_Priority p;
621 GNUNET_assert (p < GNUNET_SCHEDULER_PRIORITY_COUNT);
628 sched->ready_count--;
638 sched->pending = t->next;
640 sched->ready[p] = t->next;
643 prev->next = t->next;
644 ret = t->callback_cls;
651 * Continue the current execution with the given function. This is
652 * similar to the other "add" functions except that there is no delay
653 * and the reason code can be specified.
655 * @param sched scheduler to use
656 * @param run_on_shutdown should this task be run if we are shutting down?
657 * @param main main function of the task
658 * @param cls closure for 'main'
659 * @param reason reason for task invocation
662 GNUNET_SCHEDULER_add_continuation (struct GNUNET_SCHEDULER_Handle *sched,
664 GNUNET_SCHEDULER_Task main,
666 enum GNUNET_SCHEDULER_Reason reason)
670 task = GNUNET_malloc (sizeof (struct Task));
671 task->callback = main;
672 task->callback_cls = cls;
673 task->id = ++sched->last_id;
674 task->reason = reason;
675 task->priority = sched->current_priority;
676 task->run_on_shutdown = run_on_shutdown;
677 queue_ready_task (sched, task);
682 * Schedule a new task to be run after the specified
683 * prerequisite task has completed.
685 * @param sched scheduler to use
686 * @param run_on_shutdown run on shutdown?
687 * @param prio how important is this task?
688 * @param prerequisite_task run this task after the task with the given
689 * task identifier completes (and any of our other
690 * conditions, such as delay, read or write-readyness
691 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
692 * on completion of other tasks.
693 * @param main main function of the task
694 * @param cls closure for 'main'
695 * @return unique task identifier for the job
696 * only valid until "main" is started!
698 GNUNET_SCHEDULER_TaskIdentifier
699 GNUNET_SCHEDULER_add_after (struct GNUNET_SCHEDULER_Handle *sched,
701 enum GNUNET_SCHEDULER_Priority prio,
702 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
703 GNUNET_SCHEDULER_Task main, void *cls)
705 return GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
707 GNUNET_TIME_UNIT_ZERO,
708 NULL, NULL, main, cls);
713 * Schedule a new task to be run with a specified delay. The task
714 * will be scheduled for execution once the delay has expired and the
715 * prerequisite task has completed.
717 * @param sched scheduler to use
718 * @param run_on_shutdown run on shutdown? You can use this
719 * argument to run a function only during shutdown
720 * by setting delay to -1. 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 main main function of the task
731 * @param cls closure of task
732 * @return unique task identifier for the job
733 * only valid until "main" is started!
735 GNUNET_SCHEDULER_TaskIdentifier
736 GNUNET_SCHEDULER_add_delayed (struct GNUNET_SCHEDULER_Handle * sched,
738 enum GNUNET_SCHEDULER_Priority prio,
739 GNUNET_SCHEDULER_TaskIdentifier
741 struct GNUNET_TIME_Relative delay,
742 GNUNET_SCHEDULER_Task main, void *cls)
744 return GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
745 prerequisite_task, delay,
746 NULL, NULL, main, cls);
751 * Schedule a new task to be run with a specified delay or when the
752 * specified file descriptor is ready for reading. The delay can be
753 * used as a timeout on the socket being ready. The task will be
754 * scheduled for execution once either the delay has expired or the
755 * socket operation is ready.
757 * @param sched scheduler to use
758 * @param run_on_shutdown run on shutdown? Set this
759 * argument to GNUNET_NO to skip this task if
760 * the user requested process termination.
761 * @param prio how important is this task?
762 * @param prerequisite_task run this task after the task with the given
763 * task identifier completes (and any of our other
764 * conditions, such as delay, read or write-readyness
765 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
766 * on completion of other tasks.
767 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
768 * @param rfd read file-descriptor
769 * @param main main function of the task
770 * @param cls closure of task
771 * @return unique task identifier for the job
772 * only valid until "main" is started!
774 GNUNET_SCHEDULER_TaskIdentifier
775 GNUNET_SCHEDULER_add_read_net (struct GNUNET_SCHEDULER_Handle * sched,
777 enum GNUNET_SCHEDULER_Priority prio,
778 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
779 struct GNUNET_TIME_Relative delay,
780 struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_Task main, void *cls)
782 struct GNUNET_NETWORK_FDSet *rs;
783 GNUNET_SCHEDULER_TaskIdentifier ret;
785 GNUNET_assert (rfd != NULL);
786 rs = GNUNET_NETWORK_fdset_create ();
787 GNUNET_NETWORK_fdset_set (rs, rfd);
788 ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
789 prerequisite_task, delay,
790 rs, NULL, main, cls);
791 GNUNET_NETWORK_fdset_destroy (rs);
797 * Schedule a new task to be run with a specified delay or when the
798 * specified file descriptor is ready for writing. The delay can be
799 * used as a timeout on the socket being ready. The task will be
800 * scheduled for execution once either the delay has expired or the
801 * socket operation is ready.
803 * @param sched scheduler to use
804 * @param run_on_shutdown run on shutdown? Set this
805 * argument to GNUNET_NO to skip this task if
806 * the user requested process termination.
807 * @param prio how important is this task?
808 * @param prerequisite_task run this task after the task with the given
809 * task identifier completes (and any of our other
810 * conditions, such as delay, read or write-readyness
811 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
812 * on completion of other tasks.
813 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
814 * @param wfd write file-descriptor
815 * @param main main function of the task
816 * @param cls closure of task
817 * @return unique task identifier for the job
818 * only valid until "main" is started!
820 GNUNET_SCHEDULER_TaskIdentifier
821 GNUNET_SCHEDULER_add_write_net (struct GNUNET_SCHEDULER_Handle * sched,
823 enum GNUNET_SCHEDULER_Priority prio,
824 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
825 struct GNUNET_TIME_Relative delay,
826 struct GNUNET_NETWORK_Handle *wfd, GNUNET_SCHEDULER_Task main, void *cls)
828 struct GNUNET_NETWORK_FDSet *ws;
829 GNUNET_SCHEDULER_TaskIdentifier ret;
831 GNUNET_assert (wfd != NULL);
832 ws = GNUNET_NETWORK_fdset_create ();
833 GNUNET_NETWORK_fdset_set (ws, wfd);
834 ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
835 prerequisite_task, delay,
836 NULL, ws, main, cls);
837 GNUNET_NETWORK_fdset_destroy (ws);
843 * Schedule a new task to be run with a specified delay or when any of
844 * the specified file descriptor sets is ready. The delay can be used
845 * as a timeout on the socket(s) being ready. The task will be
846 * scheduled for execution once either the delay has expired or any of
847 * the socket operations is ready. This is the most general
848 * function of the "add" family. Note that the "prerequisite_task"
849 * must be satisfied in addition to any of the other conditions. In
850 * other words, the task will be started when
856 * || (shutdown-active && run-on-shutdown) )
859 * @param sched scheduler to use
860 * @param run_on_shutdown run on shutdown? Set this
861 * argument to GNUNET_NO to skip this task if
862 * the user requested process termination.
863 * @param prio how important is this task?
864 * @param prerequisite_task run this task after the task with the given
865 * task identifier completes (and any of our other
866 * conditions, such as delay, read or write-readyness
867 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
868 * on completion of other tasks.
869 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
870 * @param rs set of file descriptors we want to read (can be NULL)
871 * @param ws set of file descriptors we want to write (can be NULL)
872 * @param main main function of the task
873 * @param cls closure of task
874 * @return unique task identifier for the job
875 * only valid until "main" is started!
877 GNUNET_SCHEDULER_TaskIdentifier
878 GNUNET_SCHEDULER_add_select (struct GNUNET_SCHEDULER_Handle * sched,
880 enum GNUNET_SCHEDULER_Priority prio,
881 GNUNET_SCHEDULER_TaskIdentifier
883 struct GNUNET_TIME_Relative delay,
884 const struct GNUNET_NETWORK_FDSet * rs, const struct GNUNET_NETWORK_FDSet * ws,
885 GNUNET_SCHEDULER_Task main, void *cls)
889 task = GNUNET_malloc (sizeof (struct Task));
890 task->callback = main;
891 task->callback_cls = cls;
892 task->read_set = GNUNET_NETWORK_fdset_create ();
894 GNUNET_NETWORK_fdset_copy (task->read_set, rs);
895 task->write_set = GNUNET_NETWORK_fdset_create ();
897 GNUNET_NETWORK_fdset_copy (task->write_set, ws);
898 task->id = ++sched->last_id;
899 task->prereq_id = prerequisite_task;
900 task->timeout = GNUNET_TIME_relative_to_absolute (delay);
902 check_priority ((prio ==
903 GNUNET_SCHEDULER_PRIORITY_KEEP) ? sched->current_priority
905 task->run_on_shutdown = run_on_shutdown;
906 task->next = sched->pending;
907 sched->pending = task;
912 * Schedule a new task to be run with a specified delay or when the
913 * specified file descriptor is ready for reading. The delay can be
914 * used as a timeout on the socket being ready. The task will be
915 * scheduled for execution once either the delay has expired or the
916 * socket operation is ready.
918 * @param sched scheduler to use
919 * @param run_on_shutdown run on shutdown? Set this
920 * argument to GNUNET_NO to skip this task if
921 * the user requested process termination.
922 * @param prio how important is this task?
923 * @param prerequisite_task run this task after the task with the given
924 * task identifier completes (and any of our other
925 * conditions, such as delay, read or write-readyness
926 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
927 * on completion of other tasks.
928 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
929 * @param rfd read file-descriptor
930 * @param main main function of the task
931 * @param cls closure of task
932 * @return unique task identifier for the job
933 * only valid until "main" is started!
935 GNUNET_SCHEDULER_TaskIdentifier
936 GNUNET_SCHEDULER_add_read_file (struct GNUNET_SCHEDULER_Handle * sched,
938 enum GNUNET_SCHEDULER_Priority prio,
939 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
940 struct GNUNET_TIME_Relative delay,
941 const struct GNUNET_DISK_FileHandle *rfd,
942 GNUNET_SCHEDULER_Task main, void *cls)
944 struct GNUNET_NETWORK_FDSet *rs;
945 GNUNET_SCHEDULER_TaskIdentifier ret;
947 GNUNET_assert (rfd != NULL);
948 rs = GNUNET_NETWORK_fdset_create ();
949 GNUNET_NETWORK_fdset_handle_set (rs, rfd);
950 ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
951 prerequisite_task, delay,
952 rs, NULL, main, cls);
953 GNUNET_NETWORK_fdset_destroy (rs);
959 * Schedule a new task to be run with a specified delay or when the
960 * specified file descriptor is ready for writing. The delay can be
961 * used as a timeout on the socket being ready. The task will be
962 * scheduled for execution once either the delay has expired or the
963 * socket operation is ready.
965 * @param sched scheduler to use
966 * @param run_on_shutdown run on shutdown? Set this
967 * argument to GNUNET_NO to skip this task if
968 * the user requested process termination.
969 * @param prio how important is this task?
970 * @param prerequisite_task run this task after the task with the given
971 * task identifier completes (and any of our other
972 * conditions, such as delay, read or write-readyness
973 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
974 * on completion of other tasks.
975 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
976 * @param wfd write file-descriptor
977 * @param main main function of the task
978 * @param cls closure of task
979 * @return unique task identifier for the job
980 * only valid until "main" is started!
982 GNUNET_SCHEDULER_TaskIdentifier
983 GNUNET_SCHEDULER_add_write_file (struct GNUNET_SCHEDULER_Handle * sched,
985 enum GNUNET_SCHEDULER_Priority prio,
986 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
987 struct GNUNET_TIME_Relative delay,
988 const struct GNUNET_DISK_FileHandle *wfd,
989 GNUNET_SCHEDULER_Task main, void *cls)
991 struct GNUNET_NETWORK_FDSet *ws;
992 GNUNET_SCHEDULER_TaskIdentifier ret;
994 GNUNET_assert (wfd != NULL);
995 ws = GNUNET_NETWORK_fdset_create ();
996 GNUNET_NETWORK_fdset_handle_set (ws, wfd);
997 ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
998 prerequisite_task, delay,
999 NULL, ws, main, cls);
1000 GNUNET_NETWORK_fdset_destroy (ws);
1005 /* end of scheduler.c */