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

📄 proc.c

📁 一个简单的操作系统minix的核心代码
💻 C
📖 第 1 页 / 共 2 页
字号:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
				src/kernel/proc.c	 	 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

06900	/* This file contains essentially all of the process and message handling.
06901	 * It has two main entry points from the outside:
06902	 *
06903	 *   sys_call:   called when a process or task does SEND, RECEIVE or SENDREC
06904	 *   interrupt: called by interrupt routines to send a message to task
06905	 *
06906	 * It also has several minor entry points:
06907	 *
06908	 *   lock_ready:      put a process on one of the ready queues so it can be run
06909	 *   lock_unready:    remove a process from the ready queues
06910	 *   lock_sched:      a process has run too long; schedule another one
06911	 *   lock_mini_send:  send a message (used by interrupt signals, etc.)
06912	 *   lock_pick_proc:  pick a process to run (used by system initialization)
06913	 *   unhold:          repeat all held-up interrupts
06914	 */
06915	
06916	#include "kernel.h"
06917	#include <minix/callnr.h>
06918	#include <minix/com.h>
06919	#include "proc.h"
06920	
06921	PRIVATE unsigned char switching;        /* nonzero to inhibit interrupt() */
06922	
06923	FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dest,
06924	                message *m_ptr) );
06925	FORWARD _PROTOTYPE( int mini_rec, (struct proc *caller_ptr, int src,
06926	                message *m_ptr) );
06927	FORWARD _PROTOTYPE( void ready, (struct proc *rp) );
06928	FORWARD _PROTOTYPE( void sched, (void) );
06929	FORWARD _PROTOTYPE( void unready, (struct proc *rp) );
06930	FORWARD _PROTOTYPE( void pick_proc, (void) );
06931	
06932	#define CopyMess(s,sp,sm,dp,dm) \
06933	        cp_mess(s, (sp)->p_map[D].mem_phys, (vir_bytes)sm, (dp)->p_map[D].mem_phys, (vir_bytes)dm)
06934	
06935	/*===========================================================================*
06936	 *                              interrupt                                    * 
06937	 *===========================================================================*/
06938	PUBLIC void interrupt(task)
06939	int task;                       /* number of task to be started */
06940	{
06941	/* An interrupt has occurred.  Schedule the task that handles it. */
06942	
06943	  register struct proc *rp;     /* pointer to task's proc entry */
06944	
06945	  rp = proc_addr(task);
06946	
06947	  /* If this call would compete with other process-switching functions, put
06948	   * it on the 'held' queue to be flushed at the next non-competing restart().
06949	   * The competing conditions are:
06950	   * (1) k_reenter == (typeof k_reenter) -1:
06951	   *     Call from the task level, typically from an output interrupt
06952	   *     routine.  An interrupt handler might reenter interrupt().  Rare,
06953	   *     so not worth special treatment.
06954	   * (2) k_reenter > 0:
06955	   *     Call from a nested interrupt handler.  A previous interrupt handler
06956	   *     might be inside interrupt() or sys_call().
06957	   * (3) switching != 0:
06958	   *     Some process-switching function other than interrupt() is being
06959	   *     called from the task level, typically sched() from CLOCK.  An
06960	   *     interrupt handler might call interrupt and pass the k_reenter test.
06961	   */
06962	  if (k_reenter != 0 || switching) {
06963	        lock();
06964	        if (!rp->p_int_held) {
06965	                rp->p_int_held = TRUE;
06966	                if (held_head != NIL_PROC)
06967	                        held_tail->p_nextheld = rp;
06968	                else
06969	                        held_head = rp;
06970	                held_tail = rp;
06971	                rp->p_nextheld = NIL_PROC;
06972	        }
06973	        unlock();
06974	        return;
06975	  }
06976	
06977	  /* If task is not waiting for an interrupt, record the blockage. */
06978	  if ( (rp->p_flags & (RECEIVING | SENDING)) != RECEIVING ||
06979	      !isrxhardware(rp->p_getfrom)) {
06980	        rp->p_int_blocked = TRUE;
06981	        return;
06982	  }
06983	
06984	  /* Destination is waiting for an interrupt.
06985	   * Send it a message with source HARDWARE and type HARD_INT.
06986	   * No more information can be reliably provided since interrupt messages
06987	   * are not queued.
06988	   */
06989	  rp->p_messbuf->m_source = HARDWARE;
06990	  rp->p_messbuf->m_type = HARD_INT;
06991	  rp->p_flags &= ~RECEIVING;
06992	  rp->p_int_blocked = FALSE;
06993	
06994	   /* Make rp ready and run it unless a task is already running.  This is
06995	    * ready(rp) in-line for speed.
06996	    */
06997	  if (rdy_head[TASK_Q] != NIL_PROC)
06998	        rdy_tail[TASK_Q]->p_nextready = rp;
06999	  else
07000	        proc_ptr = rdy_head[TASK_Q] = rp;
07001	  rdy_tail[TASK_Q] = rp;
07002	  rp->p_nextready = NIL_PROC;
07003	}
	
07005	/*===========================================================================*
07006	 *                              sys_call                                     * 
07007	 *===========================================================================*/
07008	PUBLIC int sys_call(function, src_dest, m_ptr)
07009	int function;                   /* SEND, RECEIVE, or BOTH */
07010	int src_dest;                   /* source to receive from or dest to send to */
07011	message *m_ptr;                 /* pointer to message */
07012	{
07013	/* The only system calls that exist in MINIX are sending and receiving
07014	 * messages.  These are done by trapping to the kernel with an INT instruction.
07015	 * The trap is caught and sys_call() is called to send or receive a message
07016	 * (or both). The caller is always given by proc_ptr.
07017	 */
07018	
07019	  register struct proc *rp;
07020	  int n;
07021	
07022	  /* Check for bad system call parameters. */
07023	  if (!isoksrc_dest(src_dest)) return(E_BAD_SRC);
07024	  rp = proc_ptr;
07025	
07026	  if (isuserp(rp) && function != BOTH) return(E_NO_PERM);
07027	  
07028	  /* The parameters are ok. Do the call. */
07029	  if (function & SEND) {
07030	        /* Function = SEND or BOTH. */
07031	        n = mini_send(rp, src_dest, m_ptr);
07032	        if (function == SEND || n != OK)
07033	                return(n);      /* done, or SEND failed */
07034	  }
07035	
07036	  /* Function = RECEIVE or BOTH.
07037	   * We have checked user calls are BOTH, and trust 'function' otherwise.
07038	   */
07039	  return(mini_rec(rp, src_dest, m_ptr));
07040	}
	
07042	/*===========================================================================*
07043	 *                              mini_send                                    * 
07044	 *===========================================================================*/
07045	PRIVATE int mini_send(caller_ptr, dest, m_ptr)
07046	register struct proc *caller_ptr;       /* who is trying to send a message? */
07047	int dest;                       /* to whom is message being sent? */
07048	message *m_ptr;                 /* pointer to message buffer */
07049	{
07050	/* Send a message from 'caller_ptr' to 'dest'. If 'dest' is blocked waiting
07051	 * for this message, copy the message to it and unblock 'dest'. If 'dest' is
07052	 * not waiting at all, or is waiting for another source, queue 'caller_ptr'.
07053	 */
07054	
07055	  register struct proc *dest_ptr, *next_ptr;
07056	  vir_bytes vb;                 /* message buffer pointer as vir_bytes */
07057	  vir_clicks vlo, vhi;          /* virtual clicks containing message to send */
07058	
07059	  /* User processes are only allowed to send to FS and MM.  Check for this. */
07060	  if (isuserp(caller_ptr) && !issysentn(dest)) return(E_BAD_DEST);
07061	  dest_ptr = proc_addr(dest);   /* pointer to destination's proc entry */
07062	  if (dest_ptr->p_flags & P_SLOT_FREE) return(E_BAD_DEST);      /* dead dest */
07063	
07064	  /* This check allows a message to be anywhere in data or stack or gap. 
07065	   * It will have to be made more elaborate later for machines which
07066	   * don't have the gap mapped.
07067	   */
07068	  vb = (vir_bytes) m_ptr;
07069	  vlo = vb >> CLICK_SHIFT;      /* vir click for bottom of message */
07070	  vhi = (vb + MESS_SIZE - 1) >> CLICK_SHIFT;    /* vir click for top of msg */
07071	  if (vlo < caller_ptr->p_map[D].mem_vir || vlo > vhi ||
07072	      vhi >= caller_ptr->p_map[S].mem_vir + caller_ptr->p_map[S].mem_len)
07073	        return(EFAULT); 
07074	
07075	  /* Check for deadlock by 'caller_ptr' and 'dest' sending to each other. */
07076	  if (dest_ptr->p_flags & SENDING) {
07077	        next_ptr = proc_addr(dest_ptr->p_sendto);
07078	        while (TRUE) {
07079	                if (next_ptr == caller_ptr) return(ELOCKED);
07080	                if (next_ptr->p_flags & SENDING)
07081	                        next_ptr = proc_addr(next_ptr->p_sendto);
07082	                else
07083	                        break;
07084	        }
07085	  }
07086	
07087	  /* Check to see if 'dest' is blocked waiting for this message. */
07088	  if ( (dest_ptr->p_flags & (RECEIVING | SENDING)) == RECEIVING &&
07089	       (dest_ptr->p_getfrom == ANY ||
07090	        dest_ptr->p_getfrom == proc_number(caller_ptr))) {
07091	        /* Destination is indeed waiting for this message. */
07092	        CopyMess(proc_number(caller_ptr), caller_ptr, m_ptr, dest_ptr,
07093	                 dest_ptr->p_messbuf);
07094	        dest_ptr->p_flags &= ~RECEIVING;        /* deblock destination */
07095	        if (dest_ptr->p_flags == 0) ready(dest_ptr);
07096	  } else {
07097	        /* Destination is not waiting.  Block and queue caller. */
07098	        caller_ptr->p_messbuf = m_ptr;
07099	        if (caller_ptr->p_flags == 0) unready(caller_ptr);
07100	        caller_ptr->p_flags |= SENDING;
07101	        caller_ptr->p_sendto= dest;
07102	
07103	        /* Process is now blocked.  Put in on the destination's queue. */
07104	        if ( (next_ptr = dest_ptr->p_callerq) == NIL_PROC)
07105	                dest_ptr->p_callerq = caller_ptr;
07106	        else {
07107	                while (next_ptr->p_sendlink != NIL_PROC)
07108	                        next_ptr = next_ptr->p_sendlink;
07109	                next_ptr->p_sendlink = caller_ptr;
07110	        }
07111	        caller_ptr->p_sendlink = NIL_PROC;
07112	  }
07113	  return(OK);
07114	}
	
07116	/*===========================================================================*
07117	 *                              mini_rec                                     * 
07118	 *===========================================================================*/
07119	PRIVATE int mini_rec(caller_ptr, src, m_ptr)
07120	register struct proc *caller_ptr;       /* process trying to get message */
07121	int src;                        /* which message source is wanted (or ANY) */
07122	message *m_ptr;                 /* pointer to message buffer */
07123	{
07124	/* A process or task wants to get a message.  If one is already queued,
07125	 * acquire it and deblock the sender.  If no message from the desired source
07126	 * is available, block the caller.  No need to check parameters for validity.
07127	 * Users calls are always sendrec(), and mini_send() has checked already.  
07128	 * Calls from the tasks, MM, and FS are trusted.
07129	 */
07130	
07131	  register struct proc *sender_ptr;
07132	  register struct proc *previous_ptr;
07133	
07134	  /* Check to see if a message from desired source is already available. */
07135	  if (!(caller_ptr->p_flags & SENDING)) {
07136	        /* Check caller queue. */
07137	    for (sender_ptr = caller_ptr->p_callerq; sender_ptr != NIL_PROC;
07138	         previous_ptr = sender_ptr, sender_ptr = sender_ptr->p_sendlink) {
07139	        if (src == ANY || src == proc_number(sender_ptr)) {
07140	                /* An acceptable message has been found. */
07141	                CopyMess(proc_number(sender_ptr), sender_ptr,
07142	                         sender_ptr->p_messbuf, caller_ptr, m_ptr);
07143	                if (sender_ptr == caller_ptr->p_callerq)
07144	                        caller_ptr->p_callerq = sender_ptr->p_sendlink;
07145	                else
07146	                        previous_ptr->p_sendlink = sender_ptr->p_sendlink;
07147	                if ((sender_ptr->p_flags &= ~SENDING) == 0)
07148	                        ready(sender_ptr);      /* deblock sender */
07149	                return(OK);
07150	        }
07151	    }
07152	
07153	    /* Check for blocked interrupt. */
07154	    if (caller_ptr->p_int_blocked && isrxhardware(src)) {
07155	        m_ptr->m_source = HARDWARE;
07156	        m_ptr->m_type = HARD_INT;
07157	        caller_ptr->p_int_blocked = FALSE;

⌨️ 快捷键说明

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