1. Preface
This paper mainly based on Linux 0.12 source code, analysis of the Linux kernel version of the process model and its scheduler algorithm.
Linux 0.12 Source code: http://oldlinux.org/Linux.old/kernel/0.1x/linux-0.12.tar.gz
2. Process 2.1 What is a process
- The core concept of the operating system is the process. A process is simply a program running in the operating system, which is the smallest unit of operating system resource management.
- A process is a dynamic entity, which is a process of executing a program.
- A process is a run-time activity of a program with certain independent functions, and is also the smallest unit of resource allocation.
2.2 Characteristics of the process
- Dynamic: The essence of the process is the process of a program in a multi-channel program system , the process is dynamic generation, dynamic extinction.
- Concurrency: Any process can execute concurrently with other processes.
- Independence: A process is a basic unit that can run independently, and is also an independent unit for allocating resources and dispatching the system.
- asynchrony : Because of the inter-process constraints, the process has a discontinuity of execution, that is, the process at its own independent, unpredictable speed forward.
- Structure characteristic: The process consists of three parts, the program, the data and the Process Control block .
3. Organization of the process 3.1 Process control block
In the Linux kernel, the process is managed through a task_struct struct called the process descriptor, which contains all the information required for a process. It is defined in this file (see below):
Linux-2.6.38.8/include/linux/sched.h
Task_struct contains these elements:
① Identifier: A unique identifier that describes the process used to differentiate other processes.
② Status: Task status, exit code, exit signal, etc.
③ priority: The priority relative to other processes.
④ Program counter: The address of the next instruction that will be executed in the program.
⑤ Memory Pointers: pointers to program code and process-related data, as well as memory blocks shared with other processes.
⑥ Context Data: The data in the processor's registers when the process executes.
⑦I/O status information: Includes the I/O requests that are displayed, the I/O devices that are assigned to the process, and the list of files that are used by the process.
⑧ accounting information: May include the total processor time, the sum of the number of clocks used, time limit, accounting number, etc.
Identifier of the 3.1.1 process (PID)Each process has a unique ID in the system that identifies it, and this ID is the process identifier (PID).
This is defined in Linux 0.12:
long pid;
State analysis of the state ① process of the 3.1.2 process
Long /* */
The State member is evaluated as follows:
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define Task_uninterruptible 2
#define Task_zombie 3
#define TASK_STOPPED 4
Analysis of Process state:
- Task_running (running state) He is a combination of a run state and a ready state, indicating that the process is running or ready to run.
- task_interruptible (interruptible sleep state) the process is sleeping (blocked), waiting for the resource to arrive to wake up, or it can wake up through another process signal or clock interrupt to enter the run queue.
- task_uninterruptible (non-disruptive sleep state) It is basically similar to shallow sleep, but one thing is that no other process signal or clock interrupt wakes up.
- task_stopped (paused state) The process pauses execution to accept some sort of processing.
- Task_zombie (zombie state) the process has ended without releasing the PCB, which is said to be in a zombie state.
② transition of process state
- Running state ===> blocking state: For example, a running process is making an I/O request that is converted from a running state to a blocking state
- Blocking state ===> Ready state: For example, after the I/O operation is complete, the blocking state is converted to a ready state
- Ready state ===> Running state: a process such as a ready state is selected by the process scheduler, assigned to the CPU, and converted from ready state to run state
- Run state ===> ready state: The time slice of the running process is exhausted, and the ucpu is forced to be converted from the running state to the ready state.
③ Process state transition diagram
3.2 Program Segments
The program segment is the program code snippet that can be dispatched by the process scheduler to the CPU execution. Note that programs can be shared by multiple processes, which means that multiple processes can run the same program.
3.3 Data Segments
The data segment of a process can be the raw data processed by the process's corresponding program, or it can be the intermediate or final result when the program executes.
4. Scheduling of Processes 4.1 What is process scheduling
Modern operating systems are multitasking operating systems, although with the development of technology, hardware processor core more and more, but still can not guarantee a process corresponding to a core, which is bound to need a management unit, responsible for the scheduling process, by the management unit to determine the next moment who should use the CPU, This is the process scheduler that acts as the snap-in.
task of the Process Scheduler: 1, assign time to process 2, context switch
4.2 The evolution of the scheduler
Field |
version |
An O (n) Initial scheduling algorithm |
linux-0.11~2.4 |
O (1) Scheduler |
linux-2.5 |
CFS Scheduler |
Linux-2.6~ to present
|
4.3 Understanding the main scheduler function
- Initialization subroutine for Kernel scheduler
voidSched_init (void) { inti; structDesc_struct * p;//Descriptor Chart Structure Pointers//at the beginning of the development of Linux system, the kernel is immature. The kernel code is often modified. Linus is afraid of inadvertently modifying these critical data structures, resulting in incompatibilities with the POSIX standard. Add the following judgment here//statements are not necessary, purely to remind themselves of and others who modify kernel code. if(sizeof(structsigaction)! = -)//Sigaction is the structure that holds the state of the signal. Panic"Struct sigaction must be bytes"); //The task State segment descriptor and the local data table descriptor for the initial task (task 0) are set in the Global descriptor table. //the values for First_tss_entry and First_ldt_entry are 4 and 5, respectively, defined in Include/linux/sched.h. The GDT is a descriptor array (include/linux/head.h),//In fact, the corresponding program Head.s the base address of the descriptor (GDT). So Gdt+first_tss_entry is Gdt[first_tss_entry] (that is, gdt[4]), that is, the addresses of the 4th item of the GDT array//See include/asm/system.hSet_tss_desc (gdt+first_tss_entry,&(INIT_TASK.TASK.TSS)); Set_ldt_desc (GDT+first_ldt_entry,&(Init_task.task.ldt)); //Clear Task Array and descriptor descriptor (note i=1 begins, so the descriptor for the initial task is still in). The descriptor entry structure is defined in the file include/linux/head.h. p = gdt+2+First_tss_entry; for(i=1; i<nr_tasks;i++) {Task[i]=NULL; P->a=p->b=0; P++; P->a=p->b=0; P++; } /*Clear NT, so, we won ' t has troubles with the later on*/ /*clear the bit NT in the flag register so that there will be no trouble later*/ //the NT flag bit in EFlags is used to control nested calls to tasks. When the NT location bit, the current interrupt task executes the iret instruction, which causes the task to switch. NT indicates whether the Back_link field in TSS is valid. //invalid when nt=0. __ASM__ ("PUSHFL; Andl $0xffffbfff, (%ESP); POPFL"); //Select Fugazai for the TSS segment of task 0 to the Task Register tr. Select the local descriptor descriptor Fugazai to the local Descriptor List register LDTR. Attention!! is to Fugazai the selection of the corresponding LDT descriptor in the GDT to LDTR. //only explicitly added this time, after the new task Ldt loading, is the CPU according to the LDT in TSS automatically loaded. Ltr0);//defined in Include/linux/sched.hLldt (0);//where the parameter (0) is the task number. //The following code initializes the 8253 timer. Channel 0, select mode of Operation 3, binary count mode. The output pin of channel 0 is on the IRQ0 of the interrupt control main chip, which emits a IRQ0 request every 10 milliseconds. //latch is the initial timer count value. Outb_p (0x36,0x43);/*binary, Mode 3, LSB/MSB, CH 0*/outb_p (LATCH&0xFF,0x40);/*LSB*/ //fixed value low byteOUTB (LATCH >>8,0x40);/*MSB*/ //fixed value high byte//sets the clock interrupt handler handle (sets the clock interrupt gate). Modify the interrupt controller mask to allow the clock to break. //then set the system call to break the gate. These two settings interrupt the definition of a macro that describes the descriptor in the in-place IDT in the file include/asm/system.h. The difference between the two is described at the beginning of the system.h file. Set_intr_gate (0x20,&timer_interrupt); Outb (Inb_p (0x21) &~0x01,0x21); Set_system_gate (0x80,&System_call); }
- Schedule () is the function of the main scheduler, and in many parts of the kernel, if you want to assign the CPU to another process that is different from the currently active process, the main scheduler function is called directly schedule ()
voidSchedulevoid) { intI,next,c; structtask_struct * * p;//pointer to the task structure pointer. /*Check Alarm, wake up any interruptible tasks that has got a signal*/ /*detects alarm (process alarm timing value), wakes up any interruptible tasks that have been signaled*/ //starts the loop detection alarm from the last task in the task array. Skips a null pointer item while looping. for(p = &last_task; p > &first_task;--p)if(*p) {//Resets the timeout value if the task time-out timed timeout is set and has timed out, and if the task is under Task_interruptible sleep state, set it to Ready//status (task_running). if((*p)->timeout && (*p)->timeout <jiffies) { (*P)->timeout =0; if((*p)->state = =task_interruptible) (*P)->state =task_running; } //if the scheduled value of the task is set to alarm and has expired (alarm<jiffies), the SIGALRM signal is sent to the task, which sends the SIGALARM signal to the mission. Then alarm. //The default action for this signal is to terminate the process. Jiffies is the number of ticks (10ms/ticks) that the system has counted from the start-up. defined in Sched.h. if((*p)->alarm && (*p)->alarm <jiffies) { (*P)->signal |= (1<< (sigalrm-1)); (*P)->alarm =0; } //If there are other signals in the signal bitmap other than the blocked signal, and the task is in a interruptible state, the task is in the ready state. //where ' ~ (_blockable & (*p)->blocked) ' is used to ignore blocked signals, but Sigkill and Sigstop cannot be blocked. if((*p)->signal & ~ (_blockable & (*p)->blocked)) && (*P)->state==task_interruptible) (*P)->state=task_running; } /*This is the scheduler proper:*/ /*This is the main part of the scheduler.*/ while(1) {C= -1; Next=0; I=Nr_tasks; P= &Task[nr_tasks]; //This code is processed from the last task in the task array and skips the bad array without the task. Compares the counter (descending tick count of task run time) values for each Ready state task,//which value is large, the running time is not long, and next points to which task number. while(--i) {if(!*--p)Continue; if((*p)->state = = task_running && (*p)->counter >c) C= (*p)->counter, next =i; } //If you compare a result that has a counter value that is not equal to 0, or if there is no running task in the back (c is still -1,next=0), exit the start loop and perform a task switch on line 161//operation. Otherwise, depending on the priority value of each task, the counter value of each task is updated and then returned to 125 rows for re-comparison. The counter value is calculated as Counter = COUNTER/2 +priority. //Note that the calculation process here does not take into account the state of the process. if(c) Break; for(p = &last_task; p > &first_task;--p)if(*p) (*p)->counter = ((*p)->counter >>1) + (*P)Priority ; } //Use the following macro (defined in sched.h) to point the current task pointer to the task number next and switch to run in that task. On line 146, next is initialized to 0. So if there is no//when other tasks are operational, next is always 0. Therefore, the dispatch function executes the task 0 when the system is idle. Task 0 Right now execution pause ()Switch_to (next);//Switch to task number for next task and run it. }
4.4 O (n) Scheduling algorithm
- You need to traverse a running queue
- O (n) Problem: The scheduler chooses the process to traverse the entire runqueue, so the algorithm executes in a proportional proportion to the number of processes. In addition, the time spent each time the counter is recalculated increases linearly with the number of processes in the system.
5. View of the operating system process model
A process is an application that is running in a system that, once run, is a process (a process is an instance of a program when it executes). From the kernel point of view, the purpose of the process is to assume the basic unit of allocating system resources (CPU time, memory, etc.). In the computer, the CPU is the most valuable resource, in order to improve the CPU utilization, so the process of scheduling is very important. From the evolution of Linux process scheduling, from O (n) to O (1), to all have achieved great success, but with the rapid development of science and technology, Linux process scheduling is more to keep improving.
6. References
7292563
Http://blog.chinaunix.net/uid-26126915-id-2948970.html
45850565
First job: Analysis based on Linux process model