aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlurchi <lurchi@strangeplace.net>2018-07-29 18:18:34 +0200
committerlurchi <lurchi@strangeplace.net>2018-07-29 18:18:34 +0200
commit5bd70d462b4b50afd729eb234e0c2b6a02388bea (patch)
treee26bca5ad87b1564d11895bb8a03445d0466b637
parent88d8593d0b28b81ced737da13a9c52e39faa8ec4 (diff)
downloadgnunet-5bd70d462b4b50afd729eb234e0c2b6a02388bea.tar.gz
gnunet-5bd70d462b4b50afd729eb234e0c2b6a02388bea.zip
GNUNET_SCHEDULER_do_work: always check if shutdown is necessary and update wakeup
time
-rw-r--r--src/util/scheduler.c162
1 files 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)
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)