This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Cygwin >= 1.7.7 Installing a signal handler causes system calls in other threads to get interrupted.


Hi,

I have the following problem. When I install a signal handler and unblock the according signal in one thread, system calls in other threads will be interrupted, although the signal is blocked or ignored in those other threads.

Regards,

Manuel

Btw: Thanks Corinna for the ultra fast bugfix last time. I just didn't want to spam the list with this one line ;)

-------------------------

Basic structure of the test case:

Main:
- Block signal X
- Create thread 1 and 2
- Send signal X to thread 1

Thread 1:
- Install signal handler for signal X
- Unblock signal X

Thread 2:
- [Signal X is still blocked]
- execute an interruptible system call.

After sending signal X to thread 1, the system call in thread 2 will be interrupted.

Code of the test case:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>

pthread_t DoNotInterruptThreadId1;
pthread_t DoNotInterruptThreadId2;
pthread_t UsesSignalThreadId;

int createThread(void* (*fpStartRoutine)(void* ), void * arg, pthread_t * threadId )
{
  int ret = 0;
  pthread_attr_t attr;

  ret = pthread_attr_init( &attr );
  if( ret != 0 )
  {
    pthread_attr_destroy( &attr );
    printf("pthread_attr_init() failed: %s %d\n",sys_errlist[ret],ret);
    return EXIT_FAILURE;
  }

  ret = pthread_create(threadId, &attr, fpStartRoutine, arg);
  if( ret != 0 )
  {
    pthread_attr_destroy( &attr );
    printf("pthread_create failed: %s %d\n",sys_errlist[ret],ret);
    return EXIT_FAILURE;
  }
  pthread_attr_destroy( &attr );

  return EXIT_SUCCESS;
}

static void SignalHandler(int signo)
{
  int i = 0;
  i++;

  printf("---> Signalhandler called: ");

  switch (signo)
  {
    case SIGUSR1:
    {
      i++;    // Some dummy code.
      printf("SIGUSR1.\n");
      break;
    }
    default: printf("Unknown signal.\n"); break;
  }
}

void * DoNotInterruptThread(void * data)
{
  sigset_t   signal_mask;

  // Check, if the signal is still blocked.
  sigemptyset (&signal_mask);
  if (pthread_sigmask (SIG_BLOCK, NULL, &signal_mask) != 0)
  {
    printf("DoNotInterruptThread: Failed to check signal state.\n");
    return (void*)EXIT_FAILURE;
  }

  if (sigismember(&signal_mask, SIGUSR1) != 1)
  {
    printf("DoNotInterruptThread: SIGUSR1 not blocked.\n");
  }
  else
  {
    printf("DoNotInterruptThread: SIGUSR1 blocked.\n");
  }

  while(1)
  {
   if (sleep(1) != 0)
   {
     printf("DoNotInterruptThread: Sleep failed: %s %d\n",sys_errlist[errno],errno);
     return (void*)EXIT_FAILURE;
   }
#if 0
   // Send signal, nothing should happen...
   printf("DoNotInterruptThread: Starting to send SIGUSR1 to self.\n");
   int err = 0;
   err = pthread_kill(pthread_self(), SIGUSR1);
   if (err != 0)
   {
     printf("DoNotInterruptThread: Sending SIGUSR1 to self...failed.\n");
     return (void*)EXIT_FAILURE;
   }
#endif
  }
}

void * UsesSignalThread(void * data)
{
  sigset_t          signal_mask;
  struct sigaction  sa;

  // Check, if the signal is still blocked.
  sigemptyset (&signal_mask);
  if (pthread_sigmask (SIG_BLOCK, NULL, &signal_mask) != 0)
  {
    printf("UsesSignalThread: Failed to check signal state.\n");
    return (void*)EXIT_FAILURE;
  }

  if (sigismember(&signal_mask, SIGUSR1) != 1)
  {
    printf("UsesSignalThread: SIGUSR1 not blocked (error).\n");
  }
  else
  {
    printf("UsesSignalThread: SIGUSR1 blocked (as expected).\n");
  }

  // Install signal handler
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = SignalHandler;
  sigemptyset(&sa.sa_mask); // Don't block other signals while in the signal handler function
  //sa.sa_flags = SA_RESTART; // Restart functions if interrupted by handler
  if (sigaction(SIGUSR1, &sa, NULL) == -1) // NULL = don't return the previous installed signal action.
  {
    printf("UsesSignalThread: Failed to install signal handler.\n");
    return (void*)EXIT_FAILURE;
  }
  else
  {
    printf("UsesSignalThread: Successfully installed signal handler.\n");
  }

  // Unblock the signal to be able to enter the signal handler.
  sigemptyset (&signal_mask);
  sigaddset (&signal_mask, SIGUSR1);
  if (pthread_sigmask (SIG_UNBLOCK, &signal_mask, NULL) != 0)
  {
    printf("UsesSignalThread: Failed to unblock signal.\n");
    return (void*)EXIT_FAILURE;
  }
  else
  {
    printf("UsesSignalThread: Successfully unblocked signal.\n");
  }

  // Wait some time.
  if (sleep(2) != 0)
  {
    printf("UsesSignalThread: Sleep failed: %s %d\n",sys_errlist[errno],errno);
  }
  return (void*)EXIT_SUCCESS;
}

int main(void)
{
  sigset_t signal_mask;

  puts("Starting Signal test.");

  // Block SIGUSR1 in this thread and thus in all threads created after this point.
  // Those threads which need the signal will unblock it for themselves.
  sigemptyset (&signal_mask);
  sigaddset (&signal_mask, SIGUSR1);
  if (pthread_sigmask (SIG_BLOCK, &signal_mask, NULL) != 0)
  {
    printf("pthread_sigmask() failed.\n");
    return EXIT_FAILURE;
  }

  // Create 2 two threads which shall not be interrupted by SIGUSR1.
  if (createThread(DoNotInterruptThread, NULL, &DoNotInterruptThreadId1) != EXIT_SUCCESS)
  {
    printf("Failed to create DoNotInterrupt 1.\n");
  }
  if (createThread(DoNotInterruptThread, NULL, &DoNotInterruptThreadId2) != EXIT_SUCCESS)
  {
    printf("Failed to create DoNotInterrupt 2.\n");
  }

  // Create a thread which uses a signal handler to handle SIGUSR1.
  if (createThread(UsesSignalThread, NULL, &UsesSignalThreadId) != EXIT_SUCCESS)
  {
    printf("Failed to create UsesSignalThread.\n");
  }

  sleep(1); // Sleep one second

  printf("Main: Starting to send SIGUSR1.\n");
  int err = 0;
  err = pthread_kill(UsesSignalThreadId, SIGUSR1);
  if (err != 0)
  {
    printf("Main: Sending SIGUSR1...failed.\n");
    return EXIT_FAILURE;
  }

  printf("Main: Sending SIGUSR1...success.\n");

  pthread_join(UsesSignalThreadId, NULL);

	return EXIT_SUCCESS;
}

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]