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:
David van Moolenbroek 2009-09-30 09:57:22 +00:00
parent 8d9aa1fe4f
commit b423d7b477
70 changed files with 3177 additions and 1446 deletions

View file

@ -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)
{
/* Got ping from RS. Just notify RS */
notify(RS_PROC_NR);
/* 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);

View file

@ -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);

View file

@ -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 */

View file

@ -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);

View file

@ -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);
}
/*===========================================================================*

View file

@ -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 );
}

View file

@ -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. */
}

View file

@ -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) );

View file

@ -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. */
}

View file

@ -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) );

View file

@ -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;

View file

@ -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;

View file

@ -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) );

View file

@ -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);
}
/*****************************************************************************

View file

@ -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)) {

View file

@ -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);

View file

@ -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
* 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) */
/*===========================================================================*
* Messages used between PM and VFS *
*===========================================================================*/
/* 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 */
#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_FRAME m1_p2 /* arguments and environment */
# define PM_FRAME_LEN m1_i3 /* size of frame */
/* 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 */

View file

@ -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

View file

@ -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));

View file

@ -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__); }

View file

@ -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));

View file

@ -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 */

View file

@ -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>

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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);
}

View file

@ -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,14 +80,21 @@ PUBLIC void clock_task()
minix_panic("receive() failed", result);
/* Handle the request. Only clock ticks are expected. */
switch (m.m_type) {
case HARD_INT:
do_clocktick(&m); /* handle clock tick */
break;
default: /* illegal request type */
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);
}
}
}
}

View file

@ -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

View file

@ -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);

View file

@ -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);
}

View file

@ -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,21 +138,76 @@ 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);
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",
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););
vmassert(proc_ptr->p_rts_flags);
vmassert(next_ptr != proc_ptr);
if(delivermsg(proc_ptr) == VMSUSPEND) {
vmassert(next_ptr);
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;
}
}
}
TRACE(VF_SCHEDULING, printf("starting %s / %d\n",
proc_ptr->p_name, proc_ptr->p_endpoint););
@ -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,25 +969,25 @@ 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 */
caller_ptr->p_misc_flags &= ~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

View file

@ -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

View file

@ -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 */

View file

@ -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
/*===========================================================================*

View file

@ -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)

View file

@ -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

View file

@ -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;

View file

@ -27,32 +27,25 @@ 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);
/* The value passed in is currently between PRIO_MIN and PRIO_MAX.
* We have to scale this between MIN_USER_Q and MAX_USER_Q to match
* the kernel's scheduling queues.
*/
new_q = MAX_USER_Q + (pri-PRIO_MIN) * (MIN_USER_Q-MAX_USER_Q+1) /
(PRIO_MAX-PRIO_MIN+1);
if (new_q < MAX_USER_Q) new_q = MAX_USER_Q; /* shouldn't happen */
if (new_q > MIN_USER_Q) new_q = MIN_USER_Q; /* shouldn't happen */
new_q = MAX_USER_Q + (pri-PRIO_MIN) * (MIN_USER_Q-MAX_USER_Q+1) /
(PRIO_MAX-PRIO_MIN+1);
if (new_q < MAX_USER_Q) new_q = MAX_USER_Q; /* shouldn't happen */
if (new_q > MIN_USER_Q) new_q = MIN_USER_Q; /* shouldn't happen */
/* Make sure the process is not running while changing its priority.
* Put the process back in its new queue if it is runnable.
*/
RTS_LOCK_SET(rp, NO_PRIORITY);
rp->p_max_priority = rp->p_priority = new_q;
RTS_LOCK_UNSET(rp, NO_PRIORITY);
/* 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, SYS_LOCK);
rp->p_max_priority = rp->p_priority = new_q;
RTS_LOCK_UNSET(rp, SYS_LOCK);
return(OK);
}
return(EINVAL);
return(OK);
}
#endif /* USE_NICE */

68
kernel/system/do_runctl.c Normal file
View 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 */

View file

@ -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");

View file

@ -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,10 +104,22 @@ 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);
m_ptr->CTL_DATA = *(long *) ((char *) rp + (int) tr_addr);
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 */
@ -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);
}

View file

@ -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)

View file

@ -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

View file

@ -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
View 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));
}

View file

@ -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;

View file

@ -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.
*/

View file

@ -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
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).
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
.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
.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.
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
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.
When the traced process performs a successful
.BR execve (2)
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
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.
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
To forestall possible fraud,
.B ptrace
inhibits the set-user-id and set-group-id facilities
on subsequent
.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.
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
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.
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>

View file

@ -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 $
*/

View file

@ -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' : '-';

View file

@ -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,14 +49,14 @@ 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("%2d(%2d) %2d(%2d) ",
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 ",
mp->mp_nice, flags_str(mp->mp_flags));

View file

@ -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)

View file

@ -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);
}

View file

@ -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,39 +284,34 @@ 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)
{
/* 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);
if (rmp->mp_flags & PRIV_PROC)
{
/* Destroy system processes without waiting for FS. This is
* needed because the system process might be a block device
* driver that FS is blocked waiting on.
*/
if((r= sys_exit(rmp->mp_endpoint)) != OK)
panic(__FILE__, "exit_proc: sys_exit failed", r);
}
}
else
{
panic(__FILE__, "pm_exit: FS died", r);
panic(__FILE__, "exit_proc: 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.
/* Tell FS about the exiting process. */
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)
{
/* Destroy system processes without waiting for FS. This is
* needed because the system process might be a block device
* driver that FS is blocked waiting on.
*/
if((r= sys_exit(rmp->mp_endpoint)) != OK)
panic(__FILE__, "exit_proc: sys_exit failed", r);
}
/* 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) {
/* 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 */
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;
children++; /* this child is acceptable */
/* The value of pidarg determines which children qualify. */
if (pidarg > 0 && pidarg != rp->mp_pid) continue;
if (pidarg < -1 && -pidarg != rp->mp_procgrp) continue;
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);
rmp->mp_flags |= ZOMBIE;
/* 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;
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);
t_mp = &mproc[rmp->mp_tracer];
if (parent_waiting && right_child)
tell_parent(rmp); /* tell parent */
else
sig_proc(p_mp, SIGCHLD); /* send parent a "child died" signal */
/* Do not bother sending SIGCHLD signals to tracers. */
if (!wait_test(t_mp, rmp))
return;
tell_tracer(rmp);
}
else {
rmp->mp_flags |= ZOMBIE;
}
/* No tracer, or tracer is parent, or tracer has now been notified. */
check_parent(rmp, FALSE /*try_cleanup*/);
}
/*===========================================================================*
* 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 *
*===========================================================================*/

View file

@ -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);
}

View file

@ -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];

View file

@ -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,299 +400,109 @@ 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;
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];
/* 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;
/* Call is finished */
rmp->mp_fs_call= PM_IDLE;
/* Ask the kernel to abort. All system services, including
* the PM, will get a HARD_STOP notification. Await the
* notification in the main loop.
*/
code_addr = (vir_bytes) monitor_code;
code_size = strlen(monitor_code) + 1;
sys_abort(abort_flag, PM_PROC_NR, code_addr, code_size);
exit_restart(rmp, FALSE /*dump_core*/);
return;
}
break;
/* Get the process associated with this call */
proc_e = m_in.PM_PROC;
case PM_REBOOT_REPLY:
{
vir_bytes code_addr;
size_t code_size;
if (pm_isokendpt(proc_e, &proc_n) != OK) {
panic(__FILE__, "handle_fs_reply: got bad endpoint from FS", proc_e);
}
/* Ask the kernel to abort. All system services, including
* the PM, will get a HARD_STOP notification. Await the
* notification in the main loop.
*/
code_addr = (vir_bytes) monitor_code;
code_size = strlen(monitor_code) + 1;
sys_abort(abort_flag, PM_PROC_NR, code_addr, code_size);
break;
}
rmp = &mproc[proc_n];
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);
}
rmp= &mproc[proc_n];
/* 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);
/* Call is finished */
rmp->mp_fs_call= PM_IDLE;
rmp->mp_flags &= ~FS_CALL;
exec_restart(rmp, m_ptr->PM_EXEC_STATUS);
if (rmp->mp_flags & UNPAUSED)
panic(__FILE__, "handle_fs_reply: UNPAUSED set on entry", call_nr);
restart_sigs(rmp);
/* 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;
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];
case PM_SETSID_REPLY:
/* Wake up the original caller */
setreply(rmp-mproc, rmp->mp_procgrp);
if (m_ptr->PM_CORE_STATUS == OK)
rmp->mp_sigstatus |= DUMPED;
break;
/* Call is finished */
rmp->mp_fs_call= PM_IDLE;
case PM_EXEC_REPLY:
exec_restart(rmp, m_in.PM_STATUS);
exit_restart(rmp, TRUE /*dump_core*/);
break;
break;
}
default:
panic(__FILE__, "handle_fs_reply: unknown reply type",
m_ptr->m_type);
break;
}
case PM_EXIT_REPLY:
exit_restart(rmp, FALSE /*dump_core*/);
}
/*===========================================================================*
* 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);
}
}
break;
case PM_CORE_REPLY:
if (m_in.PM_STATUS == OK)
rmp->mp_sigstatus |= DUMPED;
exit_restart(rmp, TRUE /*dump_core*/);
break;
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);
}
/* Now that the process is idle again, look at pending signals */
if ((rmp->mp_flags & (IN_USE | EXITING)) == IN_USE)
restart_sigs(rmp);
}

View file

@ -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,14 +316,12 @@ 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)) {
mp->mp_reply.PM_ENDPT = rmp->mp_endpoint;
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);
printf("PM: pid result: %d\n", rmp->mp_endpoint);
#endif
return(OK);
}
return(OK);
}
return(ESRCH);
} else if (m_in.namelen > 0) { /* lookup process by name */
@ -393,6 +384,7 @@ PUBLIC int do_getpuid()
*===========================================================================*/
PUBLIC int do_reboot()
{
message m;
int r;
/* Check permission to abort the system. */
@ -419,12 +411,13 @@ 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 */
/* Tell FS to reboot */
m.m_type = PM_REBOOT;
tell_fs(&mproc[FS_PROC_NR], &m);
report_reboot= 1;
r= notify(FS_PROC_NR);
if (r != OK) panic("pm", "do_reboot: unable to notify FS", r);
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);
}
/*===========================================================================*

View file

@ -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)

View file

@ -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,31 +58,24 @@ _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) );
_PROTOTYPE( int do_sprofile, (void) );
_PROTOTYPE( int do_cprofile, (void) );
/* signal.c */
_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) );
@ -101,9 +85,9 @@ _PROTOTYPE( int do_gettimeofday, (void) );
/* timers.c */
_PROTOTYPE( void pm_set_timer, (timer_t *tp, int delta,
tmr_func_t watchdog, int arg));
_PROTOTYPE( void pm_expire_timers, (clock_t now));
_PROTOTYPE( void pm_cancel_timer, (timer_t *tp));
tmr_func_t watchdog, int arg) );
_PROTOTYPE( void pm_expire_timers, (clock_t now) );
_PROTOTYPE( void pm_cancel_timer, (timer_t *tp) );
/* trace.c */
_PROTOTYPE( int do_trace, (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( int pm_isokendpt, (int ep, int *proc));
_PROTOTYPE( char *find_param, (const char *key) );
_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) );

View file

@ -5,17 +5,18 @@
* can be signaled. The actual signaling is done by sig_proc().
*
* The entry points into this file are:
* do_sigaction: perform the SIGACTION system call
* do_sigpending: perform the SIGPENDING system call
* do_sigprocmask: perform the SIGPROCMASK system call
* do_sigreturn: perform the SIGRETURN system call
* do_sigsuspend: perform the SIGSUSPEND system call
* do_kill: perform the KILL system call
* do_pause: perform the PAUSE system call
* ksig_pending: the kernel notified about pending signals
* 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
* do_sigaction: perform the SIGACTION system call
* do_sigpending: perform the SIGPENDING system call
* do_sigprocmask: perform the SIGPROCMASK system call
* do_sigreturn: perform the SIGRETURN system call
* do_sigsuspend: perform the SIGSUSPEND system call
* do_kill: perform the KILL system call
* do_pause: perform the PAUSE system call
* ksig_pending: the kernel notified about pending signals
* 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,111 +351,99 @@ 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)
{
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;
}
if (rmp->mp_flags & FS_CALL) {
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*/);
stop_proc(rmp, signo); /* a signal causes it to stop */
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;
}
/* Some signals are ignored by default. */
if (sigismember(&rmp->mp_ignore, signo)) {
return;
/* Signal should be ignored. */
return;
}
if (sigismember(&rmp->mp_sigmask, signo)) {
/* Signal should be blocked. */
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;
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,12 +535,47 @@ 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);
break;
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);
}
}
}
@ -560,9 +583,8 @@ register struct mproc *rmp;
/*===========================================================================*
* 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)
{
/* 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;
}
}
else
{
if (rmp->mp_fs_call2 != PM_IDLE)
panic( __FILE__, "unpause: not idle", rmp->mp_fs_call2);
rmp->mp_fs_call2= PM_UNPAUSE;
}
r= notify(FS_PROC_NR);
if (r != OK) panic("pm", "unpause: unable to notify FS", r);
}

View file

@ -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) */

View file

@ -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 */
@ -75,47 +114,32 @@ PUBLIC int do_trace()
/* Make sure the text segment is not used as a source for shared
* text.
*/
child->mp_ino= 0;
child->mp_dev= 0;
child->mp_ctime= 0;
child->mp_ino = 0;
child->mp_dev = 0;
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;
break;
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);
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;
}

View file

@ -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)

View file

@ -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) {

View file

@ -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);
/* No need to report status to PM */
break;
m_out.m_type = PM_SETUID_REPLY;
m_out.PM_PROC = m_in.PM_PROC;
case PM_SETGID:
pm_setgid(m.PM_SETGID_PROC, m.PM_SETGID_EGID,
m.PM_SETGID_RGID);
break;
/* No need to report status to PM */
break;
case PM_SETGID:
pm_setgid(m_in.PM_PROC, m_in.PM_EID, m_in.PM_RID);
case PM_SETUID:
pm_setuid(m.PM_SETUID_PROC, m.PM_SETUID_EGID,
m.PM_SETUID_RGID);
m_out.m_type = PM_SETGID_REPLY;
m_out.PM_PROC = m_in.PM_PROC;
/* No need to report status to PM */
break;
break;
case PM_FORK:
pm_fork(m.PM_FORK_PPROC, m.PM_FORK_CPROC,
m.PM_FORK_CPID);
case PM_SETSID:
pm_setsid(m_in.PM_PROC);
/* No need to report status to PM */
break;
m_out.m_type = PM_SETSID_REPLY;
m_out.PM_PROC = m_in.PM_PROC;
case PM_EXIT:
pm_exit(m.PM_EXIT_PROC);
break;
/* Reply dummy status to PM for synchronization */
m.m_type= PM_EXIT_REPLY;
/* Keep m.PM_EXIT_PROC */
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);
r= send(PM_PROC_NR, &m);
if (r != OK)
panic(__FILE__, "service_pm: send failed", r);
break;
/* Reply status to PM */
m_out.m_type = PM_EXEC_REPLY;
m_out.PM_PROC = m_in.PM_PROC;
m_out.PM_STATUS = r;
case PM_UNPAUSE:
case PM_UNPAUSE_TR:
unpause(m.PM_UNPAUSE_PROC);
break;
/* No need to report status to PM */
break;
case PM_EXIT:
pm_exit(m_in.PM_PROC);
case PM_REBOOT:
pm_reboot();
/* Reply dummy status to PM for synchronization */
m_out.m_type = PM_EXIT_REPLY;
m_out.PM_PROC = m_in.PM_PROC;
/* 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;
break;
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);
case PM_DUMPCORE:
r = pm_dumpcore(m_in.PM_PROC,
NULL /* (struct mem_map *) m_in.PM_SEGPTR */);
/* 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;
/* 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_DUMPCORE:
r= pm_dumpcore(m.PM_CORE_PROC,
(struct mem_map *)m.PM_CORE_SEGPTR);
case PM_FORK:
case PM_FORK_NB:
pm_fork(m_in.PM_PPROC, m_in.PM_PROC, m_in.PM_CPID);
/* 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;
m_out.m_type = (call_nr == PM_FORK) ? PM_FORK_REPLY : PM_FORK_NB_REPLY;
m_out.PM_PROC = m_in.PM_PROC;
default:
panic("VFS", "service_pm: unknown call", m.m_type);
}
}
break;
case PM_UNPAUSE:
unpause(m_in.PM_PROC);
m_out.m_type = PM_UNPAUSE_REPLY;
m_out.PM_PROC = m_in.PM_PROC;
break;
case PM_REBOOT:
pm_reboot();
/* Reply dummy status to PM for synchronization */
m_out.m_type = PM_REBOOT_REPLY;
break;
default:
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);
}

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff