aboutsummaryrefslogtreecommitdiff
path: root/src/util/scheduler.c
diff options
context:
space:
mode:
authorlurchi <lurchi@strangeplace.net>2018-01-24 22:52:25 +0100
committerlurchi <lurchi@strangeplace.net>2018-01-24 22:52:25 +0100
commite7ba3b64baa9aef8f1ca83c6da443cb4a1ec362a (patch)
tree0be38b7aa6f342eeb92ad10b72f279314cf43af0 /src/util/scheduler.c
parentf0140aa59e7e6570deec0cde35fc0147ee1292cb (diff)
downloadgnunet-e7ba3b64baa9aef8f1ca83c6da443cb4a1ec362a.tar.gz
gnunet-e7ba3b64baa9aef8f1ca83c6da443cb4a1ec362a.zip
make GNUNET_SCHEDULER_run_from_driver more graceful
GNUNET_SCHEDULER_run_from_driver may now be called without any tasks being ready if the timeout has not been reached yet. A warning is printed because it may be a programming error in the driver (see comments)
Diffstat (limited to 'src/util/scheduler.c')
-rw-r--r--src/util/scheduler.c47
1 files changed, 26 insertions, 21 deletions
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index a8d572a56..2daa6dd80 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -1896,11 +1896,10 @@ GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task,
1896 * the scheduler (using the set_wakeup callback) is reached. 1896 * the scheduler (using the set_wakeup callback) is reached.
1897 * 1897 *
1898 * @param sh scheduler handle that was given to the `loop` 1898 * @param sh scheduler handle that was given to the `loop`
1899 * @return #GNUNET_OK if there are more tasks that are ready, 1899 * @return #GNUNET_YES if there are more tasks that are ready,
1900 * and thus we would like to run more (yield to avoid 1900 * and thus we would like to run more (yield to avoid
1901 * blocking other activities for too long) 1901 * blocking other activities for too long)
1902 * #GNUNET_NO if we are done running tasks (yield to block) 1902 * #GNUNET_NO if we are done running tasks (yield to block)
1903 * #GNUNET_SYSERR on error, e.g. no tasks were ready
1904 */ 1903 */
1905int 1904int
1906GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) 1905GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh)
@@ -1944,9 +1943,27 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh)
1944 1943
1945 if (0 == ready_count) 1944 if (0 == ready_count)
1946 { 1945 {
1947 LOG (GNUNET_ERROR_TYPE_ERROR, 1946 struct GNUNET_TIME_Absolute timeout = get_timeout ();
1948 "GNUNET_SCHEDULER_run_from_driver was called, but no tasks are ready!\n"); 1947
1949 return GNUNET_SYSERR; 1948 if (timeout.abs_value_us < now.abs_value_us)
1949 {
1950 /**
1951 * The driver called this function before the current timeout was
1952 * reached (and no FD tasks are ready). This can happen in the
1953 * rare case when the system time is changed while the driver is
1954 * waiting for the timeout, so we handle this gracefully. It might
1955 * also be a programming error in the driver though.
1956 */
1957 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1958 "GNUNET_SCHEDULER_run_from_driver did not find any ready "
1959 "tasks and timeout has not been reached yet.");
1960 return GNUNET_NO;
1961 }
1962 /**
1963 * the current timeout was reached but no ready tasks were found,
1964 * internal scheduler error!
1965 */
1966 GNUNET_assert (0);
1950 } 1967 }
1951 1968
1952 /* find out which task priority level we are going to 1969 /* find out which task priority level we are going to
@@ -2034,7 +2051,7 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh)
2034 } 2051 }
2035 scheduler_driver->set_wakeup (scheduler_driver->cls, 2052 scheduler_driver->set_wakeup (scheduler_driver->cls,
2036 GNUNET_TIME_absolute_get ()); 2053 GNUNET_TIME_absolute_get ());
2037 return GNUNET_OK; 2054 return GNUNET_YES;
2038} 2055}
2039 2056
2040 2057
@@ -2231,13 +2248,11 @@ select_loop (void *cls,
2231 struct GNUNET_NETWORK_FDSet *ws; 2248 struct GNUNET_NETWORK_FDSet *ws;
2232 struct DriverContext *context; 2249 struct DriverContext *context;
2233 int select_result; 2250 int select_result;
2234 int tasks_ready;
2235 2251
2236 context = cls; 2252 context = cls;
2237 GNUNET_assert (NULL != context); 2253 GNUNET_assert (NULL != context);
2238 rs = GNUNET_NETWORK_fdset_create (); 2254 rs = GNUNET_NETWORK_fdset_create ();
2239 ws = GNUNET_NETWORK_fdset_create (); 2255 ws = GNUNET_NETWORK_fdset_create ();
2240 tasks_ready = GNUNET_NO;
2241 while (NULL != context->scheduled_head || 2256 while (NULL != context->scheduled_head ||
2242 GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != context->timeout.abs_value_us) 2257 GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != context->timeout.abs_value_us)
2243 { 2258 {
@@ -2335,21 +2350,11 @@ select_loop (void *cls,
2335 } 2350 }
2336 } 2351 }
2337 } 2352 }
2338 else 2353 if (GNUNET_YES == GNUNET_SCHEDULER_run_from_driver (sh))
2339 { 2354 {
2340 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 2355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2341 if (now.abs_value_us < context->timeout.abs_value_us) 2356 "scheduler has more tasks ready!\n");
2342 {
2343 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2344 "select was expected to return at %" PRIu64 ", "
2345 "but returned already at %" PRIu64 "\n",
2346 context->timeout.abs_value_us,
2347 now.abs_value_us);
2348 GNUNET_assert (0);
2349 }
2350 } 2357 }
2351 tasks_ready = GNUNET_SCHEDULER_run_from_driver (sh);
2352 GNUNET_assert (GNUNET_SYSERR != tasks_ready);
2353 } 2358 }
2354 GNUNET_NETWORK_fdset_destroy (rs); 2359 GNUNET_NETWORK_fdset_destroy (rs);
2355 GNUNET_NETWORK_fdset_destroy (ws); 2360 GNUNET_NETWORK_fdset_destroy (ws);