對Minix3中進程模型的簡要分析

簡單介紹

Minix(Mini UNIX)原來是荷蘭阿姆斯特丹的Vrije大學計算機科學系的Andrew S. Tanenbaum教授所發展的一個類Unix操做系統。算法

目前的Minix版本爲Minix 3,是一個免費、開源的操做系統,設計目標是實現高可靠性、靈活性及安全性。數組

其系統主要包括在覈心模式下運做的微核心和在用戶模式下做爲一系列獨立、受保護的進程運行的其他全部操做系統組件。安全

Minix3的總體認識

MINIX3自己就是一組進程的集合服務器

第一層的主要功能是爲上層驅動程序和服務器提供一組特權內核調用。進程都潛在具備必定特權,這是另外三層的不一樣之處。網絡

第二層擁有最多特權。第二層內的稱爲設備驅動程序(device driver)。數據結構

第三層包含了服務器,有兩個服務器不可少,進程管理器(Process Manager,PM)和文件系統(File System,FS),app

還有信息服務器(information server,IS),再生服務器(reincarnation server,RS),ide

在一個網絡操做系統上還可能有網絡服務器(network server,inet)。函數

Minix3是怎麼組織進程

進程的定義     

如下是來自《現代操做系統》中對進程的一些描述      
        進程是對正在運行程序的一個抽象
        進程本質是正在執行的一個程序
        一個進程就是一個正在執行程序的實例,包括程序計數器、寄存器和變量的當前值this

進程的數據結構

 kernel/proc.h定義了內核進程表,進程表中的每一項被定義爲一個proc進程:

 

struct proc {
struct stackframe_s p_reg;            /*process' registers saved in stack frame */
reg_t p_ldt_sel;                  /*selector in gdt with ldt base and limit */
struct segdesc_sp_ldt[2+NR_REMOTE_SEGS];    /* CS, DS and remote segments */
proc_n r_tp_nr;                   /* numberof this process (for fast access) */
struct priv *p_priv;                /*system privileges structure */
char p_rts_flags;                  /*SENDING, RECEIVING, etc. */
char p_priority;                  /*current scheduling priority */
char p_max_priority;                /*maximum scheduling priority */
char p_ticks_left;                  /*number of scheduling ticks left */
char p_quantum_size;                          /*quantum size in ticks */
struct mem_mapp_memmap[NR_LOCAL_SEGS];        /* memory map (T, D, S) */
clock_t p_user_time;                 /*user time in ticks */
clock_t p_sys_time;                   /*sys time in ticks */
struct proc *p_nextready;             /*pointer to next ready process */
struct proc *p_caller_q;              /*head of list of procs wishing to send */
struct proc *p_q_link;               /*link to next proc wishing to send */
message* p_messbuf;                 /*pointer to passed message buffer */
proc_n r_tp_getfrom;                /*from whom does process want to receive? */
proc_n r_tp_sendto;                 /* towhom does process want to send? */
sigset_t p_pending;                 /*bit map for pending kernel signals */
char p_name[P_NAME_LEN];              /*name of the process, including \0 */
};

 

每一項包括進程寄存器、棧指針、狀態值、內存映射、棧限制、進程號、計數值、alarm時間以及消息信息。

 

進程表自己被定義爲一個proc結構體的數組proc[NR_TASKS+NR_PROCS],

常量 NR_TASKS include/minix/com.h中被定義爲4

常量 NR_PROCS include/minix/congfig.h中被定義爲64

若是須要,NR_PROCS能夠更改,以建立一個可以處理更多進程的系統(如在一個大型服務器上)。

 

進程狀態如何轉換

進程狀態

 

一個進程從建立而產生至撤銷而消亡的整個生命期間,
有時佔有處理器執行,有時雖可運行但分不處處理器、有時雖有空閒處理器但因等待某個事件的發生而沒法執行,
這一切都說明進程和程序不相同,它是活動的且有狀態變化的,這能夠用一組狀態加以刻畫。
爲了便於管理進程,通常來講,按進程在執行過程當中的不一樣狀況至少要定義三種不一樣的進程狀態:

 

  (1)運行(running)態:進程佔有處理器正在運行。

 

  (2)就緒(ready)態:進程具有運行條件,等待系統分配處理器以便運行。

 

  (3)等待(wait)態:又稱爲阻塞(blocked)態或睡眠(sleep)態,指進程不具有運行條件,正在等待某個事件的完成。

 

 

進程狀態轉換

 

 

進程是如何調度的

 當進程被中斷(被輸入輸出設備或時鐘等),或進程執行軟中斷指令,或進程結束時,系統將決定接下來運行哪一個進程。

隊列優先級

Minix的進程調度使用多級隊列,每一個隊列的優先級不一樣。

見 kernel/proc.h 中:

/* Scheduling priorities for p_priority. Values must start at zero (highest
 * priority) and increment.  Priorities of the processes in the boot image
 * can be set in table.c. IDLE must have a queue for itself, to prevent low
 * priority user processes to run round-robin with IDLE.
 */
#define NR_SCHED_QUEUES   16        /* MUST equal minimum priority + 1 */
#define TASK_Q             0        /* highest, used for kernel tasks */
#define MAX_USER_Q         0        /* highest priority for user processes */  
#define USER_Q             7        /* default (should correspond to nice 0) */  
#define MIN_USER_Q        14        /* minimum priority for user processes */
#define IDLE_Q            15        /* lowest, only IDLE process goes here */
EXTERN struct proc *rdy_head[NR_SCHED_QUEUES]; /* ptrs to ready list headers */ EXTERN struct proc *rdy_tail[NR_SCHED_QUEUES]; /* ptrs to ready list tails */

服務進程所用的隊列一般比用戶進程所用的隊列優先級更高;而驅動進程所用的隊列一般比服務進程所用的隊列優先級更高;

而時鐘和系統任務使用的隊列,是全部隊列中優先級最高的。

時間片

用戶進程的時間片一般相對較小;驅動進程和服務進程一般應該運行直至阻塞,但實際上被分配了大卻有限的時間片。在每個時鐘節拍,都將檢查當前正在運行的進程是否用完了它的時間片,若是是,則它將被放到隊尾,而後選擇下一個進程運行。

見 /kernel/clock.c 中:

PRIVATE int clock_handler(hook)
irq_hook_t *hook;
{
/* This executes on each clock tick (i.e., every time the timer chip generates
 * an interrupt). It does a little bit of work so the clock task does not have
 * to be called on every tick.  The clock task is called when:
 *
 *        (1) the scheduling quantum of the running process has expired, or ......
 */
  ......
  /* Check if do_clocktick() must be called. Done for alarms and scheduling.
   ......
   */
  if (  ...... || (proc_ptr->p_ticks_left <= 0)) {
      prev_ptr = proc_ptr;                        /* store running process */
      lock_notify(HARDWARE, CLOCK);               /* send notification */
  }
  ......
}

上面函數clock_handler()中的lock_notify()將致使下面的函數do_clocktick()被調用。
        見 /kernel/clock.c 中:

PRIVATE int do_clocktick(m_ptr)
message *m_ptr;                                /* pointer to request message */
{
   ......
  /* A process used up a full quantum. The interrupt handler stored this
   * process in 'prev_ptr'.  First make sure that the process is not on the
   * scheduling queues.  Then announce the process ready again. Since it has
   * no more time left, it gets a new quantum and is inserted at the right
   * place in the queues.  As a side-effect a new process will be scheduled.
   */
  if (prev_ptr->p_ticks_left <= 0 && priv(prev_ptr)->s_flags & PREEMPTIBLE) {
      lock_dequeue(prev_ptr);                /* take it off the queues */
      lock_enqueue(prev_ptr);                /* and reinsert it again */
  }
  ......
}

上面函數do_clocktick()中的lock_enqueue()實際調用了下面的函數enqueue(),從而選擇下一個進程運行。
  見 /kernel/proc.c 中:

PRIVATE void enqueue(rp)
register struct proc *rp; /* this process is now runnable */
{
/* Add 'rp' to one of the queues of runnable processes.  This function is
 * responsible for inserting a process into one of the scheduling queues.
 * The mechanism is implemented here.   The actual scheduling policy is
 * defined in sched() and pick_proc().
 */
  int q;      /* scheduling queue to use */
  int front;     /* add to front or back */

  /* Determine where to insert to process. */
  sched(rp, &q, &front);

  /* Now add the process to the queue. */
  if (rdy_head[q] == NIL_PROC) {        /* add to empty queue */
      rdy_head[q] = rdy_tail[q] = rp;   /* create a new queue */
      rp->p_nextready = NIL_PROC;       /* mark new end */
  }
  else if (front) {              /* add to head of queue */
      rp->p_nextready = rdy_head[q];    /* chain head of queue */
      rdy_head[q] = rp;                 /* set new queue head */
  }
  else {                                /* add to tail of queue */
      rdy_tail[q]->p_nextready = rp;    /* chain tail of queue */ 
      rdy_tail[q] = rp;                 /* set new queue tail */
      rp->p_nextready = NIL_PROC;       /* mark new end */
  }

  /* Now select the next process to run. */
  pick_proc();   

}

對Minix3進程模型的見解

本文基於Minix3源代碼簡要的分析了Minix3的進程模型,其中主要包括:操做系統是怎麼組織進程的、 進程狀態如何轉換以及進程是如何調度的;

MINIX3 的進程調度仍是很是簡單的,調度算法是很是短小的,其目的就是體現 了一個簡單和高效的設計原則,固然簡單和高效其實很難並存,

總體而言,就是 一個多隊列調度算法,根據優先級來放到相應的位置。

相關文章
相關標籤/搜索