7.3 Data Structures Used by the Scheduler | | | | | |
| · The runqueue Data Structure | | | | | |
| | //kernel/sched.c | | | | | |
| | /* | | | | | | |
| | * This is the main, per-CPU runqueue data structure. | | |
| | * | | | | | | |
| | * Locking rule: those places that want to lock multiple runqueues | |
| | * (such as the load balancing or the thread migration code), lock | |
| | * acquire operations must be ordered by ascending &runqueue. | | |
| | */ | | | | | | |
| | struct runqueue { | | | | | |
| | | spinlock_t lock; | | | | |
| | | | | | | | |
| | | /* | | | | | |
| | | * nr_running and cpu_load should be in the same cacheline because |
| | | * remote CPUs use both these fields when doing load calculation. |
| | | */ | | | | | |
| | | unsigned long nr_running; | | | | |
| | #ifdef CONFIG_SMP | | | | | |
| | | unsigned long cpu_load; | | | | |
| | #endif | | | | | | |
| | | unsigned long long nr_switches; | | | |
| | | | | | | | |
| | | /* | | | | | |
| | | * This is part of a global counter where only the total sum | |
| | | * over all CPUs matters. A task can increase this counter on | |
| | | * one CPU and if it got migrated afterwards it may decrease | |
| | | * it on another CPU. Always updated under the runqueue lock: | |
| | | */ | | | | | |
| | | unsigned long nr_uninterruptible; | | | |
| | | | | | | | |
| | | unsigned long expired_timestamp; | | | |
| | | unsigned long long timestamp_last_tick; | | |
| | | task_t *curr, *idle; | | | | |
| | | struct mm_struct *prev_mm; | | | |
| | | prio_array_t *active, *expired, arrays[2]; | | |
| | | int best_expired_prio; | | | | |
| | | atomic_t nr_iowait; | | | | |
| | | | | | | | |
| | #ifdef CONFIG_SMP | | | | | |
| | | struct sched_domain *sd; | | | | |
| | | | | | | | |
| | | /* For active balancing */ | | | |
| | | int active_balance; | | | | |
| | | int push_cpu; | | | | |
| | | | | | | | |
| | | task_t *migration_thread; | | | | |
| | | struct list_head migration_queue; | | | |
| | #endif | | | | | | |
| | | | | | | | |
| | #ifdef CONFIG_SCHEDSTATS | | | | |
| | | …… | | | | | |
| | #endif | | | | | | |
| | }; | | | | | | |
| · fields of task_struct Data Structure | | | | | |
| | …… | | | | | | |
| | static DEFINE_PER_CPU(struct runqueue, runqueues); | | |
| | | | | | | | |
| | #define for_each_domain(cpu, domain) / | | | | |
| | | for (domain = cpu_rq(cpu)->sd; domain; domain = domain->parent) |
| | | | | | | | |
| | #define cpu_rq(cpu) | (&per_cpu(runqueues, (cpu))) | | |
| | #define this_rq() | (&__get_cpu_var(runqueues)) | | |
| | #define task_rq(p) | cpu_rq(task_cpu(p)) | | | |
| | #define cpu_curr(cpu) | (cpu_rq(cpu)->curr) | | | |
| | | | | | | | |
| | When a new process is created, sched_fork( ), invoked by copy_process( ), | |
| | sets the time_slice field of both current (the parent) and p (the child) | |
| | processes in the following way: | | | | |
| | p->time_slice = (current->time_slice + 1) >> 1; | | | |
| | current->time_slice >>= 1; | | | | | |
| | | | | | | | |
7.4. Functions Used by the Scheduler | | | | | |
| The scheduler relies on several functions in order to do its work; the most important are: | |
| scheduler_tick( ) | | | | | | |
| | Keeps the time_slice counter of current up-to-date | | |
| try_to_wake_up( ) | | | | | | |
| | Awakens a sleeping process | | | | |
| recalc_task_prio( ) | | | | | | |
| | Updates the dynamic priority of a process | | | |
| schedule( ) | | | | | | |
| | Selects a new process to be executed | | | | |
| load_balance() | | | | | | |
| | Keeps the runqueues of a multiprocessor system balanced | | |
| | | | | | | | |