aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlurchi <lurchi@strangeplace.net>2017-08-25 12:39:04 +0200
committerlurchi <lurchi@strangeplace.net>2017-08-25 12:39:04 +0200
commitba7ceb320716f8a1b20883fccbdec15fee41002b (patch)
tree8f17d9146df6173dd08e3e95c93f4a3f1167add3 /src
parentfe7759b2428c183fe9595640abece0937ec88bcc (diff)
downloadgnunet-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')
-rw-r--r--src/util/scheduler.c151
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 */
223struct Scheduled 226struct 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 */
242struct DriverContext 254struct 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 */
822void scheduler_multi_function_call (struct GNUNET_SCHEDULER_Task *t, 850void 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 *
876GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task) 899GNUNET_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
2124int 2162int
2125select_del (void *cls, 2163select_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 }