📄 proc.c
字号:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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 + -