Linux system---process concept


Article directory

  • Von Neumann architecture
  • Operating system (OS)
  • understanding of process
  • process status
  • process priority
  • environment variables
  • process address space
  • Linux2.6 kernel process scheduling queue


1. Von Neumann architecture

Our common computers, such as laptops. Most of our uncommon computers, such as servers, follow the von Neumann system.
The picture shows the von Neumann architecture diagram:

  • Input devices : including keyboard, mouse, scanner, writing tablet, etc.
  • Memory : just memory
  • Output device : monitor, printer, etc.
  • Central processing unit (CPU): contains arithmetic units, controllers, registers, etc.

Notice:

  • Hardware such as disks is not considered storage.
  • Input devices and output devices are collectively called peripherals, so hardware such as disks are peripherals.
  • Regardless of the cache, the CPU here can and can only read and write memory, and cannot access peripherals (input or output devices)
  • Peripherals (input or output devices) need to input or output data, and they can only write to or read from memory.
  • All devices can only deal with memory directly.
Differences in access speed:
         CPU>Memory>Peripherals

When the data is taken out from the peripheral, it is first loaded into the memory, and then handed over to the CPU for processing. After processing, the result is returned to the memory, and then returned to the peripheral. This will speed up the overall speed. If there is no memory, then the interaction between the CPU and the peripherals will slow down the overall speed compared to not adding memory.

The understanding of von Neumann cannot stop at the concept. It must go deep into the understanding of software data flow. Please explain the data flow process from the time you log in to QQ and start chatting with a friend. The data flow process from when you open the window and start sending him a message to when he receives the message. What if you are sending files on QQ?

First, enter the message you send to your friend from the keyboard. At this time, the peripheral has data. Then the peripheral loads the data into the memory, and the CPU processes it. Then the processing result is returned to the peripheral, and then the data is sent. After receiving the message, the network card in the other party's host computer loads the data on the network card into the memory, then lets the CPU process it, returns it to the memory after processing, and finally returns the data to the display peripheral on the computer.

in conclusion:

  •         In the von Neumann architecture, the CPU does not directly interact with peripherals, but through memory.
  •         The von Neumann architecture improves the efficiency of the entire machine.

2. Operating system (OS)

Concept: Any computer system contains a basic collection of programs called an operating system (OS). Generally understood, the operating system includes: kernel (process management, memory management, file management, driver management) other programs (such as function libraries, shell programs, etc.)
The purpose of designing an OS is to interact with hardware, manage all software and hardware resources, and provide a good execution environment for user programs (applications).
Positioning: In the entire computer software and hardware architecture, the operating system’s positioning is: a pure “management” software

Operating system: It is a software that manages the interaction between software and hardware.

The essence of management is to manage data. The operating system manages these hardware by using structures, which store various attribute information about these hardware. Because Linux is written in C language, struct structures are used to record the properties of resources, organized using relevant data structures and algorithms, and then managed.

The following figure is a schematic diagram of the computer's software and hardware architecture:

System call and library function concepts

  • From a development perspective, the operating system will appear as a whole to the outside world, but it will expose some of its interfaces for upper-layer development. This part of the interface provided by the operating system is called a system call.
  • In terms of use, the functions of system calls are relatively basic and the requirements for users are relatively high. Therefore, thoughtful developers can appropriately encapsulate some system calls to form libraries. With libraries, it is very beneficial for higher-level users or Developers conduct secondary development.

Summarize:
computer management hardware
        1. To describe, use struct structure
        2. Organize it using linked lists or other efficient data structures

3. Understanding of process

1. Basic concepts:

Concept : an execution instance of a program, an executing program, etc.
Kernel perspective : The entity responsible for allocating system resources (CPU time, memory).

Process = corresponding PCB structure + corresponding code and data

2. Process -Understanding of PCB structure

Process information is placed in a data structure called a process control block, which can be understood as a collection of process attributes.
It is called PCB (process control block) in the operating system. The PCB under the Linux operating system is: task_struc t
 
task_struct is a data structure of the Linux kernel. It is loaded into RAM (memory) and contains process information. This structure is mainly used to record attributes related to the process.

3.task_ struct content classification

  • Identifier : A unique identifier that describes this process and is used to distinguish other processes.
  • Status : Task status, exit code, exit signal, etc.
  • Priority : Priority relative to other processes.
  • Program Counter : The address of the next instruction to be executed in the program.
  • Memory pointers : including pointers to program code and process-related data, as well as pointers to memory blocks shared with other processes
  • Context data : the data in the processor's registers when the process is executed [example of leave of absence, please add the figure of CPU, register].
  • I/O status information : includes displayed I/O requests, I/O devices assigned to the process and a list of files used by the process.
  • Accounting information: may include the total processor time, the total number of clocks used, time limits, accounting accounts, etc.
  • other information

4. Organize and view processes

Organization process: It can be found in the kernel source code. All processes running in the system are stored in the kernel in the form of task_struct linked lists.

View process: Process information can be viewed through the /proc system folder

 For example: To obtain the process information with PID 1, you need to view the /proc/1 folder.

   Most process information can also be obtained using user-level tools such as top and ps.

Use ps aux alone to display all process information, and use the grep command to specify information related to a certain process.

 To terminate a process, you can use ctrl+c, or you can use kill -9 to terminate the pid of a process. ctrl+c essentially sends signal No. 9.

5. Obtain the process identifier through system calls

1. Obtain the parent-child process identifier through getpid and getppid.

process id (PID)
Parent process id (PPID)

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
  printf("pid:%d\n",getpid());
  printf("ppid:%d\n",getppid());
  return 0;
}

 

2. Use fork to obtain the process identifier

 Fork is a system call interface, which mainly creates a child process. This function is executed once and has two return values. The parent process returns the pid of the child process, and the child process returns 0. Among them, the code of the father and son processes is shared, and the data each opens up space and has a private copy (copy-on-write is used)

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
  pid_t id=fork();
  if(id==0){
    //子进程
    while(1){
      printf("I am child process,我的pid是:%d,我的父进程是:%d\n",getpid(),getppid());
      sleep(1);
    }
  }
  else{
    //父进程
    while(1){
      printf("I am father process,我的pid是:%d,我的父进程是:%d\n",getpid(),getppid());
      sleep(1);
    }
  }
  return 0;
}

 

 Because after fork, the parent and child processes will share code and copy-on-write occurs. Since after fork, the return values ​​are different, and different code blocks can be executed. After fork, the order in which the parent and child processes proceed is determined by the scheduler in the CPU and the corresponding scheduling algorithm.

Fork function, why does it return twice? Related Links

4. Process status

1. Process status under Linux

  • R running status (running): does not mean that the process is definitely running, it indicates that the process is either running or in the run queue.
  • S sleeping state (sleeping): means that the process is waiting for the event to complete (sleep here is sometimes called interruptible sleep).
  • D disk sleep state (Disk sleep): sometimes also called uninterruptible sleep state (uninterruptible sleep), the process in this state usually waits for the end of IO.
  • T stopped state (stopped) : The (T) process can be stopped by sending the SIGSTOP signal to the process. The suspended process can continue running by sending the SIGCONT signal.
  • X Death state (dead): This state is just a return state, you will not see this state in the task list.
  • Z(zombie)-Zombie state: Zombies are a special state. A zombie (zombie) process occurs when a process exits and the parent process does not read the return code of the child process's exit. The zombie process will remain in the process table in a terminated state and will always wait for the parent process to read the exit status code . Therefore, as long as the child process exits, the parent process is still running, but the parent process does not read the child process status, and the child process enters the Z state.

Source code of process status in Linux kernel:

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

2. Process blocking and process hanging

Process blocking: When a running process cannot execute because it is waiting for an event to occur, it abandons the processor and enters a blocked state. There are many types of events that cause process blocking, such as waiting for I/O to complete, requesting a buffer that cannot be satisfied, waiting for a signal, etc.

Process hangs: When there is insufficient memory, the OS replaces the code and data of the process to the disk appropriately, and the state of the process is called suspended.

3. View process status

ps aux / ps axj command
Common process status viewing commands:
  • ps aux | head -1 && ps aux | grep 进程PID
  • ps ajx |head -1 && ps ajx |grop specification PID

  • 1) ps a displays all programs under the current terminal, including programs of other users.
  • 2) ps -A displays all programs.
  • 3) When ps c lists programs, it displays the real instruction name of each program, without including the path, parameters or identification of resident services.
  • 4) ps -e The effect of this parameter is the same as specifying the "A" parameter.
  • 5) When ps e lists programs, display the environment variables used by each program.
  • 6) ps f uses ASCII characters to display the tree structure and express the relationship between programs.
  • 7) ps -H displays a tree structure, indicating the relationship between programs.
  • 8) ps -N displays all programs, except the programs under the terminal that execute the ps command.
  • 9) ps s uses the program signal format to display the program status.
  • 10) When ps S lists programs, it includes interrupted subroutine information.
  • 11) ps -t specifies the terminal number and lists the status of the programs belonging to the terminal.
  • 12) ps u displays the program status in a user-oriented format.
  • 13) ps x displays all programs, not distinguished by terminal.
  • ps displays the current running processes, grep searches for them, and ps aux displays all processes and their status.

4. Front and back processes

Foreground process:

By default, every process we start is a foreground process. It gets input from the keyboard and sends its output to the screen.

When a process is running in the foreground, we cannot run any other command (start any other process) in the same command line prompt because the command line prompt is not available until the program ends its process.

 It can be seen from here that + indicates that the process is a foreground process.

backstage process:

Use kill -19 PID to pause the process

Use kill -18 PID to continue executing the process

 Before suspension:

 When paused:

 Continue execution:

 From the picture above, we can know that the process has changed from a foreground process to a background process. Note that the background process cannot be stopped with ctrl+c. You can only use kill -9 to terminate the process.

5. Classification of process status

1.Running status (R)

Test R status code:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
  int a=0;
  while(1){
    a=1+1;
  }
  return 0;
}

Here we can find that the status of the process is R+, which means that the process is a foreground process that is running or in the run queue.

 2. Sleep state (S)

Test S status code:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
  printf("I am running\n");
  printf("我的pid是:%d\n",getpid());
  sleep(10);
  return 0;
}

 From the above figure, we can know that the process is in the S state, which means that the process is waiting for the event to complete. Being in a light sleep state can be interrupted or terminated at any time, so this state can be called an interruptible sleep state.

3. Disk hibernation state (D)

Sometimes also called uninterruptible sleep state (uninterruptible sleep), the process in this state usually waits for the end of IO.

 

 Therefore, this state indicates that a process is in a deep sleep state. The process will not be released by the operating system and can only be restored when the process wakes up automatically.

4. Stop state (T)

A (T) process can be stopped by sending a SIGSTOP signal to the process. The suspended process can continue running by sending the SIGCONT signal .

 Test T status code:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
 while(1){
  printf("我是一个进程pid:%d\n",getpid());
 }
return 0;
}

5.Death state(X)

This status is just a return status, you will not see this status in the task list. When the parent process reads the return result of the child process, the child process immediately releases the resources. The state of death is very short-lived and almost impossible to capture via PS commands.

6. Zombie state (Z)

  • Zombies are a rather special state. A zombie process occurs when a process exits and the parent process (using the wait() system call) does not read the return code of the child process exit.
  • A zombie process remains in the process table in a terminated state and is waiting for the parent process to read the exit status code.
  • Therefore, as long as the child process exits, the parent process is still running, but the parent process does not read the child process status, and the child process enters the Z state.

Test Z status code:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
  printf("I am running...\n");
  pid_t id=fork();

  if(id==0){
    //child
    int cnt=5;
    while(cnt){
      printf("I am child,我的pid是:%d,我的ppid:%d,cnt:%d\n",getpid(),getppid(),--cnt);
      sleep(1);
    }
    printf("child quit\n");
    exit(1);
  }
  else{
    while(1){
      printf("I am father,我的pid是:%d,我的ppid:%d\n",getpid(),getppid());
      sleep(1);
    }
  }
  return 0;
}

 Here we can see that the child process changes to the Z+ state, which is called the zombie state, and the process is called the zombie process.

 Zombie process hazards

  • The exit status of the process must be maintained, because it needs to tell the process that cares about it (the parent process) how But if the parent process never reads, the child process will always be in the Z state.
  • Maintaining the exit status itself requires data maintenance, and it is also the basic information of the process, so it is stored in task_struct (PCB). In other words Z status will never exit, and the PCB will always be maintained.
  • That parent process has created many child processes, but if they are not recycled, will it cause a waste of memory resources? Because the data structure object itself takes up memory, think about defining a structure variable (object) in C to open up space !
  • memory leak

7. Orphan status

If the parent process exits early, then the child process exits later and enters Z. What should be done?

  • If the parent process exits first, the child process is called an "orphan process".
  • The orphan process is adopted by init process No. 1. Of course, it must be recycled by the init process.

Test orphan status code:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
  pid_t id = fork();
  if(id < 0){
  perror("fork");
  return 1;
  }
  else if(id == 0){//child
  printf("I am child, pid : %d\n", getpid());
  sleep(10);
  }else{//parent
  printf("I am parent, pid: %d\n", getpid());
  sleep(3);
  exit(0);
  }
return 0;
}

 Here we can find that the child process is adopted by process No. 1. This state is called the orphan state, and the process is called an orphan process.

5. Process priority

basic concept:

  • The order in which CPU resources are allocated refers to the priority of the process.
  • Processes with higher priority have priority execution rights. Configuring process priorities is very useful for Linux in a multi-tasking environment and can improve system performance.
  • You can also run the process on a designated CPU. In this way, scheduling unimportant processes to a certain CPU can greatly improve the overall .

1. View system processes

In a linux or unix system, using the ps -l command will output something similar to the following:

  • UID: represents the identity of the executor
  • PID: represents the codename of this process
  • PPID: represents which process this process is derived from, that is, the code name of the parent process
  • PRI: represents the priority at which this process can be executed. The smaller the value, the earlier it will be executed.
  • NI: represents the nice value of this process

2. PRI and NI

  • PRI is the priority of the process, or in layman's terms, the order in which programs are executed by the CPU. The smaller the value, the higher the priority of the process. The default value is 80.
  • NI is the nice value we are talking about, which represents the modified value of the priority at which the process can be executed.
  • The smaller the PRI value, the faster it will be executed. After adding the nice value, the PRI will become: PRI(new)=PRI(old)+nice
  • In this way, when the nice value is negative, the priority value of the program will become smaller, that is, its priority will become higher, and the faster it will be executed.
  • Therefore, adjusting the process priority under Linux means adjusting the nice value of the process. The value range of nice is -20 to 19, with a total of 40 levels.

Note: The nice value of a process is not the priority of the process. They are not a concept, but the nice value of the process will affect the priority change of the process. It can be understood that the nice value is the modified data of the process priority.

3. Command to view process priority

Use the top command to change the niceness of an existing process :
top
After entering top, press “r” –> enter the process PID –> enter the nice value

4. Other concepts about processes

  • Competition: There are many system processes, but there are only a small number of CPU resources, or even one, so there is competition between processes. In order to complete tasks efficiently and compete for related resources more reasonably, priority is given
  • Independence: Multi-process operation requires exclusive use of various resources, and multi-process operations do not interfere with each other.
  • Parallelism: Multiple processes run on multiple CPUs at the same time. This is called parallelism.
  • Concurrency: Multiple processes use process switching under one CPU to advance multiple processes within a period of time, which is called concurrency.

5. Process switching

Process switching is a basic function that today's multi-tasking and multi-user operating systems should have.

In order to control the execution of a process, the operating system must have the ability to suspend the process running on the CPU and resume the execution of a previously suspended process. This behavior is called process switching, task switching or context switching. In other words, process switching means to take back the processor from the running process, and then let the waiting process occupy the processor. What is said here about taking back the processor from a process is essentially to find a place to store the intermediate data stored in the processor's register by the process, thereby freeing up the processor's register for other processes to use. So where can the intermediate data of the suspended running process be stored? Of course, this place should be the private stack of the process.

 

For example: when process 1 is being executed, the contents of the registers in the CPU are related to process 1. Due to concurrency, when the CPU changes from executing process 1 to executing process 2, the registers originally belong to The contents of process 1 need to be saved, because process 2 will also use these registers and will overwrite the original contents. It can currently be considered that the contents of the registers related to process 1 are copied to the PCB. This process is called context protection in process switching. When the CPU changes from executing process 2 to executing process 1 again, the contents in the registers related to process 2 will also be protected, and the context-protected contents in the PCB of process 1 will be restored to the CPU registers, overwriting Delete the content belonging to process 2, and then continue execution at the previously executed position. This position is read from the recovered data by the eip (PC pointer) register. This process is called,context recovery in process switch.

Time slice: (timeslice), also known as "quantum" or "processor slice", is a microscopic period of CPU time allocated by the time-sharing operating system to each running process (in the preemption kernel it is : The time from when the process starts running until it is preempted). Assume this time is 10ms. When process 1 is executed for 10ms, the temporary data generated by process 1 will be context protected, that is, the contents of the CPU registers will be copied to the corresponding PCB. Then start executing process 2. When process 2 is executed for 10ms, the context of process 2 will also be protected, and then the context of process 1 will be restored, and process 1 will continue to be executed. This repeats until the two processes end. The contents of the registers in the CPU only belong to the process currently being executed. Since the CPU execution speed is very fast and the time for a process to be executed is very short, the result of multiple processes is that they are executed together. The length of time a process is executed is the time slice.

6. Environment variables

  • Environment variables generally refer to some parameters used in the operating system to specify the operating environment of the operating system. For example: when we write C/C++ code and link, we never know the dynamic and static variables we are linking to. No matter where the library is, you can still link successfully and generate an executable program. The reason is that there are relevant environment variables to help the compiler find it.
  • Environment variables usually have some special purpose, and they usually have global properties in the system.

1. Common environment variables

  • PATH: Specify the search path for the command
  • HOME: Specify the user's home working directory (that is, the default directory when the user logs in to the Linux system)
  • SHELL: The current Shell, its value is usually /bin/bash.

2. How to view environment variables

echo $PATH //PATH: your environment variable name
env | grep PATH

3. Commands related to environment variables

  • 1. echo: Display the value of an environment variable
  • 2. export: Set a new environment variable
  • 3. env: displays all environment variables
  • 4. unset: clear environment variables
  • 5. set: Display locally defined shell variables and environment variables

4. How environment variables are organized

Each program will receive an environment table. The environment table is an array of character pointers. Each pointer points to an environment string terminated by '\0'.

 

5. How to obtain environment variables through code

  Print the third parameter of the command line

#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
    //我们给main函数传递的argc、argv[]参数,其实是传递的命令行中输入的程序名和选项!
    //char *env[]存储的是环境变量的地址
     int i = 0;
     for(; env[i]; i++)
     {
     	printf("%s\n", env[i]);
 	}
 	return 0;
}

 Obtained through the third-party variable environ

#include<stdio.h>
#include<unistd.h>
#include<string.h>

int main()
{
    //libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明
    extern char** environ;
    for(int i=0;environ[i];i++)
    {
        printf("%s\n",environ[i]);
    }
    return 0;
}

 Get or set environment variables through system calls

#include <stdio.h>
#include <stdlib.h>
int main()
{
 printf("%s\n", getenv("PATH"));
 return 0;
}
The getenv and putenv functions are commonly used to access specific environment variables.

7. Process address space

Process address space layout diagram

Test address space code:

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<malloc.h>

int g_val=100;
int g_unval;

int main(int argc,char* argv[],char* envp[])
{
    printf("code addr:%p\n",main);
    char* str = "hello world";
    printf("read only addr:%p\n",str);
    printf("init addr:%p\n",&g_val);
    printf("uninit addr:%p\n",&g_unval);
    
    int* p = malloc(10);
    printf("heap addr:%p\n",p);
    
    printf("stack addr:%p\n",&str);
    printf("stack addr:%p\n",&p);
     
    int i=0;
    for(;i<argc;i++)
    {
        printf("args addr:%p\n",argv[i]);
    }

    i=0;
    while(envp[i])
    {
        printf("env addr:%p\n",envp[i]);
        i++;
    }
    return 0;   
}

 As can be seen from the picture above, the addresses are printed from low to high. Then the address space distribution was verified.

1. Deeply understand the process address space

First look at a piece of code:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int g_val=100;

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        //child
        int flag = 0;
        while(1)
        {
            printf("我是子进程:%d, ppid: %d, g_val: %d, &g_val: %p\n\n", getpid(), getppid(), g_val, &g_val);
            sleep(1);
            flag++;
            if(flag == 5)
            {
                g_val=200;
                printf("我是子进程,全局数据我已经改了,用户你注意查看!\n");
            }
        }
    }
    else 
    {
        //parent
        while(1)
        {
            printf("我是父进程:%d, ppid: %d, g_val: %d, &g_val: %p\n\n", getpid(), getppid(), g_val, &g_val);
            sleep(2);
        }
    }
}

g_val all points to the same address, why are two different values ​​printed?

First of all, the value and address we printed before the global variable has not changed are the same. When g_val changes in the child process, we can find that g_val has not changed in the parent process. At this time the addresses are all the same. It is understandable based on the independence between processes. The address is the same. There are two values ​​​​under the same physical address. This is unlikely, indicating that the address at this time is not a real physical address.

Under Linux, this kind of address is called a linear address (virtual address), sometimes also called a logical address. At the language level, the addresses we call are virtual addresses. The physical addresses are basically managed by the OS system.

2. Division of process address space areas

"User virtual address space" includes the following areas:

① Code segment

② Data segment

③ Uninitialized data segment

④ Dynamic library code segment, data segment, uninitialized data segment;

⑤ Heap memory: malloc brk vmallocdynamically allocated memory applied through functions such as;

⑥ Stack memory: stores local variables and function call stack;

⑦ Memory mapping area: Map the file mmapto the "memory mapping area" of the "virtual address space" through the function;

⑧ Environment variables and parameters: The environment variables and parameter configuration information for program running are stored at the bottom of the stack;

In the Linux operating system, each process occupies 4G exclusively. When scheduling, due to limited CPU resources, a process can only be designated to execute corresponding resources at a certain time through time slices.

There is an mm pointer in each process that points to the mm_struct structure. This structure divides the 4GB space.

The following is the underlying source code of mm_struct under Linux:

struct mm_struct {
	struct vm_area_struct *mmap;		/* list of VMAs */
	struct rb_root mm_rb;
	u32 vmacache_seqnum;                   /* per-thread vmacache */
#ifdef CONFIG_MMU
	unsigned long (*get_unmapped_area) (struct file *filp,
				unsigned long addr, unsigned long len,
				unsigned long pgoff, unsigned long flags);
#endif
	unsigned long mmap_base;		/* base of mmap area */
	unsigned long mmap_legacy_base;         /* base of mmap area in bottom-up allocations */
#ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES
	/* Base adresses for compatible mmap() */
	unsigned long mmap_compat_base;
	unsigned long mmap_compat_legacy_base;
#endif
	unsigned long task_size;		/* size of task vm space */
	unsigned long highest_vm_end;		/* highest vma end address */
	pgd_t * pgd;

	/**
	 * @mm_users: The number of users including userspace.
	 *
	 * Use mmget()/mmget_not_zero()/mmput() to modify. When this drops
	 * to 0 (i.e. when the task exits and there are no other temporary
	 * reference holders), we also release a reference on @mm_count
	 * (which may then free the &struct mm_struct if @mm_count also
	 * drops to 0).
	 */
	atomic_t mm_users;

	/**
	 * @mm_count: The number of references to &struct mm_struct
	 * (@mm_users count as 1).
	 *
	 * Use mmgrab()/mmdrop() to modify. When this drops to 0, the
	 * &struct mm_struct is freed.
	 */
	atomic_t mm_count;

	atomic_long_t nr_ptes;			/* PTE page table pages */
#if CONFIG_PGTABLE_LEVELS > 2
	atomic_long_t nr_pmds;			/* PMD page table pages */
#endif
	int map_count;				/* number of VMAs */

	spinlock_t page_table_lock;		/* Protects page tables and some counters */
	struct rw_semaphore mmap_sem;

	struct list_head mmlist;		/* List of maybe swapped mm's.	These are globally strung
						 * together off init_mm.mmlist, and are protected
						 * by mmlist_lock
						 */


	unsigned long hiwater_rss;	/* High-watermark of RSS usage */
	unsigned long hiwater_vm;	/* High-water virtual memory usage */

	unsigned long total_vm;		/* Total pages mapped */
	unsigned long locked_vm;	/* Pages that have PG_mlocked set */
	unsigned long pinned_vm;	/* Refcount permanently increased */
	unsigned long data_vm;		/* VM_WRITE & ~VM_SHARED & ~VM_STACK */
	unsigned long exec_vm;		/* VM_EXEC & ~VM_WRITE & ~VM_STACK */
	unsigned long stack_vm;		/* VM_STACK */
	unsigned long def_flags;
	unsigned long start_code, end_code, start_data, end_data;
	unsigned long start_brk, brk, start_stack;
	unsigned long arg_start, arg_end, env_start, env_end;

	unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */

	/*
	 * Special counters, in some configurations protected by the
	 * page_table_lock, in other configurations by being atomic.
	 */
	struct mm_rss_stat rss_stat;

	struct linux_binfmt *binfmt;

	cpumask_var_t cpu_vm_mask_var;

	/* Architecture-specific MM context */
	mm_context_t context;

	unsigned long flags; /* Must use atomic bitops to access the bits */

	struct core_state *core_state; /* coredumping support */
#ifdef CONFIG_AIO
	spinlock_t			ioctx_lock;
	struct kioctx_table __rcu	*ioctx_table;
#endif
#ifdef CONFIG_MEMCG
	/*
	 * "owner" points to a task that is regarded as the canonical
	 * user/owner of this mm. All of the following must be true in
	 * order for it to be changed:
	 *
	 * current == mm->owner
	 * current->mm != mm
	 * new_owner->mm == mm
	 * new_owner->alloc_lock is held
	 */
	struct task_struct __rcu *owner;
#endif
	struct user_namespace *user_ns;

	/* store ref to file /proc/<pid>/exe symlink points to */
	struct file __rcu *exe_file;
#ifdef CONFIG_MMU_NOTIFIER
	struct mmu_notifier_mm *mmu_notifier_mm;
#endif
#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS
	pgtable_t pmd_huge_pte; /* protected by page_table_lock */
#endif
#ifdef CONFIG_CPUMASK_OFFSTACK
	struct cpumask cpumask_allocation;
#endif
#ifdef CONFIG_NUMA_BALANCING
	/*
	 * numa_next_scan is the next time that the PTEs will be marked
	 * pte_numa. NUMA hinting faults will gather statistics and migrate
	 * pages to new nodes if necessary.
	 */
	unsigned long numa_next_scan;

	/* Restart point for scanning and setting pte_numa */
	unsigned long numa_scan_offset;

	/* numa_scan_seq prevents two threads setting pte_numa */
	int numa_scan_seq;
#endif
#if defined(CONFIG_NUMA_BALANCING) || defined(CONFIG_COMPACTION)
	/*
	 * An operation with batched TLB flushing is going on. Anything that
	 * can move process memory needs to flush the TLB when moving a
	 * PROT_NONE or PROT_NUMA mapped page.
	 */
	bool tlb_flush_pending;
#endif
	struct uprobes_state uprobes_state;
#ifdef CONFIG_HUGETLB_PAGE
	atomic_long_t hugetlb_usage;
#endif
	struct work_struct async_put_work;
};

3. The connection between process address space and physical memory

When an executable program file on the disk has gone through four processes: preprocessing, compilation, assembly, and linking, during this process the compiler will form the address of the file according to the distribution of the process address space, which is called a logical Address, also called a virtual address. In this way, the file is loaded from the disk into the memory, and the memory will allocate space to it to store the code, but the address in the code is a virtual address. The OS then maps the virtual address to the physical address through a page table.

In this way, we can answer the above situation where g_val values ​​are different?

  • In the process address space of the parent and child processes, there is a global variable g_val at the same address, which is mapped in physical memory through their respective page tables.
  • Every time this global variable changes, the value in the parent and child processes is the same, so the two processes only need to be mapped to a physical space in physical memory. When the child process changes its global variable, the value of the variable in the two processes is different, so it can no longer be mapped to a physical space. So at this time, the operating system will copy the global variables originally in the physical space, place them in another space, and update the physical address of the new physical space to the page table of the child process. At this time, in the parent and child processes, the virtual addresses of global variables in their respective process address spaces are still the same, but the corresponding physical addresses in their respective page tables are different.
  • During the appeal process, when the child process changes the global variable, the operating system copies the value in the original physical space into the new space. This behavior is called copy-on-write.

4. The significance of the existence of process address space

  • 1. Any illegal access or mapping to the OS is identified and the process is terminated, thus effectively protecting the physical memory. Because the address space and page table are created and maintained by the OS, anyone who wants to use the address space and page table for mapping must access it under the supervision of the OS. This protects all legal data in physical memory, as well as all processes and relevant valid data of the kernel.
  • 2. Due to the existence of address space and page table mapping, data in the disk can be loaded arbitrarily in physical memory. Since the memory management module and the process management module are decoupled, the independence of the process is ensured. Due to the existence of the address space, when the upper layer applies for space, it actually applies for it in the address space. The OS adopts a delayed allocation strategy to improve the efficiency of the entire machine. When you actually access the physical address space, the corresponding management algorithm is executed to help you apply for memory and build a page table mapping relationship.
  • 3. In theory, physical memory can be loaded arbitrarily. It is precisely because of the existence of the page table that the virtual address in the address space can be mapped through the table and the physical address. It is precisely because of the existence of the address space that each process thinks it has 4GB of space, and each area is ordered. Each process is mapped to different areas through the page table to achieve process independence.

8. Linux2.6 kernel process scheduling queue

The following figure is the data structure of the process queue in the Linux 2.6 kernel:

 A CPU has a runqueue

If you have multiple CPUs, you must consider the load balancing issue of the number of processes.
priority
  • Ordinary priority: 100~139 (We all have ordinary priorities. Think about the range of the nice value and it can correspond to it!)
  • Real-time priority: 0~99 (don’t care)
activity queue
  • All processes whose time slice has not yet ended are placed in this queue according to priority.
  • nr_active: How many running processes are there in total?
  • queue[140]: One element is a process queue. Processes with the same priority are queued and scheduled according to FIFO rules. Therefore, the array subscript is the priority!
  • From this structure, what is the process of selecting the most appropriate process?
    • 1. Traverse queue[140] starting from the table below 0
    • 2. Find the first non-empty queue, which must be the queue with the highest priority
    • 3. Get the first process in the selected queue, start running, and the scheduling is completed!
    • 4. The time complexity of traversing queue[140] is constant! But it’s still too inefficient!
  • bitmap[5]: A total of 140 priorities and a total of 140 process queues. In order to improve the efficiency of searching for non-empty queues, 5*32 bits can be used to indicate whether the queue is empty. In this way, the search efficiency can be greatly improved!
Expiration queue
  • The structure of the expired queue and the active queue are exactly the same
  • The processes placed on the expiration queue are all processes whose time slices have been exhausted.
  • After all processes in the active queue have been processed, the time slice of the processes in the expired queue is recalculated.
active pointer and expired pointer
  • The active pointer always points to the active queue
  • The expired pointer always points to the expired queue
  • However, there will be fewer and fewer processes on the active queue, and more and more processes on the expired queue, because the process will always exist when its time slice expires.
  • It doesn't matter, as long as the contents of the active pointer and expired pointer can be exchanged at the appropriate time, it is equivalent to having a new batch of active processes!

Guess you like

Origin blog.csdn.net/qq_67458830/article/details/131883104