Merge of David's ptrace branch. Summary:
o Support for ptrace T_ATTACH/T_DETACH and T_SYSCALL o PM signal handling logic should now work properly, even with debuggers being present o Asynchronous PM/VFS protocol, full IPC support for senda(), and AMF_NOREPLY senda() flag DETAILS Process stop and delay call handling of PM: o Added sys_runctl() kernel call with sys_stop() and sys_resume() aliases, for PM to stop and resume a process o Added exception for sending/syscall-traced processes to sys_runctl(), and matching SIGKREADY pseudo-signal to PM o Fixed PM signal logic to deal with requests from a process after stopping it (so-called "delay calls"), using the SIGKREADY facility o Fixed various PM panics due to race conditions with delay calls versus VFS calls o Removed special PRIO_STOP priority value o Added SYS_LOCK RTS kernel flag, to stop an individual process from running while modifying its process structure Signal and debugger handling in PM: o Fixed debugger signals being dropped if a second signal arrives when the debugger has not retrieved the first one o Fixed debugger signals being sent to the debugger more than once o Fixed debugger signals unpausing process in VFS; removed PM_UNPAUSE_TR protocol message o Detached debugger signals from general signal logic and from being blocked on VFS calls, meaning that even VFS can now be traced o Fixed debugger being unable to receive more than one pending signal in one process stop o Fixed signal delivery being delayed needlessly when multiple signals are pending o Fixed wait test for tracer, which was returning for children that were not waited for o Removed second parallel pending call from PM to VFS for any process o Fixed process becoming runnable between exec() and debugger trap o Added support for notifying the debugger before the parent when a debugged child exits o Fixed debugger death causing child to remain stopped forever o Fixed consistently incorrect use of _NSIG Extensions to ptrace(): o Added T_ATTACH and T_DETACH ptrace request, to attach and detach a debugger to and from a process o Added T_SYSCALL ptrace request, to trace system calls o Added T_SETOPT ptrace request, to set trace options o Added TO_TRACEFORK trace option, to attach automatically to children of a traced process o Added TO_ALTEXEC trace option, to send SIGSTOP instead of SIGTRAP upon a successful exec() of the tracee o Extended T_GETUSER ptrace support to allow retrieving a process's priv structure o Removed T_STOP ptrace request again, as it does not help implementing debuggers properly o Added MINIX3-specific ptrace test (test42) o Added proper manual page for ptrace(2) Asynchronous PM/VFS interface: o Fixed asynchronous messages not being checked when receive() is called with an endpoint other than ANY o Added AMF_NOREPLY senda() flag, preventing such messages from satisfying the receive part of a sendrec() o Added asynsend3() that takes optional flags; asynsend() is now a #define passing in 0 as third parameter o Made PM/VFS protocol asynchronous; reintroduced tell_fs() o Made PM_BASE request/reply number range unique o Hacked in a horrible temporary workaround into RS to deal with newly revealed RS-PM-VFS race condition triangle until VFS is asynchronous System signal handling: o Fixed shutdown logic of device drivers; removed old SIGKSTOP signal o Removed is-superuser check from PM's do_procstat() (aka getsigset()) o Added sigset macros to allow system processes to deal with the full signal set, rather than just the POSIX subset Miscellaneous PM fixes: o Split do_getset into do_get and do_set, merging common code and making structure clearer o Fixed setpriority() being able to put to sleep processes using an invalid parameter, or revive zombie processes o Made find_proc() global; removed obsolete proc_from_pid() o Cleanup here and there Also included: o Fixed false-positive boot order kernel warning o Removed last traces of old NOTIFY_FROM code THINGS OF POSSIBLE INTEREST o It should now be possible to run PM at any priority, even lower than user processes o No assumptions are made about communication speed between PM and VFS, although communication must be FIFO o A debugger will now receive incoming debuggee signals at kill time only; the process may not yet be fully stopped o A first step has been made towards making the SYSTEM task preemptible
This commit is contained in:
parent
8d9aa1fe4f
commit
b423d7b477
70 changed files with 3177 additions and 1446 deletions
|
@ -44,6 +44,7 @@
|
|||
|
||||
#include "audio_fw.h"
|
||||
#include <sys/vm.h>
|
||||
#include <minix/endpoint.h>
|
||||
#include <minix/ds.h>
|
||||
#include <sys/vm_i386.h>
|
||||
|
||||
|
@ -92,14 +93,29 @@ PUBLIC void main(void)
|
|||
caller = mess.m_source;
|
||||
proc_nr = mess.IO_ENDPT;
|
||||
|
||||
if (caller == RS_PROC_NR && mess.m_type == DEV_PING)
|
||||
{
|
||||
/* Now carry out the work. First check for notifications. */
|
||||
if (is_notify(mess.m_type)) {
|
||||
switch (_ENDPOINT_P(mess.m_source)) {
|
||||
case HARDWARE:
|
||||
msg_hardware();
|
||||
break;
|
||||
case PM_PROC_NR:
|
||||
msg_sig_stop();
|
||||
break;
|
||||
case RS_PROC_NR:
|
||||
/* Got ping from RS. Just notify RS */
|
||||
notify(RS_PROC_NR);
|
||||
break;
|
||||
default:
|
||||
dprint("%s: %d uncaught notify!\n",
|
||||
drv.DriverName, mess.m_type);
|
||||
}
|
||||
|
||||
/* get next message */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now carry out the work. */
|
||||
/* Normal messages. */
|
||||
switch(mess.m_type) {
|
||||
case DEV_OPEN:
|
||||
/* open the special file ( = parameter) */
|
||||
|
@ -149,10 +165,6 @@ PUBLIC void main(void)
|
|||
repl_mess.REP_STATUS = r;
|
||||
send(caller, &repl_mess);
|
||||
continue;
|
||||
case HARD_INT:
|
||||
msg_hardware();continue; /* don't reply */
|
||||
case SYS_SIG:
|
||||
msg_sig_stop(); continue; /* don't reply */
|
||||
default:
|
||||
dprint("%s: %d uncaught msg!\n",
|
||||
drv.DriverName, mess.m_type);
|
||||
|
@ -883,14 +895,14 @@ PRIVATE int init_buffers(sub_dev_t *sub_dev_ptr)
|
|||
{
|
||||
#if (CHIP == INTEL)
|
||||
char *base;
|
||||
size_t size, off;
|
||||
size_t size;
|
||||
unsigned left;
|
||||
u32_t i;
|
||||
phys_bytes ph;
|
||||
|
||||
/* allocate dma buffer space */
|
||||
size= sub_dev_ptr->DmaSize + 64 * 1024;
|
||||
off = base= alloc_contig(size, AC_ALIGN4K, &ph);
|
||||
base= alloc_contig(size, AC_ALIGN4K, &ph);
|
||||
if (!base) {
|
||||
error("%s: failed to allocate dma buffer for channel %d\n",
|
||||
drv.DriverName,i);
|
||||
|
|
|
@ -281,17 +281,20 @@ int main(int argc, char *argv[])
|
|||
case HARDWARE:
|
||||
r = handle_hw_intr();
|
||||
break;
|
||||
case SYSTEM:
|
||||
if (sigismember((sigset_t*)
|
||||
&m.NOTIFY_ARG,
|
||||
SIGKSTOP))
|
||||
case PM_PROC_NR:
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
if (getsigset(&set) != 0) break;
|
||||
|
||||
if (sigismember(&set, SIGTERM))
|
||||
dp8390_stop();
|
||||
|
||||
break;
|
||||
}
|
||||
case CLOCK:
|
||||
printf("dp8390: notify from CLOCK\n");
|
||||
break;
|
||||
case PM_PROC_NR:
|
||||
break;
|
||||
default:
|
||||
panic("", "dp8390: illegal notify from",
|
||||
m.m_source);
|
||||
|
|
|
@ -544,10 +544,12 @@ static void do_watchdog(void *message)
|
|||
|
||||
PRIVATE void handle_system_signal(message *m)
|
||||
{
|
||||
sigset_t sigset = m->NOTIFY_ARG;
|
||||
sigset_t set;
|
||||
int port;
|
||||
|
||||
if (sigismember(&sigset, SIGKSTOP)) { /* Shut down */
|
||||
if (getsigset(&set) != 0) return;
|
||||
|
||||
if (sigismember(&set, SIGTERM)) { /* Shut down */
|
||||
for (port = 0; port < DE_PORT_NR; port += 1) {
|
||||
if (de_table[port].de_mode == DEM_ENABLED) {
|
||||
m->m_type = DL_STOP;
|
||||
|
@ -624,9 +626,6 @@ PUBLIC int main(int argc, char **argv)
|
|||
/* Status request from RS */
|
||||
notify(m.m_source);
|
||||
break;
|
||||
case SYSTEM:
|
||||
handle_system_signal(&m);
|
||||
break;
|
||||
case HARDWARE:
|
||||
/* Interrupt from device */
|
||||
handle_hw_intr();
|
||||
|
@ -636,6 +635,7 @@ PUBLIC int main(int argc, char **argv)
|
|||
do_dump(&m);
|
||||
break;
|
||||
case PM_PROC_NR:
|
||||
handle_system_signal(&m);
|
||||
break;
|
||||
default:
|
||||
/* Invalid message type */
|
||||
|
|
|
@ -263,7 +263,7 @@ FORWARD _PROTOTYPE( void f_reset, (void) );
|
|||
FORWARD _PROTOTYPE( int f_intr_wait, (void) );
|
||||
FORWARD _PROTOTYPE( int read_id, (void) );
|
||||
FORWARD _PROTOTYPE( int f_do_open, (struct driver *dp, message *m_ptr) );
|
||||
FORWARD _PROTOTYPE( void floppy_stop, (struct driver *dp, message *m_ptr));
|
||||
FORWARD _PROTOTYPE( void floppy_stop, (struct driver *dp, sigset_t *set));
|
||||
FORWARD _PROTOTYPE( int test_read, (int density) );
|
||||
FORWARD _PROTOTYPE( void f_geometry, (struct partition *entry) );
|
||||
|
||||
|
@ -805,12 +805,11 @@ timer_t *tp;
|
|||
/*===========================================================================*
|
||||
* floppy_stop *
|
||||
*===========================================================================*/
|
||||
PRIVATE void floppy_stop(struct driver *dp, message *m_ptr)
|
||||
PRIVATE void floppy_stop(struct driver *dp, sigset_t *set)
|
||||
{
|
||||
/* Stop all activity and cleanly exit with the system. */
|
||||
int s;
|
||||
sigset_t sigset = m_ptr->NOTIFY_ARG;
|
||||
if (sigismember(&sigset, SIGTERM) || sigismember(&sigset, SIGKSTOP)) {
|
||||
if (sigismember(set, SIGTERM)) {
|
||||
if ((s=sys_outb(DOR, ENABLE_INT)) != OK)
|
||||
panic("FLOPPY","Sys_outb in floppy_stop() failed", s);
|
||||
exit(0);
|
||||
|
|
|
@ -353,12 +353,17 @@ int main(int argc, char *argv[])
|
|||
case HARDWARE:
|
||||
handle_hw_intr();
|
||||
break;
|
||||
case SYSTEM:
|
||||
if (sigismember((sigset_t *)&m.NOTIFY_ARG, SIGKSTOP))
|
||||
fxp_stop();
|
||||
break;
|
||||
case PM_PROC_NR:
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
if (getsigset(&set) != 0) break;
|
||||
|
||||
if (sigismember(&set, SIGTERM))
|
||||
fxp_stop();
|
||||
|
||||
break;
|
||||
}
|
||||
case CLOCK:
|
||||
fxp_expire_timers();
|
||||
break;
|
||||
|
@ -2639,7 +2644,7 @@ static void fxp_stop()
|
|||
printf("%s: resetting device\n", fp->fxp_name);
|
||||
fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET);
|
||||
}
|
||||
sys_exit(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
|
@ -328,10 +328,6 @@ void main( int argc, char **argv )
|
|||
case TTY_PROC_NR:
|
||||
lance_dump();
|
||||
break;
|
||||
case SYSTEM:
|
||||
if (sigismember((sigset_t*)&m.NOTIFY_ARG, SIGKSTOP))
|
||||
lance_stop();
|
||||
break;
|
||||
case HARDWARE:
|
||||
for (i=0;i<EC_PORT_NR_MAX;++i)
|
||||
{
|
||||
|
@ -348,7 +344,16 @@ void main( int argc, char **argv )
|
|||
}
|
||||
break;
|
||||
case PM_PROC_NR:
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
if (getsigset(&set) != 0) break;
|
||||
|
||||
if (sigismember(&set, SIGTERM))
|
||||
lance_stop();
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic( "lance", "illegal notify source", m.m_source);
|
||||
}
|
||||
|
@ -469,7 +474,7 @@ static void lance_stop()
|
|||
printf("LANCE driver stopped.\n");
|
||||
#endif
|
||||
|
||||
sys_exit( 0 );
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ struct driver *dp; /* Device dependent entry points. */
|
|||
|
||||
int r, proc_nr;
|
||||
message mess;
|
||||
sigset_t set;
|
||||
|
||||
system_hz = sys_hz();
|
||||
|
||||
|
@ -104,8 +105,12 @@ struct driver *dp; /* Device dependent entry points. */
|
|||
}
|
||||
break;
|
||||
case PM_PROC_NR:
|
||||
if (getsigset(&set) != 0) break;
|
||||
(*dp->dr_signal)(dp, &set);
|
||||
break;
|
||||
case SYSTEM:
|
||||
(*dp->dr_signal)(dp, &mess);
|
||||
set = mess.NOTIFY_ARG;
|
||||
(*dp->dr_signal)(dp, &set);
|
||||
break;
|
||||
case CLOCK:
|
||||
(*dp->dr_alarm)(dp, &mess);
|
||||
|
@ -349,9 +354,9 @@ int safe;
|
|||
/*============================================================================*
|
||||
* nop_signal *
|
||||
*============================================================================*/
|
||||
PUBLIC void nop_signal(dp, mp)
|
||||
PUBLIC void nop_signal(dp, set)
|
||||
struct driver *dp;
|
||||
message *mp;
|
||||
sigset_t *set;
|
||||
{
|
||||
/* Default action for signal is to ignore. */
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ struct driver {
|
|||
iovec_t *iov, unsigned nr_req, int safe) );
|
||||
_PROTOTYPE( void (*dr_cleanup), (void) );
|
||||
_PROTOTYPE( void (*dr_geometry), (struct partition *entry) );
|
||||
_PROTOTYPE( void (*dr_signal), (struct driver *dp, message *m_ptr) );
|
||||
_PROTOTYPE( void (*dr_signal), (struct driver *dp, sigset_t *set) );
|
||||
_PROTOTYPE( void (*dr_alarm), (struct driver *dp, message *m_ptr) );
|
||||
_PROTOTYPE( int (*dr_cancel), (struct driver *dp, message *m_ptr) );
|
||||
_PROTOTYPE( int (*dr_select), (struct driver *dp, message *m_ptr) );
|
||||
|
@ -60,7 +60,7 @@ _PROTOTYPE( int do_nop, (struct driver *dp, message *m_ptr) );
|
|||
_PROTOTYPE( struct device *nop_prepare, (int device) );
|
||||
_PROTOTYPE( void nop_cleanup, (void) );
|
||||
_PROTOTYPE( void nop_task, (void) );
|
||||
_PROTOTYPE( void nop_signal, (struct driver *dp, message *m_ptr) );
|
||||
_PROTOTYPE( void nop_signal, (struct driver *dp, sigset_t *set) );
|
||||
_PROTOTYPE( void nop_alarm, (struct driver *dp, message *m_ptr) );
|
||||
_PROTOTYPE( int nop_cancel, (struct driver *dp, message *m_ptr) );
|
||||
_PROTOTYPE( int nop_select, (struct driver *dp, message *m_ptr) );
|
||||
|
|
|
@ -53,8 +53,6 @@ FORWARD _PROTOTYPE( void init_buffer, (void) );
|
|||
FORWARD _PROTOTYPE( int do_rdwt, (struct driver *dr, message *mp, int safe) );
|
||||
FORWARD _PROTOTYPE( int do_vrdwt, (struct driver *dr, message *mp, int safe) );
|
||||
|
||||
_PROTOTYPE( int asynsend, (endpoint_t dst, message *mp));
|
||||
|
||||
int device_caller;
|
||||
PRIVATE mq_t *queue_head = NULL;
|
||||
|
||||
|
@ -68,6 +66,7 @@ struct driver *dp; /* Device dependent entry points. */
|
|||
|
||||
int r, proc_nr;
|
||||
message mess, reply_mess;
|
||||
sigset_t set;
|
||||
|
||||
/* Init MQ library. */
|
||||
mq_init();
|
||||
|
@ -117,8 +116,12 @@ struct driver *dp; /* Device dependent entry points. */
|
|||
}
|
||||
break;
|
||||
case PM_PROC_NR:
|
||||
if (getsigset(&set) != 0) break;
|
||||
(*dp->dr_signal)(dp, &set);
|
||||
break;
|
||||
case SYSTEM:
|
||||
(*dp->dr_signal)(dp, &mess);
|
||||
set = mess.NOTIFY_ARG;
|
||||
(*dp->dr_signal)(dp, &set);
|
||||
break;
|
||||
case CLOCK:
|
||||
(*dp->dr_alarm)(dp, &mess);
|
||||
|
@ -409,9 +412,9 @@ int safe;
|
|||
/*============================================================================*
|
||||
* nop_signal *
|
||||
*============================================================================*/
|
||||
PUBLIC void nop_signal(dp, mp)
|
||||
PUBLIC void nop_signal(dp, set)
|
||||
struct driver *dp;
|
||||
message *mp;
|
||||
sigset_t *set;
|
||||
{
|
||||
/* Default action for signal is to ignore. */
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ struct driver {
|
|||
iovec_t *iov, unsigned nr_req, int safe) );
|
||||
_PROTOTYPE( void (*dr_cleanup), (void) );
|
||||
_PROTOTYPE( void (*dr_geometry), (struct partition *entry) );
|
||||
_PROTOTYPE( void (*dr_signal), (struct driver *dp, message *m_ptr) );
|
||||
_PROTOTYPE( void (*dr_signal), (struct driver *dp, sigset_t *set) );
|
||||
_PROTOTYPE( void (*dr_alarm), (struct driver *dp, message *m_ptr) );
|
||||
_PROTOTYPE( int (*dr_cancel), (struct driver *dp, message *m_ptr) );
|
||||
_PROTOTYPE( int (*dr_select), (struct driver *dp, message *m_ptr) );
|
||||
|
@ -60,7 +60,7 @@ _PROTOTYPE( int do_nop, (struct driver *dp, message *m_ptr) );
|
|||
_PROTOTYPE( struct device *nop_prepare, (int device) );
|
||||
_PROTOTYPE( void nop_cleanup, (void) );
|
||||
_PROTOTYPE( void nop_task, (void) );
|
||||
_PROTOTYPE( void nop_signal, (struct driver *dp, message *m_ptr) );
|
||||
_PROTOTYPE( void nop_signal, (struct driver *dp, sigset_t *set) );
|
||||
_PROTOTYPE( void nop_alarm, (struct driver *dp, message *m_ptr) );
|
||||
_PROTOTYPE( int nop_cancel, (struct driver *dp, message *m_ptr) );
|
||||
_PROTOTYPE( int nop_select, (struct driver *dp, message *m_ptr) );
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
/*==========================================================================*
|
||||
* do_new_kmess *
|
||||
*==========================================================================*/
|
||||
PUBLIC int do_new_kmess(m)
|
||||
message *m; /* notification message */
|
||||
PUBLIC int do_new_kmess(from)
|
||||
endpoint_t from; /* who sent this message? */
|
||||
{
|
||||
/* Notification for a new kernel message. */
|
||||
static struct kmessages kmess; /* entire kmess structure */
|
||||
|
@ -31,7 +31,7 @@ message *m; /* notification message */
|
|||
static int kernel_prev_next = 0;
|
||||
static int tty_prev_next = 0;
|
||||
|
||||
if (m->m_source == TTY_PROC_NR)
|
||||
if (from == TTY_PROC_NR)
|
||||
{
|
||||
cp_grant_id_t gid;
|
||||
message mess;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "log.h"
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <minix/endpoint.h>
|
||||
|
||||
#define LOG_DEBUG 0 /* enable/ disable debugging */
|
||||
|
||||
|
@ -28,7 +29,7 @@ FORWARD _PROTOTYPE( int log_transfer, (int proc_nr, int opcode, u64_t position,
|
|||
FORWARD _PROTOTYPE( int log_do_open, (struct driver *dp, message *m_ptr) );
|
||||
FORWARD _PROTOTYPE( int log_cancel, (struct driver *dp, message *m_ptr) );
|
||||
FORWARD _PROTOTYPE( int log_select, (struct driver *dp, message *m_ptr) );
|
||||
FORWARD _PROTOTYPE( void log_signal, (struct driver *dp, message *m_ptr) );
|
||||
FORWARD _PROTOTYPE( void log_signal, (struct driver *dp, sigset_t *set) );
|
||||
FORWARD _PROTOTYPE( int log_other, (struct driver *dp, message *m_ptr, int) );
|
||||
FORWARD _PROTOTYPE( void log_geometry, (struct partition *entry) );
|
||||
FORWARD _PROTOTYPE( int subread, (struct logdevice *log, int count, int proc_nr, vir_bytes user_vir, size_t, int safe) );
|
||||
|
@ -368,13 +369,12 @@ message *m_ptr;
|
|||
/*============================================================================*
|
||||
* log_signal *
|
||||
*============================================================================*/
|
||||
PRIVATE void log_signal(dp, m_ptr)
|
||||
PRIVATE void log_signal(dp, set)
|
||||
struct driver *dp;
|
||||
message *m_ptr;
|
||||
sigset_t *set;
|
||||
{
|
||||
sigset_t sigset = m_ptr->NOTIFY_ARG;
|
||||
if (sigismember(&sigset, SIGKMESS)) {
|
||||
do_new_kmess(m_ptr);
|
||||
if (sigismember(set, SIGKMESS)) {
|
||||
do_new_kmess(SYSTEM);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -392,6 +392,19 @@ int safe;
|
|||
/* This function gets messages that the generic driver doesn't
|
||||
* understand.
|
||||
*/
|
||||
if (is_notify(m_ptr->m_type)) {
|
||||
switch (_ENDPOINT_P(m_ptr->m_source)) {
|
||||
case TTY_PROC_NR:
|
||||
do_new_kmess(m_ptr->m_source);
|
||||
r = EDONTREPLY;
|
||||
break;
|
||||
default:
|
||||
r = EINVAL;
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
switch(m_ptr->m_type) {
|
||||
case DIAGNOSTICS_OLD: {
|
||||
r = do_diagnostics(m_ptr, 0);
|
||||
|
@ -406,10 +419,6 @@ int safe;
|
|||
r = EDONTREPLY;
|
||||
break;
|
||||
}
|
||||
case NOTIFY_FROM(TTY_PROC_NR):
|
||||
do_new_kmess(m_ptr);
|
||||
r = EDONTREPLY;
|
||||
break;
|
||||
default:
|
||||
r = EINVAL;
|
||||
break;
|
||||
|
|
|
@ -31,7 +31,7 @@ struct logdevice {
|
|||
};
|
||||
|
||||
/* Function prototypes. */
|
||||
_PROTOTYPE( int do_new_kmess, (message *m) );
|
||||
_PROTOTYPE( int do_new_kmess, (endpoint_t from) );
|
||||
_PROTOTYPE( int do_diagnostics, (message *m, int safe) );
|
||||
_PROTOTYPE( void log_append, (char *buf, int len) );
|
||||
|
||||
|
|
|
@ -280,11 +280,6 @@ int main(int argc, char *argv[]) {
|
|||
case CLOCK:
|
||||
or_watchdog_f(NULL);
|
||||
break;
|
||||
case SYSTEM:
|
||||
if (sigismember((sigset_t*)&m.NOTIFY_ARG,
|
||||
SIGKSTOP))
|
||||
orinoco_stop();
|
||||
break;
|
||||
case HARDWARE:
|
||||
do_hard_int();
|
||||
if (int_event_check)
|
||||
|
@ -294,7 +289,16 @@ int main(int argc, char *argv[]) {
|
|||
or_dump(&m);
|
||||
break;
|
||||
case PM_PROC_NR:
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
if (getsigset(&set) != 0) break;
|
||||
|
||||
if (sigismember(&set, SIGTERM))
|
||||
orinoco_stop();
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic(__FILE__,
|
||||
"orinoco: illegal notify from:",
|
||||
|
@ -424,7 +428,7 @@ static void orinoco_stop () {
|
|||
continue;
|
||||
/* TODO: send a signal to the card to shut it down */
|
||||
}
|
||||
sys_exit(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
|
|
@ -90,7 +90,7 @@ PRIVATE int revive_pending; /* set to true if revive is pending */
|
|||
PRIVATE int revive_status; /* revive status */
|
||||
PRIVATE int done_status; /* status of last output completion */
|
||||
PRIVATE int oleft; /* bytes of output left in obuf */
|
||||
PRIVATE char obuf[128]; /* output buffer */
|
||||
PRIVATE unsigned char obuf[128]; /* output buffer */
|
||||
PRIVATE unsigned char *optr; /* ptr to next char in obuf to print */
|
||||
PRIVATE int orig_count; /* original byte count */
|
||||
PRIVATE int port_base; /* I/O port for printer */
|
||||
|
@ -113,7 +113,7 @@ FORWARD _PROTOTYPE( void prepare_output, (void) );
|
|||
FORWARD _PROTOTYPE( void do_initialize, (void) );
|
||||
FORWARD _PROTOTYPE( void reply, (int code,int replyee,int proc,int status));
|
||||
FORWARD _PROTOTYPE( void do_printer_output, (void) );
|
||||
FORWARD _PROTOTYPE( void do_signal, (message *m_ptr) );
|
||||
FORWARD _PROTOTYPE( void do_signal, (void) );
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -140,13 +140,11 @@ PUBLIC void main(void)
|
|||
case HARDWARE:
|
||||
do_printer_output();
|
||||
break;
|
||||
case SYSTEM:
|
||||
do_signal(&pr_mess);
|
||||
break;
|
||||
case RS_PROC_NR:
|
||||
notify(pr_mess.m_source);
|
||||
break;
|
||||
case PM_PROC_NR:
|
||||
do_signal();
|
||||
break;
|
||||
default:
|
||||
reply(TASK_REPLY, pr_mess.m_source,
|
||||
|
@ -175,11 +173,11 @@ PUBLIC void main(void)
|
|||
/*===========================================================================*
|
||||
* do_signal *
|
||||
*===========================================================================*/
|
||||
PRIVATE void do_signal(m_ptr)
|
||||
message *m_ptr; /* signal message */
|
||||
PRIVATE void do_signal()
|
||||
{
|
||||
int sig;
|
||||
sigset_t sigset = m_ptr->NOTIFY_ARG;
|
||||
sigset_t sigset;
|
||||
|
||||
if (getsigset(&sigset) != 0) return;
|
||||
|
||||
/* Expect a SIGTERM signal when this server must shutdown. */
|
||||
if (sigismember(&sigset, SIGTERM)) {
|
||||
|
|
|
@ -369,11 +369,6 @@ int main(int argc, char *argv[])
|
|||
*/
|
||||
rl_watchdog_f(NULL);
|
||||
break;
|
||||
case SYSTEM:
|
||||
if (sigismember((sigset_t*)&m.NOTIFY_ARG,
|
||||
SIGKSTOP))
|
||||
rtl8139_stop();
|
||||
break;
|
||||
case HARDWARE:
|
||||
do_hard_int();
|
||||
if (int_event_check)
|
||||
|
@ -383,7 +378,16 @@ int main(int argc, char *argv[])
|
|||
rtl8139_dump(&m);
|
||||
break;
|
||||
case PM_PROC_NR:
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
if (getsigset(&set) != 0) break;
|
||||
|
||||
if (sigismember(&set, SIGTERM))
|
||||
rtl8139_stop();
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic("rtl8139","illegal notify from",
|
||||
m.m_source);
|
||||
|
|
|
@ -64,20 +64,10 @@
|
|||
/* FIXME will be is_notify(a) ((a) == NOTIFY_MESSAGE) */
|
||||
#define is_notify(a) ((a) & NOTIFY_MESSAGE)
|
||||
#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 */
|
||||
# define FKEY_PRESSED NOTIFY_FROM(TTY_PROC_NR)/* function key press */
|
||||
# define DEV_PING NOTIFY_FROM(RS_PROC_NR) /* driver liveness ping */
|
||||
# define DS_UPDATE NOTIFY_FROM(DS_PROC_NR) /* subscription update */
|
||||
|
||||
/* Shorthands for message parameters passed with notifications. */
|
||||
#define NOTIFY_SOURCE m_source
|
||||
#define NOTIFY_TYPE m_type
|
||||
#define NOTIFY_ARG m2_l1
|
||||
#define NOTIFY_TIMESTAMP m2_l2
|
||||
#define NOTIFY_FLAGS m2_i1
|
||||
|
||||
/*===========================================================================*
|
||||
* Messages for BUS controller drivers *
|
||||
|
@ -330,8 +320,9 @@
|
|||
# define SYS_SYSCTL (KERNEL_CALL + 44) /* sys_sysctl() */
|
||||
|
||||
# define SYS_VTIMER (KERNEL_CALL + 45) /* sys_vtimer() */
|
||||
# define SYS_RUNCTL (KERNEL_CALL + 46) /* sys_runctl() */
|
||||
|
||||
#define NR_SYS_CALLS 46 /* number of system calls */
|
||||
#define NR_SYS_CALLS 47 /* number of system calls */
|
||||
|
||||
/* Pseudo call for use in kernel/table.c. */
|
||||
#define SYS_ALL_CALLS (NR_SYS_CALLS)
|
||||
|
@ -621,6 +612,12 @@
|
|||
#define VT_VALUE m2_l1 /* new/previous value of the timer */
|
||||
#define VT_ENDPT m2_l2 /* process to set/retrieve the timer for */
|
||||
|
||||
/* Field names for SYS_RUNCTL. */
|
||||
#define RC_ENDPT m1_i1 /* which process to stop or resume */
|
||||
#define RC_ACTION m1_i2 /* set or clear stop flag */
|
||||
# define RC_STOP 0 /* stop the process, unless delaying */
|
||||
# define RC_RESUME 1 /* clear the stop flag */
|
||||
|
||||
/*===========================================================================*
|
||||
* Messages for the Reincarnation Server *
|
||||
*===========================================================================*/
|
||||
|
@ -696,52 +693,57 @@
|
|||
|
||||
#define DIAG_REPL_OLD (DIAG_BASE+0x80+0) /* reply to DIAGNOSTICS(_S) */
|
||||
|
||||
#define PM_BASE 0x900
|
||||
#define PM_GET_WORK (PM_BASE + 1) /* Get work from PM */
|
||||
#define PM_IDLE (PM_BASE + 2) /* PM doesn't have any more work */
|
||||
#define PM_BUSY (PM_BASE + 3) /* A reply from FS is needed */
|
||||
#define PM_SETSID (PM_BASE + 5) /* Tell FS about the session leader */
|
||||
#define PM_SETSID_PROC m1_i1 /* process */
|
||||
#define PM_SETGID (PM_BASE + 6) /* Tell FS about the new group IDs */
|
||||
#define PM_SETGID_PROC m1_i1 /* process */
|
||||
#define PM_SETGID_EGID m1_i2 /* effective group id */
|
||||
#define PM_SETGID_RGID m1_i3 /* real group id */
|
||||
#define PM_SETUID (PM_BASE + 7) /* Tell FS about the new user IDs */
|
||||
#define PM_SETUID_PROC m1_i1 /* process */
|
||||
#define PM_SETUID_EGID m1_i2 /* effective user id */
|
||||
#define PM_SETUID_RGID m1_i3 /* real user id */
|
||||
#define PM_FORK (PM_BASE + 8) /* Tell FS about the new process */
|
||||
#define PM_FORK_PPROC m1_i1 /* parent process */
|
||||
#define PM_FORK_CPROC m1_i2 /* child process */
|
||||
#define PM_FORK_CPID m1_i3 /* child pid */
|
||||
#define PM_EXIT (PM_BASE + 9) /* Tell FS about the exiting process */
|
||||
#define PM_EXIT_PROC m1_i1 /* process */
|
||||
#define PM_UNPAUSE (PM_BASE + 10) /* interrupted process */
|
||||
#define PM_UNPAUSE_PROC m1_i1 /* process */
|
||||
#define PM_REBOOT (PM_BASE + 11) /* Tell FS that we about to reboot */
|
||||
#define PM_EXEC (PM_BASE + 12) /* Forward exec call to FS */
|
||||
#define PM_EXEC_PROC m1_i1 /* process */
|
||||
#define PM_EXEC_PATH m1_p1 /* executable */
|
||||
#define PM_EXEC_PATH_LEN m1_i2 /* length of path including
|
||||
/*===========================================================================*
|
||||
* Messages used between PM and VFS *
|
||||
*===========================================================================*/
|
||||
|
||||
#define PM_BASE 0xE00
|
||||
|
||||
/* Requests from PM to VFS */
|
||||
#define PM_SETUID (PM_BASE + 1) /* Tell FS about the new user IDs */
|
||||
#define PM_SETGID (PM_BASE + 2) /* Tell FS about the new group IDs */
|
||||
#define PM_SETSID (PM_BASE + 3) /* Tell FS about the session leader */
|
||||
#define PM_EXIT (PM_BASE + 4) /* Tell FS about the exiting process */
|
||||
#define PM_DUMPCORE (PM_BASE + 5) /* Ask FS to generate a core dump */
|
||||
#define PM_EXEC (PM_BASE + 6) /* Forward exec call to FS */
|
||||
#define PM_FORK (PM_BASE + 7) /* Tell FS about the new process */
|
||||
#define PM_FORK_NB (PM_BASE + 8) /* Tell FS about the fork_nb call */
|
||||
#define PM_UNPAUSE (PM_BASE + 9) /* interrupted process */
|
||||
#define PM_REBOOT (PM_BASE + 10) /* Tell FS that we about to reboot */
|
||||
|
||||
/* Replies from VFS to PM */
|
||||
#define PM_SETUID_REPLY (PM_BASE + 21)
|
||||
#define PM_SETGID_REPLY (PM_BASE + 22)
|
||||
#define PM_SETSID_REPLY (PM_BASE + 23)
|
||||
#define PM_EXIT_REPLY (PM_BASE + 24)
|
||||
#define PM_CORE_REPLY (PM_BASE + 25)
|
||||
#define PM_EXEC_REPLY (PM_BASE + 26)
|
||||
#define PM_FORK_REPLY (PM_BASE + 27)
|
||||
#define PM_FORK_NB_REPLY (PM_BASE + 28)
|
||||
#define PM_UNPAUSE_REPLY (PM_BASE + 29)
|
||||
#define PM_REBOOT_REPLY (PM_BASE + 30)
|
||||
|
||||
/* Standard parameters for all requests and replies, except PM_REBOOT */
|
||||
# define PM_PROC m1_i1 /* process */
|
||||
|
||||
/* Additional parameters for PM_SETUID and PM_SETGID */
|
||||
# define PM_EID m1_i2 /* effective user/group id */
|
||||
# define PM_RID m1_i3 /* real user/group id */
|
||||
|
||||
/* Additional parameters for PM_EXEC */
|
||||
# define PM_PATH m1_p1 /* executable */
|
||||
# define PM_PATH_LEN m1_i2 /* length of path including
|
||||
* terminating nul
|
||||
*/
|
||||
#define PM_EXEC_FRAME m1_p2 /* arguments and environment */
|
||||
#define PM_EXEC_FRAME_LEN m1_i3 /* size of frame */
|
||||
#define PM_FORK_NB (PM_BASE + 13) /* Tell FS about the fork_nb call */
|
||||
#define PM_DUMPCORE (PM_BASE + 14) /* Ask FS to generate a core dump */
|
||||
#define PM_CORE_PROC m1_i1
|
||||
#define PM_CORE_SEGPTR m1_p1
|
||||
#define PM_UNPAUSE_TR (PM_BASE + 15) /* interrupted process (for tracing) */
|
||||
# define PM_FRAME m1_p2 /* arguments and environment */
|
||||
# define PM_FRAME_LEN m1_i3 /* size of frame */
|
||||
|
||||
/* Replies */
|
||||
#define PM_EXIT_REPLY (PM_BASE + 20) /* Reply from FS */
|
||||
#define PM_REBOOT_REPLY (PM_BASE + 21) /* Reply from FS */
|
||||
#define PM_EXEC_REPLY (PM_BASE + 22) /* Reply from FS */
|
||||
/* PM_EXEC_PROC m1_i1 */
|
||||
#define PM_EXEC_STATUS m1_i2 /* OK or failure */
|
||||
#define PM_CORE_REPLY (PM_BASE + 23) /* Reply from FS */
|
||||
/* PM_CORE_PROC m1_i1 */
|
||||
#define PM_CORE_STATUS m1_i2 /* OK or failure */
|
||||
/* Additional parameters for PM_EXEC_REPLY and PM_CORE_REPLY */
|
||||
# define PM_STATUS m1_i2 /* OK or failure */
|
||||
|
||||
/* Additional parameters for PM_FORK and PM_FORK_NB */
|
||||
# define PM_PPROC m1_i2 /* parent process */
|
||||
# define PM_CPID m1_i3 /* child pid */
|
||||
|
||||
/* Parameters for the EXEC_NEWMEM call */
|
||||
#define EXC_NM_PROC m1_i1 /* process that needs new map */
|
||||
|
|
|
@ -133,6 +133,7 @@ typedef struct asynmsg
|
|||
* result is stored in 'result'
|
||||
*/
|
||||
#define AMF_NOTIFY 4 /* Send a notification when AMF_DONE is set */
|
||||
#define AMF_NOREPLY 8 /* Not a reply message for a SENDREC */
|
||||
|
||||
/* Hide names to avoid name space pollution. */
|
||||
#define echo _echo
|
||||
|
|
|
@ -40,6 +40,11 @@ _PROTOTYPE( int sys_newmap, (endpoint_t proc_ep, struct mem_map *ptr));
|
|||
_PROTOTYPE( int sys_exit, (endpoint_t proc_ep));
|
||||
_PROTOTYPE( int sys_trace, (int req, endpoint_t proc_ep, long addr, long *data_p));
|
||||
|
||||
/* Shorthands for sys_runctl() system call. */
|
||||
#define sys_stop(proc_ep) sys_runctl(proc_ep, RC_STOP)
|
||||
#define sys_resume(proc_ep) sys_runctl(proc_ep, RC_RESUME)
|
||||
_PROTOTYPE( int sys_runctl, (endpoint_t proc_ep, int action));
|
||||
|
||||
_PROTOTYPE( int sys_privctl, (endpoint_t proc_ep, int req, void *p));
|
||||
_PROTOTYPE( int sys_setgrant, (cp_grant_t *grants, int ngrants));
|
||||
_PROTOTYPE( int sys_nice, (endpoint_t proc_ep, int priority));
|
||||
|
|
|
@ -56,10 +56,11 @@ _PROTOTYPE( void util_nstrcat, (char *str, unsigned long n) );
|
|||
_PROTOTYPE( void util_stacktrace_strcat, (char *));
|
||||
_PROTOTYPE( int micro_delay, (u32_t micros));
|
||||
_PROTOTYPE( u32_t micros_to_ticks, (u32_t micros));
|
||||
_PROTOTYPE( int asynsend, (endpoint_t ep, message *msg));
|
||||
_PROTOTYPE( void ser_putc, (char c));
|
||||
_PROTOTYPE( void get_randomness, (struct k_randomness *, int));
|
||||
|
||||
#define asynsend(ep, msg) asynsend3(ep, msg, 0)
|
||||
_PROTOTYPE( int asynsend3, (endpoint_t ep, message *msg, int flags));
|
||||
|
||||
#define ASSERT(c) if(!(c)) { panic(__FILE__, "assert " #c " failed at line", __LINE__); }
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <minix/endpoint.h>
|
||||
|
||||
_PROTOTYPE( int vm_exit, (endpoint_t ep));
|
||||
_PROTOTYPE( int vm_fork, (endpoint_t ep, int slotno, int *child_ep));
|
||||
_PROTOTYPE( int vm_fork, (endpoint_t ep, int slotno, endpoint_t *child_ep));
|
||||
_PROTOTYPE( int vm_brk, (endpoint_t ep, char *newaddr));
|
||||
_PROTOTYPE( int vm_exec_newmem, (endpoint_t ep, struct exec_newmem *args,
|
||||
int args_bytes, char **ret_stack_top, int *ret_flags));
|
||||
|
|
|
@ -66,7 +66,7 @@ typedef unsigned long sigset_t;
|
|||
*/
|
||||
#define SIGKMESS 29 /* new kernel message */
|
||||
#define SIGKSIG 30 /* kernel signal pending */
|
||||
#define SIGKSTOP 31 /* kernel shutting down */
|
||||
#define SIGKREADY 31 /* ready for signal delivery */
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -113,15 +113,29 @@ _PROTOTYPE( int kill, (pid_t _pid, int _sig) );
|
|||
_PROTOTYPE( int killpg, (pid_t _pgrp, int _sig) );
|
||||
_PROTOTYPE( int sigaction,
|
||||
(int _sig, const struct sigaction *_act, struct sigaction *_oact) );
|
||||
_PROTOTYPE( int sigpending, (sigset_t *_set) );
|
||||
_PROTOTYPE( int sigprocmask,
|
||||
(int _how, const sigset_t *_set, sigset_t *_oset) );
|
||||
_PROTOTYPE( int sigsuspend, (const sigset_t *_sigmask) );
|
||||
|
||||
/* For the sigset functions, only use the library version with error
|
||||
* checking from user programs. System programs need to be able to use
|
||||
* nonstanard signals.
|
||||
*/
|
||||
#ifndef _SYSTEM
|
||||
_PROTOTYPE( int sigaddset, (sigset_t *_set, int _sig) );
|
||||
_PROTOTYPE( int sigdelset, (sigset_t *_set, int _sig) );
|
||||
_PROTOTYPE( int sigemptyset, (sigset_t *_set) );
|
||||
_PROTOTYPE( int sigfillset, (sigset_t *_set) );
|
||||
_PROTOTYPE( int sigismember, (const sigset_t *_set, int _sig) );
|
||||
_PROTOTYPE( int sigpending, (sigset_t *_set) );
|
||||
_PROTOTYPE( int sigprocmask,
|
||||
(int _how, const sigset_t *_set, sigset_t *_oset) );
|
||||
_PROTOTYPE( int sigsuspend, (const sigset_t *_sigmask) );
|
||||
#else
|
||||
#define sigaddset(set, sig) ((int) ((*(set) |= (1 << (sig))) && 0))
|
||||
#define sigdelset(set, sig) ((int) ((*(set) &= ~(1 << (sig))) && 0))
|
||||
#define sigemptyset(set) ((int) (*(set) = 0))
|
||||
#define sigfillset(set) ((int) ((*(set) = ~0) && 0))
|
||||
#define sigismember(set, sig) ((*(set) & (1 << (sig))) ? 1 : 0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _SIGNAL_H */
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#ifndef _PTRACE_H
|
||||
#define _PTRACE_H
|
||||
|
||||
/* Trace requests. */
|
||||
#define T_STOP -1 /* stop the process */
|
||||
#define T_OK 0 /* enable tracing by parent for this process */
|
||||
#define T_GETINS 1 /* return value from instruction space */
|
||||
|
@ -16,6 +17,10 @@
|
|||
#define T_RESUME 7 /* resume execution */
|
||||
#define T_EXIT 8 /* exit */
|
||||
#define T_STEP 9 /* set trace bit */
|
||||
#define T_SYSCALL 10 /* trace system call */
|
||||
#define T_ATTACH 11 /* attach to a running process */
|
||||
#define T_DETACH 12 /* detach from a traced process */
|
||||
#define T_SETOPT 13 /* set trace options */
|
||||
|
||||
#define T_READB_INS 100 /* Read a byte from the text segment of an
|
||||
* untraced process (only for root)
|
||||
|
@ -24,6 +29,10 @@
|
|||
* untraced process (only for root)
|
||||
*/
|
||||
|
||||
/* Trace options. */
|
||||
#define TO_TRACEFORK 0x1 /* automatically attach to forked children */
|
||||
#define TO_ALTEXEC 0x2 /* send SIGSTOP on successful exec() */
|
||||
|
||||
/* Function Prototypes. */
|
||||
#ifndef _ANSI_H
|
||||
#include <ansi.h>
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
#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
|
||||
|
|
|
@ -166,6 +166,7 @@ struct proc *t;
|
|||
* k_reenter larger than zero.
|
||||
*/
|
||||
if (k_reenter == 0 && ! iskernelp(saved_proc)) {
|
||||
#if 0
|
||||
{
|
||||
|
||||
kprintf(
|
||||
|
@ -181,6 +182,7 @@ struct proc *t;
|
|||
proc_stacktrace(saved_proc);
|
||||
}
|
||||
|
||||
#endif
|
||||
cause_sig(proc_nr(saved_proc), ep->signum);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -367,10 +367,8 @@ set_restart1:
|
|||
_s_call:
|
||||
_p_s_call:
|
||||
cld ! set direction flag to a known value
|
||||
sub esp, 6*4 ! skip RETADR, eax, ecx, edx, ebx, est
|
||||
push ebp ! stack already points into proc table
|
||||
push esi
|
||||
push edi
|
||||
sub esp, 4 ! skip RETADR
|
||||
pushad ! save "general" registers
|
||||
o16 push ds
|
||||
o16 push es
|
||||
o16 push fs
|
||||
|
|
|
@ -353,3 +353,23 @@ PUBLIC int arch_set_params(char *params, int size)
|
|||
return OK;
|
||||
}
|
||||
|
||||
PUBLIC void arch_do_syscall(struct proc *proc)
|
||||
{
|
||||
/* Perform a previously postponed system call.
|
||||
*/
|
||||
int call_nr, src_dst_e;
|
||||
message *m_ptr;
|
||||
long bit_map;
|
||||
|
||||
/* Get the system call parameters from their respective registers. */
|
||||
call_nr = proc->p_reg.cx;
|
||||
src_dst_e = proc->p_reg.retreg;
|
||||
m_ptr = (message *) proc->p_reg.bx;
|
||||
bit_map = proc->p_reg.dx;
|
||||
|
||||
/* sys_call() expects the given process's memory to be accessible. */
|
||||
vm_set_cr3(proc);
|
||||
|
||||
/* Make the system call, for real this time. */
|
||||
proc->p_reg.retreg = sys_call(call_nr, src_dst_e, m_ptr, bit_map);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "proc.h"
|
||||
#include <signal.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/endpoint.h>
|
||||
#include <minix/portio.h>
|
||||
|
||||
/* Function prototype for PRIVATE functions.
|
||||
|
@ -79,11 +80,18 @@ PUBLIC void clock_task()
|
|||
minix_panic("receive() failed", result);
|
||||
|
||||
/* Handle the request. Only clock ticks are expected. */
|
||||
switch (m.m_type) {
|
||||
case HARD_INT:
|
||||
if (is_notify(m.m_type)) {
|
||||
switch (_ENDPOINT_P(m.m_source)) {
|
||||
case HARDWARE:
|
||||
do_clocktick(&m); /* handle clock tick */
|
||||
break;
|
||||
default: /* illegal request type */
|
||||
kprintf("CLOCK: illegal notify %d from %d.\n",
|
||||
m.m_type, m.m_source);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* illegal request type */
|
||||
kprintf("CLOCK: illegal request %d from %d.\n",
|
||||
m.m_type, m.m_source);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#define USE_PHYSCOPY 1 /* copy using physical addressing */
|
||||
#define USE_PHYSVCOPY 1 /* vector with physical copy requests */
|
||||
#define USE_MEMSET 1 /* write char to a given memory area */
|
||||
#define USE_RUNCTL 1 /* control stop flags of a process */
|
||||
|
||||
/* Length of program names stored in the process table. This is only used
|
||||
* for the debugging dumps that can be generated with the IS server. The PM
|
||||
|
|
|
@ -117,7 +117,7 @@ rtsflagstr(int flags)
|
|||
#define FLAG(n) if(flags & n) { strcat(str, #n " "); }
|
||||
|
||||
FLAG(SLOT_FREE);
|
||||
FLAG(NO_PRIORITY);
|
||||
FLAG(PROC_STOP);
|
||||
FLAG(SENDING);
|
||||
FLAG(RECEIVING);
|
||||
FLAG(SIGNALED);
|
||||
|
|
|
@ -87,7 +87,7 @@ PUBLIC void main()
|
|||
priv(rp)->s_trap_mask = ip->trap_mask; /* allowed traps */
|
||||
|
||||
/* Warn about violations of the boot image table order consistency. */
|
||||
if (priv_id(rp) != s_nr_to_id(ip->proc_nr))
|
||||
if (priv_id(rp) != s_nr_to_id(ip->proc_nr) && (ip->flags & SYS_PROC))
|
||||
kprintf("Warning: boot image table has wrong process order\n");
|
||||
|
||||
/* Initialize call mask bitmap from unordered set.
|
||||
|
@ -173,7 +173,7 @@ PUBLIC void main()
|
|||
RTS_SET(rp, VMINHIBIT);
|
||||
|
||||
/* Set ready. The HARDWARE task is never ready. */
|
||||
if (rp->p_nr == HARDWARE) RTS_SET(rp, NO_PRIORITY);
|
||||
if (rp->p_nr == HARDWARE) RTS_SET(rp, PROC_STOP);
|
||||
RTS_UNSET(rp, SLOT_FREE); /* remove SLOT_FREE and schedule */
|
||||
alloc_segments(rp);
|
||||
}
|
||||
|
|
162
kernel/proc.c
162
kernel/proc.c
|
@ -59,7 +59,8 @@ FORWARD _PROTOTYPE( int mini_senda, (struct proc *caller_ptr,
|
|||
FORWARD _PROTOTYPE( int deadlock, (int function,
|
||||
register struct proc *caller, int src_dst));
|
||||
FORWARD _PROTOTYPE( int try_async, (struct proc *caller_ptr));
|
||||
FORWARD _PROTOTYPE( int try_one, (struct proc *src_ptr, struct proc *dst_ptr));
|
||||
FORWARD _PROTOTYPE( int try_one, (struct proc *src_ptr, struct proc *dst_ptr,
|
||||
int *postponed));
|
||||
FORWARD _PROTOTYPE( void sched, (struct proc *rp, int *queue, int *front));
|
||||
FORWARD _PROTOTYPE( void pick_proc, (void));
|
||||
|
||||
|
@ -137,19 +138,74 @@ PUBLIC void schedcheck(void)
|
|||
}
|
||||
vmassert(proc_ptr);
|
||||
vmassert(!proc_ptr->p_rts_flags);
|
||||
while(proc_ptr->p_misc_flags & MF_DELIVERMSG) {
|
||||
while (proc_ptr->p_misc_flags &
|
||||
(MF_DELIVERMSG | MF_SC_DEFER | MF_SC_TRACE | MF_SC_ACTIVE)) {
|
||||
|
||||
vmassert(!next_ptr);
|
||||
vmassert(!proc_ptr->p_rts_flags);
|
||||
if (proc_ptr->p_misc_flags & MF_DELIVERMSG) {
|
||||
TRACE(VF_SCHEDULING, printf("delivering to %s / %d\n",
|
||||
proc_ptr->p_name, proc_ptr->p_endpoint););
|
||||
if(delivermsg(proc_ptr) == VMSUSPEND) {
|
||||
vmassert(next_ptr);
|
||||
TRACE(VF_SCHEDULING, printf("suspending %s / %d\n",
|
||||
proc_ptr->p_name, proc_ptr->p_endpoint););
|
||||
TRACE(VF_SCHEDULING,
|
||||
printf("suspending %s / %d\n",
|
||||
proc_ptr->p_name,
|
||||
proc_ptr->p_endpoint););
|
||||
vmassert(proc_ptr->p_rts_flags);
|
||||
vmassert(next_ptr != proc_ptr);
|
||||
}
|
||||
}
|
||||
else if (proc_ptr->p_misc_flags & MF_SC_DEFER) {
|
||||
/* Perform the system call that we deferred earlier. */
|
||||
|
||||
#if DEBUG_SCHED_CHECK
|
||||
if (proc_ptr->p_misc_flags & MF_SC_ACTIVE)
|
||||
minix_panic("MF_SC_ACTIVE and MF_SC_DEFER set",
|
||||
NO_NUM);
|
||||
#endif
|
||||
|
||||
arch_do_syscall(proc_ptr);
|
||||
|
||||
/* If the process is stopped for signal delivery, and
|
||||
* not blocked sending a message after the system call,
|
||||
* inform PM.
|
||||
*/
|
||||
if ((proc_ptr->p_misc_flags & MF_SIG_DELAY) &&
|
||||
!RTS_ISSET(proc_ptr, SENDING))
|
||||
sig_delay_done(proc_ptr);
|
||||
}
|
||||
else if (proc_ptr->p_misc_flags & MF_SC_TRACE) {
|
||||
/* Trigger a system call leave event if this was a
|
||||
* system call. We must do this after processing the
|
||||
* other flags above, both for tracing correctness and
|
||||
* to be able to use 'break'.
|
||||
*/
|
||||
if (!(proc_ptr->p_misc_flags & MF_SC_ACTIVE))
|
||||
break;
|
||||
|
||||
proc_ptr->p_misc_flags &=
|
||||
~(MF_SC_TRACE | MF_SC_ACTIVE);
|
||||
|
||||
/* Signal the "leave system call" event.
|
||||
* Block the process.
|
||||
*/
|
||||
cause_sig(proc_nr(proc_ptr), SIGTRAP);
|
||||
}
|
||||
else if (proc_ptr->p_misc_flags & MF_SC_ACTIVE) {
|
||||
/* If MF_SC_ACTIVE was set, remove it now:
|
||||
* we're leaving the system call.
|
||||
*/
|
||||
proc_ptr->p_misc_flags &= ~MF_SC_ACTIVE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* If proc_ptr is now descheduled,
|
||||
* continue with another process.
|
||||
*/
|
||||
if (next_ptr) {
|
||||
proc_ptr = next_ptr;
|
||||
vmassert(!proc_ptr->p_rts_flags);
|
||||
next_ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -181,6 +237,37 @@ long bit_map; /* notification event set or flags */
|
|||
int src_dst_p; /* Process slot number */
|
||||
size_t msg_size;
|
||||
|
||||
/* If this process is subject to system call tracing, handle that first. */
|
||||
if (caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) {
|
||||
/* Are we tracing this process, and is it the first sys_call entry? */
|
||||
if ((caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) ==
|
||||
MF_SC_TRACE) {
|
||||
/* We must notify the tracer before processing the actual
|
||||
* system call. If we don't, the tracer could not obtain the
|
||||
* input message. Postpone the entire system call.
|
||||
*/
|
||||
caller_ptr->p_misc_flags &= ~MF_SC_TRACE;
|
||||
caller_ptr->p_misc_flags |= MF_SC_DEFER;
|
||||
|
||||
/* Signal the "enter system call" event. Block the process. */
|
||||
cause_sig(proc_nr(caller_ptr), SIGTRAP);
|
||||
|
||||
/* Preserve the return register's value. */
|
||||
return caller_ptr->p_reg.retreg;
|
||||
}
|
||||
|
||||
/* If the MF_SC_DEFER flag is set, the syscall is now being resumed. */
|
||||
caller_ptr->p_misc_flags &= ~MF_SC_DEFER;
|
||||
|
||||
#if DEBUG_SCHED_CHECK
|
||||
if (caller_ptr->p_misc_flags & MF_SC_ACTIVE)
|
||||
minix_panic("MF_SC_ACTIVE already set", NO_NUM);
|
||||
#endif
|
||||
|
||||
/* Set a flag to allow reliable tracing of leaving the system call. */
|
||||
caller_ptr->p_misc_flags |= MF_SC_ACTIVE;
|
||||
}
|
||||
|
||||
#if DEBUG_SCHED_CHECK
|
||||
if(caller_ptr->p_misc_flags & MF_DELIVERMSG) {
|
||||
kprintf("sys_call: MF_DELIVERMSG on for %s / %d\n",
|
||||
|
@ -593,6 +680,8 @@ int flags;
|
|||
vmassert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
|
||||
QueueMess((*xpp)->p_endpoint,
|
||||
vir2phys(&(*xpp)->p_sendmsg), caller_ptr);
|
||||
if ((*xpp)->p_misc_flags & MF_SIG_DELAY)
|
||||
sig_delay_done(*xpp);
|
||||
RTS_UNSET(*xpp, SENDING);
|
||||
*xpp = (*xpp)->p_q_link; /* remove from queue */
|
||||
return(OK); /* report success */
|
||||
|
@ -603,16 +692,10 @@ int flags;
|
|||
if (caller_ptr->p_misc_flags & MF_ASYNMSG)
|
||||
{
|
||||
if (src_e != ANY)
|
||||
{
|
||||
#if 0
|
||||
kprintf("mini_receive: should try async from %d\n", src_e);
|
||||
#endif
|
||||
r= EAGAIN;
|
||||
}
|
||||
r= try_one(proc_addr(src_p), caller_ptr, NULL);
|
||||
else
|
||||
{
|
||||
r= try_async(caller_ptr);
|
||||
}
|
||||
|
||||
if (r == OK)
|
||||
return OK; /* Got a message */
|
||||
}
|
||||
|
@ -772,7 +855,7 @@ size_t size;
|
|||
continue;
|
||||
|
||||
/* Check for reserved bits in the flags field */
|
||||
if (flags & ~(AMF_VALID|AMF_DONE|AMF_NOTIFY) ||
|
||||
if (flags & ~(AMF_VALID|AMF_DONE|AMF_NOTIFY|AMF_NOREPLY) ||
|
||||
!(flags & AMF_VALID))
|
||||
{
|
||||
return EINVAL;
|
||||
|
@ -831,14 +914,13 @@ size_t size;
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Check if 'dst' is blocked waiting for this message. The
|
||||
* destination's SENDING flag may be set when its SENDREC call
|
||||
* blocked while sending.
|
||||
/* Check if 'dst' is blocked waiting for this message.
|
||||
* If AMF_NOREPLY is set, do not satisfy the receiving part of
|
||||
* a SENDREC.
|
||||
*/
|
||||
if ( (dst_ptr->p_rts_flags & (RECEIVING | SENDING)) ==
|
||||
RECEIVING &&
|
||||
(dst_ptr->p_getfrom_e == ANY ||
|
||||
dst_ptr->p_getfrom_e == caller_ptr->p_endpoint))
|
||||
if (WILLRECEIVE(dst_ptr, caller_ptr->p_endpoint) &&
|
||||
(!(flags & AMF_NOREPLY) ||
|
||||
!(dst_ptr->p_misc_flags & MF_REPLY_PEND)))
|
||||
{
|
||||
/* Destination is indeed waiting for this message. */
|
||||
m_ptr= &table[i].msg; /* Note: pointer in the
|
||||
|
@ -887,24 +969,24 @@ struct proc *caller_ptr;
|
|||
int r;
|
||||
struct priv *privp;
|
||||
struct proc *src_ptr;
|
||||
int postponed = FALSE;
|
||||
|
||||
/* Try all privilege structures */
|
||||
for (privp = BEG_PRIV_ADDR; privp < END_PRIV_ADDR; ++privp)
|
||||
{
|
||||
if (privp->s_proc_nr == NONE || privp->s_id == USER_PRIV_ID)
|
||||
continue;
|
||||
if (privp->s_asynsize == 0)
|
||||
if (privp->s_proc_nr == NONE)
|
||||
continue;
|
||||
|
||||
src_ptr= proc_addr(privp->s_proc_nr);
|
||||
if (!may_send_to(src_ptr, proc_nr(caller_ptr)))
|
||||
continue;
|
||||
|
||||
vmassert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
|
||||
r= try_one(src_ptr, caller_ptr);
|
||||
r= try_one(src_ptr, caller_ptr, &postponed);
|
||||
if (r == OK)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Nothing found, clear MF_ASYNMSG */
|
||||
/* Nothing found, clear MF_ASYNMSG unless messages were postponed */
|
||||
if (postponed == FALSE)
|
||||
caller_ptr->p_misc_flags &= ~MF_ASYNMSG;
|
||||
|
||||
return ESRCH;
|
||||
|
@ -914,9 +996,10 @@ struct proc *caller_ptr;
|
|||
/*===========================================================================*
|
||||
* try_one *
|
||||
*===========================================================================*/
|
||||
PRIVATE int try_one(src_ptr, dst_ptr)
|
||||
PRIVATE int try_one(src_ptr, dst_ptr, postponed)
|
||||
struct proc *src_ptr;
|
||||
struct proc *dst_ptr;
|
||||
int *postponed;
|
||||
{
|
||||
int i, do_notify, done;
|
||||
unsigned flags;
|
||||
|
@ -931,6 +1014,12 @@ struct proc *dst_ptr;
|
|||
int r;
|
||||
|
||||
privp= priv(src_ptr);
|
||||
|
||||
/* Basic validity checks */
|
||||
if (privp->s_id == USER_PRIV_ID) return EAGAIN;
|
||||
if (privp->s_asynsize == 0) return EAGAIN;
|
||||
if (!may_send_to(src_ptr, proc_nr(dst_ptr))) return EAGAIN;
|
||||
|
||||
size= privp->s_asynsize;
|
||||
table_v = privp->s_asyntab;
|
||||
caller_ptr = src_ptr;
|
||||
|
@ -953,7 +1042,7 @@ struct proc *dst_ptr;
|
|||
}
|
||||
|
||||
/* Check for reserved bits in the flags field */
|
||||
if (flags & ~(AMF_VALID|AMF_DONE|AMF_NOTIFY) ||
|
||||
if (flags & ~(AMF_VALID|AMF_DONE|AMF_NOTIFY|AMF_NOREPLY) ||
|
||||
!(flags & AMF_VALID))
|
||||
{
|
||||
kprintf("try_one: bad bits in table\n");
|
||||
|
@ -980,6 +1069,19 @@ struct proc *dst_ptr;
|
|||
continue;
|
||||
}
|
||||
|
||||
/* If AMF_NOREPLY is set, do not satisfy the receiving part of
|
||||
* a SENDREC. Do not unset MF_ASYNMSG later because of this,
|
||||
* though: this message is still to be delivered later.
|
||||
*/
|
||||
if ((flags & AMF_NOREPLY) &&
|
||||
(dst_ptr->p_misc_flags & MF_REPLY_PEND))
|
||||
{
|
||||
if (postponed != NULL)
|
||||
*postponed = TRUE;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Deliver message */
|
||||
table_ptr= (asynmsg_t *)privp->s_asyntab;
|
||||
m_ptr= &table_ptr[i].msg; /* Note: pointer in the
|
||||
|
|
|
@ -106,7 +106,7 @@ struct proc {
|
|||
|
||||
/* Bits for the runtime flags. A process is runnable iff p_rts_flags == 0. */
|
||||
#define SLOT_FREE 0x01 /* process slot is free */
|
||||
#define NO_PRIORITY 0x02 /* process has been stopped */
|
||||
#define PROC_STOP 0x02 /* process has been stopped */
|
||||
#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 */
|
||||
|
@ -118,6 +118,7 @@ struct proc {
|
|||
#define PAGEFAULT 0x400 /* process has unhandled pagefault */
|
||||
#define VMREQUEST 0x800 /* originator of vm memory request */
|
||||
#define VMREQTARGET 0x1000 /* target of vm memory request */
|
||||
#define SYS_LOCK 0x2000 /* temporary process lock flag for systask */
|
||||
|
||||
/* These runtime flags can be tested and manipulated by these macros. */
|
||||
|
||||
|
@ -177,12 +178,16 @@ struct proc {
|
|||
} while(0)
|
||||
|
||||
/* Misc flags */
|
||||
#define MF_REPLY_PEND 0x01 /* reply to IPC_REQUEST is pending */
|
||||
#define MF_VIRT_TIMER 0x02 /* process-virtual timer is running */
|
||||
#define MF_PROF_TIMER 0x04 /* process-virtual profile timer is running */
|
||||
#define MF_ASYNMSG 0x10 /* Asynchrous message pending */
|
||||
#define MF_FULLVM 0x20
|
||||
#define MF_DELIVERMSG 0x40 /* Copy message for him before running */
|
||||
#define MF_REPLY_PEND 0x001 /* reply to IPC_REQUEST is pending */
|
||||
#define MF_VIRT_TIMER 0x002 /* process-virtual timer is running */
|
||||
#define MF_PROF_TIMER 0x004 /* process-virtual profile timer is running */
|
||||
#define MF_ASYNMSG 0x010 /* Asynchrous message pending */
|
||||
#define MF_FULLVM 0x020
|
||||
#define MF_DELIVERMSG 0x040 /* Copy message for him before running */
|
||||
#define MF_SIG_DELAY 0x080 /* Send signal when no longer sending */
|
||||
#define MF_SC_ACTIVE 0x100 /* Syscall tracing: in a system call now */
|
||||
#define MF_SC_DEFER 0x200 /* Syscall tracing: deferred system call */
|
||||
#define MF_SC_TRACE 0x400 /* Syscall tracing: trigger syscall events */
|
||||
|
||||
/* Scheduling priorities for p_priority. Values must start at zero (highest
|
||||
* priority) and increment. Priorities of the processes in the boot image
|
||||
|
|
|
@ -58,6 +58,7 @@ _PROTOTYPE( void set_sendto_bit, (struct proc *rc, int id) );
|
|||
_PROTOTYPE( void unset_sendto_bit, (struct proc *rc, int id) );
|
||||
_PROTOTYPE( void send_sig, (int proc_nr, int sig_nr) );
|
||||
_PROTOTYPE( void cause_sig, (int proc_nr, int sig_nr) );
|
||||
_PROTOTYPE( void sig_delay_done, (struct proc *rp) );
|
||||
_PROTOTYPE( void sys_task, (void) );
|
||||
#define numap_local(proc_nr, vir_addr, bytes) \
|
||||
umap_local(proc_addr(proc_nr), D, (vir_addr), (bytes))
|
||||
|
@ -173,5 +174,6 @@ _PROTOTYPE( int vm_suspend, (struct proc *caller, struct proc *target,
|
|||
_PROTOTYPE( int delivermsg, (struct proc *target));
|
||||
_PROTOTYPE( phys_bytes arch_switch_copymsg, (struct proc *rp, message *m,
|
||||
phys_bytes lin));
|
||||
_PROTOTYPE( void arch_do_syscall, (struct proc *proc) );
|
||||
|
||||
#endif /* PROTO_H */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
* unset_sendto_bit: disallow a process from sending messages to a target
|
||||
* send_sig: send a signal directly to a system process
|
||||
* cause_sig: take action to cause a signal to occur via PM
|
||||
* sig_delay_done: tell PM that a process is not sending
|
||||
* umap_bios: map virtual address in BIOS_SEG to physical
|
||||
* get_randomness: accumulate randomness in a buffer
|
||||
* clear_endpoint: remove a process' ability to send and receive messages
|
||||
|
@ -178,6 +179,7 @@ PRIVATE void initialize(void)
|
|||
map(SYS_PRIVCTL, do_privctl); /* system privileges control */
|
||||
map(SYS_TRACE, do_trace); /* request a trace operation */
|
||||
map(SYS_SETGRANT, do_setgrant); /* get/set own parameters */
|
||||
map(SYS_RUNCTL, do_runctl); /* set/clear stop flag of a process */
|
||||
|
||||
/* Signal handling. */
|
||||
map(SYS_KILL, do_kill); /* cause a process to be signaled */
|
||||
|
@ -365,6 +367,22 @@ int sig_nr; /* signal to be sent, 1 to _NSIG */
|
|||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sig_delay_done *
|
||||
*===========================================================================*/
|
||||
PUBLIC void sig_delay_done(rp)
|
||||
struct proc *rp;
|
||||
{
|
||||
/* A process is now known not to send any direct messages.
|
||||
* Tell PM by sending a signal to the process.
|
||||
* Used for actual signal delivery.
|
||||
*/
|
||||
|
||||
rp->p_misc_flags &= ~MF_SIG_DELAY;
|
||||
|
||||
cause_sig(proc_nr(rp), SIGKREADY);
|
||||
}
|
||||
|
||||
#if _MINIX_CHIP == _CHIP_INTEL
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
|
@ -69,6 +69,11 @@ _PROTOTYPE( int do_nice, (message *m_ptr) );
|
|||
#define do_nice do_unused
|
||||
#endif
|
||||
|
||||
_PROTOTYPE( int do_runctl, (message *m_ptr) );
|
||||
#if ! USE_RUNCTL
|
||||
#define do_runctl do_unused
|
||||
#endif
|
||||
|
||||
_PROTOTYPE( int do_copy, (message *m_ptr) );
|
||||
#define do_vircopy do_copy
|
||||
#if ! (USE_VIRCOPY || USE_PHYSCOPY)
|
||||
|
|
|
@ -29,6 +29,7 @@ OBJECTS = \
|
|||
$(SYSTEM)(do_exit.o) \
|
||||
$(SYSTEM)(do_trace.o) \
|
||||
$(SYSTEM)(do_nice.o) \
|
||||
$(SYSTEM)(do_runctl.o) \
|
||||
$(SYSTEM)(do_times.o) \
|
||||
$(SYSTEM)(do_setalarm.o) \
|
||||
$(SYSTEM)(do_stime.o) \
|
||||
|
@ -92,6 +93,9 @@ $(SYSTEM)(do_trace.o): do_trace.c
|
|||
$(SYSTEM)(do_nice.o): do_nice.c
|
||||
$(CC) do_nice.c
|
||||
|
||||
$(SYSTEM)(do_runctl.o): do_runctl.c
|
||||
$(CC) do_runctl.c
|
||||
|
||||
$(SYSTEM)(do_times.o): do_times.c
|
||||
$(CC) do_times.c
|
||||
|
||||
|
|
|
@ -74,8 +74,7 @@ register message *m_ptr; /* pointer to request message */
|
|||
rpc->p_sys_time = 0;
|
||||
|
||||
rpc->p_reg.psw &= ~TRACEBIT; /* clear trace bit */
|
||||
|
||||
rpc->p_misc_flags &= ~(MF_VIRT_TIMER | MF_PROF_TIMER);
|
||||
rpc->p_misc_flags &= ~(MF_VIRT_TIMER | MF_PROF_TIMER | MF_SC_TRACE);
|
||||
rpc->p_virt_left = 0; /* disable, clear the process-virtual timers */
|
||||
rpc->p_prof_left = 0;
|
||||
|
||||
|
|
|
@ -27,17 +27,12 @@ PUBLIC int do_nice(message *m_ptr)
|
|||
pri = m_ptr->PR_PRIORITY;
|
||||
rp = proc_addr(proc_nr);
|
||||
|
||||
if (pri == PRIO_STOP) {
|
||||
/* Take process off the scheduling queues. */
|
||||
RTS_LOCK_SET(rp, 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.
|
||||
*/
|
||||
if (pri < PRIO_MIN || pri > PRIO_MAX) return(EINVAL);
|
||||
|
||||
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 */
|
||||
|
@ -46,14 +41,12 @@ PUBLIC int do_nice(message *m_ptr)
|
|||
/* Make sure the process is not running while changing its priority.
|
||||
* Put the process back in its new queue if it is runnable.
|
||||
*/
|
||||
RTS_LOCK_SET(rp, NO_PRIORITY);
|
||||
RTS_LOCK_SET(rp, SYS_LOCK);
|
||||
rp->p_max_priority = rp->p_priority = new_q;
|
||||
RTS_LOCK_UNSET(rp, NO_PRIORITY);
|
||||
RTS_LOCK_UNSET(rp, SYS_LOCK);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
return(EINVAL);
|
||||
}
|
||||
|
||||
#endif /* USE_NICE */
|
||||
|
||||
|
|
68
kernel/system/do_runctl.c
Normal file
68
kernel/system/do_runctl.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* The kernel call implemented in this file:
|
||||
* m_type: SYS_RUNCTL
|
||||
*
|
||||
* The parameters for this kernel call are:
|
||||
* m1_i1: RC_ENDPT process number to control
|
||||
* m1_i2: RC_ACTION stop or resume the process
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
#include <minix/type.h>
|
||||
|
||||
#if USE_RUNCTL
|
||||
|
||||
/*===========================================================================*
|
||||
* do_runctl *
|
||||
*===========================================================================*/
|
||||
PUBLIC int do_runctl(message *m_ptr)
|
||||
{
|
||||
/* Control a process's PROC_STOP flag. Used for process management.
|
||||
* If the process is queued sending a message or stopped for system call
|
||||
* tracing, set MF_SIG_DELAY instead of PROC_STOP, and send a SIGKREADY signal
|
||||
* later when the process is done sending. Used by PM for safe signal delivery.
|
||||
*/
|
||||
int proc_nr, action, delayed;
|
||||
register struct proc *rp;
|
||||
|
||||
/* Extract the message parameters and do sanity checking. */
|
||||
if (!isokendpt(m_ptr->RC_ENDPT, &proc_nr)) return(EINVAL);
|
||||
if (iskerneln(proc_nr)) return(EPERM);
|
||||
rp = proc_addr(proc_nr);
|
||||
|
||||
action = m_ptr->RC_ACTION;
|
||||
|
||||
/* Is the target sending or syscall-traced? Then set MF_SIG_DELAY instead.
|
||||
* The process will not become runnable before PM has called SYS_ENDKSIG.
|
||||
* Note that asynchronous messages are not covered: a process using SENDA
|
||||
* should not also install signal handlers *and* expect POSIX compliance.
|
||||
*/
|
||||
if (action == RC_STOP) {
|
||||
RTS_LOCK_SET(rp, SYS_LOCK);
|
||||
|
||||
if (RTS_ISSET(rp, SENDING) || (rp->p_misc_flags & MF_SC_DEFER))
|
||||
rp->p_misc_flags |= MF_SIG_DELAY;
|
||||
|
||||
delayed = (rp->p_misc_flags & MF_SIG_DELAY);
|
||||
|
||||
RTS_LOCK_UNSET(rp, SYS_LOCK);
|
||||
|
||||
if (delayed) return(EBUSY);
|
||||
}
|
||||
|
||||
/* Either set or clear the stop flag. */
|
||||
switch (action) {
|
||||
case RC_STOP:
|
||||
RTS_LOCK_SET(rp, PROC_STOP);
|
||||
break;
|
||||
case RC_RESUME:
|
||||
RTS_LOCK_UNSET(rp, PROC_STOP);
|
||||
break;
|
||||
default:
|
||||
return(EINVAL);
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
#endif /* USE_RUNCTL */
|
||||
|
|
@ -75,10 +75,7 @@ message *m_ptr; /* pointer to request message */
|
|||
rp->p_reg.sp = (reg_t) frp;
|
||||
rp->p_reg.pc = (reg_t) smsg.sm_sighandler;
|
||||
|
||||
/* Reschedule if necessary. */
|
||||
if(RTS_ISSET(rp, NO_PRIORITY))
|
||||
RTS_LOCK_UNSET(rp, NO_PRIORITY);
|
||||
else {
|
||||
if(!RTS_ISSET(rp, PROC_STOP)) {
|
||||
struct proc *caller;
|
||||
caller = proc_addr(who_p);
|
||||
kprintf("system: warning: sigsend a running process\n");
|
||||
|
|
|
@ -34,6 +34,7 @@ register message *m_ptr;
|
|||
* T_RESUME resume execution
|
||||
* T_EXIT exit
|
||||
* T_STEP set trace bit
|
||||
* T_SYSCALL trace system call
|
||||
*
|
||||
* The T_OK and T_EXIT commands are handled completely by the process manager,
|
||||
* all others come here.
|
||||
|
@ -81,11 +82,12 @@ register message *m_ptr;
|
|||
if (iskerneln(tr_proc_nr)) return(EPERM);
|
||||
|
||||
rp = proc_addr(tr_proc_nr);
|
||||
if (isemptyp(rp)) return(EIO);
|
||||
if (isemptyp(rp)) return(EINVAL);
|
||||
switch (tr_request) {
|
||||
case T_STOP: /* stop process */
|
||||
RTS_LOCK_SET(rp, P_STOP);
|
||||
rp->p_reg.psw &= ~TRACEBIT; /* clear trace bit */
|
||||
rp->p_misc_flags &= ~MF_SC_TRACE; /* clear syscall trace flag */
|
||||
return(OK);
|
||||
|
||||
case T_GETINS: /* return value from instruction space */
|
||||
|
@ -102,11 +104,23 @@ register message *m_ptr;
|
|||
break;
|
||||
|
||||
case T_GETUSER: /* return value from process table */
|
||||
if ((tr_addr & (sizeof(long) - 1)) != 0 ||
|
||||
tr_addr > sizeof(struct proc) - sizeof(long))
|
||||
return(EIO);
|
||||
if ((tr_addr & (sizeof(long) - 1)) != 0) return(EIO);
|
||||
|
||||
if (tr_addr <= sizeof(struct proc) - sizeof(long)) {
|
||||
m_ptr->CTL_DATA = *(long *) ((char *) rp + (int) tr_addr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* The process's proc struct is followed by its priv struct.
|
||||
* The alignment here should be unnecessary, but better safe..
|
||||
*/
|
||||
i = sizeof(long) - 1;
|
||||
tr_addr -= (sizeof(struct proc) + i) & ~i;
|
||||
|
||||
if (tr_addr > sizeof(struct priv) - sizeof(long)) return(EIO);
|
||||
|
||||
m_ptr->CTL_DATA = *(long *) ((char *) rp->p_priv + (int) tr_addr);
|
||||
break;
|
||||
|
||||
case T_SETINS: /* set value in instruction space */
|
||||
if (rp->p_memmap[T].mem_len != 0) {
|
||||
|
@ -160,6 +174,12 @@ register message *m_ptr;
|
|||
m_ptr->CTL_DATA = 0;
|
||||
break;
|
||||
|
||||
case T_SYSCALL: /* trace system call */
|
||||
rp->p_misc_flags |= MF_SC_TRACE;
|
||||
RTS_LOCK_UNSET(rp, P_STOP);
|
||||
m_ptr->CTL_DATA = 0;
|
||||
break;
|
||||
|
||||
case T_READB_INS: /* get value from instruction space */
|
||||
COPYFROMPROC(rp->p_memmap[T].mem_len > 0 ? T : D, tr_addr, (vir_bytes) &ub, 1);
|
||||
m_ptr->CTL_DATA = ub;
|
||||
|
@ -171,7 +191,7 @@ register message *m_ptr;
|
|||
break;
|
||||
|
||||
default:
|
||||
return(EIO);
|
||||
return(EINVAL);
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <lib.h>
|
||||
#define sigaction _sigaction
|
||||
#define sigemptyset _sigemptyset
|
||||
#define _SYSTEM 1
|
||||
#include <signal.h>
|
||||
|
||||
PUBLIC sighandler_t signal(sig, disp)
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
#include <lib.h>
|
||||
/* XXX - these have to be hidden because signal() uses them and signal() is
|
||||
* ANSI and not POSIX. It would be surely be better to use macros for the
|
||||
* library and system uses, and perhaps macros as well as functions for the
|
||||
* POSIX user interface. The macros would not need underlines. It may be
|
||||
* inconvenient to match the exact semantics of the current functions
|
||||
* because the interface is bloated by reporting errors. For library and
|
||||
* system uses, the signal number is mostly already known to be valid
|
||||
* before the sigset-changing routines are called.
|
||||
/* System processes use simpler macros with no range error checking (defined in
|
||||
* signal.h). The ANSI signal() implementation now also uses the macro
|
||||
* versions, which makes hiding of the functions here a historical remains.
|
||||
*/
|
||||
#define sigaddset _sigaddset
|
||||
#define sigdelset _sigdelset
|
||||
|
|
|
@ -46,6 +46,7 @@ libsys_FILES=" \
|
|||
sys_out.c \
|
||||
sys_physcopy.c \
|
||||
sys_readbios.c \
|
||||
sys_runctl.c \
|
||||
sys_safecopy.c \
|
||||
sys_sysctl.c \
|
||||
sys_vsafecopy.c \
|
||||
|
|
14
lib/syslib/sys_runctl.c
Normal file
14
lib/syslib/sys_runctl.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include "syslib.h"
|
||||
|
||||
/*===========================================================================*
|
||||
* sys_runctl *
|
||||
*===========================================================================*/
|
||||
PUBLIC int sys_runctl(endpoint_t proc_ep, int action)
|
||||
{
|
||||
message m;
|
||||
|
||||
m.RC_ENDPT = proc_ep;
|
||||
m.RC_ACTION = action;
|
||||
|
||||
return(_taskcall(SYSTASK, SYS_RUNCTL, &m));
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
/*===========================================================================*
|
||||
* vm_fork *
|
||||
*===========================================================================*/
|
||||
PUBLIC int vm_fork(endpoint_t ep, int slot, int *childep)
|
||||
PUBLIC int vm_fork(endpoint_t ep, int slot, endpoint_t *childep)
|
||||
{
|
||||
message m;
|
||||
int result;
|
||||
|
|
|
@ -22,9 +22,10 @@
|
|||
PRIVATE asynmsg_t msgtable[ASYN_NR];
|
||||
PRIVATE int first_slot= 0, next_slot= 0;
|
||||
|
||||
PUBLIC int asynsend(dst, mp)
|
||||
PUBLIC int asynsend3(dst, mp, fl)
|
||||
endpoint_t dst;
|
||||
message *mp;
|
||||
int fl;
|
||||
{
|
||||
int r, src_ind, dst_ind;
|
||||
unsigned flags;
|
||||
|
@ -115,9 +116,10 @@ message *mp;
|
|||
panic(__FILE__, "asynsend: msgtable full", NO_NUM);
|
||||
}
|
||||
|
||||
fl |= AMF_VALID;
|
||||
msgtable[next_slot].dst= dst;
|
||||
msgtable[next_slot].msg= *mp;
|
||||
msgtable[next_slot].flags= AMF_VALID; /* Has to be last. The kernel
|
||||
msgtable[next_slot].flags= fl; /* Has to be last. The kernel
|
||||
* scans this table while we
|
||||
* are sleeping.
|
||||
*/
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
.\" Copyright (c) 1980 Regents of the University of California.
|
||||
.\" All rights reserved. The Berkeley software License Agreement
|
||||
.\" specifies the terms and conditions for redistribution.
|
||||
.\"
|
||||
.\" @(#)ptrace.2 6.4 (Berkeley) 5/23/86
|
||||
.\"
|
||||
.TH PTRACE 2 "May 23, 1986"
|
||||
.TH PTRACE 2 "September 27, 2009"
|
||||
.UC 4
|
||||
.SH NAME
|
||||
ptrace \- process trace
|
||||
|
@ -12,220 +6,179 @@ ptrace \- process trace
|
|||
.nf
|
||||
.ft B
|
||||
#include <sys/types.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
int ptrace(int \fIrequest\fP, pid_t \fIpid\fP, long \fIaddr\fP, long \fIdata\fP)
|
||||
long ptrace(int \fIreq\fP, pid_t \fIpid\fP, long \fIaddr\fP, long \fIdata\fP)
|
||||
.ft R
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
.ft B
|
||||
Note: This manual page has no relation to MINIX 3. Someone who knows ptrace()
|
||||
has to check, or rewrite, this page. (kjb)
|
||||
.ft R
|
||||
.PP
|
||||
.B Ptrace
|
||||
provides a means by which a parent process
|
||||
may control the execution of a child process,
|
||||
and examine and change its core image.
|
||||
Its primary use is for the implementation of breakpoint debugging.
|
||||
There are four arguments whose interpretation
|
||||
depends on a
|
||||
.I request
|
||||
argument.
|
||||
Generally,
|
||||
.I pid
|
||||
is the process ID of the traced process,
|
||||
which must be a child (no more distant descendant)
|
||||
of the tracing process.
|
||||
A process being traced
|
||||
behaves normally until it encounters some signal
|
||||
whether internally generated
|
||||
like \*(lqillegal instruction\*(rq or externally
|
||||
generated like \*(lqinterrupt\*(rq.
|
||||
See
|
||||
.BR sigaction (2)
|
||||
for the list.
|
||||
Then the traced process enters a stopped state
|
||||
and its parent is notified via
|
||||
The \fBptrace\fP call provides a primitive means to trace (debug) another
|
||||
process. A process can submit itself to tracing using a \fBT_OK\fP ptrace
|
||||
request, or can be attached to by a tracer using a \fBT_ATTACH\fP request.
|
||||
From that point on, whenever a signal is sent to the traced process,
|
||||
the process will be stopped. Its tracer will be told about the signal
|
||||
causing the stop, via
|
||||
.BR wait (2).
|
||||
When the child is in the stopped state,
|
||||
its core image can be examined and modified
|
||||
using
|
||||
.BR ptrace .
|
||||
If desired, another
|
||||
.B ptrace
|
||||
request can then cause the child either to terminate
|
||||
or to continue, possibly ignoring the signal.
|
||||
The tracer can then inspect the traced process, and choose how to continue the
|
||||
process's execution and whether to pass on the signal to it.
|
||||
.PP
|
||||
The value of the
|
||||
.I request
|
||||
argument determines the precise
|
||||
action of the call:
|
||||
.TP 4
|
||||
PT_TRACE_ME
|
||||
This request is the only one used by the child process;
|
||||
it declares that the process is to be traced by its parent.
|
||||
All the other arguments are ignored.
|
||||
Peculiar results will ensue
|
||||
if the parent does not expect to trace the child.
|
||||
.TP 4
|
||||
PT_READ_I, PT_READ_D
|
||||
The
|
||||
word in the child process's address space
|
||||
at
|
||||
.I addr
|
||||
is returned.
|
||||
If I and D space are separated (e.g. historically
|
||||
on a pdp-11), request PT_READ_I indicates I space,
|
||||
PT_READ_D D space.
|
||||
.I Addr
|
||||
must be even on some machines.
|
||||
The child must be stopped.
|
||||
The input
|
||||
.I data
|
||||
is ignored.
|
||||
.TP 4
|
||||
PT_READ_U
|
||||
The word
|
||||
of the system's per-process data area corresponding to
|
||||
.I addr
|
||||
is returned.
|
||||
.I Addr
|
||||
must be even on some machines and less than 512.
|
||||
This space contains the registers and other information about
|
||||
the process;
|
||||
its layout corresponds to the
|
||||
.I user
|
||||
structure in the system.
|
||||
.TP 4
|
||||
PT_WRITE_I, PT_WRITE_D
|
||||
The
|
||||
given
|
||||
.I data
|
||||
is written at the word in the process's address space corresponding to
|
||||
.I addr,
|
||||
which must be even on some machines.
|
||||
No useful value is returned.
|
||||
If I and D space are separated, request PT_WRITE_I indicates I space,
|
||||
PT_WRITE_D D space.
|
||||
Attempts to write in pure procedure
|
||||
fail if another process is executing the same file.
|
||||
.TP 4
|
||||
PT_WRITE_U
|
||||
The process's system data is written,
|
||||
as it is read with request PT_READ_U.
|
||||
Only a few locations can be written in this way:
|
||||
the general registers,
|
||||
the floating point status and registers,
|
||||
and certain bits of the processor status word.
|
||||
.TP 4
|
||||
PT_CONTINUE
|
||||
The
|
||||
.I data
|
||||
argument is taken as a signal number
|
||||
and the child's execution continues
|
||||
at location
|
||||
.I addr
|
||||
as if it had incurred that signal.
|
||||
Normally the signal number will be
|
||||
either 0 to indicate that the signal that caused the stop
|
||||
should be ignored,
|
||||
or that value fetched out of the
|
||||
process's image indicating which signal caused
|
||||
the stop.
|
||||
If
|
||||
.I addr
|
||||
is (int *)1 then execution continues from where it stopped.
|
||||
.TP 4
|
||||
PT_KILL
|
||||
The traced process terminates.
|
||||
.TP 4
|
||||
PT_STEP
|
||||
Execution continues as in request PT_CONTINUE;
|
||||
however, as soon as possible after execution of at least one instruction,
|
||||
execution stops again.
|
||||
The signal number from the stop is
|
||||
SIGTRAP.
|
||||
(On the VAX-11 the T-bit is used and just one instruction
|
||||
is executed.)
|
||||
This is part of the mechanism for implementing breakpoints.
|
||||
In the current model, the tracer will be notified of the signal before any
|
||||
checks on ignore or block masks are made. A \fBSIGKILL\fP signal cannot be
|
||||
intercepted by the tracer, and will always kill the traced process.
|
||||
.PP
|
||||
As indicated,
|
||||
these calls
|
||||
(except for request PT_TRACE_ME)
|
||||
can be used only when the subject process has stopped.
|
||||
The
|
||||
.B wait
|
||||
call is used to determine
|
||||
when a process stops;
|
||||
in such a case the \*(lqtermination\*(rq status
|
||||
returned by
|
||||
.B wait
|
||||
has the value 0177 to indicate stoppage rather
|
||||
than genuine termination.
|
||||
.PP
|
||||
To forestall possible fraud,
|
||||
.B ptrace
|
||||
inhibits the set-user-id and set-group-id facilities
|
||||
on subsequent
|
||||
When the traced process performs a successful
|
||||
.BR execve (2)
|
||||
calls.
|
||||
If a traced process calls
|
||||
.BR execve ,
|
||||
it will stop before executing the first instruction of the new image
|
||||
showing signal SIGTRAP.
|
||||
call, it will be stopped and a \fBSIGTRAP\fP will be generated for it.
|
||||
Set-uid and set-gid bits on the new executable are ignored.
|
||||
.PP
|
||||
On a VAX-11, \*(lqword\*(rq also means a 32-bit integer,
|
||||
but the \*(lqeven\*(rq
|
||||
restriction does not apply.
|
||||
.SH "RETURN VALUE
|
||||
A 0 value is returned if the call succeeds. If the call fails
|
||||
then a \-1 is returned and the global variable \fIerrno\fP is
|
||||
set to indicate the error.
|
||||
.SH "ERRORS
|
||||
.TP 15
|
||||
[EIO]
|
||||
The request code is invalid.
|
||||
.TP 15
|
||||
[ESRCH]
|
||||
The specified process does not exist.
|
||||
.TP 15
|
||||
[EIO]
|
||||
The given signal number is invalid.
|
||||
.TP 15
|
||||
[EIO]
|
||||
The specified address is out of bounds.
|
||||
.TP 15
|
||||
[EPERM]
|
||||
The specified process cannot be traced.
|
||||
The \fIreq\fP parameter specifies the process trace request. The interpretation
|
||||
of the remaining parameters depends on the given request. For all requests
|
||||
except \fBT_OK\fP, the \fIpid\fP parameter specifies process ID of the target
|
||||
process. For all requests except \fBT_OK\fP and \fBT_ATTACH\fP, the process
|
||||
must be stopped. The following requests are supported:
|
||||
.TP 2
|
||||
.B T_OK
|
||||
Set the caller's parent to be its tracer. All other arguments are ignored.
|
||||
This request is typically made by the child fork of a debugger,
|
||||
before performing an
|
||||
.BR execve (2)
|
||||
call.
|
||||
.TP
|
||||
.B T_GETINS, T_GETDATA
|
||||
Retrieve a value from the given process's instruction and data area,
|
||||
respectively, at the address given in \fIaddr\fP.
|
||||
.TP
|
||||
.B T_SETINS, T_SETDATA
|
||||
Set the value from the given process's instruction and data area, respectively,
|
||||
at the address given in \fIaddr\fP, to the value given in \fIdata\fP.
|
||||
.TP
|
||||
.B T_GETUSER
|
||||
Retrieve the value at the zero-based offset given in \fIaddr\fP from the
|
||||
process's \fBstruct proc\fP kernel structure, followed by, aligned on
|
||||
\fBlong\fP size boundary, its \fBstruct priv\fP kernel structure.
|
||||
.TP
|
||||
.B T_SETUSER
|
||||
Set some of the given process's registers at the beginning of its
|
||||
\fBstruct proc\fP kernel structure. The value in \fIdata\fP will be written to
|
||||
the zero-based offset given in \fIaddr\fP from the process's \fBstruct proc\fP
|
||||
kernel structure.
|
||||
.TP
|
||||
.B T_RESUME
|
||||
Resume execution of the process. A nonzero \fIdata\fP argument will be
|
||||
interpreted as a signal to pass to the process.
|
||||
.TP
|
||||
.B T_STEP
|
||||
Single-step an instruction. A nonzero \fIdata\fP argument will be interpreted
|
||||
as a signal to pass to the process.
|
||||
.TP
|
||||
.B T_SYSCALL
|
||||
Resume execution with system call tracing. When the traced process makes a
|
||||
system call, a \fBSIGTRAP\fP signal will be generated. A subsequent
|
||||
\fBT_SYSCALL\fP request will then cause a \fBSIGTRAP\fP signal to be generated
|
||||
when the process leaves the system call. A nonzero \fIdata\fP argument will be
|
||||
interpreted as a signal to pass to the process.
|
||||
.TP
|
||||
.B T_EXIT
|
||||
Terminate the traced process, with the exit code given in the \fIdata\fP
|
||||
argument. This call will return once the process has exited.
|
||||
.TP
|
||||
.B T_ATTACH
|
||||
Attach to the given process. The process will be stopped with a \fBSIGSTOP\fP
|
||||
signal.
|
||||
.TP
|
||||
.B T_DETACH
|
||||
Detach from the given process. Any signals still pending for the tracer are
|
||||
passed on directly to the process. A nonzero \fIdata\fP argument will be
|
||||
interpreted as an additional signal to pass to the process.
|
||||
.TP
|
||||
.B T_SETOPT
|
||||
Set the given process's trace options to the bit combination of flags given
|
||||
in the \fIdata\fP argument.
|
||||
.PP
|
||||
The following option flags are currently supported for \fBT_SETOPT\fP:
|
||||
.TP 2
|
||||
.B TO_TRACEFORK
|
||||
When the traced process performs a
|
||||
.BR fork (2),
|
||||
automatically attach to the new child as well.
|
||||
The child will be stopped with a \fBSIGSTOP\fP signal right after forking.
|
||||
.TP
|
||||
.B TO_ALTEXEC
|
||||
Send \fBSIGSTOP\fP instead of \fBSIGTRAP\fP upon a successful
|
||||
.BR execve (2).
|
||||
This allows the tracer to disambiguate between this case and other traps.
|
||||
.PP
|
||||
All addresses specified for the \fBT_GET\fP* and \fBT_SET\fP* requests must be
|
||||
aligned on \fBlong\fP boundary. Similarly, only \fBlong\fP sized values can be
|
||||
retrieved and set at a time.
|
||||
.SH "RETURN VALUE"
|
||||
All but the \fBT_GET\fP* requests return 0 upon successful completion.
|
||||
Otherwise, a value of -1 is returned and \fIerrno\fP is set to indicate the
|
||||
error.
|
||||
.PP
|
||||
The \fBT_GET\fP* requests return the resulting data. Here, -1 is a legitimate
|
||||
return value. To distinguish between this and an error, clear \fIerrno\fP
|
||||
before the \fBptrace\fP call, and check whether it is zero afterwards.
|
||||
.SH ERRORS
|
||||
The functions will fail if any of the following errors occur:
|
||||
.TP 10
|
||||
.B EINVAL
|
||||
Invalid request or signal given.
|
||||
.TP 10
|
||||
.B ESRCH
|
||||
The given process is not found, exiting, or not traced by the caller.
|
||||
.TP 10
|
||||
.B EBUSY
|
||||
The given process is not stopped, or already being traced.
|
||||
.TP 10
|
||||
.B EIO
|
||||
The given address is out of range or not properly aligned.
|
||||
.TP 10
|
||||
.B EPERM
|
||||
Attaching is denied, because the caller equals the given process,
|
||||
or the caller is not root and does not match the given process's
|
||||
user or group ID, or the caller is not root and the given process
|
||||
is a system process, or the caller is a system process,
|
||||
or the given process may not be traced at all.
|
||||
.TP
|
||||
.SH LIMITATIONS
|
||||
Signals are not ordered. Attaching to a process guarantees that a \fBSIGSTOP\fP
|
||||
will arrive at the tracer, but it is not guaranteed that this will be the first
|
||||
signal to arrive. The same goes for automatically attached children of the
|
||||
traced process. Similarly, if the tracer wants to detach from a running
|
||||
process, it will typically send a \fBSIGSTOP\fP using
|
||||
.BR kill (2)
|
||||
to the process to stop it, but there is no guarantee that this will be the
|
||||
first signal to arrive.
|
||||
.PP
|
||||
Signals not caused by the process itself (e.g. those caused by
|
||||
.BR kill (2))
|
||||
will arrive at the tracer while the process is in stopped state, but this does
|
||||
not imply that the process is in a stable state at that point. The process may
|
||||
still have a system call pending, and this means that registers and memory of
|
||||
the process may change almost arbitrarily after the tracer has been told about
|
||||
the arrival of the current signal. Implementers of debuggers are advised to
|
||||
make minimal assumptions about the conditions of the process when an unexpected
|
||||
signal arrives.
|
||||
.PP
|
||||
It is not possible to use \fBT_SYSCALL\fP to get a trap upon leaving of a
|
||||
system call, if \fBT_SYSCALL\fP was not used to get a trap upon entering that
|
||||
system call. This is in fact helpful: after attaching to a process, the first
|
||||
\fBT_SYSCALL\fP call will always cause a trap after entering the next system
|
||||
call. As the only exception, \fBT_SYSCALL\fP on a
|
||||
.BR fork (2)
|
||||
call of a process with \fBTO_TRACEFORK\fP set, will result in two traps upon
|
||||
leaving: one for the parent, and one for the child. The child's \fBSIGSTOP\fP
|
||||
signal will always come before the \fBSIGTRAP\fP from its leaving the system
|
||||
call.
|
||||
.PP
|
||||
There is no way to reliably distinguish between real signals and signals
|
||||
generated for the tracer.
|
||||
.PP
|
||||
For system stability reasons, the PM and VM servers cannot be traced.
|
||||
.SH "SEE ALSO"
|
||||
.BR wait (2),
|
||||
.BR sigaction (2),
|
||||
.BR mdb (1).
|
||||
.SH BUGS
|
||||
.B Ptrace
|
||||
is unique and arcane; it should be replaced with a special file that
|
||||
can be opened and read and written. The control functions could then
|
||||
be implemented with
|
||||
.BR ioctl (2)
|
||||
calls on this file. This would be simpler to understand and have much
|
||||
higher performance.
|
||||
.PP
|
||||
The request PT_TRACE_ME call should be able to specify
|
||||
signals that are to be treated normally and not cause a stop.
|
||||
In this way, for example,
|
||||
programs with simulated floating point (which
|
||||
use \*(lqillegal instruction\*(rq signals at a very high rate)
|
||||
could be efficiently debugged.
|
||||
.PP
|
||||
The error indication, \-1, is a legitimate function value;
|
||||
.BR errno ,
|
||||
(see
|
||||
.BR intro (2)),
|
||||
can be used to disambiguate.
|
||||
.PP
|
||||
It should be possible to stop a process on occurrence of a system
|
||||
call;
|
||||
in this way a completely controlled environment could
|
||||
be provided.
|
||||
.BR kill (2),
|
||||
.BR mdb (1)
|
||||
.SH AUTHOR
|
||||
Manual page written by David van Moolenbroek <dcvmoole@cs.vu.nl>
|
||||
|
|
|
@ -34,10 +34,6 @@ FORWARD _PROTOTYPE( eth_port_t *find_port, (message *m) );
|
|||
FORWARD _PROTOTYPE( void eth_restart, (eth_port_t *eth_port, int tasknr) );
|
||||
FORWARD _PROTOTYPE( void send_getstat, (eth_port_t *eth_port) );
|
||||
|
||||
#if 0
|
||||
FORWARD _PROTOTYPE( int asynsend, (endpoint_t dst, message *mp) );
|
||||
#endif
|
||||
|
||||
PUBLIC void osdep_eth_init()
|
||||
{
|
||||
int i, j, r, rport;
|
||||
|
@ -1013,57 +1009,6 @@ eth_port_t *eth_port;
|
|||
ip_panic(( "eth_get_stat: asynsend failed: %d", r));
|
||||
}
|
||||
|
||||
#if 0
|
||||
PRIVATE asynmsg_t *msgtable= NULL;
|
||||
PRIVATE size_t msgtable_n= 0;
|
||||
|
||||
PRIVATE int asynsend(dst, mp)
|
||||
endpoint_t dst;
|
||||
message *mp;
|
||||
{
|
||||
int i;
|
||||
unsigned flags;
|
||||
|
||||
if (msgtable == NULL)
|
||||
{
|
||||
printf("asynsend: allocating msg table\n");
|
||||
msgtable_n= 5;
|
||||
msgtable= malloc(msgtable_n * sizeof(msgtable[0]));
|
||||
for (i= 0; i<msgtable_n; i++)
|
||||
msgtable[i].flags= AMF_EMPTY;
|
||||
}
|
||||
|
||||
/* Find slot in table */
|
||||
for (i= 0; i<msgtable_n; i++)
|
||||
{
|
||||
flags= msgtable[i].flags;
|
||||
if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE))
|
||||
{
|
||||
if (msgtable[i].result != OK)
|
||||
{
|
||||
printf(
|
||||
"asynsend: found completed entry %d with error %d\n",
|
||||
i, msgtable[i].result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (flags == AMF_EMPTY)
|
||||
break;
|
||||
}
|
||||
if (i >= msgtable_n)
|
||||
ip_panic(( "asynsend: should resize table" ));
|
||||
msgtable[i].dst= dst;
|
||||
msgtable[i].msg= *mp;
|
||||
msgtable[i].flags= AMF_VALID; /* Has to be last. The kernel
|
||||
* scans this table while we are
|
||||
* sleeping.
|
||||
*/
|
||||
|
||||
/* Tell the kernel to rescan the table */
|
||||
return senda(msgtable, msgtable_n);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $PchId: mnx_eth.c,v 1.16 2005/06/28 14:24:37 philip Exp $
|
||||
*/
|
||||
|
|
|
@ -341,7 +341,7 @@ PUBLIC void privileges_dmp()
|
|||
PRIVATE char *p_rts_flags_str(int flags)
|
||||
{
|
||||
static char str[10];
|
||||
str[0] = (flags & NO_PRIORITY) ? 's' : '-';
|
||||
str[0] = (flags & PROC_STOP) ? 's' : '-';
|
||||
str[1] = (flags & SENDING) ? 'S' : '-';
|
||||
str[2] = (flags & RECEIVING) ? 'R' : '-';
|
||||
str[3] = (flags & SIGNALED) ? 'I' : '-';
|
||||
|
|
|
@ -20,20 +20,21 @@ PUBLIC struct mproc mproc[NR_PROCS];
|
|||
*===========================================================================*/
|
||||
PRIVATE char *flags_str(int flags)
|
||||
{
|
||||
static char str[13];
|
||||
static char str[14];
|
||||
str[0] = (flags & WAITING) ? 'W' : '-';
|
||||
str[1] = (flags & ZOMBIE) ? 'Z' : '-';
|
||||
str[2] = (flags & PAUSED) ? 'P' : '-';
|
||||
str[3] = (flags & ALARM_ON) ? 'A' : '-';
|
||||
str[4] = (flags & TRACED) ? 'T' : '-';
|
||||
str[4] = (flags & EXITING) ? 'E' : '-';
|
||||
str[5] = (flags & STOPPED) ? 'S' : '-';
|
||||
str[6] = (flags & SIGSUSPENDED) ? 'U' : '-';
|
||||
str[7] = (flags & REPLY) ? 'R' : '-';
|
||||
str[8] = (flags & PRIV_PROC) ? 'p' : '-';
|
||||
str[8] = (flags & FS_CALL) ? 'F' : '-';
|
||||
str[9] = (flags & PM_SIG_PENDING) ? 's' : '-';
|
||||
str[10] = (flags & PARTIAL_EXEC) ? 'x' : '-';
|
||||
str[11] = (flags & EXITING) ? 'E' : '-';
|
||||
str[12] = '\0';
|
||||
str[10] = (flags & PRIV_PROC) ? 'p' : '-';
|
||||
str[11] = (flags & PARTIAL_EXEC) ? 'x' : '-';
|
||||
str[12] = (flags & DELAY_CALL) ? 'd' : '-';
|
||||
str[13] = '\0';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
@ -48,13 +49,13 @@ PUBLIC void mproc_dmp()
|
|||
|
||||
getsysinfo(PM_PROC_NR, SI_PROC_TAB, mproc);
|
||||
|
||||
printf("-process- -nr-prnt- -pid ppid grp- -uid--gid- -nice- -flags------\n");
|
||||
printf("-process- -nr-pnr-tnr- --pid--ppid--pgrp- -uid-- -gid-- -nice- -flags-------\n");
|
||||
for (i=prev_i; i<NR_PROCS; i++) {
|
||||
mp = &mproc[i];
|
||||
if (mp->mp_pid == 0 && i != PM_PROC_NR) continue;
|
||||
if (++n > 22) break;
|
||||
printf("%8.8s %4d%4d %5d %5d %5d ",
|
||||
mp->mp_name, i, mp->mp_parent, mp->mp_pid, mproc[mp->mp_parent].mp_pid, mp->mp_procgrp);
|
||||
printf("%8.8s %4d%4d%4d %5d %5d %5d ",
|
||||
mp->mp_name, i, mp->mp_parent, mp->mp_tracer, mp->mp_pid, mproc[mp->mp_parent].mp_pid, mp->mp_procgrp);
|
||||
printf("%2d(%2d) %2d(%2d) ",
|
||||
mp->mp_realuid, mp->mp_effuid, mp->mp_realgid, mp->mp_effgid);
|
||||
printf(" %3d %s ",
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#define PM_PID 0 /* PM's process id number */
|
||||
#define INIT_PID 1 /* INIT's process id number */
|
||||
|
||||
#define NO_TRACER 0 /* process is not being traced */
|
||||
|
||||
#define DUMPED 0200 /* bit set in status when core dumped */
|
||||
|
||||
#define MAX_SECS (((1<<(sizeof(clock_t)*8-1))-1)/system_hz)
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <a.out.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include "mproc.h"
|
||||
#include "param.h"
|
||||
|
||||
|
@ -38,23 +39,18 @@
|
|||
*===========================================================================*/
|
||||
PUBLIC int do_exec()
|
||||
{
|
||||
message m;
|
||||
int r;
|
||||
|
||||
/* Save parameters */
|
||||
mp->mp_exec_path= m_in.exec_name;
|
||||
mp->mp_exec_path_len= m_in.exec_len;
|
||||
mp->mp_exec_frame= m_in.stack_ptr;
|
||||
mp->mp_exec_frame_len= m_in.stack_bytes;
|
||||
|
||||
/* Forward call to FS */
|
||||
if (mp->mp_fs_call != PM_IDLE)
|
||||
{
|
||||
panic(__FILE__, "do_exec: not idle", mp->mp_fs_call);
|
||||
}
|
||||
mp->mp_fs_call= PM_EXEC;
|
||||
r= notify(FS_PROC_NR);
|
||||
if (r != OK)
|
||||
panic(__FILE__, "do_exec: unable to notify FS", r);
|
||||
m.m_type = PM_EXEC;
|
||||
m.PM_PROC = mp->mp_endpoint;
|
||||
m.PM_PATH = m_in.exec_name;
|
||||
m.PM_PATH_LEN = m_in.exec_len;
|
||||
m.PM_FRAME = m_in.stack_ptr;
|
||||
m.PM_FRAME_LEN = m_in.stack_bytes;
|
||||
|
||||
tell_fs(mp, &m);
|
||||
|
||||
/* Do not reply */
|
||||
return SUSPEND;
|
||||
|
@ -92,7 +88,7 @@ PUBLIC int exec_newmem()
|
|||
if((r=vm_exec_newmem(proc_e, &args, sizeof(args), &stack_top, &flags)) == OK) {
|
||||
allow_setuid= 0; /* Do not allow setuid execution */
|
||||
|
||||
if ((rmp->mp_flags & TRACED) == 0) {
|
||||
if (rmp->mp_tracer == NO_TRACER) {
|
||||
/* Okay, setuid execution is allowed */
|
||||
allow_setuid= 1;
|
||||
rmp->mp_effuid = args.new_uid;
|
||||
|
@ -174,7 +170,7 @@ int result;
|
|||
/* Fix 'mproc' fields, tell kernel that exec is done, reset caught
|
||||
* sigs.
|
||||
*/
|
||||
for (sn = 1; sn <= _NSIG; sn++) {
|
||||
for (sn = 1; sn < _NSIG; sn++) {
|
||||
if (sigismember(&rmp->mp_catch, sn)) {
|
||||
sigdelset(&rmp->mp_catch, sn);
|
||||
rmp->mp_sigact[sn].sa_handler = SIG_DFL;
|
||||
|
@ -182,13 +178,18 @@ int result;
|
|||
}
|
||||
}
|
||||
|
||||
/* Cause a signal if this process is traced.
|
||||
* Do this before making the process runnable again!
|
||||
*/
|
||||
if (rmp->mp_tracer != NO_TRACER) {
|
||||
sn = (rmp->mp_trace_flags & TO_ALTEXEC) ? SIGSTOP : SIGTRAP;
|
||||
|
||||
check_sig(rmp->mp_pid, sn);
|
||||
}
|
||||
|
||||
new_sp= (char *)rmp->mp_procargs;
|
||||
pc= 0; /* for now */
|
||||
r= sys_exec(rmp->mp_endpoint, new_sp, rmp->mp_name, pc);
|
||||
if (r != OK) panic(__FILE__, "sys_exec failed", r);
|
||||
|
||||
/* Cause a signal if this process is traced. */
|
||||
if (rmp->mp_flags & TRACED) check_sig(rmp->mp_pid, SIGTRAP);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
* exit_proc: actually do the exiting, and tell FS about it
|
||||
* exit_restart: continue exiting a process after FS has replied
|
||||
* do_waitpid: perform the WAITPID or WAIT system call
|
||||
* wait_test: check whether a parent is waiting for a child
|
||||
*/
|
||||
|
||||
#include "pm.h"
|
||||
|
@ -20,6 +21,7 @@
|
|||
#include <minix/callnr.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/vm.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/resource.h>
|
||||
#include <signal.h>
|
||||
#include "mproc.h"
|
||||
|
@ -28,7 +30,11 @@
|
|||
#define LAST_FEW 2 /* last few slots reserved for superuser */
|
||||
|
||||
FORWARD _PROTOTYPE (void zombify, (struct mproc *rmp) );
|
||||
FORWARD _PROTOTYPE (void check_parent, (struct mproc *child,
|
||||
int try_cleanup) );
|
||||
FORWARD _PROTOTYPE (void tell_parent, (struct mproc *child) );
|
||||
FORWARD _PROTOTYPE (void tell_tracer, (struct mproc *child) );
|
||||
FORWARD _PROTOTYPE (void tracer_died, (struct mproc *child) );
|
||||
FORWARD _PROTOTYPE (void cleanup, (register struct mproc *rmp) );
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -43,6 +49,7 @@ PUBLIC int do_fork()
|
|||
static int next_child;
|
||||
int i, n = 0, r, s;
|
||||
endpoint_t child_ep;
|
||||
message m;
|
||||
|
||||
/* If tables might fill up during FORK, don't even start since recovery half
|
||||
* way through is such a nuisance.
|
||||
|
@ -79,8 +86,13 @@ PUBLIC int do_fork()
|
|||
procs_in_use++;
|
||||
*rmc = *rmp; /* copy parent's process slot to child's */
|
||||
rmc->mp_parent = who_p; /* record child's parent */
|
||||
if (!(rmc->mp_trace_flags & TO_TRACEFORK)) {
|
||||
rmc->mp_tracer = NO_TRACER; /* no tracer attached */
|
||||
rmc->mp_trace_flags = 0;
|
||||
sigemptyset(&rmc->mp_sigtrace);
|
||||
}
|
||||
/* inherit only these flags */
|
||||
rmc->mp_flags &= (IN_USE|PRIV_PROC);
|
||||
rmc->mp_flags &= (IN_USE|PRIV_PROC|DELAY_CALL);
|
||||
rmc->mp_child_utime = 0; /* reset administration */
|
||||
rmc->mp_child_stime = 0; /* reset administration */
|
||||
rmc->mp_exitstatus = 0;
|
||||
|
@ -93,11 +105,16 @@ PUBLIC int do_fork()
|
|||
new_pid = get_free_pid();
|
||||
rmc->mp_pid = new_pid; /* assign pid to child */
|
||||
|
||||
if (rmc->mp_fs_call != PM_IDLE)
|
||||
panic("pm", "do_fork: not idle", rmc->mp_fs_call);
|
||||
rmc->mp_fs_call= PM_FORK;
|
||||
r= notify(FS_PROC_NR);
|
||||
if (r != OK) panic("pm", "do_fork: unable to notify FS", r);
|
||||
m.m_type = PM_FORK;
|
||||
m.PM_PROC = rmc->mp_endpoint;
|
||||
m.PM_PPROC = rmp->mp_endpoint;
|
||||
m.PM_CPID = rmc->mp_pid;
|
||||
|
||||
tell_fs(rmc, &m);
|
||||
|
||||
/* Tell the tracer, if any, about the new child */
|
||||
if (rmc->mp_tracer != NO_TRACER)
|
||||
sig_proc(rmc, SIGSTOP, TRUE /*trace*/);
|
||||
|
||||
/* Do not reply until FS is ready to process the fork
|
||||
* request
|
||||
|
@ -118,6 +135,7 @@ PUBLIC int do_fork_nb()
|
|||
static int next_child;
|
||||
int i, n = 0, r;
|
||||
endpoint_t child_ep;
|
||||
message m;
|
||||
|
||||
/* Only system processes are allowed to use fork_nb */
|
||||
if (!(mp->mp_flags & PRIV_PROC))
|
||||
|
@ -155,8 +173,13 @@ PUBLIC int do_fork_nb()
|
|||
procs_in_use++;
|
||||
*rmc = *rmp; /* copy parent's process slot to child's */
|
||||
rmc->mp_parent = who_p; /* record child's parent */
|
||||
if (!(rmc->mp_trace_flags & TO_TRACEFORK)) {
|
||||
rmc->mp_tracer = NO_TRACER; /* no tracer attached */
|
||||
rmc->mp_trace_flags = 0;
|
||||
sigemptyset(&rmc->mp_sigtrace);
|
||||
}
|
||||
/* inherit only these flags */
|
||||
rmc->mp_flags &= (IN_USE|PRIV_PROC);
|
||||
rmc->mp_flags &= (IN_USE|PRIV_PROC|DELAY_CALL);
|
||||
rmc->mp_child_utime = 0; /* reset administration */
|
||||
rmc->mp_child_stime = 0; /* reset administration */
|
||||
rmc->mp_exitstatus = 0;
|
||||
|
@ -169,11 +192,16 @@ PUBLIC int do_fork_nb()
|
|||
new_pid = get_free_pid();
|
||||
rmc->mp_pid = new_pid; /* assign pid to child */
|
||||
|
||||
if (rmc->mp_fs_call != PM_IDLE)
|
||||
panic("pm", "do_fork: not idle", rmc->mp_fs_call);
|
||||
rmc->mp_fs_call= PM_FORK_NB;
|
||||
r= notify(FS_PROC_NR);
|
||||
if (r != OK) panic("pm", "do_fork: unable to notify FS", r);
|
||||
m.m_type = PM_FORK_NB;
|
||||
m.PM_PROC = rmc->mp_endpoint;
|
||||
m.PM_PPROC = rmp->mp_endpoint;
|
||||
m.PM_CPID = rmc->mp_pid;
|
||||
|
||||
tell_fs(rmc, &m);
|
||||
|
||||
/* Tell the tracer, if any, about the new child */
|
||||
if (rmc->mp_tracer != NO_TRACER)
|
||||
sig_proc(rmc, SIGSTOP, TRUE /*trace*/);
|
||||
|
||||
/* Wakeup the newly created process */
|
||||
setreply(rmc-mproc, OK);
|
||||
|
@ -210,6 +238,7 @@ int dump_core; /* flag indicating whether to dump core */
|
|||
pid_t procgrp;
|
||||
struct mproc *p_mp;
|
||||
clock_t user_time, sys_time;
|
||||
message m;
|
||||
|
||||
/* Do not create core files for set uid execution */
|
||||
if (dump_core && rmp->mp_realuid != rmp->mp_effuid)
|
||||
|
@ -244,7 +273,7 @@ int dump_core; /* flag indicating whether to dump core */
|
|||
* 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 */
|
||||
sys_stop(proc_nr_e); /* stop the process */
|
||||
if((r=vm_willexit(proc_nr_e)) != OK) {
|
||||
panic(__FILE__, "exit_proc: vm_willexit failed", r);
|
||||
}
|
||||
|
@ -255,15 +284,17 @@ int dump_core; /* flag indicating whether to dump core */
|
|||
printf("PM: INIT died\n");
|
||||
return;
|
||||
}
|
||||
else
|
||||
if(proc_nr_e != FS_PROC_NR) /* if it is not FS that is exiting.. */
|
||||
if (proc_nr_e == FS_PROC_NR)
|
||||
{
|
||||
panic(__FILE__, "exit_proc: FS died", r);
|
||||
}
|
||||
|
||||
|
||||
/* Tell FS about the exiting process. */
|
||||
if (rmp->mp_fs_call != PM_IDLE)
|
||||
panic(__FILE__, "exit_proc: not idle", rmp->mp_fs_call);
|
||||
rmp->mp_fs_call= dump_core ? PM_DUMPCORE : PM_EXIT;
|
||||
r= notify(FS_PROC_NR);
|
||||
if (r != OK) panic(__FILE__, "exit_proc: unable to notify FS", r);
|
||||
m.m_type = dump_core ? PM_DUMPCORE : PM_EXIT;
|
||||
m.PM_PROC = rmp->mp_endpoint;
|
||||
|
||||
tell_fs(rmp, &m);
|
||||
|
||||
if (rmp->mp_flags & PRIV_PROC)
|
||||
{
|
||||
|
@ -274,20 +305,13 @@ int dump_core; /* flag indicating whether to dump core */
|
|||
if((r= sys_exit(rmp->mp_endpoint)) != OK)
|
||||
panic(__FILE__, "exit_proc: sys_exit failed", r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
panic(__FILE__, "pm_exit: FS died", r);
|
||||
}
|
||||
|
||||
/* The process is now officially exiting. The ZOMBIE flag is not enough, as
|
||||
* it is not set here for core dumps - introducing potential race conditions.
|
||||
/* Clean up most of the flags describing the process's state before the exit,
|
||||
* and mark it as exiting.
|
||||
*/
|
||||
rmp->mp_flags &= (IN_USE|FS_CALL|PRIV_PROC|TRACE_EXIT);
|
||||
rmp->mp_flags |= EXITING;
|
||||
|
||||
/* Pending reply messages for the dead process cannot be delivered. */
|
||||
rmp->mp_flags &= ~REPLY;
|
||||
|
||||
/* Keep the process around until FS is finished with it. */
|
||||
|
||||
rmp->mp_exitstatus = (char) exit_status;
|
||||
|
@ -300,16 +324,18 @@ int dump_core; /* flag indicating whether to dump core */
|
|||
|
||||
/* If the process has children, disinherit them. INIT is the new parent. */
|
||||
for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
|
||||
if (rmp->mp_flags & IN_USE && rmp->mp_parent == proc_nr) {
|
||||
if (!(rmp->mp_flags & IN_USE)) continue;
|
||||
if (rmp->mp_tracer == proc_nr) {
|
||||
/* This child's tracer died. Do something sensible. */
|
||||
tracer_died(rmp);
|
||||
}
|
||||
if (rmp->mp_parent == proc_nr) {
|
||||
/* 'rmp' now points to a child to be disinherited. */
|
||||
rmp->mp_parent = INIT_PROC_NR;
|
||||
parent_waiting = mproc[INIT_PROC_NR].mp_flags & WAITING;
|
||||
if (parent_waiting && (rmp->mp_flags & ZOMBIE)) {
|
||||
tell_parent(rmp);
|
||||
|
||||
if (rmp->mp_fs_call == PM_IDLE)
|
||||
cleanup(rmp);
|
||||
}
|
||||
/* Notify new parent. */
|
||||
if (rmp->mp_flags & ZOMBIE)
|
||||
check_parent(rmp, TRUE /*try_cleanup*/);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -345,11 +371,11 @@ int dump_core; /* flag indicating whether to dump core */
|
|||
panic(__FILE__, "exit_restart: vm_exit failed", r);
|
||||
}
|
||||
|
||||
if ((rmp->mp_flags & TRACE_EXIT) && rmp->mp_parent != INIT_PROC_NR)
|
||||
if (rmp->mp_flags & TRACE_EXIT)
|
||||
{
|
||||
/* Wake up the parent, completing the ptrace(T_EXIT) call */
|
||||
mproc[rmp->mp_parent].mp_reply.reply_trace = 0;
|
||||
setreply(rmp->mp_parent, OK);
|
||||
/* Wake up the tracer, completing the ptrace(T_EXIT) call */
|
||||
mproc[rmp->mp_tracer].mp_reply.reply_trace = 0;
|
||||
setreply(rmp->mp_tracer, OK);
|
||||
}
|
||||
|
||||
/* Clean up if the parent has collected the exit status */
|
||||
|
@ -372,7 +398,7 @@ PUBLIC int do_waitpid()
|
|||
* Both WAIT and WAITPID are handled by this code.
|
||||
*/
|
||||
register struct mproc *rp;
|
||||
int pidarg, options, children;
|
||||
int i, pidarg, options, children;
|
||||
|
||||
/* Set internal variables, depending on whether this is WAIT or WAITPID. */
|
||||
pidarg = (call_nr == WAIT ? -1 : m_in.pid); /* 1st param of waitpid */
|
||||
|
@ -386,26 +412,47 @@ PUBLIC int do_waitpid()
|
|||
*/
|
||||
children = 0;
|
||||
for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {
|
||||
if ( (rp->mp_flags & IN_USE) && rp->mp_parent == who_p) {
|
||||
if ((rp->mp_flags & (IN_USE | TOLD_PARENT)) != IN_USE) continue;
|
||||
if (rp->mp_parent != who_p && rp->mp_tracer != who_p) continue;
|
||||
if (rp->mp_parent != who_p && (rp->mp_flags & ZOMBIE)) continue;
|
||||
|
||||
/* The value of pidarg determines which children qualify. */
|
||||
if (pidarg > 0 && pidarg != rp->mp_pid) continue;
|
||||
if (pidarg < -1 && -pidarg != rp->mp_procgrp) continue;
|
||||
if (rp->mp_flags & TOLD_PARENT) continue; /* post-ZOMBIE */
|
||||
|
||||
children++; /* this child is acceptable */
|
||||
|
||||
if (rp->mp_tracer == who_p) {
|
||||
if (rp->mp_flags & TRACE_ZOMBIE) {
|
||||
/* Traced child meets the pid test and has exited. */
|
||||
tell_tracer(rp);
|
||||
check_parent(rp, TRUE /*try_cleanup*/);
|
||||
return(SUSPEND);
|
||||
}
|
||||
if (rp->mp_flags & STOPPED) {
|
||||
/* This child meets the pid test and is being traced.
|
||||
* Deliver a signal to the tracer, if any.
|
||||
*/
|
||||
for (i = 1; i < _NSIG; i++) {
|
||||
if (sigismember(&rp->mp_sigtrace, i)) {
|
||||
sigdelset(&rp->mp_sigtrace, i);
|
||||
|
||||
mp->mp_reply.reply_res2 =
|
||||
0177 | (i << 8);
|
||||
return(rp->mp_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rp->mp_parent == who_p) {
|
||||
if (rp->mp_flags & ZOMBIE) {
|
||||
/* This child meets the pid test and has exited. */
|
||||
tell_parent(rp); /* this child has already exited */
|
||||
if (rp->mp_fs_call == PM_IDLE)
|
||||
if (!(rp->mp_flags & FS_CALL))
|
||||
cleanup(rp);
|
||||
return(SUSPEND);
|
||||
}
|
||||
if ((rp->mp_flags & STOPPED) && rp->mp_sigstatus) {
|
||||
/* This child meets the pid test and is being traced.*/
|
||||
mp->mp_reply.reply_res2 = 0177|(rp->mp_sigstatus << 8);
|
||||
rp->mp_sigstatus = 0;
|
||||
return(rp->mp_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -424,35 +471,100 @@ PUBLIC int do_waitpid()
|
|||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* wait_test *
|
||||
*===========================================================================*/
|
||||
PUBLIC int wait_test(rmp, child)
|
||||
struct mproc *rmp; /* process that may be waiting */
|
||||
struct mproc *child; /* process that may be waited for */
|
||||
{
|
||||
/* See if a parent or tracer process is waiting for a child process.
|
||||
* A tracer is considered to be a pseudo-parent.
|
||||
*/
|
||||
int parent_waiting, right_child;
|
||||
pid_t pidarg;
|
||||
|
||||
pidarg = rmp->mp_wpid; /* who's being waited for? */
|
||||
parent_waiting = rmp->mp_flags & WAITING;
|
||||
right_child = /* child meets one of the 3 tests? */
|
||||
(pidarg == -1 || pidarg == child->mp_pid ||
|
||||
-pidarg == child->mp_procgrp);
|
||||
|
||||
return (parent_waiting && right_child);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* zombify *
|
||||
*===========================================================================*/
|
||||
PRIVATE void zombify(rmp)
|
||||
struct mproc *rmp;
|
||||
{
|
||||
/* Zombify a process. If the parent is waiting, notify it immediately.
|
||||
* Otherwise, send a SIGCHLD signal to the parent.
|
||||
/* Zombify a process. First check if the exiting process is traced by a process
|
||||
* other than its parent; if so, the tracer must be notified about the exit
|
||||
* first. Once that is done, the real parent may be notified about the exit of
|
||||
* its child.
|
||||
*/
|
||||
struct mproc *p_mp;
|
||||
int parent_waiting, right_child;
|
||||
pid_t pidarg;
|
||||
struct mproc *t_mp;
|
||||
|
||||
if (rmp->mp_flags & ZOMBIE)
|
||||
if (rmp->mp_flags & (TRACE_ZOMBIE | ZOMBIE))
|
||||
panic(__FILE__, "zombify: process was already a zombie", NO_NUM);
|
||||
|
||||
rmp->mp_flags &= (IN_USE|PRIV_PROC|EXITING|TRACE_EXIT);
|
||||
/* See if we have to notify a tracer process first. */
|
||||
if (rmp->mp_tracer != NO_TRACER && rmp->mp_tracer != rmp->mp_parent) {
|
||||
rmp->mp_flags |= TRACE_ZOMBIE;
|
||||
|
||||
t_mp = &mproc[rmp->mp_tracer];
|
||||
|
||||
/* Do not bother sending SIGCHLD signals to tracers. */
|
||||
if (!wait_test(t_mp, rmp))
|
||||
return;
|
||||
|
||||
tell_tracer(rmp);
|
||||
}
|
||||
else {
|
||||
rmp->mp_flags |= ZOMBIE;
|
||||
}
|
||||
|
||||
p_mp = &mproc[rmp->mp_parent];
|
||||
pidarg = p_mp->mp_wpid; /* who's being waited for? */
|
||||
parent_waiting = p_mp->mp_flags & WAITING;
|
||||
right_child = /* child meets one of the 3 tests? */
|
||||
(pidarg == -1 || pidarg == rmp->mp_pid || -pidarg == rmp->mp_procgrp);
|
||||
/* No tracer, or tracer is parent, or tracer has now been notified. */
|
||||
check_parent(rmp, FALSE /*try_cleanup*/);
|
||||
}
|
||||
|
||||
if (parent_waiting && right_child)
|
||||
tell_parent(rmp); /* tell parent */
|
||||
else
|
||||
sig_proc(p_mp, SIGCHLD); /* send parent a "child died" signal */
|
||||
/*===========================================================================*
|
||||
* check_parent *
|
||||
*===========================================================================*/
|
||||
PRIVATE void check_parent(child, try_cleanup)
|
||||
struct mproc *child; /* tells which process is exiting */
|
||||
int try_cleanup; /* clean up the child when done? */
|
||||
{
|
||||
/* We would like to inform the parent of an exiting child about the child's
|
||||
* death. If the parent is waiting for the child, tell it immediately;
|
||||
* otherwise, send it a SIGCHLD signal.
|
||||
*
|
||||
* Note that we may call this function twice on a single child; first with
|
||||
* its original parent, later (if the parent died) with INIT as its parent.
|
||||
*/
|
||||
struct mproc *p_mp;
|
||||
|
||||
p_mp = &mproc[child->mp_parent];
|
||||
|
||||
if (p_mp->mp_flags & EXITING) {
|
||||
/* This may trigger if the child of a dead parent dies. The child will
|
||||
* be assigned to INIT and rechecked shortly after. Do nothing.
|
||||
*/
|
||||
}
|
||||
else if (wait_test(p_mp, child)) {
|
||||
tell_parent(child);
|
||||
|
||||
/* The 'try_cleanup' flag merely saves us from having to be really
|
||||
* careful with statement ordering in exit_proc() and exit_restart().
|
||||
*/
|
||||
if (try_cleanup && !(child->mp_flags & FS_CALL))
|
||||
cleanup(child);
|
||||
}
|
||||
else {
|
||||
/* Parent is not waiting. */
|
||||
sig_proc(p_mp, SIGCHLD, TRUE /*trace*/);
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -482,6 +594,64 @@ register struct mproc *child; /* tells which process is exiting */
|
|||
child->mp_flags |= TOLD_PARENT; /* avoid informing parent twice */
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* tell_tracer *
|
||||
*===========================================================================*/
|
||||
PRIVATE void tell_tracer(child)
|
||||
struct mproc *child; /* tells which process is exiting */
|
||||
{
|
||||
int exitstatus, mp_tracer;
|
||||
struct mproc *tracer;
|
||||
|
||||
mp_tracer = child->mp_tracer;
|
||||
if (mp_tracer <= 0)
|
||||
panic(__FILE__, "tell_tracer: bad value in mp_tracer", mp_tracer);
|
||||
if(!(child->mp_flags & TRACE_ZOMBIE))
|
||||
panic(__FILE__, "tell_tracer: child not a zombie", NO_NUM);
|
||||
tracer = &mproc[mp_tracer];
|
||||
|
||||
exitstatus = (child->mp_exitstatus << 8) | (child->mp_sigstatus & 0377);
|
||||
tracer->mp_reply.reply_res2 = exitstatus;
|
||||
setreply(child->mp_tracer, child->mp_pid);
|
||||
tracer->mp_flags &= ~WAITING; /* tracer no longer waiting */
|
||||
child->mp_flags &= ~TRACE_ZOMBIE; /* child no longer zombie to tracer */
|
||||
child->mp_flags |= ZOMBIE; /* child is now zombie to parent */
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* tracer_died *
|
||||
*===========================================================================*/
|
||||
PRIVATE void tracer_died(child)
|
||||
struct mproc *child; /* process being traced */
|
||||
{
|
||||
/* The process that was tracing the given child, has died for some reason.
|
||||
* This is really the tracer's fault, but we can't let INIT deal with this.
|
||||
*/
|
||||
|
||||
child->mp_tracer = NO_TRACER;
|
||||
child->mp_flags &= ~TRACE_EXIT;
|
||||
|
||||
/* If the tracer died while the child was running or stopped, we have no
|
||||
* idea what state the child is in. Avoid a trainwreck, by killing the child.
|
||||
* Note that this may cause cascading exits.
|
||||
*/
|
||||
if (!(child->mp_flags & EXITING)) {
|
||||
sig_proc(child, SIGKILL, TRUE /*trace*/);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the tracer died while the child was telling it about its own death,
|
||||
* forget about the tracer and notify the real parent instead.
|
||||
*/
|
||||
if (child->mp_flags & TRACE_ZOMBIE) {
|
||||
child->mp_flags &= ~TRACE_ZOMBIE;
|
||||
child->mp_flags |= ZOMBIE;
|
||||
|
||||
check_parent(child, TRUE /*try_cleanup*/);
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* cleanup *
|
||||
*===========================================================================*/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* This file handles the 4 system calls that get and set uids and gids.
|
||||
/* This file handles the 6 system calls that get and set uids and gids.
|
||||
* It also handles getpid(), setsid(), and getpgrp(). The code for each
|
||||
* one is so tiny that it hardly seemed worthwhile to make each a separate
|
||||
* function.
|
||||
|
@ -13,14 +13,11 @@
|
|||
#include "param.h"
|
||||
|
||||
/*===========================================================================*
|
||||
* do_getset *
|
||||
* do_get *
|
||||
*===========================================================================*/
|
||||
PUBLIC int do_getset()
|
||||
PUBLIC int do_get()
|
||||
{
|
||||
/* Handle GETUID, GETGID, GETPID, GETPGRP, SETUID, SETGID, SETSID. The four
|
||||
* GETs and SETSID return their primary results in 'r'. GETUID, GETGID, and
|
||||
* GETPID also return secondary results (the effective IDs, or the parent
|
||||
* process ID) in 'reply_res2', which is returned to the user.
|
||||
/* Handle GETUID, GETGID, GETPID, GETPGRP.
|
||||
*/
|
||||
|
||||
register struct mproc *rmp = mp;
|
||||
|
@ -48,74 +45,6 @@ PUBLIC int do_getset()
|
|||
rmp->mp_reply.reply_res3 = mproc[proc].mp_pid;
|
||||
break;
|
||||
|
||||
case SETEUID:
|
||||
case SETUID:
|
||||
if (rmp->mp_realuid != (uid_t) m_in.usr_id &&
|
||||
rmp->mp_effuid != SUPER_USER)
|
||||
return(EPERM);
|
||||
if(call_nr == SETUID) rmp->mp_realuid = (uid_t) m_in.usr_id;
|
||||
rmp->mp_effuid = (uid_t) m_in.usr_id;
|
||||
|
||||
if (rmp->mp_fs_call != PM_IDLE)
|
||||
{
|
||||
panic(__FILE__, "do_getset: not idle",
|
||||
rmp->mp_fs_call);
|
||||
}
|
||||
rmp->mp_fs_call= PM_SETUID;
|
||||
r= notify(FS_PROC_NR);
|
||||
if (r != OK)
|
||||
panic(__FILE__, "do_getset: unable to notify FS", r);
|
||||
|
||||
/* Do not reply until FS is ready to process the setuid
|
||||
* request
|
||||
*/
|
||||
r= SUSPEND;
|
||||
break;
|
||||
|
||||
case SETEGID:
|
||||
case SETGID:
|
||||
if (rmp->mp_realgid != (gid_t) m_in.grp_id &&
|
||||
rmp->mp_effuid != SUPER_USER)
|
||||
return(EPERM);
|
||||
if(call_nr == SETGID) rmp->mp_realgid = (gid_t) m_in.grp_id;
|
||||
rmp->mp_effgid = (gid_t) m_in.grp_id;
|
||||
|
||||
if (rmp->mp_fs_call != PM_IDLE)
|
||||
{
|
||||
panic(__FILE__, "do_getset: not idle",
|
||||
rmp->mp_fs_call);
|
||||
}
|
||||
rmp->mp_fs_call= PM_SETGID;
|
||||
r= notify(FS_PROC_NR);
|
||||
if (r != OK)
|
||||
panic(__FILE__, "do_getset: unable to notify FS", r);
|
||||
|
||||
/* Do not reply until FS is ready to process the setgid
|
||||
* request
|
||||
*/
|
||||
r= SUSPEND;
|
||||
break;
|
||||
|
||||
case SETSID:
|
||||
if (rmp->mp_procgrp == rmp->mp_pid) return(EPERM);
|
||||
rmp->mp_procgrp = rmp->mp_pid;
|
||||
|
||||
if (rmp->mp_fs_call != PM_IDLE)
|
||||
{
|
||||
panic(__FILE__, "do_getset: not idle",
|
||||
rmp->mp_fs_call);
|
||||
}
|
||||
rmp->mp_fs_call= PM_SETSID;
|
||||
r= notify(FS_PROC_NR);
|
||||
if (r != OK)
|
||||
panic(__FILE__, "do_getset: unable to notify FS", r);
|
||||
|
||||
/* Do not reply until FS is ready to process the setsid
|
||||
* request
|
||||
*/
|
||||
r= SUSPEND;
|
||||
break;
|
||||
|
||||
case GETPGRP:
|
||||
r = rmp->mp_procgrp;
|
||||
break;
|
||||
|
@ -126,3 +55,66 @@ PUBLIC int do_getset()
|
|||
}
|
||||
return(r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_set *
|
||||
*===========================================================================*/
|
||||
PUBLIC int do_set()
|
||||
{
|
||||
/* Handle SETUID, SETEUID, SETGID, SETEGID, SETSID. These calls have in common
|
||||
* that, if successful, they will be forwarded to VFS as well.
|
||||
*/
|
||||
register struct mproc *rmp = mp;
|
||||
message m;
|
||||
int r;
|
||||
|
||||
switch(call_nr) {
|
||||
case SETUID:
|
||||
case SETEUID:
|
||||
if (rmp->mp_realuid != (uid_t) m_in.usr_id &&
|
||||
rmp->mp_effuid != SUPER_USER)
|
||||
return(EPERM);
|
||||
if(call_nr == SETUID) rmp->mp_realuid = (uid_t) m_in.usr_id;
|
||||
rmp->mp_effuid = (uid_t) m_in.usr_id;
|
||||
|
||||
m.m_type = PM_SETUID;
|
||||
m.PM_PROC = rmp->mp_endpoint;
|
||||
m.PM_EID = rmp->mp_effuid;
|
||||
m.PM_RID = rmp->mp_realuid;
|
||||
|
||||
break;
|
||||
|
||||
case SETGID:
|
||||
case SETEGID:
|
||||
if (rmp->mp_realgid != (gid_t) m_in.grp_id &&
|
||||
rmp->mp_effuid != SUPER_USER)
|
||||
return(EPERM);
|
||||
if(call_nr == SETGID) rmp->mp_realgid = (gid_t) m_in.grp_id;
|
||||
rmp->mp_effgid = (gid_t) m_in.grp_id;
|
||||
|
||||
m.m_type = PM_SETGID;
|
||||
m.PM_PROC = rmp->mp_endpoint;
|
||||
m.PM_EID = rmp->mp_effgid;
|
||||
m.PM_RID = rmp->mp_realgid;
|
||||
|
||||
break;
|
||||
|
||||
case SETSID:
|
||||
if (rmp->mp_procgrp == rmp->mp_pid) return(EPERM);
|
||||
rmp->mp_procgrp = rmp->mp_pid;
|
||||
|
||||
m.m_type = PM_SETSID;
|
||||
m.PM_PROC = rmp->mp_endpoint;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return(EINVAL);
|
||||
}
|
||||
|
||||
/* Send the request to FS */
|
||||
tell_fs(rmp, &m);
|
||||
|
||||
/* Do not reply until FS has processed the request */
|
||||
return(SUSPEND);
|
||||
}
|
||||
|
|
|
@ -27,8 +27,5 @@ EXTERN time_t boottime; /* time when the system was booted (for
|
|||
* reporting to FS)
|
||||
*/
|
||||
EXTERN u32_t system_hz; /* System clock frequency. */
|
||||
EXTERN int report_reboot; /* During reboot to report to FS that we are
|
||||
* rebooting.
|
||||
*/
|
||||
EXTERN int abort_flag;
|
||||
EXTERN char monitor_code[256];
|
||||
|
|
|
@ -43,9 +43,7 @@ EXTERN unsigned long calls_stats[NCALLS];
|
|||
FORWARD _PROTOTYPE( void get_work, (void) );
|
||||
FORWARD _PROTOTYPE( void pm_init, (void) );
|
||||
FORWARD _PROTOTYPE( int get_nice_value, (int queue) );
|
||||
FORWARD _PROTOTYPE( void send_work, (void) );
|
||||
FORWARD _PROTOTYPE( void handle_fs_reply, (message *m_ptr) );
|
||||
FORWARD _PROTOTYPE( void restart_sigs, (struct mproc *rmp) );
|
||||
FORWARD _PROTOTYPE( void handle_fs_reply, (void) );
|
||||
|
||||
#define click_to_round_k(n) \
|
||||
((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
|
||||
|
@ -66,6 +64,10 @@ PUBLIC int main()
|
|||
while (TRUE) {
|
||||
get_work(); /* wait for an PM system call */
|
||||
|
||||
/* Drop delayed calls from exiting processes. */
|
||||
if (mp->mp_flags & EXITING)
|
||||
continue;
|
||||
|
||||
/* Check for system notifications first. Special cases. */
|
||||
if (is_notify(call_nr)) {
|
||||
switch(who_p) {
|
||||
|
@ -90,22 +92,19 @@ PUBLIC int main()
|
|||
|
||||
switch(call_nr)
|
||||
{
|
||||
case PM_GET_WORK:
|
||||
if (who_e == FS_PROC_NR)
|
||||
{
|
||||
send_work();
|
||||
result= SUSPEND; /* don't reply */
|
||||
}
|
||||
else
|
||||
result= ENOSYS;
|
||||
break;
|
||||
case PM_EXIT_REPLY:
|
||||
case PM_REBOOT_REPLY:
|
||||
case PM_SETUID_REPLY:
|
||||
case PM_SETGID_REPLY:
|
||||
case PM_SETSID_REPLY:
|
||||
case PM_EXEC_REPLY:
|
||||
case PM_EXIT_REPLY:
|
||||
case PM_CORE_REPLY:
|
||||
case PM_FORK_REPLY:
|
||||
case PM_FORK_NB_REPLY:
|
||||
case PM_UNPAUSE_REPLY:
|
||||
case PM_REBOOT_REPLY:
|
||||
if (who_e == FS_PROC_NR)
|
||||
{
|
||||
handle_fs_reply(&m_in);
|
||||
handle_fs_reply();
|
||||
result= SUSPEND; /* don't reply */
|
||||
}
|
||||
else
|
||||
|
@ -255,9 +254,6 @@ PRIVATE void pm_init()
|
|||
/* Initialize process table, including timers. */
|
||||
for (rmp=&mproc[0]; rmp<&mproc[NR_PROCS]; rmp++) {
|
||||
tmr_inittimer(&rmp->mp_timer);
|
||||
|
||||
rmp->mp_fs_call= PM_IDLE;
|
||||
rmp->mp_fs_call2= PM_IDLE;
|
||||
}
|
||||
|
||||
/* Build the set of signals which cause core dumps, and the set of signals
|
||||
|
@ -404,219 +400,19 @@ void checkme(char *str, int line)
|
|||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* send_work *
|
||||
*===========================================================================*/
|
||||
PRIVATE void send_work()
|
||||
{
|
||||
int r, call;
|
||||
struct mproc *rmp;
|
||||
message m;
|
||||
|
||||
m.m_type= PM_IDLE;
|
||||
for (rmp= mproc; rmp < &mproc[NR_PROCS]; rmp++)
|
||||
{
|
||||
call= rmp->mp_fs_call;
|
||||
if (call == PM_IDLE)
|
||||
call= rmp->mp_fs_call2;
|
||||
if (call == PM_IDLE)
|
||||
continue;
|
||||
switch(call)
|
||||
{
|
||||
case PM_SETSID:
|
||||
m.m_type= call;
|
||||
m.PM_SETSID_PROC= rmp->mp_endpoint;
|
||||
|
||||
/* FS does not reply */
|
||||
rmp->mp_fs_call= PM_IDLE;
|
||||
|
||||
/* Wakeup the original caller */
|
||||
setreply(rmp-mproc, rmp->mp_procgrp);
|
||||
break;
|
||||
|
||||
case PM_SETGID:
|
||||
m.m_type= call;
|
||||
m.PM_SETGID_PROC= rmp->mp_endpoint;
|
||||
m.PM_SETGID_EGID= rmp->mp_effgid;
|
||||
m.PM_SETGID_RGID= rmp->mp_realgid;
|
||||
|
||||
/* FS does not reply */
|
||||
rmp->mp_fs_call= PM_IDLE;
|
||||
|
||||
/* Wakeup the original caller */
|
||||
setreply(rmp-mproc, OK);
|
||||
break;
|
||||
|
||||
case PM_SETUID:
|
||||
m.m_type= call;
|
||||
m.PM_SETUID_PROC= rmp->mp_endpoint;
|
||||
m.PM_SETUID_EGID= rmp->mp_effuid;
|
||||
m.PM_SETUID_RGID= rmp->mp_realuid;
|
||||
|
||||
/* FS does not reply */
|
||||
rmp->mp_fs_call= PM_IDLE;
|
||||
|
||||
/* Wakeup the original caller */
|
||||
setreply(rmp-mproc, OK);
|
||||
break;
|
||||
|
||||
case PM_FORK:
|
||||
{
|
||||
int parent_p;
|
||||
struct mproc *parent_mp;
|
||||
|
||||
parent_p = rmp->mp_parent;
|
||||
parent_mp = &mproc[parent_p];
|
||||
|
||||
m.m_type= call;
|
||||
m.PM_FORK_PPROC= parent_mp->mp_endpoint;
|
||||
m.PM_FORK_CPROC= rmp->mp_endpoint;
|
||||
m.PM_FORK_CPID= rmp->mp_pid;
|
||||
|
||||
/* FS does not reply */
|
||||
rmp->mp_fs_call= PM_IDLE;
|
||||
|
||||
/* Wakeup the newly created process */
|
||||
setreply(rmp-mproc, OK);
|
||||
|
||||
/* Wakeup the parent */
|
||||
setreply(parent_mp-mproc, rmp->mp_pid);
|
||||
break;
|
||||
}
|
||||
|
||||
case PM_EXIT:
|
||||
m.m_type= call;
|
||||
m.PM_EXIT_PROC= rmp->mp_endpoint;
|
||||
|
||||
/* Mark the process as busy */
|
||||
rmp->mp_fs_call= PM_BUSY;
|
||||
|
||||
break;
|
||||
|
||||
case PM_UNPAUSE:
|
||||
m.m_type= call;
|
||||
m.PM_UNPAUSE_PROC= rmp->mp_endpoint;
|
||||
|
||||
/* FS does not reply */
|
||||
rmp->mp_fs_call2= PM_IDLE;
|
||||
|
||||
/* Ask the kernel to deliver the signal */
|
||||
r= sys_sigsend(rmp->mp_endpoint,
|
||||
&rmp->mp_sigmsg);
|
||||
if (r != OK) {
|
||||
#if 0
|
||||
panic(__FILE__,"sys_sigsend failed",r);
|
||||
#else
|
||||
printf("PM: PM_UNPAUSE: sys_sigsend failed to %d: %d\n",
|
||||
rmp->mp_endpoint, r);
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PM_UNPAUSE_TR:
|
||||
m.m_type= call;
|
||||
m.PM_UNPAUSE_PROC= rmp->mp_endpoint;
|
||||
|
||||
/* FS does not reply */
|
||||
rmp->mp_fs_call= PM_IDLE;
|
||||
|
||||
break;
|
||||
|
||||
case PM_EXEC:
|
||||
m.m_type= call;
|
||||
m.PM_EXEC_PROC= rmp->mp_endpoint;
|
||||
m.PM_EXEC_PATH= rmp->mp_exec_path;
|
||||
m.PM_EXEC_PATH_LEN= rmp->mp_exec_path_len;
|
||||
m.PM_EXEC_FRAME= rmp->mp_exec_frame;
|
||||
m.PM_EXEC_FRAME_LEN= rmp->mp_exec_frame_len;
|
||||
|
||||
/* Mark the process as busy */
|
||||
rmp->mp_fs_call= PM_BUSY;
|
||||
|
||||
break;
|
||||
|
||||
case PM_FORK_NB:
|
||||
{
|
||||
int parent_p;
|
||||
struct mproc *parent_mp;
|
||||
|
||||
parent_p = rmp->mp_parent;
|
||||
parent_mp = &mproc[parent_p];
|
||||
|
||||
m.m_type= PM_FORK;
|
||||
m.PM_FORK_PPROC= parent_mp->mp_endpoint;
|
||||
m.PM_FORK_CPROC= rmp->mp_endpoint;
|
||||
m.PM_FORK_CPID= rmp->mp_pid;
|
||||
|
||||
/* FS does not reply */
|
||||
rmp->mp_fs_call= PM_IDLE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PM_DUMPCORE:
|
||||
m.m_type= call;
|
||||
m.PM_CORE_PROC= rmp->mp_endpoint;
|
||||
/* XXX
|
||||
m.PM_CORE_SEGPTR= (char *)rmp->mp_seg;
|
||||
*/
|
||||
|
||||
/* Mark the process as busy */
|
||||
rmp->mp_fs_call= PM_BUSY;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("send_work: should report call 0x%x to FS\n",
|
||||
call);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (m.m_type != PM_IDLE)
|
||||
{
|
||||
restart_sigs(rmp);
|
||||
}
|
||||
else if (report_reboot)
|
||||
{
|
||||
m.m_type= PM_REBOOT;
|
||||
report_reboot= FALSE;
|
||||
}
|
||||
r= send(FS_PROC_NR, &m);
|
||||
if (r != OK) panic("pm", "send_work: send failed", r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* handle_fs_reply *
|
||||
*===========================================================================*/
|
||||
PRIVATE void handle_fs_reply(m_ptr)
|
||||
message *m_ptr;
|
||||
PRIVATE void handle_fs_reply()
|
||||
{
|
||||
int r, proc_e, proc_n, s;
|
||||
struct mproc *rmp;
|
||||
endpoint_t proc_e;
|
||||
int r, proc_n;
|
||||
|
||||
switch(m_ptr->m_type)
|
||||
{
|
||||
case PM_EXIT_REPLY:
|
||||
proc_e= m_ptr->PM_EXIT_PROC;
|
||||
if (pm_isokendpt(proc_e, &proc_n) != OK)
|
||||
{
|
||||
panic(__FILE__,
|
||||
"PM_EXIT_REPLY: got bad endpoint from FS",
|
||||
proc_e);
|
||||
}
|
||||
rmp= &mproc[proc_n];
|
||||
|
||||
/* Call is finished */
|
||||
rmp->mp_fs_call= PM_IDLE;
|
||||
|
||||
exit_restart(rmp, FALSE /*dump_core*/);
|
||||
|
||||
break;
|
||||
|
||||
case PM_REBOOT_REPLY:
|
||||
{
|
||||
/* PM_REBOOT is the only request not associated with a process.
|
||||
* Handle its reply first.
|
||||
*/
|
||||
if (call_nr == PM_REBOOT_REPLY) {
|
||||
vir_bytes code_addr;
|
||||
size_t code_size;
|
||||
|
||||
|
@ -627,76 +423,86 @@ message *m_ptr;
|
|||
code_addr = (vir_bytes) monitor_code;
|
||||
code_size = strlen(monitor_code) + 1;
|
||||
sys_abort(abort_flag, PM_PROC_NR, code_addr, code_size);
|
||||
break;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case PM_EXEC_REPLY:
|
||||
proc_e= m_ptr->PM_EXEC_PROC;
|
||||
if (pm_isokendpt(proc_e, &proc_n) != OK)
|
||||
{
|
||||
panic(__FILE__,
|
||||
"PM_EXIT_REPLY: got bad endpoint from FS",
|
||||
proc_e);
|
||||
/* Get the process associated with this call */
|
||||
proc_e = m_in.PM_PROC;
|
||||
|
||||
if (pm_isokendpt(proc_e, &proc_n) != OK) {
|
||||
panic(__FILE__, "handle_fs_reply: got bad endpoint from FS", proc_e);
|
||||
}
|
||||
|
||||
rmp = &mproc[proc_n];
|
||||
|
||||
/* Call is finished */
|
||||
rmp->mp_fs_call= PM_IDLE;
|
||||
/* Now that FS replied, mark the process as FS-idle again */
|
||||
if (!(rmp->mp_flags & FS_CALL))
|
||||
panic(__FILE__, "handle_fs_reply: reply without request", call_nr);
|
||||
|
||||
exec_restart(rmp, m_ptr->PM_EXEC_STATUS);
|
||||
rmp->mp_flags &= ~FS_CALL;
|
||||
|
||||
restart_sigs(rmp);
|
||||
if (rmp->mp_flags & UNPAUSED)
|
||||
panic(__FILE__, "handle_fs_reply: UNPAUSED set on entry", call_nr);
|
||||
|
||||
/* Call-specific handler code */
|
||||
switch (call_nr) {
|
||||
case PM_SETUID_REPLY:
|
||||
case PM_SETGID_REPLY:
|
||||
/* Wake up the original caller */
|
||||
setreply(rmp-mproc, OK);
|
||||
|
||||
break;
|
||||
|
||||
case PM_SETSID_REPLY:
|
||||
/* Wake up the original caller */
|
||||
setreply(rmp-mproc, rmp->mp_procgrp);
|
||||
|
||||
break;
|
||||
|
||||
case PM_EXEC_REPLY:
|
||||
exec_restart(rmp, m_in.PM_STATUS);
|
||||
|
||||
break;
|
||||
|
||||
case PM_EXIT_REPLY:
|
||||
exit_restart(rmp, FALSE /*dump_core*/);
|
||||
|
||||
break;
|
||||
|
||||
case PM_CORE_REPLY:
|
||||
{
|
||||
proc_e= m_ptr->PM_CORE_PROC;
|
||||
if (pm_isokendpt(proc_e, &proc_n) != OK)
|
||||
{
|
||||
panic(__FILE__,
|
||||
"PM_EXIT_REPLY: got bad endpoint from FS",
|
||||
proc_e);
|
||||
}
|
||||
rmp= &mproc[proc_n];
|
||||
|
||||
if (m_ptr->PM_CORE_STATUS == OK)
|
||||
if (m_in.PM_STATUS == OK)
|
||||
rmp->mp_sigstatus |= DUMPED;
|
||||
|
||||
/* Call is finished */
|
||||
rmp->mp_fs_call= PM_IDLE;
|
||||
|
||||
exit_restart(rmp, TRUE /*dump_core*/);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic(__FILE__, "handle_fs_reply: unknown reply type",
|
||||
m_ptr->m_type);
|
||||
|
||||
case PM_FORK_REPLY:
|
||||
/* Wake up the newly created process */
|
||||
setreply(proc_n, OK);
|
||||
|
||||
/* Wake up the parent */
|
||||
setreply(rmp->mp_parent, rmp->mp_pid);
|
||||
|
||||
break;
|
||||
|
||||
case PM_FORK_NB_REPLY:
|
||||
/* Nothing to do */
|
||||
|
||||
break;
|
||||
|
||||
case PM_UNPAUSE_REPLY:
|
||||
/* Process is now unpaused */
|
||||
rmp->mp_flags |= UNPAUSED;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
panic(__FILE__, "handle_fs_reply: unknown reply code", call_nr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* restart_sigs *
|
||||
*===========================================================================*/
|
||||
PRIVATE void restart_sigs(rmp)
|
||||
struct mproc *rmp;
|
||||
{
|
||||
|
||||
if (rmp->mp_fs_call != PM_IDLE || rmp->mp_fs_call2 != PM_IDLE)
|
||||
return;
|
||||
|
||||
if (rmp->mp_flags & TRACE_EXIT) {
|
||||
exit_proc(rmp, rmp->mp_exitstatus, FALSE /*dump_core*/);
|
||||
}
|
||||
else if (rmp->mp_flags & PM_SIG_PENDING) {
|
||||
rmp->mp_flags &= ~PM_SIG_PENDING;
|
||||
check_pending(rmp);
|
||||
if (!(rmp->mp_flags & PM_SIG_PENDING)) {
|
||||
/* Allow the process to be scheduled */
|
||||
sys_nice(rmp->mp_endpoint, rmp->mp_nice);
|
||||
}
|
||||
}
|
||||
/* Now that the process is idle again, look at pending signals */
|
||||
if ((rmp->mp_flags & (IN_USE | EXITING)) == IN_USE)
|
||||
restart_sigs(rmp);
|
||||
}
|
||||
|
|
|
@ -117,13 +117,6 @@ PUBLIC int do_procstat()
|
|||
*/
|
||||
|
||||
/* This call should be removed, or made more general. */
|
||||
if (mp->mp_effuid != 0)
|
||||
{
|
||||
printf("PM: unauthorized call of do_procstat by proc %d\n",
|
||||
mp->mp_endpoint);
|
||||
sys_sysctl_stacktrace(mp->mp_endpoint);
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
if (m_in.stat_nr == SELF) {
|
||||
mp->mp_reply.sig_set = mp->mp_sigpending;
|
||||
|
@ -323,15 +316,13 @@ PUBLIC int do_getprocnr()
|
|||
#endif
|
||||
|
||||
if (m_in.pid >= 0) { /* lookup process by pid */
|
||||
for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
|
||||
if ((rmp->mp_flags & IN_USE) && (rmp->mp_pid==m_in.pid)) {
|
||||
if ((rmp = find_proc(m_in.pid)) != NIL_MPROC) {
|
||||
mp->mp_reply.PM_ENDPT = rmp->mp_endpoint;
|
||||
#if 0
|
||||
printf("PM: pid result: %d\n", rmp->mp_endpoint);
|
||||
#endif
|
||||
return(OK);
|
||||
}
|
||||
}
|
||||
return(ESRCH);
|
||||
} else if (m_in.namelen > 0) { /* lookup process by name */
|
||||
key_len = MIN(m_in.namelen, PROC_NAME_LEN);
|
||||
|
@ -393,6 +384,7 @@ PUBLIC int do_getpuid()
|
|||
*===========================================================================*/
|
||||
PUBLIC int do_reboot()
|
||||
{
|
||||
message m;
|
||||
int r;
|
||||
|
||||
/* Check permission to abort the system. */
|
||||
|
@ -419,11 +411,12 @@ PUBLIC int do_reboot()
|
|||
*/
|
||||
|
||||
check_sig(-1, SIGKILL); /* kill all users except init */
|
||||
sys_nice(INIT_PROC_NR, PRIO_STOP); /* stop init, but keep it around */
|
||||
sys_stop(INIT_PROC_NR); /* stop init, but keep it around */
|
||||
|
||||
report_reboot= 1;
|
||||
r= notify(FS_PROC_NR);
|
||||
if (r != OK) panic("pm", "do_reboot: unable to notify FS", r);
|
||||
/* Tell FS to reboot */
|
||||
m.m_type = PM_REBOOT;
|
||||
|
||||
tell_fs(&mproc[FS_PROC_NR], &m);
|
||||
|
||||
return(SUSPEND); /* don't reply to caller */
|
||||
}
|
||||
|
@ -433,8 +426,7 @@ PUBLIC int do_reboot()
|
|||
*===========================================================================*/
|
||||
PUBLIC int do_getsetpriority()
|
||||
{
|
||||
int arg_which, arg_who, arg_pri;
|
||||
int rmp_nr;
|
||||
int r, arg_which, arg_who, arg_pri;
|
||||
struct mproc *rmp;
|
||||
|
||||
arg_which = m_in.m1_i1;
|
||||
|
@ -448,13 +440,11 @@ PUBLIC int do_getsetpriority()
|
|||
return(EINVAL);
|
||||
|
||||
if (arg_who == 0)
|
||||
rmp_nr = who_p;
|
||||
rmp = mp;
|
||||
else
|
||||
if ((rmp_nr = proc_from_pid(arg_who)) < 0)
|
||||
if ((rmp = find_proc(arg_who)) == NIL_MPROC)
|
||||
return(ESRCH);
|
||||
|
||||
rmp = &mproc[rmp_nr];
|
||||
|
||||
if (mp->mp_effuid != SUPER_USER &&
|
||||
mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid)
|
||||
return EPERM;
|
||||
|
@ -468,9 +458,12 @@ PUBLIC int do_getsetpriority()
|
|||
if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER)
|
||||
return(EACCES);
|
||||
|
||||
/* We're SET, and it's allowed. Do it and tell kernel. */
|
||||
/* We're SET, and it's allowed. */
|
||||
if ((r = sys_nice(rmp->mp_endpoint, arg_pri)) != OK)
|
||||
return(r);
|
||||
|
||||
rmp->mp_nice = arg_pri;
|
||||
return sys_nice(rmp->mp_endpoint, arg_pri);
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <timers.h>
|
||||
#include <signal.h>
|
||||
|
||||
/* Needs to be included here, for 'ps' etc */
|
||||
#include "const.h"
|
||||
|
||||
EXTERN struct mproc {
|
||||
|
@ -17,6 +18,7 @@ EXTERN struct mproc {
|
|||
pid_t mp_procgrp; /* pid of process group (used for signals) */
|
||||
pid_t mp_wpid; /* pid this process is waiting for */
|
||||
int mp_parent; /* index of parent process */
|
||||
int mp_tracer; /* index of tracer process, or NO_TRACER */
|
||||
|
||||
/* Child user and system times. Accounting done on child exit. */
|
||||
clock_t mp_child_utime; /* cumulative user time of children */
|
||||
|
@ -35,26 +37,17 @@ EXTERN struct mproc {
|
|||
sigset_t mp_sigmask; /* signals to be blocked */
|
||||
sigset_t mp_sigmask2; /* saved copy of mp_sigmask */
|
||||
sigset_t mp_sigpending; /* pending signals to be handled */
|
||||
struct sigaction mp_sigact[_NSIG + 1]; /* as in sigaction(2) */
|
||||
sigset_t mp_sigtrace; /* signals to hand to tracer first */
|
||||
struct sigaction mp_sigact[_NSIG]; /* as in sigaction(2) */
|
||||
vir_bytes mp_sigreturn; /* address of C library __sigreturn function */
|
||||
struct sigmsg mp_sigmsg; /* Save the details of the signal until the
|
||||
* PM_UNPAUSE request is delivered.
|
||||
*/
|
||||
struct timer mp_timer; /* watchdog timer for alarm(2), setitimer(2) */
|
||||
clock_t mp_interval[NR_ITIMERS]; /* setitimer(2) repetition intervals */
|
||||
|
||||
unsigned mp_flags; /* flag bits */
|
||||
unsigned mp_trace_flags; /* trace options */
|
||||
vir_bytes mp_procargs; /* ptr to proc's initial stack arguments */
|
||||
message mp_reply; /* reply message to be sent to one */
|
||||
|
||||
/* Communication with FS */
|
||||
int mp_fs_call; /* Record the call for normal system calls */
|
||||
int mp_fs_call2; /* Record the call for signals */
|
||||
char *mp_exec_path; /* Path of executable */
|
||||
vir_bytes mp_exec_path_len; /* Length of path (including nul) */
|
||||
char *mp_exec_frame; /* Arguments */
|
||||
vir_bytes mp_exec_frame_len; /* Length of arguments */
|
||||
|
||||
/* Scheduling priority. */
|
||||
signed int mp_nice; /* nice is PRIO_MIN..PRIO_MAX, standard 0. */
|
||||
|
||||
|
@ -62,21 +55,24 @@ EXTERN struct mproc {
|
|||
} mproc[NR_PROCS];
|
||||
|
||||
/* Flag values */
|
||||
#define IN_USE 0x001 /* set when 'mproc' slot in use */
|
||||
#define WAITING 0x002 /* set by WAIT system call */
|
||||
#define ZOMBIE 0x004 /* waiting for parent to issue WAIT call */
|
||||
#define PAUSED 0x008 /* set by PAUSE system call */
|
||||
#define ALARM_ON 0x010 /* set when SIGALRM timer started */
|
||||
#define TRACED 0x040 /* set if process is to be traced */
|
||||
#define STOPPED 0x080 /* set if process stopped for tracing */
|
||||
#define SIGSUSPENDED 0x100 /* set by SIGSUSPEND system call */
|
||||
#define REPLY 0x200 /* set if a reply message is pending */
|
||||
#define PRIV_PROC 0x2000 /* system process, special privileges */
|
||||
#define PM_SIG_PENDING 0x4000 /* process got a signal while waiting for FS */
|
||||
#define PARTIAL_EXEC 0x8000 /* Process got a new map but no content */
|
||||
#define TOLD_PARENT 0x10000 /* Parent wait() completed, ZOMBIE off */
|
||||
#define EXITING 0x20000 /* set by EXIT, process is now exiting */
|
||||
#define TRACE_EXIT 0x40000 /* tracer is forcing this process to exit */
|
||||
#define IN_USE 0x00001 /* set when 'mproc' slot in use */
|
||||
#define WAITING 0x00002 /* set by WAIT system call */
|
||||
#define ZOMBIE 0x00004 /* waiting for parent to issue WAIT call */
|
||||
#define PAUSED 0x00008 /* set by PAUSE system call */
|
||||
#define ALARM_ON 0x00010 /* set when SIGALRM timer started */
|
||||
#define EXITING 0x00020 /* set by EXIT, process is now exiting */
|
||||
#define TOLD_PARENT 0x00040 /* parent wait() completed, ZOMBIE off */
|
||||
#define STOPPED 0x00080 /* set if process stopped for tracing */
|
||||
#define SIGSUSPENDED 0x00100 /* set by SIGSUSPEND system call */
|
||||
#define REPLY 0x00200 /* set if a reply message is pending */
|
||||
#define FS_CALL 0x00400 /* set if waiting for FS (normal calls) */
|
||||
#define PM_SIG_PENDING 0x00800 /* process got a signal while waiting for FS */
|
||||
#define UNPAUSED 0x01000 /* process is not in a blocking call */
|
||||
#define PRIV_PROC 0x02000 /* system process, special privileges */
|
||||
#define PARTIAL_EXEC 0x04000 /* process got a new map but no content */
|
||||
#define TRACE_EXIT 0x08000 /* tracer is forcing this process to exit */
|
||||
#define TRACE_ZOMBIE 0x10000 /* waiting for tracer to issue WAIT call */
|
||||
#define DELAY_CALL 0x20000 /* waiting for call before sending signal */
|
||||
|
||||
#define NIL_MPROC ((struct mproc *) 0)
|
||||
|
||||
|
|
|
@ -16,19 +16,10 @@ _PROTOTYPE( void check_vtimer, (int proc_nr, int sig) );
|
|||
/* break.c */
|
||||
_PROTOTYPE( int do_brk, (void) );
|
||||
|
||||
/* devio.c */
|
||||
_PROTOTYPE( int do_dev_io, (void) );
|
||||
_PROTOTYPE( int do_dev_io, (void) );
|
||||
|
||||
/* dma.c */
|
||||
_PROTOTYPE( int do_adddma, (void) );
|
||||
_PROTOTYPE( int do_deldma, (void) );
|
||||
_PROTOTYPE( int do_getdma, (void) );
|
||||
_PROTOTYPE( void release_dma, (endpoint_t proc_e, phys_clicks base,
|
||||
phys_clicks size) );
|
||||
|
||||
/* dmp.c */
|
||||
_PROTOTYPE( int do_fkey_pressed, (void) );
|
||||
|
||||
/* exec.c */
|
||||
_PROTOTYPE( int do_exec, (void) );
|
||||
|
@ -40,19 +31,19 @@ _PROTOTYPE( void exec_restart, (struct mproc *rmp, int result) );
|
|||
_PROTOTYPE( int do_fork, (void) );
|
||||
_PROTOTYPE( int do_fork_nb, (void) );
|
||||
_PROTOTYPE( int do_exit, (void) );
|
||||
_PROTOTYPE( int do_waitpid, (void) );
|
||||
_PROTOTYPE( void exit_proc, (struct mproc *rmp, int exit_status,
|
||||
int dump_core) );
|
||||
_PROTOTYPE( void exit_restart, (struct mproc *rmp, int dump_core) );
|
||||
_PROTOTYPE( int do_waitpid, (void) );
|
||||
_PROTOTYPE( int wait_test, (struct mproc *rmp, struct mproc *child) );
|
||||
|
||||
/* getset.c */
|
||||
_PROTOTYPE( int do_getset, (void) );
|
||||
|
||||
/* kputc.c */
|
||||
_PROTOTYPE( void diag_repl, (void) );
|
||||
_PROTOTYPE( int do_get, (void) );
|
||||
_PROTOTYPE( int do_set, (void) );
|
||||
|
||||
/* main.c */
|
||||
_PROTOTYPE( int main, (void) );
|
||||
_PROTOTYPE( void setreply, (int proc_nr, int result) );
|
||||
|
||||
/* misc.c */
|
||||
_PROTOTYPE( int do_reboot, (void) );
|
||||
|
@ -67,13 +58,6 @@ _PROTOTYPE( int do_allocmem, (void) );
|
|||
_PROTOTYPE( int do_freemem, (void) );
|
||||
_PROTOTYPE( int do_getsetpriority, (void) );
|
||||
|
||||
|
||||
#if (MACHINE == MACINTOSH)
|
||||
_PROTOTYPE( phys_clicks start_click, (void) );
|
||||
#endif
|
||||
|
||||
_PROTOTYPE( void setreply, (int proc_nr, int result) );
|
||||
|
||||
/* profile.c */
|
||||
_PROTOTYPE( int do_sprofile, (void) );
|
||||
_PROTOTYPE( int do_cprofile, (void) );
|
||||
|
@ -83,15 +67,15 @@ _PROTOTYPE( int do_kill, (void) );
|
|||
_PROTOTYPE( int ksig_pending, (void) );
|
||||
_PROTOTYPE( int do_pause, (void) );
|
||||
_PROTOTYPE( int check_sig, (pid_t proc_id, int signo) );
|
||||
_PROTOTYPE( void sig_proc, (struct mproc *rmp, int sig_nr) );
|
||||
_PROTOTYPE( void sig_proc, (struct mproc *rmp, int signo, int trace) );
|
||||
_PROTOTYPE( int do_sigaction, (void) );
|
||||
_PROTOTYPE( int do_sigpending, (void) );
|
||||
_PROTOTYPE( int do_sigprocmask, (void) );
|
||||
_PROTOTYPE( int do_sigreturn, (void) );
|
||||
_PROTOTYPE( int do_sigsuspend, (void) );
|
||||
_PROTOTYPE( void check_pending, (struct mproc *rmp) );
|
||||
_PROTOTYPE( int, vm_notify_sig_wrapper(endpoint_t ep) );
|
||||
|
||||
_PROTOTYPE( void restart_sigs, (struct mproc *rmp) );
|
||||
_PROTOTYPE( void vm_notify_sig_wrapper, (endpoint_t ep) );
|
||||
|
||||
/* time.c */
|
||||
_PROTOTYPE( int do_stime, (void) );
|
||||
|
@ -112,8 +96,7 @@ _PROTOTYPE( void stop_proc, (struct mproc *rmp, int sig_nr) );
|
|||
/* utility.c */
|
||||
_PROTOTYPE( pid_t get_free_pid, (void) );
|
||||
_PROTOTYPE( int no_sys, (void) );
|
||||
_PROTOTYPE( void panic, (char *who, char *mess, int num) );
|
||||
_PROTOTYPE( char *find_param, (const char *key) );
|
||||
_PROTOTYPE( int proc_from_pid, (pid_t p));
|
||||
_PROTOTYPE( struct mproc *find_proc, (pid_t lpid) );
|
||||
_PROTOTYPE( int pm_isokendpt, (int ep, int *proc) );
|
||||
|
||||
_PROTOTYPE( void tell_fs, (struct mproc *rmp, message *m_ptr) );
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
* sig_proc: interrupt or terminate a signaled process
|
||||
* check_sig: check which processes to signal with sig_proc()
|
||||
* check_pending: check if a pending signal can now be delivered
|
||||
* restart_sigs: restart signal work after finishing a FS call
|
||||
*/
|
||||
|
||||
#include "pm.h"
|
||||
|
@ -32,8 +33,9 @@
|
|||
#include "mproc.h"
|
||||
#include "param.h"
|
||||
|
||||
FORWARD _PROTOTYPE( void unpause, (int pro, int for_trace) );
|
||||
FORWARD _PROTOTYPE( void unpause, (struct mproc *rmp) );
|
||||
FORWARD _PROTOTYPE( void handle_ksig, (int proc_nr, sigset_t sig_map) );
|
||||
FORWARD _PROTOTYPE( int sig_send, (struct mproc *rmp, int signo) );
|
||||
|
||||
/*===========================================================================*
|
||||
* do_sigaction *
|
||||
|
@ -45,7 +47,7 @@ PUBLIC int do_sigaction()
|
|||
struct sigaction *svp;
|
||||
|
||||
if (m_in.sig_nr == SIGKILL) return(OK);
|
||||
if (m_in.sig_nr < 1 || m_in.sig_nr > _NSIG) return (EINVAL);
|
||||
if (m_in.sig_nr < 1 || m_in.sig_nr >= _NSIG) return(EINVAL);
|
||||
svp = &mp->mp_sigact[m_in.sig_nr];
|
||||
if ((struct sigaction *) m_in.sig_osa != (struct sigaction *) NULL) {
|
||||
r = sys_datacopy(PM_PROC_NR,(vir_bytes) svp,
|
||||
|
@ -122,14 +124,14 @@ PUBLIC int do_sigprocmask()
|
|||
case SIG_BLOCK:
|
||||
sigdelset((sigset_t *)&m_in.sig_set, SIGKILL);
|
||||
sigdelset((sigset_t *)&m_in.sig_set, SIGSTOP);
|
||||
for (i = 1; i <= _NSIG; i++) {
|
||||
for (i = 1; i < _NSIG; i++) {
|
||||
if (sigismember((sigset_t *)&m_in.sig_set, i))
|
||||
sigaddset(&mp->mp_sigmask, i);
|
||||
}
|
||||
break;
|
||||
|
||||
case SIG_UNBLOCK:
|
||||
for (i = 1; i <= _NSIG; i++) {
|
||||
for (i = 1; i < _NSIG; i++) {
|
||||
if (sigismember((sigset_t *)&m_in.sig_set, i))
|
||||
sigdelset(&mp->mp_sigmask, i);
|
||||
}
|
||||
|
@ -212,7 +214,7 @@ PUBLIC int ksig_pending()
|
|||
* signals until all signals are handled. If there are no more signals,
|
||||
* NONE is returned in the process number field.
|
||||
*/
|
||||
int proc_nr_e;
|
||||
endpoint_t proc_nr_e;
|
||||
sigset_t sig_map;
|
||||
|
||||
while (TRUE) {
|
||||
|
@ -257,7 +259,9 @@ sigset_t sig_map;
|
|||
}
|
||||
rmp = &mproc[proc_nr];
|
||||
if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) {
|
||||
#if 0
|
||||
printf("PM: handle_ksig: %d?? exiting / not in use\n", proc_nr_e);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
proc_id = rmp->mp_pid;
|
||||
|
@ -272,7 +276,7 @@ sigset_t sig_map;
|
|||
* to indicate a broadcast to the recipient's process group. For
|
||||
* SIGKILL, use proc_id -1 to indicate a systemwide broadcast.
|
||||
*/
|
||||
for (i = 1; i <= _NSIG; i++) {
|
||||
for (i = 1; i < _NSIG; i++) {
|
||||
if (!sigismember(&sig_map, i)) continue;
|
||||
#if 0
|
||||
printf("PM: sig %d for %d from kernel\n",
|
||||
|
@ -293,6 +297,26 @@ sigset_t sig_map;
|
|||
}
|
||||
check_sig(id, i);
|
||||
}
|
||||
|
||||
/* If SIGKREADY is set, an earlier sys_stop() failed because the process was
|
||||
* still sending, and the kernel hereby tells us that the process is now done
|
||||
* with that. We can now try to resume what we planned to do in the first
|
||||
* place: set up a signal handler. However, the process's message may have
|
||||
* been a call to PM, in which case the process may have changed any of its
|
||||
* signal settings. The process may also have forked, exited etcetera.
|
||||
*/
|
||||
if (sigismember(&sig_map, SIGKREADY) && (rmp->mp_flags & DELAY_CALL)) {
|
||||
rmp->mp_flags &= ~DELAY_CALL;
|
||||
|
||||
if (rmp->mp_flags & (FS_CALL | PM_SIG_PENDING))
|
||||
panic(__FILE__, "handle_ksig: bad process state", NO_NUM);
|
||||
|
||||
/* Process as many normal signals as possible. */
|
||||
check_pending(rmp);
|
||||
|
||||
if (rmp->mp_flags & DELAY_CALL)
|
||||
panic(__FILE__, "handle_ksig: multiple delay calls?", NO_NUM);
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -306,34 +330,13 @@ PUBLIC int do_pause()
|
|||
return(SUSPEND);
|
||||
}
|
||||
|
||||
PUBLIC vm_notify_sig_wrapper(endpoint_t ep)
|
||||
{
|
||||
/* get IPC's endpoint,
|
||||
* the reason that we directly get the endpoint
|
||||
* instead of from DS server is that otherwise
|
||||
* it will cause deadlock between PM, VM and DS.
|
||||
*/
|
||||
struct mproc *rmp;
|
||||
endpoint_t ipc_ep = 0;
|
||||
|
||||
for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
|
||||
if (!(rmp->mp_flags & IN_USE))
|
||||
continue;
|
||||
if (!strcmp(rmp->mp_name, "ipc")) {
|
||||
ipc_ep = rmp->mp_endpoint;
|
||||
vm_notify_sig(ep, ipc_ep);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sig_proc *
|
||||
*===========================================================================*/
|
||||
PUBLIC void sig_proc(rmp, signo)
|
||||
PUBLIC void sig_proc(rmp, signo, trace)
|
||||
register struct mproc *rmp; /* pointer to the process to be signaled */
|
||||
int signo; /* signal to send to process (1 to _NSIG) */
|
||||
int signo; /* signal to send to process (1 to _NSIG-1) */
|
||||
int trace; /* pass signal to tracer first? */
|
||||
{
|
||||
/* Send a signal to a process. Check to see if the signal is to be caught,
|
||||
* ignored, tranformed into a message (for system processes) or blocked.
|
||||
|
@ -348,34 +351,44 @@ int signo; /* signal to send to process (1 to _NSIG) */
|
|||
* context from the sigcontext structure.
|
||||
* If there is insufficient stack space, kill the process.
|
||||
*/
|
||||
|
||||
vir_bytes cur_sp;
|
||||
int s;
|
||||
int slot;
|
||||
int sigflags;
|
||||
int r, slot;
|
||||
|
||||
slot = (int) (rmp - mproc);
|
||||
if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) {
|
||||
printf("PM: signal %d sent to exiting process %d\n", signo, slot);
|
||||
panic(__FILE__,"", NO_NUM);
|
||||
}
|
||||
if (rmp->mp_fs_call != PM_IDLE || rmp->mp_fs_call2 != PM_IDLE)
|
||||
{
|
||||
sigaddset(&rmp->mp_sigpending, signo);
|
||||
rmp->mp_flags |= PM_SIG_PENDING;
|
||||
/* keep the process from running */
|
||||
sys_nice(rmp->mp_endpoint, PRIO_STOP);
|
||||
return;
|
||||
|
||||
}
|
||||
if ((rmp->mp_flags & TRACED) && signo != SIGKILL) {
|
||||
/* A traced process has special handling. */
|
||||
unpause(slot, TRUE /*for_trace*/);
|
||||
if (trace == TRUE && rmp->mp_tracer != NO_TRACER && signo != SIGKILL) {
|
||||
/* Signal should be passed to the debugger first.
|
||||
* This happens before any checks on block/ignore masks; otherwise,
|
||||
* the process itself could block/ignore debugger signals.
|
||||
*/
|
||||
|
||||
sigaddset(&rmp->mp_sigtrace, signo);
|
||||
|
||||
if (!(rmp->mp_flags & STOPPED))
|
||||
stop_proc(rmp, signo); /* a signal causes it to stop */
|
||||
|
||||
return;
|
||||
}
|
||||
/* Some signals are ignored by default. */
|
||||
|
||||
if (rmp->mp_flags & FS_CALL) {
|
||||
sigaddset(&rmp->mp_sigpending, signo);
|
||||
|
||||
if (!(rmp->mp_flags & PM_SIG_PENDING)) {
|
||||
/* This stop request must never result in EBUSY here! */
|
||||
if ((r = sys_stop(rmp->mp_endpoint)) != OK)
|
||||
panic(__FILE__, "sys_stop failed", r);
|
||||
|
||||
rmp->mp_flags |= PM_SIG_PENDING;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (sigismember(&rmp->mp_ignore, signo)) {
|
||||
/* Signal should be ignored. */
|
||||
return;
|
||||
}
|
||||
if (sigismember(&rmp->mp_sigmask, signo)) {
|
||||
|
@ -383,76 +396,54 @@ int signo; /* signal to send to process (1 to _NSIG) */
|
|||
sigaddset(&rmp->mp_sigpending, signo);
|
||||
return;
|
||||
}
|
||||
sigflags = rmp->mp_sigact[signo].sa_flags;
|
||||
if (sigismember(&rmp->mp_catch, signo)) {
|
||||
if (rmp->mp_flags & SIGSUSPENDED)
|
||||
rmp->mp_sigmsg.sm_mask = rmp->mp_sigmask2;
|
||||
else
|
||||
rmp->mp_sigmsg.sm_mask = rmp->mp_sigmask;
|
||||
rmp->mp_sigmsg.sm_signo = signo;
|
||||
rmp->mp_sigmsg.sm_sighandler =
|
||||
(vir_bytes) rmp->mp_sigact[signo].sa_handler;
|
||||
rmp->mp_sigmsg.sm_sigreturn = rmp->mp_sigreturn;
|
||||
rmp->mp_sigmask |= rmp->mp_sigact[signo].sa_mask;
|
||||
|
||||
if (sigflags & SA_NODEFER)
|
||||
sigdelset(&rmp->mp_sigmask, signo);
|
||||
else
|
||||
sigaddset(&rmp->mp_sigmask, signo);
|
||||
|
||||
if (sigflags & SA_RESETHAND) {
|
||||
sigdelset(&rmp->mp_catch, signo);
|
||||
rmp->mp_sigact[signo].sa_handler = SIG_DFL;
|
||||
}
|
||||
sigdelset(&rmp->mp_sigpending, signo);
|
||||
|
||||
/* Stop process from running before we fiddle with its stack. */
|
||||
sys_nice(rmp->mp_endpoint, PRIO_STOP);
|
||||
if(vm_push_sig(rmp->mp_endpoint, &cur_sp) != OK)
|
||||
goto doterminate;
|
||||
|
||||
rmp->mp_sigmsg.sm_stkptr = cur_sp;
|
||||
|
||||
/* Check to see if process is hanging on a PAUSE, WAIT or SIGSUSPEND
|
||||
* call.
|
||||
*/
|
||||
if (rmp->mp_flags & (PAUSED | WAITING | SIGSUSPENDED)) {
|
||||
rmp->mp_flags &= ~(PAUSED | WAITING | SIGSUSPENDED);
|
||||
setreply(slot, EINTR);
|
||||
|
||||
/* Ask the kernel to deliver the signal */
|
||||
s= sys_sigsend(rmp->mp_endpoint, &rmp->mp_sigmsg);
|
||||
if (s != OK)
|
||||
panic(__FILE__, "sys_sigsend failed", s);
|
||||
|
||||
/* Done */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ask FS to unpause the process. Deliver the signal when FS is
|
||||
* ready.
|
||||
*/
|
||||
unpause(slot, FALSE /*!for_trace*/);
|
||||
vm_notify_sig_wrapper(rmp->mp_endpoint);
|
||||
return;
|
||||
}
|
||||
else if (sigismember(&rmp->mp_sig2mess, signo)) {
|
||||
|
||||
if (sigismember(&rmp->mp_sig2mess, signo)) {
|
||||
/* Mark event pending in process slot and send notification. */
|
||||
sigaddset(&rmp->mp_sigpending, signo);
|
||||
notify(rmp->mp_endpoint);
|
||||
return;
|
||||
}
|
||||
|
||||
doterminate:
|
||||
/* Signal should not or cannot be caught. Take default action. */
|
||||
if (sigismember(&ign_sset, signo)) {
|
||||
if ((rmp->mp_flags & STOPPED) && signo != SIGKILL) {
|
||||
/* If the process is stopped for a debugger, do not deliver any signals
|
||||
* (except SIGKILL) in order not to confuse the debugger. The signals
|
||||
* will be delivered using the check_pending() calls in do_trace().
|
||||
*/
|
||||
sigaddset(&rmp->mp_sigpending, signo);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sigismember(&rmp->mp_catch, signo)) {
|
||||
/* Signal is caught. First interrupt the process's current call, if
|
||||
* applicable. This may involve a roundtrip to FS, in which case we'll
|
||||
* have to check back later.
|
||||
*/
|
||||
if (!(rmp->mp_flags & UNPAUSED)) {
|
||||
unpause(rmp);
|
||||
|
||||
if (!(rmp->mp_flags & UNPAUSED)) {
|
||||
/* not yet unpaused; continue later */
|
||||
sigaddset(&rmp->mp_sigpending, signo);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Then send the actual signal to the process, by setting up a signal
|
||||
* handler.
|
||||
*/
|
||||
if (sig_send(rmp, signo))
|
||||
return;
|
||||
|
||||
/* We were unable to spawn a signal handler. Kill the process. */
|
||||
}
|
||||
else if (sigismember(&ign_sset, signo)) {
|
||||
/* Signal defaults to being ignored. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Terminate process */
|
||||
rmp->mp_sigstatus = (char) signo;
|
||||
if (sigismember(&core_sset, signo) && slot != FS_PROC_NR) {
|
||||
if (sigismember(&core_sset, signo)) {
|
||||
printf("PM: coredump signal %d for %d / %s\n", signo, rmp->mp_pid,
|
||||
rmp->mp_name);
|
||||
exit_proc(rmp, 0, TRUE /*dump_core*/);
|
||||
|
@ -467,7 +458,7 @@ doterminate:
|
|||
*===========================================================================*/
|
||||
PUBLIC int check_sig(proc_id, signo)
|
||||
pid_t proc_id; /* pid of proc to sig, or 0 or -1, or -pgrp */
|
||||
int signo; /* signal to send to process (0 to _NSIG) */
|
||||
int signo; /* signal to send to process (0 to _NSIG-1) */
|
||||
{
|
||||
/* Check to see if it is possible to send a signal. The signal may have to be
|
||||
* sent to a group of processes. This routine is invoked by the KILL system
|
||||
|
@ -478,7 +469,7 @@ int signo; /* signal to send to process (0 to _NSIG) */
|
|||
int count; /* count # of signals sent */
|
||||
int error_code;
|
||||
|
||||
if (signo < 0 || signo > _NSIG) return(EINVAL);
|
||||
if (signo < 0 || signo >= _NSIG) return(EINVAL);
|
||||
|
||||
/* Return EINVAL for attempts to send SIGKILL to INIT alone. */
|
||||
if (proc_id == INIT_PID && signo == SIGKILL) return(EINVAL);
|
||||
|
@ -518,7 +509,7 @@ int signo; /* signal to send to process (0 to _NSIG) */
|
|||
* signal may be caught, blocked, ignored, or cause process
|
||||
* termination, possibly with core dump.
|
||||
*/
|
||||
sig_proc(rmp, signo);
|
||||
sig_proc(rmp, signo, TRUE /*trace*/);
|
||||
|
||||
if (proc_id > 0) break; /* only one process being signaled */
|
||||
}
|
||||
|
@ -534,11 +525,8 @@ int signo; /* signal to send to process (0 to _NSIG) */
|
|||
PUBLIC void check_pending(rmp)
|
||||
register struct mproc *rmp;
|
||||
{
|
||||
/* Check to see if any pending signals have been unblocked. The
|
||||
* first such signal found is delivered.
|
||||
*
|
||||
* If multiple pending unmasked signals are found, they will be
|
||||
* delivered sequentially.
|
||||
/* Check to see if any pending signals have been unblocked. Deliver as many
|
||||
* of them as we can, until we have to wait for a reply from VFS first.
|
||||
*
|
||||
* There are several places in this file where the signal mask is
|
||||
* changed. At each such place, check_pending() should be called to
|
||||
|
@ -547,22 +535,56 @@ register struct mproc *rmp;
|
|||
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= _NSIG; i++) {
|
||||
for (i = 1; i < _NSIG; i++) {
|
||||
if (sigismember(&rmp->mp_sigpending, i) &&
|
||||
!sigismember(&rmp->mp_sigmask, i)) {
|
||||
sigdelset(&rmp->mp_sigpending, i);
|
||||
sig_proc(rmp, i);
|
||||
sig_proc(rmp, i, FALSE /*trace*/);
|
||||
|
||||
if (rmp->mp_flags & FS_CALL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* restart_sigs *
|
||||
*===========================================================================*/
|
||||
PUBLIC void restart_sigs(rmp)
|
||||
struct mproc *rmp;
|
||||
{
|
||||
/* FS has replied to a request from us; do signal-related work.
|
||||
*/
|
||||
|
||||
if (rmp->mp_flags & (FS_CALL | EXITING)) return;
|
||||
|
||||
if (rmp->mp_flags & TRACE_EXIT) {
|
||||
/* Tracer requested exit with specific exit value */
|
||||
exit_proc(rmp, rmp->mp_exitstatus, FALSE /*dump_core*/);
|
||||
}
|
||||
else if (rmp->mp_flags & PM_SIG_PENDING) {
|
||||
/* We saved signal(s) for after finishing a FS call. Deal with this.
|
||||
* PM_SIG_PENDING remains set to indicate the process is still stopped.
|
||||
*/
|
||||
check_pending(rmp);
|
||||
|
||||
/* The process may now be FS-blocked again, because a signal exited the
|
||||
* process or was caught. Restart the process only when this is NOT the
|
||||
* case.
|
||||
*/
|
||||
if (!(rmp->mp_flags & FS_CALL)) {
|
||||
rmp->mp_flags &= ~(PM_SIG_PENDING | UNPAUSED);
|
||||
|
||||
sys_resume(rmp->mp_endpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* unpause *
|
||||
*===========================================================================*/
|
||||
PRIVATE void unpause(pro, for_trace)
|
||||
int pro; /* which process number */
|
||||
int for_trace; /* for tracing */
|
||||
PRIVATE void unpause(rmp)
|
||||
struct mproc *rmp; /* which process */
|
||||
{
|
||||
/* A signal is to be sent to a process. If that process is hanging on a
|
||||
* system call, the system call must be terminated with EINTR. Possible
|
||||
|
@ -570,31 +592,144 @@ int for_trace; /* for tracing */
|
|||
* First check if the process is hanging on an PM call. If not, tell FS,
|
||||
* so it can check for READs and WRITEs from pipes, ttys and the like.
|
||||
*/
|
||||
register struct mproc *rmp;
|
||||
int r;
|
||||
message m;
|
||||
int r, slot;
|
||||
|
||||
rmp = &mproc[pro];
|
||||
/* If we're already waiting for a delayed call, don't do anything now. */
|
||||
if (rmp->mp_flags & DELAY_CALL)
|
||||
return;
|
||||
|
||||
/* Check to see if process is hanging on a PAUSE, WAIT or SIGSUSPEND call. */
|
||||
if (rmp->mp_flags & (PAUSED | WAITING | SIGSUSPENDED)) {
|
||||
rmp->mp_flags &= ~(PAUSED | WAITING | SIGSUSPENDED);
|
||||
setreply(pro, EINTR);
|
||||
/* Stop process from running.
|
||||
* This stop request must never result in EBUSY here!
|
||||
*/
|
||||
if ((r = sys_stop(rmp->mp_endpoint)) != OK)
|
||||
panic(__FILE__, "sys_stop failed", r);
|
||||
|
||||
rmp->mp_flags |= UNPAUSED;
|
||||
|
||||
/* We interrupt the actual call from sig_send() below. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Process is not hanging on an PM call. Ask FS to take a look. */
|
||||
if (for_trace)
|
||||
{
|
||||
if (rmp->mp_fs_call != PM_IDLE)
|
||||
panic( __FILE__, "unpause: not idle", rmp->mp_fs_call);
|
||||
rmp->mp_fs_call= PM_UNPAUSE_TR;
|
||||
/* Not paused in PM. Let FS try to unpause the process. */
|
||||
if (!(rmp->mp_flags & PM_SIG_PENDING)) {
|
||||
/* Stop process from running. */
|
||||
r = sys_stop(rmp->mp_endpoint);
|
||||
|
||||
/* If the process is still busy sending a message, the kernel will give
|
||||
* us EBUSY now and send a SIGKREADY to the process as soon as sending
|
||||
* is done.
|
||||
*/
|
||||
if (r == EBUSY) {
|
||||
rmp->mp_flags |= DELAY_CALL;
|
||||
|
||||
return;
|
||||
}
|
||||
else if (r != OK) panic(__FILE__, "sys_stop failed", r);
|
||||
|
||||
rmp->mp_flags |= PM_SIG_PENDING;
|
||||
}
|
||||
|
||||
m.m_type = PM_UNPAUSE;
|
||||
m.PM_PROC = rmp->mp_endpoint;
|
||||
|
||||
tell_fs(rmp, &m);
|
||||
|
||||
/* Also tell VM. */
|
||||
vm_notify_sig_wrapper(rmp->mp_endpoint);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sig_send *
|
||||
*===========================================================================*/
|
||||
PRIVATE int sig_send(rmp, signo)
|
||||
struct mproc *rmp; /* what process to spawn a signal handler in */
|
||||
int signo; /* signal to send to process (1 to _NSIG-1) */
|
||||
{
|
||||
/* The process is supposed to catch this signal. Spawn a signal handler.
|
||||
* Return TRUE if this succeeded, FALSE otherwise.
|
||||
*/
|
||||
struct sigmsg sigmsg;
|
||||
vir_bytes cur_sp;
|
||||
int r, sigflags, slot;
|
||||
|
||||
if (!(rmp->mp_flags & UNPAUSED))
|
||||
panic(__FILE__, "sig_send: process not unpaused", NO_NUM);
|
||||
|
||||
sigflags = rmp->mp_sigact[signo].sa_flags;
|
||||
slot = (int) (rmp - mproc);
|
||||
|
||||
if (rmp->mp_flags & SIGSUSPENDED)
|
||||
sigmsg.sm_mask = rmp->mp_sigmask2;
|
||||
else
|
||||
sigmsg.sm_mask = rmp->mp_sigmask;
|
||||
sigmsg.sm_signo = signo;
|
||||
sigmsg.sm_sighandler =
|
||||
(vir_bytes) rmp->mp_sigact[signo].sa_handler;
|
||||
sigmsg.sm_sigreturn = rmp->mp_sigreturn;
|
||||
rmp->mp_sigmask |= rmp->mp_sigact[signo].sa_mask;
|
||||
|
||||
if (sigflags & SA_NODEFER)
|
||||
sigdelset(&rmp->mp_sigmask, signo);
|
||||
else
|
||||
sigaddset(&rmp->mp_sigmask, signo);
|
||||
|
||||
if (sigflags & SA_RESETHAND) {
|
||||
sigdelset(&rmp->mp_catch, signo);
|
||||
rmp->mp_sigact[signo].sa_handler = SIG_DFL;
|
||||
}
|
||||
sigdelset(&rmp->mp_sigpending, signo);
|
||||
|
||||
if(vm_push_sig(rmp->mp_endpoint, &cur_sp) != OK)
|
||||
return(FALSE);
|
||||
|
||||
sigmsg.sm_stkptr = cur_sp;
|
||||
|
||||
/* Ask the kernel to deliver the signal */
|
||||
r = sys_sigsend(rmp->mp_endpoint, &sigmsg);
|
||||
if (r != OK)
|
||||
panic(__FILE__, "sys_sigsend failed", r);
|
||||
|
||||
/* Was the process suspended in PM? Then interrupt the blocking call. */
|
||||
if (rmp->mp_flags & (PAUSED | WAITING | SIGSUSPENDED)) {
|
||||
rmp->mp_flags &= ~(PAUSED | WAITING | SIGSUSPENDED);
|
||||
|
||||
setreply(slot, EINTR);
|
||||
}
|
||||
|
||||
/* Was the process stopped just for this signal? Then resume it. */
|
||||
if ((rmp->mp_flags & (PM_SIG_PENDING | UNPAUSED)) == UNPAUSED) {
|
||||
rmp->mp_flags &= ~UNPAUSED;
|
||||
|
||||
sys_resume(rmp->mp_endpoint);
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* vm_notify_sig_wrapper *
|
||||
*===========================================================================*/
|
||||
PUBLIC void vm_notify_sig_wrapper(endpoint_t ep)
|
||||
{
|
||||
if (rmp->mp_fs_call2 != PM_IDLE)
|
||||
panic( __FILE__, "unpause: not idle", rmp->mp_fs_call2);
|
||||
rmp->mp_fs_call2= PM_UNPAUSE;
|
||||
/* get IPC's endpoint,
|
||||
* the reason that we directly get the endpoint
|
||||
* instead of from DS server is that otherwise
|
||||
* it will cause deadlock between PM, VM and DS.
|
||||
*/
|
||||
struct mproc *rmp;
|
||||
endpoint_t ipc_ep = 0;
|
||||
|
||||
for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
|
||||
if (!(rmp->mp_flags & IN_USE))
|
||||
continue;
|
||||
if (!strcmp(rmp->mp_name, "ipc")) {
|
||||
ipc_ep = rmp->mp_endpoint;
|
||||
vm_notify_sig(ep, ipc_ep);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
r= notify(FS_PROC_NR);
|
||||
if (r != OK) panic("pm", "unpause: unable to notify FS", r);
|
||||
}
|
||||
|
|
|
@ -34,11 +34,11 @@ _PROTOTYPE (int (*call_vec[]), (void) ) = {
|
|||
do_brk, /* 17 = break */
|
||||
no_sys, /* 18 = stat */
|
||||
no_sys, /* 19 = lseek */
|
||||
do_getset, /* 20 = getpid */
|
||||
do_get, /* 20 = getpid */
|
||||
no_sys, /* 21 = mount */
|
||||
no_sys, /* 22 = umount */
|
||||
do_getset, /* 23 = setuid */
|
||||
do_getset, /* 24 = getuid */
|
||||
do_set, /* 23 = setuid */
|
||||
do_get, /* 24 = getuid */
|
||||
do_stime, /* 25 = stime */
|
||||
do_trace, /* 26 = ptrace */
|
||||
do_alarm, /* 27 = alarm */
|
||||
|
@ -60,8 +60,8 @@ _PROTOTYPE (int (*call_vec[]), (void) ) = {
|
|||
do_times, /* 43 = times */
|
||||
no_sys, /* 44 = (prof) */
|
||||
no_sys, /* 45 = unused */
|
||||
do_getset, /* 46 = setgid */
|
||||
do_getset, /* 47 = getgid */
|
||||
do_set, /* 46 = setgid */
|
||||
do_get, /* 47 = getgid */
|
||||
no_sys, /* 48 = (signal)*/
|
||||
no_sys, /* 49 = unused */
|
||||
no_sys, /* 50 = unused */
|
||||
|
@ -76,8 +76,8 @@ _PROTOTYPE (int (*call_vec[]), (void) ) = {
|
|||
do_exec, /* 59 = execve */
|
||||
no_sys, /* 60 = umask */
|
||||
no_sys, /* 61 = chroot */
|
||||
do_getset, /* 62 = setsid */
|
||||
do_getset, /* 63 = getpgrp */
|
||||
do_set, /* 62 = setsid */
|
||||
do_get, /* 63 = getpgrp */
|
||||
do_itimer, /* 64 = itimer */
|
||||
no_sys, /* 65 = unused */
|
||||
no_sys, /* 66 = unused */
|
||||
|
@ -105,8 +105,8 @@ _PROTOTYPE (int (*call_vec[]), (void) ) = {
|
|||
do_getsetpriority, /* 88 = getpriority */
|
||||
do_getsetpriority, /* 89 = setpriority */
|
||||
do_time, /* 90 = gettimeofday */
|
||||
do_getset, /* 91 = seteuid */
|
||||
do_getset, /* 92 = setegid */
|
||||
do_set, /* 91 = seteuid */
|
||||
do_set, /* 92 = setegid */
|
||||
no_sys, /* 93 = (truncate) */
|
||||
no_sys, /* 94 = (ftruncate) */
|
||||
no_sys, /* 95 = (fchmod) */
|
||||
|
|
|
@ -14,10 +14,15 @@
|
|||
* T_RESUME resume execution
|
||||
* T_EXIT exit
|
||||
* T_STEP set trace bit
|
||||
* T_SYSCALL trace system call
|
||||
* T_ATTACH attach to an existing process
|
||||
* T_DETACH detach from a traced process
|
||||
* T_SETOPT set trace options
|
||||
*
|
||||
* The T_OK and T_EXIT commands are handled here, and the T_RESUME and
|
||||
* T_STEP commands are partially handled here and completed by the system
|
||||
* task. The rest are handled entirely by the system task.
|
||||
* The T_OK, T_ATTACH, T_EXIT, and T_SETOPT commands are handled here, and the
|
||||
* T_RESUME, T_STEP, T_SYSCALL, and T_DETACH commands are partially handled
|
||||
* here and completed by the system task. The rest are handled entirely by the
|
||||
* system task.
|
||||
*/
|
||||
|
||||
#include "pm.h"
|
||||
|
@ -27,47 +32,81 @@
|
|||
#include "mproc.h"
|
||||
#include "param.h"
|
||||
|
||||
#define NIL_MPROC ((struct mproc *) 0)
|
||||
|
||||
FORWARD _PROTOTYPE( struct mproc *find_proc, (pid_t lpid) );
|
||||
|
||||
/*===========================================================================*
|
||||
* do_trace *
|
||||
*===========================================================================*/
|
||||
PUBLIC int do_trace()
|
||||
{
|
||||
register struct mproc *child;
|
||||
int r;
|
||||
int i, r, req;
|
||||
|
||||
/* the T_OK call is made by the child fork of the debugger before it execs
|
||||
* the process to be traced
|
||||
req = m_in.request;
|
||||
|
||||
/* The T_OK call is made by the child fork of the debugger before it execs
|
||||
* the process to be traced. The T_ATTACH call is made by the debugger itself
|
||||
* to attach to an existing process.
|
||||
*/
|
||||
if (m_in.request == T_OK) { /* enable tracing by parent for this proc */
|
||||
mp->mp_flags |= TRACED;
|
||||
switch (req) {
|
||||
case T_OK: /* enable tracing by parent for this proc */
|
||||
if (mp->mp_tracer != NO_TRACER) return(EBUSY);
|
||||
|
||||
mp->mp_tracer = mp->mp_parent;
|
||||
mp->mp_reply.reply_trace = 0;
|
||||
return(OK);
|
||||
}
|
||||
if (m_in.request == T_READB_INS)
|
||||
{
|
||||
/* Special hack for reading text segments */
|
||||
if (mp->mp_effuid != SUPER_USER)
|
||||
return(EPERM);
|
||||
if ((child=find_proc(m_in.pid))==NIL_MPROC)
|
||||
return(ESRCH);
|
||||
|
||||
r= sys_trace(m_in.request,child->mp_endpoint,m_in.PMTRACE_ADDR,&m_in.data);
|
||||
case T_ATTACH: /* attach to an existing process */
|
||||
if ((child = find_proc(m_in.pid)) == NIL_MPROC) return(ESRCH);
|
||||
if (child->mp_flags & EXITING) return(ESRCH);
|
||||
|
||||
/* For non-root processes, user and group ID must match. */
|
||||
if (mp->mp_effuid != SUPER_USER &&
|
||||
(mp->mp_effuid != child->mp_effuid ||
|
||||
mp->mp_effgid != child->mp_effgid ||
|
||||
child->mp_effuid != child->mp_realuid ||
|
||||
child->mp_effgid != child->mp_realgid)) return(EPERM);
|
||||
|
||||
/* Only root may trace system servers. */
|
||||
if (mp->mp_effuid != SUPER_USER && (child->mp_flags & PRIV_PROC))
|
||||
return(EPERM);
|
||||
|
||||
/* System servers may not trace anyone. They can use sys_trace(). */
|
||||
if (mp->mp_flags & PRIV_PROC) return(EPERM);
|
||||
|
||||
/* Can't trace self, PM or VM. */
|
||||
if (child == mp || child->mp_endpoint == PM_PROC_NR ||
|
||||
child->mp_endpoint == VM_PROC_NR) return(EPERM);
|
||||
|
||||
/* Can't trace a process that is already being traced. */
|
||||
if (child->mp_tracer != NO_TRACER) return(EBUSY);
|
||||
|
||||
child->mp_tracer = who_p;
|
||||
|
||||
sig_proc(child, SIGSTOP, TRUE /*trace*/);
|
||||
|
||||
mp->mp_reply.reply_trace = 0;
|
||||
return(OK);
|
||||
|
||||
case T_STOP: /* stop the process */
|
||||
/* This call is not exposed to user programs, because its effect can be
|
||||
* achieved better by sending the traced process a signal with kill(2).
|
||||
*/
|
||||
return(EINVAL);
|
||||
|
||||
case T_READB_INS: /* special hack for reading text segments */
|
||||
if (mp->mp_effuid != SUPER_USER) return(EPERM);
|
||||
if ((child = find_proc(m_in.pid)) == NIL_MPROC) return(ESRCH);
|
||||
if (child->mp_flags & EXITING) return(ESRCH);
|
||||
|
||||
r = sys_trace(req, child->mp_endpoint, m_in.PMTRACE_ADDR, &m_in.data);
|
||||
if (r != OK) return(r);
|
||||
|
||||
mp->mp_reply.reply_trace = m_in.data;
|
||||
return(OK);
|
||||
}
|
||||
if (m_in.request == T_WRITEB_INS)
|
||||
{
|
||||
/* Special hack for patching text segments */
|
||||
if (mp->mp_effuid != SUPER_USER)
|
||||
return(EPERM);
|
||||
if ((child=find_proc(m_in.pid))==NIL_MPROC)
|
||||
return(ESRCH);
|
||||
|
||||
case T_WRITEB_INS: /* special hack for patching text segments */
|
||||
if (mp->mp_effuid != SUPER_USER) return(EPERM);
|
||||
if ((child = find_proc(m_in.pid)) == NIL_MPROC) return(ESRCH);
|
||||
if (child->mp_flags & EXITING) return(ESRCH);
|
||||
|
||||
#if 0
|
||||
/* Should check for shared text */
|
||||
|
@ -80,42 +119,27 @@ PUBLIC int do_trace()
|
|||
child->mp_ctime = 0;
|
||||
#endif
|
||||
|
||||
r= sys_trace(m_in.request,child->mp_endpoint,m_in.PMTRACE_ADDR,&m_in.data);
|
||||
r = sys_trace(req, child->mp_endpoint, m_in.PMTRACE_ADDR, &m_in.data);
|
||||
if (r != OK) return(r);
|
||||
|
||||
mp->mp_reply.reply_trace = m_in.data;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/* all the other calls are made by the parent fork of the debugger to
|
||||
* control execution of the child
|
||||
/* All the other calls are made by the tracing process to control execution
|
||||
* of the child. For all these calls, the child must be stopped.
|
||||
*/
|
||||
if ((child=find_proc(m_in.pid))==NIL_MPROC || child->mp_parent != who_p)
|
||||
return(ESRCH);
|
||||
if ((child = find_proc(m_in.pid)) == NIL_MPROC) return(ESRCH);
|
||||
if (child->mp_flags & EXITING) return(ESRCH);
|
||||
if (child->mp_tracer != who_p) return(ESRCH);
|
||||
if (!(child->mp_flags & STOPPED)) return(EBUSY);
|
||||
|
||||
if (m_in.request == T_STOP) {
|
||||
if ((r = sys_trace(T_STOP, child->mp_endpoint, 0L, (long *) 0)) != OK)
|
||||
return(r);
|
||||
|
||||
child->mp_flags |= STOPPED;
|
||||
child->mp_sigstatus = 0;
|
||||
|
||||
mp->mp_reply.reply_trace = 0;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/* for calls other than T_STOP, the child must be stopped and the parent
|
||||
* must have waited for it
|
||||
*/
|
||||
if (!(child->mp_flags & STOPPED) || child->mp_sigstatus > 0)
|
||||
return(ESRCH);
|
||||
|
||||
switch (m_in.request) {
|
||||
switch (req) {
|
||||
case T_EXIT: /* exit */
|
||||
child->mp_flags |= TRACE_EXIT;
|
||||
|
||||
/* Defer the exit if the traced process has an FS call pending. */
|
||||
if (child->mp_fs_call != PM_IDLE || child->mp_fs_call2 != PM_IDLE)
|
||||
if (child->mp_flags & FS_CALL)
|
||||
child->mp_exitstatus = (int) m_in.data; /* save for later */
|
||||
else
|
||||
exit_proc(child, (int) m_in.data, FALSE /*dump_core*/);
|
||||
|
@ -123,41 +147,72 @@ PUBLIC int do_trace()
|
|||
/* Do not reply to the caller until FS has processed the exit
|
||||
* request.
|
||||
*/
|
||||
return SUSPEND;
|
||||
case T_RESUME:
|
||||
case T_STEP: /* resume execution */
|
||||
if (m_in.data < 0 || m_in.data > _NSIG) return(EIO);
|
||||
if (m_in.data > 0) { /* issue signal */
|
||||
child->mp_flags &= ~TRACED; /* so signal is not diverted */
|
||||
sig_proc(child, (int) m_in.data);
|
||||
child->mp_flags |= TRACED;
|
||||
return(SUSPEND);
|
||||
|
||||
case T_SETOPT: /* set trace options */
|
||||
child->mp_trace_flags = m_in.data;
|
||||
|
||||
mp->mp_reply.reply_trace = 0;
|
||||
return(OK);
|
||||
|
||||
case T_DETACH: /* detach from traced process */
|
||||
if (m_in.data < 0 || m_in.data >= _NSIG) return(EINVAL);
|
||||
|
||||
child->mp_tracer = NO_TRACER;
|
||||
|
||||
/* Let all tracer-pending signals through the filter. */
|
||||
for (i = 1; i < _NSIG; i++) {
|
||||
if (sigismember(&child->mp_sigtrace, i)) {
|
||||
sigdelset(&child->mp_sigtrace, i);
|
||||
check_sig(child->mp_pid, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_in.data > 0) { /* issue signal */
|
||||
sig_proc(child, (int) m_in.data, TRUE /*trace*/);
|
||||
}
|
||||
|
||||
/* Resume the child as if nothing ever happened. */
|
||||
child->mp_flags &= ~STOPPED;
|
||||
child->mp_trace_flags = 0;
|
||||
req = T_RESUME;
|
||||
|
||||
check_pending(child);
|
||||
|
||||
break;
|
||||
|
||||
case T_RESUME:
|
||||
case T_STEP:
|
||||
case T_SYSCALL: /* resume execution */
|
||||
if (m_in.data < 0 || m_in.data >= _NSIG) return(EINVAL);
|
||||
|
||||
if (m_in.data > 0) { /* issue signal */
|
||||
sig_proc(child, (int) m_in.data, FALSE /*trace*/);
|
||||
}
|
||||
|
||||
/* If there are any other signals waiting to be delivered,
|
||||
* feign a successful resumption.
|
||||
*/
|
||||
for (i = 1; i < _NSIG; i++) {
|
||||
if (sigismember(&child->mp_sigtrace, i)) {
|
||||
mp->mp_reply.reply_trace = 0;
|
||||
return(OK);
|
||||
}
|
||||
}
|
||||
|
||||
child->mp_flags &= ~STOPPED;
|
||||
|
||||
check_pending(child);
|
||||
|
||||
break;
|
||||
}
|
||||
r= sys_trace(m_in.request,child->mp_endpoint,m_in.PMTRACE_ADDR,&m_in.data);
|
||||
r = sys_trace(req, child->mp_endpoint, m_in.PMTRACE_ADDR, &m_in.data);
|
||||
if (r != OK) return(r);
|
||||
|
||||
mp->mp_reply.reply_trace = m_in.data;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* find_proc *
|
||||
*===========================================================================*/
|
||||
PRIVATE struct mproc *find_proc(lpid)
|
||||
pid_t lpid;
|
||||
{
|
||||
register struct mproc *rmp;
|
||||
|
||||
for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++)
|
||||
if ((rmp->mp_flags & (IN_USE | EXITING)) == IN_USE &&
|
||||
rmp->mp_pid == lpid) {
|
||||
return(rmp);
|
||||
}
|
||||
return(NIL_MPROC);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* stop_proc *
|
||||
*===========================================================================*/
|
||||
|
@ -167,19 +222,18 @@ int signo;
|
|||
{
|
||||
/* A traced process got a signal so stop it. */
|
||||
|
||||
register struct mproc *rpmp = mproc + rmp->mp_parent;
|
||||
register struct mproc *rpmp = mproc + rmp->mp_tracer;
|
||||
int r;
|
||||
|
||||
r = sys_trace(T_STOP, rmp->mp_endpoint, 0L, (long *) 0);
|
||||
if (r != OK) panic("pm", "sys_trace failed", r);
|
||||
|
||||
rmp->mp_flags |= STOPPED;
|
||||
if (rpmp->mp_flags & WAITING) {
|
||||
if (wait_test(rpmp, rmp)) {
|
||||
sigdelset(&rmp->mp_sigtrace, signo);
|
||||
|
||||
rpmp->mp_flags &= ~WAITING; /* parent is no longer waiting */
|
||||
rpmp->mp_reply.reply_res2 = 0177 | (signo << 8);
|
||||
setreply(rmp->mp_parent, rmp->mp_pid);
|
||||
} else {
|
||||
rmp->mp_sigstatus = signo;
|
||||
setreply(rmp->mp_tracer, rmp->mp_pid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
/* This file contains some utility routines for PM.
|
||||
*
|
||||
* The entry points are:
|
||||
* find_param: look up a boot monitor parameter
|
||||
* get_free_pid: get a free process or group id
|
||||
* no_sys: called for invalid system call numbers
|
||||
* proc_from_pid: return process pointer from pid number
|
||||
* find_param: look up a boot monitor parameter
|
||||
* find_proc: return process pointer from pid number
|
||||
* pm_isokendpt: check the validity of an endpoint
|
||||
* tell_fs: send a request to FS on behalf of a process
|
||||
*/
|
||||
|
||||
#include "pm.h"
|
||||
|
@ -88,18 +89,18 @@ const char *name;
|
|||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* proc_from_pid *
|
||||
* find_proc *
|
||||
*===========================================================================*/
|
||||
PUBLIC int proc_from_pid(mp_pid)
|
||||
pid_t mp_pid;
|
||||
PUBLIC struct mproc *find_proc(lpid)
|
||||
pid_t lpid;
|
||||
{
|
||||
int rmp;
|
||||
register struct mproc *rmp;
|
||||
|
||||
for (rmp = 0; rmp < NR_PROCS; rmp++)
|
||||
if (mproc[rmp].mp_pid == mp_pid)
|
||||
return rmp;
|
||||
for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++)
|
||||
if ((rmp->mp_flags & IN_USE) && rmp->mp_pid == lpid)
|
||||
return(rmp);
|
||||
|
||||
return -1;
|
||||
return(NIL_MPROC);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -117,6 +118,27 @@ PUBLIC int pm_isokendpt(int endpoint, int *proc)
|
|||
return OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* tell_fs *
|
||||
*===========================================================================*/
|
||||
PUBLIC void tell_fs(rmp, m_ptr)
|
||||
struct mproc *rmp;
|
||||
message *m_ptr;
|
||||
{
|
||||
/* Send a request to VFS, without blocking.
|
||||
*/
|
||||
int r;
|
||||
|
||||
if (rmp->mp_flags & FS_CALL)
|
||||
panic(__FILE__, "tell_fs: not idle", m_ptr->m_type);
|
||||
|
||||
r = asynsend3(FS_PROC_NR, m_ptr, AMF_NOREPLY);
|
||||
if (r != OK)
|
||||
panic(__FILE__, "unable to send to FS", r);
|
||||
|
||||
rmp->mp_flags |= FS_CALL;
|
||||
}
|
||||
|
||||
int unmap_ok = 0;
|
||||
|
||||
PUBLIC int munmap(void *addrstart, vir_bytes len)
|
||||
|
|
|
@ -897,6 +897,19 @@ endpoint_t *endpoint;
|
|||
printf("RS: start_service: ds_publish_u32 done: %s -> %d\n",
|
||||
rp->r_label, child_proc_nr_e);
|
||||
|
||||
/* The purpose of non-blocking forks is to avoid involving VFS in the forking
|
||||
* process, because VFS may be blocked on a sendrec() to a MFS that is
|
||||
* waiting for a endpoint update for a dead driver. We have just published
|
||||
* that update, but VFS may still be blocked. As a result, VFS may not yet
|
||||
* have received PM's fork message. Hence, if we call mapdriver5()
|
||||
* immediately, VFS may not know about the process and thus refuse to add the
|
||||
* driver entry. The following temporary hack works around this by forcing
|
||||
* blocking communication from PM to VFS. Once VFS has been made non-blocking
|
||||
* towards MFS instances, this hack and the entire fork_nb() call can go.
|
||||
*/
|
||||
if (use_copy)
|
||||
setuid(0);
|
||||
|
||||
if (rp->r_dev_nr > 0) { /* set driver map */
|
||||
if ((s=mapdriver5(rp->r_label, strlen(rp->r_label),
|
||||
rp->r_dev_nr, rp->r_dev_style, !!use_copy /* force */)) < 0) {
|
||||
|
|
|
@ -69,9 +69,6 @@ PUBLIC int main(void)
|
|||
SANITYCHECK;
|
||||
get_work(); /* sets who and call_nr */
|
||||
|
||||
if (who_e == PM_PROC_NR && call_nr != PROC_EVENT)
|
||||
printf("FS: strange, got message %d from PM\n", call_nr);
|
||||
|
||||
if (call_nr == DEV_REVIVE)
|
||||
{
|
||||
endpoint_t endpt;
|
||||
|
@ -114,8 +111,7 @@ PUBLIC int main(void)
|
|||
if (is_notify(call_nr)) {
|
||||
if (who_p == PM_PROC_NR)
|
||||
{
|
||||
/* PM tries to get FS to do something */
|
||||
service_pm();
|
||||
/* Signaled by PM, ignore. */
|
||||
}
|
||||
else if (who_p == CLOCK)
|
||||
{
|
||||
|
@ -152,6 +148,13 @@ PUBLIC int main(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Calls from PM. */
|
||||
if (who_e == PM_PROC_NR) {
|
||||
service_pm();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Calls from VM. */
|
||||
if(who_e == VM_PROC_NR) {
|
||||
int caught = 1;
|
||||
|
@ -502,112 +505,96 @@ PRIVATE void init_root()
|
|||
*===========================================================================*/
|
||||
PRIVATE void service_pm()
|
||||
{
|
||||
int r, call;
|
||||
message m;
|
||||
int r;
|
||||
|
||||
/* Ask PM for work until there is nothing left to do */
|
||||
for (;;)
|
||||
{
|
||||
m.m_type= PM_GET_WORK;
|
||||
r= sendrec(PM_PROC_NR, &m);
|
||||
if (r != OK)
|
||||
{
|
||||
panic("VFS", "service_pm: sendrec failed", r);
|
||||
}
|
||||
if (m.m_type == PM_IDLE) {
|
||||
break;
|
||||
}
|
||||
call= m.m_type;
|
||||
switch(call)
|
||||
{
|
||||
case PM_SETSID:
|
||||
pm_setsid(m.PM_SETSID_PROC);
|
||||
switch (call_nr) {
|
||||
case PM_SETUID:
|
||||
pm_setuid(m_in.PM_PROC, m_in.PM_EID, m_in.PM_RID);
|
||||
|
||||
m_out.m_type = PM_SETUID_REPLY;
|
||||
m_out.PM_PROC = m_in.PM_PROC;
|
||||
|
||||
/* No need to report status to PM */
|
||||
break;
|
||||
|
||||
case PM_SETGID:
|
||||
pm_setgid(m.PM_SETGID_PROC, m.PM_SETGID_EGID,
|
||||
m.PM_SETGID_RGID);
|
||||
pm_setgid(m_in.PM_PROC, m_in.PM_EID, m_in.PM_RID);
|
||||
|
||||
m_out.m_type = PM_SETGID_REPLY;
|
||||
m_out.PM_PROC = m_in.PM_PROC;
|
||||
|
||||
/* No need to report status to PM */
|
||||
break;
|
||||
|
||||
case PM_SETUID:
|
||||
pm_setuid(m.PM_SETUID_PROC, m.PM_SETUID_EGID,
|
||||
m.PM_SETUID_RGID);
|
||||
case PM_SETSID:
|
||||
pm_setsid(m_in.PM_PROC);
|
||||
|
||||
m_out.m_type = PM_SETSID_REPLY;
|
||||
m_out.PM_PROC = m_in.PM_PROC;
|
||||
|
||||
/* No need to report status to PM */
|
||||
break;
|
||||
|
||||
case PM_FORK:
|
||||
pm_fork(m.PM_FORK_PPROC, m.PM_FORK_CPROC,
|
||||
m.PM_FORK_CPID);
|
||||
case PM_EXEC:
|
||||
r = pm_exec(m_in.PM_PROC, m_in.PM_PATH, m_in.PM_PATH_LEN,
|
||||
m_in.PM_FRAME, m_in.PM_FRAME_LEN);
|
||||
|
||||
/* Reply status to PM */
|
||||
m_out.m_type = PM_EXEC_REPLY;
|
||||
m_out.PM_PROC = m_in.PM_PROC;
|
||||
m_out.PM_STATUS = r;
|
||||
|
||||
/* No need to report status to PM */
|
||||
break;
|
||||
|
||||
case PM_EXIT:
|
||||
pm_exit(m.PM_EXIT_PROC);
|
||||
pm_exit(m_in.PM_PROC);
|
||||
|
||||
/* Reply dummy status to PM for synchronization */
|
||||
m.m_type= PM_EXIT_REPLY;
|
||||
/* Keep m.PM_EXIT_PROC */
|
||||
m_out.m_type = PM_EXIT_REPLY;
|
||||
m_out.PM_PROC = m_in.PM_PROC;
|
||||
|
||||
break;
|
||||
|
||||
case PM_DUMPCORE:
|
||||
r = pm_dumpcore(m_in.PM_PROC,
|
||||
NULL /* (struct mem_map *) m_in.PM_SEGPTR */);
|
||||
|
||||
/* Reply status to PM */
|
||||
m_out.m_type = PM_CORE_REPLY;
|
||||
m_out.PM_PROC = m_in.PM_PROC;
|
||||
m_out.PM_STATUS = r;
|
||||
|
||||
break;
|
||||
|
||||
case PM_FORK:
|
||||
case PM_FORK_NB:
|
||||
pm_fork(m_in.PM_PPROC, m_in.PM_PROC, m_in.PM_CPID);
|
||||
|
||||
m_out.m_type = (call_nr == PM_FORK) ? PM_FORK_REPLY : PM_FORK_NB_REPLY;
|
||||
m_out.PM_PROC = m_in.PM_PROC;
|
||||
|
||||
r= send(PM_PROC_NR, &m);
|
||||
if (r != OK)
|
||||
panic(__FILE__, "service_pm: send failed", r);
|
||||
break;
|
||||
|
||||
case PM_UNPAUSE:
|
||||
case PM_UNPAUSE_TR:
|
||||
unpause(m.PM_UNPAUSE_PROC);
|
||||
unpause(m_in.PM_PROC);
|
||||
|
||||
m_out.m_type = PM_UNPAUSE_REPLY;
|
||||
m_out.PM_PROC = m_in.PM_PROC;
|
||||
|
||||
/* No need to report status to PM */
|
||||
break;
|
||||
|
||||
case PM_REBOOT:
|
||||
pm_reboot();
|
||||
|
||||
/* Reply dummy status to PM for synchronization */
|
||||
m.m_type= PM_REBOOT_REPLY;
|
||||
r= send(PM_PROC_NR, &m);
|
||||
if (r != OK)
|
||||
panic(__FILE__, "service_pm: send failed", r);
|
||||
break;
|
||||
m_out.m_type = PM_REBOOT_REPLY;
|
||||
|
||||
case PM_EXEC:
|
||||
r= pm_exec(m.PM_EXEC_PROC, m.PM_EXEC_PATH,
|
||||
m.PM_EXEC_PATH_LEN, m.PM_EXEC_FRAME,
|
||||
m.PM_EXEC_FRAME_LEN);
|
||||
|
||||
/* Reply status to PM */
|
||||
m.m_type= PM_EXEC_REPLY;
|
||||
/* Keep m.PM_EXEC_PROC */
|
||||
m.PM_EXEC_STATUS= r;
|
||||
|
||||
r= send(PM_PROC_NR, &m);
|
||||
if (r != OK)
|
||||
panic(__FILE__, "service_pm: send failed", r);
|
||||
break;
|
||||
|
||||
case PM_DUMPCORE:
|
||||
r= pm_dumpcore(m.PM_CORE_PROC,
|
||||
(struct mem_map *)m.PM_CORE_SEGPTR);
|
||||
|
||||
/* Reply status to PM */
|
||||
m.m_type= PM_CORE_REPLY;
|
||||
/* Keep m.PM_CORE_PROC */
|
||||
m.PM_CORE_STATUS= r;
|
||||
|
||||
r= send(PM_PROC_NR, &m);
|
||||
if (r != OK)
|
||||
panic(__FILE__, "service_pm: send failed", r);
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("VFS", "service_pm: unknown call", m.m_type);
|
||||
}
|
||||
}
|
||||
printf("VFS: don't know how to handle PM request %x\n", call_nr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
r = send(PM_PROC_NR, &m_out);
|
||||
if (r != OK)
|
||||
panic(__FILE__, "service_pm: send failed", r);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ OBJ= test1 test2 test3 test4 test5 test6 test7 test8 test9 \
|
|||
test10 test12 test13 test14 test15 test16 test17 test18 test19 \
|
||||
test21 test22 test23 test25 test26 test27 test28 test29 \
|
||||
test30 test31 test32 test34 test35 test36 test37 test38 \
|
||||
test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41
|
||||
test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41 \
|
||||
test42
|
||||
|
||||
BIGOBJ= test20 test24
|
||||
ROOTOBJ= test11 test33
|
||||
|
@ -81,3 +82,4 @@ t40d: t40d.c
|
|||
t40e: t40e.c
|
||||
t40f: t40f.c
|
||||
test41: test41.c
|
||||
test42: test42.c
|
||||
|
|
4
test/run
4
test/run
|
@ -12,13 +12,13 @@ badones= # list of tests that failed
|
|||
|
||||
# Print test welcome message
|
||||
clr
|
||||
echo "Running POSIX compliance test suite. There are 43 tests in total."
|
||||
echo "Running POSIX compliance test suite. There are 44 tests in total."
|
||||
echo " "
|
||||
|
||||
# Run all the tests, keeping track of who failed.
|
||||
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||
41 sh1.sh sh2.sh
|
||||
41 42 sh1.sh sh2.sh
|
||||
do total=`expr $total + 1`
|
||||
FAIL=0
|
||||
if [ $USER = root -a \( $i = 11 -o $i = 33 \) ]
|
||||
|
|
1349
test/test42.c
Normal file
1349
test/test42.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue