/* MINIX specific calls, e.g., to support system services. */
#define SVRCTL 77
- /* unused */
+#define PROCSTAT 78 /* to PM */
#define GETSYSINFO 79 /* to PM or FS */
#define GETPROCNR 80 /* to PM */
#define DEVCTL 81 /* to FS */
*/
#define NOTIFY_MESSAGE 0x1000
#define NOTIFY_FROM(p_nr) (NOTIFY_MESSAGE | ((p_nr) + NR_TASKS))
+# define PROC_EVENT NOTIFY_FROM(PM_PROC_NR) /* process status change */
# define SYN_ALARM NOTIFY_FROM(CLOCK) /* synchronous alarm */
# define SYS_SIG NOTIFY_FROM(SYSTEM) /* system signal */
# define HARD_INT NOTIFY_FROM(HARDWARE) /* hardware interrupt */
*===========================================================================*/
/* Miscellaneous request types and field names, e.g. used by IS server. */
-#define PANIC_DUMPS 97 /* debug dumps at the TTY on RBT_PANIC */
#define FKEY_CONTROL 98 /* control a function key at the TTY */
# define FKEY_REQUEST m2_i1 /* request to perform at TTY */
# define FKEY_MAP 10 /* observe function key */
#define sendrec _sendrec
#define receive _receive
#define send _send
-#define nb_receive _nb_receive
-#define nb_send _nb_send
_PROTOTYPE( int echo, (message *m_ptr) );
_PROTOTYPE( int notify, (int dest) );
_PROTOTYPE( int sendrec, (int src_dest, message *m_ptr) );
_PROTOTYPE( int receive, (int src, message *m_ptr) );
_PROTOTYPE( int send, (int dest, message *m_ptr) );
-_PROTOTYPE( int nb_receive, (int src, message *m_ptr) );
-_PROTOTYPE( int nb_send, (int dest, message *m_ptr) );
+
+#define ipc_request _ipc_request
+#define ipc_reply _ipc_reply
+#define ipc_notify _ipc_notify
+#define ipc_select _ipc_select
+
+_PROTOTYPE( int ipc_request, (int dst, message *m_ptr) );
+_PROTOTYPE( int ipc_reply, (int dst, message *m_ptr) );
+_PROTOTYPE( int ipc_notify, (int dst, long event_set) );
+_PROTOTYPE( int ipc_receive, (int src, long events, message *m_ptr) );
+
#endif /* _IPC_H */
#endif
#endif
+/* Regular signals. */
#define SIGHUP 1 /* hangup */
#define SIGINT 2 /* interrupt (DEL) */
#define SIGQUIT 3 /* quit (ASCII FS) */
#define SIGTERM 15 /* software termination signal from kill */
#define SIGEMT 16 /* EMT instruction */
#define SIGCHLD 17 /* child process terminated or stopped */
+#define SIGWINCH 21 /* window size has changed */
/* MINIX specific signals. These signals are not used by user proceses,
* but meant to inform system processes, like the PM, about system events.
*/
-#define SIGKMESS 18 /* new kernel message */
-#define SIGKSIG 19 /* kernel signal pending */
-#define SIGKSTOP 20 /* kernel shutting down */
-
-/* Regular signals. */
-#define SIGWINCH 21 /* window size has changed */
+#define SIGKMESS 23 /* new kernel message */
+#define SIGKSIG 24 /* kernel signal pending */
+#define SIGKSTOP 25 /* kernel shutting down */
-#define _NSIG 21 /* number of signals used */
+#define _NSIG 25 /* number of signals used */
/* POSIX requires the following signals to be defined, even if they are
* not supported. Here are the definitions, but they are not supported.
*/
-#define SIGCONT 18 /* continue if stopped */
-#define SIGSTOP 19 /* stop signal */
-#define SIGTSTP 20 /* interactive stop signal */
-#define SIGTTIN 21 /* background process wants to read */
-#define SIGTTOU 22 /* background process wants to write */
+#define SIGCONT 28 /* continue if stopped */
+#define SIGSTOP 29 /* stop signal */
+#define SIGTSTP 30 /* interactive stop signal */
+#define SIGTTIN 31 /* background process wants to read */
+#define SIGTTOU 32 /* background process wants to write */
#ifdef _MINIX
#define SIGIOT SIGABRT /* for people who speak PDP-11 */
#define PRIO_MIN -20
#define PRIO_MAX 20
+/* Magic, invalid priority to stop the process. */
+#define PRIO_STOP 76
+
#define PRIO_PROCESS 0
#define PRIO_PGRP 1
#define PRIO_USER 2
#ifdef _MINIX
/* How to exit the system or stop a server process. */
-#define RBT_HALT 0
-#define RBT_REBOOT 1
+#define RBT_HALT 0 /* shutdown and return to monitor */
+#define RBT_REBOOT 1 /* reboot the system through the monitor */
#define RBT_PANIC 2 /* a server panics */
#define RBT_MONITOR 3 /* let the monitor do this */
#define RBT_RESET 4 /* hard reset the system */
+#define RBT_INVALID 5 /* first invalid reboot flag */
+
#define _PM_SEG_FLAG (1L << 30) /* for read() and write() to FS by PM */
#endif
_PROTOTYPE( int fttyslot, (int _fd) );
_PROTOTYPE( char *crypt, (const char *_key, const char *_salt) );
_PROTOTYPE( int getsysinfo, (int who, int what, void *where) );
+_PROTOTYPE( int getsigset, (sigset_t *sigset) );
_PROTOTYPE( int getprocnr, (void) );
_PROTOTYPE( int getnprocnr, (pid_t pid) );
_PROTOTYPE( int getpprocnr, (void) );
/* Initialize the CLOCK's interrupt hook. */
clock_hook.proc_nr_e = CLOCK;
- /* Initialize channel 0 of the 8253A timer to, e.g., 60 Hz. */
+ /* Initialize channel 0 of the 8253A timer to, e.g., 60 Hz, and register
+ * the CLOCK task's interrupt handler to be run on every clock tick.
+ */
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 */
- put_irq_handler(&clock_hook, CLOCK_IRQ, clock_handler);/* register handler */
+ put_irq_handler(&clock_hook, CLOCK_IRQ, clock_handler);
enable_irq(&clock_hook); /* ready for clock interrupts */
+
+ /* Set a watchdog timer to periodically balance the scheduling queues. */
+ balance_queues(NULL); /* side-effect sets new timer */
}
/*===========================================================================*
*===========================================================================*/
PUBLIC void clock_stop()
{
-/* Reset the clock to the BIOS rate. (For rebooting) */
+/* Reset the clock to the BIOS rate. (For rebooting.) */
outb(TIMER_MODE, 0x36);
outb(TIMER0, 0);
outb(TIMER0, 0);
#include <minix/com.h>
/* Masks and flags for system calls. */
-#define SYSCALL_FUNC 0x0F /* mask for system call function */
-#define SYSCALL_FLAGS 0xF0 /* mask for system call flags */
-#define NON_BLOCKING 0x10 /* prevent blocking, return error */
+#define SYSCALL_FUNC 0x00FF /* mask for system call function */
+#define SYSCALL_FLAGS 0xFF00 /* mask for system call flags */
+#define NON_BLOCKING 0x0100 /* do not block if target not ready */
/* System call numbers that are passed when trapping to the kernel. The
* numbers are carefully defined so that it can easily be seen (based on
* the bits that are on) which checks should be done in sys_call().
*/
-#define SEND 1 /* 0 0 0 1 : blocking send */
-#define RECEIVE 2 /* 0 0 1 0 : blocking receive */
-#define SENDREC 3 /* 0 0 1 1 : SEND + RECEIVE */
-#define NOTIFY 4 /* 0 1 0 0 : nonblocking notify */
-#define ECHO 8 /* 1 0 0 0 : echo a message */
+#define SEND 1 /* 0000 0001 : blocking send */
+#define RECEIVE 2 /* 0000 0010 : blocking receive */
+#define SENDREC 3 /* 0000 0011 : SEND + RECEIVE */
+#define NOTIFY 4 /* 0000 0100 : nonblocking notify */
+#define ECHO 8 /* 0000 1000 : echo a message */
+
+#define IPC_REQUEST 0x10 /* 0001 0000 : blocking request */
+#define IPC_REPLY 0x20 /* 0010 0000 : nonblocking reply */
+#define IPC_NOTIFY 0x40 /* 0100 0000 : nonblocking notification */
+#define IPC_RECEIVE 0x80 /* 1000 0000 : blocking receive */
/* The following bit masks determine what checks that should be done. */
-#define CHECK_PTR 0x0B /* 1 0 1 1 : validate message buffer */
-#define CHECK_DST 0x05 /* 0 1 0 1 : validate message destination */
-#define CHECK_SRC 0x02 /* 0 0 1 0 : validate message source */
-#define CHECK_DEADLOCK 0x03 /* 0 0 1 1 : check for deadlock */
+#define CHECK_PTR 0xBB /* 1011 1011 : validate message buffer */
+#define CHECK_DST 0x55 /* 0101 0101 : validate message destination */
+#define CHECK_DEADLOCK 0x93 /* 1001 0011 : check for deadlock */
#endif /* IPC_H */
* run their shutdown code, e.g, to synchronize the FS or to let the TTY
* switch to the first console.
*/
+#if DEAD_CODE
kprintf("Sending SIGKSTOP to system processes ...\n");
for (rp=BEG_PROC_ADDR; rp<END_PROC_ADDR; rp++) {
if (!isemptyp(rp) && (priv(rp)->s_flags & SYS_PROC) && !iskernelp(rp))
send_sig(proc_nr(rp), SIGKSTOP);
}
+#endif
/* Continue after 1 second, to give processes a chance to get scheduled to
* do shutdown work. Set a watchog timer to call shutdown(). The timer
o16 push es
o16 push fs
o16 push gs
- mov dx, ss
- mov ds, dx
- mov es, dx
- incb (_k_reenter)
+ mov si, ss ! ss is kernel data segment
+ mov ds, si ! load rest of kernel segments
+ mov es, si ! kernel does not use fs, gs
+ incb (_k_reenter) ! increment kernel entry count
mov esi, esp ! assumes P_STACKBASE == 0
mov esp, k_stktop
xor ebp, ebp ! for stacktrace
! end of inline save
! now set up parameters for sys_call()
+ push edx ! event set or flags bit map
push ebx ! pointer to user message
- push eax ! src/dest
- push ecx ! SEND/RECEIVE/BOTH
- call _sys_call ! sys_call(function, src_dest, m_ptr)
+ push eax ! source / destination
+ push ecx ! call number (ipc primitive to use)
+ call _sys_call ! sys_call(call_nr, src_dst, m_ptr, bit_map)
! caller is now explicitly in proc_ptr
mov AXREG(esi), eax ! sys_call MUST PRESERVE si
struct far_mem s_farmem[NR_REMOTE_SEGS]; /* remote memory map */
reg_t *s_stack_guard; /* stack guard word for kernel tasks */
- int s_nr_io_range;
+ int s_nr_io_range; /* allowed I/O ports */
struct io_range s_io_tab[NR_IO_RANGE];
- int s_nr_mem_range;
+ int s_nr_mem_range; /* allowed memory ranges */
struct mem_range s_mem_tab[NR_MEM_RANGE];
- int s_nr_irq;
+ int s_nr_irq; /* allowed IRQ lines */
int s_irq_tab[NR_IRQ];
};
#define STACK_GUARD ((reg_t) (sizeof(reg_t) == 2 ? 0xBEEF : 0xDEADBEEF))
/* Bits for the system property flags. */
-#define PREEMPTIBLE 0x01 /* kernel tasks are not preemptible */
+#define PREEMPTIBLE 0x02 /* kernel tasks are not preemptible */
#define BILLABLE 0x04 /* some processes are not billable */
-#define SYS_PROC 0x10 /* system processes are privileged */
-#define SENDREC_BUSY 0x20 /* sendrec() in progress */
-#define CHECK_IO_PORT 0x40 /* Check whether an I/O request is allowed */
-#define CHECK_MEM 0x80 /* Check whether a (vm) memory map request is
- * allowed
- */
-#define CHECK_IRQ 0x100 /* Check whether an IRQ can be used */
+
+#define SYS_PROC 0x10 /* system processes have own priv structure */
+#define CHECK_IO_PORT 0x20 /* check if I/O request is allowed */
+#define CHECK_IRQ 0x40 /* check if IRQ can be used */
+#define CHECK_MEM 0x80 /* check if (VM) mem map request is allowed */
/* Magic system structure table addresses. */
#define BEG_PRIV_ADDR (&priv[0])
/*===========================================================================*
* sys_call *
*===========================================================================*/
-PUBLIC int sys_call(call_nr, src_dst_e, m_ptr)
+PUBLIC int sys_call(call_nr, src_dst_e, m_ptr, bit_map)
int call_nr; /* system call number and flags */
int src_dst_e; /* src to receive from or dst to send to */
message *m_ptr; /* pointer to message in the caller's space */
+long bit_map; /* notification event set or flags */
{
/* System calls are done by trapping to the kernel with an INT instruction.
* The trap is caught and sys_call() is called to send or receive a message
switch(function) {
case SENDREC:
/* A flag is set so that notifications cannot interrupt SENDREC. */
- priv(caller_ptr)->s_flags |= SENDREC_BUSY;
+ caller_ptr->p_misc_flags |= REPLY_PENDING;
/* fall through */
case SEND:
result = mini_send(caller_ptr, src_dst_e, m_ptr, flags);
} /* fall through for SENDREC */
case RECEIVE:
if (function == RECEIVE)
- priv(caller_ptr)->s_flags &= ~SENDREC_BUSY;
+ caller_ptr->p_misc_flags &= ~REPLY_PENDING;
result = mini_receive(caller_ptr, src_dst_e, m_ptr, flags);
break;
case NOTIFY:
if (!(caller_ptr->p_rts_flags & SENDING)) {
/* Check if there are pending notifications, except for SENDREC. */
- if (! (priv(caller_ptr)->s_flags & SENDREC_BUSY)) {
+ if (! (caller_ptr->p_misc_flags & REPLY_PENDING)) {
map = &priv(caller_ptr)->s_notify_pending;
for (chunk=&map->chunk[0]; chunk<&map->chunk[NR_SYS_CHUNKS]; chunk++) {
* can be both sending and receiving during a SENDREC system call.
*/
if ((dst_ptr->p_rts_flags & (RECEIVING|SENDING)) == RECEIVING &&
- ! (priv(dst_ptr)->s_flags & SENDREC_BUSY) &&
- (dst_ptr->p_getfrom_e == ANY
- || dst_ptr->p_getfrom_e == caller_ptr->p_endpoint)) {
+ ! (dst_ptr->p_misc_flags & REPLY_PENDING) &&
+ (dst_ptr->p_getfrom_e == ANY ||
+ dst_ptr->p_getfrom_e == caller_ptr->p_endpoint)) {
/* Destination is indeed waiting for a message. Assemble a notification
* message and deliver it. Copy from pseudo-source HARDWARE, since the
* process must be added to one of the scheduling queues to decide where to
* insert it. As a side-effect the process' priority may be updated.
*/
- static struct proc *prev_ptr = NIL_PROC; /* previous without time */
int time_left = (rp->p_ticks_left > 0); /* quantum fully consumed */
- int penalty = 0; /* change in priority */
/* Check whether the process has time left. Otherwise give a new quantum
- * and possibly raise the priority. Processes using multiple quantums
- * in a row get a lower priority to catch infinite loops in high priority
- * processes (system servers and drivers).
+ * and lower the process' priority, unless the process already is in the
+ * lowest queue.
*/
- if ( ! time_left) { /* quantum consumed ? */
+ if (! time_left) { /* quantum consumed ? */
rp->p_ticks_left = rp->p_quantum_size; /* give new quantum */
- if (prev_ptr == rp) penalty ++; /* catch infinite loops */
- else penalty --; /* give slow way back */
- prev_ptr = rp; /* store ptr for next */
- }
-
- /* Determine the new priority of this process. The bounds are determined
- * by IDLE's queue and the maximum priority of this process. Kernel task
- * and the idle process are never changed in priority.
- */
- if (penalty != 0 && ! iskernelp(rp)) {
- rp->p_priority += penalty; /* update with penalty */
- if (rp->p_priority < rp->p_max_priority) /* check upper bound */
- rp->p_priority=rp->p_max_priority;
- else if (rp->p_priority > IDLE_Q-1) /* check lower bound */
- rp->p_priority = IDLE_Q-1;
+ if (rp->p_priority < (IDLE_Q-1)) {
+ rp->p_priority += 1; /* lower priority */
+ }
}
/* If there is time left, the process is added to the front of its queue,
}
}
+/*===========================================================================*
+ * balance_queues *
+ *===========================================================================*/
+#define Q_BALANCE_TICKS 100
+PUBLIC void balance_queues(tp)
+timer_t *tp; /* watchdog timer pointer */
+{
+/* Check entire process table and give all process a higher priority. This
+ * effectively means giving a new quantum. If a process already is at its
+ * maximum priority, its quantum will be renewed.
+ */
+ static timer_t queue_timer; /* timer structure to use */
+ register struct proc* rp; /* process table pointer */
+ clock_t next_period; /* time of next period */
+ int ticks_added = 0; /* total time added */
+
+ for (rp=BEG_PROC_ADDR; rp<END_PROC_ADDR; rp++) {
+ if (! isemptyp(rp)) { /* check slot use */
+ lock(5,"balance_queues");
+ if (rp->p_priority > rp->p_max_priority) { /* update priority? */
+ if (rp->p_rts_flags == 0) dequeue(rp); /* take off queue */
+ ticks_added += rp->p_quantum_size; /* do accounting */
+ rp->p_priority -= 1; /* raise priority */
+ if (rp->p_rts_flags == 0) enqueue(rp); /* put on queue */
+ }
+ else {
+ ticks_added += rp->p_quantum_size - rp->p_ticks_left;
+ rp->p_ticks_left = rp->p_quantum_size; /* give new quantum */
+ }
+ unlock(5);
+ }
+ }
+ kprintf("ticks_added: %d\n", ticks_added);
+
+ /* Now schedule a new watchdog timer to balance the queues again. The
+ * period depends on the total amount of quantum ticks added.
+ */
+ next_period = MAX(Q_BALANCE_TICKS, ticks_added); /* calculate next */
+ set_timer(&queue_timer, get_uptime() + next_period, balance_queues);
+}
+
/*===========================================================================*
* lock_send *
*===========================================================================*/
{
/* Safe gateway to dequeue() for tasks. */
if (k_reenter >= 0) {
- /* We're in an exception or interrupt, so don't lock (and..
+ /* We're in an exception or interrupt, so don't lock (and ...
* don't unlock).
*/
dequeue(rp);
proc_nr_t p_nr; /* number of this process (for fast access) */
struct priv *p_priv; /* system privileges structure */
- char p_rts_flags; /* SENDING, RECEIVING, etc. */
-
- char p_misc_flags; /* Flags that do suspend the process */
+ short p_rts_flags; /* process is runnable only if zero */
+ short p_misc_flags; /* flags that do suspend the process */
char p_priority; /* current scheduling priority */
char p_max_priority; /* maximum scheduling priority */
/* Bits for the runtime flags. A process is runnable iff p_rts_flags == 0. */
#define SLOT_FREE 0x01 /* process slot is free */
#define NO_MAP 0x02 /* keeps unmapped forked child from running */
-#define SENDING 0x04 /* process blocked trying to SEND */
-#define RECEIVING 0x08 /* process blocked trying to RECEIVE */
+#define SENDING 0x04 /* process blocked trying to send */
+#define RECEIVING 0x08 /* process blocked trying to receive */
#define SIGNALED 0x10 /* set when new kernel signal arrives */
#define SIG_PENDING 0x20 /* unready while signal being processed */
#define P_STOP 0x40 /* set when process is being traced */
#define NO_PRIV 0x80 /* keep forked system process from running */
+#define NO_PRIORITY 0x100 /* process has been stopped */
/* Misc flags */
-#define MF_VM 0x01 /* Process uses VM */
+#define REPLY_PENDING 0x01 /* reply to IPC_REQUEST is pending */
+#define MF_VM 0x08 /* process uses VM */
/* Scheduling priorities for p_priority. Values must start at zero (highest
* priority) and increment. Priorities of the processes in the boot image
_PROTOTYPE( void panic, (_CONST char *s, int n) );
/* proc.c */
-_PROTOTYPE( int sys_call, (int function, int src_dest, message *m_ptr) );
+_PROTOTYPE( int sys_call, (int call_nr, int src_dst,
+ message *m_ptr, long bit_map) );
_PROTOTYPE( int lock_notify, (int src, int dst) );
_PROTOTYPE( int lock_send, (int dst, message *m_ptr) );
_PROTOTYPE( void lock_enqueue, (struct proc *rp) );
_PROTOTYPE( void lock_dequeue, (struct proc *rp) );
+_PROTOTYPE( void balance_queues, (struct timer *tp) );
#if DEBUG_ENABLE_IPC_WARNINGS
_PROTOTYPE( int isokendpt_f, (char *file, int line, int e, int *p, int f));
#define isokendpt_d(e, p, f) isokendpt_f(__FILE__, __LINE__, (e), (p), (f))
if (sig_nr > _NSIG) return(EINVAL);
if (iskerneln(proc_nr)) return(EPERM);
- if (m_ptr->m_source == PM_PROC_NR) {
- /* Directly send signal notification to a system process. */
- if (! (priv(proc_addr(proc_nr))->s_flags & SYS_PROC)) return(EPERM);
- send_sig(proc_nr, sig_nr);
- } else {
- /* Set pending signal to be processed by the PM. */
- cause_sig(proc_nr, sig_nr);
- }
+ /* Set pending signal to be processed by the PM. */
+ cause_sig(proc_nr, sig_nr);
return(OK);
}
*===========================================================================*/
PUBLIC int do_nice(message *m_ptr)
{
+/* Change process priority or stop the process. */
int proc_nr, pri, new_q ;
register struct proc *rp;
if(!isokendpt(m_ptr->PR_ENDPT, &proc_nr)) return EINVAL;
if (iskerneln(proc_nr)) return(EPERM);
pri = m_ptr->PR_PRIORITY;
- if (pri < PRIO_MIN || pri > PRIO_MAX) return(EINVAL);
-
- /* The priority is currently between PRIO_MIN and PRIO_MAX. We have to
- * scale this between MIN_USER_Q and MAX_USER_Q.
- */
- new_q = MAX_USER_Q + (pri-PRIO_MIN) * (MIN_USER_Q-MAX_USER_Q+1) /
- (PRIO_MAX-PRIO_MIN+1);
- if (new_q < MAX_USER_Q) new_q = MAX_USER_Q; /* shouldn't happen */
- if (new_q > MIN_USER_Q) new_q = MIN_USER_Q; /* shouldn't happen */
-
- /* Make sure the process is not running while changing its priority; the
- * max_priority is the base priority. Put the process back in its new
- * queue if it is runnable.
- */
rp = proc_addr(proc_nr);
- lock_dequeue(rp);
- rp->p_max_priority = rp->p_priority = new_q;
- if (! rp->p_rts_flags) lock_enqueue(rp);
- return(OK);
+ if (pri == PRIO_STOP) {
+
+ /* Take process off the scheduling queues. */
+ lock_dequeue(rp);
+ rp->p_rts_flags |= NO_PRIORITY;
+ return(OK);
+ }
+ else if (pri >= PRIO_MIN && pri <= PRIO_MAX) {
+
+ /* The value passed in is currently between PRIO_MIN and PRIO_MAX.
+ * We have to scale this between MIN_USER_Q and MAX_USER_Q to match
+ * the kernel's scheduling queues.
+ */
+ new_q = MAX_USER_Q + (pri-PRIO_MIN) * (MIN_USER_Q-MAX_USER_Q+1) /
+ (PRIO_MAX-PRIO_MIN+1);
+ if (new_q < MAX_USER_Q) new_q = MAX_USER_Q; /* shouldn't happen */
+ if (new_q > MIN_USER_Q) new_q = MIN_USER_Q; /* shouldn't happen */
+
+ /* Make sure the process is not running while changing its priority.
+ * Put the process back in its new queue if it is runnable.
+ */
+ lock_dequeue(rp);
+ rp->p_max_priority = rp->p_priority = new_q;
+ if (! rp->p_rts_flags) lock_enqueue(rp);
+
+ return(OK);
+ }
+ return(EINVAL);
}
#endif /* USE_NICE */
#define DS_C ~0
#define PM_C ~(c(SYS_DEVIO) | c(SYS_SDEVIO) | c(SYS_VDEVIO) | c(SYS_IRQCTL) | c(SYS_INT86))
#define FS_C (c(SYS_KILL) | c(SYS_VIRCOPY) | c(SYS_VIRVCOPY) | c(SYS_UMAP) | c(SYS_GETINFO) | c(SYS_EXIT) | c(SYS_TIMES) | c(SYS_SETALARM))
-#define DRV_C (FS_C | c(SYS_SEGCTL) | c(SYS_IRQCTL) | c(SYS_INT86) | c(SYS_DEVIO) | c(SYS_VDEVIO) | c(SYS_SDEVIO))
-#define PCI_C (c(SYS_VIRCOPY) | c(SYS_DEVIO) | c(SYS_VDEVIO) | c(SYS_SDEVIO) | c(SYS_PRIVCTL) | c(SYS_GETINFO))
+#define DRV_C (FS_C | c(SYS_SEGCTL) | c(SYS_IRQCTL) | c(SYS_INT86) | c(SYS_DEVIO) | c(SYS_SDEVIO) | c(SYS_VDEVIO))
#define TTY_C (DRV_C | c(SYS_ABORT) | c(SYS_VM_MAP) | c(SYS_IOPENABLE))
#define MEM_C (DRV_C | c(SYS_PHYSCOPY) | c(SYS_PHYSVCOPY) | c(SYS_VM_MAP) | \
c(SYS_IOPENABLE))
/* The system image table lists all programs that are part of the boot image.
* The order of the entries here MUST agree with the order of the programs
* in the boot image and all kernel tasks must come first.
- * Each entry provides the process number, flags, quantum size (qs), scheduling
+ *
+ * Each entry provides the process number, flags, quantum size, scheduling
* queue, allowed traps, ipc mask, and a name for the process table. The
* initial program counter and stack size is also provided for kernel tasks.
+ *
+ * Note: the quantum size must be positive in all cases!
*/
PUBLIC struct boot_image image[] = {
/* process nr, pc, flags, qs, queue, stack, traps, ipcto, call, name */
- { IDLE, idle_task, IDL_F, 8, IDLE_Q, IDL_S, 0, 0, 0, "IDLE" },
- { CLOCK,clock_task, TSK_F, 0, TASK_Q, TSK_S, TSK_T, 0, 0, "CLOCK" },
- { SYSTEM, sys_task, TSK_F, 0, TASK_Q, TSK_S, TSK_T, 0, 0, "SYSTEM"},
- { HARDWARE, 0, TSK_F, 0, TASK_Q, HRD_S, 0, 0, 0, "KERNEL"},
+ { IDLE, idle_task, IDL_F, 8, IDLE_Q, IDL_S, 0, 0, 0, "idle" },
+ { CLOCK,clock_task, TSK_F, 8, TASK_Q, TSK_S, TSK_T, 0, 0, "clock" },
+ { SYSTEM, sys_task, TSK_F, 8, TASK_Q, TSK_S, TSK_T, 0, 0, "system"},
+ { HARDWARE, 0, TSK_F, 8, TASK_Q, HRD_S, 0, 0, 0, "kernel"},
{ PM_PROC_NR, 0, SRV_F, 32, 3, 0, SRV_T, SRV_M, PM_C, "pm" },
{ FS_PROC_NR, 0, SRV_F, 32, 4, 0, SRV_T, SRV_M, FS_C, "fs" },
{ RS_PROC_NR, 0, SRV_F, 4, 3, 0, SRV_T, SYS_M, RS_C, "rs" },
{ DS_PROC_NR, 0, SRV_F, 4, 3, 0, SRV_T, SYS_M, DS_C, "ds" },
{ TTY_PROC_NR, 0, SRV_F, 4, 1, 0, SRV_T, SYS_M, TTY_C, "tty" },
- { MEM_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, MEM_C, "memory"},
+ { MEM_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, MEM_C, "mem" },
{ LOG_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, DRV_C, "log" },
-#if 0
- { DRVR_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, DRV_C, "driver"},
- { PCI_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, PCI_C, "pci"},
-#endif
{ INIT_PROC_NR, 0, USR_F, 8, USER_Q, 0, USR_T, USR_M, 0, "init" },
};
/* Declare some local functions. */
FORWARD _PROTOTYPE(void init_server, (int argc, char **argv) );
FORWARD _PROTOTYPE(void exit_server, (void) );
+FORWARD _PROTOTYPE(void sig_handler, (void) );
FORWARD _PROTOTYPE(void get_work, (message *m_ptr) );
FORWARD _PROTOTYPE(void reply, (int whom, message *m_ptr) );
get_work(&m);
switch (callnr) {
- case SYS_SIG:
- sigset = (sigset_t) m.NOTIFY_ARG;
- if (sigismember(&sigset,SIGTERM) || sigismember(&sigset,SIGKSTOP)) {
- exit_server();
- }
+ case PROC_EVENT:
+ sig_handler();
continue;
case DS_PUBLISH:
result = do_publish(&m);
report("DS","warning, sigaction() failed", errno);
}
+/*===========================================================================*
+ * sig_handler *
+ *===========================================================================*/
+PRIVATE void sig_handler()
+{
+/* Signal handler. */
+ sigset_t sigset;
+ int sig;
+
+ /* Try to obtain signal set from PM. */
+ if (getsigset(&sigset) != 0) return;
+
+ /* Check for known signals. */
+ if (sigismember(&sigset, SIGTERM)) {
+ exit_server();
+ }
+}
+
/*===========================================================================*
* exit_server *
*===========================================================================*/
FORWARD _PROTOTYPE( void fs_init, (void) );
FORWARD _PROTOTYPE( int igetenv, (char *var, int optional) );
FORWARD _PROTOTYPE( void get_work, (void) );
-FORWARD _PROTOTYPE( void load_ram, (void) );
-FORWARD _PROTOTYPE( void load_super, (Dev_t super_dev) );
+FORWARD _PROTOTYPE( void init_root, (void) );
/*===========================================================================*
* main *
/* This is the main loop that gets work, processes it, and sends replies. */
while (TRUE) {
get_work(); /* sets who and call_nr */
-
fp = &fproc[who_p]; /* pointer to proc table struct */
super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */
/* Check for special control messages first. */
- if (call_nr == SYS_SIG) {
- sigset = m_in.NOTIFY_ARG;
- if (sigismember(&sigset, SIGKSTOP)) {
- do_sync();
- sys_exit(0); /* never returns */
- }
+ if (call_nr == PROC_EVENT) {
+ /* Assume FS got signal. Synchronize, but don't exit. */
+ do_sync();
} else if (call_nr == SYN_ALARM) {
- /* Not a user request; system has expired one of our timers,
- * currently only in use for select(). Check it.
- */
+ /* Alarm timer expired. Used only for select(). Check it. */
fs_expire_timers(m_in.NOTIFY_TIMESTAMP);
} else if ((call_nr & NOTIFY_MESSAGE)) {
/* Device notifies us of an event. */
/* Call the internal function that does the work. */
if (call_nr < 0 || call_nr >= NCALLS) {
error = ENOSYS;
+ /* Not supposed to happen. */
printf("FS, warning illegal %d system call by %d\n", call_nr, who_e);
} else if (fp->fp_pid == PID_FREE) {
error = ENOSYS;
int whom; /* process to reply to */
int result; /* result of the call (usually OK or error #) */
{
-/* Send a reply to a user process. It may fail (if the process has just
- * been killed by a signal), so don't check the return code. If the send
- * fails, just ignore it.
- */
+/* Send a reply to a user process. If the send fails, just ignore it. */
int s;
m_out.reply_type = result;
s = send(whom, &m_out);
buf_pool(); /* initialize buffer pool */
build_dmap(); /* build device table and map boot driver */
- load_ram(); /* init RAM disk, load if it is root */
- load_super(root_dev); /* load super block for root device */
+ init_root(); /* init root device and load super block */
init_select(); /* init select() structures */
/* The root device can now be accessed; set process directories. */
}
/*===========================================================================*
- * load_ram *
+ * init_root *
*===========================================================================*/
-PRIVATE void load_ram(void)
+PRIVATE void init_root()
{
-/* Allocate a RAM disk with size given in the boot parameters. If a RAM disk
- * image is given, the copy the entire image device block-by-block to a RAM
- * disk with the same size as the image.
- * If the root device is not set, the RAM disk will be used as root instead.
- */
- register struct buf *bp, *bp1;
- u32_t lcount, ram_size_kb;
- zone_t zones;
- struct super_block *sp, *dsp;
- block_t b;
- Dev_t image_dev;
- static char sbbuf[_MIN_BLOCK_SIZE];
- int block_size_image, block_size_ram, ramfs_block_size;
+ int bad;
+ register struct super_block *sp;
+ register struct inode *rip;
int s;
- /* Get some boot environment variables. */
- root_dev = igetenv("rootdev", 0);
- root_dev = DEV_IMGRD;
- image_dev = igetenv("ramimagedev", 0);
- ram_size_kb = igetenv("ramsize", 0);
-
/* Open the root device. */
- if (dev_open(root_dev, FS_PROC_NR, R_BIT|W_BIT) != OK)
- panic(__FILE__,"Cannot open root device",NO_NUM);
-
-#if 0
- /* If we must initialize a ram disk, get details from the image device. */
- if (root_dev == DEV_RAM) {
- u32_t fsmax, probedev;
-
- /* If we are running from CD, see if we can find it. */
- if (igetenv("cdproberoot", 1) && (probedev=cdprobe()) != NO_DEV) {
- char devnum[10];
- struct sysgetenv env;
-
- /* If so, this is our new RAM image device. */
- image_dev = probedev;
-
- /* Tell PM about it, so userland can find out about it
- * with sysenv interface.
- */
- env.key = "cdproberoot";
- env.keylen = strlen(env.key);
- sprintf(devnum, "%d", (int) probedev);
- env.val = devnum;
- env.vallen = strlen(devnum);
- svrctl(MMSETPARAM, &env);
- }
-
- /* Open image device for RAM root. */
- if (dev_open(image_dev, FS_PROC_NR, R_BIT) != OK)
- panic(__FILE__,"Cannot open RAM image device", NO_NUM);
-
- /* Get size of RAM disk image from the super block. */
- sp = &super_block[0];
- sp->s_dev = image_dev;
- if (read_super(sp) != OK)
- panic(__FILE__,"Bad RAM disk image FS", NO_NUM);
-
- lcount = sp->s_zones << sp->s_log_zone_size; /* # blks on root dev*/
-
- /* Stretch the RAM disk file system to the boot parameters size, but
- * no further than the last zone bit map block allows.
- */
- if (ram_size_kb*1024 < lcount*sp->s_block_size)
- ram_size_kb = lcount*sp->s_block_size/1024;
- fsmax = (u32_t) sp->s_zmap_blocks * CHAR_BIT * sp->s_block_size;
- fsmax = (fsmax + (sp->s_firstdatazone-1)) << sp->s_log_zone_size;
- if (ram_size_kb*1024 > fsmax*sp->s_block_size)
- ram_size_kb = fsmax*sp->s_block_size/1024;
- }
-#endif
-
- /* Tell RAM driver how big the RAM disk must be. */
- m_out.m_type = DEV_IOCTL;
- m_out.PR_ENDPT = FS_PROC_NR;
- m_out.DEVICE = RAM_DEV;
- m_out.REQUEST = MIOCRAMSIZE; /* I/O control to use */
- m_out.POSITION = (ram_size_kb * 1024); /* request in bytes */
-#if 0
- if ((s=sendrec(MEM_PROC_NR, &m_out)) != OK)
- panic("FS","sendrec from MEM failed", s);
- else if (m_out.REP_STATUS != OK) {
- /* Report and continue, unless RAM disk is required as root FS. */
- if (root_dev != DEV_RAM) {
- report("FS","can't set RAM disk size", m_out.REP_STATUS);
- return;
- } else {
- panic(__FILE__,"can't set RAM disk size", m_out.REP_STATUS);
- }
- }
-#endif
+ root_dev = DEV_IMGRD;
+ if ((s=dev_open(root_dev, FS_PROC_NR, R_BIT|W_BIT)) != OK)
+ panic(__FILE__,"Cannot open root device", s);
#if ENABLE_CACHE2
/* The RAM disk is a second level block cache while not otherwise used. */
init_cache2(ram_size);
#endif
- /* See if we must load the RAM disk image, otherwise return. */
- if (root_dev != DEV_RAM)
- return;
-
-#if 0
-
- /* Copy the blocks one at a time from the image to the RAM disk. */
- printf("Loading RAM disk onto /dev/ram:\33[23CLoaded: 0 KB");
-
- inode[0].i_mode = I_BLOCK_SPECIAL; /* temp inode for rahead() */
- inode[0].i_size = LONG_MAX;
- inode[0].i_dev = image_dev;
- inode[0].i_zone[0] = image_dev;
-
- block_size_ram = get_block_size(DEV_RAM);
- block_size_image = get_block_size(image_dev);
-
- /* RAM block size has to be a multiple of the root image block
- * size to make copying easier.
- */
- if (block_size_image % block_size_ram) {
- printf("\nram block size: %d image block size: %d\n",
- block_size_ram, block_size_image);
- panic(__FILE__, "ram disk block size must be a multiple of "
- "the image disk block size", NO_NUM);
- }
-
- /* Loading blocks from image device. */
- for (b = 0; b < (block_t) lcount; b++) {
- int rb, factor;
- bp = rahead(&inode[0], b, (off_t)block_size_image * b, block_size_image);
- factor = block_size_image/block_size_ram;
- for(rb = 0; rb < factor; rb++) {
- bp1 = get_block(root_dev, b * factor + rb, NO_READ);
- memcpy(bp1->b_data, bp->b_data + rb * block_size_ram,
- (size_t) block_size_ram);
- bp1->b_dirt = DIRTY;
- put_block(bp1, FULL_DATA_BLOCK);
- }
- put_block(bp, FULL_DATA_BLOCK);
- if (b % 11 == 0)
- printf("\b\b\b\b\b\b\b\b\b%6ld KB", ((long) b * block_size_image)/1024L);
- }
-
- /* Commit changes to RAM so dev_io will see it. */
- do_sync();
-
- printf("\rRAM disk of %u KB loaded onto /dev/ram.", (unsigned) ram_size_kb);
- if (root_dev == DEV_RAM) printf(" Using RAM disk as root FS.");
- printf(" \n");
-
- /* Invalidate and close the image device. */
- invalidate(image_dev);
- dev_close(image_dev);
-
- /* Resize the RAM disk root file system. */
- if (dev_io(DEV_READ, root_dev, FS_PROC_NR,
- sbbuf, SUPER_BLOCK_BYTES, _MIN_BLOCK_SIZE, 0) != _MIN_BLOCK_SIZE) {
- printf("WARNING: ramdisk read for resizing failed\n");
- }
- dsp = (struct super_block *) sbbuf;
- if (dsp->s_magic == SUPER_V3)
- ramfs_block_size = dsp->s_block_size;
- else
- ramfs_block_size = _STATIC_BLOCK_SIZE;
- zones = (ram_size_kb * 1024 / ramfs_block_size) >> sp->s_log_zone_size;
-
- dsp->s_nzones = conv2(sp->s_native, (u16_t) zones);
- dsp->s_zones = conv4(sp->s_native, zones);
- if (dev_io(DEV_WRITE, root_dev, FS_PROC_NR,
- sbbuf, SUPER_BLOCK_BYTES, _MIN_BLOCK_SIZE, 0) != _MIN_BLOCK_SIZE) {
- printf("WARNING: ramdisk write for resizing failed\n");
- }
-#endif
-}
-
-/*===========================================================================*
- * load_super *
- *===========================================================================*/
-PRIVATE void load_super(super_dev)
-dev_t super_dev; /* place to get superblock from */
-{
- int bad;
- register struct super_block *sp;
- register struct inode *rip;
-
/* Initialize the super_block table. */
for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
sp->s_dev = NO_DEV;
/* Read in super_block for the root file system. */
sp = &super_block[0];
- sp->s_dev = super_dev;
+ sp->s_dev = root_dev;
/* Check super_block for consistency. */
bad = (read_super(sp) != OK);
if (!bad) {
- rip = get_inode(super_dev, ROOT_INODE); /* inode for root dir */
+ rip = get_inode(root_dev, ROOT_INODE); /* inode for root dir */
if ( (rip->i_mode & I_TYPE) != I_DIRECTORY || rip->i_nlinks < 3) bad++;
}
if (bad) panic(__FILE__,"Invalid root file system", NO_NUM);
/* Invalidate endpoint number for error and sanity checks. */
fp->fp_endpoint = NONE;
- /* If a session leader exits then revoke access to its controlling tty from
- * all other processes using it.
+ /* If a session leader exits and it has a controlling tty, then revoke
+ * access to its controlling tty from all other processes using it.
*/
- if (!fp->fp_sesldr) {
- fp->fp_pid = PID_FREE;
- return(OK); /* not a session leader */
- }
- fp->fp_sesldr = FALSE;
- if (fp->fp_tty == 0) {
- fp->fp_pid = PID_FREE;
- return(OK); /* no controlling tty */
- }
- dev = fp->fp_tty;
+ if (fp->fp_sesldr && fp->fp_tty != 0) {
+
+ dev = fp->fp_tty;
- for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
- if (rfp->fp_tty == dev) rfp->fp_tty = 0;
+ for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
+ if (rfp->fp_tty == dev) rfp->fp_tty = 0;
- for (i = 0; i < OPEN_MAX; i++) {
+ for (i = 0; i < OPEN_MAX; i++) {
if ((rfilp = rfp->fp_filp[i]) == NIL_FILP) continue;
if (rfilp->filp_mode == FILP_CLOSED) continue;
rip = rfilp->filp_ino;
if ((dev_t) rip->i_zone[0] != dev) continue;
dev_close(dev);
rfilp->filp_mode = FILP_CLOSED;
- }
+ }
+ }
}
- /* Mark slot as free. */
+ /* Exit done. Mark slot as free. */
fp->fp_pid = PID_FREE;
-
return(OK);
}
printf("FS panic (%s): %s ", who, mess);
if (num != NO_NUM) printf("%d",num);
(void) do_sync(); /* flush everything to the disk */
- sys_exit(1);
+ sys_exit(SELF);
}
/*===========================================================================*
clck_tick(&mq->mq_mess);
mq_free(mq);
}
- else if (mq->mq_mess.m_type == SYS_SIG)
+ else if (mq->mq_mess.m_type == PROC_EVENT)
{
/* signaled */
/* probably SIGTERM */
/* Define hooks for the debugging dumps. This table maps function keys
* onto a specific dump and provides a description for it.
*/
-#define NHOOKS 19
+#define NHOOKS 18
struct hook_entry {
int key;
{ F9, sched_dmp, "Scheduling queues" },
{ F10, kenv_dmp, "Kernel parameters" },
{ F11, timing_dmp, "Timing details (if enabled)" },
- { F12, reboot_dmp, "Reboot system after panic." },
{ SF1, mproc_dmp, "Process manager process table" },
{ SF2, sigaction_dmp, "Signals" },
{ SF3, fproc_dmp, "Filesystem process table" },
return name;
}
-/*===========================================================================*
- * reboot_dmp *
- *===========================================================================*/
-PUBLIC void reboot_dmp(void)
-{
- if (sys_panic) sys_abort(RBT_HALT);
-}
-
/*===========================================================================*
* mapping_dmp *
message m_out; /* the output message used for reply */
int who_e; /* caller's proc number */
int callnr; /* system call number */
-int sys_panic; /* flag to indicate system-wide panic */
extern int errno; /* error number set by system library */
/* Declare some local functions. */
FORWARD _PROTOTYPE(void init_server, (int argc, char **argv) );
+FORWARD _PROTOTYPE(void sig_handler, (void) );
FORWARD _PROTOTYPE(void exit_server, (void) );
FORWARD _PROTOTYPE(void get_work, (void) );
FORWARD _PROTOTYPE(void reply, (int whom, int result) );
switch (callnr) {
case SYS_SIG:
- sigset = (sigset_t) m_in.NOTIFY_ARG;
- if (sigismember(&sigset,SIGTERM) || sigismember(&sigset,SIGKSTOP)) {
- exit_server();
- }
- continue;
- case PANIC_DUMPS:
- printf("Oops ... panic in %d. ", who_e);
- printf("Hit F-keys for debug dumps or F12 to shut down.\n");
- sys_panic = TRUE; /* set flag to allow exit */
+ printf("got SYS_SIG message\n");
+ sigset = m_in.NOTIFY_ARG;
+ for ( result=0; result< _NSIG; result++) {
+ if (sigismember(&sigset, result))
+ printf("signal %d found\n", result);
+ }
continue;
+ case PROC_EVENT:
+ sig_handler();
+ continue;
case FKEY_PRESSED:
result = do_fkey_pressed(&m_in);
break;
report("IS", "warning, fkey_map failed:", s);
}
+/*===========================================================================*
+ * sig_handler *
+ *===========================================================================*/
+PRIVATE void sig_handler()
+{
+ sigset_t sigset;
+ int sig;
+
+ /* Try to obtain signal set from PM. */
+ if (getsigset(&sigset) != 0) return;
+
+ /* Check for known signals. */
+ if (sigismember(&sigset, SIGTERM)) {
+ exit_server();
+ }
+}
+
/*===========================================================================*
* exit_server *
*===========================================================================*/
/* dmp.c */
_PROTOTYPE( int do_fkey_pressed, (message *m) );
_PROTOTYPE( void mapping_dmp, (void) );
-_PROTOTYPE( void reboot_dmp, (void) );
/* dmp_kernel.c */
_PROTOTYPE( void proctab_dmp, (void) );
#include <sys/wait.h>
#include <minix/callnr.h>
#include <minix/com.h>
+#include <sys/resource.h>
#include <signal.h>
#include "mproc.h"
#include "param.h"
p_mp->mp_child_utime += t[0] + rmp->mp_child_utime; /* add user time */
p_mp->mp_child_stime += t[1] + rmp->mp_child_stime; /* add system time */
- /* Tell the kernel and FS that the process is no longer runnable. */
- tell_fs(EXIT, proc_nr_e, 0, 0); /* file system can free the proc slot */
- if((r=sys_exit(proc_nr_e)) != OK)
+ /* Tell the kernel the process is no longer runnable to prevent it from
+ * being scheduled in between the following steps. Then tell FS that it
+ * the process has exited and finally, clean up the process at the kernel.
+ * This order is important so that FS can tell drivers to cancel requests
+ * such as copying to/ from the exiting process, before it is gone.
+ */
+ sys_nice(proc_nr_e, PRIO_STOP); /* stop the process */
+ tell_fs(EXIT, proc_nr_e, 0, 0); /* tell FS to free the slot */
+ if((r=sys_exit(proc_nr_e)) != OK) /* destroy the process */
panic(__FILE__,"pm_exit: sys_exit failed", r);
/* Pending reply messages for the dead process cannot be delivered. */
EXTERN struct mproc *mp; /* ptr to 'mproc' slot of current process */
EXTERN int procs_in_use; /* how many processes are marked as IN_USE */
EXTERN char monitor_params[128*sizeof(char *)]; /* boot monitor parameters */
-EXTERN struct kinfo kinfo; /* kernel information */
+EXTERN struct kinfo kinfo; /* kernel information */
/* The parameters of the call are kept here. */
EXTERN message m_in; /* the incoming message itself is kept here. */
else { /* system process */
rmp->mp_pid = get_free_pid();
rmp->mp_flags |= IN_USE | DONT_SWAP | PRIV_PROC;
-#if DEAD_CODE
for (sig_ptr = mess_sigs;
sig_ptr < mess_sigs+sizeof(mess_sigs);
sig_ptr++)
sigaddset(&rmp->mp_sig2mess, *sig_ptr);
-#endif
}
/* Get kernel endpoint identifier. */
mproc[PM_PROC_NR].mp_pid = PM_PID; /* PM has magic pid */
mproc[RS_PROC_NR].mp_parent = INIT_PROC_NR; /* INIT is root */
sigfillset(&mproc[PM_PROC_NR].mp_ignore); /* guard against signals */
- sigfillset(&mproc[FS_PROC_NR].mp_sig2mess); /* forward signals */
- sigfillset(&mproc[TTY_PROC_NR].mp_sig2mess); /* forward signals */
/* Tell FS that no more system processes follow and synchronize. */
mess.PR_ENDPT = NONE;
* 31 Mar 2000
* The entry points into this file are:
* do_reboot: kill all processes, then reboot system
- * do_svrctl: process manager control
+ * do_procstat: request process status (Jorrit N. Herder)
* do_getsysinfo: request copy of PM data structure (Jorrit N. Herder)
* do_getprocnr: lookup process slot number (Jorrit N. Herder)
* do_allocmem: allocate a chunk of memory (Jorrit N. Herder)
* do_freemem: deallocate a chunk of memory (Jorrit N. Herder)
* do_getsetpriority: get/set process priority
+ * do_svrctl: process manager control
*/
#include "pm.h"
return(OK);
}
+/*===========================================================================*
+ * do_procstat *
+ *===========================================================================*/
+PUBLIC int do_procstat()
+{
+ /* For the moment, this is only used to return pending signals to
+ * system processes that request the PM for their own status.
+ *
+ * Future use might include the FS requesting for process status of
+ * any user process.
+ */
+ if (m_in.stat_nr == SELF) {
+ mp->mp_reply.sig_set = mp->mp_sigpending;
+ sigemptyset(&mp->mp_sigpending);
+ }
+ else {
+ return(ENOSYS);
+ }
+ return(OK);
+}
+
/*===========================================================================*
* do_getsysinfo *
*===========================================================================*/
/*===========================================================================*
* do_reboot *
*===========================================================================*/
-#define REBOOT_CODE "delay; boot"
PUBLIC int do_reboot()
{
char monitor_code[32*sizeof(char *)];
- int code_len;
+ vir_bytes code_addr;
+ int code_size;
int abort_flag;
+ /* Check permission to abort the system. */
if (mp->mp_effuid != SUPER_USER) return(EPERM);
- switch (m_in.reboot_flag) {
- case RBT_HALT:
- case RBT_PANIC:
- case RBT_RESET:
- abort_flag = m_in.reboot_flag;
- break;
- case RBT_REBOOT:
- code_len = strlen(REBOOT_CODE) + 1;
- strncpy(monitor_code, REBOOT_CODE, code_len);
- abort_flag = RBT_MONITOR;
- break;
- case RBT_MONITOR:
- code_len = m_in.reboot_strlen + 1;
- if (code_len > sizeof(monitor_code)) return(EINVAL);
- if (sys_datacopy(who_e, (vir_bytes) m_in.reboot_code,
- PM_PROC_NR, (vir_bytes) monitor_code,
- (phys_bytes) (code_len)) != OK) return(EFAULT);
- if (monitor_code[code_len-1] != 0) return(EINVAL);
- abort_flag = RBT_MONITOR;
- break;
- default:
- return(EINVAL);
+ /* See how the system should be aborted. */
+ abort_flag = (unsigned) m_in.reboot_flag;
+ if (abort_flag >= RBT_INVALID) return(EINVAL);
+ if (RBT_MONITOR == abort_flag) {
+ code_addr = (vir_bytes) m_in.reboot_code;
+ code_size = m_in.reboot_strlen + 1;
}
/* Order matters here. When FS is told to reboot, it exits all its
* processes, and then would be confused if they're exited again by
- * SIGKILL. So first kill, then reboot.
+ * SIGKILL. So first kill, then reboot.
*/
- check_sig(-1, SIGKILL); /* kill all processes except init */
+ printf("check_sig(-1, SIGKILL) ...\n");
+ check_sig(-1, SIGKILL); /* kill all users except init */
+ printf("stopping init with PRIO_STOP ...\n");
+ sys_nice(INIT_PROC_NR, PRIO_STOP); /* stop init, but keep it around */
+ printf("tell_fs to sync() ...\n");
tell_fs(REBOOT, 0, 0, 0); /* tell FS to synchronize */
+ printf("sys_abort ...\n");
/* Ask the kernel to abort. All system services, including the PM, will
* get a HARD_STOP notification. Await the notification in the main loop.
*/
- sys_abort(abort_flag, PM_PROC_NR, monitor_code, code_len);
- return(SUSPEND); /* don't reply to killed process */
+ sys_abort(abort_flag, who_e, code_addr, code_size);
+ return(SUSPEND); /* don't reply to caller */
}
/*===========================================================================*
#define sig_nsa m1_p1
#define sig_osa m1_p2
#define sig_ret m1_p3
+#define stat_nr m2_i1
#define sig_set m2_l1
#define sig_how m2_i1
#define sig_flags m2_i2
/* misc.c */
_PROTOTYPE( int do_reboot, (void) );
+_PROTOTYPE( int do_procstat, (void) );
_PROTOTYPE( int do_getsysinfo, (void) );
_PROTOTYPE( int do_getprocnr, (void) );
_PROTOTYPE( int do_svrctl, (void) );
FORWARD _PROTOTYPE( void dump_core, (struct mproc *rmp) );
FORWARD _PROTOTYPE( void unpause, (int pro) );
-FORWARD _PROTOTYPE( void handle_sig, (int proc_nr, sigset_t sig_map) );
+FORWARD _PROTOTYPE( void handle_ksig, (int proc_nr, sigset_t sig_map) );
FORWARD _PROTOTYPE( void cause_sigalrm, (struct timer *tp) );
/*===========================================================================*
int proc_nr_p;
if(pm_isokendpt(proc_nr_e, &proc_nr_p) != OK)
panic(__FILE__,"sys_getksig strange process", proc_nr_e);
- handle_sig(proc_nr_e, sig_map); /* handle the received signal */
+ handle_ksig(proc_nr_e, sig_map); /* handle the received signal */
/* If the process still exists to the kernel after the signal
* has been handled ...
*/
}
/*===========================================================================*
- * handle_sig *
+ * handle_ksig *
*===========================================================================*/
-PRIVATE void handle_sig(proc_nr_e, sig_map)
+PRIVATE void handle_ksig(proc_nr_e, sig_map)
int proc_nr_e;
sigset_t sig_map;
{
panic(__FILE__, "sys_sigsend failed", s);
}
else if (sigismember(&rmp->mp_sig2mess, signo)) {
- if (OK != (s=sys_kill(rmp->mp_endpoint,signo)))
- panic(__FILE__, "warning, sys_kill failed", s);
+
+ /* Mark event pending in process slot and send notification. */
+ sigaddset(&rmp->mp_sigpending, signo);
+ notify(rmp->mp_endpoint);
return;
}
/* Return EINVAL for attempts to send SIGKILL to INIT alone. */
if (proc_id == INIT_PID && signo == SIGKILL) return(EINVAL);
- /* Search the proc table for processes to signal. (See forkexit.c about
- * pid magic.)
+ /* Search the proc table for processes to signal.
+ * (See forkexit.c aboutpid magic.)
*/
count = 0;
error_code = ESRCH;
if (proc_id == -1 && rmp->mp_pid <= INIT_PID) continue;
if (proc_id < -1 && rmp->mp_procgrp != -proc_id) continue;
+ /* Do not kill servers and drivers when broadcasting SIGKILL. */
+ if (proc_id == -1 && signo == SIGKILL &&
+ (rmp->mp_flags & PRIV_PROC)) continue;
+
/* Check for permission. */
if (mp->mp_effuid != SUPER_USER
&& mp->mp_realuid != rmp->mp_realuid
do_sigreturn, /* 75 = sigreturn */
do_reboot, /* 76 = reboot */
do_svrctl, /* 77 = svrctl */
-
- no_sys, /* 78 = unused */
+ do_procstat, /* 78 = procstat */
do_getsysinfo, /* 79 = getsysinfo */
do_getprocnr, /* 80 = getprocnr */
no_sys, /* 81 = unused */
{
/* An unrecoverable error has occurred. Panics are caused when an internal
* inconsistency is detected, e.g., a programming error or illegal value of a
- * defined constant. The process manager decides to shut down. This results
- * in a HARD_STOP notification to all system processes to allow local cleanup.
+ * defined constant. The process manager decides to exit.
*/
message m;
int s;
printf("PM panic (%s): %s", who, mess);
if (num != NO_NUM) printf(": %d",num);
printf("\n");
-
-#if 0
- /* Allow for debug dumps if the IS server is available. */
- m.m_type = PANIC_DUMPS;
- if (OK == (s= nb_send(11, &m))) {
- return; /* IS responsible for exit */
- }
- printf("Shutting down: IS is not answering: %d\n", s);
- sys_abort(RBT_PANIC);
-#endif
+
+ /* Exit PM. */
sys_exit(SELF);
}
/* Declare some local functions. */
FORWARD _PROTOTYPE(void init_server, (void) );
+FORWARD _PROTOTYPE(void sig_handler, (void) );
FORWARD _PROTOTYPE(void get_work, (message *m) );
FORWARD _PROTOTYPE(void reply, (int whom, int result) );
case SYN_ALARM:
do_period(&m); /* check drivers status */
continue;
- case SYS_SIG:
- sigset = (sigset_t) m.NOTIFY_ARG; /* check signals passed */
- if (sigismember(&sigset, SIGCHLD)) do_exit(&m);
- if (sigismember(&sigset, SIGTERM)) do_shutdown(NULL);
- if (sigismember(&sigset, SIGKSTOP)) do_shutdown(NULL);
+ case PROC_EVENT:
+ sig_handler();
continue;
default: /* heartbeat notification */
if (rproc_ptr[who_p] != NULL) /* mark heartbeat time */
sa.sa_flags = 0;
if (sigaction(SIGCHLD,&sa,NULL)<0) panic("RS","sigaction failed", errno);
if (sigaction(SIGTERM,&sa,NULL)<0) panic("RS","sigaction failed", errno);
- if (sigaction(SIGABRT,&sa,NULL)<0) panic("RS","sigaction failed", errno);
- if (sigaction(SIGHUP, &sa,NULL)<0) panic("RS","sigaction failed", errno);
/* Initialize the system process table. Use the boot image from the kernel
* and the device map from the FS to gather all needed information.
}
+/*===========================================================================*
+ * sig_handler *
+ *===========================================================================*/
+PRIVATE void sig_handler()
+{
+ sigset_t sigset;
+ int sig;
+
+ /* Try to obtain signal set from PM. */
+ if (getsigset(&sigset) != 0) return;
+
+ /* Check for known signals. */
+ if (sigismember(&sigset, SIGCHLD)) do_exit(NULL);
+ if (sigismember(&sigset, SIGTERM)) do_shutdown(NULL);
+}
/*===========================================================================*
* get_work *