当前位置:网站首页>ucore lab4
ucore lab4
2022-06-27 08:54:00 【CNRalap】
UCORE experiment 4
The experiment purpose
Learn about kernel thread creation / The implementation of the management process and the kernel thread switching and basic scheduling process .
Experimental content
experiment 2/3 Completed physical and virtual memory management , This creates a kernel thread ( Kernel thread is a special process ) Laid the foundation for providing memory management . When a program is loaded into memory to run , First, through ucore OS The memory management subsystem allocates appropriate space , Then you need to think about how to use time-sharing CPU Come on “ Concurrent ” Execute multiple programs , Let each program run ( Here, thread or process is used to represent )“ feel ” They each have “ own ” Of CPU.
This experiment will first touch the management of kernel threads . Kernel thread is a special process , There are two differences between kernel threads and user processes :
Kernel thread only runs in kernel state , User processes run alternately in user mode and kernel mode .
All kernel threads share ucore Kernel memory space , There is no need to maintain separate memory space for each kernel thread , User processes need to maintain their own user memory space .
See the appendix for the introduction of relevant principles B:【 principle 】 process / Thread properties and characteristics analysis .
( stay ucore Scheduling and execution management of , There is no distinction between threads and processes . And because ucore All kernel threads in the kernel share a kernel address space and other resources , So these kernel threads belong to the same unique kernel process , namely ucore The kernel itself .)
practice 0: Fill in the existing experiment
This experiment relies on experiments 1/2/3. Please take your experiment 1/2/3 Fill in the code in this experiment. There are “LAB1”,“LAB2”,“LAB3” The corresponding part of the notes .
analysis
Use meld You can modify it. .
practice 1: Allocate and initialize a process control block ( Need to code )
alloc_proc function ( be located kern/process/proc.c in ) Assign and return a new struct proc_struct structure , Used to store the management information of the newly established kernel thread .ucore This structure needs to be initialized at the most basic level , You need to complete this initialization process .
【 Tips 】 stay alloc_proc Function implementation , Need to initialize proc_struct The member variables in the structure include at least :state/pid/runs/kstack/need_resched/parent/mm/context/tf/cr3/flags/name.
Please briefly describe your design and implementation process in the experimental report . Please answer the following questions :
Please explain proc_struct in struct context context and struct trapframe *tf What is the meaning of member variables and their role in this experiment ?( Tip: you can tell by looking at the code and programming debugging )
analysis
Relevant background knowledge :
Threads and processes :
The unit that owns the resource is often still called a process , The management of resources becomes process management ; The unit of instruction execution flow is called thread , Thread management is thread scheduling and thread dispatch . In a process , There may be one or more threads , Each thread has thread execution state ( function 、 be ready 、 Waiting, etc ), Save the thread context of the last run 、 Thread execution stack, etc . in consideration of CPU There are different privilege modes , Refer to the classification of processes , Threads can be further refined into user threads and kernel threads .
Process control block :
The process control block is a collection of information used by the operating system to manage and control the process . For the operating system PCB To describe the basic situation of the process and the process of running changes .PCB Is the only sign that a process exists , Each process has a corresponding... In the operating system PCB. Process control blocks can be organized through a data structure ( Such as the list ). Of processes in the same state PCB Connect into a linked list , Multiple states correspond to multiple different linked lists . The process of each state forms a different linked list , Such as ready linked list , Block linked list, etc .
In Experiment 4 , Process management information struct proc_struct Express , stay kern/process/proc.h Is defined as follows :
struct proc_struct {
enum proc_state state; // Process state
int pid; // Process ID
int runs; // the running times of Proces
uintptr_t kstack; // Process kernel stack
volatile bool need_resched; // need to be rescheduled to release CPU?
struct proc_struct *parent; // the parent process
struct mm_struct *mm; // Process's memory management field
struct context context; // Switch here to run process
struct trapframe *tf; // Trap frame for current interrupt
uintptr_t cr3; // the base addr of Page Directroy Table(PDT)
uint32_t flags; // Process flag
char name[PROC_NAME_LEN + 1]; // Process name
list_entry_t list_link; // Process link list
list_entry_t hash_link; // Process hash list
};
Some of the more important member variables :
● mm: Memory management information , Include a list of memory mappings 、 Page table pointer, etc .mm Member variables are in lab3 For virtual storage management . But in reality OS in , Kernel threads are resident in memory , There is no need to consider swap page problem , stay lab5 User processes are involved in , To consider the memory space of the process user swap page problem ,mm It will work . So in lab4 in mm No use for kernel threads , So the kernel thread proc_struct Member variables of * mm=0 It's reasonable .mm There is a very important item in pgdir, The physical address of the first level page table used by the process is recorded . because *mm=NULL, So in proc_struct There needs to be a substitute in the data structure pgdir Item to record the starting address of the page table , This is it. proc_struct In data structure cr3 Member variables .
● state: The state of the process , There are four kinds ,PROC_UNINIT( uninitialized ),PROC_SLEEPING( Sleep ),PROC_RUNNABLE( Ready to run ),PROC_ZOMBIE( Zombie process , Wait for the parent process to recycle resources ).
● parent: The parent process of the user process ( The process that created it ). In all the processes , Only one process has no parent process , Is the first kernel thread created by the kernel idleproc. The kernel builds a tree structure based on this parent-child relationship , It is used to maintain some special operations , For example, determine whether one process can perform some operation on another process, etc .
● context: The context of the process , For process switching ( See switch.S). stay uCore in , All processes are relatively independent in the kernel ( For example, independent kernel stack and context, etc ). Use context The purpose of saving registers is to switch between contexts in kernel mode . The actual use of context The function for context switching is in kern/process/switch.S In the definition of switch_to.
● tf: Pointer to the interrupt frame , Always point to a location on the kernel stack : When a process jumps from user space to kernel space , The interrupt frame records the status of the process before it is interrupted . When the kernel needs to jump back into user space , The interrupt frame needs to be adjusted to recover the values of each register that allows the process to continue execution . besides ,uCore The kernel allows nested interrupts . Therefore, to ensure that nested interrupts occur tf Always able to point to the current trapframe,uCore Maintained on the kernel stack tf Chain , You can refer to trap.c::trap Function to further understand .
● cr3: cr3 Save the physical address of the page table , The purpose is to facilitate direct use during process switching cr3 Realize page table switching , Avoid every time according to mm To calculate cr3.mm Data structure is used to realize virtual memory management of user space , But kernel threads have no user space , It executes only a small piece of code in the kernel ( It's usually a short function ), So it doesn't have mm structure , That is to say NULL. When a process is a normal user mode process ,PCB Medium cr3 Namely mm Middle page table (pgdir) The physical address of ; When it is a kernel thread ,cr3 be equal to boot_cr3. and boot_cr3 Yes uCore The first address of the page directory table of the kernel virtual space established at startup .
● kstack: Each thread has a kernel stack , And in different locations in the kernel address space . For kernel threads , This stack is the stack used by the program at run time ; For ordinary processes , This stack is used to save the interrupted hardware information when the privilege level changes .uCore When the process was created, it was assigned 2 Consecutive physical pages ( See memlayout.h in KSTACKSIZE The definition of ) Space as kernel stack . This stack is very small , So the code in the kernel should be as compact as possible , And avoid allocating large data structures on the stack , Avoid stack overflow , Causing the system to crash .kstack Records the assigned to the process / The location of the kernel stack of the thread . The main functions are as follows : First , When the kernel is ready to switch from one process to another , Need basis kstack The value of is set correctly tss ( You can review what was said in Experiment 1 tss Role in interrupt processing ), So that the correct stack can be used in case of interruption after process switching . secondly , The kernel stack is located in the kernel address space , And not shared ( Each thread has its own kernel stack ), So it's not subject to mm Management of , When the process exits , The kernel can be based on kstack To quickly locate the stack and recycle it .uCore The design of this kernel stack is based on linux Methods ( However, due to the differences in memory management implementation , It is far less realized than linux Flexible ), It makes the kernel stack of each thread in a different location , This is convenient for debugging to some extent , But it also makes the kernel very insensitive to stack overflows , Because once overflow occurs , It is very likely to contaminate other data in the kernel and cause the kernel to crash . If you can use the page table , Map the kernel stack of all processes to a fixed address , Can avoid this problem , However, it will make the stack modification in the process of process switching very cumbersome .
To manage all process control blocks in the system ,uCore The following global variables are maintained ( be located kern/process/proc.c):
● static struct proc *current: Current occupancy CPU And in “ function ” State process control block pointer . Usually this variable is read-only , It can only be modified during process switching , And the whole switching and modification process needs to ensure the atomicity of the operation , At least you need to mask interrupts . You can refer to switch_to The implementation of the .
● static struct proc *initproc: In this study , Point to a kernel thread . After this experiment , This pointer will point to the first user mode process .
● static list_entry_t hash_list[HASH_LIST_SIZE]: Hash table of all process control blocks ,proc_struct Member variables in hash_link Will be based on pid Link into this hash table .
● list_entry_t proc_list: Bidirectional linear list of all process control blocks ,proc_struct Member variables in list_link Link into this linked list .
1.alloc_proc Implementation of function
Improve according to the background knowledge and notes :
// alloc_proc - alloc a proc_struct and init all fields of proc_struct
static struct proc_struct *
alloc_proc(void) {
struct proc_struct *proc = kmalloc(sizeof(struct proc_struct));
if (proc != NULL) {
//LAB4:EXERCISE1 202008010404
proc->state = PROC_UNINIT; // Set the process to “ initial ” state
proc->pid = -1; // Set up the process pid Uninitialized value of
proc->runs = 0; // The running time of the process is 0
proc->kstack = 0; // The kernel stack of the process is 0, That is, there is no kernel stack
proc->need_resched = 0; //1 Occupy... For processes CPU,0 Release for process CPU
proc->parent = NULL; // The parent of the process
proc->mm = NULL; //lab4 in mm It is not useful for kernel threads
memset(&(proc->context), 0, sizeof(struct context)); // Initialize process context
proc->tf = NULL; // The pointer of the interrupt frame is NULL
proc->cr3 = boot_cr3; // Use the base address of the kernel page directory table
proc->flags = 0; // The process flag is 0
memset(proc->name, 0, PROC_NAME_LEN); // Initialization process name
}
return proc;
}
2. Please explain proc_struct in struct context context and struct trapframe *tf What is the meaning of member variables and their role in this experiment
struct context context: The context of the process , For process switching ( See switch.S). stay uCore in , All processes are relatively independent in the kernel ( For example, independent kernel stack and context, etc ), Use context The purpose of saving registers is to switch between contexts in kernel mode .
struct context {
uint32_t eip;
uint32_t esp;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
uint32_t esi;
uint32_t edi;
uint32_t ebp;
};
struct trapframe *tf: Pointer to the interrupt frame , Always point to a location on the kernel stack . When a process jumps from user space to kernel space , The interrupt frame records the status of the process before it is interrupted . When the kernel needs to jump back into user space , The interrupt frame needs to be adjusted to recover the values of each register that allows the process to continue execution .
struct trapframe {
struct pushregs tf_regs;
uint16_t tf_gs;
uint16_t tf_padding0;
uint16_t tf_fs;
uint16_t tf_padding1;
uint16_t tf_es;
uint16_t tf_padding2;
uint16_t tf_ds;
uint16_t tf_padding3;
uint32_t tf_trapno;
/* below here defined by x86 hardware */
uint32_t tf_err;
uintptr_t tf_eip;
uint16_t tf_cs;
uint16_t tf_padding4;
uint32_t tf_eflags;
/* below here only when crossing rings, such as from user to kernel */
uintptr_t tf_esp;
uint16_t tf_ss;
uint16_t tf_padding5;
} __attribute__((packed));
With kernel_thread Function as an example , Describe their roles in this experiment :
int
kernel_thread(int (*fn)(void *), void *arg, uint32_t clone_flags) {
struct trapframe tf;
memset(&tf, 0, sizeof(struct trapframe));
tf.tf_cs = KERNEL_CS;
tf.tf_ds = tf.tf_es = tf.tf_ss = KERNEL_DS;
tf.tf_regs.reg_ebx = (uint32_t)fn; // Objective function address
tf.tf_regs.reg_edx = (uint32_t)arg; // Parameter address
tf.tf_eip = (uint32_t)kernel_thread_entry; //kernel_thread_entry Address
return do_fork(clone_flags | CLONE_VM, 0, &tf);
}
kernel_thread Is a function that creates a kernel thread , Local variables are used tf To place a temporary interrupt frame that holds the kernel thread , And pass the pointer of the interrupt frame to do_fork function , and do_fork Function will call copy_thread Function to allocate a space on the newly created process kernel stack for the interrupt frame of the process .
static void
copy_thread(struct proc_struct *proc, uintptr_t esp, struct trapframe *tf) {
// Set the interrupt frame size at the top of the kernel stack
proc->tf = (struct trapframe *)(proc->kstack + KSTACKSIZE) - 1;
*(proc->tf) = *tf; // Copy in kernel_thread The initial value of the temporary interrupt frame established by the function
proc->tf->tf_regs.reg_eax = 0;
// Set up child processes / The thread is finished do_fork The return value after
proc->tf->tf_esp = esp; // Set the stack pointer in the interrupt frame esp
proc->tf->tf_eflags |= FL_IF; // To interrupt
proc->context.eip = (uintptr_t)forkret;
proc->context.esp = (uintptr_t)(proc->tf);
}
After setting the interrupt frame , The last is to set initproc Process context (process context, Also called execution site ) 了 . Only after setting up the execution site , once uCore The scheduler selected initproc perform , It needs to be based on initproc->context The execution site saved in initproc Implementation . I've set it up here initproc Two main information in the execution site of : The address of the next instruction when execution was last stopped context.eip And the stack address when execution was last stopped context.esp. Actually initproc It has not been executed yet , So this is actually initproc The address and stack pointer of the first instruction actually executed . It can be seen that , because initproc The interrupt frame of takes up the actual space initproc Top of allocated stack space , therefore initproc You can only put the pointer at the top of the stack context.esp Set in the initproc The starting position of the interrupt frame of . according to context.eip Assignment , You can know initproc The place where the implementation actually started is forkret function ( yes forkrets The wrapper function of ,forkrets The main function is from current->tf Restore context in , Jump to current->tf->tf_eip, That is to say kernel_thread_entry, That is, the function completes do_fork Function returns the processing work ) It's about .
To make a long story short ,proc->context.eip = (uintptr_t)forkret It will make the new process return from the interrupt handling routine correctly . and proc->context.esp = (uintptr_t)proc_struct->tf, When the interrupt returns , Restore the new process to the saved trapframe Information to each register , Then start executing the user code . so ,tf And context It is used to save and restore the state of the process .
practice 2: Allocate resources for newly created kernel threads ( Need to code )
Creating a kernel thread requires a lot of resources to be allocated and set up .kernel_thread Function by calling do_fork Function to complete the creation of specific kernel threads .do_kernel Function will call alloc_proc Function to allocate and initialize a process control block , but alloc_proc Just found a small piece of memory to record the necessary information of the process , These resources are not actually allocated .ucore Usually by do_fork Actually create a new kernel thread .do_fork The role of is , Create a copy of the current kernel thread , Their execution context 、 Code 、 The data are the same , But the storage location is different . In the process , New kernel threads need to be allocated resources , And copy the state of the original process . You need to finish in kern/process/proc.c Medium do_fork Processing procedure in function . Its general execution steps include :
call alloc_proc, First, get a block of user information .
Assign a kernel stack to the process .
Copy the memory management information of the original process to the new process ( But kernel threads don't have to do this ).
Copy the original process context to the new process .
Add a new process to the process list .
Wake up a new process .
Return the new process number .
Please briefly describe your design and implementation process in the experimental report . Please answer the following questions :
Please explain ucore Whether to give each new fork A unique thread id? Please explain your analysis and reasons .
analysis
1. Complete according to the notes do_fork function
Let's first refine do_fork Function running process :
① Allocate and initialize process control blocks (alloc_proc function ).
② Allocate and initialize the kernel stack (setup_stack function ).
③ according to clone_flag Flag copy or share process memory management structure (copy_mm function ).
④ Set the process in the kernel ( In the future, it also includes user mode ) Interrupt frames and execution context required for normal operation and scheduling (copy_thread function ).
⑤ Put the set process control block into hash_list and proc_list In the linked list of two global processes .
⑥ Since then , The process is ready to execute , Set the process status to “ be ready ” state .
⑦ Set the return code to that of the child process id Number .
do_fork Is involved in MACROs,Functions,DEFINEs:
MACROs or Functions:
alloc_proc: create a proc struct and init fields (lab4:exercise1)
Create a proc Structure and initial fields .
setup_kstack: alloc pages with size KSTACKPAGE as process kernel stack
The allocation size is KSTACKPAGE As the kernel stack of the process .
copy_mm:process “proc” duplicate OR share process “current” 's mm according clone_flags,if clone_flags & CLONE_VM, then “share” ; else “duplicate”
according to clone_flags To determine whether the current process replicates or shares the current mm( Memory management information ), If clone_flags & CLONE_VM by 1, Then share mm, On the contrary, copy .
copy_thread:setup the trapframe on the process’s kernel stack top and setup the kernel entry point and stack of process
Create a stack frame at the top of the process's kernel stack , And set the kernel entry of the process and the stack of the process .
hash_proc:dd proc into proc hash_list
Copy the process to the process Hash list .
get_pid:alloc a unique pid for process
Assign a unique to the process pid.
wakeup_proc:set proc->state = PROC_RUNNABLE
Set the process status to ready .
VARIABLES:
proc_list:the process set’s list
Linked list of process collection .( Of the same state process PCB Will be linked into a linked list )
nr_process:the number of process set
Number of process collections .
int
do_fork(uint32_t clone_flags, uintptr_t stack, struct trapframe *tf) {
int ret = -E_NO_FREE_PROC;
struct proc_struct *proc;
if (nr_process >= MAX_PROCESS) {
goto fork_out;
}
ret = -E_NO_MEM;
//LAB4:EXERCISE2 202008010404
// First allocate and initialize a PCB, If the allocation fails, jump to fork_out
if ((proc = alloc_proc()) == NULL) {
goto fork_out;
}
//fork There must be a parent process , So set the parent process of the child process
proc->parent = current;
// Allocate and initialize the kernel stack
if (setup_kstack(proc) != 0) {
goto bad_fork_cleanup_proc;
}
// according to clone_flag Flag copy or share process memory management structure
if (copy_mm(clone_flags, proc) != 0) {
goto bad_fork_cleanup_kstack;
}
// Set the process in the kernel ( In the future, it also includes user mode ) Interrupt frames and execution context required for normal operation and scheduling
copy_thread(proc, stack, tf);
// Put the child process's PCB Add to hash_list and proc_list In the linked list of two global processes
bool intr_flag;
local_intr_save(intr_flag);// Mask interrupt , To prevent other processes from scheduling during process switching
{
proc->pid = get_pid();
hash_proc(proc);
list_add(&proc_list, &(proc->list_link));
nr_process ++;
}
local_intr_restore(intr_flag);// Turn on interrupt
// Set the new child process executable
wakeup_proc(proc);
// Returns the pid
ret = proc->pid;
fork_out:
return ret;
bad_fork_cleanup_kstack:
put_kstack(proc);
bad_fork_cleanup_proc:
kfree(proc);
goto fork_out;
}
2. Please explain ucore Whether to give each new fork A unique thread id? Please explain your analysis and reasons .
Due to the access to pid By get_pid Accomplished , So let's look at get_pid:
// get_pid - alloc a unique pid for process
static int
get_pid(void) {
static_assert(MAX_PID > MAX_PROCESS);
struct proc_struct *proc;
list_entry_t *list = &proc_list, *le;
static int next_safe = MAX_PID, last_pid = MAX_PID;
if (++ last_pid >= MAX_PID) {
last_pid = 1;
goto inside;
}
if (last_pid >= next_safe) {
inside:
next_safe = MAX_PID;
repeat:
le = list;
while ((le = list_next(le)) != list) {
proc = le2proc(le, list_link);
if (proc->pid == last_pid) {
if (++ last_pid >= next_safe) {
if (last_pid >= MAX_PID) {
last_pid = 1;
}
next_safe = MAX_PID;
goto repeat;
}
}
else if (proc->pid > last_pid && next_safe > proc->pid) {
next_safe = proc->pid;
}
}
}
return last_pid;
}
In function get_pid in , If static member last_pid Less than next_safe, The currently allocated last_pid It must be safe , The only one PID. But if last_pid Greater than or equal to next_safe, perhaps last_pid The value of exceeds MAX_PID, Then the current last_pid Is not necessarily the only PID, At this point, you need to traverse proc_list, Back to the last_pid and next_safe Set it up , For the next time get_pid Call to lay the foundation .
practice 3: Reading the code , understand proc_run Function and the function it calls how to complete process switching .( No coding work )
Please briefly explain your understanding of proc_run Analysis of functions . And answer the following questions :
During the execution of this experiment , Several kernel threads were created and run ?
sentence local_intr_save(intr_flag);…local_intr_restore(intr_flag); What is the role here ? Please give reasons
After the code is written , Compile and run the code :make qemu
If you can get something like appendix A As shown in ( For reference only , Not standard answer output ), Is basically correct .
analysis
1. Process switching and proc_run Function analysis
(1) The first kernel thread
stay uCore After execution proc_init After the function , Two kernel threads are created :idleproc and initproc. First, the current execution context ( from kern_init Since its launch ) It can be regarded as uCore kernel ( It can also be seen as a kernel process ) The context of a kernel thread in . So ,uCore By assigning a process control block to the current execution context and initializing it accordingly , Make it the No 0 Kernel threads – idleproc.
(2) Process scheduling
establish idleproc after , It will execute cpu_idle function , And call... From it schedule function , Ready to start scheduling process .
void cpu_idle(void) {
while (1) // Keep spinning until a process can be scheduled
if (current->need_resched)
schedule();
}
schedule The function is one of the simplest FIFO The core of the scheduler , The execution logic is as follows :
① Set the current kernel thread current->need_resched by 0.
② stay proc_list Find the next in the queue “ be ready ” A thread or process in a state next;.
③ After finding such a process , Just call proc_run function , Save the current process current The execution site of ( Process context ), Restore the execution site of the new process , Complete process switching .
alike , Note that the process cannot be interrupted during scheduling , Otherwise, it will cause inter process looting CPU.
schedule Function as follows :
void
schedule(void) {
bool intr_flag;
list_entry_t *le, *last;
struct proc_struct *next = NULL; // Clear the dispatch flag
local_intr_save(intr_flag); // Turn off interrupt
{
current->need_resched = 0; // Make the current process in a non scheduled state
last = (current == idleproc) ? &proc_list : &(current->list_link);
le = last;
do {
if ((le = list_next(le)) != &proc_list) {
next = le2proc(le, list_link);
if (next->state == PROC_RUNNABLE) { // Find a process in the ready state
break;
}
}
} while (le != last);
if (next == NULL || next->state != PROC_RUNNABLE) { // If not found , be next Gyrus digiti idleproc
next = idleproc;
}
next->runs ++; // Find the number of processes that need to be scheduled +1
if (next != current) {
proc_run(next); // perform proc_run, Give Way next And current Context exchange
}
}
local_intr_restore(intr_flag);
}
(3) Process switching
thus , New process next And we're going to execute it . Because in proc10 There are only two kernel threads in the , And idleproc Get out of the way CPU to initproc perform , We can see schedule Function by looking up proc_list Process queue , Only one can be found in “ be ready ” State initproc Kernel thread . And pass proc_run And further switch_to Function to switch between two execution sites , The specific process is as follows :
① Give Way current Point to next Kernel thread initproc.
② Set the task status segment ts Medium privileged state 0 Top of stack pointer under esp0 by next Kernel thread initproc The top of the kernel stack , namely next->kstack + KSTACKSIZE.
( The meaning of this setting is , Establish a kernel thread or a user thread in the future to perform privileged switching ( From the privileged state 0<–> Privileged state 3, Or from the privileged state 3<–> Privileged state 3) It can be correctly located in the privileged state 0 The top of the kernel stack of the process , In fact, there is one on the top of the stack trapframe The memory space of the structure .)
③ Set up CR3 The value of the register is next Kernel thread initproc The starting address of the page table of contents next->cr3, This actually completes the page table switching between processes .
④ from switch_to Function to switch between two threads , That is, switch each register , When switch_to Function execution finished “ret” After the instruction , Just switch to initproc Yes .
proc_run Function as follows :
// proc_run - make process "proc" running on cpu
// NOTE: before call switch_to, should load base addr of "proc"'s new PDT
void
proc_run(struct proc_struct *proc) {
// Determine whether the process to be switched to is the current process , If so, no treatment is required
if (proc != current) {
bool intr_flag;
struct proc_struct *prev = current, *next = proc;
local_intr_save(intr_flag); // Mask interrupt
{
current = proc; // Set the currently executing process
load_esp0(next->kstack + KSTACKSIZE); // Set up ring0 Kernel stack address of
lcr3(next->cr3); // Reload cr3 register , Update the page directory table to the page directory table of the new process
switch_to(&(prev->context), &(next->context)); // Context switch , Save the values of the current registers of the current process in its proc_struct Structure of the context variable , Then switch to the process proc_struct Structure of the context Variables are loaded into each register .
}
local_intr_restore(intr_flag); // Open interrupt
}
}
switch_to Function as follows :
.text
.globl switch_to
switch_to: # switch_to(from, to)
# save from's registers
movl 4(%esp), %eax # Get the... Of the current process context Structure address
popl 0(%eax) # take eip Save to... Of the current process context structure
movl %esp, 4(%eax) # take esp Save to... Of the current process context structure
movl %ebx, 8(%eax) # take ebx Save to... Of the current process context structure
movl %ecx, 12(%eax) # take ecx Save to... Of the current process context structure
movl %edx, 16(%eax) # take edx Save to... Of the current process context structure
movl %esi, 20(%eax) # take esi Save to... Of the current process context structure
movl %edi, 24(%eax) # take edi Save to... Of the current process context structure
movl %ebp, 28(%eax) # take ebp Save to... Of the current process context structure
# restore to's registers
movl 4(%esp), %eax # Get the next process's context Structure address
# It should be noted that , Its address is not 8(%esp), Because I've been pop Pass the stack once .
movl 28(%eax), %ebp # recovery ebp To the next process context structure
movl 24(%eax), %edi # recovery edi To the next process context structure
movl 20(%eax), %esi # recovery esi To the next process context structure
movl 16(%eax), %edx # recovery edx To the next process context structure
movl 12(%eax), %ecx # recovery ecx To the next process context structure
movl 8(%eax), %ebx # recovery ebx To the next process context structure
movl 4(%eax), %esp # recovery esp To the next process context structure
pushl 0(%eax) # Insert the next process's eip, For convenience ret To the code location of the next process .
ret
2. During the execution of this experiment , Several kernel threads were created and run ?
It is not difficult to see that two threads have been created ,idleproc and initproc.
3. sentence local_intr_save(intr_flag);…local_intr_restore(intr_flag); What is the role here ? Please give reasons
These two codes are used to block interrupts and unblock interrupts , This makes the code block between the two sentences form an atomic operation , Keep some key code from being broken , So as to avoid causing some unexpected errors .
Take process switching as an example , stay proc_run in , When just set up current Pointer to the next process , But the control has not been completely transferred , If the process is suddenly interrupted by an interrupt , The execution of the interrupt handling routine may throw an exception , because current The process pointed to by the pointer is inconsistent with the process resources actually used .
The final result is as follows :

Experimental experience
lab2 and lab3 Complete the virtualization of memory , But the whole control flow is executed in a line in series .lab4 On this basis CPU Virtualization of , That is to let ucore Realize time sharing CPU, Realize that multiple control flows can be executed concurrently . To some extent , We can think of the control flow as a kernel thread . This experiment gives me a better understanding of process creation , Dispatch , Context switching and other related contents : In this study ,kern_init Function to initialize the virtual memory , It's called proc_init function , This function completes idleproc Creation of kernel threads . The first 0 Kernel threads idleproc The main work is to complete the initialization of each subsystem in the kernel , Then by executing cpu_idle Function is starting to retire , But there is other work to be done , So by calling kernel_thread Function creates a kernel thread . Division call kernel_thread Out of function , Also called do_fork Functions and copy_thread Function to create kernel threads together initproc. And then idleproc Kernel threads give up CPU, Give Way schedule take initproc Kernel threads are scheduled to run , It involves process switching , and Initprocde The main function of is simply to output a string , Then return to kernel_tread_entry function , And call do_exit The exit operation has been executed .
边栏推荐
猜你喜欢

支付宝微信支付业务流程图

oracle用一条sql查出哪些数据不在某个表里

Design of a solar charge pump power supply circuit

Redis master-slave replication and sentinel mode

初步认识pytorch
![[vivid understanding] the meanings of various evaluation indicators commonly used in deep learning TP, FP, TN, FN, IOU and accuracy](/img/d6/119f32f73d25ddd97801f536d68752.png)
[vivid understanding] the meanings of various evaluation indicators commonly used in deep learning TP, FP, TN, FN, IOU and accuracy

MATLAB小技巧(18)矩阵分析--熵权法

JVM常见的垃圾收集器

RMAN-08137 主库无法删除归档文件
快捷键 bug,可复现(貌似 bug 才是需要的功能 [滑稽.gif])
随机推荐
oracle用一条sql查出哪些数据不在某个表里
IMX8QXP DMA资源和使用(未完结)
DV scroll board width of datav rotation table component
[vivid understanding] the meanings of various evaluation indicators commonly used in deep learning TP, FP, TN, FN, IOU and accuracy
我大抵是卷上瘾了,横竖睡不着!竟让一个Bug,搞我两次!
三道基础面试题总结
That is, a one-stop live broadcast service with "smooth live broadcast" and full link upgrade
ThreadLocal digs its knowledge points again
今日3大面试Demo[Integer ASCII 类关系]
fastadmin 安装后访问后台提示模块不存在
招聘需求 视觉工程师
E+H二次表维修PH变送器二次显示仪修理CPM253-MR0005
冒牌构造函数???
Creation process and memory layout of objects at JVM level
並發編程JUC的AQS底層源碼
[cloud native] 2.3 kubernetes core practice (Part 1)
CLassLoader
Win10 add right-click menu for any file
win10为任意文件添加右键菜单
RMAN-08137 主库无法删除归档文件