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