From: Jorrit Herder Date: Tue, 24 May 2005 10:06:17 +0000 (+0000) Subject: New NOTIFY system call! Queued at kernel. Duplicate messages (with same source X-Git-Tag: v3.1.0~822 X-Git-Url: http://zhaoyanbai.com/repos/tz-link.htm?a=commitdiff_plain;h=ccd17ecfed2669cb022fdf5c076c1411d8080028;p=minix.git New NOTIFY system call! Queued at kernel. Duplicate messages (with same source and type) are overwritten with newer flags/ arguments. The interface from within the kernel is lock_notify(). User processes can make a system call with notify(). NOTIFY fully replaces the old notification mechanism. --- diff --git a/commands/reboot/halt.c b/commands/reboot/halt.c index 6fbdca4bd..f5cab5a3b 100755 --- a/commands/reboot/halt.c +++ b/commands/reboot/halt.c @@ -127,7 +127,7 @@ char **argv; /* Give everybody a chance to die peacefully. */ printf("Sending SIGTERM to all processes ...\n"); kill(-1, SIGTERM); - sleep(3); + sleep(2); } reboot(flag, monitor_code, strlen(monitor_code)); diff --git a/drivers/at_wini/at_wini.c b/drivers/at_wini/at_wini.c index aa0390d20..86f366952 100644 --- a/drivers/at_wini/at_wini.c +++ b/drivers/at_wini/at_wini.c @@ -833,6 +833,10 @@ PRIVATE void w_intr_wait() } else if (m.m_type == HARD_INT) { sys_inb((w_wn->base + REG_STATUS), &w_status); } + else { + printf("AT_WINI got unexpected message %d from %d\n", + m.m_type, m.m_source); + } } } else { /* Interrupt not yet allocated; use polling. */ diff --git a/include/ibm/interrupt.h b/include/ibm/interrupt.h index deb9c46cf..40ad5b114 100644 --- a/include/ibm/interrupt.h +++ b/include/ibm/interrupt.h @@ -12,7 +12,7 @@ #define INT2_CTLMASK 0xA1 /* setting bits in this port disables ints */ /* Magic numbers for interrupt controller. */ -#define ENABLE 0x20 /* code used to re-enable after an interrupt */ +#define END_OF_INT 0x20 /* code used to re-enable after an interrupt */ /* Interrupt vectors defined/reserved by processor. */ diff --git a/include/minix/com.h b/include/minix/com.h index f04c220f2..a7a5ad8e4 100755 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -82,9 +82,10 @@ #define NR_NOTIFY_TYPES 5 /* nr of bits in mask */ /* Shorthands for message parameters passed with notifications. */ -#define NOTIFY_TYPE m2_i1 -#define NOTIFY_FLAGS m2_i2 -#define NOTIFY_ARG m2_i3 +#define NOTIFY_SOURCE m_source +#define NOTIFY_TYPE m_type +#define NOTIFY_FLAGS m2_i1 +#define NOTIFY_ARG m2_l1 /*===========================================================================* diff --git a/include/minix/config.h b/include/minix/config.h index f62bc7d3c..90d5b21c7 100755 --- a/include/minix/config.h +++ b/include/minix/config.h @@ -3,7 +3,7 @@ /* Minix release and version numbers. */ #define OS_RELEASE "3" -#define OS_VERSION "0.3" +#define OS_VERSION "0.4" /* This file sets configuration parameters for the MINIX kernel, FS, and PM. * It is divided up into two main sections. The first section contains diff --git a/include/minix/type.h b/include/minix/type.h index 6b53612af..ae322e01f 100755 --- a/include/minix/type.h +++ b/include/minix/type.h @@ -106,6 +106,7 @@ struct kinfo { long notify_blocked; long notify_switching; long notify_reenter; + long notify_taskcall; long notify_ok; long notify_unhold; long notify_int; diff --git a/kernel/clock.c b/kernel/clock.c index c41119bee..77a909348 100755 --- a/kernel/clock.c +++ b/kernel/clock.c @@ -128,7 +128,7 @@ PUBLIC void clock_task() */ if (result != EDONTREPLY) { m.m_type = result; - lock_send(proc_addr(CLOCK), m.m_source, &m); + lock_send(CLOCK, m.m_source, &m); } } } @@ -222,6 +222,7 @@ irq_hook_t *hook; */ register struct proc *rp; register unsigned ticks; + message m; clock_t now; /* Acknowledge the PS/2 clock interrupt. */ @@ -247,7 +248,8 @@ irq_hook_t *hook; if (next_timeout <= now || (sched_ticks == 1 && bill_ptr == prev_ptr && rdy_head[PPRI_USER] != NIL_PROC)) { - lock_notify(CLOCK, HARD_INT); + m.NOTIFY_TYPE = HARD_INT; + lock_notify(HARDWARE, CLOCK, &m); } else if (--sched_ticks == 0) { sched_ticks = SCHED_RATE; /* reset quantum */ diff --git a/kernel/const.h b/kernel/const.h index 3aa549e43..b120f02b3 100755 --- a/kernel/const.h +++ b/kernel/const.h @@ -33,8 +33,17 @@ /* How many IRQ hooks are there in total. */ #define NR_IRQ_HOOKS 16 -/* How many notification buffers (12B each) should there be? */ -#define NR_NOTIFY_BUFS 128 +/* How many buffers for notification messages should there be? */ +#define NR_NOTIFY_BUFS 64 + +/* Constants and macros for bit map manipulation. */ +#define BITCHUNK_BITS (sizeof(bitchunk_t) * CHAR_BIT) +#define BITMAP_CHUNKS(nr_bits) (((nr_bits)+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) ) /* Program stack words and masks. */ #define INIT_PSW 0x0200 /* initial psw */ diff --git a/kernel/glo.h b/kernel/glo.h index 68ba887e8..41eae15f5 100755 --- a/kernel/glo.h +++ b/kernel/glo.h @@ -23,17 +23,12 @@ EXTERN struct machine machine; /* machine information for users */ EXTERN struct kmessages kmess; /* diagnostic messages in kernel */ EXTERN struct memory mem[NR_MEMS]; /* base and size of chunks of memory */ -/* Low level notifications may be put on the 'held' queue to prevent races. */ -EXTERN struct proc *held_head; /* head of queue of held-up interrupts */ -EXTERN struct proc *held_tail; /* tail of queue of held-up interrupts */ -EXTERN unsigned char k_reenter; /* kernel reentry count (entry count less 1)*/ -EXTERN unsigned char switching; /* nonzero if process switching in progress */ - /* Process table. Here to stop too many things having to include proc.h. */ EXTERN struct proc *proc_ptr; /* pointer to currently running process */ /* Miscellaneous. */ -EXTERN unsigned lost_ticks; /* clock ticks counted outside the clock task */ +EXTERN char k_reenter; /* kernel reentry count (entry count less 1) */ +EXTERN unsigned lost_ticks; /* clock ticks counted outside clock task */ #if (CHIP == INTEL) diff --git a/kernel/i8259.c b/kernel/i8259.c index a752c6bd4..7bc396bf6 100755 --- a/kernel/i8259.c +++ b/kernel/i8259.c @@ -10,8 +10,10 @@ #define ICW1_AT 0x11 /* edge triggered, cascade, need ICW4 */ #define ICW1_PC 0x13 /* edge triggered, no cascade, need ICW4 */ #define ICW1_PS 0x19 /* level triggered, cascade, need ICW4 */ -#define ICW4_AT 0x01 /* not SFNM, not buffered, normal EOI, 8086 */ -#define ICW4_PC 0x09 /* not SFNM, buffered, normal EOI, 8086 */ +#define ICW4_AT_SLAVE 0x01 /* not SFNM, not buffered, normal EOI, 8086 */ +#define ICW4_AT_MASTER 0x05 /* not SFNM, not buffered, normal EOI, 8086 */ +#define ICW4_PC_SLAVE 0x09 /* not SFNM, buffered, normal EOI, 8086 */ +#define ICW4_PC_MASTER 0x0D /* not SFNM, buffered, normal EOI, 8086 */ #if _WORD_SIZE == 2 typedef _PROTOTYPE( void (*vecaddr_t), (void) ); @@ -54,13 +56,13 @@ int mine; outb(INT_CTLMASK, mine ? IRQ0_VECTOR : BIOS_IRQ0_VEC); /* ICW2 for master */ outb(INT_CTLMASK, (1 << CASCADE_IRQ)); /* ICW3 tells slaves */ - outb(INT_CTLMASK, ICW4_AT); + outb(INT_CTLMASK, ICW4_AT_MASTER); outb(INT_CTLMASK, ~(1 << CASCADE_IRQ)); /* IRQ 0-7 mask */ outb(INT2_CTL, machine.ps_mca ? ICW1_PS : ICW1_AT); outb(INT2_CTLMASK, mine ? IRQ8_VECTOR : BIOS_IRQ8_VEC); /* ICW2 for slave */ outb(INT2_CTLMASK, CASCADE_IRQ); /* ICW3 is slave nr */ - outb(INT2_CTLMASK, ICW4_AT); + outb(INT2_CTLMASK, ICW4_AT_SLAVE); outb(INT2_CTLMASK, ~0); /* IRQ 8-15 mask */ /* Copy the BIOS vectors from the BIOS to the Minix location, so we diff --git a/kernel/klibc.c b/kernel/klibc.c index 609bff7d5..9bdb54775 100644 --- a/kernel/klibc.c +++ b/kernel/klibc.c @@ -154,13 +154,15 @@ int c; /* character to append */ /* Accumulate a single character for a kernel message. Send a notification * the to TTY driver if the buffer if a END_OF_KMESS is encountered. */ + message m; if (c != END_OF_KMESS) { kmess.km_buf[kmess.km_next] = c; /* put normal char in buffer */ if (kmess.km_size < KMESS_BUF_SIZE) kmess.km_size += 1; kmess.km_next = (kmess.km_next + 1) % KMESS_BUF_SIZE; } else { - lock_notify(TTY, NEW_KMESS); /* let TTY display the message */ + m.NOTIFY_TYPE = NEW_KMESS; + lock_notify(HARDWARE, TTY, &m); } } diff --git a/kernel/main.c b/kernel/main.c index 9cd66d332..3b29037b8 100755 --- a/kernel/main.c +++ b/kernel/main.c @@ -217,6 +217,7 @@ int how; /* 0 = halt, 1 = reboot, 2 = panic!, ... */ * sure it is only executed once. Unless a CPU exception occurred, the * stop_sequence() is started. */ + message m; if (shutting_down) return; @@ -225,7 +226,6 @@ int how; /* 0 = halt, 1 = reboot, 2 = panic!, ... */ * We rely on TTY to call sys_abort() when it is done with the dumps. */ if (how == RBT_PANIC) { - message m; m.m_type = PANIC_DUMPS; if (nb_send(TTY, &m) == OK) /* don't block if TTY isn't ready */ return; /* await sys_abort() from TTY */ @@ -234,7 +234,8 @@ int how; /* 0 = halt, 1 = reboot, 2 = panic!, ... */ /* The TTY expects two HARD_STOP notifications. One to switch to the * primary console for stop sequence output, and one to actually exit. */ - lock_notify(TTY, HARD_STOP); /* let TTY switch to console 0 */ + m.NOTIFY_TYPE = HARD_STOP; + lock_notify(HARDWARE, TTY, &m); /* Run the stop sequence. The timer argument passes the shutdown status. * The stop sequence is skipped for fatal CPU exceptions. @@ -266,6 +267,7 @@ 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. */ if (p != NIL_PROC) { @@ -288,7 +290,9 @@ timer_t *tp; kprintf("- Stopping %s ", karg(p->p_name)); kprintf("%s ... ", karg(types[p->p_type])); shutdown_process = p; /* directly continue if exited */ - lock_notify(proc_number(p), HARD_STOP); + m.NOTIFY_TYPE = HARD_STOP; + m.NOTIFY_ARG = tmr_arg(tp)->ta_int; /* how */ + lock_notify(HARDWARE, proc_number(p), &m); set_timer(tp, get_uptime()+STOP_TICKS, stop_sequence); return; /* allow the process to shut down */ } @@ -330,7 +334,7 @@ PRIVATE void shutdown(int how) * For RBT_MONITOR, the MM has provided the program. */ if (how == RBT_HALT) { - phys_copy(vir2phys("delay;"), kinfo.params_base, 7); + phys_copy(vir2phys("delay;menu"), kinfo.params_base, 11); } else if (how == RBT_REBOOT) { phys_copy(vir2phys("delay;boot"), kinfo.params_base, 11); } diff --git a/kernel/misc.c b/kernel/misc.c index a7b48bf82..c4b8195ca 100755 --- a/kernel/misc.c +++ b/kernel/misc.c @@ -2,6 +2,9 @@ * panic abort MINIX due to a fatal error * bad_assertion for debugging * bad_compare for debugging + * alloc_bit bit map manipulation + * free_bit bit map manipulation + * print_bitmap bit map manipulation */ #include "kernel.h" @@ -35,6 +38,78 @@ int n; } +/*===========================================================================* + * print_bitmap * + *===========================================================================*/ +PUBLIC void print_bitmap(bitmap, nr_bits) +bitchunk_t *bitmap; +bit_t nr_bits; +{ + bit_t bit_i; + + for (bit_i=0; bit_i < nr_bits; bit_i++) { + + kprintf("%d", GET_BIT(bitmap, bit_i) > 0 ); + if (! ((bit_i+1) % 8) ) kprintf(" ", NO_ARG); + if (! ((bit_i+1) % 64) ) kprintf("\n", NO_ARG); + } + kprintf("\n", NO_ARG); +} + +/*===========================================================================* + * free_bit * + *===========================================================================*/ +PUBLIC void free_bit(bit_nr, bitmap, nr_bits) +bit_t bit_nr; +bitchunk_t *bitmap; +bit_t nr_bits; +{ + bitchunk_t *chunk; + if (bit_nr >= nr_bits) { + kprintf("Warning, free_bit: %d illegal index\n", bit_nr); + return; + } + chunk = &bitmap[(bit_nr/BITCHUNK_BITS)]; + *chunk &= ~(1 << (bit_nr % BITCHUNK_BITS)); +} + +/*===========================================================================* + * alloc_bit * + *===========================================================================*/ +PUBLIC int alloc_bit(bitmap, nr_bits) +bitchunk_t *bitmap; +bit_t nr_bits; +{ + bitchunk_t *chunk; + int nr_chunks; + int bit_nr; + int i; + + /* Iterate over the words in block. */ + nr_chunks = BITMAP_CHUNKS(nr_bits); + for (chunk = &bitmap[0]; chunk < &bitmap[nr_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 - &bitmap[0]) * BITCHUNK_BITS + i; + + /* Don't allocate bits beyond the end of the map. */ + if (bit_nr >= nr_bits) break; + + *chunk |= 1 << bit_nr % BITCHUNK_BITS; + return(bit_nr); + + } + kprintf("Warning, all %d bits in map busy\n", nr_bits); + return(-1); +} + + + + #if !NDEBUG /*=========================================================================* * bad_assertion * diff --git a/kernel/mpx386.s b/kernel/mpx386.s index efebfbfad..1cd4140bd 100755 --- a/kernel/mpx386.s +++ b/kernel/mpx386.s @@ -55,6 +55,7 @@ begbss: #include #include #include +#include #include "const.h" #include "protect.h" #include "sconst.h" @@ -212,24 +213,48 @@ csinit: !* hwint00 - 07 * !*===========================================================================* ! Note this is a macro, it just looks like a subroutine. -#define hwint_master(irq) \ +#define hwint_master_slave_fail(irq) \ call save /* save interrupted process state */;\ - inb INT_CTLMASK ;\ - orb al, [1<= 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 * - *===========================================================================*/ -PUBLIC void lock_notify(proc_nr, notify_type) -int proc_nr; /* number of process to be started */ -int notify_type; /* notification to be sent */ -{ -/* A system event has occurred. Send a notification with source HARDWARE to - * the given process. The notify() function was carefully designed so that it - * (1) can be used safely from both interrupt handlers and the task level, and - * (2) realizes asynchronous message passing with at least once semantics, - * that is, the notifications are not queued. If a race condition occurs, the - * notification is queued and repeated later by unhold(). If the receiver is - * not ready, the notification is blocked and checked later in receive(). - */ - register struct proc *rp; /* pointer to task's proc entry */ - message m; /* message to send the notification */ - unsigned int notify_bit; /* bit for this notification */ - - /* Get notify bit and process pointer. */ - notify_bit = (unsigned int) (notify_type & ~NOTIFICATION); - rp = proc_addr(proc_nr); - - /* If this call would compete with other process-switching functions, put - * it on the 'held' queue to be flushed at the next non-competing restart(). - * The competing conditions are: - * (1) k_reenter == (typeof k_reenter) -1: - * Call from the task level, typically from an output interrupt - * routine. An interrupt handler might reenter notify(). Rare, - * so not worth special treatment. - * (2) k_reenter > 0: - * Call from a nested interrupt handler. A previous interrupt - * handler might be inside notify() or sys_call(). - * (3) switching != 0: - * A process-switching function other than notify() is being called - * from the task level, typically sched() from CLOCK. An interrupt - * handler might call notify() and pass the 'k_reenter' test. - */ - if (k_reenter != 0 || switching) { - kinfo.notify_held ++; - if (switching) kinfo.notify_switching ++; - if (k_reenter > 0) kinfo.notify_reenter ++; - switch(notify_type) { - case HARD_INT: kinfo.notify_int ++; break; - case HARD_STOP: kinfo.notify_stop ++; break; - case SYN_ALARM: kinfo.notify_alarm ++; break; - case KSIG_PENDING: kinfo.notify_sig ++; break; - case NEW_KMESS: kinfo.notify_kmess ++; break; - } - lock(); - /* already on held queue? */ - if (! isset_bit(rp->p_ntf_held, notify_bit)) { - if (held_head != NIL_PROC) - held_tail->p_ntf_nextheld = rp; - else - held_head = rp; - held_tail = rp; - rp->p_ntf_nextheld = NIL_PROC; - } - set_bit(rp->p_ntf_held, notify_bit); /* add bit to held mask */ - unlock(); - return; - } - - /* If process is not waiting for a notification, record the blockage. Else, - * send it a message with source HARDWARE and type 'notify_type'. No more - * information can be reliably provided since notifications are not queued. - */ - switching = TRUE; - - if ( (rp->p_flags & (RECEIVING | SENDING)) != RECEIVING || - !isrxhardware(rp->p_getfrom)) { - kinfo.notify_blocked ++; - set_bit(rp->p_ntf_blocked, notify_bit); /* update blocked mask */ - } else { - - /* Assemble notification message and send it. */ - m.m_source = HARDWARE; - m.m_type = notify_type; - CopyMess(HARDWARE, proc_addr(HARDWARE), &m, rp, rp->p_messbuf); - clear_bit(rp->p_ntf_blocked, notify_bit); - rp->p_flags &= ~RECEIVING; - kinfo.notify_ok ++; - - /* Announce the process ready and select a fresh process to run. */ - ready(rp); - pick_proc(); - } - switching = FALSE; -} +PRIVATE bitchunk_t notify_bitmap[BITMAP_CHUNKS(NR_NOTIFY_BUFS)]; /*===========================================================================* @@ -223,7 +71,7 @@ int notify_type; /* notification to be sent */ *===========================================================================*/ PUBLIC int sys_call(call_nr, src_dst, m_ptr) int call_nr; /* (NB_)SEND, (NB_)RECEIVE, BOTH */ -int src_dst; /* source to receive from or dest 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 */ { /* System calls are done by trapping to the kernel with an INT instruction. @@ -298,21 +146,21 @@ message *m_ptr; /* pointer to message in the caller's space */ /*===========================================================================* * mini_send * *===========================================================================*/ -PRIVATE int mini_send(caller_ptr, dest, m_ptr, may_block) +PRIVATE int mini_send(caller_ptr, dst, m_ptr, may_block) register struct proc *caller_ptr; /* who is trying to send a message? */ -int dest; /* to whom is message being sent? */ +int dst; /* to whom is message being sent? */ message *m_ptr; /* pointer to message buffer */ int may_block; /* (dis)allow blocking */ { -/* Send a message from 'caller_ptr' to 'dest'. If 'dest' is blocked waiting - * for this message, copy the message to it and unblock 'dest'. If 'dest' is +/* 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 *dest_ptr, *next_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 */ - dest_ptr = proc_addr(dest); /* pointer to destination's proc entry */ + 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. @@ -335,9 +183,9 @@ int may_block; /* (dis)allow blocking */ return(EFAULT); #endif - /* Check for deadlock by 'caller_ptr' and 'dest' sending to each other. */ - if (dest_ptr->p_flags & SENDING) { - next_ptr = proc_addr(dest_ptr->p_sendto); + /* 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) { if (next_ptr == caller_ptr) return(ELOCKED); if (next_ptr->p_flags & SENDING) @@ -347,25 +195,25 @@ int may_block; /* (dis)allow blocking */ } } - /* Check to see if 'dest' 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))) { + /* Check to see if 'dst' is blocked waiting for this message. */ + if ( (dst_ptr->p_flags & (RECEIVING | SENDING)) == RECEIVING && + (dst_ptr->p_getfrom == ANY || + dst_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); + CopyMess(proc_number(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); } else if (may_block) { /* Destination is not waiting. Block and queue caller. */ caller_ptr->p_messbuf = m_ptr; if (caller_ptr->p_flags == 0) unready(caller_ptr); caller_ptr->p_flags |= SENDING; - caller_ptr->p_sendto= dest; + caller_ptr->p_sendto = dst; /* Process is now blocked. Put in on the destination's queue. */ - if ( (next_ptr = dest_ptr->p_caller_q) == NIL_PROC) - dest_ptr->p_caller_q = caller_ptr; + 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; @@ -422,6 +270,7 @@ int may_block; /* (dis)allow blocking */ while (*ntf_q_pp) { 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; @@ -431,28 +280,11 @@ int may_block; /* (dis)allow blocking */ 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 */ + free_bit(bit_nr, notify_bitmap, NR_NOTIFY_BUFS); 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 - * priority of other messages. - */ - if (caller_ptr->p_ntf_blocked && isrxhardware(src)) { - for (i=0; ip_ntf_blocked, i)) { - m.m_source = HARDWARE; - m.m_type = NOTIFICATION | i; - CopyMess(HARDWARE, proc_addr(HARDWARE), &m, caller_ptr, m_ptr); - clear_bit(caller_ptr->p_ntf_blocked, i); - return(OK); - } - } - } } /* No suitable message is available. Block the process trying to receive, @@ -469,6 +301,7 @@ int may_block; /* (dis)allow blocking */ } } + /*===========================================================================* * mini_notify * *===========================================================================*/ @@ -477,48 +310,75 @@ register struct proc *caller_ptr; /* process trying to notify */ int dst; /* which process to notify */ message *m_ptr; /* pointer to message buffer */ { - register struct proc *dest_ptr = proc_addr(dst); + register struct proc *dst_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))) { + if ( (dst_ptr->p_flags & (RECEIVING | SENDING)) == RECEIVING && + (dst_ptr->p_getfrom == ANY || + dst_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 { + CopyMess(proc_number(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, + proc_addr(HARDWARE), &ntf_mess); + m_ptr = &ntf_mess; + } - /* See if there is a free notification buffer. */ - if ((ntf_index = alloc_notify_buf()) < 0) - return(ENOSPC); /* should be atomic! */ + /* Enqueue the message. Existing notifications are overwritten with + * the newer one. New notifications are added to the end of the list. + */ + ntf_q_pp = &dst_ptr->p_ntf_q; + while (*ntf_q_pp) { + /* 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) { + (*ntf_q_pp)->n_flags = m_ptr->NOTIFY_FLAGS; + (*ntf_q_pp)->n_arg = m_ptr->NOTIFY_ARG; + break; + } + return(OK); + } - /* Copy details from notification message. */ - CopyMess(proc_number(caller_ptr), caller_ptr, m_ptr, - proc_addr(HARDWARE), &ntf_mess); + /* 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! */ 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_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_p->n_next = NULL; } return(OK); } +/*==========================================================================* + * lock_notify * + *==========================================================================*/ +PUBLIC int lock_notify(src, dst, m_ptr) +int src; /* who is trying to send a message? */ +int dst; /* to whom is message being sent? */ +message *m_ptr; /* pointer to message buffer */ +{ +/* Safe gateway to mini_notify() for tasks. */ + int result; + lock(); + result = mini_notify(proc_addr(src), dst, m_ptr); + unlock(); + return(result); +} /*===========================================================================* * pick_proc * @@ -618,16 +478,6 @@ register struct proc *rp; /* this process is no longer runnable */ rdy_tail[q] = rp; } } - - -#if DEAD_CODE - while (xp->p_nextready != rp) /* find rp */ - if ( (xp = xp->p_nextready) == NIL_PROC) - return; - xp->p_nextready = xp->p_nextready->p_nextready; - qtail = &rdy_tail[q]; - if (*qtail == rp) *qtail = xp; -#endif } /*===========================================================================* @@ -655,25 +505,25 @@ PRIVATE void sched() PUBLIC void lock_pick_proc() { /* Safe gateway to pick_proc() for tasks. */ - switching = TRUE; + lock(); pick_proc(); - switching = FALSE; + unlock(); } /*==========================================================================* * lock_send * *==========================================================================*/ -PUBLIC int lock_send(caller_ptr, dest, m_ptr) -register struct proc *caller_ptr; /* who is trying to send a message? */ -int dest; /* to whom is message being sent? */ -message *m_ptr; /* pointer to message buffer */ +PUBLIC int lock_send(src, dst, m_ptr) +int src; /* who is trying to send a message? */ +int dst; /* to whom is message being sent? */ +message *m_ptr; /* pointer to message buffer */ { /* Safe gateway to mini_send() for tasks. */ int result; - switching = TRUE; - result = mini_send(caller_ptr, dest, m_ptr, FALSE); - switching = FALSE; + lock(); + result = mini_send(proc_addr(src), dst, m_ptr, FALSE); + unlock(); return(result); } @@ -685,9 +535,9 @@ PUBLIC void lock_ready(rp) struct proc *rp; /* this process is now runnable */ { /* Safe gateway to ready() for tasks. */ - switching = TRUE; + lock(); ready(rp); - switching = FALSE; + unlock(); } /*==========================================================================* @@ -697,9 +547,9 @@ PUBLIC void lock_unready(rp) struct proc *rp; /* this process is no longer runnable */ { /* Safe gateway to unready() for tasks. */ - switching = TRUE; + lock(); unready(rp); - switching = FALSE; + unlock(); } /*==========================================================================* @@ -708,45 +558,8 @@ struct proc *rp; /* this process is no longer runnable */ PUBLIC void lock_sched() { /* Safe gateway to sched() for tasks. */ - switching = TRUE; + lock(); sched(); - switching = FALSE; -} - -/*==========================================================================* - * unhold * - *==========================================================================*/ -PUBLIC void unhold() -{ -/* Flush any held-up notifications. 'k_reenter' must be 0. 'held_head' must - * not be NIL_PROC. Interrupts must be disabled. They will be enabled but - * will be disabled when this returns. - */ - register struct proc *rp; /* current head of held queue */ - int i; - - kinfo.notify_unhold ++; - - if (switching) return; - rp = held_head; - do { - for (i=0; ip_ntf_held,i)) { - clear_bit(rp->p_ntf_held,i); - if (! rp->p_ntf_held) /* proceed to next in queue? */ - if ( (held_head = rp->p_ntf_nextheld) == NIL_PROC) - held_tail = NIL_PROC; -#if DEAD_CODE - unlock(); /* reduce latency; held queue may change! */ -#endif - lock_notify(proc_number(rp), NOTIFICATION | i); -#if DEAD_CODE - lock(); /* protect the held queue again */ -#endif - } - } - } - while ( (rp = held_head) != NIL_PROC); + unlock(); } - diff --git a/kernel/proc.h b/kernel/proc.h index db69a2e57..0c0b7b27d 100755 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -33,12 +33,6 @@ struct proc { proc_nr_t p_nr; /* number of this process (for fast access) */ - notify_mask_t p_ntf_blocked; /* bit mask for blocked notifications */ - 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_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) */ struct far_mem p_farmem[NR_REMOTE_SEGS]; /* remote memory map */ @@ -61,6 +55,8 @@ struct proc { int p_getfrom; /* from whom does process want to receive? */ int p_sendto; /* to whom does process want to send? */ + struct notification *p_ntf_q; /* queue of pending notifications */ + struct proc *p_nextready; /* pointer to next ready process */ sigset_t p_pending; /* bit map for pending signals */ unsigned p_pendcount; /* count of pending and unfinished signals */ diff --git a/kernel/proto.h b/kernel/proto.h index 733f3c9fb..e2e9971e7 100755 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -38,16 +38,18 @@ _PROTOTYPE( void stop_sequence, (struct timer *tp) ); /* misc.c */ _PROTOTYPE( void panic, (_CONST char *s, int n) ); +_PROTOTYPE( int alloc_bit, (bitchunk_t *map, bit_t nr_bits) ); +_PROTOTYPE( void free_bit, (bit_t nr, bitchunk_t *map, bit_t nr_bits) ); +_PROTOTYPE( void print_bitmap, (bitchunk_t *map, bit_t nr_bits) ); /* proc.c */ _PROTOTYPE( int sys_call, (int function, int src_dest, message *m_ptr) ); -_PROTOTYPE( void unhold, (void) ); +_PROTOTYPE( int lock_notify, (int src, int dst, message *m_ptr) ); +_PROTOTYPE( int lock_send, (int src, 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_unready, (struct proc *rp) ); -_PROTOTYPE( void lock_notify, (int proc_nr, int notify_type) ); -_PROTOTYPE( int lock_send, (struct proc *rp, int to, message *m_ptr) ); /* start.c */ _PROTOTYPE( void cstart, (U16_t cs, U16_t ds, U16_t mds, diff --git a/kernel/system.c b/kernel/system.c index 84e429b74..e9174c0e1 100755 --- a/kernel/system.c +++ b/kernel/system.c @@ -89,7 +89,7 @@ PUBLIC void sys_task() */ if (result != EDONTREPLY) { m.m_type = result; /* report status of call */ - lock_send(proc_addr(SYSTASK), m.m_source, &m); + lock_send(SYSTASK, m.m_source, &m); } } } @@ -243,7 +243,10 @@ irq_hook_t *hook; * interrupts are transformed into messages to a driver. The IRQ line will be * reenabled if the policy says so. */ - lock_notify(hook->proc_nr, HARD_INT); + message m; + m.NOTIFY_TYPE = HARD_INT; + m.NOTIFY_ARG = hook->irq; + lock_notify(HARDWARE, hook->proc_nr, &m); return(hook->policy & IRQ_REENABLE); } @@ -268,6 +271,7 @@ int sig_nr; /* signal to be sent, 1 to _NSIG */ * do a core dump. */ register struct proc *rp, *mmp; + message m; rp = proc_addr(proc_nr); if (sigismember(&rp->p_pending, sig_nr)) @@ -278,12 +282,15 @@ int sig_nr; /* signal to be sent, 1 to _NSIG */ return; /* another signal already pending */ if (rp->p_flags == 0) lock_unready(rp); rp->p_flags |= PENDING | SIG_PENDING; - lock_notify(PM_PROC_NR, KSIG_PENDING); + m.NOTIFY_TYPE = KSIG_PENDING; + m.NOTIFY_ARG = 0; + m.NOTIFY_FLAGS = 0; + lock_notify(HARDWARE, PM_PROC_NR, &m); } /*===========================================================================* - * umap_bios * + * umap_bios * *===========================================================================*/ PUBLIC phys_bytes umap_bios(rp, vir_addr, bytes) register struct proc *rp; /* pointer to proc table entry for process */ diff --git a/kernel/system/clock.c b/kernel/system/clock.c index 55b18073d..d07074697 100644 --- a/kernel/system/clock.c +++ b/kernel/system/clock.c @@ -164,7 +164,12 @@ timer_t *tp; * alarm. The process number is stored in timer argument 'ta_int'. Notify that * process given with a SYN_ALARM message. */ - lock_notify(tmr_arg(tp)->ta_int, SYN_ALARM); + message m; + m.NOTIFY_SOURCE = HARDWARE; + m.NOTIFY_TYPE = SYN_ALARM; + m.NOTIFY_ARG = get_uptime(); + m.NOTIFY_FLAGS = 0; + lock_notify(HARDWARE, tmr_arg(tp)->ta_int, &m); } diff --git a/kernel/type.h b/kernel/type.h index 598ad4198..cca1815f2 100755 --- a/kernel/type.h +++ b/kernel/type.h @@ -13,7 +13,7 @@ typedef long karg_t; /* use largest type here */ * short we can support up to 256 user processes and more kernel tasks than * one can ever create. */ -typedef int proc_nr_t; /* process table entry number */ +typedef short proc_nr_t; /* process table entry number */ typedef unsigned long send_mask_t; /* bit mask for sender */ struct system_image { @@ -32,8 +32,8 @@ struct memory { }; typedef unsigned long notify_mask_t; /* bit mask for notifications */ -typedef char notify_type_t; /* notification type */ -typedef char notify_flags_t; /* notification flags */ +typedef short notify_type_t; /* notification type */ +typedef short notify_flags_t; /* notification flags */ typedef int notify_arg_t; /* notification argument */ struct notification { diff --git a/servers/is/dmp.c b/servers/is/dmp.c index 4cd399a29..c71b0708f 100644 --- a/servers/is/dmp.c +++ b/servers/is/dmp.c @@ -325,11 +325,12 @@ PRIVATE void kenv_dmp() printf("- bootdev_size: %5u\n", kinfo.bootdev_size); printf("- params_base: %5u\n", kinfo.params_base); printf("- params_size: %5u\n", kinfo.params_size); - printf("- notify_held: %8u\n", kinfo.notify_held); printf("- notify_blocked:%8u\n", kinfo.notify_blocked); - printf("- notify_switch: %8u\n", kinfo.notify_switching); - printf("- notify_reenter:%8u\n", kinfo.notify_reenter); printf("- notify_ok: %8u\n", kinfo.notify_ok); + printf("- notify_held: %8u\n", kinfo.notify_held); + printf("- notify_switch: %8u\n", kinfo.notify_switching); + printf("- notify_reenter:%8u\n", kinfo.notify_reenter); + printf("- notify_taskcall:%7u\n", kinfo.notify_taskcall); printf("- notify_unhold: %8u\n", kinfo.notify_unhold); printf("- hard_int: %8u\n", kinfo.notify_int); printf("- hard_stop: %8u\n", kinfo.notify_stop); diff --git a/test/Makefile b/test/Makefile index 5e9663d95..0ee5053d0 100644 --- a/test/Makefile +++ b/test/Makefile @@ -28,7 +28,7 @@ $(ROOTOBJ): rm a.out clean: - @rm -f *.o *.s *.bak test? test?? t10a t11a t11b DIR* + rm -rf *.o *.s *.bak test? test?? t10a t11a t11b DIR* test1: test1.c test2: test2.c