2002-12-21 Roland McGrath <roland@redhat.com>

* syscall.c (force_result): New function.
	* process.c (internal_wait): Handle ECHILD exit from wait call with
	WNOHANG flag set; force the return value to 0 in the inferior when it
	has live children we are tracing.
This commit is contained in:
Roland McGrath 2002-12-21 23:25:18 +00:00
parent f57204d839
commit b69f81b8e5
2 changed files with 190 additions and 5 deletions

View File

@ -1592,14 +1592,35 @@ int
internal_wait(tcp)
struct tcb *tcp;
{
if (entering(tcp)) {
/* WTA: fix bug with hanging children */
if (!(tcp->u_arg[2] & WNOHANG) && tcp->nchildren > 0) {
if (entering(tcp) && tcp->nchildren > 0) {
/* There are children that this parent should block for.
But ptrace made us the parent of the traced children
and the real parent will get ECHILD from the wait call.
XXX If we attached with strace -f -p PID, then there
may be untraced dead children the parent could be reaping
now, but we make him block. */
/* ??? WTA: fix bug with hanging children */
if (!(tcp->u_arg[2] & WNOHANG)) {
/* There are traced children */
tcp->flags |= TCB_SUSPENDED;
tcp->waitpid = tcp->u_arg[0];
}
}
if (exiting(tcp) && tcp->u_error == ECHILD && tcp->nchildren > 0) {
if (tcp->u_arg[2] & WNOHANG) {
/* We must force a fake result of 0 instead of
the ECHILD error. */
extern int force_result();
return force_result(tcp, 0, 0);
}
else
fprintf(stderr,
"internal_wait: should not have resumed %d\n",
tcp->pid);
}
return 0;
}

168
syscall.c
View File

@ -1444,6 +1444,172 @@ struct tcb *tcp;
return 1;
}
int
force_result(tcp, error, rval)
struct tcb *tcp;
int error;
long rval;
{
#ifdef LINUX
#if defined(S390) || defined(S390X)
gpr2 = error ? -error : rval;
if (upeek(pid, PT_GPR2, &gpr2) < 0)
return -1;
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)PT_GPR2, gpr2) < 0)
return -1;
#else /* !S390 && !S390X */
#ifdef I386
eax = error ? -error : rval;
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(EAX * 4), eax) < 0)
return -1;
#else /* !I386 */
#ifdef X86_64
rax = error ? -error : rval;
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(RAX * 4), rax) < 0)
return -1;
#else
#ifdef IA64
if (ia32) {
r8 = error ? -error : rval;
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0)
return -1;
}
else {
if (error) {
r8 = error;
r10 = -1;
}
else {
r8 = rval;
r10 = 0;
}
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R8), r8) < 0 ||
ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R10), r10) < 0)
return -1;
}
#else /* !IA64 */
#ifdef MIPS
if (error) {
r2 = error;
a3 = -1;
}
else {
r2 = rval;
a3 = 0;
}
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
return -1;
#else
#ifdef POWERPC
if (upeek(tcp->pid, 4*PT_CCR, &flags) < 0)
return -1;
if (error) {
flags |= SO_MASK;
result = error;
}
else {
flags &= ~SO_MASK;
result = rval;
}
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_CCR), flags) < 0 ||
ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_R3), result) < 0)
return -1;
#else /* !POWERPC */
#ifdef M68K
d0 = error ? -error : rval;
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_D0), d0) < 0)
return -1;
#else /* !M68K */
#ifdef ARM
r0 = error ? -error : rval;
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*0), r0) < 0)
return -1;
#else /* !ARM */
#ifdef ALPHA
if (error) {
a3 = -1;
r0 = error;
}
else {
a3 = 0;
r0 = rval;
}
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R0), r0) < 0)
return -1;
#else /* !ALPHA */
#ifdef SPARC
if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0)
return -1;
if (error) {
regs.r_psr |= PSR_C;
regs.r_o0 = error;
}
else {
regs.r_psr &= ~PSR_C;
regs.r_o0 = rval;
}
if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0)
return -1;
#else /* !SPARC */
#ifdef HPPA
r28 = error ? -error : rval;
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR28), r28) < 0)
return -1;
#else
#ifdef SH
r0 = error ? -error : rval;
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*REG_REG0), r0) < 0)
return -1;
#endif /* SH */
#endif /* HPPA */
#endif /* SPARC */
#endif /* ALPHA */
#endif /* ARM */
#endif /* M68K */
#endif /* POWERPC */
#endif /* MIPS */
#endif /* IA64 */
#endif /* X86_64 */
#endif /* I386 */
#endif /* S390 || S390X */
#endif /* LINUX */
#ifdef SUNOS4
if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_error),
error << 24) < 0 ||
ptrace(PTRACE_POKEUSER, tcp->pid, (char*)uoff(u_rval1), rval) < 0)
return -1;
#endif /* SUNOS4 */
#ifdef SVR4
/* XXX no clue */
return -1;
#endif /* SVR4 */
#ifdef FREEBSD
if (pread(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
perror("pread");
return -1;
}
if (error) {
regs.r_eflags |= PSL_C;
regs.r_eax = error;
}
else {
regs.r_eflags &= ~PSL_C;
regs.r_eax = rval;
}
if (pwrite(tcp->pfd_reg, &regs, sizeof(regs), 0) < 0) {
perror("pwrite");
return -1;
}
#endif /* FREEBSD */
/* All branches reach here on success (only). */
tcp->u_error = error;
tcp->u_rval = rval;
return 0;
}
int syscall_enter(tcp)
struct tcb *tcp;
{
@ -1763,8 +1929,6 @@ struct tcb *tcp;
res = get_error(tcp);
if (res != 1)
return res;
u_error = tcp->u_error;
internal_syscall(tcp);
if (tcp->scno >= 0 && tcp->scno < nsyscalls &&