aboutsummaryrefslogtreecommitdiff
path: root/src/util/scheduler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/scheduler.c')
-rw-r--r--src/util/scheduler.c189
1 files changed, 97 insertions, 92 deletions
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index 93d133d1b..5d3836639 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -965,8 +965,6 @@ GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task)
965 965
966 /* scheduler must be running */ 966 /* scheduler must be running */
967 GNUNET_assert (NULL != scheduler_driver); 967 GNUNET_assert (NULL != scheduler_driver);
968 GNUNET_assert ( (NULL != active_task) ||
969 (GNUNET_NO == task->lifeness) );
970 is_fd_task = (NULL != task->fds); 968 is_fd_task = (NULL != task->fds);
971 if (is_fd_task) 969 if (is_fd_task)
972 { 970 {
@@ -1056,9 +1054,9 @@ GNUNET_SCHEDULER_add_with_reason_and_priority (GNUNET_SCHEDULER_TaskCallback tas
1056{ 1054{
1057 struct GNUNET_SCHEDULER_Task *t; 1055 struct GNUNET_SCHEDULER_Task *t;
1058 1056
1057 /* scheduler must be running */
1058 GNUNET_assert (NULL != scheduler_driver);
1059 GNUNET_assert (NULL != task); 1059 GNUNET_assert (NULL != task);
1060 GNUNET_assert ((NULL != active_task) ||
1061 (GNUNET_SCHEDULER_REASON_STARTUP == reason));
1062 t = GNUNET_new (struct GNUNET_SCHEDULER_Task); 1060 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1063 t->read_fd = -1; 1061 t->read_fd = -1;
1064 t->write_fd = -1; 1062 t->write_fd = -1;
@@ -1099,7 +1097,8 @@ GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at,
1099 struct GNUNET_SCHEDULER_Task *pos; 1097 struct GNUNET_SCHEDULER_Task *pos;
1100 struct GNUNET_SCHEDULER_Task *prev; 1098 struct GNUNET_SCHEDULER_Task *prev;
1101 1099
1102 GNUNET_assert (NULL != active_task); 1100 /* scheduler must be running */
1101 GNUNET_assert (NULL != scheduler_driver);
1103 GNUNET_assert (NULL != task); 1102 GNUNET_assert (NULL != task);
1104 t = GNUNET_new (struct GNUNET_SCHEDULER_Task); 1103 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1105 t->callback = task; 1104 t->callback = task;
@@ -1286,7 +1285,8 @@ GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task,
1286{ 1285{
1287 struct GNUNET_SCHEDULER_Task *t; 1286 struct GNUNET_SCHEDULER_Task *t;
1288 1287
1289 GNUNET_assert (NULL != active_task); 1288 /* scheduler must be running */
1289 GNUNET_assert (NULL != scheduler_driver);
1290 GNUNET_assert (NULL != task); 1290 GNUNET_assert (NULL != task);
1291 t = GNUNET_new (struct GNUNET_SCHEDULER_Task); 1291 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1292 t->callback = task; 1292 t->callback = task;
@@ -1403,7 +1403,8 @@ add_without_sets (struct GNUNET_TIME_Relative delay,
1403{ 1403{
1404 struct GNUNET_SCHEDULER_Task *t; 1404 struct GNUNET_SCHEDULER_Task *t;
1405 1405
1406 GNUNET_assert (NULL != active_task); 1406 /* scheduler must be running */
1407 GNUNET_assert (NULL != scheduler_driver);
1407 GNUNET_assert (NULL != task); 1408 GNUNET_assert (NULL != task);
1408 t = GNUNET_new (struct GNUNET_SCHEDULER_Task); 1409 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1409 init_fd_info (t, 1410 init_fd_info (t,
@@ -1832,7 +1833,6 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
1832 1833
1833 /* scheduler must be running */ 1834 /* scheduler must be running */
1834 GNUNET_assert (NULL != scheduler_driver); 1835 GNUNET_assert (NULL != scheduler_driver);
1835 GNUNET_assert (NULL != active_task);
1836 GNUNET_assert (NULL != task); 1836 GNUNET_assert (NULL != task);
1837 int no_rs = (NULL == rs); 1837 int no_rs = (NULL == rs);
1838 int no_ws = (NULL == ws); 1838 int no_ws = (NULL == ws);
@@ -2022,99 +2022,109 @@ GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh)
2022 if (timeout.abs_value_us > now.abs_value_us) 2022 if (timeout.abs_value_us > now.abs_value_us)
2023 { 2023 {
2024 /** 2024 /**
2025 * The driver called this function before the current timeout was 2025 * The event loop called this function before the current timeout was
2026 * reached (and no FD tasks are ready). This can happen in the 2026 * reached (and no FD tasks are ready). This is acceptable if
2027 * rare case when the system time is changed while the driver is 2027 *
2028 * waiting for the timeout, so we handle this gracefully. It might 2028 * - the system time was changed while the driver was waiting for
2029 * also be a programming error in the driver though. 2029 * the timeout
2030 * - an external event loop called GNUnet API functions outside of
2031 * the callbacks called in GNUNET_SCHEDULER_do_work and thus
2032 * wasn't notified about the new timeout
2033 *
2034 * It might also mean we are busy-waiting because of a programming
2035 * error in the external event loop.
2030 */ 2036 */
2031 LOG (GNUNET_ERROR_TYPE_DEBUG, 2037 LOG (GNUNET_ERROR_TYPE_DEBUG,
2032 "GNUNET_SCHEDULER_do_work did not find any ready " 2038 "GNUNET_SCHEDULER_do_work did not find any ready "
2033 "tasks and timeout has not been reached yet.\n"); 2039 "tasks and timeout has not been reached yet.\n");
2034 return GNUNET_NO;
2035 } 2040 }
2036 /** 2041 else
2037 * the current timeout was reached but no ready tasks were found, 2042 {
2038 * internal scheduler error! 2043 /**
2039 */ 2044 * the current timeout was reached but no ready tasks were found,
2040 GNUNET_assert (0); 2045 * internal scheduler error!
2041 } 2046 */
2042 2047 GNUNET_assert (0);
2043 /* find out which task priority level we are going to 2048 }
2044 process this time */
2045 max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP;
2046 GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]);
2047 /* yes, p>0 is correct, 0 is "KEEP" which should
2048 * always be an empty queue (see assertion)! */
2049 for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--)
2050 {
2051 pos = ready_head[p];
2052 if (NULL != pos)
2053 break;
2054 } 2049 }
2055 GNUNET_assert (NULL != pos); /* ready_count wrong? */ 2050 else
2056
2057 /* process all tasks at this priority level, then yield */
2058 while (NULL != (pos = ready_head[p]))
2059 { 2051 {
2060 GNUNET_CONTAINER_DLL_remove (ready_head[p], 2052 /* find out which task priority level we are going to
2061 ready_tail[p], 2053 process this time */
2062 pos); 2054 max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP;
2063 ready_count--; 2055 GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]);
2064 current_priority = pos->priority; 2056 /* yes, p>0 is correct, 0 is "KEEP" which should
2065 current_lifeness = pos->lifeness; 2057 * always be an empty queue (see assertion)! */
2066 active_task = pos; 2058 for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--)
2067#if PROFILE_DELAYS
2068 if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us >
2069 DELAY_THRESHOLD.rel_value_us)
2070 { 2059 {
2071 LOG (GNUNET_ERROR_TYPE_DEBUG, 2060 pos = ready_head[p];
2072 "Task %p took %s to be scheduled\n", 2061 if (NULL != pos)
2073 pos, 2062 break;
2074 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time),
2075 GNUNET_YES));
2076 } 2063 }
2077#endif 2064 GNUNET_assert (NULL != pos); /* ready_count wrong? */
2078 tc.reason = pos->reason; 2065
2079 GNUNET_NETWORK_fdset_zero (sh->rs); 2066 /* process all tasks at this priority level, then yield */
2080 GNUNET_NETWORK_fdset_zero (sh->ws); 2067 while (NULL != (pos = ready_head[p]))
2081 // FIXME: do we have to remove FdInfos from fds if they are not ready?
2082 tc.fds_len = pos->fds_len;
2083 tc.fds = pos->fds;
2084 for (unsigned int i = 0; i != pos->fds_len; ++i)
2085 { 2068 {
2086 struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i]; 2069 GNUNET_CONTAINER_DLL_remove (ready_head[p],
2087 if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)) 2070 ready_tail[p],
2071 pos);
2072 ready_count--;
2073 current_priority = pos->priority;
2074 current_lifeness = pos->lifeness;
2075 active_task = pos;
2076#if PROFILE_DELAYS
2077 if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us >
2078 DELAY_THRESHOLD.rel_value_us)
2088 { 2079 {
2089 GNUNET_NETWORK_fdset_set_native (sh->rs, 2080 LOG (GNUNET_ERROR_TYPE_DEBUG,
2090 fdi->sock); 2081 "Task %p took %s to be scheduled\n",
2082 pos,
2083 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time),
2084 GNUNET_YES));
2091 } 2085 }
2092 if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)) 2086#endif
2087 tc.reason = pos->reason;
2088 GNUNET_NETWORK_fdset_zero (sh->rs);
2089 GNUNET_NETWORK_fdset_zero (sh->ws);
2090 // FIXME: do we have to remove FdInfos from fds if they are not ready?
2091 tc.fds_len = pos->fds_len;
2092 tc.fds = pos->fds;
2093 for (unsigned int i = 0; i != pos->fds_len; ++i)
2093 { 2094 {
2094 GNUNET_NETWORK_fdset_set_native (sh->ws, 2095 struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i];
2095 fdi->sock); 2096 if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et))
2097 {
2098 GNUNET_NETWORK_fdset_set_native (sh->rs,
2099 fdi->sock);
2100 }
2101 if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et))
2102 {
2103 GNUNET_NETWORK_fdset_set_native (sh->ws,
2104 fdi->sock);
2105 }
2096 } 2106 }
2097 } 2107 tc.read_ready = sh->rs;
2098 tc.read_ready = sh->rs; 2108 tc.write_ready = sh->ws;
2099 tc.write_ready = sh->ws; 2109 LOG (GNUNET_ERROR_TYPE_DEBUG,
2100 LOG (GNUNET_ERROR_TYPE_DEBUG, 2110 "Running task %p\n",
2101 "Running task %p\n", 2111 pos);
2102 pos); 2112 GNUNET_assert (NULL != pos->callback);
2103 GNUNET_assert (NULL != pos->callback); 2113 pos->callback (pos->callback_cls);
2104 pos->callback (pos->callback_cls); 2114 if (NULL != pos->fds)
2105 if (NULL != pos->fds)
2106 {
2107 int del_result = scheduler_driver->del (scheduler_driver->cls, pos);
2108 if (GNUNET_OK != del_result)
2109 { 2115 {
2110 LOG (GNUNET_ERROR_TYPE_ERROR, 2116 int del_result = scheduler_driver->del (scheduler_driver->cls, pos);
2111 "driver could not delete task %p\n", pos); 2117 if (GNUNET_OK != del_result)
2112 GNUNET_assert (0); 2118 {
2119 LOG (GNUNET_ERROR_TYPE_ERROR,
2120 "driver could not delete task %p\n", pos);
2121 GNUNET_assert (0);
2122 }
2113 } 2123 }
2124 active_task = NULL;
2125 dump_backtrace (pos);
2126 destroy_task (pos);
2114 } 2127 }
2115 active_task = NULL;
2116 dump_backtrace (pos);
2117 destroy_task (pos);
2118 } 2128 }
2119 shutdown_if_no_lifeness (); 2129 shutdown_if_no_lifeness ();
2120 if (0 == ready_count) 2130 if (0 == ready_count)
@@ -2164,12 +2174,12 @@ struct GNUNET_SCHEDULER_Handle *
2164GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver) 2174GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver)
2165{ 2175{
2166 struct GNUNET_SCHEDULER_Handle *sh; 2176 struct GNUNET_SCHEDULER_Handle *sh;
2167 struct GNUNET_SCHEDULER_Task tsk;
2168 const struct GNUNET_DISK_FileHandle *pr; 2177 const struct GNUNET_DISK_FileHandle *pr;
2169 2178
2170 /* general set-up */ 2179 /* scheduler must not be running */
2171 GNUNET_assert (NULL == active_task); 2180 GNUNET_assert (NULL == scheduler_driver);
2172 GNUNET_assert (NULL == shutdown_pipe_handle); 2181 GNUNET_assert (NULL == shutdown_pipe_handle);
2182 /* general set-up */
2173 sh = GNUNET_new (struct GNUNET_SCHEDULER_Handle); 2183 sh = GNUNET_new (struct GNUNET_SCHEDULER_Handle);
2174 shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, 2184 shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO,
2175 GNUNET_NO, 2185 GNUNET_NO,
@@ -2204,10 +2214,6 @@ GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver)
2204 /* Setup initial tasks */ 2214 /* Setup initial tasks */
2205 current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT; 2215 current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
2206 current_lifeness = GNUNET_NO; 2216 current_lifeness = GNUNET_NO;
2207 memset (&tsk,
2208 0,
2209 sizeof (tsk));
2210 active_task = &tsk;
2211 install_parent_control_task = 2217 install_parent_control_task =
2212 GNUNET_SCHEDULER_add_now (&install_parent_control_handler, 2218 GNUNET_SCHEDULER_add_now (&install_parent_control_handler,
2213 NULL); 2219 NULL);
@@ -2217,7 +2223,6 @@ GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver)
2217 &shutdown_pipe_cb, 2223 &shutdown_pipe_cb,
2218 NULL); 2224 NULL);
2219 current_lifeness = GNUNET_YES; 2225 current_lifeness = GNUNET_YES;
2220 active_task = NULL;
2221 scheduler_driver->set_wakeup (scheduler_driver->cls, 2226 scheduler_driver->set_wakeup (scheduler_driver->cls,
2222 get_timeout ()); 2227 get_timeout ());
2223 /* begin main event loop */ 2228 /* begin main event loop */