Wait for Hard Disk Reading Data, Process Scheduling, and Switch to Process 0 to Execute

Một phần của tài liệu The art of linux kernel design (Trang 149 - 152)

3.3.1 Preparing to Install the Hard Disk File System by Process 1

3.3.1.5 Wait for Hard Disk Reading Data, Process Scheduling, and Switch to Process 0 to Execute

After entering the schedule functions, it switches to process 0. Figure 3.28 gives the main steps.

Specific implementation steps have been illustrated in Section 3.2. The results are not similar to the execution results in Section 3.2 when traversing task[64] the second time. At this time, only two processes, the state of process 0 is interruptible state, the state of pro- cess 1 is set to uninterruptible state, the conventional process switching condition is that has the most of rest time piece and must be ready state. Like the code "if ((*p)-> state ==

TASK_RUNNING & & (* p)-> counter > c)" give conditions. Now the two processes are not ready condition, according to the conventional conditions, it cannot be the switching process and no process can be executed.

This is a very embarrassing state!

To solve this problem, the designers of the OS are forced to switch to process 0!

Note: The value of c will continue to be -1; hence, the next will still be 0, next is the process ID which switch to. If there is no suitable process, the value of next will always be 0, and the process will switch to process 0 to execute.

The execution code is as follows:

//code path:kernel/sched.c:

void schedule(void) {

……

while (1) { c = -1;

next = 0;

i = NR_TASKS;

//code path:kernel/sched.c:

void sleep_on(struct task_struct **p) {

struct task_struct *tmp;

if (!p)

return;

if (current == &(init_task.task))

panic(“task[0] trying to sleep”);

tmp = *p;

*p = current;

current->state = TASK_UNINTERRUPTIBLE;

schedule();

if (tmp)

tmp->state = 0;

}

p = &task[NR_TASKS];

while (— — i) { if (!*— — p)

continue;

if ((*p)->state == TASK_RUNNING && (*p)->counter > c) c = (*p)->counter, next = i;

}

if (c) break;

for(p = &LAST_TASK ; p > &FIRST_TASK ;— — p) if (*p)

(*p)->counter = ((*p)->counter >> 1) + (*p)->priority;

}

switch_to(next);//next is 0!

}

Kernel

Enable interrupt

0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF

Kernel code area Kernel data area

Schedule switch_to EIP

Disk Process status

Process 0 Process 1

Uninterruptible Interruptible

Current process

Step 1:

enable interrupt, since every process has standalone eflag

Step 2: switch to process 0 Step 3: execute switch_to Execute instructions next to the switch point of process 0

“cmpl %%ecx,_last_task_used_math\n\t”\ Reading data continuously from disk

ROM BIOS and VGA

Figure 3.28 Switch to process 0 to execute.

Call switch_to(0). The execution code is as follows:

After executing switch_to(0), it has switched to process 0. As illustrated in Section 3.2, when the process 0 switch to the process 1, it begin with the line “ljmp% 0\n\t” of the switch_to(1) switch to, TSS save all the value of CPU registers, cs,eip points to the next line, so the process 0 begin to execute from the cmpl%% ecx _last_task_used_math \n\t. It is shown as the third step in Figure 3.28.

Execute code as follows:

In Section 3.2, process 0 switching to process 1 is caused by pause(), sys_pause(), schedule(), and switch_to(1). Now, the latter part of switch_to(1) has been implemented; it will return to sys_pause(), for (;;) the pause() to execute.

Pause() will be called repeatedly in the for (;;) cycle; thus, it will continue to call sched- ule() to switch process. When switching again, the two processes are not in the ready status, all processes suspend, and the kernel performs switch_to and is forced to switch to process 0.

//code path:kernel/sched.h:

#define switch_to(n) {\

struct {long a,b;} __tmp; \

__asm__(“cmpl%%ecx,_current\n\t” \

“je 1f\n\t” \

“movw%%dx,%1\n\t” \

“xchgl%%ecx,_current\n\t” \

“ljmp%0\n\t” \ //jump to process 0, reference the

//introduction of switch_to in Section 3.2

“cmpl%%ecx,_last_task_used_math\n\t” \

“jne 1f\n\t” \

“clts\n” \

“1:” \

::“m” (*&__tmp.a),“m” (*&__tmp.b), \

“d” (_TSS(n)),“c” ((long) task[n])); \ }

//code path:kernel/sched.h:

#define switch_to(n) {\

struct {long a,b;} __tmp; \

__asm__(“cmpl%%ecx,_current\n\t” \

“je 1f\n\t” \

“movw%%dx,%1\n\t” \

“xchgl%%ecx,_current\n\t” \

“ljmp%0\n\t” \

cmpl%%ecx,_last_task_used_math\n\t” \ //from this line to //execute, in this case, //it‘s process 0 with //privilege level 0

“jne 1f\n\t” \

“clts\n” \

“1:” \

::“m” (*&__tmp.a),“m” (*&__tmp.b), \

“d” (_TSS(n)),“c” ((long) task[n])); \ }

Now, the condition that switch_to need to deal with has some changes, the meaning of “cmpl%% ecx, _current \n\t” “je, 1f\n\t,” is: if the process to switch to is the current pro- cess, jump to the following “1:” directly return. The current process is the process 0 and also the process to switch to, just meet this condition.

The execution code is as follows:

Hence, return to process 0 (Note: it’s not switch to process 0).

Repeatedly execute this operation.

From here, the reader can see the special functions of process 0 that are designed by OS designers: when all processes suspend or do not have any process to execute, process 0 emerges to maintain the basic OS functions, waiting other suspended processes meet the ready condition to continue execute (Figure 3.29).

Note: The read and write speed of the hard disk are much lower than the speed of the CPU in executing instructions (about two to three orders of magnitude). Now, the drive is still busy reading the specified data into its cache.

Một phần của tài liệu The art of linux kernel design (Trang 149 - 152)

Tải bản đầy đủ (PDF)

(524 trang)