New NOTIFY trap (IPC call) to send queued notification messages.

The call works. Permission check, restriction of outstanding notifications
to be added. Low level code to make it work from within interrupt handlers
will be added as well.
This commit is contained in:
Jorrit Herder 2005-05-19 14:05:51 +00:00
parent 129b82d207
commit 307c825515
13 changed files with 151 additions and 30 deletions

View file

@ -31,9 +31,6 @@ _PROTOTYPE( int _syscall, (int _who, int _syscallnr, message *_msgptr) );
_PROTOTYPE( void _loadname, (const char *_name, message *_msgptr) );
_PROTOTYPE( int _len, (const char *_s) );
_PROTOTYPE( void panic, (const char *_message, int _errnum) );
#if 0
_PROTOTYPE( int _sendrec, (int _src_dest, message *_m_ptr) );
#endif
_PROTOTYPE( void _begsig, (int _dummy) );
#endif /* _LIB_H */

View file

@ -82,7 +82,9 @@
#define NR_NOTIFY_TYPES 5 /* nr of bits in mask */
/* Shorthands for message parameters passed with notifications. */
#define NOTIFY_ARG m2_l1 /* passed for some types */
#define NOTIFY_TYPE m2_i1
#define NOTIFY_FLAGS m2_i2
#define NOTIFY_ARG m2_i3
/*===========================================================================*

View file

@ -143,9 +143,7 @@ _PROTOTYPE( int ttyslot, (void) );
_PROTOTYPE( int fttyslot, (int _fd) );
_PROTOTYPE( char *crypt, (const char *_key, const char *_salt) );
_PROTOTYPE( int getsysinfo, (int who, int what, void *where) );
#if ENABLE_MESSAGE_STATS
_PROTOTYPE( int mstats, (struct message_statentry *ms, int entries, int reset) );
#endif
_PROTOTYPE( int getprocnr, (int *proc_nr) );
#endif
_PROTOTYPE( int setcache, (int kb));

View file

@ -14,7 +14,6 @@
* unhold: repeat all held-up notifications
*
* Changes:
* Nov 05, 2004 removed lock_mini_send() (Jorrit N. Herder)
* Oct 28, 2004 non-blocking SEND and RECEIVE (Jorrit N. Herder)
* Oct 28, 2004 rewrite of sys_call() (Jorrit N. Herder)
* Oct 10, 2004 require BOTH for kernel sys_call() (Jorrit N. Herder)
@ -23,7 +22,6 @@
* Sep 23, 2004 removed PM sig check in mini_rec() (Jorrit N. Herder)
* Aug 19, 2004 generalized ready()/unready() (Jorrit N. Herder)
* Aug 18, 2004 added notify() function (Jorrit N. Herder)
* May 01, 2004 check p_sendmask in mini_send() (Jorrit N. Herder)
*/
#include "kernel.h"
@ -43,6 +41,8 @@ FORWARD _PROTOTYPE( void ready, (struct proc *rp) );
FORWARD _PROTOTYPE( void sched, (void) );
FORWARD _PROTOTYPE( void unready, (struct proc *rp) );
FORWARD _PROTOTYPE( void pick_proc, (void) );
FORWARD _PROTOTYPE( int alloc_notify_buf, (void) );
FORWARD _PROTOTYPE( void free_notify_buf, (int index) );
#if (CHIP == M68000)
FORWARD _PROTOTYPE( void cp_mess, (int src, struct proc *src_p, message *src_m,
@ -66,8 +66,65 @@ FORWARD _PROTOTYPE( void cp_mess, (int src, struct proc *src_p, message *src_m,
#define clear_bit(mask, n) ((mask) &= ~(1 << (n)))
#define isset_bit(mask, n) ((mask) & (1 << (n)))
/* Declare buffer space for notifications. */
PRIVATE struct notification notify_buf[NR_NOTIFY_BUFS];
/* Constants and macros for the notification bit map. */
#define BITCHUNK_BITS (sizeof(bitchunk_t) * CHAR_BIT)
#define BITMAP_CHUNKS ((NR_NOTIFY_BUFS + BITCHUNK_BITS - 1)/BITCHUNK_BITS)
#define MAP_CHUNK(map,bit) (map)[((bit)/BITCHUNK_BITS)]
#define CHUNK_OFFSET(bit) ((bit)%BITCHUNK_BITS))
#define GET_BIT(map,bit) ( MAP_CHUNK(map,bit) & (1 << CHUNK_OFFSET(bit) )
#define SET_BIT(map,bit) ( MAP_CHUNK(map,bit) |= (1 << CHUNK_OFFSET(bit) )
#define UNSET_BIT(map,bit) ( MAP_CHUNK(map,bit) &= ~(1 << CHUNK_OFFSET(bit) )
/* Declare buffer space for notifications and bit map for administration. */
PRIVATE struct notification notify_buffer[NR_NOTIFY_BUFS];
PRIVATE bitchunk_t notify_bitmap[BITMAP_CHUNKS];
/*===========================================================================*
* free_notify_buf *
*===========================================================================*/
PRIVATE void free_notify_buf(buf_index)
int buf_index; /* buffer to release */
{
bitchunk_t *chunk;
if (buf_index >= NR_NOTIFY_BUFS) return;
chunk = &notify_bitmap[(buf_index/BITCHUNK_BITS)];
*chunk &= ~(buf_index % BITCHUNK_BITS);
}
/*===========================================================================*
* alloc_notify_buf *
*===========================================================================*/
PRIVATE int alloc_notify_buf()
{
bitchunk_t *chunk;
int i, bit_nr;
/* Iterate over the words in block. */
for (chunk = &notify_bitmap[0];
chunk < &notify_bitmap[BITMAP_CHUNKS]; chunk++) {
/* Does this chunk contain a free bit? */
if (*chunk == (bitchunk_t) ~0) continue;
/* Get bit number from the start of the bit map. */
for (i = 0; (*chunk & (1 << i)) != 0; ++i) {}
bit_nr = (chunk - &notify_bitmap[0]) * BITCHUNK_BITS + i;
/* Don't allocate bits beyond the end of the map. */
if (bit_nr >= NR_NOTIFY_BUFS) break;
*chunk |= 1 << bit_nr % BITCHUNK_BITS;
kprintf("Allocated bit %d\n", bit_nr);
return(bit_nr);
}
return(-1);
}
/*===========================================================================*
* lock_notify *
@ -307,8 +364,8 @@ int may_block; /* (dis)allow blocking */
caller_ptr->p_sendto= dest;
/* Process is now blocked. Put in on the destination's queue. */
if ( (next_ptr = dest_ptr->p_callerq) == NIL_PROC)
dest_ptr->p_callerq = caller_ptr;
if ( (next_ptr = dest_ptr->p_caller_q) == NIL_PROC)
dest_ptr->p_caller_q = caller_ptr;
else {
while (next_ptr->p_sendlink != NIL_PROC)
next_ptr = next_ptr->p_sendlink;
@ -336,21 +393,22 @@ int may_block; /* (dis)allow blocking */
*/
register struct proc *sender_ptr;
register struct proc *previous_ptr;
register struct notification **ntf_q_pp;
message m;
int i;
int bit_nr, i;
/* Check to see if a message from desired source is already available. */
if (!(caller_ptr->p_flags & SENDING)) {
/* Check caller queue. */
for (sender_ptr = caller_ptr->p_callerq; sender_ptr != NIL_PROC;
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)) {
/* An acceptable message has been found. */
CopyMess(proc_number(sender_ptr), sender_ptr,
sender_ptr->p_messbuf, caller_ptr, m_ptr);
if (sender_ptr == caller_ptr->p_callerq)
caller_ptr->p_callerq = sender_ptr->p_sendlink;
if (sender_ptr == caller_ptr->p_caller_q)
caller_ptr->p_caller_q = sender_ptr->p_sendlink;
else
previous_ptr->p_sendlink = sender_ptr->p_sendlink;
if ((sender_ptr->p_flags &= ~SENDING) == 0)
@ -359,6 +417,26 @@ int may_block; /* (dis)allow blocking */
}
}
/* Check if there are pending notifications. */
ntf_q_pp = &caller_ptr->p_ntf_q; /* get pointer pointer */
while (*ntf_q_pp) {
if (src == ANY || src == (*ntf_q_pp)->n_source) {
/* Found notification. Assemble and copy message. */
m.NOTIFY_TYPE = (*ntf_q_pp)->n_type;
m.NOTIFY_FLAGS = (*ntf_q_pp)->n_flags;
m.NOTIFY_ARG = (*ntf_q_pp)->n_arg;
CopyMess((*ntf_q_pp)->n_source, proc_addr(HARDWARE), &m,
caller_ptr, m_ptr);
/* Remove notification from queue and return. */
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_notify_buf(bit_nr); /* afterwards: prevent race */
return(OK); /* report success */
}
ntf_q_pp = &(*ntf_q_pp)->n_next; /* proceed to next */
}
/* Check bit mask for blocked notifications. If multiple bits are set,
* send the first notification encountered; the rest is handled later.
* This effectively prioritizes notifications. Notification also have
@ -395,12 +473,49 @@ int may_block; /* (dis)allow blocking */
* mini_notify *
*===========================================================================*/
PRIVATE int mini_notify(caller_ptr, dst, m_ptr)
register struct proc *caller_ptr; /* process trying to get message */
register struct proc *caller_ptr; /* process trying to notify */
int dst; /* which process to notify */
message *m_ptr; /* pointer to message buffer */
{
kprintf("Kernel notify from %d", caller_ptr->p_nr);
kprintf("for %d\n", dst);
register struct proc *dest_ptr = proc_addr(dst);
register struct notification *ntf_p ;
register struct notification **ntf_q_pp;
int ntf_index;
message ntf_mess;
/* Check to see if target is blocked waiting for this message. */
if ( (dest_ptr->p_flags & (RECEIVING | SENDING)) == RECEIVING &&
(dest_ptr->p_getfrom == ANY ||
dest_ptr->p_getfrom == proc_number(caller_ptr))) {
/* Destination is indeed waiting for this message. */
CopyMess(proc_number(caller_ptr), caller_ptr, m_ptr, dest_ptr,
dest_ptr->p_messbuf);
dest_ptr->p_flags &= ~RECEIVING; /* deblock destination */
if (dest_ptr->p_flags == 0) ready(dest_ptr);
} else {
/* See if there is a free notification buffer. */
if ((ntf_index = alloc_notify_buf()) < 0)
return(ENOSPC); /* should be atomic! */
/* Copy details from notification message. */
CopyMess(proc_number(caller_ptr), caller_ptr, m_ptr,
proc_addr(HARDWARE), &ntf_mess);
ntf_p = &notify_buffer[ntf_index];
ntf_p->n_source = proc_number(caller_ptr);
ntf_p->n_type = ntf_mess.NOTIFY_TYPE;
ntf_p->n_flags = ntf_mess.NOTIFY_FLAGS;
ntf_p->n_arg = ntf_mess.NOTIFY_ARG;
/* Enqueue the notification message for later. New notifications
* are added to the end of the list. First find the NULL pointer,
* then add the new pointer to the end.
*/
ntf_q_pp = &dest_ptr->p_ntf_q;
while (*ntf_q_pp) ntf_q_pp = &(*ntf_q_pp)->n_next;
*ntf_q_pp = ntf_p;
ntf_p->n_next = NULL;
}
return(OK);
}

View file

@ -37,7 +37,7 @@ struct proc {
notify_mask_t p_ntf_held; /* bit mask for held up notify() calls */
struct proc *p_ntf_nextheld; /* next in chain of held-up int processes */
struct notification *p_ntfq; /* queue of pending notifications */
struct notification *p_ntf_q; /* queue of pending notifications */
int p_flags; /* SENDING, RECEIVING, etc. */
struct mem_map p_memmap[NR_LOCAL_SEGS]; /* local memory map (T, D, S) */
@ -55,7 +55,7 @@ struct proc {
timer_t p_syncalrm; /* synchronous alarm timer */
send_mask_t p_sendmask; /* mask indicating to whom proc may send */
struct proc *p_callerq; /* head of list of procs wishing to send */
struct proc *p_caller_q; /* head of list of procs wishing to send */
struct proc *p_sendlink; /* link to next proc wishing to send */
message *p_messbuf; /* pointer to message buffer */
int p_getfrom; /* from whom does process want to receive? */

View file

@ -198,14 +198,14 @@ int proc_nr; /* slot of process to clean up */
if (rc->p_flags & SENDING) {
/* 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_callerq == NIL_PROC) continue;
if (rp->p_callerq == rc) {
if (rp->p_caller_q == NIL_PROC) continue;
if (rp->p_caller_q == rc) {
/* Exiting process is on front of this queue. */
rp->p_callerq = rc->p_sendlink;
rp->p_caller_q = rc->p_sendlink;
break;
} else {
/* See if exiting process is in middle of queue. */
np = rp->p_callerq;
np = rp->p_caller_q;
while ( ( xp = np->p_sendlink) != NIL_PROC) {
if (xp == rc) {
np->p_sendlink = xp->p_sendlink;

View file

@ -47,8 +47,8 @@ register message *m_ptr; /* pointer to request message */
rpc->p_ldt_sel = old_ldt_sel;
#endif
rpc->p_nr = m_ptr->PR_PROC_NR; /* this was obliterated by copy */
rpc->p_flags |= NO_MAP; /* inhibit the process from running */
rpc->p_ntf_q = NULL; /* remove pending notifications */
rpc->p_flags |= NO_MAP; /* inhibit process from running */
rpc->p_flags &= ~(PENDING | SIG_PENDING | P_STOP);

View file

@ -40,7 +40,7 @@ struct notification {
proc_nr_t n_source; /* sender of notification */
notify_type_t n_type; /* notification type */
notify_arg_t n_arg; /* notification argument */
notify_flags_t n_fags; /* notification flags */
notify_flags_t n_flags; /* notification flags */
struct notification* n_next; /* pointer to next notification */
};

View file

@ -15,6 +15,7 @@ OBJECTS = \
$(LIBRARY)(_seekdir.o) \
$(LIBRARY)(_svrctl.o) \
$(LIBRARY)(_getsysinfo.o) \
$(LIBRARY)(_getprocnr.o) \
$(LIBRARY)(asynchio.o) \
$(LIBRARY)(configfile.o) \
$(LIBRARY)(crypt.o) \
@ -74,6 +75,9 @@ $(LIBRARY)(_seekdir.o): _seekdir.c
$(LIBRARY)(_svrctl.o): _svrctl.c
$(CC1) _svrctl.c
$(LIBRARY)(_getprocnr.o): _getprocnr.c
$(CC1) _getprocnr.c
$(LIBRARY)(_getsysinfo.o): _getsysinfo.c
$(CC1) _getsysinfo.c

View file

@ -1,6 +1,5 @@
#include <lib.h>
#define getsysinfo _getsysinfo
#define getsysinfo _getsysinfo
#include <unistd.h>

View file

@ -43,6 +43,7 @@ OBJECTS = \
$(LIBRARY)(getpid.o) \
$(LIBRARY)(getppid.o) \
$(LIBRARY)(getuid.o) \
$(LIBRARY)(getprocnr.o) \
$(LIBRARY)(ioctl.o) \
$(LIBRARY)(isatty.o) \
$(LIBRARY)(kill.o) \
@ -214,6 +215,9 @@ $(LIBRARY)(getpid.o): getpid.s
$(LIBRARY)(getppid.o): getppid.s
$(CC1) getppid.s
$(LIBRARY)(getprocnr.o): getprocnr.s
$(CC1) getprocnr.s
$(LIBRARY)(getuid.o): getuid.s
$(CC1) getuid.s

View file

@ -36,6 +36,7 @@ PUBLIC int do_getsysinfo()
*=====================================================================*/
PUBLIC int do_getprocnr()
{
mp->mp_reply.procnr = who;
return(OK);
}

View file

@ -6,6 +6,7 @@
#define grp_id m1_i1
#define namelen m1_i1
#define pid m1_i1
#define procnr m1_i1
#define seconds m1_i1
#define sig m6_i1
#define stack_bytes m1_i2