The first assignment: in-depth source code analysis process model

Write at the top:

  • The kernel source code used this time: Linux 0.12 version.
  • What this article is about: It aims to use source code to help understand the concept of processes in operating systems.

  Process : This is an abstraction of a running program. Everything else in the operating system revolves around the concept of a process. A process is an instance of an executing program.

    

1. How the operating system organizes processes

  1. Number of processes

  In sched.h, there are the following statements:

   1 #define NR_TASKS 64  

  This statement defines the maximum number of tasks (processes) in the system, that is, at the same instant, there can be up to 64 processes in the system.

  

  2. Process identifier

  • There is a process structure in sched.h: task_struct. In the structure, the identifier of the process (unique) is defined:

   1 long pid;  

  • Note: Task 0 is an "idle" task that is called when no other tasks can run. It cannot be killed, it cannot sleep. The 'status' information in task[0] is never used.
  • The full definition of the structure is as follows:
1  struct task_struct {
 2  /* these are hardcoded - don't touch */ 
3      long state;         // The running state of the task, -1 not runnable, 0 runnable (ready), >0 stopped 
4      long counter;     // Task running time count 
5      long priority;
 6      long signal;
 7      struct sigaction sigaction[ 32 ];
 8      long blocked;     /* bitmap of masked signals */ 
9  /* various fields */ 
10      int exit_code;
 11     unsigned long start_code,end_code,end_data,brk,start_stack;
 12      long pid,pgrp,session,leader;     // From left to right: process identification number (process number), process group number, session number, session leader 
13      int     groups[NGROUPS];     // The group number to which the process belongs, a process can belong to multiple groups 
14      /*  
15       * pointers to parent process, youngest child, younger sibling,
 16       * older sibling, respectively. (p->father can be replaced with 
 17       * p->p_pptr->pid)
 18       */ 
19      // From left to right: pointer to the parent process, pointer to the latest child process, pointer to the adjacent process created later than yourself, pointer to the parent process A pointer to an adjacent process that was created earlier. 
20      struct task_struct *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
21     unsigned short uid,euid,suid;
22     unsigned short gid,egid,sgid;
23     unsigned long timeout,alarm;
24     long utime,stime,cutime,cstime,start_time;
25     struct rlimit rlim[RLIM_NLIMITS]; 
26     unsigned int flags;    /* per process flags, defined below */
27     unsigned short used_math;
28 /* file system info */
29     int tty;        /* -1 if no tty, so it must be signed */
30     unsigned short umask;
31     struct m_inode * pwd;
32     struct m_inode * root;
33     struct m_inode * executable;
34     struct m_inode * library;
35     unsigned long close_on_exec;
36     struct file * filp[NR_OPEN];
37 /* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
38     struct desc_struct ldt[3];
39 /* tss for this task */
40     struct tss_struct tss;
41 };

 

 

  3. Definition of possible states of a process

1  // This defines the state that the process may be in when it is running 
2  #define TASK_RUNNING 0   // The process is running or ready 
3  #define TASK_INTERRUPTIBLE 1   // The process is in an interruptible waiting state 
4  #define TASK_UNINTERRUPTIBLE 2   // The process is in an uninterruptible waiting state Interrupt waiting state, mainly used for I/O operation waiting 
5  #define TASK_ZOMBIE 3   // The process is in a zombie state and has stopped running, but the parent process has not sent a signal. 
6  #define TASK_STOPPED 4   // The process has stopped

 

2. How to convert the process state (given the process state transition diagram)

  •  Three states of the process:

            Running state: The process actually occupies the CPU at this moment.

    就绪态:可运行,但因为其它进程正在运行而暂时停止。

    阻塞态:除非某种外部时间发生,否则进程不能运行。

  • 进程状态转换图:

          

  • 转换关系图解释如下:

     1. 进程因为等待输入而被阻止。

     2. 调度程序选择另一个进程。

     3. 调度程序选择这个进程。

     4. 出现有效输入。

 

三.进程是如何调度的

  调度当系统中就绪的进程数大于系统中可用的CPU数时,可用的CPU必须选择下一个要运行的进程。在操作系统中,完成选择工作的这一部分称为调度程序(scheduler),该程序使用的算法称为调度算法(scheduling algorithm)

  在Linux 0.12中采用基于优先级排队的调度策略。

  schedule()函数首先扫描任务数组。通过比较每个就绪态(TASK RUNNING) 任务的运行时间递减滴答计数counter 的值,来确定当前哪个进程运行的时间最少。哪一个的值大,就表示运行时间还不长,于是就选中该进程,并使用任务切换宏函数切换到该进程运行。 

 

  源码:

 1 void schedule(void)
 2 {
 3     int i,next,c;
 4     struct task_struct ** p;  //任务结构指针的指针
 5 
 6 /* check alarm, wake up any interruptible tasks that have got a signal */
 7 
 8     for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
 9         if (*p) {
10             if ((*p)->timeout && (*p)->timeout < jiffies) {
11                 (*p)->timeout = 0;
12                 if ((*p)->state == TASK_INTERRUPTIBLE)
13                     (*p)->state = TASK_RUNNING;
14             }
15             if ((*p)->alarm && (*p)->alarm < jiffies) {
16                 (*p)->signal |= (1<<(SIGALRM-1));
17                 (*p)->alarm = 0;
18             }
19             if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
20             (*p)->state==TASK_INTERRUPTIBLE)
21                 (*p)->state=TASK_RUNNING;
22         }
23 
24 /* this is the scheduler proper: */
25 //-------------------这是调度程序的主要部分-------------------
26     while (1) {
27         c = -1;
28         next = 0;
29         i = NR_TASKS;
30         p = &task[NR_TASKS];
31         while (--i) {
32             if (!*--p)
33                 continue;
34             if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
35                 c = (*p)->counter, next = i;
36         }
37         if (c) break;
38         for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
39             if (*p)
40                 (*p)->counter = ((*p)->counter >> 1) +
41                         (*p)->priority;
42     }
43     switch_to(next);
44 }

 

四.谈谈自己对该操作系统进程模型的看法  

     对于Linux0.12 来讲,系统最多可有64 个进程同时存在。程序使用进程标识号(pid) 来标识每个进程。对于只有一个CPU 的系统,在某一瞬间只能有一个进程真正在运行。内核通过调度程序分时调度各个进程运行。 利用分时技术,在Linux 操作系统上可以(伪)同时运行多个进程。分时技术的基本原理是把CPU 的运行时间划分成个个规定长度的时间片(time slice),让每个进程在一个时间片内运行。当进程的时间片用完时系统就利用调度程序切换到另一个进程去运行。因此实际上对于具有单个CPU 的机器来说某一时刻只能运行一个进程。但由于每个进程运行的时间片很短(例如15 个系统滴答=l50ms),所以表面看来好像所有进程在同时运行着。
  调度的实现有很多不同的算法,Linux 0.12版本较为早期了,后期的版本代码量似乎大了很多,有关进程调度的也一定更为完善。

 

最后:

参考资料: 

  • Linux内核完全剖析-基于0.12内核 (赵炯) 中文pdf扫描版   下载地址:http://www.jb51.net/books/415345.html  ;
  • 《现代操作系统》第四版。

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325081614&siteId=291194637