From 307c825515e7e343650fecb3cbfad1f0f1610470 Mon Sep 17 00:00:00 2001 From: Jorrit Herder Date: Thu, 19 May 2005 14:05:51 +0000 Subject: [PATCH] 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. --- include/lib.h | 3 - include/minix/com.h | 4 +- include/unistd.h | 4 +- kernel/proc.c | 141 ++++++++++++++++++++++++++++++++++++---- kernel/proc.h | 4 +- kernel/system.c | 8 +-- kernel/system/proctl.c | 4 +- kernel/type.h | 2 +- lib/other/Makefile | 4 ++ lib/other/_getsysinfo.c | 1 - lib/syscall/Makefile | 4 ++ servers/pm/misc.c | 1 + servers/pm/param.h | 1 + 13 files changed, 151 insertions(+), 30 deletions(-) diff --git a/include/lib.h b/include/lib.h index 948739a47..d00eda7cf 100755 --- a/include/lib.h +++ b/include/lib.h @@ -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 */ diff --git a/include/minix/com.h b/include/minix/com.h index a00c761ca..f04c220f2 100755 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -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 /*===========================================================================* diff --git a/include/unistd.h b/include/unistd.h index 22c0f9bee..a5921db6e 100755 --- a/include/unistd.h +++ b/include/unistd.h @@ -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)); diff --git a/kernel/proc.c b/kernel/proc.c index c271268a0..54d977864 100755 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -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 = ¬ify_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 = ¬ify_bitmap[0]; + chunk < ¬ify_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 - ¬ify_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) ¬ify_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 = ¬ify_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); } diff --git a/kernel/proc.h b/kernel/proc.h index 633259d14..db69a2e57 100755 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -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? */ diff --git a/kernel/system.c b/kernel/system.c index 0d93e7fb8..84e429b74 100755 --- a/kernel/system.c +++ b/kernel/system.c @@ -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; diff --git a/kernel/system/proctl.c b/kernel/system/proctl.c index 31493b838..c35b6248f 100644 --- a/kernel/system/proctl.c +++ b/kernel/system/proctl.c @@ -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); diff --git a/kernel/type.h b/kernel/type.h index 80a38ae26..598ad4198 100755 --- a/kernel/type.h +++ b/kernel/type.h @@ -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 */ }; diff --git a/lib/other/Makefile b/lib/other/Makefile index 1654def69..c05c91a73 100755 --- a/lib/other/Makefile +++ b/lib/other/Makefile @@ -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 diff --git a/lib/other/_getsysinfo.c b/lib/other/_getsysinfo.c index d98b8833f..19675ab18 100644 --- a/lib/other/_getsysinfo.c +++ b/lib/other/_getsysinfo.c @@ -1,6 +1,5 @@ #include #define getsysinfo _getsysinfo -#define getsysinfo _getsysinfo #include diff --git a/lib/syscall/Makefile b/lib/syscall/Makefile index 1b179c2e0..41bee90db 100755 --- a/lib/syscall/Makefile +++ b/lib/syscall/Makefile @@ -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 diff --git a/servers/pm/misc.c b/servers/pm/misc.c index 983435e38..32aa327d5 100644 --- a/servers/pm/misc.c +++ b/servers/pm/misc.c @@ -36,6 +36,7 @@ PUBLIC int do_getsysinfo() *=====================================================================*/ PUBLIC int do_getprocnr() { + mp->mp_reply.procnr = who; return(OK); } diff --git a/servers/pm/param.h b/servers/pm/param.h index e5764812c..c39752fbd 100644 --- a/servers/pm/param.h +++ b/servers/pm/param.h @@ -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