* Fixed bug relating to nested locking in interrupt handlers. The nested lock
caused interrupts to be reenabled (due to unlock), which caused a race. The problems were especially visible on slower machines. * Relocated free memory parsing to process manager. This saved quite some code at the kernel level. Text size was reduced by about 650 bytes. * Removed locks for updating the realtime in the clock's main loop and the get_uptime function. Interrupts are no longer reentrant, so realtime is immediately updated.
This commit is contained in:
parent
90b80ad31e
commit
e0a98a4d65
13 changed files with 76 additions and 206 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
#define NEW_TIME_COUNT 1
|
||||||
/* The file contais the clock task, which handles all time related functions.
|
/* The file contais the clock task, which handles all time related functions.
|
||||||
* Important events that are handled by the CLOCK include alarm timers and
|
* Important events that are handled by the CLOCK include alarm timers and
|
||||||
* (re)scheduling user processes.
|
* (re)scheduling user processes.
|
||||||
|
@ -84,7 +85,9 @@ PRIVATE clock_t realtime; /* real time clock */
|
||||||
|
|
||||||
/* Variables for and changed by the CLOCK's interrupt handler. */
|
/* Variables for and changed by the CLOCK's interrupt handler. */
|
||||||
PRIVATE irq_hook_t clock_hook;
|
PRIVATE irq_hook_t clock_hook;
|
||||||
|
#if ! NEW_TIME_COUNT
|
||||||
PRIVATE clock_t pending_ticks; /* ticks seen by low level only */
|
PRIVATE clock_t pending_ticks; /* ticks seen by low level only */
|
||||||
|
#endif
|
||||||
PRIVATE int sched_ticks = SCHED_RATE; /* counter: when 0, call scheduler */
|
PRIVATE int sched_ticks = SCHED_RATE; /* counter: when 0, call scheduler */
|
||||||
PRIVATE struct proc *prev_ptr; /* last user process run by clock */
|
PRIVATE struct proc *prev_ptr; /* last user process run by clock */
|
||||||
|
|
||||||
|
@ -107,11 +110,13 @@ PUBLIC void clock_task()
|
||||||
/* Go get a message. */
|
/* Go get a message. */
|
||||||
receive(ANY, &m);
|
receive(ANY, &m);
|
||||||
|
|
||||||
|
#if ! NEW_TIME_COUNT
|
||||||
/* Transfer ticks seen by the low level handler. */
|
/* Transfer ticks seen by the low level handler. */
|
||||||
lock(8, "realtime");
|
lock(8, "realtime");
|
||||||
realtime += pending_ticks;
|
realtime += pending_ticks;
|
||||||
pending_ticks = 0;
|
pending_ticks = 0;
|
||||||
unlock(8);
|
unlock(8);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Handle the request. */
|
/* Handle the request. */
|
||||||
switch (m.m_type) {
|
switch (m.m_type) {
|
||||||
|
@ -202,10 +207,12 @@ irq_hook_t *hook;
|
||||||
* The variables which are changed require more care:
|
* The variables which are changed require more care:
|
||||||
* rp->p_user_time, rp->p_sys_time:
|
* rp->p_user_time, rp->p_sys_time:
|
||||||
* These are protected by explicit locks in system.c.
|
* These are protected by explicit locks in system.c.
|
||||||
|
#if ! NEW_TIME_COUNT
|
||||||
* pending_ticks:
|
* pending_ticks:
|
||||||
* This is protected by explicit locks in clock.c. Don't
|
* This is protected by explicit locks in clock.c. Don't
|
||||||
* update realtime directly, since there are too many
|
* update realtime directly, since there are too many
|
||||||
* references to it to guard conveniently.
|
* references to it to guard conveniently.
|
||||||
|
#endif
|
||||||
* lost_ticks:
|
* lost_ticks:
|
||||||
* Clock ticks counted outside the clock task.
|
* Clock ticks counted outside the clock task.
|
||||||
* sched_ticks, prev_ptr:
|
* sched_ticks, prev_ptr:
|
||||||
|
@ -222,7 +229,9 @@ irq_hook_t *hook;
|
||||||
register struct proc *rp;
|
register struct proc *rp;
|
||||||
register unsigned ticks;
|
register unsigned ticks;
|
||||||
message m;
|
message m;
|
||||||
|
#if ! NEW_TIME_COUNT
|
||||||
clock_t now;
|
clock_t now;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Acknowledge the PS/2 clock interrupt. */
|
/* Acknowledge the PS/2 clock interrupt. */
|
||||||
if (machine.ps_mca) outb(PORT_B, inb(PORT_B) | CLOCK_ACK_BIT);
|
if (machine.ps_mca) outb(PORT_B, inb(PORT_B) | CLOCK_ACK_BIT);
|
||||||
|
@ -232,10 +241,16 @@ irq_hook_t *hook;
|
||||||
* process is running, charge the billable process for system time as well.
|
* process is running, charge the billable process for system time as well.
|
||||||
* Thus the unbillable process' user time is the billable user's system time.
|
* Thus the unbillable process' user time is the billable user's system time.
|
||||||
*/
|
*/
|
||||||
|
#if NEW_TIME_COUNT
|
||||||
|
ticks = lost_ticks + 1;
|
||||||
|
lost_ticks = 0;
|
||||||
|
realtime += ticks;
|
||||||
|
#else
|
||||||
ticks = lost_ticks + 1;
|
ticks = lost_ticks + 1;
|
||||||
lost_ticks = 0;
|
lost_ticks = 0;
|
||||||
pending_ticks += ticks;
|
pending_ticks += ticks;
|
||||||
now = realtime + pending_ticks;
|
now = realtime + pending_ticks;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Update administration. */
|
/* Update administration. */
|
||||||
proc_ptr->p_user_time += ticks;
|
proc_ptr->p_user_time += ticks;
|
||||||
|
@ -244,11 +259,15 @@ irq_hook_t *hook;
|
||||||
/* Check if do_clocktick() must be called. Done for alarms and scheduling.
|
/* Check if do_clocktick() must be called. Done for alarms and scheduling.
|
||||||
* If bill_ptr == prev_ptr, there are no ready users so don't need sched().
|
* If bill_ptr == prev_ptr, there are no ready users so don't need sched().
|
||||||
*/
|
*/
|
||||||
|
#if NEW_TIME_COUNT
|
||||||
|
if (next_timeout <= realtime || (sched_ticks == 1 && bill_ptr == prev_ptr
|
||||||
|
#else
|
||||||
if (next_timeout <= now || (sched_ticks == 1 && bill_ptr == prev_ptr
|
if (next_timeout <= now || (sched_ticks == 1 && bill_ptr == prev_ptr
|
||||||
|
#endif
|
||||||
&& rdy_head[PPRI_USER] != NIL_PROC))
|
&& rdy_head[PPRI_USER] != NIL_PROC))
|
||||||
{
|
{
|
||||||
m.NOTIFY_TYPE = HARD_INT;
|
m.NOTIFY_TYPE = HARD_INT;
|
||||||
lock_notify(CLOCK, &m);
|
int_notify(CLOCK, &m);
|
||||||
}
|
}
|
||||||
else if (--sched_ticks <= 0) {
|
else if (--sched_ticks <= 0) {
|
||||||
sched_ticks = SCHED_RATE; /* reset the quantum */
|
sched_ticks = SCHED_RATE; /* reset the quantum */
|
||||||
|
@ -266,12 +285,16 @@ PUBLIC clock_t get_uptime()
|
||||||
/* Get and return the current clock uptime in ticks.
|
/* Get and return the current clock uptime in ticks.
|
||||||
* Be careful about pending_ticks.
|
* Be careful about pending_ticks.
|
||||||
*/
|
*/
|
||||||
|
#if NEW_TIME_COUNT
|
||||||
|
return(realtime);
|
||||||
|
#else
|
||||||
clock_t uptime;
|
clock_t uptime;
|
||||||
|
|
||||||
lock(9, "get_uptime");
|
lock(9, "get_uptime");
|
||||||
uptime = realtime + pending_ticks;
|
uptime = realtime + pending_ticks;
|
||||||
unlock(9);
|
unlock(9);
|
||||||
return(uptime);
|
return(uptime);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ unsigned vec_nr;
|
||||||
ep = &ex_data[vec_nr];
|
ep = &ex_data[vec_nr];
|
||||||
|
|
||||||
if (vec_nr == 2) { /* spurious NMI on some machines */
|
if (vec_nr == 2) { /* spurious NMI on some machines */
|
||||||
kprintf("got spurious NMI\n",NO_ARG);
|
kprintf("got spurious NMI\n",NO_NUM);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,19 +68,7 @@ unsigned vec_nr;
|
||||||
kprintf("pc = %d:", (unsigned) saved_proc->p_reg.cs);
|
kprintf("pc = %d:", (unsigned) saved_proc->p_reg.cs);
|
||||||
kprintf("0x%x\n", (unsigned) saved_proc->p_reg.pc);
|
kprintf("0x%x\n", (unsigned) saved_proc->p_reg.pc);
|
||||||
|
|
||||||
/* If the exception originates in the kernel, shut down MINIX. Otherwise,
|
|
||||||
* kill the process that caused it. If MINIX is shut down and the stop
|
|
||||||
* sequence is skipped, the kprintf() output cannot be flushed by the TTY
|
|
||||||
* driver. This leaves the user with a hanging system without proper
|
|
||||||
* notification ...
|
|
||||||
*/
|
|
||||||
if (istaskp(saved_proc)) { /* serious problem */
|
|
||||||
kernel_exception = TRUE; /* directly shutdown */
|
kernel_exception = TRUE; /* directly shutdown */
|
||||||
panic("exception in a kernel task", NO_NUM);
|
panic("exception in a kernel task", NO_NUM);
|
||||||
} else {
|
|
||||||
clear_proc(saved_proc->p_nr);
|
|
||||||
kprintf("%s was killed by MINIX due to an exception",
|
|
||||||
karg(saved_proc->p_name));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ EXTERN struct kinfo kinfo; /* kernel information for users */
|
||||||
EXTERN struct machine machine; /* machine information for users */
|
EXTERN struct machine machine; /* machine information for users */
|
||||||
EXTERN struct kmessages kmess; /* diagnostic messages in kernel */
|
EXTERN struct kmessages kmess; /* diagnostic messages in kernel */
|
||||||
EXTERN struct randomness krandom; /* gather kernel random information */
|
EXTERN struct randomness krandom; /* gather kernel random information */
|
||||||
EXTERN struct memory mem[NR_MEMS]; /* base and size of chunks of memory */
|
|
||||||
|
|
||||||
/* Process scheduling information and the kernel reentry count. */
|
/* Process scheduling information and the kernel reentry count. */
|
||||||
EXTERN struct proc *proc_ptr; /* pointer to currently running process */
|
EXTERN struct proc *proc_ptr; /* pointer to currently running process */
|
||||||
|
|
|
@ -45,7 +45,7 @@ int mine;
|
||||||
/* Initialize the 8259s, finishing with all interrupts disabled. This is
|
/* Initialize the 8259s, finishing with all interrupts disabled. This is
|
||||||
* only done in protected mode, in real mode we don't touch the 8259s, but
|
* only done in protected mode, in real mode we don't touch the 8259s, but
|
||||||
* use the BIOS locations instead. The flag "mine" is set if the 8259s are
|
* 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.
|
* to be programmed for MINIX, or to be reset to what the BIOS expects.
|
||||||
*/
|
*/
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
* kstrcmp: lexicographical comparison of two strings
|
* kstrcmp: lexicographical comparison of two strings
|
||||||
* kstrlen: get number of non-null characters in string
|
* kstrlen: get number of non-null characters in string
|
||||||
* kstrncpy: copy string and pad or copy up to n chars
|
* kstrncpy: copy string and pad or copy up to n chars
|
||||||
* kstrtoulb: convert string to unsigned long value
|
|
||||||
*
|
*
|
||||||
* This file contains the routines that take care of kernel messages, i.e.,
|
* This file contains the routines that take care of kernel messages, i.e.,
|
||||||
* diagnostic output within the kernel. Kernel messages are not directly
|
* diagnostic output within the kernel. Kernel messages are not directly
|
||||||
|
@ -152,7 +151,7 @@ PRIVATE void kputc(c)
|
||||||
int c; /* character to append */
|
int c; /* character to append */
|
||||||
{
|
{
|
||||||
/* Accumulate a single character for a kernel message. Send a notification
|
/* 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.
|
* the to TTY driver if an END_OF_KMESS is encountered.
|
||||||
*/
|
*/
|
||||||
message m;
|
message m;
|
||||||
if (c != END_OF_KMESS) {
|
if (c != END_OF_KMESS) {
|
||||||
|
@ -225,45 +224,3 @@ PUBLIC char *kstrncpy(char *ret, register const char *s2, register size_t n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*=========================================================================*
|
|
||||||
* kstrtoul *
|
|
||||||
*=========================================================================*/
|
|
||||||
PUBLIC unsigned long kstrtoul(strptr, endptr, base)
|
|
||||||
const char *strptr; /* pointer to string to be parsed */
|
|
||||||
char ** const endptr; /* store pointer to end here */
|
|
||||||
int base;
|
|
||||||
{
|
|
||||||
/* A simplified version of strtoul() for the kernel to prevent including the
|
|
||||||
* one in the ASNI library. No whitespaces are skipped, the numeric value is
|
|
||||||
* expected at the start of 'string'.
|
|
||||||
*/
|
|
||||||
register unsigned long val = 0;
|
|
||||||
register int c;
|
|
||||||
register unsigned int v;
|
|
||||||
int overflow = 0;
|
|
||||||
|
|
||||||
/* Get rid of 0x or 0X for hexidecimal values. */
|
|
||||||
if (base==16 && *strptr=='0' && (*++strptr=='x' || *strptr=='X'))
|
|
||||||
strptr++;
|
|
||||||
|
|
||||||
/* Now parse the actual unsigned long number. */
|
|
||||||
for (;;) {
|
|
||||||
c = *strptr;
|
|
||||||
if ('0' <= c && c <= '9') v = c - '0';
|
|
||||||
else if ('a' <= c && c <= 'z') v = c - 'a' + 0xa;
|
|
||||||
else if ('A' <= c && c <= 'Z') v = c - 'A' + 0xA;
|
|
||||||
else break; /* end of number */
|
|
||||||
if (v >= base) break; /* end of number */
|
|
||||||
if (val > (ULONG_MAX - v) / base) overflow = 1;
|
|
||||||
val = (val*base) + v;
|
|
||||||
strptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tell caller where parsing ended unless a NULL pointer was passed. */
|
|
||||||
if (endptr) *endptr = (char *) strptr;
|
|
||||||
|
|
||||||
/* Done, return parsed value or maximum value on overflow. */
|
|
||||||
return (overflow) ? ULONG_MAX : val;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -114,19 +114,6 @@ PUBLIC void main()
|
||||||
rp->p_memmap[S].mem_phys = text_base + text_clicks + data_clicks;
|
rp->p_memmap[S].mem_phys = text_base + text_clicks + data_clicks;
|
||||||
rp->p_memmap[S].mem_vir = data_clicks; /* empty - stack is in data */
|
rp->p_memmap[S].mem_vir = data_clicks; /* empty - stack is in data */
|
||||||
|
|
||||||
/* Remove server memory from the free memory list. The boot monitor
|
|
||||||
* promises to put processes at the start of memory chunks. The
|
|
||||||
* tasks all use same base address, so only the first task changes
|
|
||||||
* the memory lists. The servers and init have their own memory
|
|
||||||
* spaces and their memory will be removed from the list.
|
|
||||||
*/
|
|
||||||
for (memp = mem; memp < &mem[NR_MEMS]; memp++) {
|
|
||||||
if (memp->base == text_base) {
|
|
||||||
memp->base += text_clicks + data_clicks;
|
|
||||||
memp->size -= text_clicks + data_clicks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set initial register values. The processor status word for tasks
|
/* Set initial register values. The processor status word for tasks
|
||||||
* is different from that of other processes because tasks can
|
* is different from that of other processes because tasks can
|
||||||
* access I/O; this is not allowed to less-privileged processes
|
* access I/O; this is not allowed to less-privileged processes
|
||||||
|
@ -144,7 +131,6 @@ PUBLIC void main()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set ready. The HARDWARE task is never ready. */
|
/* Set ready. The HARDWARE task is never ready. */
|
||||||
|
|
||||||
#if ENABLE_K_DEBUGGING
|
#if ENABLE_K_DEBUGGING
|
||||||
rp->p_ready = 0;
|
rp->p_ready = 0;
|
||||||
#endif
|
#endif
|
||||||
|
@ -163,30 +149,16 @@ PUBLIC void main()
|
||||||
hdrindex ++;
|
hdrindex ++;
|
||||||
phys_copy(aout + hdrindex * A_MINHDR,vir2phys(&e_hdr),(phys_bytes) A_MINHDR);
|
phys_copy(aout + hdrindex * A_MINHDR,vir2phys(&e_hdr),(phys_bytes) A_MINHDR);
|
||||||
if (e_hdr.a_flags & A_IMG) {
|
if (e_hdr.a_flags & A_IMG) {
|
||||||
|
|
||||||
kinfo.bootdev_base = e_hdr.a_syms;
|
kinfo.bootdev_base = e_hdr.a_syms;
|
||||||
kinfo.bootdev_size = e_hdr.a_data;
|
kinfo.bootdev_size = e_hdr.a_data;
|
||||||
|
|
||||||
/* Remove from free list, to prevent being overwritten. */
|
|
||||||
bootdev_base = e_hdr.a_syms >> CLICK_SHIFT;
|
|
||||||
bootdev_clicks = (e_hdr.a_total + CLICK_SIZE-1) >> CLICK_SHIFT;
|
|
||||||
for (memp = mem; memp < &mem[NR_MEMS]; memp++) {
|
|
||||||
if (memp->base == bootdev_base) {
|
|
||||||
memp->base += bootdev_clicks;
|
|
||||||
memp->size -= bootdev_clicks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This actually is not needed, because ready() already set 'proc_ptr.' */
|
/* MINIX is now ready. All boot image processes are on the ready queue.
|
||||||
lock_pick_proc();
|
* Return to the assembly code to start running the current process.
|
||||||
bill_ptr = proc_addr(IDLE); /* it has to point somewhere */
|
|
||||||
|
|
||||||
/* MINIX is now ready. Display the startup banner to the user and return
|
|
||||||
* to the assembly code to start running the current process.
|
|
||||||
*/
|
*/
|
||||||
announce();
|
bill_ptr = proc_addr(IDLE); /* it has to point somewhere */
|
||||||
|
announce(); /* print MINIX startup banner */
|
||||||
restart();
|
restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +171,7 @@ PRIVATE void announce(void)
|
||||||
{
|
{
|
||||||
/* Display the MINIX startup banner. */
|
/* Display the MINIX startup banner. */
|
||||||
kprintf("MINIX %s. Copyright 2001 Prentice-Hall, Inc.\n",
|
kprintf("MINIX %s. Copyright 2001 Prentice-Hall, Inc.\n",
|
||||||
karg(kinfo.version));
|
karg(OS_RELEASE "." OS_VERSION));
|
||||||
|
|
||||||
#if (CHIP == INTEL)
|
#if (CHIP == INTEL)
|
||||||
/* Real mode, or 16/32-bit protected mode? */
|
/* Real mode, or 16/32-bit protected mode? */
|
||||||
|
@ -249,10 +221,10 @@ int how; /* 0 = halt, 1 = reboot, 2 = panic!, ... */
|
||||||
shutting_down = TRUE; /* flag for sys_exit() */
|
shutting_down = TRUE; /* flag for sys_exit() */
|
||||||
tmr_arg(&shutdown_timer)->ta_int = how; /* pass how in timer */
|
tmr_arg(&shutdown_timer)->ta_int = how; /* pass how in timer */
|
||||||
if (kernel_exception) { /* set in exception() */
|
if (kernel_exception) { /* set in exception() */
|
||||||
kprintf("\nAn exception occured; skipping stop sequence.\n", NO_ARG);
|
kprintf("\nAn exception occured; skipping stop sequence.\n", NO_NUM);
|
||||||
shutdown(&shutdown_timer); /* TTY isn't scheduled */
|
shutdown(&shutdown_timer); /* TTY isn't scheduled */
|
||||||
} else {
|
} else {
|
||||||
kprintf("\nNotifying system services about MINIX shutdown.\n", NO_ARG);
|
kprintf("\nNotifying system services about MINIX shutdown.\n", NO_NUM);
|
||||||
set_timer(&shutdown_timer, get_uptime(), stop_sequence);
|
set_timer(&shutdown_timer, get_uptime(), stop_sequence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ int n;
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
kprintf("\nKernel panic: %s", karg(s));
|
kprintf("\nKernel panic: %s", karg(s));
|
||||||
if (n != NO_NUM) kprintf(" %d", n);
|
if (n != NO_NUM) kprintf(" %d", n);
|
||||||
kprintf("\n",NO_ARG);
|
kprintf("\n",NO_NUM);
|
||||||
}
|
}
|
||||||
prepare_shutdown(RBT_PANIC);
|
prepare_shutdown(RBT_PANIC);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#define NEW_ELOCKED_CHECK 1
|
#define NEW_ELOCKED_CHECK 1
|
||||||
#define NEW_SCHED_Q 1
|
#define NEW_SCHED_Q 0
|
||||||
#define OLD_SEND 0
|
#define OLD_SEND 0
|
||||||
#define OLD_RECV 0
|
#define OLD_RECV 0
|
||||||
/* This file contains essentially all of the process and message handling.
|
/* This file contains essentially all of the process and message handling.
|
||||||
|
@ -11,11 +11,11 @@
|
||||||
* As well as several entry points used from the interrupt and task level:
|
* As well as several entry points used from the interrupt and task level:
|
||||||
*
|
*
|
||||||
* lock_notify: send a notification to inform a process of a system event
|
* lock_notify: send a notification to inform a process of a system event
|
||||||
|
* int_notify: same as above, but from an interrupt handler (no locking)
|
||||||
* lock_send: send a message to a process
|
* 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_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_unready: remove a process from the ready queues
|
||||||
* lock_sched: a process has run too long; schedule another one
|
* lock_sched: a process has run too long; schedule another one
|
||||||
* lock_pick_proc: pick a process to run (used by system initialization)
|
|
||||||
*
|
*
|
||||||
* Changes:
|
* Changes:
|
||||||
* , 2005 better protection in sys_call() (Jorrit N. Herder)
|
* , 2005 better protection in sys_call() (Jorrit N. Herder)
|
||||||
|
@ -438,13 +438,12 @@ PUBLIC int lock_notify(dst, m_ptr)
|
||||||
int dst; /* to whom is message being sent? */
|
int dst; /* to whom is message being sent? */
|
||||||
message *m_ptr; /* pointer to message buffer */
|
message *m_ptr; /* pointer to message buffer */
|
||||||
{
|
{
|
||||||
/* Safe gateway to mini_notify() for tasks and interrupt handlers. This
|
/* Safe gateway to mini_notify() for tasks. Don't use this function from the
|
||||||
* function checks if it is called from an interrupt handler and ensures
|
* interrupt level, as it will reenable interrupts (because of the unlock()
|
||||||
* that the correct message source is put on the notification.
|
* call). For interrupt handlers, int_notify() is available.
|
||||||
*/
|
*/
|
||||||
int result;
|
int result;
|
||||||
struct proc *caller_ptr;
|
register struct proc *caller_ptr;
|
||||||
|
|
||||||
lock(0, "notify");
|
lock(0, "notify");
|
||||||
caller_ptr = (k_reenter >= 0) ? proc_addr(HARDWARE) : proc_ptr;
|
caller_ptr = (k_reenter >= 0) ? proc_addr(HARDWARE) : proc_ptr;
|
||||||
result = mini_notify(caller_ptr, dst, m_ptr);
|
result = mini_notify(caller_ptr, dst, m_ptr);
|
||||||
|
@ -452,6 +451,24 @@ message *m_ptr; /* pointer to message buffer */
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* int_notify *
|
||||||
|
*==========================================================================*/
|
||||||
|
PUBLIC int int_notify(dst, m_ptr)
|
||||||
|
int dst; /* to whom is message being sent? */
|
||||||
|
message *m_ptr; /* pointer to message buffer */
|
||||||
|
{
|
||||||
|
/* Gateway to mini_notify() for interrupt handlers. This function doesn't
|
||||||
|
* use lock() and unlock() because interrupts are already disabled.
|
||||||
|
*/
|
||||||
|
int result;
|
||||||
|
register struct proc *caller_ptr = proc_addr(HARDWARE);
|
||||||
|
result = mini_notify(caller_ptr, dst, m_ptr);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* pick_proc *
|
* pick_proc *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -627,25 +644,14 @@ int queue;
|
||||||
xp->p_nextready = NIL_PROC; /* mark new end of queue */
|
xp->p_nextready = NIL_PROC; /* mark new end of queue */
|
||||||
|
|
||||||
#else
|
#else
|
||||||
rdy_tail[queue]->p_nextready = rdy_head[queue];
|
rdy_tail[queue]->p_nextready = rdy_head[queue]; /* add expired to end */
|
||||||
rdy_tail[queue] = rdy_head[queue];
|
rdy_tail[queue] = rdy_head[queue]; /* set new tail */
|
||||||
rdy_head[queue] = rdy_head[queue]->p_nextready;
|
rdy_head[queue] = rdy_head[queue]->p_nextready; /* set new head */
|
||||||
rdy_tail[queue]->p_nextready = NIL_PROC;
|
rdy_tail[queue]->p_nextready = NIL_PROC; /* mark new end */
|
||||||
#endif
|
#endif
|
||||||
pick_proc();
|
pick_proc();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
|
||||||
* lock_pick_proc *
|
|
||||||
*==========================================================================*/
|
|
||||||
PUBLIC void lock_pick_proc()
|
|
||||||
{
|
|
||||||
/* Safe gateway to pick_proc() for tasks. */
|
|
||||||
lock(1, "pick_proc");
|
|
||||||
pick_proc();
|
|
||||||
unlock(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* lock_send *
|
* lock_send *
|
||||||
|
|
|
@ -25,9 +25,6 @@ _PROTOTYPE( int kstrncmp,
|
||||||
(register const char *s1, register const char *s2, register size_t n));
|
(register const char *s1, register const char *s2, register size_t n));
|
||||||
_PROTOTYPE( char *kstrncpy,
|
_PROTOTYPE( char *kstrncpy,
|
||||||
(char *s1, register const char *s2, register const size_t n));
|
(char *s1, register const char *s2, register const size_t n));
|
||||||
_PROTOTYPE( unsigned long kstrtoul,
|
|
||||||
(const char *string, char ** const end, int base) );
|
|
||||||
#define NO_ARG 0
|
|
||||||
#define karg(arg) (karg_t) (arg)
|
#define karg(arg) (karg_t) (arg)
|
||||||
_PROTOTYPE( void kprintf, (const char *fmt, karg_t arg) );
|
_PROTOTYPE( void kprintf, (const char *fmt, karg_t arg) );
|
||||||
|
|
||||||
|
@ -44,8 +41,8 @@ _PROTOTYPE( void free_bit, (bit_t nr, bitchunk_t *map, bit_t nr_bits) );
|
||||||
/* proc.c */
|
/* proc.c */
|
||||||
_PROTOTYPE( int sys_call, (int function, int src_dest, message *m_ptr) );
|
_PROTOTYPE( int sys_call, (int function, int src_dest, message *m_ptr) );
|
||||||
_PROTOTYPE( int lock_notify, (int dst, message *m_ptr) );
|
_PROTOTYPE( int lock_notify, (int dst, message *m_ptr) );
|
||||||
|
_PROTOTYPE( int int_notify, (int dst, message *m_ptr) );
|
||||||
_PROTOTYPE( int lock_send, (int dst, message *m_ptr) );
|
_PROTOTYPE( int lock_send, (int dst, message *m_ptr) );
|
||||||
_PROTOTYPE( void lock_pick_proc, (void) );
|
|
||||||
_PROTOTYPE( void lock_ready, (struct proc *rp) );
|
_PROTOTYPE( void lock_ready, (struct proc *rp) );
|
||||||
_PROTOTYPE( void lock_sched, (int queue) );
|
_PROTOTYPE( void lock_sched, (int queue) );
|
||||||
_PROTOTYPE( void lock_unready, (struct proc *rp) );
|
_PROTOTYPE( void lock_unready, (struct proc *rp) );
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include "protect.h"
|
#include "protect.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
|
|
||||||
FORWARD _PROTOTYPE( void mem_init, (_CONST char *params));
|
|
||||||
FORWARD _PROTOTYPE( char *get_value, (_CONST char *params, _CONST char *key));
|
FORWARD _PROTOTYPE( char *get_value, (_CONST char *params, _CONST char *key));
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
|
@ -57,7 +56,8 @@ U16_t parmoff, parmsize; /* boot parameters offset and length */
|
||||||
/* Record miscellaneous information for user-space servers. */
|
/* Record miscellaneous information for user-space servers. */
|
||||||
kinfo.nr_procs = NR_PROCS;
|
kinfo.nr_procs = NR_PROCS;
|
||||||
kinfo.nr_tasks = NR_TASKS;
|
kinfo.nr_tasks = NR_TASKS;
|
||||||
kstrncpy(kinfo.version, OS_RELEASE "." OS_VERSION, 6);
|
kstrncpy(kinfo.release, OS_RELEASE, 4);
|
||||||
|
kstrncpy(kinfo.version, OS_VERSION, 4);
|
||||||
kinfo.proc_addr = (vir_bytes) proc;
|
kinfo.proc_addr = (vir_bytes) proc;
|
||||||
kinfo.kmem_base = vir2phys(0);
|
kinfo.kmem_base = vir2phys(0);
|
||||||
kinfo.kmem_size = (phys_bytes) &end;
|
kinfo.kmem_size = (phys_bytes) &end;
|
||||||
|
@ -84,79 +84,12 @@ U16_t parmoff, parmsize; /* boot parameters offset and length */
|
||||||
if (kstrcmp(value, "ega") == 0) machine.vdu_ega = TRUE;
|
if (kstrcmp(value, "ega") == 0) machine.vdu_ega = TRUE;
|
||||||
if (kstrcmp(value, "vga") == 0) machine.vdu_vga = machine.vdu_ega = TRUE;
|
if (kstrcmp(value, "vga") == 0) machine.vdu_vga = machine.vdu_ega = TRUE;
|
||||||
|
|
||||||
/* Initialize free memory list from size passed by boot monitor. */
|
|
||||||
mem_init(params);
|
|
||||||
|
|
||||||
/* Return to assembler code to switch to protected mode (if 286),
|
/* Return to assembler code to switch to protected mode (if 286),
|
||||||
* reload selectors and call main().
|
* reload selectors and call main().
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* In real mode only 1M can be addressed, and in 16-bit protected we can go
|
|
||||||
* no further than we can count in clicks. (The 286 is further limited by
|
|
||||||
* its 24 bit address bus, but we can assume in that case that no more than
|
|
||||||
* 16M memory is reported by the BIOS.)
|
|
||||||
*/
|
|
||||||
#define MAX_REAL 0x00100000L
|
|
||||||
#define MAX_16BIT (0xFFF0L << CLICK_SHIFT)
|
|
||||||
|
|
||||||
/*=========================================================================*
|
|
||||||
* mem_init *
|
|
||||||
*=========================================================================*/
|
|
||||||
PRIVATE void mem_init(params)
|
|
||||||
_CONST char *params; /* boot monitor parameters */
|
|
||||||
{
|
|
||||||
/* Initialize the free memory list from the 'memory' boot variable. Translate
|
|
||||||
* the byte offsets and sizes in this list to clicks, properly truncated. Also
|
|
||||||
* make sure that we don't exceed the maximum address space of the 286 or the
|
|
||||||
* 8086, i.e. when running in 16-bit protected mode or real mode.
|
|
||||||
*/
|
|
||||||
long base, size, limit;
|
|
||||||
char *s, *end; /* use to parse boot variable */
|
|
||||||
int i;
|
|
||||||
struct memory *memp;
|
|
||||||
#if _WORD_SIZE == 2
|
|
||||||
unsigned long max_address;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* The available memory is determined by MINIX' boot loader as a list of
|
|
||||||
* (base:size)-pairs in boothead.s. The 'memory' boot variable is set in
|
|
||||||
* in boot.s. The format is "b0:s0,b1:s1,b2:s2", where b0:s0 is low mem,
|
|
||||||
* b1:s1 is mem between 1M and 16M, b2:s2 is mem above 16M. Pairs b1:s1
|
|
||||||
* and b2:s2 are combined if the memory is adjacent.
|
|
||||||
*/
|
|
||||||
s = get_value(params, "memory"); /* get memory boot variable */
|
|
||||||
for (i = 0; i < NR_MEMS; i++) {
|
|
||||||
memp = &mem[i]; /* next mem chunk is stored here */
|
|
||||||
base = size = 0; /* initialize next base:size pair */
|
|
||||||
if (*s != 0) { /* get fresh data, unless at end */
|
|
||||||
|
|
||||||
/* Read fresh base and expect colon as next char. */
|
|
||||||
base = kstrtoul(s, &end, 0x10); /* get number */
|
|
||||||
if (end != s && *end == ':') s = ++end; /* skip ':' */
|
|
||||||
else *s=0; /* terminate, should not happen */
|
|
||||||
|
|
||||||
/* Read fresh size and expect comma or assume end. */
|
|
||||||
size = kstrtoul(s, &end, 0x10); /* get number */
|
|
||||||
if (end != s && *end == ',') s = ++end; /* skip ',' */
|
|
||||||
else *s=0; /* found end */
|
|
||||||
}
|
|
||||||
limit = base + size; /* limit is used for validity check */
|
|
||||||
#if _WORD_SIZE == 2
|
|
||||||
max_address = kinfo.protected ? MAX_16BIT : MAX_REAL;
|
|
||||||
if (limit > max_address) limit = max_address;
|
|
||||||
#endif
|
|
||||||
base = (base + CLICK_SIZE-1) & ~(long)(CLICK_SIZE-1);
|
|
||||||
limit &= ~(long)(CLICK_SIZE-1);
|
|
||||||
if (limit <= base) continue;
|
|
||||||
memp->base = base >> CLICK_SHIFT;
|
|
||||||
memp->size = (limit - base) >> CLICK_SHIFT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* get_value *
|
* get_value *
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
|
@ -296,7 +296,7 @@ irq_hook_t *hook;
|
||||||
/* Build notification message and return. */
|
/* Build notification message and return. */
|
||||||
m.NOTIFY_TYPE = HARD_INT;
|
m.NOTIFY_TYPE = HARD_INT;
|
||||||
m.NOTIFY_ARG = hook->irq;
|
m.NOTIFY_ARG = hook->irq;
|
||||||
lock_notify(hook->proc_nr, &m);
|
int_notify(hook->proc_nr, &m);
|
||||||
return(hook->policy & IRQ_REENABLE);
|
return(hook->policy & IRQ_REENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,11 +308,11 @@ PUBLIC void cause_sig(proc_nr, sig_nr)
|
||||||
int proc_nr; /* process to be signalled */
|
int proc_nr; /* process to be signalled */
|
||||||
int sig_nr; /* signal to be sent, 1 to _NSIG */
|
int sig_nr; /* signal to be sent, 1 to _NSIG */
|
||||||
{
|
{
|
||||||
/* A task wants to send a signal to a process. Examples of such tasks are:
|
/* A system process wants to send a signal to a process. Examples are:
|
||||||
* TTY wanting to cause SIGINT upon getting a DEL
|
* TTY wanting to cause SIGINT upon getting a DEL
|
||||||
* CLOCK wanting to cause SIGALRM when timer expires
|
* CLOCK wanting to cause SIGALRM when timer expires
|
||||||
* FS also uses this to send a signal, via the SYS_KILL message. Signals are
|
* FS wanting to cause SIGPIPE for a broken pipe
|
||||||
* handled by sending a message to PM. This central function handles the
|
* Signals are handled by sending a message to PM. This function handles the
|
||||||
* signals and makes sure the PM gets them by sending a notification. The
|
* signals and makes sure the PM gets them by sending a notification. The
|
||||||
* process being signaled is blocked while PM has not finished all signals
|
* process being signaled is blocked while PM has not finished all signals
|
||||||
* for it. These signals are counted in p_pendcount, and the SIG_PENDING
|
* for it. These signals are counted in p_pendcount, and the SIG_PENDING
|
||||||
|
@ -487,7 +487,7 @@ vir_bytes bytes; /* # of bytes to copy */
|
||||||
|
|
||||||
/* Check copy count. */
|
/* Check copy count. */
|
||||||
if (bytes <= 0) {
|
if (bytes <= 0) {
|
||||||
kprintf("v_cp: copy count problem <= 0\n", NO_ARG);
|
kprintf("v_cp: copy count problem <= 0\n", NO_NUM);
|
||||||
return(EDOM);
|
return(EDOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,7 +523,7 @@ vir_bytes bytes; /* # of bytes to copy */
|
||||||
|
|
||||||
/* Check if mapping succeeded. */
|
/* Check if mapping succeeded. */
|
||||||
if (phys_addr[i] <= 0 && vir_addr[i]->segment != PHYS_SEG) {
|
if (phys_addr[i] <= 0 && vir_addr[i]->segment != PHYS_SEG) {
|
||||||
kprintf("v_cp: Mapping failed ... phys <= 0\n", NO_ARG);
|
kprintf("v_cp: Mapping failed ... phys <= 0\n", NO_NUM);
|
||||||
return(EFAULT);
|
return(EFAULT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ register message *m_ptr; /* pointer to request message */
|
||||||
/* Check if process number was given implictly with SELF and is valid. */
|
/* Check if process number was given implictly with SELF and is valid. */
|
||||||
if (vir_addr[i].proc_nr == SELF) vir_addr[i].proc_nr = m_ptr->m_source;
|
if (vir_addr[i].proc_nr == SELF) vir_addr[i].proc_nr = m_ptr->m_source;
|
||||||
if (! isokprocn(vir_addr[i].proc_nr) && vir_addr[i].segment != PHYS_SEG) {
|
if (! isokprocn(vir_addr[i].proc_nr) && vir_addr[i].segment != PHYS_SEG) {
|
||||||
kprintf("do_vircopy: illegal proc nr, while not phys addr\n",NO_ARG);
|
kprintf("do_vircopy: illegal proc nr, while not phys addr\n",NO_NUM);
|
||||||
return(EINVAL);
|
return(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ register message *m_ptr; /* pointer to request message */
|
||||||
* vir_bytes. Especially copying by the PM on do_fork() is affected.
|
* vir_bytes. Especially copying by the PM on do_fork() is affected.
|
||||||
*/
|
*/
|
||||||
if (bytes != (vir_bytes) bytes) {
|
if (bytes != (vir_bytes) bytes) {
|
||||||
kprintf("do_vircopy: overflow\n", NO_ARG);
|
kprintf("do_vircopy: overflow\n", NO_NUM);
|
||||||
return(E2BIG);
|
return(E2BIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,11 +105,6 @@ register message *m_ptr; /* pointer to request message */
|
||||||
src_phys = vir2phys(irq_hooks);
|
src_phys = vir2phys(irq_hooks);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GET_MEMCHUNKS: {
|
|
||||||
length = sizeof(struct memory) * NR_MEMS;
|
|
||||||
src_phys = vir2phys(mem);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GET_SCHEDINFO: {
|
case GET_SCHEDINFO: {
|
||||||
/* This is slightly complicated because we need two data structures
|
/* This is slightly complicated because we need two data structures
|
||||||
* at once, otherwise the scheduling information may be incorrect.
|
* at once, otherwise the scheduling information may be incorrect.
|
||||||
|
|
Loading…
Reference in a new issue