Fixed clear_proc(): properly release resources (IRQ hooks, notify buffers);
Cleaned up comments in proc.c (old code still present for comparison);
This commit is contained in:
parent
fcd113da7b
commit
826fee4c6d
3 changed files with 96 additions and 63 deletions
|
@ -29,6 +29,11 @@ EXTERN struct proc *next_ptr; /* pointer to next process to run */
|
||||||
EXTERN char k_reenter; /* kernel reentry count (entry count less 1) */
|
EXTERN char k_reenter; /* kernel reentry count (entry count less 1) */
|
||||||
EXTERN unsigned lost_ticks; /* clock ticks counted outside clock task */
|
EXTERN unsigned lost_ticks; /* clock ticks counted outside clock task */
|
||||||
|
|
||||||
|
/* Declare buffer space and a bit map for notification messages. */
|
||||||
|
EXTERN struct notification notify_buffer[NR_NOTIFY_BUFS];
|
||||||
|
EXTERN bitchunk_t notify_bitmap[BITMAP_CHUNKS(NR_NOTIFY_BUFS)];
|
||||||
|
|
||||||
|
|
||||||
#if (CHIP == INTEL)
|
#if (CHIP == INTEL)
|
||||||
|
|
||||||
/* Interrupt related variables. */
|
/* Interrupt related variables. */
|
||||||
|
|
104
kernel/proc.c
104
kernel/proc.c
|
@ -2,11 +2,12 @@
|
||||||
#define OLD_SEND 0
|
#define OLD_SEND 0
|
||||||
#define OLD_RECV 0
|
#define OLD_RECV 0
|
||||||
/* This file contains essentially all of the process and message handling.
|
/* This file contains essentially all of the process and message handling.
|
||||||
* It has one main entry point from the outside:
|
* Together with "mpx.s" it forms the lowest layer of the MINIX kernel.
|
||||||
|
* There is one entry point from the outside:
|
||||||
*
|
*
|
||||||
* sys_call: a system call, i.e., the kernel is trapped with an INT
|
* sys_call: a system call, i.e., the kernel is trapped with an INT
|
||||||
*
|
*
|
||||||
* It also has several minor entry points to be used from the task level:
|
* As well as several entry points used from the interrupt and task level:
|
||||||
*
|
*
|
||||||
* lock_notify: send a notification to inform a process of a system event
|
* lock_notify: send a notification to inform a process of a system event
|
||||||
* lock_send: send a message to a process
|
* lock_send: send a message to a process
|
||||||
|
@ -16,13 +17,29 @@
|
||||||
* lock_pick_proc: pick a process to run (used by system initialization)
|
* lock_pick_proc: pick a process to run (used by system initialization)
|
||||||
*
|
*
|
||||||
* Changes:
|
* Changes:
|
||||||
|
* , 2005 better protection in sys_call() (Jorrit N. Herder)
|
||||||
* May 26, 2005 optimized message passing functions (Jorrit N. Herder)
|
* May 26, 2005 optimized message passing functions (Jorrit N. Herder)
|
||||||
* May 24, 2005 new, queued NOTIFY system call (Jorrit N. Herder)
|
* May 24, 2005 new, queued NOTIFY system call (Jorrit N. Herder)
|
||||||
* Oct 28, 2004 non-blocking SEND and RECEIVE (Jorrit N. Herder)
|
* Oct 28, 2004 new, non-blocking SEND and RECEIVE (Jorrit N. Herder)
|
||||||
* Oct 28, 2004 rewrite of sys_call() (Jorrit N. Herder)
|
* Oct 28, 2004 rewrite of sys_call() function (Jorrit N. Herder)
|
||||||
* Oct 10, 2004 require SENDREC for kernel sys_call() (Jorrit N. Herder)
|
* Aug 19, 2004 generalized multilevel scheduling (Jorrit N. Herder)
|
||||||
* (to protect kernel tasks from being blocked)
|
*
|
||||||
* Aug 19, 2004 generalized ready()/unready() (Jorrit N. Herder)
|
* The code here is critical to make everything work and is important for the
|
||||||
|
* overall performance of the system. A large fraction of the code deals with
|
||||||
|
* list manipulation. To make this both easy to understand and fast to execute
|
||||||
|
* pointer pointers are used throughout the code. Pointer pointers prevent
|
||||||
|
* exceptions for the head or tail of a linked list.
|
||||||
|
*
|
||||||
|
* node_t *queue, *new_node; // assume these as global variables
|
||||||
|
* node_t **xpp = &queue; // get pointer pointer to head of queue
|
||||||
|
* while (*xpp != NULL) // find last pointer of the linked list
|
||||||
|
* xpp = &(*xpp)->next; // get pointer to next pointer
|
||||||
|
* *xpp = new_node; // now replace the end (the NULL pointer)
|
||||||
|
* new_node->next = NULL; // and mark the new end of the list
|
||||||
|
*
|
||||||
|
* For example, when adding a new node to the end of the list, one normally
|
||||||
|
* makes an exception for an empty list and looks up the end of the list for
|
||||||
|
* nonempty lists. As shown above, this is not required with pointer pointers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
@ -45,8 +62,8 @@ FORWARD _PROTOTYPE( int mini_notify, (struct proc *caller_ptr, int dst,
|
||||||
message *m_ptr ) );
|
message *m_ptr ) );
|
||||||
|
|
||||||
FORWARD _PROTOTYPE( void ready, (struct proc *rp) );
|
FORWARD _PROTOTYPE( void ready, (struct proc *rp) );
|
||||||
FORWARD _PROTOTYPE( void sched, (int queue) );
|
|
||||||
FORWARD _PROTOTYPE( void unready, (struct proc *rp) );
|
FORWARD _PROTOTYPE( void unready, (struct proc *rp) );
|
||||||
|
FORWARD _PROTOTYPE( void sched, (int queue) );
|
||||||
FORWARD _PROTOTYPE( void pick_proc, (void) );
|
FORWARD _PROTOTYPE( void pick_proc, (void) );
|
||||||
|
|
||||||
#define BuildMess(m,n) \
|
#define BuildMess(m,n) \
|
||||||
|
@ -67,16 +84,18 @@ FORWARD _PROTOTYPE( void pick_proc, (void) );
|
||||||
#endif /* (CHIP == M68000) */
|
#endif /* (CHIP == M68000) */
|
||||||
|
|
||||||
|
|
||||||
|
#if DEAD_CODE /* now in glo.h */
|
||||||
/* Declare buffer space and a bit map for notification messages. */
|
/* Declare buffer space and a bit map for notification messages. */
|
||||||
PRIVATE struct notification notify_buffer[NR_NOTIFY_BUFS];
|
PRIVATE struct notification notify_buffer[NR_NOTIFY_BUFS];
|
||||||
PRIVATE bitchunk_t notify_bitmap[BITMAP_CHUNKS(NR_NOTIFY_BUFS)];
|
PRIVATE bitchunk_t notify_bitmap[BITMAP_CHUNKS(NR_NOTIFY_BUFS)];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* sys_call *
|
* sys_call *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PUBLIC int sys_call(call_nr, src_dst, m_ptr)
|
PUBLIC int sys_call(call_nr, src_dst, m_ptr)
|
||||||
int call_nr; /* (NB_)SEND, (NB_)RECEIVE, SENDREC */
|
int call_nr; /* system call number and flags */
|
||||||
int src_dst; /* src to receive from or dst to send to */
|
int src_dst; /* src to receive from or dst to send to */
|
||||||
message *m_ptr; /* pointer to message in the caller's space */
|
message *m_ptr; /* pointer to message in the caller's space */
|
||||||
{
|
{
|
||||||
|
@ -93,15 +112,12 @@ message *m_ptr; /* pointer to message in the caller's space */
|
||||||
vir_clicks vlo, vhi; /* virtual clicks containing message to send */
|
vir_clicks vlo, vhi; /* virtual clicks containing message to send */
|
||||||
|
|
||||||
/* Calls directed to the kernel may only be sendrec(), because tasks always
|
/* Calls directed to the kernel may only be sendrec(), because tasks always
|
||||||
* reply and may not block if the caller doesn't do receive(). Users also
|
* reply and may not block if the caller doesn't do receive().
|
||||||
* may only use sendrec() to protect the process manager and file system.
|
|
||||||
*/
|
*/
|
||||||
if (iskernel(src_dst) && function != SENDREC)
|
if (iskernel(src_dst) && function != SENDREC) return(ECALLDENIED);
|
||||||
return(ECALLDENIED); /* SENDREC was required */
|
|
||||||
|
|
||||||
/* Verify that requested source and/ or destination is a valid process. */
|
/* Verify that requested source and/ or destination is a valid process. */
|
||||||
if (! isoksrc_dst(src_dst) && function != ECHO)
|
if (! isoksrc_dst(src_dst) && function != ECHO) return(EBADSRCDST);
|
||||||
return(EBADSRCDST);
|
|
||||||
|
|
||||||
/* Check validity of message pointer. */
|
/* Check validity of message pointer. */
|
||||||
vb = (vir_bytes) m_ptr;
|
vb = (vir_bytes) m_ptr;
|
||||||
|
@ -124,8 +140,12 @@ message *m_ptr; /* pointer to message in the caller's space */
|
||||||
|
|
||||||
/* Now check if the call is known and try to perform the request. The only
|
/* Now check if the call is known and try to perform the request. The only
|
||||||
* system calls that exist in MINIX are sending and receiving messages.
|
* system calls that exist in MINIX are sending and receiving messages.
|
||||||
* Receiving is straightforward. Sending requires to check caller's send
|
* - SENDREC: combines SEND and RECEIVE in a single system call
|
||||||
* mask and whether the destination is alive.
|
* - SEND: sender blocks until its message has been delivered
|
||||||
|
* - RECEIVE: receiver blocks until an acceptable message has arrived
|
||||||
|
* - NOTIFY: sender continues; either directly deliver the message or
|
||||||
|
* queue the notification message until it can be delivered
|
||||||
|
* - ECHO: the message directly will be echoed to the sender
|
||||||
*/
|
*/
|
||||||
switch(function) {
|
switch(function) {
|
||||||
case SENDREC:
|
case SENDREC:
|
||||||
|
@ -207,15 +227,14 @@ unsigned flags; /* system call flags */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if 'dst' is blocked waiting for this message. The destination's
|
/* Check if 'dst' is blocked waiting for this message. The destination's
|
||||||
* SENDING flag may be set when SENDREC couldn't send. Await a pure RECEIVE.
|
* SENDING flag may be set when its SENDREC call blocked while sending.
|
||||||
*/
|
*/
|
||||||
if ( (dst_ptr->p_flags & (RECEIVING | SENDING)) == RECEIVING &&
|
if ( (dst_ptr->p_flags & (RECEIVING | SENDING)) == RECEIVING &&
|
||||||
(dst_ptr->p_getfrom == ANY || dst_ptr->p_getfrom == caller_ptr->p_nr)) {
|
(dst_ptr->p_getfrom == ANY || dst_ptr->p_getfrom == caller_ptr->p_nr)) {
|
||||||
/* Destination is indeed waiting for this message. */
|
/* Destination is indeed waiting for this message. */
|
||||||
CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, dst_ptr,
|
CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, dst_ptr,
|
||||||
dst_ptr->p_messbuf);
|
dst_ptr->p_messbuf);
|
||||||
if ((dst_ptr->p_flags &= ~RECEIVING) == 0)
|
if ((dst_ptr->p_flags &= ~RECEIVING) == 0) ready(dst_ptr);
|
||||||
ready(dst_ptr);
|
|
||||||
} else if ( ! (flags & NON_BLOCKING)) {
|
} else if ( ! (flags & NON_BLOCKING)) {
|
||||||
/* Destination is not waiting. Block and queue caller. */
|
/* Destination is not waiting. Block and queue caller. */
|
||||||
caller_ptr->p_messbuf = m_ptr;
|
caller_ptr->p_messbuf = m_ptr;
|
||||||
|
@ -233,13 +252,12 @@ unsigned flags; /* system call flags */
|
||||||
next_ptr->p_q_link = caller_ptr;
|
next_ptr->p_q_link = caller_ptr;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
xpp = &dst_ptr->p_caller_q;
|
xpp = &dst_ptr->p_caller_q; /* find end of list */
|
||||||
while (*xpp != NIL_PROC) xpp = &(*xpp)->p_q_link;
|
while (*xpp != NIL_PROC) xpp = &(*xpp)->p_q_link;
|
||||||
*xpp = caller_ptr;
|
*xpp = caller_ptr; /* add caller to end */
|
||||||
#endif
|
#endif
|
||||||
caller_ptr->p_q_link = NIL_PROC;
|
caller_ptr->p_q_link = NIL_PROC; /* mark new end of list */
|
||||||
} else {
|
} else {
|
||||||
kprintf("Didn't block... ;-), flags: 0x%x\n", flags);
|
|
||||||
return(ENOTREADY);
|
return(ENOTREADY);
|
||||||
}
|
}
|
||||||
return(OK);
|
return(OK);
|
||||||
|
@ -254,9 +272,9 @@ int src; /* which message source is wanted */
|
||||||
message *m_ptr; /* pointer to message buffer */
|
message *m_ptr; /* pointer to message buffer */
|
||||||
unsigned flags; /* system call flags */
|
unsigned flags; /* system call flags */
|
||||||
{
|
{
|
||||||
/* A process or task wants to get a message. If one is already queued,
|
/* A process or task wants to get a message. If a message is already queued,
|
||||||
* acquire it and deblock the sender. If no message from the desired source
|
* acquire it and deblock the sender. If no message from the desired source
|
||||||
* is available, block the caller.
|
* is available block the caller, unless the flags don't allow blocking.
|
||||||
*/
|
*/
|
||||||
#if OLD_RECV
|
#if OLD_RECV
|
||||||
register struct proc *sender_ptr;
|
register struct proc *sender_ptr;
|
||||||
|
@ -295,21 +313,18 @@ unsigned flags; /* system call flags */
|
||||||
xpp = &caller_ptr->p_caller_q;
|
xpp = &caller_ptr->p_caller_q;
|
||||||
while (*xpp != NIL_PROC) {
|
while (*xpp != NIL_PROC) {
|
||||||
if (src == ANY || src == proc_nr(*xpp)) {
|
if (src == ANY || src == proc_nr(*xpp)) {
|
||||||
/* An acceptable source has been found. Copy the message to the
|
/* Found acceptable message. Copy it and update status. */
|
||||||
* caller, update the sender's status, and remove the sender from
|
|
||||||
* the caller's queue.
|
|
||||||
*/
|
|
||||||
CopyMess((*xpp)->p_nr, *xpp, (*xpp)->p_messbuf, caller_ptr, m_ptr);
|
CopyMess((*xpp)->p_nr, *xpp, (*xpp)->p_messbuf, caller_ptr, m_ptr);
|
||||||
if (((*xpp)->p_flags &= ~SENDING) == 0) ready(*xpp);
|
if (((*xpp)->p_flags &= ~SENDING) == 0) ready(*xpp);
|
||||||
*xpp = (*xpp)->p_q_link; /* remove from queue */
|
*xpp = (*xpp)->p_q_link; /* remove from queue */
|
||||||
return(OK);
|
return(OK); /* report success */
|
||||||
}
|
}
|
||||||
xpp = &(*xpp)->p_q_link; /* proceed to next */
|
xpp = &(*xpp)->p_q_link; /* proceed to next */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Check if there are pending notifications. */
|
/* Check if there are pending notifications, except for SENDREC. */
|
||||||
if (! (flags & FRESH_ANSWER)) {
|
if (! (flags & FRESH_ANSWER)) {
|
||||||
|
|
||||||
ntf_q_pp = &caller_ptr->p_ntf_q; /* get pointer pointer */
|
ntf_q_pp = &caller_ptr->p_ntf_q; /* get pointer pointer */
|
||||||
while (*ntf_q_pp != NULL) {
|
while (*ntf_q_pp != NULL) {
|
||||||
|
@ -326,8 +341,7 @@ if (! (flags & FRESH_ANSWER)) {
|
||||||
}
|
}
|
||||||
ntf_q_pp = &(*ntf_q_pp)->n_next; /* proceed to next */
|
ntf_q_pp = &(*ntf_q_pp)->n_next; /* proceed to next */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No suitable message is available or the caller couldn't send in SENDREC.
|
/* No suitable message is available or the caller couldn't send in SENDREC.
|
||||||
|
@ -374,7 +388,7 @@ message *m_ptr; /* pointer to message buffer */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Destination is not ready. Add the notification to the pending queue.
|
/* Destination is not ready. Add the notification to the pending queue.
|
||||||
* Get pointer to notification message. Don't copy for the kernel.
|
* Get pointer to notification message. Don't copy if already in kernel.
|
||||||
*/
|
*/
|
||||||
if (! iskernelp(caller_ptr)) {
|
if (! iskernelp(caller_ptr)) {
|
||||||
CopyMess(proc_nr(caller_ptr), caller_ptr, m_ptr,
|
CopyMess(proc_nr(caller_ptr), caller_ptr, m_ptr,
|
||||||
|
@ -401,13 +415,13 @@ message *m_ptr; /* pointer to message buffer */
|
||||||
/* Add to end of queue (found above). Get a free notification buffer. */
|
/* Add to end of queue (found above). Get a free notification buffer. */
|
||||||
if ((ntf_index = alloc_bit(notify_bitmap, NR_NOTIFY_BUFS)) < 0)
|
if ((ntf_index = alloc_bit(notify_bitmap, NR_NOTIFY_BUFS)) < 0)
|
||||||
return(ENOSPC);
|
return(ENOSPC);
|
||||||
ntf_p = ¬ify_buffer[ntf_index];
|
ntf_p = ¬ify_buffer[ntf_index]; /* get pointer to buffer */
|
||||||
*ntf_q_pp = ntf_p; /* add to end of queue */
|
ntf_p->n_source = proc_nr(caller_ptr);/* store notification data */
|
||||||
ntf_p->n_next = NULL; /* mark new end of queue */
|
|
||||||
ntf_p->n_source = proc_nr(caller_ptr);
|
|
||||||
ntf_p->n_type = m_ptr->NOTIFY_TYPE;
|
ntf_p->n_type = m_ptr->NOTIFY_TYPE;
|
||||||
ntf_p->n_flags = m_ptr->NOTIFY_FLAGS;
|
ntf_p->n_flags = m_ptr->NOTIFY_FLAGS;
|
||||||
ntf_p->n_arg = m_ptr->NOTIFY_ARG;
|
ntf_p->n_arg = m_ptr->NOTIFY_ARG;
|
||||||
|
*ntf_q_pp = ntf_p; /* add to end of queue */
|
||||||
|
ntf_p->n_next = NULL; /* mark new end of queue */
|
||||||
return(OK);
|
return(OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +433,7 @@ int dst; /* to whom is message being sent? */
|
||||||
message *m_ptr; /* pointer to message buffer */
|
message *m_ptr; /* pointer to message buffer */
|
||||||
{
|
{
|
||||||
/* Safe gateway to mini_notify() for tasks and interrupt handlers. This
|
/* Safe gateway to mini_notify() for tasks and interrupt handlers. This
|
||||||
* function checks if it is called from an interrupt handler and makes sure
|
* function checks if it is called from an interrupt handler and ensures
|
||||||
* that the correct message source is put on the notification.
|
* that the correct message source is put on the notification.
|
||||||
*/
|
*/
|
||||||
int result;
|
int result;
|
||||||
|
@ -483,12 +497,12 @@ register struct proc *rp; /* this process is now runnable */
|
||||||
#if NEW_SCHED_Q
|
#if NEW_SCHED_Q
|
||||||
if (isuserp(rp)) { /* add to front of queue */
|
if (isuserp(rp)) { /* add to front of queue */
|
||||||
rp->p_nextready = rdy_head[q]; /* chain current front */
|
rp->p_nextready = rdy_head[q]; /* chain current front */
|
||||||
rdy_head[q] = rp; /* ready process becomes front */
|
rdy_head[q] = rp; /* rp becomes new front */
|
||||||
}
|
}
|
||||||
else { /* add to end of queue */
|
else { /* add to end of queue */
|
||||||
xpp = &rdy_head[q]; /* find pointer to end of queue */
|
xpp = &rdy_head[q]; /* find pointer to end */
|
||||||
while (*xpp != NIL_PROC) xpp = &(*xpp)->p_nextready;
|
while (*xpp != NIL_PROC) xpp = &(*xpp)->p_nextready;
|
||||||
*xpp = rp; /* replace end with ready process */
|
*xpp = rp; /* replace end with rp */
|
||||||
rp->p_nextready = NIL_PROC; /* mark end of queue */
|
rp->p_nextready = NIL_PROC; /* mark end of queue */
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -605,7 +619,7 @@ int queue;
|
||||||
xpp = &rdy_head[queue]; /* find end of queue */
|
xpp = &rdy_head[queue]; /* find end of queue */
|
||||||
while (*xpp != NIL_PROC) xpp = &(*xpp)->p_nextready;
|
while (*xpp != NIL_PROC) xpp = &(*xpp)->p_nextready;
|
||||||
*xpp = xp; /* add expired to end */
|
*xpp = xp; /* add expired to end */
|
||||||
xp->p_nextready = NIL_PROC; /* mark end of queue */
|
xp->p_nextready = NIL_PROC; /* mark new end of queue */
|
||||||
|
|
||||||
#else
|
#else
|
||||||
rdy_tail[queue]->p_nextready = rdy_head[queue];
|
rdy_tail[queue]->p_nextready = rdy_head[queue];
|
||||||
|
|
|
@ -186,6 +186,7 @@ int proc_nr; /* slot of process to clean up */
|
||||||
#else
|
#else
|
||||||
register struct proc **xpp; /* iterate over caller queue */
|
register struct proc **xpp; /* iterate over caller queue */
|
||||||
#endif
|
#endif
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Get a pointer to the process that exited. */
|
/* Get a pointer to the process that exited. */
|
||||||
rc = proc_addr(proc_nr);
|
rc = proc_addr(proc_nr);
|
||||||
|
@ -238,6 +239,19 @@ int proc_nr; /* slot of process to clean up */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check the table with IRQ hooks to see if hooks should be released. */
|
||||||
|
for (i=0; i < NR_IRQ_HOOKS; i++) {
|
||||||
|
if (irq_hooks[i].proc_nr == proc_nr)
|
||||||
|
irq_hooks[i].proc_nr = NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if there are pending notifications. Release the buffers. */
|
||||||
|
while (rc->p_ntf_q != NULL) {
|
||||||
|
i = (int) (rc->p_ntf_q - ¬ify_buffer[0]);
|
||||||
|
free_bit(i, notify_bitmap, NR_NOTIFY_BUFS);
|
||||||
|
rc->p_ntf_q = rc->p_ntf_q->n_next;
|
||||||
|
}
|
||||||
|
|
||||||
/* Now clean up the process table entry. Reset to defaults. */
|
/* Now clean up the process table entry. Reset to defaults. */
|
||||||
kstrncpy(rc->p_name, "<noname>", PROC_NAME_LEN); /* unset name */
|
kstrncpy(rc->p_name, "<noname>", PROC_NAME_LEN); /* unset name */
|
||||||
sigemptyset(&rc->p_pending); /* remove pending signals */
|
sigemptyset(&rc->p_pending); /* remove pending signals */
|
||||||
|
|
Loading…
Reference in a new issue