diff options
author | lurchi <lurchi@strangeplace.net> | 2017-08-25 12:39:04 +0200 |
---|---|---|
committer | lurchi <lurchi@strangeplace.net> | 2017-08-25 12:39:04 +0200 |
commit | ba7ceb320716f8a1b20883fccbdec15fee41002b (patch) | |
tree | 8f17d9146df6173dd08e3e95c93f4a3f1167add3 /src/util | |
parent | fe7759b2428c183fe9595640abece0937ec88bcc (diff) | |
download | gnunet-ba7ceb320716f8a1b20883fccbdec15fee41002b.tar.gz gnunet-ba7ceb320716f8a1b20883fccbdec15fee41002b.zip |
Simplify driver callback del; fix shutdown logic
The driver callback for deleting a task has been simplified: Now it is
only possible to delete a task, not single FdInfos.
A logic bug in GNUNET_SCHEDULER_cancel has been fixed (FD-related tasks
need to be deleted from the driver, when they are already in the ready
queue).
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/scheduler.c | 151 |
1 files changed, 92 insertions, 59 deletions
diff --git a/src/util/scheduler.c b/src/util/scheduler.c index cbb48c3a4..32916d99d 100644 --- a/src/util/scheduler.c +++ b/src/util/scheduler.c | |||
@@ -220,19 +220,31 @@ struct GNUNET_SCHEDULER_Task | |||
220 | }; | 220 | }; |
221 | 221 | ||
222 | 222 | ||
223 | /** | ||
224 | * A struct representing an event the select driver is waiting for | ||
225 | */ | ||
223 | struct Scheduled | 226 | struct Scheduled |
224 | { | 227 | { |
225 | struct Scheduled *prev; | 228 | struct Scheduled *prev; |
226 | 229 | ||
227 | struct Scheduled *next; | 230 | struct Scheduled *next; |
228 | 231 | ||
232 | /** | ||
233 | * the task, the event is related to | ||
234 | */ | ||
229 | struct GNUNET_SCHEDULER_Task *task; | 235 | struct GNUNET_SCHEDULER_Task *task; |
230 | 236 | ||
237 | /** | ||
238 | * information about the network socket / file descriptor where | ||
239 | * the event is expected to occur | ||
240 | */ | ||
231 | struct GNUNET_SCHEDULER_FdInfo *fdi; | 241 | struct GNUNET_SCHEDULER_FdInfo *fdi; |
232 | 242 | ||
243 | /** | ||
244 | * the event types (multiple event types can be ORed) the select | ||
245 | * driver is expected to wait for | ||
246 | */ | ||
233 | enum GNUNET_SCHEDULER_EventType et; | 247 | enum GNUNET_SCHEDULER_EventType et; |
234 | |||
235 | int is_ready; | ||
236 | }; | 248 | }; |
237 | 249 | ||
238 | 250 | ||
@@ -241,10 +253,22 @@ struct Scheduled | |||
241 | */ | 253 | */ |
242 | struct DriverContext | 254 | struct DriverContext |
243 | { | 255 | { |
256 | /** | ||
257 | * the head of a DLL containing information about the events the | ||
258 | * select driver is waiting for | ||
259 | */ | ||
244 | struct Scheduled *scheduled_head; | 260 | struct Scheduled *scheduled_head; |
245 | 261 | ||
262 | /** | ||
263 | * the tail of a DLL containing information about the events the | ||
264 | * select driver is waiting for | ||
265 | */ | ||
246 | struct Scheduled *scheduled_tail; | 266 | struct Scheduled *scheduled_tail; |
247 | 267 | ||
268 | /** | ||
269 | * the time until the select driver will wake up again (after | ||
270 | * calling select) | ||
271 | */ | ||
248 | struct GNUNET_TIME_Relative timeout; | 272 | struct GNUNET_TIME_Relative timeout; |
249 | }; | 273 | }; |
250 | 274 | ||
@@ -511,6 +535,10 @@ destroy_task (struct GNUNET_SCHEDULER_Task *t) | |||
511 | { | 535 | { |
512 | unsigned int i; | 536 | unsigned int i; |
513 | 537 | ||
538 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
539 | "destroying task %p\n", | ||
540 | t); | ||
541 | |||
514 | if (GNUNET_YES == t->own_handlers) | 542 | if (GNUNET_YES == t->own_handlers) |
515 | { | 543 | { |
516 | for (i = 0; i != t->fds_len; ++i) | 544 | for (i = 0; i != t->fds_len; ++i) |
@@ -819,10 +847,8 @@ init_fd_info (struct GNUNET_SCHEDULER_Task *t, | |||
819 | * @param et the event type to be set in each FdInfo after calling | 847 | * @param et the event type to be set in each FdInfo after calling |
820 | * @a driver_func on it, or -1 if no updating not desired. | 848 | * @a driver_func on it, or -1 if no updating not desired. |
821 | */ | 849 | */ |
822 | void scheduler_multi_function_call (struct GNUNET_SCHEDULER_Task *t, | 850 | void driver_add_multiple (struct GNUNET_SCHEDULER_Task *t, |
823 | int (*driver_func)(), | 851 | enum GNUNET_SCHEDULER_EventType et) |
824 | int if_not_ready, | ||
825 | enum GNUNET_SCHEDULER_EventType et) | ||
826 | { | 852 | { |
827 | struct GNUNET_SCHEDULER_FdInfo *fdi; | 853 | struct GNUNET_SCHEDULER_FdInfo *fdi; |
828 | int success = GNUNET_YES; | 854 | int success = GNUNET_YES; |
@@ -830,19 +856,16 @@ void scheduler_multi_function_call (struct GNUNET_SCHEDULER_Task *t, | |||
830 | for (int i = 0; i != t->fds_len; ++i) | 856 | for (int i = 0; i != t->fds_len; ++i) |
831 | { | 857 | { |
832 | fdi = &t->fds[i]; | 858 | fdi = &t->fds[i]; |
833 | if ((GNUNET_NO == if_not_ready) || (GNUNET_SCHEDULER_ET_NONE == fdi->et)) | 859 | success = scheduler_driver->add (scheduler_driver->cls, t, fdi) && success; |
860 | if (et != -1) | ||
834 | { | 861 | { |
835 | success = driver_func (scheduler_driver->cls, t, fdi) && success; | 862 | fdi->et = et; |
836 | if (et != -1) | ||
837 | { | ||
838 | fdi->et = et; | ||
839 | } | ||
840 | } | 863 | } |
841 | } | 864 | } |
842 | if (GNUNET_YES != success) | 865 | if (GNUNET_YES != success) |
843 | { | 866 | { |
844 | LOG (GNUNET_ERROR_TYPE_ERROR, | 867 | LOG (GNUNET_ERROR_TYPE_ERROR, |
845 | "driver call not successful"); | 868 | "driver could not add task\n"); |
846 | } | 869 | } |
847 | } | 870 | } |
848 | 871 | ||
@@ -876,38 +899,49 @@ void * | |||
876 | GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task) | 899 | GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task) |
877 | { | 900 | { |
878 | enum GNUNET_SCHEDULER_Priority p; | 901 | enum GNUNET_SCHEDULER_Priority p; |
902 | int is_fd_task; | ||
879 | void *ret; | 903 | void *ret; |
880 | 904 | ||
905 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
906 | "canceling task %p\n", | ||
907 | task); | ||
908 | |||
881 | /* scheduler must be running */ | 909 | /* scheduler must be running */ |
882 | GNUNET_assert (NULL != scheduler_driver); | 910 | GNUNET_assert (NULL != scheduler_driver); |
883 | GNUNET_assert ( (NULL != active_task) || | 911 | GNUNET_assert ( (NULL != active_task) || |
884 | (GNUNET_NO == task->lifeness) ); | 912 | (GNUNET_NO == task->lifeness) ); |
885 | if (! task->in_ready_list) | 913 | is_fd_task = (NULL != task->fds); |
914 | if (is_fd_task) | ||
886 | { | 915 | { |
887 | if (NULL == task->fds) | 916 | int del_result = scheduler_driver->del (scheduler_driver->cls, task); |
917 | if (GNUNET_OK != del_result) | ||
888 | { | 918 | { |
889 | if (GNUNET_YES == task->on_shutdown) | 919 | LOG (GNUNET_ERROR_TYPE_ERROR, |
890 | GNUNET_CONTAINER_DLL_remove (shutdown_head, | 920 | "driver could not delete task\n"); |
891 | shutdown_tail, | 921 | GNUNET_assert (0); |
892 | task); | ||
893 | else | ||
894 | { | ||
895 | GNUNET_CONTAINER_DLL_remove (pending_timeout_head, | ||
896 | pending_timeout_tail, | ||
897 | task); | ||
898 | if (pending_timeout_last == task) | ||
899 | pending_timeout_last = NULL; | ||
900 | } | ||
901 | //TODO check if this is redundant | ||
902 | if (task == pending_timeout_last) | ||
903 | pending_timeout_last = NULL; | ||
904 | } | 922 | } |
905 | else | 923 | } |
924 | if (! task->in_ready_list) | ||
925 | { | ||
926 | if (is_fd_task) | ||
906 | { | 927 | { |
907 | GNUNET_CONTAINER_DLL_remove (pending_head, | 928 | GNUNET_CONTAINER_DLL_remove (pending_head, |
908 | pending_tail, | 929 | pending_tail, |
909 | task); | 930 | task); |
910 | scheduler_multi_function_call(task, scheduler_driver->del, GNUNET_NO, -1); | 931 | } |
932 | else if (GNUNET_YES == task->on_shutdown) | ||
933 | { | ||
934 | GNUNET_CONTAINER_DLL_remove (shutdown_head, | ||
935 | shutdown_tail, | ||
936 | task); | ||
937 | } | ||
938 | else | ||
939 | { | ||
940 | GNUNET_CONTAINER_DLL_remove (pending_timeout_head, | ||
941 | pending_timeout_tail, | ||
942 | task); | ||
943 | if (pending_timeout_last == task) | ||
944 | pending_timeout_last = NULL; | ||
911 | } | 945 | } |
912 | } | 946 | } |
913 | else | 947 | else |
@@ -1341,12 +1375,9 @@ add_without_sets (struct GNUNET_TIME_Relative delay, | |||
1341 | GNUNET_CONTAINER_DLL_insert (pending_head, | 1375 | GNUNET_CONTAINER_DLL_insert (pending_head, |
1342 | pending_tail, | 1376 | pending_tail, |
1343 | t); | 1377 | t); |
1344 | scheduler_multi_function_call (t, scheduler_driver->add, GNUNET_NO, GNUNET_SCHEDULER_ET_NONE); | 1378 | driver_add_multiple (t, GNUNET_SCHEDULER_ET_NONE); |
1345 | max_priority_added = GNUNET_MAX (max_priority_added, | 1379 | max_priority_added = GNUNET_MAX (max_priority_added, |
1346 | t->priority); | 1380 | t->priority); |
1347 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1348 | "Adding task %p\n", | ||
1349 | t); | ||
1350 | init_backtrace (t); | 1381 | init_backtrace (t); |
1351 | return t; | 1382 | return t; |
1352 | } | 1383 | } |
@@ -1785,7 +1816,7 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, | |||
1785 | GNUNET_CONTAINER_DLL_insert (pending_head, | 1816 | GNUNET_CONTAINER_DLL_insert (pending_head, |
1786 | pending_tail, | 1817 | pending_tail, |
1787 | t); | 1818 | t); |
1788 | scheduler_multi_function_call (t, scheduler_driver->add, GNUNET_NO, GNUNET_SCHEDULER_ET_NONE); | 1819 | driver_add_multiple (t, GNUNET_SCHEDULER_ET_NONE); |
1789 | max_priority_added = GNUNET_MAX (max_priority_added, | 1820 | max_priority_added = GNUNET_MAX (max_priority_added, |
1790 | t->priority); | 1821 | t->priority); |
1791 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1822 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1890,8 +1921,6 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1890 | 1921 | ||
1891 | if (0 == ready_count) | 1922 | if (0 == ready_count) |
1892 | { | 1923 | { |
1893 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1894 | "no tasks run!\n"); | ||
1895 | return GNUNET_NO; | 1924 | return GNUNET_NO; |
1896 | } | 1925 | } |
1897 | 1926 | ||
@@ -1956,7 +1985,16 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1956 | "Running task %p\n", | 1985 | "Running task %p\n", |
1957 | pos); | 1986 | pos); |
1958 | pos->callback (pos->callback_cls); | 1987 | pos->callback (pos->callback_cls); |
1959 | scheduler_multi_function_call (pos, scheduler_driver->del, GNUNET_YES, -1); | 1988 | if (NULL != pos->fds) |
1989 | { | ||
1990 | int del_result = scheduler_driver->del (scheduler_driver->cls, pos); | ||
1991 | if (GNUNET_OK != del_result) | ||
1992 | { | ||
1993 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1994 | "driver could not delete task\n"); | ||
1995 | GNUNET_assert (0); | ||
1996 | } | ||
1997 | } | ||
1960 | active_task = NULL; | 1998 | active_task = NULL; |
1961 | dump_backtrace (pos); | 1999 | dump_backtrace (pos); |
1962 | destroy_task (pos); | 2000 | destroy_task (pos); |
@@ -2123,8 +2161,7 @@ select_add (void *cls, | |||
2123 | 2161 | ||
2124 | int | 2162 | int |
2125 | select_del (void *cls, | 2163 | select_del (void *cls, |
2126 | struct GNUNET_SCHEDULER_Task *task, | 2164 | struct GNUNET_SCHEDULER_Task *task) |
2127 | struct GNUNET_SCHEDULER_FdInfo *fdi) | ||
2128 | { | 2165 | { |
2129 | struct DriverContext *context; | 2166 | struct DriverContext *context; |
2130 | struct Scheduled *pos; | 2167 | struct Scheduled *pos; |
@@ -2134,16 +2171,19 @@ select_del (void *cls, | |||
2134 | 2171 | ||
2135 | context = cls; | 2172 | context = cls; |
2136 | ret = GNUNET_SYSERR; | 2173 | ret = GNUNET_SYSERR; |
2137 | for (pos = context->scheduled_head; NULL != pos; pos = pos->next) | 2174 | pos = context->scheduled_head; |
2175 | while (NULL != pos) | ||
2138 | { | 2176 | { |
2139 | if (pos->task == task && pos->fdi == fdi) | 2177 | struct Scheduled *next = pos->next; |
2178 | if (pos->task == task) | ||
2140 | { | 2179 | { |
2141 | GNUNET_CONTAINER_DLL_remove (context->scheduled_head, | 2180 | GNUNET_CONTAINER_DLL_remove (context->scheduled_head, |
2142 | context->scheduled_tail, | 2181 | context->scheduled_tail, |
2143 | pos); | 2182 | pos); |
2183 | GNUNET_free (pos); | ||
2144 | ret = GNUNET_OK; | 2184 | ret = GNUNET_OK; |
2145 | break; | ||
2146 | } | 2185 | } |
2186 | pos = next; | ||
2147 | } | 2187 | } |
2148 | return ret; | 2188 | return ret; |
2149 | } | 2189 | } |
@@ -2170,9 +2210,8 @@ select_loop (void *cls, | |||
2170 | busy_wait_warning = 0; | 2210 | busy_wait_warning = 0; |
2171 | while (NULL != context->scheduled_head || GNUNET_YES == tasks_ready) | 2211 | while (NULL != context->scheduled_head || GNUNET_YES == tasks_ready) |
2172 | { | 2212 | { |
2173 | LOG (GNUNET_ERROR_TYPE_WARNING, | 2213 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2174 | "[%p] timeout = %s\n", | 2214 | "select timeout = %s\n", |
2175 | sh, | ||
2176 | GNUNET_STRINGS_relative_time_to_string (context->timeout, GNUNET_NO)); | 2215 | GNUNET_STRINGS_relative_time_to_string (context->timeout, GNUNET_NO)); |
2177 | 2216 | ||
2178 | GNUNET_NETWORK_fdset_zero (rs); | 2217 | GNUNET_NETWORK_fdset_zero (rs); |
@@ -2206,8 +2245,6 @@ select_loop (void *cls, | |||
2206 | } | 2245 | } |
2207 | if (select_result == GNUNET_SYSERR) | 2246 | if (select_result == GNUNET_SYSERR) |
2208 | { | 2247 | { |
2209 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2210 | "select_result = GNUNET_SYSERR\n"); | ||
2211 | if (errno == EINTR) | 2248 | if (errno == EINTR) |
2212 | continue; | 2249 | continue; |
2213 | 2250 | ||
@@ -2283,24 +2320,20 @@ select_loop (void *cls, | |||
2283 | } | 2320 | } |
2284 | if (GNUNET_YES == is_ready) | 2321 | if (GNUNET_YES == is_ready) |
2285 | { | 2322 | { |
2286 | GNUNET_CONTAINER_DLL_remove (context->scheduled_head, | 2323 | //GNUNET_CONTAINER_DLL_remove (context->scheduled_head, |
2287 | context->scheduled_tail, | 2324 | // context->scheduled_tail, |
2288 | pos); | 2325 | // pos); |
2289 | GNUNET_SCHEDULER_task_ready (pos->task, pos->fdi); | 2326 | GNUNET_SCHEDULER_task_ready (pos->task, pos->fdi); |
2290 | } | 2327 | } |
2291 | } | 2328 | } |
2292 | tasks_ready = GNUNET_SCHEDULER_run_from_driver (sh); | 2329 | tasks_ready = GNUNET_SCHEDULER_run_from_driver (sh); |
2293 | LOG (GNUNET_ERROR_TYPE_WARNING, | 2330 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
2294 | "[%p] tasks_ready: %d\n", | 2331 | "tasks_ready: %d\n", |
2295 | sh, | ||
2296 | tasks_ready); | 2332 | tasks_ready); |
2297 | // FIXME: tasks_run is a driver-internal variable! Instead we should increment | 2333 | // FIXME: tasks_run is a driver-internal variable! Instead we should increment |
2298 | // a local variable tasks_ready_count everytime we're calling GNUNET_SCHEDULER_task_ready. | 2334 | // a local variable tasks_ready_count everytime we're calling GNUNET_SCHEDULER_task_ready. |
2299 | if (last_tr == tasks_run) | 2335 | if (last_tr == tasks_run) |
2300 | { | 2336 | { |
2301 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2302 | "[%p] no tasks run\n", | ||
2303 | sh); | ||
2304 | short_wait (1); | 2337 | short_wait (1); |
2305 | busy_wait_warning++; | 2338 | busy_wait_warning++; |
2306 | } | 2339 | } |