summaryrefslogtreecommitdiff
path: root/src/util/scheduler.c
diff options
context:
space:
mode:
authorlurchi <lurchi@strangeplace.net>2018-02-01 19:54:54 +0100
committerlurchi <lurchi@strangeplace.net>2018-02-01 19:55:15 +0100
commit89d1b38101ea52dfe7ef20ab8f6604a6f973bbbd (patch)
tree5af6e4158cb3d996ed0e68abe0216d62ce4d6a86 /src/util/scheduler.c
parentb3fdd5716f3e0622508e68450516d11a6d55a0ab (diff)
downloadgnunet-89d1b38101ea52dfe7ef20ab8f6604a6f973bbbd.tar.gz
gnunet-89d1b38101ea52dfe7ef20ab8f6604a6f973bbbd.zip
scheduler API change to allow use with js event loop
- GNUNET_SCHEDUELR_run_with_driver has been replaced with GNUNET_SCHEDULER_driver_init and GNUNET_SCHEDUELR_driver_done - GNUNET_SCHEDULER_run_from_driver has been renamed to GNUNET_SCHEDULER_do_work (as it's no longer being called from a driver callback) - documentation has been updated
Diffstat (limited to 'src/util/scheduler.c')
-rw-r--r--src/util/scheduler.c432
1 files changed, 257 insertions, 175 deletions
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 */
79struct GNUNET_SCHEDULER_Handle 79struct 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 */
383static void *scheduler_select_cls; 417static void *scheduler_select_cls;
384 418
385/**
386 * Scheduler handle used for the driver functions
387 */
388static 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
691int
692select_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
677GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task, 710GNUNET_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 */
1904int 1973int
1905GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) 1974GNUNET_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 */
2074int 2157struct GNUNET_SCHEDULER_Handle *
2075GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, 2158GNUNET_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 */
2239void 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
2183int
2184select_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
2213int 2269int
2214select_del (void *cls, 2270select_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
2243int
2244select_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
2388int
2389select_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
2418int
2419select_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
2365void 2448void
2366select_set_wakeup (void *cls, 2449select_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;