diff options
Diffstat (limited to 'src/util/scheduler.c')
-rw-r--r-- | src/util/scheduler.c | 189 |
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 * | |||
2164 | GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver) | 2174 | GNUNET_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 */ |