PM: fix ptrace(T_EXIT) 'exit_proc: not idle' race condition.
This commit is contained in:
parent
14f3a0e018
commit
1a9e07b0e5
|
@ -711,9 +711,6 @@
|
||||||
#define PM_CORE_PROC m1_i1
|
#define PM_CORE_PROC m1_i1
|
||||||
#define PM_CORE_SEGPTR m1_p1
|
#define PM_CORE_SEGPTR m1_p1
|
||||||
#define PM_UNPAUSE_TR (PM_BASE + 15) /* interrupted process (for tracing) */
|
#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 */
|
/* Replies */
|
||||||
#define PM_EXIT_REPLY (PM_BASE + 20) /* Reply from FS */
|
#define PM_EXIT_REPLY (PM_BASE + 20) /* Reply from FS */
|
||||||
|
@ -724,7 +721,6 @@
|
||||||
#define PM_CORE_REPLY (PM_BASE + 23) /* Reply from FS */
|
#define PM_CORE_REPLY (PM_BASE + 23) /* Reply from FS */
|
||||||
/* PM_CORE_PROC m1_i1 */
|
/* PM_CORE_PROC m1_i1 */
|
||||||
#define PM_CORE_STATUS m1_i2 /* OK or failure */
|
#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 */
|
/* 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 */
|
||||||
|
|
|
@ -162,7 +162,7 @@ int result;
|
||||||
|
|
||||||
/* Use SIGILL signal that something went wrong */
|
/* Use SIGILL signal that something went wrong */
|
||||||
rmp->mp_sigstatus = SIGILL;
|
rmp->mp_sigstatus = SIGILL;
|
||||||
exit_proc(rmp, 0, PM_EXIT);
|
exit_proc(rmp, 0, FALSE /*dump_core*/);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setreply(rmp-mproc, result);
|
setreply(rmp-mproc, result);
|
||||||
|
|
|
@ -183,17 +183,17 @@ PUBLIC int do_exit()
|
||||||
/* Perform the exit(status) system call. The real work is done by exit_proc(),
|
/* 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.
|
* 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 */
|
return(SUSPEND); /* can't communicate from beyond the grave */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* exit_proc *
|
* 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 */
|
register struct mproc *rmp; /* pointer to the process to be terminated */
|
||||||
int exit_status; /* the process' exit status (for parent) */
|
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
|
/* A process is done. Release most of the process' possessions. If its
|
||||||
* parent is waiting, release the rest, else keep the process slot and
|
* 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;
|
clock_t user_time, sys_time;
|
||||||
|
|
||||||
/* Do not create core files for set uid execution */
|
/* Do not create core files for set uid execution */
|
||||||
if (exit_type == PM_DUMPCORE && rmp->mp_realuid != rmp->mp_effuid)
|
if (dump_core && rmp->mp_realuid != rmp->mp_effuid)
|
||||||
exit_type = PM_EXIT;
|
dump_core = FALSE;
|
||||||
|
|
||||||
/* System processes are destroyed before informing FS, meaning that FS can
|
/* 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.
|
* 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))
|
if (dump_core && (rmp->mp_flags & PRIV_PROC))
|
||||||
exit_type = PM_EXIT;
|
dump_core = FALSE;
|
||||||
|
|
||||||
proc_nr = (int) (rmp - mproc); /* get process slot number */
|
proc_nr = (int) (rmp - mproc); /* get process slot number */
|
||||||
proc_nr_e = rmp->mp_endpoint;
|
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. */
|
/* Tell FS about the exiting process. */
|
||||||
if (rmp->mp_fs_call != PM_IDLE)
|
if (rmp->mp_fs_call != PM_IDLE)
|
||||||
panic(__FILE__, "exit_proc: not idle", rmp->mp_fs_call);
|
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);
|
r= notify(FS_PROC_NR);
|
||||||
if (r != OK) panic(__FILE__, "exit_proc: unable to notify FS", r);
|
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 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.
|
* For core dumps, notify the parent only once the core dump has been made.
|
||||||
*/
|
*/
|
||||||
if (exit_type != PM_DUMPCORE)
|
if (!dump_core)
|
||||||
zombify(rmp);
|
zombify(rmp);
|
||||||
|
|
||||||
/* If the process has children, disinherit them. INIT is the new parent. */
|
/* 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 *
|
* 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 */
|
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
|
/* FS replied to our exit or coredump request. Perform the second half of the
|
||||||
* exit code.
|
* exit code.
|
||||||
|
@ -324,7 +324,7 @@ int reply_type; /* one of PM_EXIT_REPLY(_TR), PM_CORE_REPLY */
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* For core dumps, now is the right time to try to contact the parent. */
|
/* 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);
|
zombify(rmp);
|
||||||
|
|
||||||
if (!(rmp->mp_flags & PRIV_PROC))
|
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);
|
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 */
|
/* Wake up the parent, completing the ptrace(T_EXIT) call */
|
||||||
mproc[rmp->mp_parent].mp_reply.reply_trace = 0;
|
mproc[rmp->mp_parent].mp_reply.reply_trace = 0;
|
||||||
|
@ -434,7 +434,7 @@ struct mproc *rmp;
|
||||||
if (rmp->mp_flags & ZOMBIE)
|
if (rmp->mp_flags & 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);
|
rmp->mp_flags &= (IN_USE|PRIV_PROC|EXITING|TRACE_EXIT);
|
||||||
rmp->mp_flags |= ZOMBIE;
|
rmp->mp_flags |= ZOMBIE;
|
||||||
|
|
||||||
p_mp = &mproc[rmp->mp_parent];
|
p_mp = &mproc[rmp->mp_parent];
|
||||||
|
|
|
@ -44,6 +44,7 @@ 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 send_work, (void) );
|
||||||
FORWARD _PROTOTYPE( void handle_fs_reply, (message *m_ptr) );
|
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))
|
||||||
|
@ -91,7 +92,6 @@ PUBLIC int main()
|
||||||
case PM_REBOOT_REPLY:
|
case PM_REBOOT_REPLY:
|
||||||
case PM_EXEC_REPLY:
|
case PM_EXEC_REPLY:
|
||||||
case PM_CORE_REPLY:
|
case PM_CORE_REPLY:
|
||||||
case PM_EXIT_REPLY_TR:
|
|
||||||
if (who_e == FS_PROC_NR)
|
if (who_e == FS_PROC_NR)
|
||||||
{
|
{
|
||||||
handle_fs_reply(&m_in);
|
handle_fs_reply(&m_in);
|
||||||
|
@ -379,9 +379,9 @@ void checkme(char *str, int line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*=========================================================================*
|
/*===========================================================================*
|
||||||
* send_work *
|
* send_work *
|
||||||
*=========================================================================*/
|
*===========================================================================*/
|
||||||
PRIVATE void send_work()
|
PRIVATE void send_work()
|
||||||
{
|
{
|
||||||
int r, call;
|
int r, call;
|
||||||
|
@ -460,7 +460,6 @@ PRIVATE void send_work()
|
||||||
}
|
}
|
||||||
|
|
||||||
case PM_EXIT:
|
case PM_EXIT:
|
||||||
case PM_EXIT_TR:
|
|
||||||
m.m_type= call;
|
m.m_type= call;
|
||||||
m.PM_EXIT_PROC= rmp->mp_endpoint;
|
m.PM_EXIT_PROC= rmp->mp_endpoint;
|
||||||
|
|
||||||
|
@ -552,18 +551,7 @@ PRIVATE void send_work()
|
||||||
}
|
}
|
||||||
if (m.m_type != PM_IDLE)
|
if (m.m_type != PM_IDLE)
|
||||||
{
|
{
|
||||||
if (rmp->mp_fs_call == PM_IDLE &&
|
restart_sigs(rmp);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (report_reboot)
|
else if (report_reboot)
|
||||||
{
|
{
|
||||||
|
@ -574,6 +562,9 @@ PRIVATE void send_work()
|
||||||
if (r != OK) panic("pm", "send_work: send failed", r);
|
if (r != OK) panic("pm", "send_work: send failed", r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* handle_fs_reply *
|
||||||
|
*===========================================================================*/
|
||||||
PRIVATE void handle_fs_reply(m_ptr)
|
PRIVATE void handle_fs_reply(m_ptr)
|
||||||
message *m_ptr;
|
message *m_ptr;
|
||||||
{
|
{
|
||||||
|
@ -583,7 +574,6 @@ message *m_ptr;
|
||||||
switch(m_ptr->m_type)
|
switch(m_ptr->m_type)
|
||||||
{
|
{
|
||||||
case PM_EXIT_REPLY:
|
case PM_EXIT_REPLY:
|
||||||
case PM_EXIT_REPLY_TR:
|
|
||||||
proc_e= m_ptr->PM_EXIT_PROC;
|
proc_e= m_ptr->PM_EXIT_PROC;
|
||||||
if (pm_isokendpt(proc_e, &proc_n) != OK)
|
if (pm_isokendpt(proc_e, &proc_n) != OK)
|
||||||
{
|
{
|
||||||
|
@ -596,7 +586,7 @@ message *m_ptr;
|
||||||
/* Call is finished */
|
/* Call is finished */
|
||||||
rmp->mp_fs_call= PM_IDLE;
|
rmp->mp_fs_call= PM_IDLE;
|
||||||
|
|
||||||
exit_restart(rmp, m_ptr->m_type);
|
exit_restart(rmp, FALSE /*dump_core*/);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -630,20 +620,8 @@ message *m_ptr;
|
||||||
|
|
||||||
exec_restart(rmp, m_ptr->PM_EXEC_STATUS);
|
exec_restart(rmp, m_ptr->PM_EXEC_STATUS);
|
||||||
|
|
||||||
if (rmp->mp_flags & PM_SIG_PENDING)
|
restart_sigs(rmp);
|
||||||
{
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PM_CORE_REPLY:
|
case PM_CORE_REPLY:
|
||||||
|
@ -663,7 +641,7 @@ message *m_ptr;
|
||||||
/* Call is finished */
|
/* Call is finished */
|
||||||
rmp->mp_fs_call= PM_IDLE;
|
rmp->mp_fs_call= PM_IDLE;
|
||||||
|
|
||||||
exit_restart(rmp, m_ptr->m_type);
|
exit_restart(rmp, TRUE /*dump_core*/);
|
||||||
|
|
||||||
break;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -77,6 +77,7 @@ EXTERN struct mproc {
|
||||||
#define PARTIAL_EXEC 0x8000 /* Process got a new map but no content */
|
#define PARTIAL_EXEC 0x8000 /* Process got a new map but no content */
|
||||||
#define TOLD_PARENT 0x10000 /* Parent wait() completed, ZOMBIE off */
|
#define TOLD_PARENT 0x10000 /* Parent wait() completed, ZOMBIE off */
|
||||||
#define EXITING 0x20000 /* set by EXIT, process is now exiting */
|
#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)
|
#define NIL_MPROC ((struct mproc *) 0)
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,8 @@ _PROTOTYPE( int do_fork_nb, (void) );
|
||||||
_PROTOTYPE( int do_exit, (void) );
|
_PROTOTYPE( int do_exit, (void) );
|
||||||
_PROTOTYPE( int do_waitpid, (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 exit_type) );
|
int dump_core) );
|
||||||
_PROTOTYPE( void exit_restart, (struct mproc *rmp, int reply_type) );
|
_PROTOTYPE( void exit_restart, (struct mproc *rmp, int dump_core) );
|
||||||
|
|
||||||
/* getset.c */
|
/* getset.c */
|
||||||
_PROTOTYPE( int do_getset, (void) );
|
_PROTOTYPE( int do_getset, (void) );
|
||||||
|
|
|
@ -421,7 +421,6 @@ int signo; /* signal to send to process (1 to _NSIG) */
|
||||||
int s;
|
int s;
|
||||||
int slot;
|
int slot;
|
||||||
int sigflags;
|
int sigflags;
|
||||||
int exit_type;
|
|
||||||
|
|
||||||
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) {
|
||||||
|
@ -518,14 +517,16 @@ doterminate:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Terminate process */
|
||||||
rmp->mp_sigstatus = (char) signo;
|
rmp->mp_sigstatus = (char) signo;
|
||||||
exit_type = PM_EXIT;
|
|
||||||
if (sigismember(&core_sset, signo) && slot != FS_PROC_NR) {
|
if (sigismember(&core_sset, signo) && slot != FS_PROC_NR) {
|
||||||
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_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 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
|
@ -112,7 +112,14 @@ PUBLIC int do_trace()
|
||||||
|
|
||||||
switch (m_in.request) {
|
switch (m_in.request) {
|
||||||
case T_EXIT: /* exit */
|
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
|
/* Do not reply to the caller until FS has processed the exit
|
||||||
* request.
|
* request.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -533,12 +533,10 @@ PRIVATE void service_pm()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PM_EXIT:
|
case PM_EXIT:
|
||||||
case PM_EXIT_TR:
|
|
||||||
pm_exit(m.PM_EXIT_PROC);
|
pm_exit(m.PM_EXIT_PROC);
|
||||||
|
|
||||||
/* Reply dummy status to PM for synchronization */
|
/* Reply dummy status to PM for synchronization */
|
||||||
m.m_type= (call == PM_EXIT_TR ? PM_EXIT_REPLY_TR :
|
m.m_type= PM_EXIT_REPLY;
|
||||||
PM_EXIT_REPLY);
|
|
||||||
/* Keep m.PM_EXIT_PROC */
|
/* Keep m.PM_EXIT_PROC */
|
||||||
|
|
||||||
r= send(PM_PROC_NR, &m);
|
r= send(PM_PROC_NR, &m);
|
||||||
|
|
Loading…
Reference in a new issue