[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::digital_unix

Title:DIGITAL UNIX(FORMERLY KNOWN AS DEC OSF/1)
Notice:Welcome to the Digital UNIX Conference
Moderator:SMURF::DENHAM
Created:Thu Mar 16 1995
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:10068
Total number of notes:35879

9898.0. "How can I get signal(SIGCHLD) from every child process ?" by NNTPD::"[email protected]" (Seok-Hwan, Lee) Tue May 20 1997 23:33


I have a problem in signal program.
When child process exited, Parent process can't get all SIGCHLD signal
from child process. At next following sample program, Parent prcess get
SIGCHLD
signal 2 times(Irregularity).
How can Parent process get signal(SIGCHLD) every time when child process
exited ?
Parent Process can get every SIGCHLD signal from child at SUN Solaris, HP-UX.

------------------------------------------------------------------------
#include        <signal.h>

void
sigh( int n )
{
        int     cpid;

        signal(SIGCHLD, sigh);
        printf( "11111111---SIGH\n" );
        cpid=wait( (int *)0 );
        printf( "sigh function cpid = %d\n", cpid );
}

void
main()
{
        int             cpid=0;

        signal(SIGCHLD, sigh);
        if( (cpid = fork()) == 0 )
        {
                printf("fork1 ok\n");
                exit();
        }
        printf("1: cpid = %d \n", cpid);
        if( (cpid = fork()) == 0 )
        {
              printf(fork2 ok\n"};
              exit();
        }
        printf("2: cpid = %d \n", cpid);
        if( (cpid = fork()) == 0 )
        {
                printf("fork3 ok\n");
                exit();
        }
        printf("3: cpid = %d \n", cpid);

        sleep( 3 );
        while( 1 )
        {
                printf( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" );
                sleep( 2 );
        }
}

[Posted by WWW Notes gateway]
T.RTitleUserPersonal
Name
DateLines
9898.1Use sigaction(2) instead of old signal(2)CECMOW::RAIKOWed May 21 1997 05:490
9898.2Same result in sigaction( ) !NNTPD::&quot;[email protected]&quot;Seok-Hwan, LeeWed May 21 1997 06:2256
I try to excute program using sigaction(), but I have
same result !
changed sample program is next following:#include        <signal.h>
--------------------------------------------------
#include <signal.h>
struct sigaction sa;

void
sigh( int n )
{
        int     cpid;

        sigaction(SIGCHLD, &sa, NULL);
        printf( "----- sigh function called ---SIGH\n" );
        cpid=wait( (int *)0 );
        printf( "Wait func cpid = %d\n", cpid );
}

void
main()
{
        int             cpid=0;

       sigemptyset(&sa.sa_mask);
       sa.sa_flags = SIGCHLD;
       sa.sa_handler = sigh;
       sigaction(SIGCHLD, &sa, NULL);

        if( (cpid = fork()) == 0 )
        {
                printf("fork1 ok\n");
                exit();
        }
        printf("1: cpid = %d \n", cpid);
        if( (cpid = fork()) == 0 )
        {
                printf("fork2 ok\n");
                exit();
        }
        printf("2: cpid = %d \n", cpid);
        if( (cpid = fork()) == 0 )
        {
                printf("fork3 ok\n");
                exit();
        }
        printf("3: cpid = %d \n", cpid);

        sleep( 3 );
        while( 1 )
        {
                printf( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" );
                sleep( 2 );
        }
}

[Posted by WWW Notes gateway]
9898.3MSKRAT::ANKANIdle words waste timeWed May 21 1997 11:1616
Well, just change your signal handler to something like:

void
sigh( int n )
{
        int     cpid;

        sigaction(SIGCHLD, &sa, NULL);
        printf( "----- sigh function called ---SIGH\n" );
        while ((cpid=wait( (int *)0 )) > 0) {
          printf( "Wait func cpid = %d\n", cpid );
        }
}

...and you should be all set. More than one child death can be
pending for a single signal.
9898.4SMURF::DENHAMDigital UNIX KernelWed May 21 1997 11:196
    That's the idea in the last reply. There's simply *no way* to
    guarantee a signal for every child -- those signals don't queue
    in the realtime fashion. Instead, you need to call waitpid or
    wait3 or wait4 or waitid with the WNOHANG flag in a loop until
    it returns failure. If you don't you the no-hang option, you
    handler will indeed hang.
9898.5Be careful what you try to do in a signal handlerWTFN::SCALESDespair is appropriate and inevitable.Wed May 21 1997 12:169
.3> Well, just change your signal handler to something like:

Yes, but...  There's a small list of "signal-safe" functions -- those which
are safe for use in signal handlers -- and printf() is _not_ one of them...
See the signal(4) man page.  The wait*() functions, however, -are-
signal-safe.  :-)


				Webb
9898.6MSKRAT::ANKANIdle words waste timeWed May 21 1997 14:3214
Nitty picky... all I need is pthread_cond_signal_int_np :-)

But, signal(4) sure raised a question; to quote:

 "The signal-catching function can cause the process to resume in a different
  context by calling the longjmp() subroutine. When the longjmp() subroutine
  is called, the process leaves the signal stack, if it is currently on it,
  and restores the process signal mask to the state when the corresponding
  setjmp() call was made."

So, if a longjmp() out of the signal handler, could I call a pthread
routine, or even printf()?


9898.7I depends on how we implemented it...WTFN::SCALESDespair is appropriate and inevitable.Wed May 21 1997 15:1531
.6> if a longjmp() out of the signal handler, could I call a pthread routine, or 
.6> even printf()?

The answer is supposed to be "yes":  once you've completed the jump, you are no
longer in the context of a signal handler, and so you are not bound by the
restrictions in signal(4).

However, as I sit here, I can't say with any confidence that that is indeed the
case.  I think it all depends on how longjmp() is implemented, and how the
non-signal-safe routines (such as printf()) are constructed.  That is, if
longjmp() were implemented such that it unwound the stack, frame by frame
(instead of arbitrarily rewriting the register set), such that any interested
routine could declare an "unwind handler" which would allow it to clean up in
the event of a longjmp(), then there would be the possibility of making things
work after jumping out of a signal handler.

The problem is that the signal could be delivered at a moment when the state in
some routine is inconsistent from an outside perspective.  For example, suppose
the signal interrupts printf() after it's filled the output buffer but before
it's flushed it (or any of several equivalent places):  calling printf() from
the signal handler could result in corruptions of either memory or the output
stream (i.e., output would be lost), and doing the longjmp() first wouldn't
change anything, _unless_ printf() could tell that the jump is occurring.  The
situation gets even worse when you introduce threads and mutexes...

So, yeah, it's supposed to work, but I've grave doubts as to whether it actually
does.  Thus, it's best to avoid doing anything more than you have to in a signal
handler, and only use setjmp() and longjmp() where you absolutely have to!


				Webb
9898.8SMURF::DENHAMDigital UNIX KernelWed May 21 1997 18:108
    Big dittos for Webb's reponse. There is indeed no unwinding done
    for a longjmp -- just Boom, you're back at the saved context.
    
    If you're in a threaded environment, using structure exceptions
    is a much better model. The exception code *does* do sane unwinding
    before it calls the kernel equivalent of longjmp, sigreturn.
    So, you would be able to back out of mutexs taken before the
    signal was generated....
9898.9DCETHD::BUTENHOFDave Butenhof, DECthreadsThu May 22 1997 07:2136
>    If you're in a threaded environment, using structure exceptions
>    is a much better model. The exception code *does* do sane unwinding
>    before it calls the kernel equivalent of longjmp, sigreturn.
>    So, you would be able to back out of mutexs taken before the
>    signal was generated....

Of course beware that libc does NOT have exception handlers, and will NOT
restore data invariants or unlock mutexes when "unwound". So an async signal
action invoked while in, for example, printf, that is unwound past the printf
call by raising an exception, will leave the file stream inconsistent and,
very likely, the mutex locked.

The libc routines are thread-safe, but they are not async signal safe.

Technically, when you call longjmp (or siglongjmp) from a signal action you
are not actually "returning" from the signal action routine. Although one can
infer from the too-specific language ("if they are called from a
signal-catching function") that it's OK to call non-async-safe functions
after a longjmp() to "another function", the standard does not actually deal
with this case. Making such an inference is very dangerous, because I very
much doubt that any implementation of UNIX, with or without threads, will
meet the expectation. If you asynchronously interrupt a stdio function in the
process of modifying the file stream state, and longjmp somewhere else, you
WILL leave the stream in an inconsistent state. Period. The result may or may
not disrupt the process at some later time, depending on how serious the
inconsistency is. (Without threads, you're not likely to do much more than
overwrite some characters in the output buffer -- but there's no
architectural guarantee of that!)

(Hmmm... the ANSI C definition of longjmp() prohibits an implementation that
"cleans up" state from the intermediate frames... it requires specifically
that "All accessible objects have values as of the time longjmp was
called...". I hate it when standards paint themselves into a corner where the
functions cannot be made to work correctly!)

	/dave