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

Conference clt::cma

Title:DECthreads Conference
Moderator:PTHRED::MARYSTEON
Created:Mon May 14 1990
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:1553
Total number of notes:9541

1547.0. "thread not inheriting signal mask in DU 3.2c?" by HYDRA::BRYANT () Wed May 21 1997 16:13

Here is a reproducer from a partner which demonstrates a parent process being
killed when its child is killed.  On DU 4.0, the parent process does not get
killed which I assume is the correct behavior.  Is there a patch
for 3.2c that I'm just not seeing?  

I killed the child process using kill(1) from another window.

parent.c
--------
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

static void *WriteToPipe(void *);
static FILE *fRead, *fWrite;

int main() {
  int childPID;
  int hIn, hOut;
  int pWrite[2];
  int pRead[2];
  pthread_t threadId;
  pthread_addr_t threadStatus;

  if ( sigignore(SIGPIPE) != 0 )
    printf("sigignore: %s\n", strerror(errno));

  if ( pipe(pWrite) != 0 || pipe(pRead) != 0 )
    printf("pipe: %s\n", strerror(errno));

  childPID = fork();

  if ( childPID == -1 )
    printf("fork: %s\n", strerror(errno));

  if ( childPID == 0 ) { /* Child */

    close(pWrite[1]);
    close(pRead[0]);
    hIn = fileno(stdin);
    hOut = fileno(stdout);
    fclose(stdin);
    fclose(stdout);
    if ( dup2(pWrite[0], hIn) == -1 || dup2(pRead[1], hOut) == -1 )
      printf("dup2: %s\n", strerror(errno));
    if ( execl("child", "child", "", (const char*)0) == -1 )
      printf("execl: %s\n", strerror(errno));
    printf("Cannot start child process\n");
    return 98;
  } else { /* Parent */
    close(pWrite[0]);
    close(pRead[1]);
    if ( (fWrite=fdopen(pWrite[1], "w")) == 0 ||
         (fRead=fdopen(pRead[0], "r")) == 0 ) {
      printf("fdopen: %s\n", strerror(errno));
      return 99;
    }
#if 1  /* Use thread */
    pthread_create(&threadId, pthread_attr_default, WriteToPipe, 0);
    pthread_join(threadId, &threadStatus);
#else  /* Don't use thread */
    WriteToPipe(0);
#endif
  }

  return 0;
}

static void *WriteToPipe(void *ignored) {
#if 0  /* sigignore in the child thread fixes the problem */
  if ( sigignore(SIGPIPE) != 0 )
    printf("sigignore: %s\n", strerror(errno));
#endif
  printf("Parent starts writing into the pipe\n");
  for ( ; ; ) {
    putc('0', fWrite);
    fflush(fWrite);
  }

  return 0;
}

child.c
--------
#include <stdio.h>

int main() {
  int firstTime = 1;

  fprintf(stderr, "Child has started\n");

  while ( getchar() != EOF ) {
    if ( firstTime ) {
      fprintf(stderr, "Child is reading from the pipe\n");
      fprintf(stderr, "Killing the child should not terminate the parent\n");
      firstTime = 0;
    }
  }
}

Makefile
--------
All: parent child

parent: parent.c
        cc -o parent -threads parent.c -lpthreads

child: child.c
        cc -o child child.c
T.RTitleUserPersonal
Name
DateLines
1547.1DCETHD::BUTENHOFDave Butenhof, DECthreadsWed May 21 1997 17:3022
You're misinterpreting what's happening. What you're doing (by calling
sigignore) is NOT setting the signal mask -- it's setting the signal ACTION
(to SIG_IGN).

In POSIX (and therefore in Digital UNIX 4.0), all threads share a common
process action for each signal. And therefore, all threads have SIGPIPE set
to SIG_IGN, and ignore the broken pipe. Prior to Digital UNIX 4.0, each
thread had its own private handler for the "synchronous" signal actions,
which happens to include SIGPIPE. Signal actions were not inherited. You can
work around that by having each thread call sigignore(), for example, before
doing any I/O.

I really don't know whether threads inherited the creator's signal mask in
3.2 -- when Jeff repaired the ancient OSF/1 "quirk" where all threads shared
a single (process-wide) signal mask, it didn't occur to me to ask. It didn't
really matter, since we weren't bound by any standard at the time -- and the
POSIX thread standard wasn't even final, so pretending to follow it would
have been of little value. If Jeff confirms that they did inherit the mask,
then you could convert the program to use sigprocmask instead of sigignore,
and take care of all the threads.

	/dave