Optimized scheduling code. Old code is still available withing DEAD_CODE

and NEW_SCHED_Q definitions. Some minor problems are being traced at the
moment. This commit is meant to backup my files.
  --- Jorrit
This commit is contained in:
Jorrit Herder 2005-05-26 13:17:57 +00:00
parent dcffa17db2
commit 77c3213948
15 changed files with 321 additions and 198 deletions

View file

@ -869,11 +869,17 @@ message *m;
int r;
/* Try to get a fresh copy of the buffer with kernel messages. */
r=0;
#if DEAD_CODE
/* During shutdown, the reply is garbled because new notifications arrive
* while the system task makes a copy of the kernel messages buffer.
* Hence, don't check the return value.
*/
if ((r=sys_getkmessages(&kmess)) != OK) {
printf("TTY: couldn't get copy of kmessages: %d, 0x%x\n", r,r);
return;
}
#endif
sys_getkmessages(&kmess);
/* Print only the new part. Determine how many new bytes there are with
* help of the current and previous 'next' index. Note that the kernel

View file

@ -526,13 +526,23 @@ int scode; /* scan code for a function key */
/* See if an observer is registered and send it a message. */
if (observers[index] != NONE) {
#if DEAD_CODE
m.m_type = FKEY_PRESSED;
m.FKEY_NUM = index+1;
m.FKEY_CODE = fkey;
if (OK != (s=nb_send(observers[index], &m))) {
printf("WARNING: F%d key notification to process %d failed: %d.\n",
printf("WARNING: F%d key nb_send to process %d failed: %d.\n",
index+1, observers[index], s);
}
#else
m.NOTIFY_TYPE = FKEY_PRESSED;
m.NOTIFY_ARG = fkey;
m.NOTIFY_FLAGS = index+1;
if (OK != (s=notify(observers[index], &m))) {
printf("WARNING: F%d key notify to process %d failed: %d.\n",
index+1, observers[index], s);
}
#endif
}
return(TRUE);
}

View file

@ -145,6 +145,7 @@ PUBLIC timer_t *tty_timers; /* queue of TTY timers */
PUBLIC clock_t tty_next_timeout; /* time that the next alarm is due */
PUBLIC struct machine machine; /* kernel environment variables */
static int debug = 0;
/*===========================================================================*
* tty_task *
@ -192,6 +193,11 @@ PUBLIC void main(void)
* request and should be handled separately. These extra functions
* do not operate on a device, in constrast to the driver requests.
*/
if (debug) {
printf("TTY got request from %d, type %d\n",
tty_mess.m_source, tty_mess.m_type);
printf("???\n");
}
switch (tty_mess.m_type) {
case SYN_ALARM: /* fall through */
case HARD_INT: /* hardware interrupt notification */
@ -204,8 +210,12 @@ PUBLIC void main(void)
case HARD_STOP: { /* MINIX is going down */
static int stop = 0; /* expect two HARD_STOP messages */
if (! stop++) {
printf("TTY got first HARD_STOP message\n");
debug = 1;
cons_stop(); /* first switch to primary console */
printf("TTY returned from cons_stop()\n");
} else {
printf("TTY got second HARD_STOP message\n");
if(irq_hook_id != -1) {
int r;
r = sys_irqdisable(&irq_hook_id);
@ -222,7 +232,9 @@ PUBLIC void main(void)
do_panic_dumps(&tty_mess);
continue;
case DIAGNOSTICS: /* a server wants to print some */
if (debug) printf("TTY get DIAG\n");
do_diagnostics(&tty_mess);
if (debug) printf("TTY finished DIAG\n");
continue;
case FKEY_CONTROL: /* (un)register a fkey observer */
do_fkey_ctl(&tty_mess);
@ -1302,8 +1314,12 @@ int status; /* reply code */
tty_mess.m_type = code;
tty_mess.REP_PROC_NR = proc_nr;
tty_mess.REP_STATUS = status;
if ((status = send(replyee, &tty_mess)) != OK)
if (debug)
printf("TTY wanted to send to %d, type %d, status %d\n",
proc_nr, code, status);
if ((status = send(replyee, &tty_mess)) != OK) {
server_panic("TTY","tty_reply failed, status\n", status);
}
}

View file

@ -118,7 +118,7 @@ PUBLIC void clock_task()
result = do_clocktick(&m); /* handle clock tick */
break;
default: /* illegal message type */
kprintf("CLOCK got illegal request from %d.\n", m.m_source);
kprintf("Warning, illegal CLOCK request from %d.\n", m.m_source);
result = EBADREQUEST;
}
@ -128,7 +128,8 @@ PUBLIC void clock_task()
*/
if (result != EDONTREPLY) {
m.m_type = result;
lock_send(m.m_source, &m);
if (OK != lock_send(m.m_source, &m))
kprintf("Warning, CLOCK couldn't reply to %d.\n", m.m_source);
}
}
}
@ -155,9 +156,10 @@ message *m_ptr; /* pointer to request message */
TMR_NEVER : clock_timers->tmr_exp_time;
}
/* If a user process has been running too long, pick another one. */
if (--sched_ticks == 0) {
if (bill_ptr == prev_ptr) lock_sched(); /* process has run too long */
/* If a process has been running too long, pick another one. */
if (--sched_ticks <= 0) {
if (bill_ptr == prev_ptr)
lock_sched(PPRI_USER); /* process has run too long */
sched_ticks = SCHED_RATE; /* reset quantum */
prev_ptr = bill_ptr; /* new previous process */
}
@ -249,7 +251,7 @@ irq_hook_t *hook;
m.NOTIFY_TYPE = HARD_INT;
lock_notify(CLOCK, &m);
}
else if (--sched_ticks == 0) {
else if (--sched_ticks <= 0) {
sched_ticks = SCHED_RATE; /* reset the quantum */
prev_ptr = bill_ptr; /* new previous process */
}

View file

@ -57,7 +57,7 @@ unsigned vec_nr;
if (k_reenter == 0 && ! istaskp(saved_proc)) {
unlock(); /* this is protected like sys_call() */
cause_sig(proc_number(saved_proc), ep->signum);
cause_sig(proc_nr(saved_proc), ep->signum);
return;
}
@ -66,7 +66,7 @@ unsigned vec_nr;
kprintf("\nIntel-reserved exception %d\n", vec_nr);
else
kprintf("\n%s\n", karg(ep->msg));
kprintf("process number %d, ", proc_number(saved_proc));
kprintf("process number %d, ", proc_nr(saved_proc));
kprintf("pc = %d:", (unsigned) saved_proc->p_reg.cs);
kprintf("0x%x\n", (unsigned) saved_proc->p_reg.pc);

View file

@ -55,7 +55,7 @@ PUBLIC void main()
intr_init(1);
/* Clear the process table. Anounce each slot as empty and
* set up mappings for proc_addr() and proc_number() macros.
* set up mappings for proc_addr() and proc_nr() macros.
*/
for (rp = BEG_PROC_ADDR, i = -NR_TASKS; rp < END_PROC_ADDR; ++rp, ++i) {
rp->p_type = P_NONE; /* isemptyp() tests on this */
@ -146,7 +146,6 @@ PUBLIC void main()
#if ENABLE_K_DEBUGGING
rp->p_ready = 0;
#endif
if (rp->p_nr != HARDWARE) lock_ready(rp);
rp->p_flags = 0;
@ -271,7 +270,6 @@ timer_t *tp;
*/
static int level = P_SERVER; /* start at the highest level */
static struct proc *p = NIL_PROC; /* next process to stop */
static char *types[] = {"task","system","driver","server","user"};
static message m;
/* See if the last process' shutdown was successful. Else, force exit. */
@ -291,13 +289,11 @@ timer_t *tp;
if (p == NIL_PROC) p = BEG_PROC_ADDR;
while (TRUE) {
if (isalivep(p) && p->p_type == level) { /* found a process */
int w;
kprintf("- Stopping %s ", karg(p->p_name));
kprintf("%s ... ", karg(types[p->p_type]));
kprintf("- Stopping %s ... ", karg(p->p_name));
shutdown_process = p; /* directly continue if exited */
m.NOTIFY_TYPE = HARD_STOP;
m.NOTIFY_ARG = tmr_arg(tp)->ta_int; /* how */
lock_notify(proc_number(p), &m);
lock_notify(proc_nr(p), &m);
set_timer(tp, get_uptime()+STOP_TICKS, stop_sequence);
return; /* allow the process to shut down */
}

View file

@ -104,7 +104,6 @@ bit_t nr_bits;
return(bit_nr);
}
kprintf("Warning, all %d bits in map busy\n", nr_bits);
return(-1);
}

View file

@ -1,3 +1,4 @@
#define NEW_SCHED_Q 1
/* This file contains essentially all of the process and message handling.
* It has one main entry point from the outside:
*
@ -13,6 +14,7 @@
* lock_pick_proc: pick a process to run (used by system initialization)
*
* Changes:
* May 26, 2005 optimized message passing functions (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 rewrite of sys_call() (Jorrit N. Herder)
@ -33,21 +35,22 @@
* interrupts to prevent race conditions.
*/
FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dst,
message *m_ptr, int may_block) );
message *m_ptr, int flags) );
FORWARD _PROTOTYPE( int mini_rec, (struct proc *caller_ptr, int src,
message *m_ptr, int may_block) );
message *m_ptr, int flags) );
FORWARD _PROTOTYPE( int mini_notify, (struct proc *caller_ptr, int dst,
message *m_ptr ) );
FORWARD _PROTOTYPE( void ready, (struct proc *rp) );
FORWARD _PROTOTYPE( void sched, (void) );
FORWARD _PROTOTYPE( void sched, (int queue) );
FORWARD _PROTOTYPE( void unready, (struct proc *rp) );
FORWARD _PROTOTYPE( void pick_proc, (void) );
#if (CHIP == M68000)
FORWARD _PROTOTYPE( void cp_mess, (int src, struct proc *src_p, message *src_m,
struct proc *dst_p, message *dst_m) );
#endif
#define BuildMess(m,n) \
(m).NOTIFY_SOURCE = (n)->n_source, \
(m).NOTIFY_TYPE = (n)->n_type, \
(m).NOTIFY_FLAGS = (n)->n_flags, \
(m).NOTIFY_ARG = (n)->n_arg;
#if (CHIP == INTEL)
#define CopyMess(s,sp,sm,dp,dm) \
@ -80,61 +83,77 @@ message *m_ptr; /* pointer to message in the caller's space */
*/
register struct proc *caller_ptr = proc_ptr; /* get pointer to caller */
int function = call_nr & SYSCALL_FUNC; /* get system call function */
int may_block = ! (call_nr & NON_BLOCKING); /* (dis)allow blocking? */
int flags = call_nr & SYSCALL_FLAGS; /* get flags */
int mask_entry; /* bit to check in send mask */
int result; /* the system call's result */
vir_bytes vb; /* message buffer pointer as vir_bytes */
vir_clicks vlo, vhi; /* virtual clicks containing message to send */
/* 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
* may only use sendrec() to protect the process manager and file system.
*/
#if DEAD_CODE
if ((iskernel(src_dst) || isuserp(caller_ptr)) && function != BOTH) {
#else
if (iskernel(src_dst) && function != BOTH) {
#endif
result = ECALLDENIED; /* BOTH was required */
}
if (iskernel(src_dst) && function != BOTH)
return(ECALLDENIED); /* BOTH was required */
/* Verify that requested source and/ or destination is a valid process. */
else if (! isoksrc_dst(src_dst)) {
result = EBADSRCDST; /* invalid process number */
}
if (! isoksrc_dst(src_dst))
return(EBADSRCDST);
/* Check validity of message pointer. */
vb = (vir_bytes) m_ptr;
vlo = vb >> CLICK_SHIFT; /* vir click for bottom of message */
vhi = (vb + MESS_SIZE - 1) >> CLICK_SHIFT; /* vir click for top of msg */
#if ALLOW_GAP_MESSAGES
/* This check allows a message to be anywhere in data or stack or gap.
* It will have to be made more elaborate later for machines which
* don't have the gap mapped.
*/
if (vlo < caller_ptr->p_memmap[D].mem_vir || vlo > vhi ||
vhi >= caller_ptr->p_memmap[S].mem_vir + caller_ptr->p_memmap[S].mem_len)
return(EFAULT);
#else
/* Check for messages wrapping around top of memory or outside data seg. */
if (vhi < vlo ||
vhi - caller_ptr->p_memmap[D].mem_vir >= caller_ptr->p_memmap[D].mem_len)
return(EFAULT);
#endif
/* 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.
* Receiving is straightforward. Sending requires to check caller's send
* mask and whether the destination is alive.
*/
else {
switch(function) {
case SEND:
/* fall through, SEND is done in BOTH */
case BOTH:
if (! isalive(src_dst)) {
result = EDEADDST; /* cannot send to the dead */
break;
}
mask_entry = isuser(src_dst) ? USER_PROC_NR : src_dst;
if (! isallowed(caller_ptr->p_sendmask, mask_entry)) {
kprintf("WARNING: sys_call denied %d ", caller_ptr->p_nr);
kprintf("sending to %d\n", proc_addr(src_dst)->p_nr);
result = ECALLDENIED; /* call denied by send mask */
break;
}
result = mini_send(caller_ptr, src_dst, m_ptr, may_block);
if (function == SEND || result != OK) {
break; /* done, or SEND failed */
} /* fall through for BOTH */
case RECEIVE:
result = mini_rec(caller_ptr, src_dst, m_ptr, may_block);
switch(function) {
case SEND:
/* fall through, SEND is done in BOTH */
case BOTH:
if (! isalive(src_dst)) {
result = EDEADDST; /* cannot send to the dead */
break;
case NOTIFY:
result = mini_notify(caller_ptr, src_dst, m_ptr);
break;
default:
result = EBADCALL; /* illegal system call */
}
mask_entry = isuser(src_dst) ? USER_PROC_NR : src_dst;
if (! isallowed(caller_ptr->p_sendmask, mask_entry)) {
kprintf("WARNING: sys_call denied %d ", caller_ptr->p_nr);
kprintf("sending to %d\n", proc_addr(src_dst)->p_nr);
result = ECALLDENIED; /* call denied by send mask */
break;
}
result = mini_send(caller_ptr, src_dst, m_ptr,
! (flags & NON_BLOCKING) );
if (function == SEND || result != OK) {
break; /* done, or SEND failed */
} /* fall through for BOTH */
case RECEIVE:
result = mini_rec(caller_ptr, src_dst, m_ptr,
! (flags & NON_BLOCKING) );
break;
case NOTIFY:
result = mini_notify(caller_ptr, src_dst, m_ptr);
break;
default:
result = EBADCALL; /* illegal system call */
}
/* Now, return the result of the system call to the caller. */
@ -145,44 +164,28 @@ message *m_ptr; /* pointer to message in the caller's space */
/*===========================================================================*
* mini_send *
*===========================================================================*/
PRIVATE int mini_send(caller_ptr, dst, m_ptr, may_block)
PRIVATE int mini_send(caller_ptr, dst, m_ptr, flags)
register struct proc *caller_ptr; /* who is trying to send a message? */
int dst; /* to whom is message being sent? */
message *m_ptr; /* pointer to message buffer */
int may_block; /* (dis)allow blocking */
int flags; /* system call flags */
{
/* Send a message from 'caller_ptr' to 'dst'. If 'dst' is blocked waiting
* for this message, copy the message to it and unblock 'dst'. If 'dst' is
* not waiting at all, or is waiting for another source, queue 'caller_ptr'.
*/
register struct proc *dst_ptr, *next_ptr;
vir_bytes vb; /* message buffer pointer as vir_bytes */
vir_clicks vlo, vhi; /* virtual clicks containing message to send */
register struct proc *dst_ptr;
#if DEAD_CODE
register struct proc *next_ptr;
#endif
register struct proc *xp;
register struct proc **xpp;
dst_ptr = proc_addr(dst); /* pointer to destination's proc entry */
#if ALLOW_GAP_MESSAGES
/* This check allows a message to be anywhere in data or stack or gap.
* It will have to be made more elaborate later for machines which
* don't have the gap mapped.
/* Check for deadlock by 'caller_ptr' and 'dst' sending to each other.
* This check is rare, so overhead is acceptable.
*/
vb = (vir_bytes) m_ptr;
vlo = vb >> CLICK_SHIFT; /* vir click for bottom of message */
vhi = (vb + MESS_SIZE - 1) >> CLICK_SHIFT; /* vir click for top of msg */
if (vlo < caller_ptr->p_memmap[D].mem_vir || vlo > vhi ||
vhi >= caller_ptr->p_memmap[S].mem_vir + caller_ptr->p_memmap[S].mem_len)
return(EFAULT);
#else
/* Check for messages wrapping around top of memory or outside data seg. */
vb = (vir_bytes) m_ptr;
vlo = vb >> CLICK_SHIFT; /* vir click for bottom of message */
vhi = (vb + MESS_SIZE - 1) >> CLICK_SHIFT; /* vir click for top of msg */
if (vhi < vlo ||
vhi - caller_ptr->p_memmap[D].mem_vir >= caller_ptr->p_memmap[D].mem_len)
return(EFAULT);
#endif
/* Check for deadlock by 'caller_ptr' and 'dst' sending to each other. */
if (dst_ptr->p_flags & SENDING) {
next_ptr = proc_addr(dst_ptr->p_sendto);
while (TRUE) {
@ -194,16 +197,17 @@ int may_block; /* (dis)allow blocking */
}
}
/* Check to see if 'dst' is blocked waiting for this message. */
/* Check if 'dst' is blocked waiting for this message. The destination's
* SENDING flag may be set when BOTH couldn't send. Await a pure RECEIVE.
*/
if ( (dst_ptr->p_flags & (RECEIVING | SENDING)) == RECEIVING &&
(dst_ptr->p_getfrom == ANY ||
dst_ptr->p_getfrom == proc_number(caller_ptr))) {
(dst_ptr->p_getfrom == ANY || dst_ptr->p_getfrom == caller_ptr->p_nr)) {
/* Destination is indeed waiting for this message. */
CopyMess(proc_number(caller_ptr), caller_ptr, m_ptr, dst_ptr,
CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, dst_ptr,
dst_ptr->p_messbuf);
dst_ptr->p_flags &= ~RECEIVING; /* deblock destination */
if (dst_ptr->p_flags == 0) ready(dst_ptr);
} else if (may_block) {
} else if (flags) {
/* Destination is not waiting. Block and queue caller. */
caller_ptr->p_messbuf = m_ptr;
if (caller_ptr->p_flags == 0) unready(caller_ptr);
@ -211,14 +215,20 @@ int may_block; /* (dis)allow blocking */
caller_ptr->p_sendto = dst;
/* Process is now blocked. Put in on the destination's queue. */
#if DEAD_CODE
if ( (next_ptr = dst_ptr->p_caller_q) == NIL_PROC)
dst_ptr->p_caller_q = caller_ptr;
else {
while (next_ptr->p_sendlink != NIL_PROC)
next_ptr = next_ptr->p_sendlink;
next_ptr->p_sendlink = caller_ptr;
while (next_ptr->p_q_link != NIL_PROC)
next_ptr = next_ptr->p_q_link;
next_ptr->p_q_link = caller_ptr;
}
caller_ptr->p_sendlink = NIL_PROC;
#else
xpp = &dst_ptr->p_caller_q;
while (*xpp != NIL_PROC) xpp = &(*xpp)->p_q_link;
*xpp = caller_ptr;
#endif
caller_ptr->p_q_link = NIL_PROC;
} else {
return(ENOTREADY);
}
@ -228,69 +238,89 @@ int may_block; /* (dis)allow blocking */
/*===========================================================================*
* mini_rec *
*===========================================================================*/
PRIVATE int mini_rec(caller_ptr, src, m_ptr, may_block)
PRIVATE int mini_rec(caller_ptr, src, m_ptr, flags)
register struct proc *caller_ptr; /* process trying to get message */
int src; /* which message source is wanted */
message *m_ptr; /* pointer to message buffer */
int may_block; /* (dis)allow blocking */
int flags; /* system call flags */
{
/* A process or task wants to get a message. If one is already queued,
* acquire it and deblock the sender. If no message from the desired source
* is available, block the caller.
*/
#if DEAD_CODE
register struct proc *sender_ptr;
register struct proc *previous_ptr;
#endif
register struct proc **xpp;
register struct notification **ntf_q_pp;
message m;
int bit_nr, i;
int bit_nr;
/* Check to see if a message from desired source is already available. */
/* Check to see if a message from desired source is already available.
* The caller's SENDING flag may be set if BOTH couldn't send. If it is
* set, the process should be blocked.
*/
if (!(caller_ptr->p_flags & SENDING)) {
/* Check caller queue. */
/* Check caller queue. Use pointer pointers to keep code simple. */
#if DEAD_CODE /* to hairy, unreadable */
for (sender_ptr = caller_ptr->p_caller_q; sender_ptr != NIL_PROC;
previous_ptr = sender_ptr, sender_ptr = sender_ptr->p_sendlink) {
if (src == ANY || src == proc_number(sender_ptr)) {
previous_ptr = sender_ptr, sender_ptr = sender_ptr->p_q_link) {
if (src == ANY || src == proc_nr(sender_ptr)) {
/* An acceptable message has been found. */
CopyMess(proc_number(sender_ptr), sender_ptr,
CopyMess(sender_ptr->p_nr, sender_ptr,
sender_ptr->p_messbuf, caller_ptr, m_ptr);
if (sender_ptr == caller_ptr->p_caller_q)
caller_ptr->p_caller_q = sender_ptr->p_sendlink;
caller_ptr->p_caller_q = sender_ptr->p_q_link;
else
previous_ptr->p_sendlink = sender_ptr->p_sendlink;
previous_ptr->p_q_link = sender_ptr->p_q_link;
if ((sender_ptr->p_flags &= ~SENDING) == 0)
ready(sender_ptr); /* deblock sender */
return(OK);
}
}
#else
xpp = &caller_ptr->p_caller_q;
while (*xpp != NIL_PROC) {
if (src == ANY || src == proc_nr(*xpp)) {
/* An acceptable source has been found. Copy the message to the
* 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);
if (((*xpp)->p_flags &= ~SENDING) == 0) ready(*xpp);
*xpp = (*xpp)->p_q_link; /* remove from queue */
return(OK);
}
xpp = &(*xpp)->p_q_link; /* proceed to next */
}
#endif
/* Check if there are pending notifications. */
ntf_q_pp = &caller_ptr->p_ntf_q; /* get pointer pointer */
while (*ntf_q_pp) {
while (*ntf_q_pp != NULL) {
if (src == ANY || src == (*ntf_q_pp)->n_source) {
/* Found notification. Assemble and copy message. */
m.NOTIFY_SOURCE = (*ntf_q_pp)->n_source;
m.NOTIFY_TYPE = (*ntf_q_pp)->n_type;
m.NOTIFY_FLAGS = (*ntf_q_pp)->n_flags;
m.NOTIFY_ARG = (*ntf_q_pp)->n_arg;
BuildMess(m, *ntf_q_pp);
CopyMess((*ntf_q_pp)->n_source, proc_addr(HARDWARE), &m,
caller_ptr, m_ptr);
/* Remove notification from queue and return. */
/* Remove notification from queue and bit map. */
bit_nr = ((long)(*ntf_q_pp) - (long) &notify_buffer[0]) /
sizeof(struct notification);
*ntf_q_pp = (*ntf_q_pp)->n_next;/* remove from queue */
free_bit(bit_nr, notify_bitmap, NR_NOTIFY_BUFS);
kinfo.nr_ntf_pending --;
return(OK); /* report success */
}
ntf_q_pp = &(*ntf_q_pp)->n_next; /* proceed to next */
}
}
/* No suitable message is available. Block the process trying to receive,
* unless this is not allowed by the system call.
/* No suitable message is available or the caller couldn't send in BOTH.
* Block the process trying to receive, unless the flags tell otherwise.
*/
if (may_block) {
if (flags) {
caller_ptr->p_getfrom = src;
caller_ptr->p_messbuf = m_ptr;
if (caller_ptr->p_flags == 0) unready(caller_ptr);
@ -316,51 +346,53 @@ message *m_ptr; /* pointer to message buffer */
int ntf_index;
message ntf_mess;
/* Check to see if target is blocked waiting for this message. */
/* Check to see if target is blocked waiting for this message. A process
* can be both sending and receiving during a BOTH system call.
*/
if ( (dst_ptr->p_flags & (RECEIVING | SENDING)) == RECEIVING &&
(dst_ptr->p_getfrom == ANY ||
dst_ptr->p_getfrom == proc_number(caller_ptr))) {
(dst_ptr->p_getfrom == ANY || dst_ptr->p_getfrom == caller_ptr->p_nr)) {
/* Destination is indeed waiting for this message. */
CopyMess(proc_number(caller_ptr), caller_ptr, m_ptr, dst_ptr,
dst_ptr->p_messbuf);
CopyMess(proc_nr(caller_ptr), caller_ptr, m_ptr,
dst_ptr, dst_ptr->p_messbuf);
dst_ptr->p_flags &= ~RECEIVING; /* deblock destination */
if (dst_ptr->p_flags == 0) ready(dst_ptr);
}
/* Destination is not ready. Add the notification to the pending queue. */
else {
/* Get pointer to notification message. */
if (! istaskp(caller_ptr)) {
CopyMess(proc_number(caller_ptr), caller_ptr, m_ptr,
/* Get pointer to notification message. Don't copy for kernel. */
if (! iskernelp(caller_ptr)) {
CopyMess(proc_nr(caller_ptr), caller_ptr, m_ptr,
proc_addr(HARDWARE), &ntf_mess);
m_ptr = &ntf_mess;
}
/* Enqueue the message. Existing notifications are overwritten with
* the newer one. New notifications are added to the end of the list.
/* Enqueue the message. Existing notifications with the same source
* and type are overwritten with newer ones. New notifications that
* are not yet on the list are added to the end.
*/
ntf_q_pp = &dst_ptr->p_ntf_q;
while (*ntf_q_pp) {
while (*ntf_q_pp != NULL) {
/* Replace notifications with same source and type. */
if ((*ntf_q_pp)->n_type == m_ptr->m_type &&
(*ntf_q_pp)->n_source == m_ptr->m_source) {
if ((*ntf_q_pp)->n_type == m_ptr->NOTIFY_TYPE &&
(*ntf_q_pp)->n_source == proc_nr(caller_ptr)) {
(*ntf_q_pp)->n_flags = m_ptr->NOTIFY_FLAGS;
(*ntf_q_pp)->n_arg = m_ptr->NOTIFY_ARG;
break;
return(OK);
}
return(OK);
ntf_q_pp = &(*ntf_q_pp)->n_next;
}
/* Add to end of queue. Get a free notification buffer. */
if ((ntf_index = alloc_bit(notify_bitmap, NR_NOTIFY_BUFS)) < 0)
return(ENOSPC); /* should be atomic! */
kinfo.nr_ntf_pending ++;
if ((ntf_index = alloc_bit(notify_bitmap, NR_NOTIFY_BUFS)) < 0)
return(ENOSPC);
ntf_p = &notify_buffer[ntf_index];
ntf_p->n_source = proc_number(caller_ptr);
ntf_p->n_source = proc_nr(caller_ptr);
ntf_p->n_type = m_ptr->NOTIFY_TYPE;
ntf_p->n_flags = m_ptr->NOTIFY_FLAGS;
ntf_p->n_arg = m_ptr->NOTIFY_ARG;
*ntf_q_pp = ntf_p;
*ntf_q_pp = ntf_p; /* add to end of queue */
ntf_p->n_next = NULL; /* mark new end of queue */
}
return(OK);
}
@ -374,16 +406,13 @@ message *m_ptr; /* pointer to message buffer */
{
/* Safe gateway to mini_notify() for tasks and interrupt handlers. This
* function checks if it is called from an interrupt handler and makes sure
* that the correct message source is put on the notification. All kernel
* generated notifications share the same pseudo-process number, to prevent
* conflicts with SENDREC calls to the kernel task.
* that the correct message source is put on the notification.
*/
int result;
struct proc *caller_ptr;
lock();
caller_ptr = (k_reenter >= 0 || istaskp(proc_ptr)) ?
proc_addr(KERNEL) : proc_ptr;
caller_ptr = (k_reenter >= 0) ? proc_addr(HARDWARE) : proc_ptr;
result = mini_notify(caller_ptr, dst, m_ptr);
unlock();
return(result);
@ -423,6 +452,7 @@ register struct proc *rp; /* this process is now runnable */
{
/* Add 'rp' to one of the queues of runnable processes. */
register int q = rp->p_priority; /* scheduling queue to use */
register struct proc **xpp; /* iterate over queue */
#if ENABLE_K_DEBUGGING
if(rp->p_ready) {
@ -435,6 +465,18 @@ register struct proc *rp; /* this process is now runnable */
* user processes are added in front of the queue, because this is a bit
* fairer to I/O bound processes.
*/
#if NEW_SCHED_Q
if (isuserp(rp)) { /* add to front of queue */
rp->p_nextready = rdy_head[q]; /* chain current front */
rdy_head[q] = rp; /* ready process becomes front */
}
else { /* add to end of queue */
xpp = &rdy_head[q]; /* find pointer to end of queue */
while (*xpp != NIL_PROC) xpp = &(*xpp)->p_nextready;
*xpp = rp; /* replace end with ready process */
rp->p_nextready = NIL_PROC; /* mark end of queue */
}
#else
if (isuserp(rp)) { /* add to front of queue */
if (rdy_head[q] == NIL_PROC)
rdy_tail[q] = rp;
@ -449,6 +491,7 @@ register struct proc *rp; /* this process is now runnable */
rdy_tail[q] = rp;
rp->p_nextready = NIL_PROC;
}
#endif
/* Run 'rp' next if it has a higher priority than 'proc_ptr' or 'next_ptr'.
* This actually should be done via pick_proc(), but the message passing
@ -456,10 +499,6 @@ register struct proc *rp; /* this process is now runnable */
*/
if (next_ptr && next_ptr->p_priority > rp->p_priority) next_ptr = rp;
else if (proc_ptr->p_priority > rp->p_priority) next_ptr = rp;
#if DEAD_CODE
if (rp->p_priority < proc_ptr->p_priority) proc_ptr = rp;
#endif
}
/*===========================================================================*
@ -470,9 +509,13 @@ register struct proc *rp; /* this process is no longer runnable */
{
/* A process has blocked. See ready for a description of the queues. */
register struct proc *xp;
register struct proc **qtail; /* queue's rdy_tail */
register int q = rp->p_priority; /* queue to use */
#if NEW_SCHED_Q
register struct proc **xpp; /* iterate over queue */
#else
register struct proc **qtail; /* queue's rdy_tail */
register struct proc *xp;
#endif
#if ENABLE_K_DEBUGGING
if(!rp->p_ready) {
@ -484,13 +527,25 @@ register struct proc *rp; /* this process is no longer runnable */
/* Side-effect for tasks: check if the task's stack still is ok? */
if (istaskp(rp)) {
if (*rp->p_stguard != STACK_GUARD)
panic("stack overrun by task", proc_number(rp));
panic("stack overrun by task", proc_nr(rp));
}
/* 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.
*/
#if NEW_SCHED_Q
xpp = &rdy_head[q];
while (*xpp != NIL_PROC) { /* check entire queue */
if (*xpp == rp) { /* lookup unready process */
*xpp = (*xpp)->p_nextready; /* replace it with next */
if (rp == proc_ptr || rp == next_ptr) /* current process removed */
pick_proc(); /* pick new process to run */
break;
}
xpp = &(*xpp)->p_nextready; /* proceed to next */
}
#else
if ( (xp = rdy_head[q]) != NIL_PROC) { /* ready queue is empty */
if (xp == rp) { /* check head of queue */
rdy_head[q] = xp->p_nextready; /* new head of queue */
@ -508,25 +563,41 @@ register struct proc *rp; /* this process is no longer runnable */
rdy_tail[q] = xp;
}
}
#endif
}
/*===========================================================================*
* sched *
*===========================================================================*/
PRIVATE void sched()
PRIVATE void sched(queue)
int queue;
{
/* The current process has run too long. If another low priority (user)
* process is runnable, put the current process on the end of the user queue,
* possibly promoting another user to head of the queue.
*/
if (rdy_head[PPRI_USER] == NIL_PROC) return;
register struct proc **xpp;
register struct proc *xp;
if (rdy_head[queue] == NIL_PROC) return;
/* One or more user processes queued. */
rdy_tail[PPRI_USER]->p_nextready = rdy_head[PPRI_USER];
rdy_tail[PPRI_USER] = rdy_head[PPRI_USER];
rdy_head[PPRI_USER] = rdy_head[PPRI_USER]->p_nextready;
rdy_tail[PPRI_USER]->p_nextready = NIL_PROC;
#if NEW_SCHED_Q
xp = rdy_head[queue]; /* save expired process */
rdy_head[queue] = xp->p_nextready; /* advance to next process */
xpp = &rdy_head[queue]; /* find end of queue */
while (*xpp != NIL_PROC) xpp = &(*xpp)->p_nextready;
*xpp = xp; /* add expired to end */
xp->p_nextready = NIL_PROC; /* mark end of queue */
#else
rdy_tail[queue]->p_nextready = rdy_head[queue];
rdy_tail[queue] = rdy_head[queue];
rdy_head[queue] = rdy_head[queue]->p_nextready;
rdy_tail[queue]->p_nextready = NIL_PROC;
#endif
pick_proc();
}
@ -585,11 +656,12 @@ struct proc *rp; /* this process is no longer runnable */
/*==========================================================================*
* lock_sched *
*==========================================================================*/
PUBLIC void lock_sched()
PUBLIC void lock_sched(queue)
int queue;
{
/* Safe gateway to sched() for tasks. */
lock();
sched();
sched(queue);
unlock();
}

View file

@ -35,7 +35,7 @@ struct proc {
struct mem_map p_memmap[NR_LOCAL_SEGS]; /* local memory map (T, D, S) */
struct far_mem p_farmem[NR_REMOTE_SEGS]; /* remote memory map */
short p_flags; /* SENDING, RECEIVING, etc. */
char p_flags; /* SENDING, RECEIVING, etc. */
char p_type; /* task, system, driver, server, user, idle */
char p_priority; /* scheduling priority */
@ -51,7 +51,7 @@ struct proc {
struct proc *p_nextready; /* pointer to next ready process */
struct notification *p_ntf_q; /* queue of pending notifications */
struct proc *p_caller_q; /* head of list of procs wishing to send */
struct proc *p_sendlink; /* link to next proc wishing to send */
struct proc *p_q_link; /* link to next proc wishing to send */
message *p_messbuf; /* pointer to message buffer */
proc_nr_t p_getfrom; /* from whom does process want to receive? */
proc_nr_t p_sendto; /* to whom does process want to send? */
@ -74,9 +74,9 @@ struct proc {
#define NO_MAP 0x01 /* keeps unmapped forked child from running */
#define SENDING 0x02 /* set when process blocked trying to send */
#define RECEIVING 0x04 /* set when process blocked trying to recv */
#define PENDING 0x08 /* set when inform() of signal pending */
#define SIG_PENDING 0x10 /* keeps to-be-signalled proc from running */
#define P_STOP 0x20 /* set when process is being traced */
#define PENDING 0x10 /* set when inform() of signal pending */
#define SIG_PENDING 0x20 /* keeps to-be-signalled proc from running */
#define P_STOP 0x40 /* set when process is being traced */
/* Values for p_type. Non-negative values represent active process types.
* Process types are important to model inter-process relationships. When
@ -120,9 +120,6 @@ struct proc {
#define isalive(n) (proc_addr(n)->p_type > P_NONE)
#define isalivep(p) ((p)->p_type > P_NONE)
#define isrxhardware(n) ((n) == ANY || (n) == HARDWARE)
#define iskernel(n) ((n) == CLOCK || (n) == SYSTASK)
#define issysentn(n) ((n) == FS_PROC_NR || (n) == PM_PROC_NR)
#define issysentp(p) (issysentn((p)->p_nr))
#define isreservedp(p) ((p)->p_type == P_RESERVED)
#define isemptyp(p) ((p)->p_type == P_NONE)
#define istaskp(p) ((p)->p_type == P_TASK)
@ -131,12 +128,11 @@ struct proc {
#define isuserp(p) ((p)->p_type == P_USER)
#define isuser(n) (proc_addr(n)->p_type == P_USER)
#define isidlep(p) ((p)->p_type == P_IDLE)
#define proc_addr(n) (pproc_addr + NR_TASKS)[(n)]
#define cproc_addr(n) (&(proc + NR_TASKS)[(n)])
#define proc_number(p) ((p)->p_nr)
#define proc_vir2phys(p, vir) \
(((phys_bytes)(p)->p_map[D].mem_phys << CLICK_SHIFT) \
+ (vir_bytes) (vir))
#define proc_addr(n) (pproc_addr + NR_TASKS)[(n)]
#define proc_nr(p) ((p)->p_nr)
#define iskernelp(p) ((p)->p_nr < 0)
#define iskernel(n) ((n) == CLOCK || (n) == SYSTASK)
/* The process table and pointers to process table slots. The pointers allow
* faster access because now a process entry can be found by indexing the

View file

@ -48,7 +48,7 @@ _PROTOTYPE( int lock_notify, (int dst, message *m_ptr) );
_PROTOTYPE( int lock_send, (int dst, message *m_ptr) );
_PROTOTYPE( void lock_pick_proc, (void) );
_PROTOTYPE( void lock_ready, (struct proc *rp) );
_PROTOTYPE( void lock_sched, (void) );
_PROTOTYPE( void lock_sched, (int queue) );
_PROTOTYPE( void lock_unready, (struct proc *rp) );
/* start.c */

View file

@ -79,7 +79,7 @@ PUBLIC void sys_task()
if ((unsigned) m.m_type < NR_SYS_CALLS) {
result = (*call_vec[m.m_type])(&m); /* do system call */
} else {
kprintf("SYS task got illegal request from %d.\n", m.m_source);
kprintf("Warning, illegal SYSTASK request from %d.\n", m.m_source);
result = EBADREQUEST; /* illegal message type */
}
@ -89,7 +89,8 @@ PUBLIC void sys_task()
*/
if (result != EDONTREPLY) {
m.m_type = result; /* report status of call */
lock_send(m.m_source, &m);
if (OK != lock_send(m.m_source, &m))
kprintf("Warning, SYSTASK couldn't reply to %d\n", m.m_source);
}
}
}
@ -177,7 +178,11 @@ PUBLIC void clear_proc(proc_nr)
int proc_nr; /* slot of process to clean up */
{
register struct proc *rp, *rc;
#if DEAD_CODE
struct proc *np, *xp;
#else
register struct proc **xpp; /* iterate over caller queue */
#endif
/* Get a pointer to the process that exited. */
rc = proc_addr(proc_nr);
@ -199,22 +204,34 @@ int proc_nr; /* slot of process to clean up */
/* Check all proc slots to see if the exiting process is queued. */
for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
if (rp->p_caller_q == NIL_PROC) continue;
#if DEAD_CODE
if (rp->p_caller_q == rc) {
/* Exiting process is on front of this queue. */
rp->p_caller_q = rc->p_sendlink;
rp->p_caller_q = rc->p_q_link;
break;
} else {
/* See if exiting process is in middle of queue. */
np = rp->p_caller_q;
while ( ( xp = np->p_sendlink) != NIL_PROC) {
while ( ( xp = np->p_q_link) != NIL_PROC) {
if (xp == rc) {
np->p_sendlink = xp->p_sendlink;
np->p_q_link = xp->p_q_link;
break;
} else {
np = xp;
}
}
}
#else
/* Make sure that the exiting process is not on the queue. */
xpp = &rp->p_caller_q;
while (*xpp != NIL_PROC) { /* check entire queue */
if (*xpp == rc) { /* process is on the queue */
*xpp = (*xpp)->p_q_link; /* replace by next process */
break;
}
xpp = &(*xpp)->p_q_link; /* proceed to next queued */
}
#endif
}
}

View file

@ -165,7 +165,6 @@ timer_t *tp;
* process given with a SYN_ALARM message.
*/
message m;
m.NOTIFY_SOURCE = SYSTASK;
m.NOTIFY_TYPE = SYN_ALARM;
m.NOTIFY_ARG = get_uptime();
m.NOTIFY_FLAGS = 0;

View file

@ -35,7 +35,7 @@ message *m_ptr; /* pointer to request message */
/* Find the next process with pending signals. */
for (rp = BEG_USER_ADDR; rp < END_PROC_ADDR; rp++) {
if (rp->p_flags & PENDING) {
m_ptr->SIG_PROC = proc_number(rp);
m_ptr->SIG_PROC = rp->p_nr;
m_ptr->SIG_MAP = rp->p_pending;
sigemptyset(&rp->p_pending); /* ball is in PM's court */
rp->p_flags &= ~PENDING; /* blocked by SIG_PENDING */

View file

@ -67,11 +67,11 @@ PUBLIC struct system_image image[] = {
{ HARDWARE, 0, P_TASK, PPRI_TASK, HARDWARE_STACK,HARDWARE_SENDMASK,"HARDWAR" },
{ PM_PROC_NR, 0, P_SERVER, PPRI_NORMAL, 0, PM_SENDMASK, "PM" },
{ FS_PROC_NR, 0, P_SERVER, PPRI_NORMAL, 0, FS_SENDMASK, "FS" },
{ IS_PROC_NR, 0, P_SYSTEM, PPRI_HIGHER, 0, IS_SENDMASK, "IS" },
{ IS_PROC_NR, 0, P_SYSTEM, PPRI_HIGH, 0, IS_SENDMASK, "IS" },
{ TTY, 0, P_SYSTEM, PPRI_HIGHER, 0, TTY_SENDMASK, "TTY" },
{ MEMORY, 0, P_DRIVER, PPRI_HIGH, 0, MEM_SENDMASK, "MEMORY" },
#if ENABLE_AT_WINI
{ AT_WINI, 0, P_DRIVER, PPRI_HIGHER, 0, AT_SENDMASK, "AT_WINI" },
{ AT_WINI, 0, P_DRIVER, PPRI_HIGH, 0, AT_SENDMASK, "AT_WINI" },
#endif
#if ENABLE_FLOPPY
{ FLOPPY, 0, P_DRIVER, PPRI_HIGH, 0, FLOPPY_SENDMASK, "FLOPPY" },

View file

@ -51,8 +51,13 @@ struct system_image image[IMAGE_SIZE];
*===========================================================================*/
PUBLIC int do_fkey_pressed(message *m)
{
#if DEAD_CODE
if (F1 <= m->FKEY_CODE && m->FKEY_CODE <= F12) {
switch(m->FKEY_CODE) {
#else
if (F1 <= m->NOTIFY_ARG && m->NOTIFY_ARG <= F12) {
switch(m->NOTIFY_ARG) {
#endif
case F1: proctab_dmp(); break;
case F2: memmap_dmp(); break;
case F3: image_dmp(); break;
@ -65,7 +70,12 @@ PUBLIC int do_fkey_pressed(message *m)
case F11: memchunks_dmp(); break;
case F12: sched_dmp(); break;
default:
#if DEAD_CODE
printf("IS: unhandled notification for F%d\n", m->FKEY_NUM);
#else
printf("IS: unhandled notify for F%d (code %d)\n",
m->NOTIFY_ARG, m->NOTIFY_FLAGS);
#endif
}
}
return(EDONTREPLY);
@ -376,7 +386,7 @@ PRIVATE void sendmask_dmp()
printf("\n\n");
printf(" ");
for (j=proc_number(BEG_PROC_ADDR); j< INIT_PROC_NR+1; j++) {
for (j=proc_nr(BEG_PROC_ADDR); j< INIT_PROC_NR+1; j++) {
printf("%3d", j);
}
printf(" *\n");
@ -386,17 +396,17 @@ PRIVATE void sendmask_dmp()
if (++n > 20) break;
printf("%8s ", rp->p_name);
j = proc_number(rp);
j = proc_nr(rp);
switch(rp->p_type) {
case P_IDLE: printf("/%3d/ ", proc_number(rp)); break;
case P_TASK: printf("[%3d] ", proc_number(rp)); break;
case P_SYSTEM: printf("<%3d> ", proc_number(rp)); break;
case P_DRIVER: printf("{%3d} ", proc_number(rp)); break;
case P_SERVER: printf("(%3d) ", proc_number(rp)); break;
default: printf(" %3d ", proc_number(rp));
case P_IDLE: printf("/%3d/ ", proc_nr(rp)); break;
case P_TASK: printf("[%3d] ", proc_nr(rp)); break;
case P_SYSTEM: printf("<%3d> ", proc_nr(rp)); break;
case P_DRIVER: printf("{%3d} ", proc_nr(rp)); break;
case P_SERVER: printf("(%3d) ", proc_nr(rp)); break;
default: printf(" %3d ", proc_nr(rp));
}
for (j=proc_number(BEG_PROC_ADDR); j<INIT_PROC_NR+2; j++) {
for (j=proc_nr(BEG_PROC_ADDR); j<INIT_PROC_NR+2; j++) {
if (isallowed(rp->p_sendmask, j)) printf(" 1 ");
else printf(" 0 ");
}
@ -438,12 +448,12 @@ PRIVATE void proctab_dmp()
size = rp->p_memmap[T].mem_len
+ ((rp->p_memmap[S].mem_phys + rp->p_memmap[S].mem_len) - data);
switch(rp->p_type) {
case P_IDLE: printf("/%3d/ ", proc_number(rp)); break;
case P_TASK: printf("[%3d] ", proc_number(rp)); break;
case P_SYSTEM: printf("<%3d> ", proc_number(rp)); break;
case P_DRIVER: printf("{%3d} ", proc_number(rp)); break;
case P_SERVER: printf("(%3d) ", proc_number(rp)); break;
default: printf(" %3d ", proc_number(rp));
case P_IDLE: printf("/%3d/ ", proc_nr(rp)); break;
case P_TASK: printf("[%3d] ", proc_nr(rp)); break;
case P_SYSTEM: printf("<%3d> ", proc_nr(rp)); break;
case P_DRIVER: printf("{%3d} ", proc_nr(rp)); break;
case P_SERVER: printf("(%3d) ", proc_nr(rp)); break;
default: printf(" %3d ", proc_nr(rp));
}
printf("%3u %7lx%7lx %6lu%6lu%6uK%6uK%6uK %3x",
rp->p_priority,
@ -493,7 +503,7 @@ PRIVATE void memmap_dmp()
+ ((rp->p_memmap[S].mem_phys + rp->p_memmap[S].mem_len)
- rp->p_memmap[D].mem_phys);
printf("%3d %-7.7s %4x %4x %4x %4x %4x %4x %4x %4x %4x %5uK\n",
proc_number(rp),
proc_nr(rp),
rp->p_name,
rp->p_memmap[T].mem_vir, rp->p_memmap[T].mem_phys, rp->p_memmap[T].mem_len,
rp->p_memmap[D].mem_vir, rp->p_memmap[D].mem_phys, rp->p_memmap[D].mem_len,