public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: "Michael Kerrisk" <mtk-lkml@gmx.net>
To: roland@redhat.com
Cc: linux-kernel@vger.kernel.org, michael.kerrisk@gmx.net
Subject: waitid() fails with EINVAL for SA_RESTART signals
Date: Wed, 18 May 2005 10:20:47 +0200 (MEST)	[thread overview]
Message-ID: <24601.1116404447@www71.gmx.net> (raw)

Hello Roland,

I'm seeing a strange behaviour with waitid() in 2.6.12-rc3 
(I'm fairly sure the behaviour also appears in other 2.6.x).

If we establish a handler for a signal with SA_RESTART, and that 
signal interrupts a blocked waitid(), then waitid() fails with 
the error EINVAL.  I would expect the call to be restarted
(like wait(), waitpid(), etc.) or if you are choosing to design
waitid() to ignore SA_RESTART, then fail with EINTR.

I haven't been able to spot the source of the EINVAL in kernel
or glibc sources.

The program below can be used to demonstrate the problem.

Cheers,

Michael

/* waitid_intr.c

   Michael Kerrisk, May 2005

   Demonstration of a problem with waitid() on Linux (Linux 2.6.12-rc3).

   If S_A_RESTART was specified for a signal handler, and that signal
   is delivered during a blocked waitid(), then the waitid() fails
   with EINVAL, when it should either be restarted or (if the intent
   is to ignore SA_RESTART in the waitid() implementation) fail
   with EINTR.  This program demonstrates the problem.

   The program creates two children.  The first is a child that sleeps
   for argv[2] seconds and is then reaped by waitid() in the parent.
   The second child sends a signal (SIG) to the parent after argv[3]
   seconds.

   argv[1] specifies options for the waitid() call (see the code
   below).

   If the optional argv[4] is present (as any string), then the
   handler for the signal sent by the second child is established
   with SA_RESTART.

   To demonstrate the waitid() problem, use the following command:

       ./waitid_intr esc 10 2 restart
*/
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <syscall.h>
#include <unistd.h>
#include <errno.h>

#define errExit(msg)    { perror(msg); exit(EXIT_FAILURE); }

#define fatalErr(msg)   { fprintf(stderr, "%s\n", msg); \
                              exit(EXIT_FAILURE); }

static void
handler(int sig)
{
    int savedErrno;

    savedErrno = errno;
    printf("Caught signal\n");
    errno = savedErrno;
} /* handler */

#define SIG SIGUSR1

int
main(int argc, char *argv[])
{
    siginfo_t info;
    int options, s;
    char *p;
    pid_t pid;
    struct rusage ru;
    struct sigaction sa;

    setbuf(stdout, NULL);

    printf("Parent's PID is %ld\n", (long) getpid());

    if (argc < 4) {
        fprintf(stderr, "%s {escHW} child-secs sig-secs [sa_restart]\n",
                argv[0]);
        exit(EXIT_FAILURE);
    } 

    options = 0;

    for (p = argv[1]; *p != '\0'; p++) {
        if      (*p == 'e') options |= WEXITED;
        else if (*p == 's') options |= WSTOPPED;
        else if (*p == 'c') options |= WCONTINUED;
        else if (*p == 'H') options |= WNOHANG;
        else if (*p == 'W') options |= WNOWAIT;

        else fatalErr("Bad option letter");
    }

    /* Create first child to waitid() for */

    pid = fork();
    if (pid == -1) errExit("fork");

    if (pid == 0) {
        printf("child (PID = %ld) started\n", (long) getpid());
        sleep(atoi(argv[2]));
        printf("child (PID = %ld) finished\n", (long) getpid());
        exit(EXIT_SUCCESS);
    } 

    /* Parent falls through */

    /* Set up handler for signal sent by child 2 */

    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = (argc > 4) ? SA_RESTART : 0;
    if (sigaction(SIG, &sa, NULL) == -1) errExit("sigaction");

    /* Create  a second child that will send parent a signal */

    switch (fork()) {
    case -1:
        errExit("fork-2");

    case 0:
        sleep(atoi(argv[3]));
        printf("Sending signal to parent\n");
        if (kill(getppid(), SIG) == -1) errExit("kill");
        exit(EXIT_SUCCESS);

    default:
        break;
    } 

    /* Parent now waits for the first child */

    memset(&info, 0, sizeof(siginfo_t));

    s = waitid(P_PID, pid, &info, options);
    //s = syscall(SYS_waitid, P_ALL,  0, &info, options, &ru);
    //s = syscall(SYS_waitpid, -1, NULL, 0);

    if (s == -1) errExit("waitid");

    printf("waitid() returned %d\n", s);
    printf("    ");
    printf("si_pid=%ld; ", (long) info.si_pid);
    printf("si_uid=%ld; ", (long) info.si_uid);
    printf("si_signo=%ld; ", (long) info.si_signo);
    printf("\n");
    printf("    ");
    printf("si_status=%ld; ", (long) info.si_status);
    printf("si_code=%ld ", (long) info.si_code);
    printf("(%s); ",
                (info.si_code == CLD_EXITED) ? "CLD_EXITED" :
                (info.si_code == CLD_KILLED) ? "CLD_KILLED" :
                (info.si_code == CLD_DUMPED) ? "CLD_DUMPED" :
                (info.si_code == CLD_TRAPPED) ? "CLD_TRAPPED" :
                (info.si_code == CLD_STOPPED) ? "CLD_STOPPED" :
                (info.si_code == CLD_CONTINUED) ? "CLD_CONTINUED" :
                "????");
    printf("\n");
} /* main */


-- 
Weitersagen: GMX DSL-Flatrates mit Tempo-Garantie!
Ab 4,99 Euro/Monat: http://www.gmx.net/de/go/dsl

             reply	other threads:[~2005-05-18  8:21 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-05-18  8:20 Michael Kerrisk [this message]
2005-05-26 21:17 ` waitid() fails with EINVAL for SA_RESTART signals Roland McGrath
2005-05-26 22:21 ` [PATCH] i386: fix prevent_tail_call Roland McGrath
2005-05-26 22:22 ` waitid() fails with EINVAL for SA_RESTART signals Roland McGrath
2005-05-26 22:37   ` David S. Miller
2005-05-26 23:19     ` Linus Torvalds
2005-05-26 23:22       ` Roland McGrath
2005-05-27  0:03         ` Parag Warudkar
2005-05-27  0:11           ` Roland McGrath
2005-05-27  0:37             ` Parag Warudkar
2005-05-27  1:05               ` Parag Warudkar
2005-05-27  2:01                 ` Parag Warudkar
2005-05-30 16:55       ` Michael Kerrisk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=24601.1116404447@www71.gmx.net \
    --to=mtk-lkml@gmx.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=michael.kerrisk@gmx.net \
    --cc=roland@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox