Fixed some comments and reorganized some code.

Fixed minor bug in notify() function.
This commit is contained in:
Jorrit Herder 2005-05-18 10:36:23 +00:00
parent 821dfb06ed
commit 614f49b557
16 changed files with 134 additions and 161 deletions

View file

@ -22,7 +22,6 @@ HEAD = mpx.o
OBJS = start.o protect.o klibc.o klib.o table.o main.o proc.o \
i8259.o exception.o system.o clock.o misc.o \
dummy.o
SYS = system/system.a
@ -135,8 +134,6 @@ table.o: proc.h
table.o: sendmask.h
table.o: $b/int86.h
dummy.o: $a
system/system.a: $a $h/devio.h $h/com.h
system/system.a: proc.h protect.h system.h sendmask.h
system/system.a: $s/ptrace.h $s/sigcontext.h

View file

@ -42,6 +42,7 @@ FORWARD _PROTOTYPE( void init_clock, (void) );
FORWARD _PROTOTYPE( int clock_handler, (irq_hook_t *hook) );
FORWARD _PROTOTYPE( int do_clocktick, (message *m_ptr) );
/* Constant definitions. */
#define SCHED_RATE (MILLISEC*HZ/1000) /* number of ticks per schedule */
#define MILLISEC 100 /* how often to call the scheduler */
@ -80,7 +81,8 @@ PRIVATE clock_t next_timeout; /* realtime that next timer expires */
*/
PRIVATE clock_t realtime; /* real time clock */
/* Variables changed by interrupt handler. */
/* Variables for and changed by the CLOCK's interrupt handler. */
PRIVATE irq_hook_t clock_hook;
PRIVATE clock_t pending_ticks; /* ticks seen by low level only */
PRIVATE int sched_ticks = SCHED_RATE; /* counter: when 0, call scheduler */
PRIVATE struct proc *prev_ptr; /* last user process run by clock */
@ -120,10 +122,13 @@ PUBLIC void clock_task()
result = EBADREQUEST;
}
/* Send reply, unless inhibited, e.g. by do_clocktick(). */
/* Send reply, unless inhibited, e.g. by do_clocktick(). Use the kernel
* function lock_send() to prevent a system call trap. The destination
* is known to be blocked waiting for a message.
*/
if (result != EDONTREPLY) {
m.m_type = result;
send(m.m_source, &m);
lock_send(proc_addr(CLOCK), m.m_source, &m);
}
}
}
@ -138,7 +143,6 @@ message *m_ptr; /* pointer to request message */
/* Despite its name, this routine is not called on every clock tick. It
* is called on those clock ticks when a lot of work needs to be done.
*/
register struct proc *rp;
register int proc_nr;
timer_t *tp;
@ -216,7 +220,6 @@ irq_hook_t *hook;
* faster on a 5MHz 8088, and make task debugging much easier since there are
* no task switches on an inactive system.
*/
register struct proc *rp;
register unsigned ticks;
clock_t now;
@ -244,13 +247,13 @@ irq_hook_t *hook;
if (next_timeout <= now || (sched_ticks == 1 && bill_ptr == prev_ptr
&& rdy_head[PPRI_USER] != NIL_PROC))
{
notify(CLOCK, HARD_INT);
lock_notify(CLOCK, HARD_INT);
}
else if (--sched_ticks == 0) {
sched_ticks = SCHED_RATE; /* reset quantum */
prev_ptr = bill_ptr; /* new previous process */
}
return 1; /* reenable clock interrupts */
return(1); /* reenable clock interrupts */
}
@ -310,9 +313,10 @@ struct timer *tp; /* pointer to timer structure */
*===========================================================================*/
PRIVATE void init_clock()
{
/* Initialize channel 0 of the 8253A timer to, e.g., 60 Hz. */
static irq_hook_t clock_hook;
/* Initialize the CLOCK's interrupt hook. */
clock_hook.proc_nr = CLOCK;
/* Initialize channel 0 of the 8253A timer to, e.g., 60 Hz. */
outb(TIMER_MODE, SQUARE_WAVE); /* set timer to run continuously */
outb(TIMER0, TIMER_COUNT); /* load timer low byte */
outb(TIMER0, TIMER_COUNT >> 8); /* load timer high byte */

View file

@ -1,86 +0,0 @@
/* A dummy task. Used to safely remove old tasks, and get notices if they get
* called by accident (i.e., because of some bug...).
*
* Created:
* Jul 27, 2004 by Jorrit N. Herder
*/
#include "kernel.h"
#include "proc.h"
#include <minix/com.h>
/* Allocated space for the global variables. */
message m_in; /* the input message itself */
message m_out; /* the output message used for reply */
int who; /* caller's proc number */
int callnr; /* system call number */
/* Declare some local functions. */
FORWARD _PROTOTYPE(void get_work, (void) );
FORWARD _PROTOTYPE(void reply, (int whom, int result) );
/*===========================================================================*
* dummy_task *
*===========================================================================*/
PUBLIC void dummy_task()
{
/* This is the main routine of this service. In principle this should block
* forever on getting new work - the dummy task is not supposed to be called.
* If new work is received, somehow, diagnostics are printed.
*/
int result;
/* kprintf("DUMMY: do nothing kernel task started (proc. nr %d).\n",
proc_number(proc_ptr)); */
/* Main loop - get work and do it, forever. */
while (TRUE) {
/* Wait for incoming message, sets 'callnr' and 'who'. */
get_work();
/* There is work to do! (re)set some variables first. */
result = EINVAL; /* illegal send to dummy task */
/* Print diagnostics: this was not supposed to happen. */
kprintf("Dummy task: request received from %d.\n", who);
/* Finally send reply message, unless disabled. */
if (result != EDONTREPLY) {
reply(who, result);
}
}
}
/*===========================================================================*
* get_work *
*===========================================================================*/
PRIVATE void get_work()
{
int status = 0;
status = receive(ANY, &m_in); /* this blocks until message arrives */
if (OK != status)
kprintf("Dummy task failed to receive message: %d", status);
who = m_in.m_source; /* message arrived! set sender */
callnr = m_in.m_type; /* set function call number */
}
/*===========================================================================*
* reply *
*===========================================================================*/
PRIVATE void reply(who, result)
int who; /* destination */
int result; /* report result to replyee */
{
int send_status;
m_out.m_type = result; /* build reply message */
send_status = send(who, &m_out); /* send the message */
if (OK != send_status)
kprintf("Dummy task unable to send reply: %d", send_status);
}

View file

@ -55,7 +55,7 @@ unsigned vec_nr;
return;
}
if (k_reenter == 0 && isuserp(saved_proc)) {
if (k_reenter == 0 && ! istaskp(saved_proc)) {
unlock(); /* this is protected like sys_call() */
cause_sig(proc_number(saved_proc), ep->signum);
return;

View file

@ -27,6 +27,7 @@ EXTERN struct memory mem[NR_MEMS]; /* base and size of chunks of memory */
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 */

View file

@ -42,7 +42,6 @@ int mine;
* use the BIOS locations instead. The flag "mine" is set if the 8259s are
* to be programmed for Minix, or to be reset to what the BIOS expects.
*/
int i;
lock();

View file

@ -160,7 +160,7 @@ int c; /* character to append */
kmess.km_size += 1;
kmess.km_next = (kmess.km_next + 1) % KMESS_BUF_SIZE;
} else {
notify(TTY, NEW_KMESS); /* let TTY display the message */
lock_notify(TTY, NEW_KMESS); /* let TTY display the message */
}
}

View file

@ -234,7 +234,7 @@ 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.
*/
notify(TTY, HARD_STOP); /* let TTY switch to console 0 */
lock_notify(TTY, HARD_STOP); /* let TTY switch to console 0 */
/* Run the stop sequence. The timer argument passes the shutdown status.
* The stop sequence is skipped for fatal CPU exceptions.
@ -289,7 +289,7 @@ timer_t *tp;
kprintf("- Stopping %s ", karg(p->p_name));
kprintf("%s ... ", karg(types[p->p_type]));
shutdown_process = p; /* directly continue if exited */
notify(proc_number(p), HARD_STOP);
lock_notify(proc_number(p), HARD_STOP);
set_timer(tp, get_uptime()+STOP_TICKS, stop_sequence);
return; /* allow the process to shut down */
}

View file

@ -1,24 +1,19 @@
#
! This file, mpx386.s, is included by mpx.s when Minix is compiled for
! 32-bit Intel CPUs. The alternative mpx88.s is compiled for 16-bit CPUs.
!
! This contains the assembler startup code for Minix and the 32-bit
! interrupt handlers. It cooperates with start.c to set up a good
! environment for main().
! This file is part of the lowest layer of the MINIX kernel. The other part
! is "proc.c". The lowest layer does process switching and message handling.
! This file is part of the lowest layer of the MINIX kernel. (The other part
! is "proc.c".) The lowest layer does process switching and message handling.
! Furthermore it contains the assembler startup code for Minix and the 32-bit
! interrupt handlers. It cooperates with the code in "start.c" to set up a
! good environment for main().
! Every transition to the kernel goes through this file. Transitions are
! caused by sending/receiving messages and by most interrupts. (RS232
! interrupts may be handled in the file "rs2.s" and then they rarely enter
! the kernel.)
! Transitions to the kernel may be nested. The initial entry may be with a
! system call, exception or hardware interrupt; reentries may only be made
! by hardware interrupts. The count of reentries is kept in "k_reenter".
! It is important for deciding whether to switch to the kernel stack and
! for protecting the message passing code in "proc.c".
! Every transition to the kernel goes through this file. Transitions to the
! kernel may be nested. The initial entry may be with a system call (i.e.,
! send or receive a message), an exception or a hardware interrupt; kernel
! reentries may only be made by hardware interrupts. The count of reentries
! is kept in "k_reenter". It is important for deciding whether to switch to
! the kernel stack and for protecting the message passing code in "proc.c".
! For the message passing trap, most of the machine state is saved in the
! proc table. (Some of the registers need not be saved.) Then the stack is
@ -226,7 +221,7 @@ csinit:
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]) */;\
call _intr_handle /* intr_handle(irq_handlers[irq]) */;\
cli /* disable interrupts */;\
pop ecx ;\
cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\
@ -397,13 +392,15 @@ _p_s_call:
!*===========================================================================*
_restart:
! Flush any held-up interrupts.
! 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.
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

View file

@ -1,11 +1,12 @@
/* This file contains essentially all of the process and message handling.
* It has two main entry points from the outside:
*
* sys_call: a system call, that is, the kernel is trapped with an INT
* notify: notify process of a system event (notifications aren't queued)
* 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
*
* It also has several minor entry points:
* It also has several minor entry points to be used from the task level:
*
* 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
@ -31,12 +32,13 @@
#include "proc.h"
#include "sendmask.h"
PRIVATE unsigned char switching; /* nonzero to inhibit notify() */
FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dest,
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,
message *m_ptr ) );
FORWARD _PROTOTYPE( void ready, (struct proc *rp) );
FORWARD _PROTOTYPE( void sched, (void) );
FORWARD _PROTOTYPE( void unready, (struct proc *rp) );
@ -66,9 +68,9 @@ FORWARD _PROTOTYPE( void cp_mess, (int src, struct proc *src_p, message *src_m,
/*===========================================================================*
* notify *
* lock_notify *
*===========================================================================*/
PUBLIC void notify(proc_nr, notify_type)
PUBLIC void lock_notify(proc_nr, notify_type)
int proc_nr; /* number of process to be started */
int notify_type; /* notification to be sent */
{
@ -104,8 +106,19 @@ int notify_type; /* notification to be sent */
* handler might call notify() and pass the 'k_reenter' test.
*/
if (k_reenter != 0 || switching) {
lock();
if (! rp->p_ntf_held) { /* already on held queue? */
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
@ -117,32 +130,35 @@ int notify_type; /* notification to be sent */
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 process is not waiting for a notification, record the blockage. */
if ( (rp->p_flags & (RECEIVING | SENDING)) != RECEIVING ||
!isrxhardware(rp->p_getfrom)) {
set_bit(rp->p_ntf_blocked, notify_bit); /* add bit to blocked mask */
switching = FALSE;
return;
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();
}
/* Destination is waiting for a notification. Send it a message with source
* HARDWARE and type 'notify_type'. No more information can be reliably
* provided since notifications are not queued.
*/
m.m_source = HARDWARE; /* direct copy does not work for servers */
m.m_type = notify_type;
CopyMess(HARDWARE, proc_addr(HARDWARE), &m, rp, rp->p_messbuf);
rp->p_flags &= ~RECEIVING;
clear_bit(rp->p_ntf_blocked, notify_bit);
/* Announce the process ready and select a fresh process to run. */
ready(rp);
pick_proc();
switching = FALSE;
}
/*===========================================================================*
* sys_call *
*===========================================================================*/
@ -203,6 +219,9 @@ message *m_ptr; /* pointer to message in the caller's space */
case RECEIVE:
result = mini_rec(caller_ptr, src_dst, m_ptr, may_block);
break;
case NOTIFY:
result = mini_notify(caller_ptr, src_dst, m_ptr);
break;
default:
result = EBADCALL; /* illegal system call */
}
@ -366,6 +385,20 @@ 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 */
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);
return(OK);
}
/*===========================================================================*
* pick_proc *
*===========================================================================*/
@ -496,6 +529,24 @@ PUBLIC void lock_pick_proc()
switching = FALSE;
}
/*==========================================================================*
* 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 */
{
/* Safe gateway to mini_send() for tasks. */
int result;
switching = TRUE;
result = mini_send(caller_ptr, dest, m_ptr, FALSE);
switching = FALSE;
return(result);
}
/*==========================================================================*
* lock_ready *
*==========================================================================*/
@ -543,6 +594,8 @@ PUBLIC void unhold()
register struct proc *rp; /* current head of held queue */
int i;
kinfo.notify_unhold ++;
if (switching) return;
rp = held_head;
do {
@ -552,9 +605,13 @@ PUBLIC void unhold()
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! */
notify(proc_number(rp), NOTIFICATION + i);
#endif
lock_notify(proc_number(rp), NOTIFICATION + i);
#if DEAD_CODE
lock(); /* protect the held queue again */
#endif
}
}
}

View file

@ -5,12 +5,8 @@
/* Struct declarations. */
struct proc;
struct time_info;
struct timer;
/* dummy.c */
_PROTOTYPE( void dummy_task, (void) );
/* clock.c */
_PROTOTYPE( void clock_task, (void) );
_PROTOTYPE( void clock_stop, (void) );
@ -37,20 +33,21 @@ _PROTOTYPE( void kprintf, (const char *fmt, karg_t arg) );
/* main.c */
_PROTOTYPE( void main, (void) );
_PROTOTYPE( void prepare_shutdown, (int) );
_PROTOTYPE( void stop_sequence, (struct timer *tp) );
_PROTOTYPE( void prepare_shutdown, (int) );
_PROTOTYPE( void stop_sequence, (struct timer *tp) );
/* misc.c */
_PROTOTYPE( void panic, (_CONST char *s, int n) );
/* proc.c */
_PROTOTYPE( int sys_call, (int function, int src_dest, message *m_ptr) );
_PROTOTYPE( void notify, (int proc_nr, int notify_type) );
_PROTOTYPE( void unhold, (void) );
_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,

View file

@ -57,6 +57,8 @@ U16_t parmoff, parmsize; /* boot parameters offset and length */
phys_copy(kinfo.params_base, vir2phys(k_environ), kinfo.params_size);
/* Record miscellaneous information for user-space servers. */
kinfo.nr_procs = NR_PROCS;
kinfo.nr_tasks = NR_TASKS;
kstrncpy(kinfo.version, OS_RELEASE "." OS_VERSION, 6);
kinfo.proc_addr = (vir_bytes) proc;
kinfo.kmem_base = vir2phys(0);

View file

@ -83,10 +83,13 @@ PUBLIC void sys_task()
result = EBADREQUEST; /* illegal message type */
}
/* Send a reply, unless inhibited by a handler function. */
/* Send a reply, unless inhibited by a handler function. Use the kernel
* function lock_send() to prevent a system call trap. The destination
* is known to be blocked waiting for a message.
*/
if (result != EDONTREPLY) {
m.m_type = result; /* report status of call */
send(m.m_source, &m); /* send reply to caller */
lock_send(proc_addr(SYSTASK), m.m_source, &m);
}
}
}
@ -240,7 +243,7 @@ irq_hook_t *hook;
* interrupts are transformed into messages to a driver. The IRQ line will be
* reenabled if the policy says so.
*/
notify(hook->proc_nr, HARD_INT);
lock_notify(hook->proc_nr, HARD_INT);
return(hook->policy & IRQ_REENABLE);
}
@ -275,7 +278,7 @@ 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;
notify(PM_PROC_NR, KSIG_PENDING);
lock_notify(PM_PROC_NR, KSIG_PENDING);
}

View file

@ -164,7 +164,7 @@ timer_t *tp;
* alarm. The process number is stored in timer argument 'ta_int'. Notify that
* process given with a SYN_ALARM message.
*/
notify(tmr_arg(tp)->ta_int, SYN_ALARM);
lock_notify(tmr_arg(tp)->ta_int, SYN_ALARM);
}

View file

@ -236,6 +236,8 @@ register message *m_ptr; /* pointer to request message */
/* Request a (DMA) buffer to be allocated in one of the memory chunks. */
phys_clicks tot_clicks;
struct memory *memp;
kprintf("SYS_KMALLOC called by %d\n", m_ptr->m_source);
tot_clicks = (m_ptr->MEM_CHUNK_SIZE + CLICK_SIZE-1) >> CLICK_SHIFT;
memp = &mem[NR_MEMS];

View file

@ -49,7 +49,7 @@
#define CLOCK_STACK SMALL_STACK
/* Stack space for all the task stacks. Declared as (char *) to align it. */
#define TOT_STACK_SPACE (IDLE_STACK+HARDWARE_STACK+CLOCK_STACK+SYS_STACK )
#define TOT_STACK_SPACE (IDLE_STACK+HARDWARE_STACK+CLOCK_STACK+SYS_STACK)
PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)];