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.
This commit is contained in:
parent
80e38daead
commit
ccd17ecfed
|
@ -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));
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -55,6 +55,7 @@ begbss:
|
|||
#include <minix/config.h>
|
||||
#include <minix/const.h>
|
||||
#include <minix/com.h>
|
||||
#include <ibm/interrupt.h>
|
||||
#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_slave_fail(irq) \
|
||||
call save /* save interrupted process state */;\
|
||||
cli ;\
|
||||
inb INT2_CTLMASK /* get current mask */ ;\
|
||||
movb ah, al ;\
|
||||
inb INT_CTLMASK /* get current mask */ ;\
|
||||
push eax ;\
|
||||
cli ;\
|
||||
movb al, ~[0] ;\
|
||||
outb INT_CTLMASK /* mask all */;\
|
||||
outb INT2_CTLMASK /* */;\
|
||||
cli ;\
|
||||
push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\
|
||||
call _intr_handle /* intr_handle(irq_handlers[irq]) */;\
|
||||
pop ecx ;\
|
||||
pop eax ;\
|
||||
cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\
|
||||
jz 0f ;\
|
||||
or eax, [1<<irq] /* mask irq */ ;\
|
||||
0: outb INT_CTLMASK /* restore master irq mask */;\
|
||||
movb al, ah ;\
|
||||
outb INT2_CTLMASK /* restore slave irq mask */;\
|
||||
movb al, END_OF_INT ;\
|
||||
outb INT_CTL /* reenable master 8259 */;\
|
||||
cmp (irq), 8 ;\
|
||||
jb 1f ;\
|
||||
outb INT2_CTL /* reenable slave 8259 */;\
|
||||
1: ret /* restart (another) process */
|
||||
|
||||
#define hwint_master(irq) \
|
||||
call save /* save interrupted process state */;\
|
||||
inb INT_CTLMASK ;\
|
||||
orb al, [1<<irq] ;\
|
||||
outb INT_CTLMASK /* disable the irq */;\
|
||||
movb al, ENABLE ;\
|
||||
outb INT_CTL /* reenable master 8259 */;\
|
||||
push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\
|
||||
sti /* enable interrupts */;\
|
||||
call _intr_handle /* intr_handle(irq_handlers[irq]) */;\
|
||||
cli /* disable interrupts */;\
|
||||
pop ecx ;\
|
||||
cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\
|
||||
jnz 0f ;\
|
||||
inb INT_CTLMASK ;\
|
||||
andb al, ~[1<<irq] ;\
|
||||
outb INT_CTLMASK /* enable the irq */;\
|
||||
0: ret /* restart (another) process */
|
||||
jz 0f ;\
|
||||
inb INT_CTLMASK /* get current mask */ ;\
|
||||
orb al, [1<<irq] /* mask irq */ ;\
|
||||
outb INT_CTLMASK /* disable the irq */;\
|
||||
0: movb al, END_OF_INT ;\
|
||||
outb INT_CTL /* reenable master 8259 */;\
|
||||
ret /* restart (another) process */
|
||||
|
||||
! Each of these entry points is an expansion of the hwint_master macro
|
||||
.align 16
|
||||
|
@ -270,23 +295,18 @@ _hwint07: ! Interrupt routine for irq 7 (printer)
|
|||
! Note this is a macro, it just looks like a subroutine.
|
||||
#define hwint_slave(irq) \
|
||||
call save /* save interrupted process state */;\
|
||||
push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\
|
||||
call _intr_handle /* intr_handle(irq_handlers[irq]) */;\
|
||||
pop ecx ;\
|
||||
cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\
|
||||
jz 0f ;\
|
||||
inb INT2_CTLMASK ;\
|
||||
orb al, [1<<[irq-8]] ;\
|
||||
outb INT2_CTLMASK /* disable the irq */;\
|
||||
movb al, ENABLE ;\
|
||||
0: movb al, END_OF_INT ;\
|
||||
outb INT_CTL /* reenable master 8259 */;\
|
||||
push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\
|
||||
outb INT2_CTL /* reenable slave 8259 */;\
|
||||
sti /* enable interrupts */;\
|
||||
call _intr_handle /* intr_handle(irq_handlers[irq]) */;\
|
||||
cli /* disable interrupts */;\
|
||||
pop ecx ;\
|
||||
cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\
|
||||
jnz 0f ;\
|
||||
inb INT2_CTLMASK ;\
|
||||
andb al, ~[1<<[irq-8]] ;\
|
||||
outb INT2_CTLMASK /* enable the irq */;\
|
||||
0: ret /* restart (another) process */
|
||||
ret /* restart (another) process */
|
||||
|
||||
! Each of these entry points is an expansion of the hwint_slave macro
|
||||
.align 16
|
||||
|
@ -375,7 +395,6 @@ _p_s_call:
|
|||
mov esp, k_stktop
|
||||
xor ebp, ebp ! for stacktrace
|
||||
! end of inline save
|
||||
sti ! allow SWITCHER to be interrupted
|
||||
! now set up parameters for sys_call()
|
||||
push ebx ! pointer to user message
|
||||
push eax ! src/dest
|
||||
|
@ -383,7 +402,6 @@ _p_s_call:
|
|||
call _sys_call ! sys_call(function, src_dest, m_ptr)
|
||||
! caller is now explicitly in proc_ptr
|
||||
mov AXREG(esi), eax ! sys_call MUST PRESERVE si
|
||||
cli ! disable interrupts
|
||||
|
||||
! Fall into code to restart proc/task running.
|
||||
|
||||
|
@ -392,17 +410,8 @@ _p_s_call:
|
|||
!*===========================================================================*
|
||||
_restart:
|
||||
|
||||
! Flush any held-up notifications.
|
||||
! This reenables interrupts, so the current interrupt handler may reenter.
|
||||
! This does not matter, because the current handler is about to exit and no
|
||||
! other handlers can reenter since flushing is only done when k_reenter == 0.
|
||||
! Restart the current process or the next process if it is set.
|
||||
|
||||
cmp (_held_head), 0 ! do fast test to usually avoid function call
|
||||
jz over_call_unhold
|
||||
cmp (_switching), 0 ! do fast test to usually avoid function call
|
||||
jnz over_call_unhold
|
||||
call _unhold ! this is rare so overhead acceptable
|
||||
over_call_unhold:
|
||||
mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0
|
||||
lldt P_LDT_SEL(esp) ! enable segment descriptors for task
|
||||
lea eax, P_STACKTOP(esp) ! arrange for next interrupt
|
||||
|
@ -522,7 +531,6 @@ exception1: ! Common for all exceptions.
|
|||
call _exception ! (ex_number, trap_errno, old_eip,
|
||||
! old_cs, old_eflags)
|
||||
add esp, 5*4
|
||||
cli
|
||||
ret
|
||||
|
||||
!*===========================================================================*
|
||||
|
|
399
kernel/proc.c
399
kernel/proc.c
|
@ -1,27 +1,24 @@
|
|||
/* This file contains essentially all of the process and message handling.
|
||||
* It has two main entry points from the outside:
|
||||
* It has one main entry point from the outside:
|
||||
*
|
||||
* sys_call: a system call, that is, the kernel is trapped with an INT
|
||||
* lock_notify: send a notification to inform a process of a system event
|
||||
* sys_call: a system call, i.e., the kernel is trapped with an INT
|
||||
*
|
||||
* It also has several minor entry points to be used from the task level:
|
||||
*
|
||||
* lock_notify: send a notification to inform a process of a system event
|
||||
* lock_send: send a message to a process
|
||||
* lock_ready: put a process on one of the ready queues so it can be run
|
||||
* lock_unready: remove a process from the ready queues
|
||||
* lock_sched: a process has run too long; schedule another one
|
||||
* lock_pick_proc: pick a process to run (used by system initialization)
|
||||
* unhold: repeat all held-up notifications
|
||||
*
|
||||
* Changes:
|
||||
* 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)
|
||||
* Oct 10, 2004 require BOTH for kernel sys_call() (Jorrit N. Herder)
|
||||
* (to protect kernel tasks from being blocked)
|
||||
* Sep 25, 2004 generalized notify() function (Jorrit N. Herder)
|
||||
* 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)
|
||||
*/
|
||||
|
||||
#include "kernel.h"
|
||||
|
@ -31,18 +28,21 @@
|
|||
#include "sendmask.h"
|
||||
|
||||
|
||||
FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dest,
|
||||
/* Scheduling and message passing functions. The functions are available to
|
||||
* other parts of the kernel through lock_...(). The lock temporarily disables
|
||||
* interrupts to prevent race conditions.
|
||||
*/
|
||||
FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dst,
|
||||
message *m_ptr, int may_block) );
|
||||
FORWARD _PROTOTYPE( int mini_rec, (struct proc *caller_ptr, int src,
|
||||
message *m_ptr, int may_block) );
|
||||
FORWARD _PROTOTYPE( int mini_notify, (struct proc *caller_ptr, int dest,
|
||||
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 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,
|
||||
|
@ -61,161 +61,9 @@ FORWARD _PROTOTYPE( void cp_mess, (int src, struct proc *src_p, message *src_m,
|
|||
#endif /* (CHIP == M68000) */
|
||||
|
||||
|
||||
/* Bit mask operations used to bits of the notification mask. */
|
||||
#define set_bit(mask, n) ((mask) |= (1 << (n)))
|
||||
#define clear_bit(mask, n) ((mask) &= ~(1 << (n)))
|
||||
#define isset_bit(mask, n) ((mask) & (1 << (n)))
|
||||
|
||||
/* 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. */
|
||||
/* Declare buffer space and a bit map for notification messages. */
|
||||
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 *
|
||||
*===========================================================================*/
|
||||
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; i<NR_NOTIFY_TYPES; i++) {
|
||||
if (isset_bit(caller_ptr->p_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 {
|
||||
|
||||
/* 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,
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
unlock();
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* 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; i<NR_NOTIFY_TYPES; i++) {
|
||||
if (isset_bit(rp->p_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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue