⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 proc.c

📁 操作系统课程设计 在minix3下实现实时进程
💻 C
📖 第 1 页 / 共 2 页
字号:
            /* Found a suitable source, deliver the notification message. */	    BuildMess(&m, src_proc_nr, caller_ptr);	/* assemble message */            CopyMess(src_proc_nr, proc_addr(HARDWARE), &m, caller_ptr, m_ptr);            return(OK);					/* report success */        }    }    /* Check caller queue. Use pointer pointers to keep code simple. */    xpp = &caller_ptr->p_caller_q;    while (*xpp != NIL_PROC) {        if (src == ANY || src == proc_nr(*xpp)) {	    /* Found acceptable message. Copy it and update status. */	    CopyMess((*xpp)->p_nr, *xpp, (*xpp)->p_messbuf, caller_ptr, m_ptr);            if (((*xpp)->p_rts_flags &= ~SENDING) == 0) enqueue(*xpp);            *xpp = (*xpp)->p_q_link;		/* remove from queue */            return(OK);				/* report success */	}	xpp = &(*xpp)->p_q_link;		/* proceed to next */    }  }  /* No suitable message is available or the caller couldn't send in SENDREC.    * Block the process trying to receive, unless the flags tell otherwise.   */  if ( ! (flags & NON_BLOCKING)) {      caller_ptr->p_getfrom = src;		      caller_ptr->p_messbuf = m_ptr;      if (caller_ptr->p_rts_flags == 0) dequeue(caller_ptr);      caller_ptr->p_rts_flags |= RECEIVING;		      return(OK);  } else {      return(ENOTREADY);  }}/*===========================================================================* *				mini_notify				     *  *===========================================================================*/PRIVATE int mini_notify(caller_ptr, dst)register struct proc *caller_ptr;	/* sender of the notification */int dst;				/* which process to notify */{  register struct proc *dst_ptr = proc_addr(dst);  int src_id;				/* source id for late delivery */  message m;				/* the notification message */  /* Check to see if target is blocked waiting for this message. A process    * can be both sending and receiving during a SENDREC system call.   */  if ((dst_ptr->p_rts_flags & (RECEIVING|SENDING)) == RECEIVING &&      ! (priv(dst_ptr)->s_flags & SENDREC_BUSY) &&      (dst_ptr->p_getfrom == ANY || dst_ptr->p_getfrom == caller_ptr->p_nr)) {      /* Destination is indeed waiting for a message. Assemble a notification        * message and deliver it. Copy from pseudo-source HARDWARE, since the       * message is in the kernel's address space.       */       BuildMess(&m, proc_nr(caller_ptr), dst_ptr);      CopyMess(proc_nr(caller_ptr), proc_addr(HARDWARE), &m,           dst_ptr, dst_ptr->p_messbuf);      dst_ptr->p_rts_flags &= ~RECEIVING;	/* deblock destination */      if (dst_ptr->p_rts_flags == 0) enqueue(dst_ptr);      return(OK);  }   /* Destination is not ready to receive the notification. Add it to the    * bit map with pending notifications. Note the indirectness: the system id    * instead of the process number is used in the pending bit map.   */   src_id = priv(caller_ptr)->s_id;  set_sys_bit(priv(dst_ptr)->s_notify_pending, src_id);   return(OK);}/*===========================================================================* *				lock_notify				     * *===========================================================================*/PUBLIC int lock_notify(src, dst)int src;			/* sender of the notification */int dst;			/* who is to be notified */{/* Safe gateway to mini_notify() for tasks and interrupt handlers. The sender * is explicitely given to prevent confusion where the call comes from. MINIX  * kernel is not reentrant, which means to interrupts are disabled after  * the first kernel entry (hardware interrupt, trap, or exception). Locking * is done by temporarily disabling interrupts.  */  int result;  /* Exception or interrupt occurred, thus already locked. */  if (k_reenter >= 0) {      result = mini_notify(proc_addr(src), dst);   }  /* Call from task level, locking is required. */  else {      lock(0, "notify");      result = mini_notify(proc_addr(src), dst);       unlock(0);  }  return(result);}/*===========================================================================* *				enqueue					     *  *===========================================================================*/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 */  struct proc *ptr, *tptr;  #if DEBUG_SCHED_CHECK  check_runqueues("enqueue");  if (rp->p_ready) kprintf("enqueue() already ready process\n");#endif  /* Determine where to insert to process. */  sched(rp, &q, &front);  if(rp->deadline > 0)  {	  rp->p_priority = rp->p_max_priority;	  q = rp->p_max_priority;	  	  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{		tptr = NIL_PROC;	  	ptr = rdy_head[q];		while( ptr != NIL_PROC && ptr->deadline > 0 && ptr->deadline < rp->deadline)		{			tptr = ptr;			ptr = ptr->p_nextready;		}		if( tptr == NIL_PROC )		{			rp->p_nextready = ptr;			rdy_head[q] = rp;		}		else{			tptr->p_nextready = rp;			rp->p_nextready = ptr;		}	  }   }  else  {		  /* 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 */		tptr = NIL_PROC;	  	ptr = rdy_head[q];		while( ptr != NIL_PROC && ptr->deadline > 0)		{			tptr = ptr;			ptr = ptr->p_nextready;		}		if( tptr == NIL_PROC )		{			rp->p_nextready = ptr;			rdy_head[q] = rp;		}		else{			tptr->p_nextready = rp;			rp->p_nextready = ptr;		}  	  }   	  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();			#if DEBUG_SCHED_CHECK  rp->p_ready = 1;  check_runqueues("enqueue");#endif}/*===========================================================================* *				dequeue					     *  *===========================================================================*/PRIVATE void dequeue(rp)register struct proc *rp;	/* this process is no longer runnable */{/* A process must be removed from the scheduling queues, for example, because * it has blocked.  If the currently active process is removed, a new process * is picked to run by calling pick_proc(). */  register int q = rp->p_priority;		/* queue to use */  register struct proc **xpp;			/* iterate over queue */  register struct proc *prev_xp;  /* Side-effect for kernel: check if the task's stack still is ok? */  if (iskernelp(rp)) { 					if (*priv(rp)->s_stack_guard != STACK_GUARD)		panic("stack overrun by task", proc_nr(rp));  }#if DEBUG_SCHED_CHECK  check_runqueues("dequeue");  if (! rp->p_ready) kprintf("dequeue() already unready process\n");#endif  /* Now make sure that the process is not in its ready queue. Remove the    * process if it is found. A process can be made unready even if it is not    * running by being sent a signal that kills it.   */  prev_xp = NIL_PROC;				  for (xpp = &rdy_head[q]; *xpp != NIL_PROC; xpp = &(*xpp)->p_nextready) {      if (*xpp == rp) {				/* found process to remove */          *xpp = (*xpp)->p_nextready;		/* replace with next chain */          if (rp == rdy_tail[q])		/* queue tail removed */              rdy_tail[q] = prev_xp;		/* set new tail */          if (rp == proc_ptr || rp == next_ptr)	/* active process removed */              pick_proc();			/* pick new process to run */          break;      }      prev_xp = *xpp;				/* save previous in chain */  }  #if DEBUG_SCHED_CHECK  rp->p_ready = 0;  check_runqueues("dequeue");#endif}/*===========================================================================* *				sched					     *  *===========================================================================*/PRIVATE void sched(rp, queue, front)register struct proc *rp;			/* process to be scheduled */int *queue;					/* return: queue to use */int *front;					/* return: front or back */{/* This function determines the scheduling policy.  It is called whenever a * process must be added to one of the scheduling queues to decide where to * insert it.  As a side-effect the process' priority may be updated.   */  static struct proc *prev_ptr = NIL_PROC;	/* previous without time */  int time_left = (rp->p_ticks_left > 0);	/* quantum fully consumed */  int penalty = 0;				/* change in priority */  /* Check whether the process has time left. Otherwise give a new quantum    * and possibly raise the priority.  Processes using multiple quantums    * in a row get a lower priority to catch infinite loops in high priority   * processes (system servers and drivers).    */  if ( ! time_left) {				/* quantum consumed ? */      rp->p_ticks_left = rp->p_quantum_size; 	/* give new quantum */      if (prev_ptr == rp) penalty ++;		/* catch infinite loops */      else penalty --; 				/* give slow way back */      prev_ptr = rp;				/* store ptr for next */  }  /* Determine the new priority of this process. The bounds are determined   * by IDLE's queue and the maximum priority of this process. Kernel task    * and the idle process are never changed in priority.   */  if (penalty != 0 && ! iskernelp(rp)) {      rp->p_priority += penalty;		/* update with penalty */      if (rp->p_priority < rp->p_max_priority)  /* check upper bound */           rp->p_priority=rp->p_max_priority;      else if (rp->p_priority > IDLE_Q-1)   	/* check lower bound */      	  rp->p_priority = IDLE_Q-1;  }  /* If there is time left, the process is added to the front of its queue,    * so that it can immediately run. The queue to use simply is always the   * process' current priority.    */  *queue = rp->p_priority;  *front = time_left;}/*===========================================================================* *				pick_proc				     *  *===========================================================================*/PRIVATE void pick_proc(){/* Decide who to run now.  A new process is selected by setting 'next_ptr'. * When a billable process is selected, record it in 'bill_ptr', so that the  * clock task can tell who to bill for system time. */  register struct proc *rp;			/* process to run */  int q;					/* iterate over queues */  /* Check each of the scheduling queues for ready processes. The number of   * queues is defined in proc.h, and priorities are set in the task table.   * The lowest queue contains IDLE, which is always ready.   */  for (q=0; q < NR_SCHED_QUEUES; q++) {	      if ( (rp = rdy_head[q]) != NIL_PROC) {          next_ptr = rp;			/* run process 'rp' next */          if (priv(rp)->s_flags & BILLABLE)	 	              bill_ptr = rp;			/* bill for system time */          return;				       }  }}/*===========================================================================* *				lock_send				     * *===========================================================================*/PUBLIC int lock_send(dst, m_ptr)int dst;			/* to whom is message being sent? */message *m_ptr;			/* pointer to message buffer */{/* Safe gateway to mini_send() for tasks. */  int result;  lock(2, "send");  result = mini_send(proc_ptr, dst, m_ptr, NON_BLOCKING);  unlock(2);  return(result);}/*===========================================================================* *				lock_enqueue				     * *===========================================================================*/PUBLIC void lock_enqueue(rp)struct proc *rp;		/* this process is now runnable */{/* Safe gateway to enqueue() for tasks. */  lock(3, "enqueue");  enqueue(rp);  unlock(3);}/*===========================================================================* *				lock_dequeue				     * *===========================================================================*/PUBLIC void lock_dequeue(rp)struct proc *rp;		/* this process is no longer runnable */{/* Safe gateway to dequeue() for tasks. */  lock(4, "dequeue");  dequeue(rp);  unlock(4);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -