Brief Analysis of Process Model in Minix3

basic introduction

Minix (Mini UNIX) was originally a Unix-like operating system developed by Professor Andrew S. Tanenbaum of the Computer Science Department of Vrije University in Amsterdam, the Netherlands.

The current version of Minix is ​​Minix 3, a free, open source operating system designed to achieve high reliability, flexibility and security.

Its system consists primarily of a microkernel operating in kernel mode and all remaining operating system components operating in user mode as a series of independent, protected processes.

Overall understanding of Minix3

MINIX3 itself is a collection of a set of processes

The main function of the first layer is to provide a set of privileged kernel calls to upper-layer drivers and servers. Processes are potentially privileged, which is what differentiates the other three layers.

The second tier has the most privileges. Inside the second layer is called a device driver.

The third layer contains the server, there are two indispensable servers, the process manager (Process Manager, PM) and the file system (File System, FS),

There are also information server (IS), regeneration server (reincarnation server, RS),

There may also be a network server (inet) on a network operating system.

How Minix3 organizes the process

definition of process     

Here are some descriptions of processes from Modern Operating Systems. A      
        process is an abstraction of a running program. The
        essence of
        a process is a program being executed. A process is an instance of an executing program, including the current value of the program counter, registers, and variables. value

process data structure

 kernel/proc.h defines the kernel process table, and each item in the process table is defined as a proc process:

 

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 */
};

 

Each item includes process register, stack pointer, status value, memory map, stack limit, process ID, count value, alarm time, and message information.

 

The process table itself is defined as an array of proc structures proc[NR_TASKS+NR_PROCS] ,

The constant NR_TASKS is defined as 4 in include/minix/com.h ,

The constant NR_PROCS is defined as 64 in include/minix/config.h .

If desired, NR_PROCS can be changed to create a system capable of handling more processes (like on a large server).

 

How process state transitions

process status

 

The entire life of a process from its creation to its revocation and its demise,
Sometimes it occupies the processor for execution, sometimes it can run but cannot be assigned to the processor, and sometimes although there is an idle processor, it cannot execute due to waiting for an event to occur.
This all means that a process is not the same as a program, it is active and has state changes, which can be characterized by a set of states.
In order to facilitate the management of the process, in general, at least three different process states should be defined according to the different situations of the process in the execution process:

 

  (1) Running state: The process occupies the processor and is running.

 

  (2) ready (ready) state: the process has the running conditions, waiting for the system to allocate a processor to run.

 

  (3) Waiting (wait) state: also known as blocked (blocked) state or sleep (sleep) state, which means that the process does not have the running conditions and is waiting for the completion of an event.

 

 

Process state transition

 

 

How processes are scheduled

 When the process is interrupted (by input and output devices or clocks, etc.), or when the process executes a soft interrupt instruction, or when the process ends, the system will decide which process to run next.

queue priority

Minix's process scheduling uses multi-level queues, and each queue has a different priority.

See in 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 */

The queue used by the service process usually has a higher priority than the queue used by the user process; the queue used by the driver process is usually higher than the queue used by the service process;

The queue used by clock and system tasks is the highest priority of all queues.

time slice

User processes are usually given relatively small time slices; driver and service processes are usually supposed to run until they block, but are actually allocated large but limited time slices. At every clock tick, it will check if the currently running process has used up its time slice, if so, it will be put at the end of the queue and the next process will be selected to run.

See in /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 */
  }
  ......
}

lock_notify() in the function clock_handler() above will cause the function do_clocktick() below to be called.
        See in /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 */
  }
  ......
}

The lock_enqueue() in the above function do_clocktick() actually calls the following function enqueue() to select the next process to run.
  See in /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();   

}

Views on the Minix3 Process Model

This paper briefly analyzes the process model of Minix3 based on the Minix3 source code, which mainly includes: how the operating system organizes the process, how the process state transitions and how the process is scheduled;

The process scheduling of MINIX3 is still very simple, the scheduling algorithm is very short, and its purpose is to reflect a simple and efficient design principle. Of course, it is difficult for simplicity and efficiency to coexist.

Overall, it is a multi-queue scheduling algorithm, which is placed in the corresponding position according to the priority.

Guess you like

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