3. Runnable & Running
struct runqueue {
spinlock_t lock;
unsigned long nr_running;
unsigned long long nr_switches;
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;
3
4. Runnable & Running(cont.)
#define BITMAP_SIZE ((((MAX_PRIO+1+7)/8)+sizeof(long)-1)/sizeof(long))
H 0
H
struct prio_array { p4 ... ...
100
unsigned int nr_active;
H H
unsigned long bitmap[BITMAP_SIZE]; 139 p1
p2
bitmap
struct list_head queue[MAX_PRIO];
0
};
... ...
100
idx = sched_find_first_bit(array->bitmap); 139
queue = array->queue + idx; queue
next = list_entry(queue->next, task_t, run_list);
struct prio_array
4
5. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
p4 ... ... ... ...
100 100
H H
139 p1 139
p2
queue p3 queue
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
P4 has the highest priority, and is selected for its execution
process
list_head 5
6. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
p4 ... ... p4 ... ...
100 100
H H
139 p1 139
p2
queue p3 queue
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
Later on, P4 runs out of its timeslice, and get moved to the expired array
process
list_head 6
7. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ...
100 100
H H
139 p1 139
p2
queue p3 queue
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
Bitmaps are also updated
process
list_head 7
8. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ...
100 100
H H
139 p1 139
p2
queue p3 queue
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
Now, P2 has the highest priority, and is selected for its execution
process
list_head 8
9. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 p1 139
p2
queue p3 queue
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
Later on, P2 runs out of its timeslice, and get moved to the expired array
process
list_head 9
10. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 p1 139
p2
queue p3 queue
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
Bitmaps are also updated
process
list_head 10
11. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 p1 139
queue p3 queue
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
Now, P1 has the highest priority, and is selected for its execution
process
list_head 11
12. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 p1 139
queue p3 queue
0 0
... ... p5 ... ...
100 100
139 139
bitmap bitmap
*active *expired
During its execution, it forks a child process P5
process
list_head 12
13. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 p5 139
queue p1 queue
p3
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
To avoid COW overhead, P1 yields the CPU to the P5
process
list_head 13
14. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 p5 H 139
queue p1 p5 queue
p3
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
Later on, P5 runs out of its timeslice, and get moved to the expired array
process
list_head 14
15. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 p5 H 139
queue p1 p5 queue
p3
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
Bitmaps are also updated
You may notice that it’s priority is changed here process
We will explain this later list_head 15
16. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 p1 139 H
H
queue p3 p5 queue
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
P1 resumes its execution, finishes its job and then exits
This is a typical fork() and the exec() scenario process
list_head 16
17. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 p3 139 H
H
queue p5 queue
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
Now, P3 has the highest priority, and is selected for its execution
process
list_head 17
18. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 p3 139 H
H
queue p5 queue p3
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
Later on, P3 runs out of its timeslice, and get moved to the expired array
process
list_head 18
19. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 p3 139 H
H
queue p5 queue p3
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*active *expired
Bitmaps are also updated
process
list_head 19
20. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 139 H
H
queue p5 queue p3
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
Exchange!
*active *expired
Now the active array is empty, scheduler exchanges it with the expired one
process
list_head 20
21. Runnable & Running(cont.)
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 100
H H
139 139 H
H
queue p5 queue p3
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*expired *active
Another round begins!
process
list_head 21
22. What Polices Do We Have?
0 MAX_RT_PRIO MAX_PRIO
SCHED_NORMAL
Ranges from MAX_RT_PRIO to MAX_PRIO - 1 (100 ~ 139)
SCHED_FIFO & SCHED_RR
Ranges from 0 to MAX_RT_PRIO -1 (0 ~ 99)
Both are soft real-time scheduling.
A SCHED_FIFO process doesn’t have timeslice.
A SCHED_RR process only round-robbin with those which have
equal priority.
The real-time processes:
never expire.
work with static priority
22
23. Realtime Scheduling
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p1
100 p2 100 p5
H H H
139 139 H
p6 p3
queue queue
p7
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*expired *active
P4 has the highest priority, and is selected for its execution
RR process Normal process
FIFO process list_head 23
24. Realtime Scheduling
struct prio_array array[2]
H 0 0
H H H
... ... p2 ... ... p1
100 p4 100 p5
H H H
139 139 H
p6 p3
queue queue
p7
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*expired *active
P4 runs out its timeslice, but since its a RR process, it does not expire
Scheduler reinserts it to the tail of its priority list
RR process Normal process
FIFO process list_head 24
25. Realtime Scheduling
struct prio_array array[2]
H 0 0
H H H
... ... p2 ... ... p1
100 p4 100 p5
H H H
139 139 H
p6 p3
queue queue
p7
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*expired *active
Now P2 has the highest priority, and is selected for its execution
RR process Normal process
FIFO process list_head 25
26. Realtime Scheduling
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p1
100 100 p5
H H H
139 139 H
p6 p3
queue queue
p7
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*expired *active
P2 finishes its job and exits
Now P4 has the highest priority, and is selected for its execution
RR process Normal process
FIFO process list_head 26
27. Realtime Scheduling
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p1
100 100 p5
H H H
139 139 H
p6 p3
queue queue
p7
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*expired *active
In this case, unless P4 exits or voluntarily relinquishes its execution,
or higher priority processes are created/waked up, it monopolize the CPU
RR process Normal process
FIFO process list_head 27
28. Realtime Scheduling
struct prio_array array[2]
H 0 0
H H H
... ... ... ... p1
100 100 p5
H H H
139 139 H
p6 p3
queue queue
p7
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*expired *active
Later on, P4 finishes its job and exits
P1 is selected for its execution
RR process Normal process
FIFO process list_head 28
29. Realtime Scheduling
struct prio_array array[2]
H 0 0
H H H
... ... ... ... p5
100 100 p1
H H H
139 139 H
p6 p3
queue queue
p7
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*expired *active
P1 runs out its timeslice and is reinserted to the tail of its list
RR process Normal process
FIFO process list_head 29
30. Realtime Scheduling
struct prio_array array[2]
H 0 0
H H H
... ... ... ... p5
100 100 p1
H H H
139 139 H
p6 p3
queue queue
p7
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*expired *active
P5 is FIFO realtime, it does not have timeslice.
Unless higher priority processes are created/waked up, it monopolizes the CPU
RR process Normal process
FIFO process list_head 30
31. The Priority of Processes
0 MAX_RT_PRIO MAX_PRIO
Static priority
mapping
Ranges from -20 to 19
Specified by the user (nice value).
Dynamic priority
A bonus or penalty from the range -5 to +5 based on the
interactivity of the task.
#define MAX_USER_RT_PRIO 100
#define MAX_RT_PRIO MAX_USER_RT_PRIO
#define MAX_PRIO (MAX_RT_PRIO + 40)
#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20)
#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20)
#define TASK_NICE(p) PRIO_TO_NICE((p)->static_prio)
31
32. The Priority of Processes(cont.)
Struct task_struct Dynamic priority.
{
int state; Specified by the user.(nice)
...
int prio, static_prio; Ranges from 0 to MAX_SLEEP_AVG
...
prio_array_t *array; timer_interrupt()
unsigned long sleep_avg;
unsigned long long timestamp, last_ran; update_process_times()
unsigned long long sched_time;
int activated;
scheduler_tick()
unsigned long policy; if (!--p->time_slice)
cpumask_t cpus_allowed;
unsigned int time_slice, first_time_slice; recalc_task_prio()
...
effective_prio()
32
33. When A Process is Interactive Enough…
struct prio_array array[2]
H 0 0
H H H
... ... p4 ... ... p2
100 p1 100
H H
139 139 H
H p3
queue queue
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*expired *active
If P4 has enough interactivity, after it runs out its timeslice,
the scheduler would reinsert it to the end of its list
Case 1 process
list_head 33
34. When A Process is Interactive Enough…
struct prio_array array[2]
H 0 0
H H H
... ... p1 ... ... p2
100 p4 100
H H
139 139 H
H p3
queue queue
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*expired *active
The scheduler would reinsert it to the end of its list
instead of moving it to the expired array
Case 1 process
list_head 34
35. When A Process is Interactive Enough…
struct prio_array array[2]
H 0 0
H H H
p4 ... ... p4 ... ... p2
100 p1 100
H H
139 139 H
H p3
queue queue
0 0
... ... ... ...
100 100
139 139
bitmap bitmap
*expired *active
However, if there are any processes that have been starved,
it still has to be expired to prevent further starvation
Case 2 process
list_head 35
40. Control Flow of scheduler_tick()
scheduler_tick()
yes no(FIFO)
Realtime task? Round robbin?
no yes
yes yes
Timeslice remained? Timeslice remained?
no
no
Remove from active
Set need_reschedule flag
Recalculate priority
and timeslice Continue exection
yes no
Interactive enough? Is there any task in Reinsert to active
no expired starving?
yes
Reinsert to expired
Set need_reschedule flag
40
41. Charge Ticks to the Current Process
timer_interrupt() #define user_mode(regs) (!!((regs)->cs & 3))
update_process_times(user_mode(regs))
User mode? jiffies_to_cputime(1)
No Yes
account_user_time() p->utime = cputime_add(p->utime, cputime);
account_system_time() p->stime = cputime_add(p->stime, cputime);
41