From 5bd70d462b4b50afd729eb234e0c2b6a02388bea Mon Sep 17 00:00:00 2001 From: lurchi Date: Sun, 29 Jul 2018 18:18:34 +0200 Subject: GNUNET_SCHEDULER_do_work: always check if shutdown is necessary and update wakeup time --- src/util/scheduler.c | 162 +++++++++++++++++++++++++++------------------------ 1 file changed, 86 insertions(+), 76 deletions(-) diff --git a/src/util/scheduler.c b/src/util/scheduler.c index 014288944..5d3836639 100644 --- a/src/util/scheduler.c +++ b/src/util/scheduler.c @@ -2022,99 +2022,109 @@ GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh) if (timeout.abs_value_us > now.abs_value_us) { /** - * The driver called this function before the current timeout was - * reached (and no FD tasks are ready). This can happen in the - * rare case when the system time is changed while the driver is - * waiting for the timeout, so we handle this gracefully. It might - * also be a programming error in the driver though. + * The event loop called this function before the current timeout was + * reached (and no FD tasks are ready). This is acceptable if + * + * - the system time was changed while the driver was waiting for + * the timeout + * - an external event loop called GNUnet API functions outside of + * the callbacks called in GNUNET_SCHEDULER_do_work and thus + * wasn't notified about the new timeout + * + * It might also mean we are busy-waiting because of a programming + * error in the external event loop. */ LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_SCHEDULER_do_work did not find any ready " "tasks and timeout has not been reached yet.\n"); - return GNUNET_NO; } - /** - * the current timeout was reached but no ready tasks were found, - * internal scheduler error! - */ - GNUNET_assert (0); - } - - /* find out which task priority level we are going to - process this time */ - max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP; - GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]); - /* yes, p>0 is correct, 0 is "KEEP" which should - * always be an empty queue (see assertion)! */ - for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--) - { - pos = ready_head[p]; - if (NULL != pos) - break; + else + { + /** + * the current timeout was reached but no ready tasks were found, + * internal scheduler error! + */ + GNUNET_assert (0); + } } - GNUNET_assert (NULL != pos); /* ready_count wrong? */ - - /* process all tasks at this priority level, then yield */ - while (NULL != (pos = ready_head[p])) + else { - GNUNET_CONTAINER_DLL_remove (ready_head[p], - ready_tail[p], - pos); - ready_count--; - current_priority = pos->priority; - current_lifeness = pos->lifeness; - active_task = pos; -#if PROFILE_DELAYS - if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us > - DELAY_THRESHOLD.rel_value_us) + /* find out which task priority level we are going to + process this time */ + max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP; + GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]); + /* yes, p>0 is correct, 0 is "KEEP" which should + * always be an empty queue (see assertion)! */ + for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--) { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Task %p took %s to be scheduled\n", - pos, - GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time), - GNUNET_YES)); + pos = ready_head[p]; + if (NULL != pos) + break; } -#endif - tc.reason = pos->reason; - GNUNET_NETWORK_fdset_zero (sh->rs); - GNUNET_NETWORK_fdset_zero (sh->ws); - // FIXME: do we have to remove FdInfos from fds if they are not ready? - tc.fds_len = pos->fds_len; - tc.fds = pos->fds; - for (unsigned int i = 0; i != pos->fds_len; ++i) + GNUNET_assert (NULL != pos); /* ready_count wrong? */ + + /* process all tasks at this priority level, then yield */ + while (NULL != (pos = ready_head[p])) { - struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i]; - if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)) + GNUNET_CONTAINER_DLL_remove (ready_head[p], + ready_tail[p], + pos); + ready_count--; + current_priority = pos->priority; + current_lifeness = pos->lifeness; + active_task = pos; +#if PROFILE_DELAYS + if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us > + DELAY_THRESHOLD.rel_value_us) { - GNUNET_NETWORK_fdset_set_native (sh->rs, - fdi->sock); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Task %p took %s to be scheduled\n", + pos, + GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time), + GNUNET_YES)); } - if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)) +#endif + tc.reason = pos->reason; + GNUNET_NETWORK_fdset_zero (sh->rs); + GNUNET_NETWORK_fdset_zero (sh->ws); + // FIXME: do we have to remove FdInfos from fds if they are not ready? + tc.fds_len = pos->fds_len; + tc.fds = pos->fds; + for (unsigned int i = 0; i != pos->fds_len; ++i) { - GNUNET_NETWORK_fdset_set_native (sh->ws, - fdi->sock); + struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i]; + if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)) + { + GNUNET_NETWORK_fdset_set_native (sh->rs, + fdi->sock); + } + if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)) + { + GNUNET_NETWORK_fdset_set_native (sh->ws, + fdi->sock); + } } - } - tc.read_ready = sh->rs; - tc.write_ready = sh->ws; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Running task %p\n", - pos); - GNUNET_assert (NULL != pos->callback); - pos->callback (pos->callback_cls); - if (NULL != pos->fds) - { - int del_result = scheduler_driver->del (scheduler_driver->cls, pos); - if (GNUNET_OK != del_result) + tc.read_ready = sh->rs; + tc.write_ready = sh->ws; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Running task %p\n", + pos); + GNUNET_assert (NULL != pos->callback); + pos->callback (pos->callback_cls); + if (NULL != pos->fds) { - LOG (GNUNET_ERROR_TYPE_ERROR, - "driver could not delete task %p\n", pos); - GNUNET_assert (0); + int del_result = scheduler_driver->del (scheduler_driver->cls, pos); + if (GNUNET_OK != del_result) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "driver could not delete task %p\n", pos); + GNUNET_assert (0); + } } + active_task = NULL; + dump_backtrace (pos); + destroy_task (pos); } - active_task = NULL; - dump_backtrace (pos); - destroy_task (pos); } shutdown_if_no_lifeness (); if (0 == ready_count) -- cgit v1.2.3