fn next_task()

in src/scheduler/pct.rs [92:128]


    fn next_task(&mut self, runnable: &[TaskId], current: Option<TaskId>, is_yielding: bool) -> Option<TaskId> {
        // If any new tasks were created, assign them priorities at random
        let known_tasks = self.priority_queue.len();
        let max_tasks = usize::from(*runnable.iter().max().unwrap());

        for tid in known_tasks..1 + max_tasks {
            let index = self.rng.gen_range(0, self.priority_queue.len() + 1);
            self.priority_queue.insert(index, TaskId::from(tid));
        }

        // No point doing priority changes when there's only one runnable task. This also means that
        // our step counter is counting actual scheduling decisions, not no-ops where there was no
        // choice about which task to run. From the paper (4.1, "Identifying Sequential Execution"):
        // > Inserting priority change points during sequential execution is not necessary. The same
        // > effect can be achieved by reducing the priority at the point the sequential thread
        // > enables/creates a second thread.
        // TODO is this really correct? need to think about it more
        if runnable.len() > 1 {
            if self.change_points.contains(&self.steps) || is_yielding {
                // Deprioritize `current` by moving it to the end of the list
                // TODO in the paper, the i'th change point gets priority i, whereas this gives d-i.
                // TODO I don't think this matters, because the change points are randomized.
                let current = current.expect("self.steps > 0 should mean a task has run");
                let idx = self.priority_queue.iter().position(|tid| *tid == current).unwrap();
                self.priority_queue.remove(idx);
                self.priority_queue.push(current);
            }

            self.steps += 1;
            if self.steps > self.max_steps {
                self.max_steps = self.steps;
            }
        }

        // Choose the highest-priority (== earliest in the queue) runnable task
        Some(*self.priority_queue.iter().find(|tid| runnable.contains(tid)).unwrap())
    }