aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-05-17 10:00:25 +0200
committerChristian Grothoff <christian@grothoff.org>2022-05-17 10:00:44 +0200
commit5fcabf87a066a776d40ff52484fa8d54e8302963 (patch)
tree9b25bab3707e27c285251193fc4d9d9a298d110c
parentb47e578091e7451fd5c98cc56447d0fadba15b00 (diff)
downloadgnunet-5fcabf87a066a776d40ff52484fa8d54e8302963.tar.gz
gnunet-5fcabf87a066a776d40ff52484fa8d54e8302963.zip
fix scheduler bug with same-priority immediately-ready tasks possibly hogging the scheduler
-rw-r--r--src/util/scheduler.c47
1 files changed, 22 insertions, 25 deletions
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index 03a7c0dfb..7e035ae3d 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2009-2017 GNUnet e.V. 3 Copyright (C) 2009-2017, 2022 GNUnet e.V.
4 4
5 GNUnet is free software: you can redistribute it and/or modify it 5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published 6 under the terms of the GNU Affero General Public License as published
@@ -516,6 +516,8 @@ queue_ready_task (struct GNUNET_SCHEDULER_Task *task)
516 GNUNET_CONTAINER_DLL_insert_tail (ready_head[p], 516 GNUNET_CONTAINER_DLL_insert_tail (ready_head[p],
517 ready_tail[p], 517 ready_tail[p],
518 task); 518 task);
519 if (p > work_priority)
520 work_priority = p;
519 task->in_ready_list = GNUNET_YES; 521 task->in_ready_list = GNUNET_YES;
520 ready_count++; 522 ready_count++;
521} 523}
@@ -639,29 +641,11 @@ sighandler_pipe ()
639} 641}
640 642
641 643
642///**
643// * Wait for a short time.
644// * Sleeps for @a ms ms (as that should be long enough for virtually all
645// * modern systems to context switch and allow another process to do
646// * some 'real' work).
647// *
648// * @param ms how many ms to wait
649// */
650// static void
651// short_wait (unsigned int ms)
652// {
653// struct GNUNET_TIME_Relative timeout;
654//
655// timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, ms);
656// (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
657// }
658
659
660/** 644/**
661 * Signal handler called for signals that should cause us to shutdown. 645 * Signal handler called for signals that should cause us to shutdown.
662 */ 646 */
663static void 647static void
664sighandler_shutdown () 648sighandler_shutdown (void)
665{ 649{
666 static char c; 650 static char c;
667 int old_errno = errno; /* backup errno */ 651 int old_errno = errno; /* backup errno */
@@ -669,15 +653,16 @@ sighandler_shutdown ()
669 if (getpid () != my_pid) 653 if (getpid () != my_pid)
670 _exit (1); /* we have fork'ed since the signal handler was created, 654 _exit (1); /* we have fork'ed since the signal handler was created,
671 * ignore the signal, see https://gnunet.org/vfork discussion */ 655 * ignore the signal, see https://gnunet.org/vfork discussion */
672 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle 656 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (
673 (shutdown_pipe_handle, GNUNET_DISK_PIPE_END_WRITE), 657 shutdown_pipe_handle,
658 GNUNET_DISK_PIPE_END_WRITE),
674 &c, sizeof(c)); 659 &c, sizeof(c));
675 errno = old_errno; 660 errno = old_errno;
676} 661}
677 662
678 663
679static void 664static void
680shutdown_if_no_lifeness () 665shutdown_if_no_lifeness (void)
681{ 666{
682 struct GNUNET_SCHEDULER_Task *t; 667 struct GNUNET_SCHEDULER_Task *t;
683 668
@@ -2072,6 +2057,8 @@ GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh)
2072 } 2057 }
2073 else 2058 else
2074 { 2059 {
2060 struct GNUNET_SCHEDULER_Task *last;
2061
2075 /* find out which task priority level we are going to 2062 /* find out which task priority level we are going to
2076 process this time */ 2063 process this time */
2077 max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP; 2064 max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP;
@@ -2088,7 +2075,9 @@ GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh)
2088 } 2075 }
2089 GNUNET_assert (NULL != pos); /* ready_count wrong? */ 2076 GNUNET_assert (NULL != pos); /* ready_count wrong? */
2090 2077
2091 /* process all tasks at this priority level, then yield */ 2078 /* process all *existing* tasks at this priority
2079 level, then yield */
2080 last = ready_tail[work_priority];
2092 while (NULL != (pos = ready_head[work_priority])) 2081 while (NULL != (pos = ready_head[work_priority]))
2093 { 2082 {
2094 GNUNET_CONTAINER_DLL_remove (ready_head[work_priority], 2083 GNUNET_CONTAINER_DLL_remove (ready_head[work_priority],
@@ -2147,7 +2136,8 @@ GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh)
2147 } 2136 }
2148 if (NULL != pos->fds) 2137 if (NULL != pos->fds)
2149 { 2138 {
2150 int del_result = scheduler_driver->del (scheduler_driver->cls, pos); 2139 int del_result = scheduler_driver->del (scheduler_driver->cls,
2140 pos);
2151 if (GNUNET_OK != del_result) 2141 if (GNUNET_OK != del_result)
2152 { 2142 {
2153 LOG (GNUNET_ERROR_TYPE_ERROR, 2143 LOG (GNUNET_ERROR_TYPE_ERROR,
@@ -2158,6 +2148,13 @@ GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh)
2158 active_task = NULL; 2148 active_task = NULL;
2159 dump_backtrace (pos); 2149 dump_backtrace (pos);
2160 destroy_task (pos); 2150 destroy_task (pos);
2151 /* pointer 'pos' was free'd, but we can still safely check for
2152 pointer equality still. */
2153 if (pos == last)
2154 break; /* All tasks that _were_ ready when we started were
2155 executed. New tasks may have been added in the
2156 meantime, but we should check with the OS to
2157 be sure no higher-priority actions are pending! */
2161 } 2158 }
2162 } 2159 }
2163 shutdown_if_no_lifeness (); 2160 shutdown_if_no_lifeness ();