HomeAbout Us A-Z IndexSearch * Contact Us Register LoginPress Shop

The Open Brand -- Problem Reporting and Interpretations System


Problem Report 1354 Details

Help Show help | Quick Search | Submit a Test Suite Support Request | Click here to view your privileges

This page provides all information on Problem Report 1354.


Report 1354 Actions


    Problem Report Number 1354
    Submitter's Classification Test Suite problem
    State Resolved
    Resolution Test Suite Deficiency (TSD)
    Problem Resolution ID TSD.X.0636
    Raised 1970-01-01 08:00
    Updated 2003-03-13 08:00
    Published 1997-02-14 08:00
    Product Standard Internationalised System Calls and Libraries Extended (UNIX 95)
    Certification Program The Open Brand certification program
    Test Suite VSU version 4.1.1
    Test Identification base/bsd_signal 6
    Problem Summary TSD4U.00181 This test may fail on implementations where the popen() child process may generate a SIGCHLD prior to the fgets() call completing causing a failure.
    Problem Text
    This test may fail on implementations where a SIGCHLD from the popen()
    child process may cause a fgets() and subsequent test failure.

    The test wants to ensure that a zombie is created when a
    child exits and persists until wait is called for it.

    To do this, it establishes a signal handler via bsd_signal()
    for SIGCHLD and creates a child. The parent program then
    spins on a global variable that until it is set to SIGCHLD
    by the execution of the SIGCHLD handler. This means that
    the child has exited.

    The program then wants to locate the expected zombie. It does
    this by executing a "ps -p CHILD-PID" via the popen()
    library function. To do its job, popen() actually creates
    a child to exec the the requested ps command, just like
    the system(). Unlike system(), though, popen() does not
    wait for the command to finish -- it simply returns and
    doesn't wait for the child until pclose() is called.

    Now, given this set up, the test program is actually set
    up to receive *2* SIGCHILD signals:

    1. The first comes from the child process it created directly.
    2. The second comes from the child created indirectly by
    the popen() function.

    Because popen() isn't called until after the "test zombie" is
    created, its worker child doesn't interfere with the first
    part of the test. But it does occasionally interfere with
    the remainder of the tests, where fgets() is called on the
    popen() FILE pointer to read the results of the ps command.

    So, here's the failure: occasionally and at random, the termination
    of the popen child enters the still-established SIGCHLD handler
    and interrupts the fgets() operation before it has read any
    data. If you zero errno before the test and check in the failure
    path, you'll see EINTR is set. Even if you set SA_RESTART
    for SIGCHLD, this failure can occur, because POSIX/UNIX95 read()
    always returns EINTR under certain conditions. Here's
    what the man page says:

    If a read() or pread() function is interrupted by a signal
    before it readsany data, it returns -1 with errno set to
    [EINTR].

    This failure is propagated from the read() called fgets() back to
    the main program.

    So, the test is flawed because it doesn't protect itself from
    the interference of the popen SIGCHLD signal, which can
    happen at any time after popen() is called.

    There are a number of ways to fix this. The simplest way is
    to un-establish the SIGCHLD handler *after* the first
    SIGCHLD signal occurs. This is the signal we want and that
    proves the assertion. The popen SIGCHLD is excess baggage
    and shouldn't be reported.

    Another approach is to have fgets() check errno for EINTR
    and retry the operation. Another is to have the program
    wait for the popen child to exit before calling fgets.

    I like the first one best, because it's probably pretty
    hardware- and implementation-dependent on where and when
    the popen SIGCHLD will occur, so you don't want to
    wait around for it. Just clear out the unneeded handler once
    the signal is caught:


    static void sighandler(int sig)
    {
    signal_caught = sig;
    bsd_signal(SIGCHLD, SIG_IGN);
    }

    does the trick.
    Test Output
    400|1 6 1 16:14:20|IC Start
    200|1 1 16:14:20|TP Start
    520|1 1 30747 1 1|SPEC1170TESTSUITE CASE 6
    520|1 1 30747 1 2|After a successful call to void (*bsd_signal(int sig,
    520|1 1 30747 1 3|void (*func)(int))) (int) when sig is SIGCHLD
    520|1 1 30747 1 4|terminating child processes of the calling process
    520|1 1 30747 1 5|shall be transformed into zombie processes.
    520|1 1 23051 1 1|PREP: Setup SIGCHLD signal handler
    520|1 1 23051 1 2|PREP: Fork child
    520|1 1 23051 2 1|PREP: Wait for child's exit signal
    520|1 1 23051 2 2|PREP: Execute /bin/ps to get child's status
    520|1 1 23051 2 3|TEST: Child is a zombie
    520|1 1 23051 2 4|ERROR: Process does not exist
    520|1 1 28907 1 1|PREP: Call exit
    220|1 1 1 16:14:21|FAIL
    410|1 6 1 16:14:21|IC End

    Review Information

    Review Type TSMA Review
    Start Date null
    Completed null
    Status Complete
    Review Recommendation No Resolution Given
    Review Response
    We agree this is a test suite deficiency in the test
    suite version(s) listed.

    Review Type SA Review
    Start Date null
    Completed null
    Status Complete
    Review Resolution Test Suite Deficiency (TSD)
    Review Conclusion
    This is an agreed Test Suite Deficiency.

    Problem Reporting System Options:

     

    Back   


Contact the Certification Authority