From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 17337 invoked by alias); 8 Dec 2001 04:05:19 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 17221 invoked from network); 8 Dec 2001 04:05:15 -0000 Received: from unknown (HELO zwingli.cygnus.com) (208.245.165.35) by sources.redhat.com with SMTP; 8 Dec 2001 04:05:15 -0000 Received: by zwingli.cygnus.com (Postfix, from userid 442) id 8D2455E9D8; Fri, 7 Dec 2001 23:06:32 -0500 (EST) From: Jim Blandy To: Michael Snyder Cc: gdb-patches@sources.redhat.com Subject: RFA: clean up logic in linux_child_wait Message-Id: <20011208040632.8D2455E9D8@zwingli.cygnus.com> Date: Fri, 07 Dec 2001 20:05:00 -0000 X-SW-Source: 2001-12/txt/msg00227.txt.bz2 GDB still uses linux-thread.c on the S/390. I don't think this function's callers actually noticed that it was returning incorrect values, so this patch can't be tested, but it wasn't analyzing things correctly. 2001-12-07 Jim Blandy * linux-thread.c (linux_child_wait): Rework logic to return proper errno values, make it clearer that we've handled all cases, and not depend on errno being preserved across successful system calls. Index: gdb/linux-thread.c =================================================================== RCS file: /cvs/cvsfiles/devo/gdb/linux-thread.c,v retrieving revision 1.17 diff -c -r1.17 linux-thread.c *** gdb/linux-thread.c 2001/06/14 21:03:15 1.17 --- gdb/linux-thread.c 2001/12/08 04:01:45 *************** *** 1256,1306 **** int linux_child_wait (int pid, int *rpid, int *status) { ! int save_errno; /* Note: inftarg has these inside the loop. */ set_sigint_trap (); /* Causes SIGINT to be passed on to the attached process. */ set_sigio_trap (); ! errno = save_errno = 0; for (;;) { ! errno = 0; ! *rpid = waitpid (pid, status, __WCLONE | WNOHANG); ! save_errno = errno; if (*rpid > 0) { /* Got an event -- break out */ break; - } - if (errno == EINTR) /* interrupted by signal, try again */ - { - continue; } ! errno = 0; *rpid = waitpid (pid, status, WNOHANG); if (*rpid > 0) { /* Got an event -- break out */ break; - } - if (errno == EINTR) - { - continue; } ! if (errno != 0 && save_errno != 0) ! { ! break; ! } sigsuspend(&linuxthreads_block_mask); } clear_sigio_trap (); clear_sigint_trap (); ! return errno ? errno : save_errno; } --- 1256,1364 ---- int linux_child_wait (int pid, int *rpid, int *status) { ! int return_errno = 0; /* Note: inftarg has these inside the loop. */ set_sigint_trap (); /* Causes SIGINT to be passed on to the attached process. */ set_sigio_trap (); ! /* On older Linux kernels, there's no way to say "please wait for ! both clones and normal processes." If you specify __WCLONE, you ! get clones; if you don't, you don't. Since you might miss one ! while waiting for the other, the only way to wait for both is to ! wait for SIGCHLD, and then use WNOHANG to see what happened. */ for (;;) { ! int clone_children_exist; + /* Check for clones. */ + *rpid = waitpid (pid, status, __WCLONE | WNOHANG); + if (*rpid > 0) { /* Got an event -- break out */ break; } + else if (*rpid < 0) + { + /* Only when the system call fails can we make any + assumptions about errno's value. A successful system + call may still set errno to something. */ ! if (errno == EINTR) ! /* interrupted by signal, try again */ ! continue; ! else if (errno != ECHILD) ! { ! /* Some other error, which we should report to our ! caller. */ ! return_errno = errno; ! break; ! } ! ! /* There are no clone children. It's not just that they ! exist but they don't have any status to report yet, since ! we used WNOHANG --- it's that there aren't any. */ ! clone_children_exist = 0; ! } ! else ! /* Here *rpid is zero. Some clone children exist, but we used ! WNOHANG and they don't have any interesting status to ! report to us yet. Fall through and check for non-clone ! children. */ ! clone_children_exist = 1; ! ! /* We didn't find any clones with interesting status; check for ! non-clones. */ *rpid = waitpid (pid, status, WNOHANG); + if (*rpid > 0) { /* Got an event -- break out */ break; } ! else if (*rpid < 0) ! { ! /* Only when the system call fails can we make any ! assumptions about errno's value. A successful system ! call may still set errno to something. */ ! ! if (errno == EINTR) ! /* interrupted by signal, try again */ ! continue; ! else if (errno != ECHILD) ! { ! /* Some unexpected error, which we should report to our ! caller. */ ! return_errno = errno; ! break; ! } ! ! /* There are no non-clone children. If there weren't any ! clone children either, then that's an error condition we ! should report to our caller. */ ! if (! clone_children_exist) ! { ! return_errno = ECHILD; ! break; ! } ! ! /* Otherwise, we should block, since there are clone ! children. */ ! } ! else ! /* Some non-clone children exist, but we used WNOHANG and they ! don't have any interesting status to report to us yet. ! Fall through and block waiting for SIGCHLD. */ ! ; ! sigsuspend(&linuxthreads_block_mask); } clear_sigio_trap (); clear_sigint_trap (); ! return return_errno; }