61615603
XV6 Process Switch-swtch function
Process switching because of the need to save the current process register state information, but also the new process record register state information loaded into the register, so it involves a lot of stack operation, the back and forth between the stack, easy to dazzle, difficult to understand. This article attempts to analyze the process switching process in the following xv6.
The current process switches the process by calling the yield function. The yield function calls the Sched function, and the Sched function starts the Swtch function to complete the process switch. The whole process is this:
yield->sched->swtch
In the Sched function, you can see that the current process always switches to the current CPU's scheduler switch:
//void sched(void)swtch(&proc->context, cpu->scheduler);
The Switcher is a dead loop that continuously scans the process table and selects a runnable process schedule, which is the transition from the scheduler switch to the newly selected process:
Scheduler switch Voidscheduler (void) {structProc*p;for (;;) {Enable interrupts on the this processor. STI ();Loop over process table looking for process to run. Acquire (&ptable.lock);For (p = ptable. Proc P < &ptable. Proc[nproc]; p++) { if (p->state! = RUNNABLE) continue; //Switch to chosen process. It is the process's job //to release ptable.lock and then reacquire it //before jumping back to us. proc = p; SWITCHUVM (p); p->state = RUNNING; Swtch (&cpu->scheduler, proc->context); SWITCHKVM (); c10>//Process is do running for now. //It should has changed its p->state before coming back. proc = 0;} release (&ptable.lock);}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21st
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
Obviously, theswtch function is the focus. The prototype of the Swtch function is:
void swtch(struct context **old, struct context *new);
Its work mainly includes: 1. Saves the context of the current (old) process. 2. Load the new process context into the machine register.
The Contex is actually a few register variables that are used to hold the values of these registers.
The function code for Swtch is as follows:
# Context Switch## void Swtch (struct context **old, struct context *new);## Save Current Register context# and then the load register context from new. Globl SWTCHSWTCH:MOVL4 (%esp), %eax movl 8 (%esp), %edx # Save Old Callee-save registers PUSHL %ebp pushl %EBX PUSHL Span class= "hljs-variable" >%esi pushl %edi # Switch Stacks MOVL %esp, (%eax) movl %edx, Span class= "hljs-variable" >%esp # Load new Callee-save registers popl %edi popl %esi popl %ebx popl %EBP ret
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21st
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
Following is an analysis of the following Swtch function execution procedures.
The execution process of swtch function
When any process calls the Swtch function, the stack of the process looks like this:
where each storage area in the stack is 4 bytes. Here we need to mention that when executing the command call, the address of the next instruction of the current instruction will be pushed to the stack, that is, the eip seen above, so that when the function returns, it can be returned to the next instruction of the function. Then Swtch began to execute,
4(%esp), %eaxmovl 8(%esp), %edx
So the register EAX and edx will point to the location as shown:
The Register of contextual information is then pushed to the stack in turn
%ebp pushl %ebx pushl %esi pushl %edi
After the push is finished, you can stack the layout as shown:
Comparing Contex and the current stack layout, you can see intuitively that at this point the stack is stored on exactly a contex. The current stack top ESP points to the address of the first element in the Contex of the current process, so it can be said that the Contex includes the stack information and register information, not only can use it for stack switching, it can also be used to recover registers . It is therefore conceivable that the next time the process is re-dispatched, only the information on the stack can be bounced directly into the appropriate registers. And this stack top pointer, we can directly with the Proc->contex pointer record on it. That
proc->contex = esp;
Let's continue to look at the Swtch function:
# Switch stacks movl %esp, (%eax) movl %edx, %esp
As you can see from the comments, these two lines are mostly used for stack switching. As we know earlier, the pointer to Old_proc->contex is stored in eax, and Old_proc->contex is a pointer to the Contex of the current process, so Movl%esp, (%EAX), is equivalent to:
old_proc->contex = esp;
That is, the Contex pointer to the current process points to the top of the stack. According to the above we can understand the principle.
To this end, the Contex preservation of the old process has been completed.
The following work is a natural way to pop the contex of the new process into the corresponding register. In fact, the save process and pop-up recovery process is symmetrical .
From the save process, we know that the Contex information of the new process can always be obtained through New_proc->contex, because New_proc->contex points to the top of the New_proc kernel stack, and the top of the stack holds the context register information in sequence. , so the New_proc->contex is assigned to ESP to complete the stack switch, and then pop can restore the context register information . But how do we get New_proc's Contex? Back to the front, we saw that, as the process calls Swtch, the New_proc Contex is placed on the stack, and based on the previous Edx=new_proc->contex. So the stack switch is
esp= edx;
And then
%edipopl %esipopl %ebxpopl %ebp
The register values saved in New_contex can then be bounced back to the corresponding registers in turn.
The final
ret
command to bounce the EIP back. So the new process starts execution from the next instruction that it last called the Swtch function.
XV6 Process Switch-swtch function