aboutsummaryrefslogtreecommitdiff
path: root/src/util/scheduler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/scheduler.c')
-rw-r--r--src/util/scheduler.c46
1 files changed, 36 insertions, 10 deletions
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index f3b220c4a..b57e2db66 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -248,6 +248,13 @@ struct GNUNET_SCHEDULER_Task
248 struct GNUNET_AsyncScopeSave scope; 248 struct GNUNET_AsyncScopeSave scope;
249}; 249};
250 250
251/**
252 * Placed at the end of a ready queue to indicate where a scheduler run pass
253 * ends. The next, prev, in_ready_list and priority fields are the only ones
254 * that should be used.
255 */
256static struct GNUNET_SCHEDULER_Task pass_end_marker;
257
251 258
252/** 259/**
253 * A struct representing an event the select driver is waiting for 260 * A struct representing an event the select driver is waiting for
@@ -503,6 +510,27 @@ get_timeout ()
503 return timeout; 510 return timeout;
504} 511}
505 512
513static void remove_pass_end_marker ()
514{
515 if (pass_end_marker.in_ready_list)
516 {
517 GNUNET_CONTAINER_DLL_remove (ready_head[pass_end_marker.priority],
518 ready_tail[pass_end_marker.priority],
519 &pass_end_marker);
520 pass_end_marker.in_ready_list = GNUNET_NO;
521 }
522}
523
524static void set_work_priority (enum GNUNET_SCHEDULER_Priority p)
525{
526 remove_pass_end_marker ();
527 GNUNET_CONTAINER_DLL_insert_tail (ready_head[p],
528 ready_tail[p],
529 &pass_end_marker);
530 pass_end_marker.priority = p;
531 pass_end_marker.in_ready_list = GNUNET_YES;
532 work_priority = p;
533}
506 534
507/** 535/**
508 * Put a task that is ready for execution into the ready queue. 536 * Put a task that is ready for execution into the ready queue.
@@ -518,7 +546,7 @@ queue_ready_task (struct GNUNET_SCHEDULER_Task *task)
518 ready_tail[p], 546 ready_tail[p],
519 task); 547 task);
520 if (p > work_priority) 548 if (p > work_priority)
521 work_priority = p; 549 set_work_priority (p);
522 task->in_ready_list = GNUNET_YES; 550 task->in_ready_list = GNUNET_YES;
523 ready_count++; 551 ready_count++;
524} 552}
@@ -752,6 +780,9 @@ GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p)
752 NULL != pos; 780 NULL != pos;
753 pos = pos->next) 781 pos = pos->next)
754 ret++; 782 ret++;
783 if (pass_end_marker.in_ready_list && pass_end_marker.priority == p)
784 // Don't count the dummy marker
785 ret--;
755 return ret; 786 return ret;
756} 787}
757 788
@@ -2050,8 +2081,9 @@ GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh)
2050 2081
2051 /* process all *existing* tasks at this priority 2082 /* process all *existing* tasks at this priority
2052 level, then yield */ 2083 level, then yield */
2053 last = ready_tail[work_priority]; 2084 set_work_priority (work_priority);
2054 while (NULL != (pos = ready_head[work_priority])) 2085 while (NULL != (pos = ready_head[work_priority])
2086 && pos != &pass_end_marker)
2055 { 2087 {
2056 GNUNET_CONTAINER_DLL_remove (ready_head[work_priority], 2088 GNUNET_CONTAINER_DLL_remove (ready_head[work_priority],
2057 ready_tail[work_priority], 2089 ready_tail[work_priority],
@@ -2121,14 +2153,8 @@ GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh)
2121 active_task = NULL; 2153 active_task = NULL;
2122 dump_backtrace (pos); 2154 dump_backtrace (pos);
2123 destroy_task (pos); 2155 destroy_task (pos);
2124 /* pointer 'pos' was free'd, but we can still safely check for
2125 pointer equality still. */
2126 if (pos == last)
2127 break; /* All tasks that _were_ ready when we started were
2128 executed. New tasks may have been added in the
2129 meantime, but we should check with the OS to
2130 be sure no higher-priority actions are pending! */
2131 } 2156 }
2157 remove_pass_end_marker ();
2132 } 2158 }
2133 shutdown_if_no_lifeness (); 2159 shutdown_if_no_lifeness ();
2134 if (0 == ready_count) 2160 if (0 == ready_count)