[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#414021: marked as done (SIGSTOP then SIGCONT on a whole process incorrectly releases a thread from sigwait(3) for another signal)



Your message dated Mon, 3 Aug 2009 19:47:26 +0200
with message-id <20090803174726.GQ22735@inutil.org>
and subject line Mark as fixed
has caused the Debian Bug report #414021,
regarding SIGSTOP then SIGCONT on a whole process incorrectly releases a thread from sigwait(3) for another signal
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
414021: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=414021
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: linux-image-2.6-amd64
Version: 2.6.18+6

I've already tried to report this bug upstream at:
http://sources.redhat.com/bugzilla/show_bug.cgi?id=4169

but the maintainers of glibc say that this is a bug in the kernel and
not in NPTL.

So...

If a whole process, which has a thread waiting with sigwait(3), is stopped with
SIGSTOP, then when it is restarted with SIGCONT sigwait returns without writing
to *sig (second argument).  This appears to be in contradiction with
POSIX-1003.1 2004.

http://www.opengroup.org/onlinepubs/000095399/functions/sigwait.html

Steps to reproduce:

$ wget http://purposeful.co.uk/testcase.c
$ gcc -o testcase -pthread -lpthread testcase.c
$./testcase

The test program prints 'a' from one thread and 'b' from another.  After ten of
each the 'b' thread calls sigwait, and you get just 'a's.  When this happens,
hit Ctrl+Z.  Now restart the process (with fg).  The 'b' thread resumes straight
away.

Expected behaviour:

$ gcc -o testcase -pthread -lpthread -DWORKAROUND testcase.c
$./testcase

Now do the same.  The 'b' thread returns to its waiting state.  You get as more
of just 'a' until there have been 10 of them and then a mix again.

$ uname -a
Linux cheese 2.6.18-4-amd64 #1 SMP Wed Feb 21 14:29:38 UTC 2007 x86_64 GNU/Linux
$ dpkg -s libc6 | fgrep Version
Version: 2.3.6.ds1-13
/* testcase.c PUBLIC DOMAIN by Tom Vajzovic */
#include <pthread.h>

#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>

#define MY_SIGSTOP  (SIGRTMIN + 8)
#define MY_SIGCONT  (SIGRTMIN + 9)

#define WASTE_TIME { int z; for( z= INT_MAX/15; z; --z ); }
#define REPS 30

void *thread_func( void *vptr_args );
void resume_handler( int arg );
void suspend_handler( int arg );

int main( int ac, char **av ){
  int i;
  struct sigaction sto_action;
  struct sigaction res_action;
  sigset_t blocked;
  pthread_t thread;
  
  sto_action. sa_handler= suspend_handler;
  sigfillset( & sto_action. sa_mask );
  sigdelset( & sto_action. sa_mask, MY_SIGCONT );
  sto_action. sa_flags= 0;

  res_action. sa_handler= resume_handler;
  sigfillset( & res_action. sa_mask );
  res_action. sa_flags= 0;

  if( sigaction( MY_SIGCONT, &res_action, NULL ) || sigaction( MY_SIGSTOP, &sto_action, NULL ) ){
    perror( "sigaction" );  
    exit( EXIT_FAILURE );
  }

  sigemptyset( &blocked );
  sigaddset( &blocked, MY_SIGSTOP );
  sigaddset( &blocked, MY_SIGCONT );

  pthread_sigmask( SIG_SETMASK, &blocked, NULL );

  pthread_create( &thread, NULL, &thread_func, NULL );

  for( i= 0; i < REPS; ++i ){
    fprintf( stderr, "a\n" );

    if( 10 == i )
      pthread_kill( thread, MY_SIGSTOP );

    if( 20 == i )
      pthread_kill( thread, MY_SIGCONT );
    
    WASTE_TIME;
  }

  pthread_join( thread, NULL );

  exit( EXIT_SUCCESS );
}

void *thread_func( void *vptr_args ){

  sigset_t blocked;
  int i;

  sigfillset( &blocked );
  sigdelset( &blocked, MY_SIGSTOP );

  pthread_sigmask( SIG_SETMASK, &blocked, NULL );

  for( i= 0; i < REPS; ++i ){
    fprintf( stdout, "  b\n" );

    WASTE_TIME;
  }

  pthread_exit( NULL );
}

void resume_handler( int arg ){
  return;
}

void suspend_handler( int arg ){
  sigset_t set;
  int sig= -1;

  sigemptyset( &set );
  sigaddset( &set, MY_SIGCONT );

#ifdef WORKAROUND
  /* define this for the correct behavior */
  while( -1 == sig )
#endif  
    sigwait( &set, &sig );
}

--- End Message ---
--- Begin Message ---
Marking as fixed.


--- End Message ---

Reply to: