From c1da6e6e24908b1af03d78a0690c9a5ce01571b9 Mon Sep 17 00:00:00 2001 From: Philip Homburg Date: Wed, 15 Mar 2006 12:01:59 +0000 Subject: [PATCH] Allow a process to kill itself. Remove the endpoint of a process that kills itself before reporting the singal to pm. --- kernel/proc.c | 14 ++++++-- kernel/proc.h | 1 + kernel/proto.h | 1 + kernel/system.c | 74 +++++++++++++++++++++++++++++++++++++++++ kernel/system/do_exit.c | 54 ++---------------------------- kernel/system/do_kill.c | 12 +++++-- 6 files changed, 100 insertions(+), 56 deletions(-) diff --git a/kernel/proc.c b/kernel/proc.c index 2635d299d..138126e03 100755 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -42,6 +42,7 @@ #include "debug.h" #include "kernel.h" #include "proc.h" +#include /* Scheduling and message passing functions. The functions are available to * other parts of the kernel through lock_...(). The lock temporarily disables @@ -147,7 +148,7 @@ long bit_map; /* notification event set or flags */ * anywhere in data or stack or gap. It will have to be made more elaborate * for machines which don't have the gap mapped. */ - if (function & CHECK_PTR) { + if (function & CHECK_PTR) { vlo = (vir_bytes) m_ptr >> CLICK_SHIFT; vhi = ((vir_bytes) m_ptr + MESS_SIZE - 1) >> CLICK_SHIFT; if (vlo < caller_ptr->p_memmap[D].mem_vir || vlo > vhi || @@ -164,7 +165,7 @@ long bit_map; /* notification event set or flags */ /* If the call is to send to a process, i.e., for SEND, SENDREC or NOTIFY, * verify that the caller is allowed to send to the given destination. */ - if (function & CHECK_DST) { + if (function & CHECK_DST) { if (! get_sys_bit(priv(caller_ptr)->s_ipc_to, nr_to_id(src_dst))) { #if DEBUG_ENABLE_IPC_WARNINGS kprintf("sys_call: ipc mask denied trap %d from %d to %d\n", @@ -295,6 +296,8 @@ unsigned flags; /* system call flags */ dst_p = _ENDPOINT_P(dst_e); dst_ptr = proc_addr(dst_p); + if (dst_ptr->p_rts_flags & NO_ENDPOINT) return EDSTDIED; + /* Check if 'dst' is blocked waiting for this message. The destination's * SENDING flag may be set when its SENDREC call blocked while sending. */ @@ -345,7 +348,12 @@ unsigned flags; /* system call flags */ int i, src_id, src_proc_nr, src_p; if(src_e == ANY) src_p = ANY; - else okendpt(src_e, &src_p); + else + { + okendpt(src_e, &src_p); + if (proc_addr(src_p)->p_rts_flags & NO_ENDPOINT) return ESRCDIED; + } + /* Check to see if a message from desired source is already available. * The caller's SENDING flag may be set if SENDREC couldn't send. If it is diff --git a/kernel/proc.h b/kernel/proc.h index df4462413..ec51bacbb 100755 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -69,6 +69,7 @@ struct proc { #define P_STOP 0x40 /* set when process is being traced */ #define NO_PRIV 0x80 /* keep forked system process from running */ #define NO_PRIORITY 0x100 /* process has been stopped */ +#define NO_ENDPOINT 0x200 /* process cannot send or receive messages */ /* Misc flags */ #define REPLY_PENDING 0x01 /* reply to IPC_REQUEST is pending */ diff --git a/kernel/proto.h b/kernel/proto.h index 071364ba6..91387954a 100755 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -59,6 +59,7 @@ _PROTOTYPE( phys_bytes umap_remote, (struct proc *rp, int seg, vir_bytes vir_addr, vir_bytes bytes) ); _PROTOTYPE( phys_bytes umap_bios, (struct proc *rp, vir_bytes vir_addr, vir_bytes bytes) ); +_PROTOTYPE( void clear_endpoint, (struct proc *rc) ); #if (CHIP == INTEL) diff --git a/kernel/system.c b/kernel/system.c index ba949ee33..5c964ea89 100755 --- a/kernel/system.c +++ b/kernel/system.c @@ -19,6 +19,7 @@ * umap_bios: map virtual address in BIOS_SEG to physical * virtual_copy: copy bytes from one virtual address to another * get_randomness: accumulate randomness in a buffer + * clear_endpoint: remove a process' ability to send and receive messages * * Changes: * Aug 04, 2005 check if system call is allowed (Jorrit N. Herder) @@ -471,3 +472,76 @@ vir_bytes bytes; /* # of bytes to copy */ return(OK); } + +/*===========================================================================* + * clear_endpoint * + *===========================================================================*/ +PUBLIC void clear_endpoint(rc) +register struct proc *rc; /* slot of process to clean up */ +{ + register struct proc *rp; /* iterate over process table */ + register struct proc **xpp; /* iterate over caller queue */ + int i; + int sys_id; + + if(isemptyp(rc)) panic("clear_proc: empty process", proc_nr(rc)); + + /* Make sure that the exiting process is no longer scheduled. */ + if (rc->p_rts_flags == 0) lock_dequeue(rc); + rc->p_rts_flags |= NO_ENDPOINT; + + /* If the process happens to be queued trying to send a + * message, then it must be removed from the message queues. + */ + if (rc->p_rts_flags & SENDING) { + int target_proc; + + okendpt(rc->p_sendto_e, &target_proc); + xpp = &proc_addr(target_proc)->p_caller_q; /* destination's queue */ + while (*xpp != NIL_PROC) { /* check entire queue */ + if (*xpp == rc) { /* process is on the queue */ + *xpp = (*xpp)->p_q_link; /* replace by next process */ +#if DEBUG_ENABLE_IPC_WARNINGS + kprintf("Proc %d removed from queue at %d\n", + proc_nr(rc), rc->p_sendto_e); +#endif + break; /* can only be queued once */ + } + xpp = &(*xpp)->p_q_link; /* proceed to next queued */ + } + rc->p_rts_flags &= ~SENDING; + } + rc->p_rts_flags &= ~RECEIVING; + + /* Likewise, if another process was sending or receive a message to or from + * the exiting process, it must be alerted that process no longer is alive. + * Check all processes. + */ + for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) { + if(isemptyp(rp)) + continue; + + /* Unset pending notification bits. */ + unset_sys_bit(priv(rp)->s_notify_pending, priv(rc)->s_id); + + /* Check if process is receiving from exiting process. */ + if ((rp->p_rts_flags & RECEIVING) && rp->p_getfrom_e == rc->p_endpoint) { + rp->p_reg.retreg = ESRCDIED; /* report source died */ + rp->p_rts_flags &= ~RECEIVING; /* no longer receiving */ +#if DEBUG_ENABLE_IPC_WARNINGS + kprintf("Proc %d receive dead src %d\n", proc_nr(rp), proc_nr(rc)); +#endif + if (rp->p_rts_flags == 0) lock_enqueue(rp);/* let process run again */ + } + if ((rp->p_rts_flags & SENDING) && rp->p_sendto_e == rc->p_endpoint) { + rp->p_reg.retreg = EDSTDIED; /* report destination died */ + rp->p_rts_flags &= ~SENDING; /* no longer sending */ +#if DEBUG_ENABLE_IPC_WARNINGS + kprintf("Proc %d send dead dst %d\n", proc_nr(rp), proc_nr(rc)); +#endif + if (rp->p_rts_flags == 0) lock_enqueue(rp);/* let process run again */ + } + } +} + + diff --git a/kernel/system/do_exit.c b/kernel/system/do_exit.c index 670a07108..165ea855c 100644 --- a/kernel/system/do_exit.c +++ b/kernel/system/do_exit.c @@ -57,6 +57,9 @@ register struct proc *rc; /* slot of process to clean up */ /* Don't clear if already cleared. */ if(isemptyp(rc)) return; + /* Remove the process' ability to send and receive messages */ + clear_endpoint(rc); + /* Turn off any alarm timers at the clock. */ reset_timer(&priv(rc)->s_alarm_timer); @@ -81,57 +84,6 @@ register struct proc *rc; /* slot of process to clean up */ rc->p_rts_flags = SLOT_FREE; if (priv(rc)->s_flags & SYS_PROC) priv(rc)->s_proc_nr = NONE; - /* If the process being terminated happens to be queued trying to send a - * message (e.g., the process was killed by a signal, rather than it doing - * a normal exit), then it must be removed from the message queues. - */ - if (saved_rts_flags & SENDING) { - int target_proc; - okendpt(rc->p_sendto_e, &target_proc); - xpp = &proc_addr(target_proc)->p_caller_q; /* destination's queue */ - while (*xpp != NIL_PROC) { /* check entire queue */ - if (*xpp == rc) { /* process is on the queue */ - *xpp = (*xpp)->p_q_link; /* replace by next process */ -#if DEBUG_ENABLE_IPC_WARNINGS - kprintf("Proc %d removed from queue at %d\n", - proc_nr(rc), rc->p_sendto_e); -#endif - break; /* can only be queued once */ - } - xpp = &(*xpp)->p_q_link; /* proceed to next queued */ - } - } - - /* Likewise, if another process was sending or receive a message to or from - * the exiting process, it must be alerted that process no longer is alive. - * Check all processes. - */ - for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) { - if(isemptyp(rp)) - continue; - - /* Unset pending notification bits. */ - unset_sys_bit(priv(rp)->s_notify_pending, priv(rc)->s_id); - - /* Check if process is receiving from exiting process. */ - if ((rp->p_rts_flags & RECEIVING) && rp->p_getfrom_e == rc->p_endpoint) { - rp->p_reg.retreg = ESRCDIED; /* report source died */ - rp->p_rts_flags &= ~RECEIVING; /* no longer receiving */ -#if DEBUG_ENABLE_IPC_WARNINGS - kprintf("Proc %d receive dead src %d\n", proc_nr(rp), proc_nr(rc)); -#endif - if (rp->p_rts_flags == 0) lock_enqueue(rp);/* let process run again */ - } - if ((rp->p_rts_flags & SENDING) && rp->p_sendto_e == rc->p_endpoint) { - rp->p_reg.retreg = EDSTDIED; /* report destination died */ - rp->p_rts_flags &= ~SENDING; /* no longer sending */ -#if DEBUG_ENABLE_IPC_WARNINGS - kprintf("Proc %d send dead dst %d\n", proc_nr(rp), proc_nr(rc)); -#endif - if (rp->p_rts_flags == 0) lock_enqueue(rp);/* let process run again */ - } - } - /* Clean up virtual memory */ if (rc->p_misc_flags & MF_VM) vm_map_default(rc); diff --git a/kernel/system/do_kill.c b/kernel/system/do_kill.c index eab947d7d..289bcc099 100644 --- a/kernel/system/do_kill.c +++ b/kernel/system/do_kill.c @@ -26,15 +26,23 @@ message *m_ptr; /* pointer to request message */ * are usually blocked on a RECEIVE), they can request the PM to transform * signals into messages. This is done by the PM with a call to sys_kill(). */ - proc_nr_t proc_nr; + proc_nr_t proc_nr, proc_nr_e; int sig_nr = m_ptr->SIG_NUMBER; - if (!isokendpt(m_ptr->SIG_ENDPT, &proc_nr)) return(EINVAL); + proc_nr_e= m_ptr->SIG_ENDPT; + + if (proc_nr_e == SELF) + proc_nr_e= m_ptr->m_source; + + if (!isokendpt(proc_nr_e, &proc_nr)) return(EINVAL); + if (sig_nr > _NSIG) return(EINVAL); if (iskerneln(proc_nr)) return(EPERM); /* Set pending signal to be processed by the PM. */ cause_sig(proc_nr, sig_nr); + if (sig_nr == SIGKILL) + clear_endpoint(proc_addr(proc_nr)); return(OK); }