Advanced operating system process management

1, Process descriptor

Process control block PCB: it is a data structure for OS control process operation, and a task struct structure.

PCB includes: process identification information (process identifier PID, etc.), execution field information (CPU field, field information needs to be saved during process switching), process image information (process address space, i.e. where the code, data and stack are placed when the process is running, which is convenient for OS to manage the address space) (field and address space are more important), process resource information and information Information No.

For PCB, say several important fields:

Mm struct: there is a member mm, indicating the address space of the process;

thread: record the process site, the last field;

In version 4.4.6, thread "info was changed to" stack ", including the kernel stack (i.e. the stack required for the process to enter the kernel is separate from the user stack) and some data that needs to be accessed quickly.

 

 

In version 4.4.6, stack takes up two pages, i.e. 8k. Most of them are on the kernel stack, and the low end is about 10k for fast access information. If the CPU wants to access the fast access data of the current process, it only needs to get the current stack pointer, that is, the value of the ESP register. It can calculate the location of the data, so when looking up its address, the access speed can be very fast. This part of data can be regarded as a part of the process descriptor, which is not continuous in space, but there are pointers between them, which can be found each other.

 

 

Process state transition diagram, self searching.

In 4.4.6, tracking and deadlock cancellation states are added.

Process descriptors are important data structures for managing processes, so their organization is very important. The descriptor of process 0 is stored by init task. From him, all process descriptors form a two-way linked list. Task struct contains a member called tasks. The tasks type is list head. The tasks themselves are embedded in the process descriptor. If you know the address of tasks, you can get the first address of the process descriptor by subtracting 620. In Linux, there are many techniques, that is, through the embedded address, we can deduce the address of the structure, and then find other members of the structure.

 

 

Process thread relationship

Multiple threads form thread groups, sharing memory and not stack.

A session corresponds to a terminal. Typing a command in the terminal is equivalent to creating a process group to execute.

The following is a demonstration. Create a file named 0.gdb. The content of the file is as follows. Run it directly

1 target remote localhost:1234
2 dir ~/aos/lab/busybox
3 add-symbol-file ~/aos/lab/busybox/busybox_unstripped 0x8048400
4 display $lx_current().pid
5 display $lx_current().comm
6 b start_kernel
7 b ls_main
8 c

 

 

Execute the file with the following code

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <pthread.h>
 4 
 5 void loop(){
 6   while(1);
 7 }
 8 
 9 void *p1(){
10   printf("thread-1 starting\n");
11   loop();
12 }
13 
14 void *p2(){
15   printf("thread-2 starting\n");
16   loop();
17 }
18 
19 void main(){
20   int pid1, pid2;
21   pthread_t t1,t2;
22   void *thread_result;
23 
24   printf("main starting\n");
25 
26   if (!(pid1 = fork())){
27     printf("child-1 starting\n");
28     loop();
29     exit(0);
30   }
31 
32   if (!(pid2 = fork())){
33     printf("child-2 starting\n");
34     loop();
35     exit(0);
36   }
37 
38   pthread_create(&t1, NULL, p1, NULL);
39   pthread_create(&t2, NULL, p2, NULL);
40   
41   pthread_join(t1, &thread_result);
42   pthread_join(t2, &thread_result);
43 
44   int status;
45   waitpid(pid1, &status, 0);
46   waitpid(pid2, &status, 0);
47   printf("main exiting\n");
48   exit(0);
49 }

You can see that the do fork executable creates three processes, 976, 977, 978

 

 

 

979 and 980 are two newly created threads

 

Once more, you can see that two are running in the background

 

The three newly created processes are just created

 

fg% + sequence number put the specified process in the foreground and ctrl+z in the background

 

 

Use the following three commands to view the leader of thread group, process group and session in turn

The command means to find the descriptor of the thread group leader according to the process descriptor. The corresponding field is the ID to be displayed

p $lx_task_by_pid(977).group_leader->pids[0].pid->numbers.nr
p $lx_task_by_pid(977).group_leader->pids[1].pid->numbers.nr
p $lx_task_by_pid(977).group_leader->pids[2].pid->numbers.nr

987 and 988 are created by 984, they are in the same thread group, and leader is 976

 

2, Process scheduling algorithm

Each process belongs to a scheduler class, each scheduler class has a process queue, different queues have different scheduling algorithms.

First scheduling hard real-time, soft real-time second, common process last.

CFS (completely fair) scheduling algorithm is used for ordinary processes:

Virtual clock: the scheduler always selects the process with the smallest clock to execute.

High priority process clocks grow slowly.

All running processes are placed in a red black tree.

 

Here's a demonstration:

Run 0.gdb again, input ls in the terminal, and make it captured

 

 

 

Create the file demo-2-2.gdb as follows

 1 break __schedule//Execute this function when the process is scheduled
 2 
 3 break __switch_to//When scheduling, this function will be called if the process is switched
 4   commands
 5     printf "next_p->pid: %d\n", next_p->pid
 6     printf "next_p->se.vruntime: "
 7     print  next_p->se.vruntime
 8   end
 9 
10 break enqueue_task_fair//If there is a new process to enter CFS When queuing, execute this function
11   commands
12     printf "p->pid: %d\n", p->pid
13     printf "p->se.vruntime: "
14     print  p->se.vruntime
15   end
16 
17 display   $lx_current().state//Displays the status of the current process
18 display   $lx_current().se.vruntime
19 display   $lx_per_cpu("runqueues").nr_running//CPU How many processes are running in it
20 
21 display ((struct sched_entity *)((void *)$lx_per_cpu("runqueues").cfs.rb_leftmost - 0x8))->vruntime//CFS The leftmost node in the queue, that is, the smallest information of the virtual clock
22 display ((struct task_struct *)((void *)$lx_per_cpu("runqueues").cfs.rb_leftmost - 0x4c))->pid

 

 

As can be seen from the above figure, process 975 is currently running. The current virtual clock can be seen from the runtime. state=0 indicates that its current state is ready or running. There is no process at the far left of the tree. Because the enqueue ﹣ task ﹣ fair function is used to add new processes to the process queue, now there is one. You can see that the number of processes to be added is 7, and the virtual clock in the next line is a negative value, which is not seen yet. Continue to execute.

 

You can see that the virtual clock of process 7 is less than 975. If you want to schedule next time, you should choose 7. The process 3 is about to be created.

 

From the above figure, the virtual clock of process 975 has increased. In these two breakpoints, there are interrupts, which leads to the increase of the clock. There is a certain randomness in the operation and a certain randomness in the virtual machine. Continue

 

Running the switch function, the next step is to switch process 7. Continue

 

The clock of the process of clock 7 is also increased. It should be noted that the current running process is not in the tree, but in the queue. The process in the queue is the process in the tree plus the current process. Continue several times

 

The next step is to create process 4.

 

In addition to the normal process has queues, other hard real-time and soft real-time have their own queues.

A node of the red black tree can be another tree, sharing a clock.

 

3, Timing of process scheduling

At the entrance of kernel program, the system calls the main control function, exception handling function, interrupt handling function and kernel thread main function. Use bt to check the top layer of the stack and determine which kernel call is based on the type of function.

Tags: Linux Session less

Posted on Wed, 18 Mar 2020 06:43:00 -0700 by whiterecluse