PM: fix ptrace(T_EXIT) 'exit_proc: not idle' race condition.

This commit is contained in:
David van Moolenbroek 2009-07-11 13:22:56 +00:00
parent 14f3a0e018
commit 1a9e07b0e5
9 changed files with 66 additions and 63 deletions

View file

@ -711,9 +711,6 @@
#define PM_CORE_PROC m1_i1
#define PM_CORE_SEGPTR m1_p1
#define PM_UNPAUSE_TR (PM_BASE + 15) /* interrupted process (for tracing) */
#define PM_EXIT_TR (PM_BASE + 16) /* Tell FS about the exiting process
* (for tracing)
*/
/* Replies */
#define PM_EXIT_REPLY (PM_BASE + 20) /* Reply from FS */
@ -724,7 +721,6 @@
#define PM_CORE_REPLY (PM_BASE + 23) /* Reply from FS */
/* PM_CORE_PROC m1_i1 */
#define PM_CORE_STATUS m1_i2 /* OK or failure */
#define PM_EXIT_REPLY_TR (PM_BASE + 24) /* Reply from FS */
/* Parameters for the EXEC_NEWMEM call */
#define EXC_NM_PROC m1_i1 /* process that needs new map */

View file

@ -162,7 +162,7 @@ int result;
/* Use SIGILL signal that something went wrong */
rmp->mp_sigstatus = SIGILL;
exit_proc(rmp, 0, PM_EXIT);
exit_proc(rmp, 0, FALSE /*dump_core*/);
return;
}
setreply(rmp-mproc, result);

View file

@ -183,17 +183,17 @@ PUBLIC int do_exit()
/* Perform the exit(status) system call. The real work is done by exit_proc(),
* which is also called when a process is killed by a signal.
*/
exit_proc(mp, m_in.status, PM_EXIT);
exit_proc(mp, m_in.status, FALSE /*dump_core*/);
return(SUSPEND); /* can't communicate from beyond the grave */
}
/*===========================================================================*
* exit_proc *
*===========================================================================*/
PUBLIC void exit_proc(rmp, exit_status, exit_type)
PUBLIC void exit_proc(rmp, exit_status, dump_core)
register struct mproc *rmp; /* pointer to the process to be terminated */
int exit_status; /* the process' exit status (for parent) */
int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */
int dump_core; /* flag indicating whether to dump core */
{
/* A process is done. Release most of the process' possessions. If its
* parent is waiting, release the rest, else keep the process slot and
@ -206,14 +206,14 @@ int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */
clock_t user_time, sys_time;
/* Do not create core files for set uid execution */
if (exit_type == PM_DUMPCORE && rmp->mp_realuid != rmp->mp_effuid)
exit_type = PM_EXIT;
if (dump_core && rmp->mp_realuid != rmp->mp_effuid)
dump_core = FALSE;
/* System processes are destroyed before informing FS, meaning that FS can
* not get their CPU state, so we can't generate a coredump for them either.
*/
if (exit_type == PM_DUMPCORE && (rmp->mp_flags & PRIV_PROC))
exit_type = PM_EXIT;
if (dump_core && (rmp->mp_flags & PRIV_PROC))
dump_core = FALSE;
proc_nr = (int) (rmp - mproc); /* get process slot number */
proc_nr_e = rmp->mp_endpoint;
@ -254,7 +254,7 @@ int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */
/* Tell FS about the exiting process. */
if (rmp->mp_fs_call != PM_IDLE)
panic(__FILE__, "exit_proc: not idle", rmp->mp_fs_call);
rmp->mp_fs_call= exit_type;
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);
@ -289,7 +289,7 @@ int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */
/* For normal exits, try to notify the parent as soon as possible.
* For core dumps, notify the parent only once the core dump has been made.
*/
if (exit_type != PM_DUMPCORE)
if (!dump_core)
zombify(rmp);
/* If the process has children, disinherit them. INIT is the new parent. */
@ -314,9 +314,9 @@ int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */
/*===========================================================================*
* exit_restart *
*===========================================================================*/
PUBLIC void exit_restart(rmp, reply_type)
PUBLIC void exit_restart(rmp, dump_core)
struct mproc *rmp; /* pointer to the process being terminated */
int reply_type; /* one of PM_EXIT_REPLY(_TR), PM_CORE_REPLY */
int dump_core; /* flag indicating whether to dump core */
{
/* FS replied to our exit or coredump request. Perform the second half of the
* exit code.
@ -324,7 +324,7 @@ int reply_type; /* one of PM_EXIT_REPLY(_TR), PM_CORE_REPLY */
int r;
/* For core dumps, now is the right time to try to contact the parent. */
if (reply_type == PM_CORE_REPLY)
if (dump_core)
zombify(rmp);
if (!(rmp->mp_flags & PRIV_PROC))
@ -339,7 +339,7 @@ int reply_type; /* one of PM_EXIT_REPLY(_TR), PM_CORE_REPLY */
panic(__FILE__, "exit_restart: vm_exit failed", r);
}
if (reply_type == PM_EXIT_REPLY_TR && rmp->mp_parent != INIT_PROC_NR)
if ((rmp->mp_flags & TRACE_EXIT) && rmp->mp_parent != INIT_PROC_NR)
{
/* Wake up the parent, completing the ptrace(T_EXIT) call */
mproc[rmp->mp_parent].mp_reply.reply_trace = 0;
@ -434,7 +434,7 @@ struct mproc *rmp;
if (rmp->mp_flags & ZOMBIE)
panic(__FILE__, "zombify: process was already a zombie", NO_NUM);
rmp->mp_flags &= (IN_USE|PRIV_PROC|EXITING);
rmp->mp_flags &= (IN_USE|PRIV_PROC|EXITING|TRACE_EXIT);
rmp->mp_flags |= ZOMBIE;
p_mp = &mproc[rmp->mp_parent];

View file

@ -44,6 +44,7 @@ FORWARD _PROTOTYPE( void pm_init, (void) );
FORWARD _PROTOTYPE( int get_nice_value, (int queue) );
FORWARD _PROTOTYPE( void send_work, (void) );
FORWARD _PROTOTYPE( void handle_fs_reply, (message *m_ptr) );
FORWARD _PROTOTYPE( void restart_sigs, (struct mproc *rmp) );
#define click_to_round_k(n) \
((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
@ -91,7 +92,6 @@ PUBLIC int main()
case PM_REBOOT_REPLY:
case PM_EXEC_REPLY:
case PM_CORE_REPLY:
case PM_EXIT_REPLY_TR:
if (who_e == FS_PROC_NR)
{
handle_fs_reply(&m_in);
@ -379,9 +379,9 @@ void checkme(char *str, int line)
}
}
/*=========================================================================*
* send_work *
*=========================================================================*/
/*===========================================================================*
* send_work *
*===========================================================================*/
PRIVATE void send_work()
{
int r, call;
@ -460,7 +460,6 @@ PRIVATE void send_work()
}
case PM_EXIT:
case PM_EXIT_TR:
m.m_type= call;
m.PM_EXIT_PROC= rmp->mp_endpoint;
@ -552,18 +551,7 @@ PRIVATE void send_work()
}
if (m.m_type != PM_IDLE)
{
if (rmp->mp_fs_call == PM_IDLE &&
rmp->mp_fs_call2 == PM_IDLE &&
(rmp->mp_flags & PM_SIG_PENDING))
{
rmp->mp_flags &= ~PM_SIG_PENDING;
check_pending(rmp);
if (!(rmp->mp_flags & PM_SIG_PENDING))
{
/* Allow the process to be scheduled */
sys_nice(rmp->mp_endpoint, rmp->mp_nice);
}
}
restart_sigs(rmp);
}
else if (report_reboot)
{
@ -574,6 +562,9 @@ PRIVATE void send_work()
if (r != OK) panic("pm", "send_work: send failed", r);
}
/*===========================================================================*
* handle_fs_reply *
*===========================================================================*/
PRIVATE void handle_fs_reply(m_ptr)
message *m_ptr;
{
@ -583,7 +574,6 @@ message *m_ptr;
switch(m_ptr->m_type)
{
case PM_EXIT_REPLY:
case PM_EXIT_REPLY_TR:
proc_e= m_ptr->PM_EXIT_PROC;
if (pm_isokendpt(proc_e, &proc_n) != OK)
{
@ -596,7 +586,7 @@ message *m_ptr;
/* Call is finished */
rmp->mp_fs_call= PM_IDLE;
exit_restart(rmp, m_ptr->m_type);
exit_restart(rmp, FALSE /*dump_core*/);
break;
@ -630,20 +620,8 @@ message *m_ptr;
exec_restart(rmp, m_ptr->PM_EXEC_STATUS);
if (rmp->mp_flags & PM_SIG_PENDING)
{
printf("handle_fs_reply: restarting signals\n");
rmp->mp_flags &= ~PM_SIG_PENDING;
check_pending(rmp);
if (!(rmp->mp_flags & PM_SIG_PENDING))
{
printf("handle_fs_reply: calling sys_nice\n");
/* Allow the process to be scheduled */
sys_nice(rmp->mp_endpoint, rmp->mp_nice);
}
else
printf("handle_fs_reply: more signals\n");
}
restart_sigs(rmp);
break;
case PM_CORE_REPLY:
@ -663,7 +641,7 @@ message *m_ptr;
/* Call is finished */
rmp->mp_fs_call= PM_IDLE;
exit_restart(rmp, m_ptr->m_type);
exit_restart(rmp, TRUE /*dump_core*/);
break;
}
@ -675,3 +653,25 @@ message *m_ptr;
}
/*===========================================================================*
* restart_sigs *
*===========================================================================*/
PRIVATE void restart_sigs(rmp)
struct mproc *rmp;
{
if (rmp->mp_fs_call != PM_IDLE || rmp->mp_fs_call2 != PM_IDLE)
return;
if (rmp->mp_flags & TRACE_EXIT) {
exit_proc(rmp, rmp->mp_exitstatus, FALSE /*dump_core*/);
}
else if (rmp->mp_flags & PM_SIG_PENDING) {
rmp->mp_flags &= ~PM_SIG_PENDING;
check_pending(rmp);
if (!(rmp->mp_flags & PM_SIG_PENDING)) {
/* Allow the process to be scheduled */
sys_nice(rmp->mp_endpoint, rmp->mp_nice);
}
}
}

View file

@ -77,6 +77,7 @@ EXTERN struct mproc {
#define PARTIAL_EXEC 0x8000 /* Process got a new map but no content */
#define TOLD_PARENT 0x10000 /* Parent wait() completed, ZOMBIE off */
#define EXITING 0x20000 /* set by EXIT, process is now exiting */
#define TRACE_EXIT 0x40000 /* tracer is forcing this process to exit */
#define NIL_MPROC ((struct mproc *) 0)

View file

@ -36,8 +36,8 @@ _PROTOTYPE( int do_fork_nb, (void) );
_PROTOTYPE( int do_exit, (void) );
_PROTOTYPE( int do_waitpid, (void) );
_PROTOTYPE( void exit_proc, (struct mproc *rmp, int exit_status,
int exit_type) );
_PROTOTYPE( void exit_restart, (struct mproc *rmp, int reply_type) );
int dump_core) );
_PROTOTYPE( void exit_restart, (struct mproc *rmp, int dump_core) );
/* getset.c */
_PROTOTYPE( int do_getset, (void) );

View file

@ -421,7 +421,6 @@ int signo; /* signal to send to process (1 to _NSIG) */
int s;
int slot;
int sigflags;
int exit_type;
slot = (int) (rmp - mproc);
if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) {
@ -518,14 +517,16 @@ doterminate:
return;
}
/* Terminate process */
rmp->mp_sigstatus = (char) signo;
exit_type = PM_EXIT;
if (sigismember(&core_sset, signo) && slot != FS_PROC_NR) {
printf("PM: coredump signal %d for %d / %s\n", signo, rmp->mp_pid,
rmp->mp_name);
exit_type = PM_DUMPCORE;
exit_proc(rmp, 0, TRUE /*dump_core*/);
}
else {
exit_proc(rmp, 0, FALSE /*dump_core*/);
}
exit_proc(rmp, 0, exit_type); /* terminate process */
}
/*===========================================================================*

View file

@ -112,7 +112,14 @@ PUBLIC int do_trace()
switch (m_in.request) {
case T_EXIT: /* exit */
exit_proc(child, (int) m_in.data, PM_EXIT_TR);
child->mp_flags |= TRACE_EXIT;
/* Defer the exit if the traced process has an FS call pending. */
if (child->mp_fs_call != PM_IDLE || child->mp_fs_call2 != PM_IDLE)
child->mp_exitstatus = (int) m_in.data; /* save for later */
else
exit_proc(child, (int) m_in.data, FALSE /*dump_core*/);
/* Do not reply to the caller until FS has processed the exit
* request.
*/

View file

@ -533,12 +533,10 @@ PRIVATE void service_pm()
break;
case PM_EXIT:
case PM_EXIT_TR:
pm_exit(m.PM_EXIT_PROC);
/* Reply dummy status to PM for synchronization */
m.m_type= (call == PM_EXIT_TR ? PM_EXIT_REPLY_TR :
PM_EXIT_REPLY);
m.m_type= PM_EXIT_REPLY;
/* Keep m.PM_EXIT_PROC */
r= send(PM_PROC_NR, &m);