diff options
-rw-r--r-- | src/include/gnunet_scheduler_lib.h | 195 | ||||
-rw-r--r-- | src/util/scheduler.c | 432 |
2 files changed, 390 insertions, 237 deletions
diff --git a/src/include/gnunet_scheduler_lib.h b/src/include/gnunet_scheduler_lib.h index d2805a685..e5c361567 100644 --- a/src/include/gnunet_scheduler_lib.h +++ b/src/include/gnunet_scheduler_lib.h | |||
@@ -237,29 +237,32 @@ struct GNUNET_SCHEDULER_Handle; | |||
237 | 237 | ||
238 | 238 | ||
239 | /** | 239 | /** |
240 | * Function called by the driver to tell the scheduler to run some of | 240 | * Function called by external event loop implementations to tell the |
241 | * the tasks that are ready. This function may return even though | 241 | * scheduler to run some of the tasks that are ready. Must be called |
242 | * there are tasks left to run just to give other tasks a chance as | 242 | * only after #GNUNET_SCHEDULER_driver_init has been called and before |
243 | * well. If we return #GNUNET_YES, the driver should call this | 243 | * #GNUNET_SCHEDULER_driver_done is called. |
244 | * function again as soon as possible, while if we return #GNUNET_NO | 244 | * This function may return even though there are tasks left to run |
245 | * it must block until either the operating system has more work (the | 245 | * just to give other tasks a chance as well. If we return #GNUNET_YES, |
246 | * scheduler has no more work to do right now) or the timeout set by | 246 | * the event loop implementation should call this function again as |
247 | * the scheduler (using the set_wakeup callback) is reached. | 247 | * soon as possible, while if we return #GNUNET_NO it must block until |
248 | * | 248 | * either the operating system has more work (the scheduler has no more |
249 | * @param sh scheduler handle that was given to the `loop` | 249 | * work to do right now) or the timeout set by the scheduler (using the |
250 | * @return #GNUNET_OK if there are more tasks that are ready, | 250 | * set_wakeup callback) is reached. |
251 | * and thus we would like to run more (yield to avoid | 251 | * |
252 | * blocking other activities for too long) | 252 | * @param sh scheduler handle that was returned by |
253 | * #GNUNET_NO if we are done running tasks (yield to block) | 253 | * #GNUNET_SCHEDULER_driver_init |
254 | * #GNUNET_SYSERR on error, e.g. no tasks were ready | 254 | * @return #GNUNET_YES if there are more tasks that are ready, |
255 | * and thus we would like to run more (yield to avoid | ||
256 | * blocking other activities for too long) #GNUNET_NO | ||
257 | * if we are done running tasks (yield to block) | ||
255 | */ | 258 | */ |
256 | int | 259 | int |
257 | GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh); | 260 | GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh); |
258 | 261 | ||
259 | 262 | ||
260 | /** | 263 | /** |
261 | * API a driver has to implement for | 264 | * API an external event loop has to implement for |
262 | * #GNUNET_SCHEDULER_run_with_driver(). | 265 | * #GNUNET_SCHEDULER_driver_init. |
263 | */ | 266 | */ |
264 | struct GNUNET_SCHEDULER_Driver | 267 | struct GNUNET_SCHEDULER_Driver |
265 | { | 268 | { |
@@ -311,23 +314,6 @@ struct GNUNET_SCHEDULER_Driver | |||
311 | (*set_wakeup)(void *cls, | 314 | (*set_wakeup)(void *cls, |
312 | struct GNUNET_TIME_Absolute dt); | 315 | struct GNUNET_TIME_Absolute dt); |
313 | 316 | ||
314 | /** | ||
315 | * Event loop's "main" function, to be called from | ||
316 | * #GNUNET_SCHEDULER_run_with_driver() to actually | ||
317 | * launch the loop. The loop should run as long as | ||
318 | * tasks (added by the add callback) are available | ||
319 | * OR the wakeup time (added by the set_wakeup | ||
320 | * callback) is not FOREVER. | ||
321 | * | ||
322 | * @param cls closure | ||
323 | * @param sh scheduler handle to pass to | ||
324 | * #GNUNET_SCHEDULER_run_from_driver() | ||
325 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | ||
326 | */ | ||
327 | int | ||
328 | (*loop)(void *cls, | ||
329 | struct GNUNET_SCHEDULER_Handle *sh); | ||
330 | |||
331 | }; | 317 | }; |
332 | 318 | ||
333 | 319 | ||
@@ -341,25 +327,55 @@ typedef void | |||
341 | 327 | ||
342 | 328 | ||
343 | /** | 329 | /** |
344 | * Initialize and run scheduler. This function will return when all | 330 | * Function called by external event loop implementations to initialize |
345 | * tasks have completed. On systems with signals, receiving a SIGTERM | 331 | * the scheduler. An external implementation has to provide @a driver |
346 | * (and other similar signals) will cause #GNUNET_SCHEDULER_shutdown | 332 | * which contains callbacks for the scheduler (see definition of struct |
347 | * to be run after the active task is complete. As a result, SIGTERM | 333 | * #GNUNET_SCHEDULER_Driver) for instructing the external implementation |
348 | * causes all shutdown tasks to be scheduled with reason | 334 | * to watch for events. If it detects any event it is expected to call |
349 | * #GNUNET_SCHEDULER_REASON_SHUTDOWN. (However, tasks added | 335 | * #GNUNET_SCHEDULER_do_work to let the scheduler handle it. If an event |
350 | * afterwards will execute normally!). Note that any particular | 336 | * is related to a specific task (e.g. the scheduler gave instructions |
351 | * signal will only shut down one scheduler; applications should | 337 | * to watch a file descriptor), the external implementation is expected |
352 | * always only create a single scheduler. | 338 | * to mark that task ready before by calling #GNUNET_SCHEDULER_task_ready. |
339 | |||
340 | * This function has to be called before any tasks are scheduled and | ||
341 | * before GNUNET_SCHEDULER_do_work is called for the first time. It | ||
342 | * allocates resources that have to be freed again by calling | ||
343 | * #GNUNET_SCHEDULER_driver_done. | ||
353 | * | 344 | * |
354 | * @param driver drive to use for the event loop | 345 | * This function installs the same signal handlers as |
355 | * @param task task to run first (and immediately) | 346 | * #GNUNET_SCHEDULER_run. This means SIGTERM (and other similar signals) |
356 | * @param task_cls closure of @a task | 347 | * will induce a call to #GNUNET_SCHEDULER_shutdown during the next |
357 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | 348 | * call to #GNUNET_SCHEDULER_do_work. As a result, SIGTERM causes all |
349 | * active tasks to be scheduled with reason | ||
350 | * #GNUNET_SCHEDULER_REASON_SHUTDOWN. (However, tasks added afterwards | ||
351 | * will execute normally!). Note that any particular signal will only | ||
352 | * shut down one scheduler; applications should always only create a | ||
353 | * single scheduler. | ||
354 | * | ||
355 | * @param driver to use for the event loop | ||
356 | * @return handle to be passed to #GNUNET_SCHEDULER_do_work and | ||
357 | * #GNUNET_SCHEDULER_driver_done | ||
358 | */ | 358 | */ |
359 | int | 359 | struct GNUNET_SCHEDULER_Handle * |
360 | GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | 360 | GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver); |
361 | GNUNET_SCHEDULER_TaskCallback task, | 361 | |
362 | void *task_cls); | 362 | |
363 | /** | ||
364 | * Counter-part of #GNUNET_SCHEDULER_driver_init. Has to be called | ||
365 | * by external event loop implementations after the scheduler has | ||
366 | * shut down. This is the case if both of the following conditions | ||
367 | * are met: | ||
368 | * | ||
369 | * - all tasks the scheduler has added through the driver's add | ||
370 | * callback have been removed again through the driver's del | ||
371 | * callback | ||
372 | * - the timeout the scheduler has set through the driver's | ||
373 | * add_wakeup callback is FOREVER | ||
374 | * | ||
375 | * @param sh the handle returned by #GNUNET_SCHEDULER_driver_init | ||
376 | */ | ||
377 | void | ||
378 | GNUNET_SCHEDULER_driver_done (struct GNUNET_SCHEDULER_Handle *sh); | ||
363 | 379 | ||
364 | 380 | ||
365 | /** | 381 | /** |
@@ -462,10 +478,15 @@ GNUNET_SCHEDULER_get_task_context (void); | |||
462 | 478 | ||
463 | /** | 479 | /** |
464 | * Cancel the task with the specified identifier. | 480 | * Cancel the task with the specified identifier. |
465 | * The task must not yet have run. | 481 | * The task must not yet have run. Only allowed to be called as long as the |
482 | * scheduler is running, that is one of the following conditions is met: | ||
483 | * | ||
484 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
485 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
486 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
466 | * | 487 | * |
467 | * @param task id of the task to cancel | 488 | * @param task id of the task to cancel |
468 | * @return the closure of the callback of the cancelled task | 489 | * @return original closure of the task |
469 | */ | 490 | */ |
470 | void * | 491 | void * |
471 | GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task); | 492 | GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task); |
@@ -634,6 +655,12 @@ GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at, | |||
634 | * used as a timeout on the socket being ready. The task will be | 655 | * used as a timeout on the socket being ready. The task will be |
635 | * scheduled for execution once either the delay has expired or the | 656 | * scheduled for execution once either the delay has expired or the |
636 | * socket operation is ready. It will be run with the DEFAULT priority. | 657 | * socket operation is ready. It will be run with the DEFAULT priority. |
658 | * Only allowed to be called as long as the scheduler is running, that | ||
659 | * is one of the following conditions is met: | ||
660 | * | ||
661 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
662 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
663 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
637 | * | 664 | * |
638 | * @param delay when should this operation time out? | 665 | * @param delay when should this operation time out? |
639 | * @param rfd read file-descriptor | 666 | * @param rfd read file-descriptor |
@@ -656,6 +683,12 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, | |||
656 | * socket being ready. The task will be scheduled for execution once | 683 | * socket being ready. The task will be scheduled for execution once |
657 | * either the delay has expired or the socket operation is ready. It | 684 | * either the delay has expired or the socket operation is ready. It |
658 | * will be run with the DEFAULT priority. | 685 | * will be run with the DEFAULT priority. |
686 | * Only allowed to be called as long as the scheduler is running, that | ||
687 | * is one of the following conditions is met: | ||
688 | * | ||
689 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
690 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
691 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
659 | * | 692 | * |
660 | * @param delay when should this operation time out? | 693 | * @param delay when should this operation time out? |
661 | * @param priority priority to use for the task | 694 | * @param priority priority to use for the task |
@@ -678,9 +711,16 @@ GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, | |||
678 | * specified file descriptor is ready for writing. The delay can be | 711 | * specified file descriptor is ready for writing. The delay can be |
679 | * used as a timeout on the socket being ready. The task will be | 712 | * used as a timeout on the socket being ready. The task will be |
680 | * scheduled for execution once either the delay has expired or the | 713 | * scheduled for execution once either the delay has expired or the |
681 | * socket operation is ready. It will be run with the DEFAULT priority. | 714 | * socket operation is ready. It will be run with the priority of |
715 | * the calling task. | ||
716 | * Only allowed to be called as long as the scheduler is running, that | ||
717 | * is one of the following conditions is met: | ||
718 | * | ||
719 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
720 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
721 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
682 | * | 722 | * |
683 | * * @param delay when should this operation time out? | 723 | * @param delay when should this operation time out? |
684 | * @param wfd write file-descriptor | 724 | * @param wfd write file-descriptor |
685 | * @param task main function of the task | 725 | * @param task main function of the task |
686 | * @param task_cls closure of @a task | 726 | * @param task_cls closure of @a task |
@@ -700,6 +740,12 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay, | |||
700 | * used as a timeout on the socket being ready. The task will be | 740 | * used as a timeout on the socket being ready. The task will be |
701 | * scheduled for execution once either the delay has expired or the | 741 | * scheduled for execution once either the delay has expired or the |
702 | * socket operation is ready. | 742 | * socket operation is ready. |
743 | * Only allowed to be called as long as the scheduler is running, that | ||
744 | * is one of the following conditions is met: | ||
745 | * | ||
746 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
747 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
748 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
703 | * | 749 | * |
704 | * @param delay when should this operation time out? | 750 | * @param delay when should this operation time out? |
705 | * @param priority priority of the task | 751 | * @param priority priority of the task |
@@ -707,7 +753,7 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay, | |||
707 | * @param on_read whether to poll the file-descriptor for readability | 753 | * @param on_read whether to poll the file-descriptor for readability |
708 | * @param on_write whether to poll the file-descriptor for writability | 754 | * @param on_write whether to poll the file-descriptor for writability |
709 | * @param task main function of the task | 755 | * @param task main function of the task |
710 | * @param task_cls closure of @a task | 756 | * @param task_cls closure of task |
711 | * @return unique task identifier for the job | 757 | * @return unique task identifier for the job |
712 | * only valid until "task" is started! | 758 | * only valid until "task" is started! |
713 | */ | 759 | */ |
@@ -720,19 +766,26 @@ GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay, | |||
720 | GNUNET_SCHEDULER_TaskCallback task, | 766 | GNUNET_SCHEDULER_TaskCallback task, |
721 | void *task_cls); | 767 | void *task_cls); |
722 | 768 | ||
769 | |||
723 | /** | 770 | /** |
724 | * Schedule a new task to be run with a specified delay or when the | 771 | * Schedule a new task to be run with a specified delay or when the |
725 | * specified file descriptor is ready for reading. The delay can be | 772 | * specified file descriptor is ready for reading. The delay can be |
726 | * used as a timeout on the socket being ready. The task will be | 773 | * used as a timeout on the socket being ready. The task will be |
727 | * scheduled for execution once either the delay has expired or the | 774 | * scheduled for execution once either the delay has expired or the |
728 | * socket operation is ready. It will be run with the DEFAULT priority. | 775 | * socket operation is ready. It will be run with the DEFAULT priority. |
776 | * Only allowed to be called as long as the scheduler is running, that | ||
777 | * is one of the following conditions is met: | ||
778 | * | ||
779 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
780 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
781 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
729 | * | 782 | * |
730 | * * @param delay when should this operation time out? | 783 | * @param delay when should this operation time out? |
731 | * @param rfd read file-descriptor | 784 | * @param rfd read file-descriptor |
732 | * @param task main function of the task | 785 | * @param task main function of the task |
733 | * @param task_cls closure of @a task | 786 | * @param task_cls closure of @a task |
734 | * @return unique task identifier for the job | 787 | * @return unique task identifier for the job |
735 | * only valid until "task" is started! | 788 | * only valid until @a task is started! |
736 | */ | 789 | */ |
737 | struct GNUNET_SCHEDULER_Task * | 790 | struct GNUNET_SCHEDULER_Task * |
738 | GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay, | 791 | GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay, |
@@ -747,8 +800,14 @@ GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay, | |||
747 | * used as a timeout on the socket being ready. The task will be | 800 | * used as a timeout on the socket being ready. The task will be |
748 | * scheduled for execution once either the delay has expired or the | 801 | * scheduled for execution once either the delay has expired or the |
749 | * socket operation is ready. It will be run with the DEFAULT priority. | 802 | * socket operation is ready. It will be run with the DEFAULT priority. |
803 | * Only allowed to be called as long as the scheduler is running, that | ||
804 | * is one of the following conditions is met: | ||
805 | * | ||
806 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
807 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
808 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
750 | * | 809 | * |
751 | * * @param delay when should this operation time out? | 810 | * @param delay when should this operation time out? |
752 | * @param wfd write file-descriptor | 811 | * @param wfd write file-descriptor |
753 | * @param task main function of the task | 812 | * @param task main function of the task |
754 | * @param task_cls closure of @a task | 813 | * @param task_cls closure of @a task |
@@ -768,6 +827,12 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay, | |||
768 | * used as a timeout on the socket being ready. The task will be | 827 | * used as a timeout on the socket being ready. The task will be |
769 | * scheduled for execution once either the delay has expired or the | 828 | * scheduled for execution once either the delay has expired or the |
770 | * socket operation is ready. | 829 | * socket operation is ready. |
830 | * Only allowed to be called as long as the scheduler is running, that | ||
831 | * is one of the following conditions is met: | ||
832 | * | ||
833 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
834 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
835 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
771 | * | 836 | * |
772 | * @param delay when should this operation time out? | 837 | * @param delay when should this operation time out? |
773 | * @param priority priority of the task | 838 | * @param priority priority of the task |
@@ -801,8 +866,14 @@ GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay, | |||
801 | * (prerequisite-run) | 866 | * (prerequisite-run) |
802 | * && (delay-ready | 867 | * && (delay-ready |
803 | * || any-rs-ready | 868 | * || any-rs-ready |
804 | * || any-ws-ready) | 869 | * || any-ws-ready) ) |
805 | * </code> | 870 | * </code> |
871 | * Only allowed to be called as long as the scheduler is running, that | ||
872 | * is one of the following conditions is met: | ||
873 | * | ||
874 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
875 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
876 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
806 | * | 877 | * |
807 | * @param prio how important is this task? | 878 | * @param prio how important is this task? |
808 | * @param delay how long should we wait? | 879 | * @param delay how long should we wait? |
@@ -811,7 +882,7 @@ GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay, | |||
811 | * @param task main function of the task | 882 | * @param task main function of the task |
812 | * @param task_cls closure of @a task | 883 | * @param task_cls closure of @a task |
813 | * @return unique task identifier for the job | 884 | * @return unique task identifier for the job |
814 | * only valid until "task" is started! | 885 | * only valid until @a task is started! |
815 | */ | 886 | */ |
816 | struct GNUNET_SCHEDULER_Task * | 887 | struct GNUNET_SCHEDULER_Task * |
817 | GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, | 888 | GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, |
diff --git a/src/util/scheduler.c b/src/util/scheduler.c index 98334490b..05a951e19 100644 --- a/src/util/scheduler.c +++ b/src/util/scheduler.c | |||
@@ -73,7 +73,7 @@ | |||
73 | 73 | ||
74 | /** | 74 | /** |
75 | * Argument to be passed from the driver to | 75 | * Argument to be passed from the driver to |
76 | * #GNUNET_SCHEDULER_run_from_driver(). Contains the | 76 | * #GNUNET_SCHEDULER_do_work(). Contains the |
77 | * scheduler's internal state. | 77 | * scheduler's internal state. |
78 | */ | 78 | */ |
79 | struct GNUNET_SCHEDULER_Handle | 79 | struct GNUNET_SCHEDULER_Handle |
@@ -91,6 +91,40 @@ struct GNUNET_SCHEDULER_Handle | |||
91 | * @deprecated | 91 | * @deprecated |
92 | */ | 92 | */ |
93 | struct GNUNET_NETWORK_FDSet *ws; | 93 | struct GNUNET_NETWORK_FDSet *ws; |
94 | |||
95 | /** | ||
96 | * context of the SIGINT handler | ||
97 | */ | ||
98 | struct GNUNET_SIGNAL_Context *shc_int; | ||
99 | |||
100 | /** | ||
101 | * context of the SIGTERM handler | ||
102 | */ | ||
103 | struct GNUNET_SIGNAL_Context *shc_term; | ||
104 | |||
105 | #if (SIGTERM != GNUNET_TERM_SIG) | ||
106 | /** | ||
107 | * context of the TERM_SIG handler | ||
108 | */ | ||
109 | struct GNUNET_SIGNAL_Context *shc_gterm; | ||
110 | #endif | ||
111 | |||
112 | #ifndef MINGW | ||
113 | /** | ||
114 | * context of the SIGQUIT handler | ||
115 | */ | ||
116 | struct GNUNET_SIGNAL_Context *shc_quit; | ||
117 | |||
118 | /** | ||
119 | * context of the SIGHUP handler | ||
120 | */ | ||
121 | struct GNUNET_SIGNAL_Context *shc_hup; | ||
122 | |||
123 | /** | ||
124 | * context of hte SIGPIPE handler | ||
125 | */ | ||
126 | struct GNUNET_SIGNAL_Context *shc_pipe; | ||
127 | #endif | ||
94 | }; | 128 | }; |
95 | 129 | ||
96 | 130 | ||
@@ -265,7 +299,7 @@ struct DriverContext | |||
265 | 299 | ||
266 | /** | 300 | /** |
267 | * The driver used for the event loop. Will be handed over to | 301 | * The driver used for the event loop. Will be handed over to |
268 | * the scheduler in #GNUNET_SCHEDULER_run_from_driver(), peristed | 302 | * the scheduler in #GNUNET_SCHEDULER_do_work(), persisted |
269 | * there in this variable for later use in functions like | 303 | * there in this variable for later use in functions like |
270 | * #GNUNET_SCHEDULER_add_select(), #add_without_sets() and | 304 | * #GNUNET_SCHEDULER_add_select(), #add_without_sets() and |
271 | * #GNUNET_SCHEDULER_cancel(). | 305 | * #GNUNET_SCHEDULER_cancel(). |
@@ -382,11 +416,6 @@ static struct GNUNET_SCHEDULER_TaskContext tc; | |||
382 | */ | 416 | */ |
383 | static void *scheduler_select_cls; | 417 | static void *scheduler_select_cls; |
384 | 418 | ||
385 | /** | ||
386 | * Scheduler handle used for the driver functions | ||
387 | */ | ||
388 | static struct GNUNET_SCHEDULER_Handle sh; | ||
389 | |||
390 | 419 | ||
391 | /** | 420 | /** |
392 | * Sets the select function to use in the scheduler (scheduler_select). | 421 | * Sets the select function to use in the scheduler (scheduler_select). |
@@ -659,6 +688,10 @@ shutdown_if_no_lifeness () | |||
659 | } | 688 | } |
660 | 689 | ||
661 | 690 | ||
691 | int | ||
692 | select_loop (struct GNUNET_SCHEDULER_Handle *sh, struct DriverContext *context); | ||
693 | |||
694 | |||
662 | /** | 695 | /** |
663 | * Initialize and run scheduler. This function will return when all | 696 | * Initialize and run scheduler. This function will return when all |
664 | * tasks have completed. On systems with signals, receiving a SIGTERM | 697 | * tasks have completed. On systems with signals, receiving a SIGTERM |
@@ -677,16 +710,21 @@ void | |||
677 | GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task, | 710 | GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task, |
678 | void *task_cls) | 711 | void *task_cls) |
679 | { | 712 | { |
713 | struct GNUNET_SCHEDULER_Handle *sh; | ||
680 | struct GNUNET_SCHEDULER_Driver *driver; | 714 | struct GNUNET_SCHEDULER_Driver *driver; |
681 | struct DriverContext context = {.scheduled_head = NULL, | 715 | struct DriverContext context = {.scheduled_head = NULL, |
682 | .scheduled_tail = NULL, | 716 | .scheduled_tail = NULL, |
683 | .timeout = GNUNET_TIME_UNIT_FOREVER_ABS}; | 717 | .timeout = GNUNET_TIME_absolute_get ()}; |
684 | 718 | ||
685 | driver = GNUNET_SCHEDULER_driver_select (); | 719 | driver = GNUNET_SCHEDULER_driver_select (); |
686 | driver->cls = &context; | 720 | driver->cls = &context; |
687 | 721 | sh = GNUNET_SCHEDULER_driver_init (driver); | |
688 | GNUNET_SCHEDULER_run_with_driver (driver, task, task_cls); | 722 | GNUNET_SCHEDULER_add_with_reason_and_priority (task, |
689 | 723 | task_cls, | |
724 | GNUNET_SCHEDULER_REASON_STARTUP, | ||
725 | GNUNET_SCHEDULER_PRIORITY_DEFAULT); | ||
726 | select_loop (sh, &context); | ||
727 | GNUNET_SCHEDULER_driver_done (sh); | ||
690 | GNUNET_free (driver); | 728 | GNUNET_free (driver); |
691 | } | 729 | } |
692 | 730 | ||
@@ -900,8 +938,11 @@ shutdown_pipe_cb (void *cls) | |||
900 | /** | 938 | /** |
901 | * Cancel the task with the specified identifier. | 939 | * Cancel the task with the specified identifier. |
902 | * The task must not yet have run. Only allowed to be called as long as the | 940 | * The task must not yet have run. Only allowed to be called as long as the |
903 | * scheduler is running (#GNUNET_SCHEDULER_run or | 941 | * scheduler is running, that is one of the following conditions is met: |
904 | * #GNUNET_SCHEDULER_run_with_driver has been called and has not returned yet). | 942 | * |
943 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
944 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
945 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
905 | * | 946 | * |
906 | * @param task id of the task to cancel | 947 | * @param task id of the task to cancel |
907 | * @return original closure of the task | 948 | * @return original closure of the task |
@@ -1401,9 +1442,12 @@ add_without_sets (struct GNUNET_TIME_Relative delay, | |||
1401 | * used as a timeout on the socket being ready. The task will be | 1442 | * used as a timeout on the socket being ready. The task will be |
1402 | * scheduled for execution once either the delay has expired or the | 1443 | * scheduled for execution once either the delay has expired or the |
1403 | * socket operation is ready. It will be run with the DEFAULT priority. | 1444 | * socket operation is ready. It will be run with the DEFAULT priority. |
1404 | * Only allowed to be called as long as the scheduler is running | 1445 | * Only allowed to be called as long as the scheduler is running, that |
1405 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | 1446 | * is one of the following conditions is met: |
1406 | * called and has not returned yet). | 1447 | * |
1448 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
1449 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
1450 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
1407 | * | 1451 | * |
1408 | * @param delay when should this operation time out? | 1452 | * @param delay when should this operation time out? |
1409 | * @param rfd read file-descriptor | 1453 | * @param rfd read file-descriptor |
@@ -1431,9 +1475,12 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, | |||
1431 | * socket being ready. The task will be scheduled for execution once | 1475 | * socket being ready. The task will be scheduled for execution once |
1432 | * either the delay has expired or the socket operation is ready. It | 1476 | * either the delay has expired or the socket operation is ready. It |
1433 | * will be run with the DEFAULT priority. | 1477 | * will be run with the DEFAULT priority. |
1434 | * Only allowed to be called as long as the scheduler is running | 1478 | * Only allowed to be called as long as the scheduler is running, that |
1435 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | 1479 | * is one of the following conditions is met: |
1436 | * called and has not returned yet). | 1480 | * |
1481 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
1482 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
1483 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
1437 | * | 1484 | * |
1438 | * @param delay when should this operation time out? | 1485 | * @param delay when should this operation time out? |
1439 | * @param priority priority to use for the task | 1486 | * @param priority priority to use for the task |
@@ -1465,9 +1512,12 @@ GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, | |||
1465 | * scheduled for execution once either the delay has expired or the | 1512 | * scheduled for execution once either the delay has expired or the |
1466 | * socket operation is ready. It will be run with the priority of | 1513 | * socket operation is ready. It will be run with the priority of |
1467 | * the calling task. | 1514 | * the calling task. |
1468 | * Only allowed to be called as long as the scheduler is running | 1515 | * Only allowed to be called as long as the scheduler is running, that |
1469 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | 1516 | * is one of the following conditions is met: |
1470 | * called and has not returned yet). | 1517 | * |
1518 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
1519 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
1520 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
1471 | * | 1521 | * |
1472 | * @param delay when should this operation time out? | 1522 | * @param delay when should this operation time out? |
1473 | * @param wfd write file-descriptor | 1523 | * @param wfd write file-descriptor |
@@ -1495,9 +1545,12 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay, | |||
1495 | * used as a timeout on the socket being ready. The task will be | 1545 | * used as a timeout on the socket being ready. The task will be |
1496 | * scheduled for execution once either the delay has expired or the | 1546 | * scheduled for execution once either the delay has expired or the |
1497 | * socket operation is ready. | 1547 | * socket operation is ready. |
1498 | * Only allowed to be called as long as the scheduler is running | 1548 | * Only allowed to be called as long as the scheduler is running, that |
1499 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | 1549 | * is one of the following conditions is met: |
1500 | * called and has not returned yet). | 1550 | * |
1551 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
1552 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
1553 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
1501 | * | 1554 | * |
1502 | * @param delay when should this operation time out? | 1555 | * @param delay when should this operation time out? |
1503 | * @param priority priority of the task | 1556 | * @param priority priority of the task |
@@ -1554,9 +1607,12 @@ GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay, | |||
1554 | * used as a timeout on the socket being ready. The task will be | 1607 | * used as a timeout on the socket being ready. The task will be |
1555 | * scheduled for execution once either the delay has expired or the | 1608 | * scheduled for execution once either the delay has expired or the |
1556 | * socket operation is ready. It will be run with the DEFAULT priority. | 1609 | * socket operation is ready. It will be run with the DEFAULT priority. |
1557 | * Only allowed to be called as long as the scheduler is running | 1610 | * Only allowed to be called as long as the scheduler is running, that |
1558 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | 1611 | * is one of the following conditions is met: |
1559 | * called and has not returned yet). | 1612 | * |
1613 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
1614 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
1615 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
1560 | * | 1616 | * |
1561 | * @param delay when should this operation time out? | 1617 | * @param delay when should this operation time out? |
1562 | * @param rfd read file-descriptor | 1618 | * @param rfd read file-descriptor |
@@ -1583,9 +1639,12 @@ GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay, | |||
1583 | * used as a timeout on the socket being ready. The task will be | 1639 | * used as a timeout on the socket being ready. The task will be |
1584 | * scheduled for execution once either the delay has expired or the | 1640 | * scheduled for execution once either the delay has expired or the |
1585 | * socket operation is ready. It will be run with the DEFAULT priority. | 1641 | * socket operation is ready. It will be run with the DEFAULT priority. |
1586 | * Only allowed to be called as long as the scheduler is running | 1642 | * Only allowed to be called as long as the scheduler is running, that |
1587 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | 1643 | * is one of the following conditions is met: |
1588 | * called and has not returned yet). | 1644 | * |
1645 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
1646 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
1647 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
1589 | * | 1648 | * |
1590 | * @param delay when should this operation time out? | 1649 | * @param delay when should this operation time out? |
1591 | * @param wfd write file-descriptor | 1650 | * @param wfd write file-descriptor |
@@ -1612,9 +1671,12 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay, | |||
1612 | * used as a timeout on the socket being ready. The task will be | 1671 | * used as a timeout on the socket being ready. The task will be |
1613 | * scheduled for execution once either the delay has expired or the | 1672 | * scheduled for execution once either the delay has expired or the |
1614 | * socket operation is ready. | 1673 | * socket operation is ready. |
1615 | * Only allowed to be called as long as the scheduler is running | 1674 | * Only allowed to be called as long as the scheduler is running, that |
1616 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | 1675 | * is one of the following conditions is met: |
1617 | * called and has not returned yet). | 1676 | * |
1677 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
1678 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
1679 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
1618 | * | 1680 | * |
1619 | * @param delay when should this operation time out? | 1681 | * @param delay when should this operation time out? |
1620 | * @param priority priority of the task | 1682 | * @param priority priority of the task |
@@ -1729,9 +1791,12 @@ extract_handles (const struct GNUNET_NETWORK_FDSet *fdset, | |||
1729 | * || any-rs-ready | 1791 | * || any-rs-ready |
1730 | * || any-ws-ready) ) | 1792 | * || any-ws-ready) ) |
1731 | * </code> | 1793 | * </code> |
1732 | * Only allowed to be called as long as the scheduler is running | 1794 | * Only allowed to be called as long as the scheduler is running, that |
1733 | * (#GNUNET_SCHEDULER_run or #GNUNET_SCHEDULER_run_with_driver has been | 1795 | * is one of the following conditions is met: |
1734 | * called and has not returned yet). | 1796 | * |
1797 | * - #GNUNET_SCHEDULER_run has been called and has not returned yet | ||
1798 | * - #GNUNET_SCHEDULER_driver_init has been run and | ||
1799 | * #GNUNET_SCHEDULER_driver_done has not been called yet | ||
1735 | * | 1800 | * |
1736 | * @param prio how important is this task? | 1801 | * @param prio how important is this task? |
1737 | * @param delay how long should we wait? | 1802 | * @param delay how long should we wait? |
@@ -1886,23 +1951,27 @@ GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, | |||
1886 | 1951 | ||
1887 | 1952 | ||
1888 | /** | 1953 | /** |
1889 | * Function called by the driver to tell the scheduler to run some of | 1954 | * Function called by external event loop implementations to tell the |
1890 | * the tasks that are ready. This function may return even though | 1955 | * scheduler to run some of the tasks that are ready. Must be called |
1891 | * there are tasks left to run just to give other tasks a chance as | 1956 | * only after #GNUNET_SCHEDULER_driver_init has been called and before |
1892 | * well. If we return #GNUNET_YES, the driver should call this | 1957 | * #GNUNET_SCHEDULER_driver_done is called. |
1893 | * function again as soon as possible, while if we return #GNUNET_NO | 1958 | * This function may return even though there are tasks left to run |
1894 | * it must block until either the operating system has more work (the | 1959 | * just to give other tasks a chance as well. If we return #GNUNET_YES, |
1895 | * scheduler has no more work to do right now) or the timeout set by | 1960 | * the event loop implementation should call this function again as |
1896 | * the scheduler (using the set_wakeup callback) is reached. | 1961 | * soon as possible, while if we return #GNUNET_NO it must block until |
1962 | * either the operating system has more work (the scheduler has no more | ||
1963 | * work to do right now) or the timeout set by the scheduler (using the | ||
1964 | * set_wakeup callback) is reached. | ||
1897 | * | 1965 | * |
1898 | * @param sh scheduler handle that was given to the `loop` | 1966 | * @param sh scheduler handle that was returned by |
1967 | * #GNUNET_SCHEDULER_driver_init | ||
1899 | * @return #GNUNET_YES if there are more tasks that are ready, | 1968 | * @return #GNUNET_YES if there are more tasks that are ready, |
1900 | * and thus we would like to run more (yield to avoid | 1969 | * and thus we would like to run more (yield to avoid |
1901 | * blocking other activities for too long) | 1970 | * blocking other activities for too long) #GNUNET_NO |
1902 | * #GNUNET_NO if we are done running tasks (yield to block) | 1971 | * if we are done running tasks (yield to block) |
1903 | */ | 1972 | */ |
1904 | int | 1973 | int |
1905 | GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | 1974 | GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh) |
1906 | { | 1975 | { |
1907 | enum GNUNET_SCHEDULER_Priority p; | 1976 | enum GNUNET_SCHEDULER_Priority p; |
1908 | struct GNUNET_SCHEDULER_Task *pos; | 1977 | struct GNUNET_SCHEDULER_Task *pos; |
@@ -1955,7 +2024,7 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1955 | * also be a programming error in the driver though. | 2024 | * also be a programming error in the driver though. |
1956 | */ | 2025 | */ |
1957 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 2026 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
1958 | "GNUNET_SCHEDULER_run_from_driver did not find any ready " | 2027 | "GNUNET_SCHEDULER_do_work did not find any ready " |
1959 | "tasks and timeout has not been reached yet."); | 2028 | "tasks and timeout has not been reached yet."); |
1960 | return GNUNET_NO; | 2029 | return GNUNET_NO; |
1961 | } | 2030 | } |
@@ -2056,43 +2125,46 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
2056 | 2125 | ||
2057 | 2126 | ||
2058 | /** | 2127 | /** |
2059 | * Initialize and run scheduler. This function will return when all | 2128 | * Function called by external event loop implementations to initialize |
2060 | * tasks have completed. On systems with signals, receiving a SIGTERM | 2129 | * the scheduler. An external implementation has to provide @a driver |
2061 | * (and other similar signals) will cause #GNUNET_SCHEDULER_shutdown | 2130 | * which contains callbacks for the scheduler (see definition of struct |
2062 | * to be run after the active task is complete. As a result, SIGTERM | 2131 | * #GNUNET_SCHEDULER_Driver) for instructing the external implementation |
2063 | * causes all shutdown tasks to be scheduled with reason | 2132 | * to watch for events. If it detects any event it is expected to call |
2064 | * #GNUNET_SCHEDULER_REASON_SHUTDOWN. (However, tasks added | 2133 | * #GNUNET_SCHEDULER_do_work to let the scheduler handle it. If an event |
2065 | * afterwards will execute normally!). Note that any particular | 2134 | * is related to a specific task (e.g. the scheduler gave instructions |
2066 | * signal will only shut down one scheduler; applications should | 2135 | * to watch a file descriptor), the external implementation is expected |
2067 | * always only create a single scheduler. | 2136 | * to mark that task ready before by calling #GNUNET_SCHEDULER_task_ready. |
2137 | |||
2138 | * This function has to be called before any tasks are scheduled and | ||
2139 | * before GNUNET_SCHEDULER_do_work is called for the first time. It | ||
2140 | * allocates resources that have to be freed again by calling | ||
2141 | * #GNUNET_SCHEDULER_driver_done. | ||
2068 | * | 2142 | * |
2069 | * @param driver drive to use for the event loop | 2143 | * This function installs the same signal handlers as |
2070 | * @param task task to run first (and immediately) | 2144 | * #GNUNET_SCHEDULER_run. This means SIGTERM (and other similar signals) |
2071 | * @param task_cls closure of @a task | 2145 | * will induce a call to #GNUNET_SCHEDULER_shutdown during the next |
2072 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | 2146 | * call to #GNUNET_SCHEDULER_do_work. As a result, SIGTERM causes all |
2147 | * active tasks to be scheduled with reason | ||
2148 | * #GNUNET_SCHEDULER_REASON_SHUTDOWN. (However, tasks added afterwards | ||
2149 | * will execute normally!). Note that any particular signal will only | ||
2150 | * shut down one scheduler; applications should always only create a | ||
2151 | * single scheduler. | ||
2152 | * | ||
2153 | * @param driver to use for the event loop | ||
2154 | * @return handle to be passed to #GNUNET_SCHEDULER_do_work and | ||
2155 | * #GNUNET_SCHEDULER_driver_done | ||
2073 | */ | 2156 | */ |
2074 | int | 2157 | struct GNUNET_SCHEDULER_Handle * |
2075 | GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | 2158 | GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver) |
2076 | GNUNET_SCHEDULER_TaskCallback task, | ||
2077 | void *task_cls) | ||
2078 | { | 2159 | { |
2079 | int ret; | 2160 | struct GNUNET_SCHEDULER_Handle *sh; |
2080 | struct GNUNET_SIGNAL_Context *shc_int; | ||
2081 | struct GNUNET_SIGNAL_Context *shc_term; | ||
2082 | #if (SIGTERM != GNUNET_TERM_SIG) | ||
2083 | struct GNUNET_SIGNAL_Context *shc_gterm; | ||
2084 | #endif | ||
2085 | #ifndef MINGW | ||
2086 | struct GNUNET_SIGNAL_Context *shc_quit; | ||
2087 | struct GNUNET_SIGNAL_Context *shc_hup; | ||
2088 | struct GNUNET_SIGNAL_Context *shc_pipe; | ||
2089 | #endif | ||
2090 | struct GNUNET_SCHEDULER_Task tsk; | 2161 | struct GNUNET_SCHEDULER_Task tsk; |
2091 | const struct GNUNET_DISK_FileHandle *pr; | 2162 | const struct GNUNET_DISK_FileHandle *pr; |
2092 | 2163 | ||
2093 | /* general set-up */ | 2164 | /* general set-up */ |
2094 | GNUNET_assert (NULL == active_task); | 2165 | GNUNET_assert (NULL == active_task); |
2095 | GNUNET_assert (NULL == shutdown_pipe_handle); | 2166 | GNUNET_assert (NULL == shutdown_pipe_handle); |
2167 | sh = GNUNET_new (struct GNUNET_SCHEDULER_Handle); | ||
2096 | shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, | 2168 | shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, |
2097 | GNUNET_NO, | 2169 | GNUNET_NO, |
2098 | GNUNET_NO, | 2170 | GNUNET_NO, |
@@ -2106,21 +2178,21 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
2106 | /* install signal handlers */ | 2178 | /* install signal handlers */ |
2107 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 2179 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2108 | "Registering signal handlers\n"); | 2180 | "Registering signal handlers\n"); |
2109 | shc_int = GNUNET_SIGNAL_handler_install (SIGINT, | 2181 | sh->shc_int = GNUNET_SIGNAL_handler_install (SIGINT, |
2110 | &sighandler_shutdown); | 2182 | &sighandler_shutdown); |
2111 | shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, | 2183 | sh->shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, |
2112 | &sighandler_shutdown); | 2184 | &sighandler_shutdown); |
2113 | #if (SIGTERM != GNUNET_TERM_SIG) | 2185 | #if (SIGTERM != GNUNET_TERM_SIG) |
2114 | shc_gterm = GNUNET_SIGNAL_handler_install (GNUNET_TERM_SIG, | 2186 | sh->shc_gterm = GNUNET_SIGNAL_handler_install (GNUNET_TERM_SIG, |
2115 | &sighandler_shutdown); | 2187 | &sighandler_shutdown); |
2116 | #endif | 2188 | #endif |
2117 | #ifndef MINGW | 2189 | #ifndef MINGW |
2118 | shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE, | 2190 | sh->shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE, |
2119 | &sighandler_pipe); | 2191 | &sighandler_pipe); |
2120 | shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, | 2192 | sh->shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, |
2121 | &sighandler_shutdown); | 2193 | &sighandler_shutdown); |
2122 | shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, | 2194 | sh->shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, |
2123 | &sighandler_shutdown); | 2195 | &sighandler_shutdown); |
2124 | #endif | 2196 | #endif |
2125 | 2197 | ||
2126 | /* Setup initial tasks */ | 2198 | /* Setup initial tasks */ |
@@ -2139,19 +2211,33 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
2139 | &shutdown_pipe_cb, | 2211 | &shutdown_pipe_cb, |
2140 | NULL); | 2212 | NULL); |
2141 | current_lifeness = GNUNET_YES; | 2213 | current_lifeness = GNUNET_YES; |
2142 | GNUNET_SCHEDULER_add_with_reason_and_priority (task, | ||
2143 | task_cls, | ||
2144 | GNUNET_SCHEDULER_REASON_STARTUP, | ||
2145 | GNUNET_SCHEDULER_PRIORITY_DEFAULT); | ||
2146 | active_task = NULL; | 2214 | active_task = NULL; |
2147 | scheduler_driver->set_wakeup (scheduler_driver->cls, | 2215 | scheduler_driver->set_wakeup (scheduler_driver->cls, |
2148 | get_timeout ()); | 2216 | get_timeout ()); |
2149 | /* begin main event loop */ | 2217 | /* begin main event loop */ |
2150 | sh.rs = GNUNET_NETWORK_fdset_create (); | 2218 | sh->rs = GNUNET_NETWORK_fdset_create (); |
2151 | sh.ws = GNUNET_NETWORK_fdset_create (); | 2219 | sh->ws = GNUNET_NETWORK_fdset_create (); |
2152 | GNUNET_NETWORK_fdset_handle_set (sh.rs, pr); | 2220 | GNUNET_NETWORK_fdset_handle_set (sh->rs, pr); |
2153 | ret = driver->loop (driver->cls, | 2221 | return sh; |
2154 | &sh); | 2222 | } |
2223 | |||
2224 | |||
2225 | /** | ||
2226 | * Counter-part of #GNUNET_SCHEDULER_driver_init. Has to be called | ||
2227 | * by external event loop implementations after the scheduler has | ||
2228 | * shut down. This is the case if both of the following conditions | ||
2229 | * are met: | ||
2230 | * | ||
2231 | * - all tasks the scheduler has added through the driver's add | ||
2232 | * callback have been removed again through the driver's del | ||
2233 | * callback | ||
2234 | * - the timeout the scheduler has set through the driver's | ||
2235 | * add_wakeup callback is FOREVER | ||
2236 | * | ||
2237 | * @param sh the handle returned by #GNUNET_SCHEDULER_driver_init | ||
2238 | */ | ||
2239 | void GNUNET_SCHEDULER_driver_done (struct GNUNET_SCHEDULER_Handle *sh) | ||
2240 | { | ||
2155 | GNUNET_assert (NULL == pending_head); | 2241 | GNUNET_assert (NULL == pending_head); |
2156 | GNUNET_assert (NULL == pending_timeout_head); | 2242 | GNUNET_assert (NULL == pending_timeout_head); |
2157 | GNUNET_assert (NULL == shutdown_head); | 2243 | GNUNET_assert (NULL == shutdown_head); |
@@ -2159,97 +2245,34 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
2159 | { | 2245 | { |
2160 | GNUNET_assert (NULL == ready_head[i]); | 2246 | GNUNET_assert (NULL == ready_head[i]); |
2161 | } | 2247 | } |
2162 | GNUNET_NETWORK_fdset_destroy (sh.rs); | 2248 | GNUNET_NETWORK_fdset_destroy (sh->rs); |
2163 | GNUNET_NETWORK_fdset_destroy (sh.ws); | 2249 | GNUNET_NETWORK_fdset_destroy (sh->ws); |
2164 | 2250 | ||
2165 | /* uninstall signal handlers */ | 2251 | /* uninstall signal handlers */ |
2166 | GNUNET_SIGNAL_handler_uninstall (shc_int); | 2252 | GNUNET_SIGNAL_handler_uninstall (sh->shc_int); |
2167 | GNUNET_SIGNAL_handler_uninstall (shc_term); | 2253 | GNUNET_SIGNAL_handler_uninstall (sh->shc_term); |
2168 | #if (SIGTERM != GNUNET_TERM_SIG) | 2254 | #if (SIGTERM != GNUNET_TERM_SIG) |
2169 | GNUNET_SIGNAL_handler_uninstall (shc_gterm); | 2255 | GNUNET_SIGNAL_handler_uninstall (sh->shc_gterm); |
2170 | #endif | 2256 | #endif |
2171 | #ifndef MINGW | 2257 | #ifndef MINGW |
2172 | GNUNET_SIGNAL_handler_uninstall (shc_pipe); | 2258 | GNUNET_SIGNAL_handler_uninstall (sh->shc_pipe); |
2173 | GNUNET_SIGNAL_handler_uninstall (shc_quit); | 2259 | GNUNET_SIGNAL_handler_uninstall (sh->shc_quit); |
2174 | GNUNET_SIGNAL_handler_uninstall (shc_hup); | 2260 | GNUNET_SIGNAL_handler_uninstall (sh->shc_hup); |
2175 | #endif | 2261 | #endif |
2176 | GNUNET_DISK_pipe_close (shutdown_pipe_handle); | 2262 | GNUNET_DISK_pipe_close (shutdown_pipe_handle); |
2177 | shutdown_pipe_handle = NULL; | 2263 | shutdown_pipe_handle = NULL; |
2178 | scheduler_driver = NULL; | 2264 | scheduler_driver = NULL; |
2179 | return ret; | 2265 | GNUNET_free (sh); |
2180 | } | ||
2181 | |||
2182 | |||
2183 | int | ||
2184 | select_add (void *cls, | ||
2185 | struct GNUNET_SCHEDULER_Task *task, | ||
2186 | struct GNUNET_SCHEDULER_FdInfo *fdi) | ||
2187 | { | ||
2188 | struct DriverContext *context = cls; | ||
2189 | GNUNET_assert (NULL != context); | ||
2190 | GNUNET_assert (NULL != task); | ||
2191 | GNUNET_assert (NULL != fdi); | ||
2192 | GNUNET_assert (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et) || | ||
2193 | 0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)); | ||
2194 | |||
2195 | if (!((NULL != fdi->fd) ^ (NULL != fdi->fh)) || (fdi->sock < 0)) | ||
2196 | { | ||
2197 | /* exactly one out of {fd, hf} must be != NULL and the OS handle must be valid */ | ||
2198 | return GNUNET_SYSERR; | ||
2199 | } | ||
2200 | |||
2201 | struct Scheduled *scheduled = GNUNET_new (struct Scheduled); | ||
2202 | scheduled->task = task; | ||
2203 | scheduled->fdi = fdi; | ||
2204 | scheduled->et = fdi->et; | ||
2205 | |||
2206 | GNUNET_CONTAINER_DLL_insert (context->scheduled_head, | ||
2207 | context->scheduled_tail, | ||
2208 | scheduled); | ||
2209 | return GNUNET_OK; | ||
2210 | } | 2266 | } |
2211 | 2267 | ||
2212 | 2268 | ||
2213 | int | 2269 | int |
2214 | select_del (void *cls, | 2270 | select_loop (struct GNUNET_SCHEDULER_Handle *sh, struct DriverContext *context) |
2215 | struct GNUNET_SCHEDULER_Task *task) | ||
2216 | { | ||
2217 | struct DriverContext *context; | ||
2218 | struct Scheduled *pos; | ||
2219 | int ret; | ||
2220 | |||
2221 | GNUNET_assert (NULL != cls); | ||
2222 | |||
2223 | context = cls; | ||
2224 | ret = GNUNET_SYSERR; | ||
2225 | pos = context->scheduled_head; | ||
2226 | while (NULL != pos) | ||
2227 | { | ||
2228 | struct Scheduled *next = pos->next; | ||
2229 | if (pos->task == task) | ||
2230 | { | ||
2231 | GNUNET_CONTAINER_DLL_remove (context->scheduled_head, | ||
2232 | context->scheduled_tail, | ||
2233 | pos); | ||
2234 | GNUNET_free (pos); | ||
2235 | ret = GNUNET_OK; | ||
2236 | } | ||
2237 | pos = next; | ||
2238 | } | ||
2239 | return ret; | ||
2240 | } | ||
2241 | |||
2242 | |||
2243 | int | ||
2244 | select_loop (void *cls, | ||
2245 | struct GNUNET_SCHEDULER_Handle *sh) | ||
2246 | { | 2271 | { |
2247 | struct GNUNET_NETWORK_FDSet *rs; | 2272 | struct GNUNET_NETWORK_FDSet *rs; |
2248 | struct GNUNET_NETWORK_FDSet *ws; | 2273 | struct GNUNET_NETWORK_FDSet *ws; |
2249 | struct DriverContext *context; | ||
2250 | int select_result; | 2274 | int select_result; |
2251 | 2275 | ||
2252 | context = cls; | ||
2253 | GNUNET_assert (NULL != context); | 2276 | GNUNET_assert (NULL != context); |
2254 | rs = GNUNET_NETWORK_fdset_create (); | 2277 | rs = GNUNET_NETWORK_fdset_create (); |
2255 | ws = GNUNET_NETWORK_fdset_create (); | 2278 | ws = GNUNET_NETWORK_fdset_create (); |
@@ -2350,7 +2373,7 @@ select_loop (void *cls, | |||
2350 | } | 2373 | } |
2351 | } | 2374 | } |
2352 | } | 2375 | } |
2353 | if (GNUNET_YES == GNUNET_SCHEDULER_run_from_driver (sh)) | 2376 | if (GNUNET_YES == GNUNET_SCHEDULER_do_work (sh)) |
2354 | { | 2377 | { |
2355 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2378 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
2356 | "scheduler has more tasks ready!\n"); | 2379 | "scheduler has more tasks ready!\n"); |
@@ -2362,6 +2385,66 @@ select_loop (void *cls, | |||
2362 | } | 2385 | } |
2363 | 2386 | ||
2364 | 2387 | ||
2388 | int | ||
2389 | select_add (void *cls, | ||
2390 | struct GNUNET_SCHEDULER_Task *task, | ||
2391 | struct GNUNET_SCHEDULER_FdInfo *fdi) | ||
2392 | { | ||
2393 | struct DriverContext *context = cls; | ||
2394 | GNUNET_assert (NULL != context); | ||
2395 | GNUNET_assert (NULL != task); | ||
2396 | GNUNET_assert (NULL != fdi); | ||
2397 | GNUNET_assert (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et) || | ||
2398 | 0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)); | ||
2399 | |||
2400 | if (!((NULL != fdi->fd) ^ (NULL != fdi->fh)) || (fdi->sock < 0)) | ||
2401 | { | ||
2402 | /* exactly one out of {fd, hf} must be != NULL and the OS handle must be valid */ | ||
2403 | return GNUNET_SYSERR; | ||
2404 | } | ||
2405 | |||
2406 | struct Scheduled *scheduled = GNUNET_new (struct Scheduled); | ||
2407 | scheduled->task = task; | ||
2408 | scheduled->fdi = fdi; | ||
2409 | scheduled->et = fdi->et; | ||
2410 | |||
2411 | GNUNET_CONTAINER_DLL_insert (context->scheduled_head, | ||
2412 | context->scheduled_tail, | ||
2413 | scheduled); | ||
2414 | return GNUNET_OK; | ||
2415 | } | ||
2416 | |||
2417 | |||
2418 | int | ||
2419 | select_del (void *cls, | ||
2420 | struct GNUNET_SCHEDULER_Task *task) | ||
2421 | { | ||
2422 | struct DriverContext *context; | ||
2423 | struct Scheduled *pos; | ||
2424 | int ret; | ||
2425 | |||
2426 | GNUNET_assert (NULL != cls); | ||
2427 | |||
2428 | context = cls; | ||
2429 | ret = GNUNET_SYSERR; | ||
2430 | pos = context->scheduled_head; | ||
2431 | while (NULL != pos) | ||
2432 | { | ||
2433 | struct Scheduled *next = pos->next; | ||
2434 | if (pos->task == task) | ||
2435 | { | ||
2436 | GNUNET_CONTAINER_DLL_remove (context->scheduled_head, | ||
2437 | context->scheduled_tail, | ||
2438 | pos); | ||
2439 | GNUNET_free (pos); | ||
2440 | ret = GNUNET_OK; | ||
2441 | } | ||
2442 | pos = next; | ||
2443 | } | ||
2444 | return ret; | ||
2445 | } | ||
2446 | |||
2447 | |||
2365 | void | 2448 | void |
2366 | select_set_wakeup (void *cls, | 2449 | select_set_wakeup (void *cls, |
2367 | struct GNUNET_TIME_Absolute dt) | 2450 | struct GNUNET_TIME_Absolute dt) |
@@ -2384,7 +2467,6 @@ GNUNET_SCHEDULER_driver_select () | |||
2384 | struct GNUNET_SCHEDULER_Driver *select_driver; | 2467 | struct GNUNET_SCHEDULER_Driver *select_driver; |
2385 | select_driver = GNUNET_new (struct GNUNET_SCHEDULER_Driver); | 2468 | select_driver = GNUNET_new (struct GNUNET_SCHEDULER_Driver); |
2386 | 2469 | ||
2387 | select_driver->loop = &select_loop; | ||
2388 | select_driver->add = &select_add; | 2470 | select_driver->add = &select_add; |
2389 | select_driver->del = &select_del; | 2471 | select_driver->del = &select_del; |
2390 | select_driver->set_wakeup = &select_set_wakeup; | 2472 | select_driver->set_wakeup = &select_set_wakeup; |