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 * How many tasks have we run so far?
149 unsigned long long tasks_run;
152 * Priority of the task running right now. Only
153 * valid while a task is running.
155 enum GNUNET_SCHEDULER_Priority current_priority;
161 * Check that the given priority is legal (and return it).
163 * @param p priority value to check
164 * @return p on success, 0 on error
166 static enum GNUNET_SCHEDULER_Priority
167 check_priority (enum GNUNET_SCHEDULER_Priority p)
169 if ((p >= 0) && (p < GNUNET_SCHEDULER_PRIORITY_COUNT))
172 return 0; /* make compiler happy */
177 * Is a task with this identifier still pending? Also updates
178 * "lowest_pending_id" as a side-effect (for faster checks in the
179 * future), but only if the return value is "GNUNET_NO" (and
180 * the "lowest_pending_id" check failed).
182 * @param sched the scheduler
183 * @param id which task are we checking for
184 * @return GNUNET_YES if so, GNUNET_NO if not
187 is_pending (struct GNUNET_SCHEDULER_Handle *sched,
188 GNUNET_SCHEDULER_TaskIdentifier id)
191 enum GNUNET_SCHEDULER_Priority p;
192 GNUNET_SCHEDULER_TaskIdentifier min;
194 if (id < sched->lowest_pending_id)
196 min = -1; /* maximum value */
197 pos = sched->pending;
206 for (p = 0; p < GNUNET_SCHEDULER_PRIORITY_COUNT; p++)
208 pos = sched->ready[p];
218 sched->lowest_pending_id = min;
224 * Update all sets and timeout for select.
226 * @param sched the scheduler
227 * @param rs read-set, set to all FDs we would like to read (updated)
228 * @param ws write-set, set to all FDs we would like to write (updated)
229 * @param timeout next timeout (updated)
232 update_sets (struct GNUNET_SCHEDULER_Handle *sched,
233 struct GNUNET_NETWORK_FDSet * rs,
234 struct GNUNET_NETWORK_FDSet * ws,
235 struct GNUNET_TIME_Relative *timeout)
239 pos = sched->pending;
243 if ((pos->prereq_id != GNUNET_SCHEDULER_NO_TASK) &&
244 (GNUNET_YES == is_pending (sched, pos->prereq_id)))
250 if (pos->timeout.value != GNUNET_TIME_UNIT_FOREVER_ABS.value)
252 struct GNUNET_TIME_Relative to;
254 to = GNUNET_TIME_absolute_get_remaining (pos->timeout);
255 if (timeout->value > to.value)
259 GNUNET_NETWORK_fdset_add (rs, pos->read_set);
260 GNUNET_NETWORK_fdset_add (ws, pos->write_set);
267 * Check if the ready set overlaps with the set we want to have ready.
268 * If so, update the want set (set all FDs that are ready). If not,
271 * @param ready set that is ready
272 * @param want set that we want to be ready
273 * @return GNUNET_YES if there was some overlap
276 set_overlaps (const struct GNUNET_NETWORK_FDSet * ready,
277 struct GNUNET_NETWORK_FDSet * want)
279 if (GNUNET_NETWORK_fdset_overlap (ready, want))
281 /* copy all over (yes, there maybe unrelated bits,
282 but this should not hurt well-written clients) */
283 GNUNET_NETWORK_fdset_copy (want, ready);
291 * Check if the given task is eligible to run now.
292 * Also set the reason why it is eligible.
294 * @param sched the scheduler
295 * @param task task to check if it is ready
296 * @param now the current time
297 * @param rs set of FDs ready for reading
298 * @param ws set of FDs ready for writing
299 * @return GNUNET_YES if we can run it, GNUNET_NO if not.
302 is_ready (struct GNUNET_SCHEDULER_Handle *sched,
304 struct GNUNET_TIME_Absolute now,
305 const struct GNUNET_NETWORK_FDSet *rs,
306 const struct GNUNET_NETWORK_FDSet * ws)
308 if ((GNUNET_NO == task->run_on_shutdown) && (GNUNET_YES == sched->shutdown))
310 if ((GNUNET_YES == task->run_on_shutdown) &&
311 (GNUNET_YES == sched->shutdown))
312 task->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN;
313 if (now.value >= task->timeout.value)
314 task->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
315 if ((0 == (task->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
316 (rs != NULL) && (set_overlaps (rs, task->read_set)))
317 task->reason |= GNUNET_SCHEDULER_REASON_READ_READY;
318 if ((0 == (task->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
319 (ws != NULL) && (set_overlaps (ws, task->write_set)))
320 task->reason |= GNUNET_SCHEDULER_REASON_WRITE_READY;
321 if (task->reason == 0)
322 return GNUNET_NO; /* not ready */
323 if (task->prereq_id != GNUNET_SCHEDULER_NO_TASK)
325 if (GNUNET_YES == is_pending (sched, task->prereq_id))
326 return GNUNET_NO; /* prereq waiting */
327 task->reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;
334 * Put a task that is ready for execution into the ready queue.
336 * @param handle the scheduler
337 * @param task task ready for execution
340 queue_ready_task (struct GNUNET_SCHEDULER_Handle *handle,
343 task->next = handle->ready[check_priority (task->priority)];
344 handle->ready[check_priority (task->priority)] = task;
345 handle->ready_count++;
350 * Check which tasks are ready and move them
351 * to the respective ready queue.
353 * @param handle the scheduler
354 * @param rs FDs ready for reading
355 * @param ws FDs ready for writing
358 check_ready (struct GNUNET_SCHEDULER_Handle *handle,
359 const struct GNUNET_NETWORK_FDSet * rs,
360 const struct GNUNET_NETWORK_FDSet * ws)
365 struct GNUNET_TIME_Absolute now;
367 now = GNUNET_TIME_absolute_get ();
369 pos = handle->pending;
373 if (GNUNET_YES == is_ready (handle, pos, now, rs, ws))
376 handle->pending = next;
379 queue_ready_task (handle, pos);
390 * Destroy a task (release associated resources)
392 * @param t task to destroy
394 static void destroy_task (struct Task *t)
397 GNUNET_NETWORK_fdset_destroy (t->read_set);
399 GNUNET_NETWORK_fdset_destroy (t->write_set);
405 * Run at least one task in the highest-priority queue that is not
406 * empty. Keep running tasks until we are either no longer running
407 * "URGENT" tasks or until we have at least one "pending" task (which
408 * may become ready, hence we should select on it). Naturally, if
409 * there are no more ready tasks, we also return.
411 * @param sched the scheduler
414 run_ready (struct GNUNET_SCHEDULER_Handle *sched)
416 enum GNUNET_SCHEDULER_Priority p;
418 struct GNUNET_SCHEDULER_TaskContext tc;
422 if (sched->ready_count == 0)
424 GNUNET_assert (sched->ready[GNUNET_SCHEDULER_PRIORITY_KEEP] == NULL);
425 /* yes, p>0 is correct, 0 is "KEEP" which should
426 always be an empty queue (see assertion)! */
427 for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--)
429 pos = sched->ready[p];
433 GNUNET_assert (pos != NULL); /* ready_count wrong? */
434 sched->ready[p] = pos->next;
435 sched->ready_count--;
436 sched->current_priority = p;
437 GNUNET_assert (pos->priority == p);
439 tc.reason = pos->reason;
440 tc.read_ready = pos->read_set;
441 tc.write_ready = pos->write_set;
442 pos->callback (pos->callback_cls, &tc);
446 while ((sched->pending == NULL) || (p == GNUNET_SCHEDULER_PRIORITY_URGENT));
451 * Have we (ever) received a SIGINT/TERM/QUIT/HUP?
453 static volatile int sig_shutdown;
457 * Signal handler called for signals that should cause us to shutdown.
460 sighandler_shutdown ()
467 * Initialize a scheduler using this thread. This function will
468 * return when either a shutdown was initiated (via signal) and all
469 * tasks marked to "run_on_shutdown" have been completed or when all
470 * tasks in general have been completed.
472 * @param task task to run immediately
473 * @param cls closure of task
476 GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *cls)
478 struct GNUNET_SCHEDULER_Handle sched;
479 struct GNUNET_NETWORK_FDSet *rs;
480 struct GNUNET_NETWORK_FDSet *ws;
481 struct GNUNET_TIME_Relative timeout;
483 struct GNUNET_SIGNAL_Context *shc_int;
484 struct GNUNET_SIGNAL_Context *shc_term;
485 struct GNUNET_SIGNAL_Context *shc_quit;
486 struct GNUNET_SIGNAL_Context *shc_hup;
488 unsigned long long last_tr;
489 unsigned int busy_wait_warning;
492 rs = GNUNET_NETWORK_fdset_create ();
493 ws = GNUNET_NETWORK_fdset_create ();
495 shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown);
496 shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown);
497 shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, &sighandler_shutdown);
498 shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, &sighandler_shutdown);
500 memset (&sched, 0, sizeof (sched));
501 sched.current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
502 GNUNET_SCHEDULER_add_continuation (&sched,
505 cls, GNUNET_SCHEDULER_REASON_STARTUP);
507 busy_wait_warning = 0;
508 while ((GNUNET_NO == sched.shutdown) &&
510 ((sched.pending != NULL) || (sched.ready_count > 0)))
512 GNUNET_NETWORK_fdset_zero (rs);
513 GNUNET_NETWORK_fdset_zero (ws);
514 timeout = GNUNET_TIME_relative_get_forever();
515 if (sched.ready_count > 0)
517 /* no blocking, more work already ready! */
518 timeout = GNUNET_TIME_relative_get_zero();
520 update_sets (&sched, rs, ws, &timeout);
521 ret = GNUNET_NETWORK_socket_select (rs, ws, NULL, timeout);
522 if (last_tr == sched.tasks_run)
525 last_tr = sched.tasks_run;
527 (timeout.value == 0) &&
528 (sched.ready_count == 0) &&
529 (busy_wait_warning > 16) )
531 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
532 _("Looks like we're busy waiting...\n"));
533 sleep (1); /* mitigate */
535 if (ret == GNUNET_SYSERR)
539 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");
542 check_ready (&sched, rs, ws);
546 sched.shutdown = GNUNET_YES;
547 GNUNET_SIGNAL_handler_uninstall (shc_int);
548 GNUNET_SIGNAL_handler_uninstall (shc_term);
549 GNUNET_SIGNAL_handler_uninstall (shc_quit);
550 GNUNET_SIGNAL_handler_uninstall (shc_hup);
554 check_ready (&sched, NULL, NULL);
556 while (sched.ready_count > 0);
557 while (NULL != (tpos = sched.pending))
559 sched.pending = tpos->next;
562 GNUNET_NETWORK_fdset_destroy (rs);
563 GNUNET_NETWORK_fdset_destroy (ws);
568 * Request the shutdown of a scheduler. This function can be used to
569 * stop a scheduling thread when created with the
570 * "GNUNET_SCHEDULER_init_thread" function or from within the signal
571 * handler for signals causing shutdowns.
573 * @param sched the scheduler
576 GNUNET_SCHEDULER_shutdown (struct GNUNET_SCHEDULER_Handle *sched)
578 sched->shutdown = GNUNET_YES;
583 * Get information about the current load of this scheduler. Use this
584 * function to determine if an elective task should be added or simply
585 * dropped (if the decision should be made based on the number of
586 * tasks ready to run).
588 * @param sched scheduler to query
589 * @param p priority level to look at
590 * @return number of tasks pending right now
593 GNUNET_SCHEDULER_get_load (struct GNUNET_SCHEDULER_Handle *sched,
594 enum GNUNET_SCHEDULER_Priority p)
599 if (p == GNUNET_SCHEDULER_PRIORITY_COUNT)
600 return sched->ready_count;
601 if (p == GNUNET_SCHEDULER_PRIORITY_KEEP)
602 p = sched->current_priority;
604 pos = sched->ready[p];
615 * Cancel the task with the specified identifier.
616 * The task must not yet have run.
618 * @param sched scheduler to use
619 * @param task id of the task to cancel
620 * @return original closure of the task
623 GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Handle *sched,
624 GNUNET_SCHEDULER_TaskIdentifier task)
628 enum GNUNET_SCHEDULER_Priority p;
644 GNUNET_assert (p < GNUNET_SCHEDULER_PRIORITY_COUNT);
651 sched->ready_count--;
661 sched->pending = t->next;
663 sched->ready[p] = t->next;
666 prev->next = t->next;
667 ret = t->callback_cls;
674 * Continue the current execution with the given function. This is
675 * similar to the other "add" functions except that there is no delay
676 * and the reason code can be specified.
678 * @param sched scheduler to use
679 * @param run_on_shutdown should this task be run if we are shutting down?
680 * @param main main function of the task
681 * @param cls closure for 'main'
682 * @param reason reason for task invocation
685 GNUNET_SCHEDULER_add_continuation (struct GNUNET_SCHEDULER_Handle *sched,
687 GNUNET_SCHEDULER_Task main,
689 enum GNUNET_SCHEDULER_Reason reason)
693 task = GNUNET_malloc (sizeof (struct Task));
694 task->callback = main;
695 task->callback_cls = cls;
696 task->id = ++sched->last_id;
697 task->reason = reason;
698 task->priority = sched->current_priority;
699 task->run_on_shutdown = run_on_shutdown;
700 queue_ready_task (sched, task);
705 * Schedule a new task to be run after the specified
706 * prerequisite task has completed.
708 * @param sched scheduler to use
709 * @param run_on_shutdown run on shutdown?
710 * @param prio how important is this task?
711 * @param prerequisite_task run this task after the task with the given
712 * task identifier completes (and any of our other
713 * conditions, such as delay, read or write-readyness
714 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
715 * on completion of other tasks.
716 * @param main main function of the task
717 * @param cls closure for 'main'
718 * @return unique task identifier for the job
719 * only valid until "main" is started!
721 GNUNET_SCHEDULER_TaskIdentifier
722 GNUNET_SCHEDULER_add_after (struct GNUNET_SCHEDULER_Handle *sched,
724 enum GNUNET_SCHEDULER_Priority prio,
725 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
726 GNUNET_SCHEDULER_Task main, void *cls)
728 return GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
730 GNUNET_TIME_UNIT_ZERO,
731 NULL, NULL, main, cls);
736 * Schedule a new task to be run with a specified delay. The task
737 * will be scheduled for execution once the delay has expired and the
738 * prerequisite task has completed.
740 * @param sched scheduler to use
741 * @param run_on_shutdown run on shutdown? You can use this
742 * argument to run a function only during shutdown
743 * by setting delay to -1. Set this
744 * argument to GNUNET_NO to skip this task if
745 * the user requested process termination.
746 * @param prio how important is this task?
747 * @param prerequisite_task run this task after the task with the given
748 * task identifier completes (and any of our other
749 * conditions, such as delay, read or write-readyness
750 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
751 * on completion of other tasks.
752 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
753 * @param main main function of the task
754 * @param cls closure of task
755 * @return unique task identifier for the job
756 * only valid until "main" is started!
758 GNUNET_SCHEDULER_TaskIdentifier
759 GNUNET_SCHEDULER_add_delayed (struct GNUNET_SCHEDULER_Handle * sched,
761 enum GNUNET_SCHEDULER_Priority prio,
762 GNUNET_SCHEDULER_TaskIdentifier
764 struct GNUNET_TIME_Relative delay,
765 GNUNET_SCHEDULER_Task main, void *cls)
767 return GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
768 prerequisite_task, delay,
769 NULL, NULL, main, cls);
774 * Schedule a new task to be run with a specified delay or when the
775 * specified file descriptor is ready for reading. The delay can be
776 * used as a timeout on the socket being ready. The task will be
777 * scheduled for execution once either the delay has expired or the
778 * socket operation is ready.
780 * @param sched scheduler to use
781 * @param run_on_shutdown run on shutdown? Set this
782 * argument to GNUNET_NO to skip this task if
783 * the user requested process termination.
784 * @param prio how important is this task?
785 * @param prerequisite_task run this task after the task with the given
786 * task identifier completes (and any of our other
787 * conditions, such as delay, read or write-readyness
788 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
789 * on completion of other tasks.
790 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
791 * @param rfd read file-descriptor
792 * @param main main function of the task
793 * @param cls closure of task
794 * @return unique task identifier for the job
795 * only valid until "main" is started!
797 GNUNET_SCHEDULER_TaskIdentifier
798 GNUNET_SCHEDULER_add_read_net (struct GNUNET_SCHEDULER_Handle * sched,
800 enum GNUNET_SCHEDULER_Priority prio,
801 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
802 struct GNUNET_TIME_Relative delay,
803 struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_Task main, void *cls)
805 struct GNUNET_NETWORK_FDSet *rs;
806 GNUNET_SCHEDULER_TaskIdentifier ret;
808 GNUNET_assert (rfd != NULL);
809 rs = GNUNET_NETWORK_fdset_create ();
810 GNUNET_NETWORK_fdset_set (rs, rfd);
811 ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
812 prerequisite_task, delay,
813 rs, NULL, main, cls);
814 GNUNET_NETWORK_fdset_destroy (rs);
820 * Schedule a new task to be run with a specified delay or when the
821 * specified file descriptor is ready for writing. The delay can be
822 * used as a timeout on the socket being ready. The task will be
823 * scheduled for execution once either the delay has expired or the
824 * socket operation is ready.
826 * @param sched scheduler to use
827 * @param run_on_shutdown run on shutdown? Set this
828 * argument to GNUNET_NO to skip this task if
829 * the user requested process termination.
830 * @param prio how important is this task?
831 * @param prerequisite_task run this task after the task with the given
832 * task identifier completes (and any of our other
833 * conditions, such as delay, read or write-readyness
834 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
835 * on completion of other tasks.
836 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
837 * @param wfd write file-descriptor
838 * @param main main function of the task
839 * @param cls closure of task
840 * @return unique task identifier for the job
841 * only valid until "main" is started!
843 GNUNET_SCHEDULER_TaskIdentifier
844 GNUNET_SCHEDULER_add_write_net (struct GNUNET_SCHEDULER_Handle * sched,
846 enum GNUNET_SCHEDULER_Priority prio,
847 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
848 struct GNUNET_TIME_Relative delay,
849 struct GNUNET_NETWORK_Handle *wfd, GNUNET_SCHEDULER_Task main, void *cls)
851 struct GNUNET_NETWORK_FDSet *ws;
852 GNUNET_SCHEDULER_TaskIdentifier ret;
854 GNUNET_assert (wfd != NULL);
855 ws = GNUNET_NETWORK_fdset_create ();
856 GNUNET_NETWORK_fdset_set (ws, wfd);
857 ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
858 prerequisite_task, delay,
859 NULL, ws, main, cls);
860 GNUNET_NETWORK_fdset_destroy (ws);
866 * Schedule a new task to be run with a specified delay or when any of
867 * the specified file descriptor sets is ready. The delay can be used
868 * as a timeout on the socket(s) being ready. The task will be
869 * scheduled for execution once either the delay has expired or any of
870 * the socket operations is ready. This is the most general
871 * function of the "add" family. Note that the "prerequisite_task"
872 * must be satisfied in addition to any of the other conditions. In
873 * other words, the task will be started when
879 * || (shutdown-active && run-on-shutdown) )
882 * @param sched scheduler to use
883 * @param run_on_shutdown run on shutdown? Set this
884 * argument to GNUNET_NO to skip this task if
885 * the user requested process termination.
886 * @param prio how important is this task?
887 * @param prerequisite_task run this task after the task with the given
888 * task identifier completes (and any of our other
889 * conditions, such as delay, read or write-readyness
890 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
891 * on completion of other tasks.
892 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
893 * @param rs set of file descriptors we want to read (can be NULL)
894 * @param ws set of file descriptors we want to write (can be NULL)
895 * @param main main function of the task
896 * @param cls closure of task
897 * @return unique task identifier for the job
898 * only valid until "main" is started!
900 GNUNET_SCHEDULER_TaskIdentifier
901 GNUNET_SCHEDULER_add_select (struct GNUNET_SCHEDULER_Handle * sched,
903 enum GNUNET_SCHEDULER_Priority prio,
904 GNUNET_SCHEDULER_TaskIdentifier
906 struct GNUNET_TIME_Relative delay,
907 const struct GNUNET_NETWORK_FDSet * rs, const struct GNUNET_NETWORK_FDSet * ws,
908 GNUNET_SCHEDULER_Task main, void *cls)
912 task = GNUNET_malloc (sizeof (struct Task));
913 task->callback = main;
914 task->callback_cls = cls;
915 task->read_set = GNUNET_NETWORK_fdset_create ();
917 GNUNET_NETWORK_fdset_copy (task->read_set, rs);
918 task->write_set = GNUNET_NETWORK_fdset_create ();
920 GNUNET_NETWORK_fdset_copy (task->write_set, ws);
921 task->id = ++sched->last_id;
922 task->prereq_id = prerequisite_task;
923 task->timeout = GNUNET_TIME_relative_to_absolute (delay);
925 check_priority ((prio ==
926 GNUNET_SCHEDULER_PRIORITY_KEEP) ? sched->current_priority
928 task->run_on_shutdown = run_on_shutdown;
929 task->next = sched->pending;
930 sched->pending = task;
935 * Schedule a new task to be run with a specified delay or when the
936 * specified file descriptor is ready for reading. The delay can be
937 * used as a timeout on the socket being ready. The task will be
938 * scheduled for execution once either the delay has expired or the
939 * socket operation is ready.
941 * @param sched scheduler to use
942 * @param run_on_shutdown run on shutdown? Set this
943 * argument to GNUNET_NO to skip this task if
944 * the user requested process termination.
945 * @param prio how important is this task?
946 * @param prerequisite_task run this task after the task with the given
947 * task identifier completes (and any of our other
948 * conditions, such as delay, read or write-readyness
949 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
950 * on completion of other tasks.
951 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
952 * @param rfd read file-descriptor
953 * @param main main function of the task
954 * @param cls closure of task
955 * @return unique task identifier for the job
956 * only valid until "main" is started!
958 GNUNET_SCHEDULER_TaskIdentifier
959 GNUNET_SCHEDULER_add_read_file (struct GNUNET_SCHEDULER_Handle * sched,
961 enum GNUNET_SCHEDULER_Priority prio,
962 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
963 struct GNUNET_TIME_Relative delay,
964 const struct GNUNET_DISK_FileHandle *rfd,
965 GNUNET_SCHEDULER_Task main, void *cls)
967 struct GNUNET_NETWORK_FDSet *rs;
968 GNUNET_SCHEDULER_TaskIdentifier ret;
970 GNUNET_assert (rfd != NULL);
971 rs = GNUNET_NETWORK_fdset_create ();
972 GNUNET_NETWORK_fdset_handle_set (rs, rfd);
973 ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
974 prerequisite_task, delay,
975 rs, NULL, main, cls);
976 GNUNET_NETWORK_fdset_destroy (rs);
982 * Schedule a new task to be run with a specified delay or when the
983 * specified file descriptor is ready for writing. The delay can be
984 * used as a timeout on the socket being ready. The task will be
985 * scheduled for execution once either the delay has expired or the
986 * socket operation is ready.
988 * @param sched scheduler to use
989 * @param run_on_shutdown run on shutdown? Set this
990 * argument to GNUNET_NO to skip this task if
991 * the user requested process termination.
992 * @param prio how important is this task?
993 * @param prerequisite_task run this task after the task with the given
994 * task identifier completes (and any of our other
995 * conditions, such as delay, read or write-readyness
996 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
997 * on completion of other tasks.
998 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever"
999 * @param wfd write file-descriptor
1000 * @param main main function of the task
1001 * @param cls closure of task
1002 * @return unique task identifier for the job
1003 * only valid until "main" is started!
1005 GNUNET_SCHEDULER_TaskIdentifier
1006 GNUNET_SCHEDULER_add_write_file (struct GNUNET_SCHEDULER_Handle * sched,
1007 int run_on_shutdown,
1008 enum GNUNET_SCHEDULER_Priority prio,
1009 GNUNET_SCHEDULER_TaskIdentifier prerequisite_task,
1010 struct GNUNET_TIME_Relative delay,
1011 const struct GNUNET_DISK_FileHandle *wfd,
1012 GNUNET_SCHEDULER_Task main, void *cls)
1014 struct GNUNET_NETWORK_FDSet *ws;
1015 GNUNET_SCHEDULER_TaskIdentifier ret;
1017 GNUNET_assert (wfd != NULL);
1018 ws = GNUNET_NETWORK_fdset_create ();
1019 GNUNET_NETWORK_fdset_handle_set (ws, wfd);
1020 ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio,
1021 prerequisite_task, delay,
1022 NULL, ws, main, cls);
1023 GNUNET_NETWORK_fdset_destroy (ws);
1028 /* end of scheduler.c */