Fixed minor bug in notify() function.
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
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
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 */
*/
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 */
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);
}
}
}
/* 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;
* 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;
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 */
}
*===========================================================================*/
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 */
+++ /dev/null
-/* 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);
-}
-
-
-
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;
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 */
* 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();
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 */
}
}
/* 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.
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 */
}
#
! 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
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? */;\
!*===========================================================================*
_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
/* 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
#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) );
/*===========================================================================*
- * 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 */
{
* 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
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 {
- /* 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();
+ /* 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;
}
+
/*===========================================================================*
* sys_call *
*===========================================================================*/
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 */
}
}
}
+/*===========================================================================*
+ * 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 *
*===========================================================================*/
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 *
*==========================================================================*/
register struct proc *rp; /* current head of held queue */
int i;
+ kinfo.notify_unhold ++;
+
if (switching) return;
rp = held_head;
do {
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
}
}
}
/* 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) );
/* 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,
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);
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);
}
}
}
* 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);
}
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);
}
* 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);
}
/* 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];
#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 *)];