Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 25 Jan 2001 02:33:03 -0800 (PST)
From:      barak@cwnt.com
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   bin/24632: libc_r delicate deviation from libc in handling SIGCHLD
Message-ID:  <200101251033.f0PAX3p99537@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         24632
>Category:       bin
>Synopsis:       libc_r delicate deviation from libc in handling SIGCHLD
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jan 25 02:40:00 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     Barak Enat
>Release:        FreeBSD 4.2
>Organization:
Charlotte's Networks
>Environment:
FreeBSD simba.cwnt.co.il 4.2-RELEASE FreeBSD 4.2-RELEASE #2: Wed Jan 17 16:22:29 GMT 2001     barak@simba.cwnt.co.il:/usr/src/sys/compile/COMPAQ_DL360  i386

>Description:
Hi,

By default, all signals behave as if an SA_RESTART flag was set for them. Thus, all system calls will be restarted once the signal handler returns. In practice this means that the EINTR error code should never happen, unless a sigaction call cleared the SA_RESTART flag for some signal.

However, this is not true with respect to SIGCHLD and the pthread library.
I enountered several cases where a read operation (for example) returned with a -1 and errno = EINTR when a child process terminated. This happened only when I was linking to the libc_r pthread library.

Here is a small example (pb.c) and an associated makefile: 

#include <unistd.h>
#include <stdio.h>

int main()
{
  int s;
  char c;

  if (! fork()) {
    char *args[3] = {"/bin/sleep", "10000", 0};
    execv(args[0], args);
  }

  while (s = read(0, &c, 1)) {
    if (s < 0) perror("read");
    else write(1, &c, 1);
  }
  return 0;
}

all: pb pb_r

pb:	pb.c
	cc -o pb pb.c

pb_r:	pb.c
	cc -pthread -o pb_r pb.c

>How-To-Repeat:
To see the problem, the makefile generates both a threaded version (pb_r) and a non threaded version (pb).
To reproduce the problem do:

1. Run pb_r. The program forks a child (sleep) process, and then it is a simple echo program.
2. Now type a line or two and let the program echo it. (This is a must - I don't know why the problem isn't revealed otherwise).
3. Now (from another terminal) kill the child process.
4. You should see the following output:

> ./pb_r
test123
test123
read: Interrupted system call

If you try the same with the non threaded program (pb), the read never returns an error.

>Fix:
Looking at the pthread library code I have noticed that in three places the sa_flags field is initialized without the SA_RESTART flag. By blindly adding the SA_RESTART flag, I was able to solve the issue, however, I'm not sure this is the apropriate approach. (Maybe, instead, all the relevant system calls, such as read, should be fixed to be restarted appon kernel EINTR if the signal flags require it.)

Below is the patch I did (again - I'm quite sure it is incomplete).

Regards,
Barak
barak@cwnt.com

--- uthread/uthread_init.c      Thu Jan 25 12:19:07 2001
+++ uthread/uthread_init.c.orig Thu Nov 16 22:21:50 2000
@@ -271,9 +271,9 @@
 
                /* Initialise the global signal action structure: */
                sigfillset(&act.sa_mask);
                act.sa_handler = (void (*) ()) _thread_sig_handler;
-               act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
+               act.sa_flags = SA_SIGINFO | SA_ONSTACK;
 
                /* Clear pending signals for the process: */
                sigemptyset(&_process_sigpending);
 
--- uthread/uthread_sigaction.c Thu Jan 25 12:19:07 2001
+++ uthread/uthread_sigaction.c.orig    Fri Nov 10 01:46:04 2000
@@ -79,9 +79,9 @@
                         * by other signals.  Always request the POSIX signal
                         * handler arguments.
                         */
                        sigfillset(&gact.sa_mask);
-                       gact.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
+                       gact.sa_flags = SA_SIGINFO | SA_ONSTACK;
 
                        /*
                         * Check if the signal handler is being set to
                         * the default or ignore handlers:

--- uthread/uthread_signal.c    Thu Jan 25 12:19:07 2001
+++ uthread/uthread_signal.c.orig       Fri Nov 10 01:46:04 2000
@@ -44,9 +44,9 @@
 
        /* Initialise the signal action structure: */
        sigemptyset(&sa.sa_mask);
        sa.sa_handler = a;
-       sa.sa_flags = SA_SIGINFO | SA_RESTART;
+       sa.sa_flags = SA_SIGINFO;
 
        /* Perform the sigaction syscall: */
        if (_thread_sys_sigaction(s, &sa, &osa) < 0) {
                /* Return an error: */


>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200101251033.f0PAX3p99537>