delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2010/11/04/08:52:46

X-Recipient: archive-cygwin AT delorie DOT com
X-SWARE-Spam-Status: No, hits=0.3 required=5.0 tests=AWL,BAYES_00,T_RP_MATCHES_RCVD
X-Spam-Check-By: sourceware.org
From: Manuel Wienand <Manuel DOT Wienand AT ubitronix DOT com>
To: "cygwin AT cygwin DOT com" <cygwin AT cygwin DOT com>
Date: Thu, 4 Nov 2010 13:49:32 +0100
Subject: Cygwin >= 1.7.7 Installing a signal handler causes system calls in other threads to get interrupted.
Message-ID: <0C11C5BF0B29FD43A8D0250F711D497F7F6CC9DAF4@ex01-ubitronix.ubitronix.local>
x-esetresult: clean, is OK
x-esetid: 457DA920DB39A13C163D
MIME-Version: 1.0
X-IsSubscribed: yes
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com

Hi,

I have the following problem. When I install a signal handler and unblock t=
he according signal in one thread, system calls in other threads will be in=
terrupted, 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 int=
errupted.

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 * t=
hreadId )
{
  int ret =3D 0;
  pthread_attr_t attr;

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

  ret =3D pthread_create(threadId, &attr, fpStartRoutine, arg);
  if( ret !=3D 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 =3D 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) !=3D 0)
  {
    printf("DoNotInterruptThread: Failed to check signal state.\n");
    return (void*)EXIT_FAILURE;
  }

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

  while(1)
  {
   if (sleep(1) !=3D 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 =3D 0;
   err =3D pthread_kill(pthread_self(), SIGUSR1);
   if (err !=3D 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) !=3D 0)
  {
    printf("UsesSignalThread: Failed to check signal state.\n");
    return (void*)EXIT_FAILURE;
  }

  if (sigismember(&signal_mask, SIGUSR1) !=3D 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 =3D SignalHandler;
  sigemptyset(&sa.sa_mask); // Don't block other signals while in the signa=
l handler function
  //sa.sa_flags =3D SA_RESTART; // Restart functions if interrupted by hand=
ler
  if (sigaction(SIGUSR1, &sa, NULL) =3D=3D -1) // NULL =3D 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) !=3D 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) !=3D 0)
  {
    printf("UsesSignalThread: Sleep failed: %s %d\n",sys_errlist[errno],err=
no);
  }
  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 thi=
s 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) !=3D 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) !=
=3D EXIT_SUCCESS)
  {
    printf("Failed to create DoNotInterrupt 1.\n");
  }
  if (createThread(DoNotInterruptThread, NULL, &DoNotInterruptThreadId2) !=
=3D 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) !=3D EXIT_S=
UCCESS)
  {
    printf("Failed to create UsesSignalThread.\n");
  }

  sleep(1); // Sleep one second

  printf("Main: Starting to send SIGUSR1.\n");
  int err =3D 0;
  err =3D pthread_kill(UsesSignalThreadId, SIGUSR1);
  if (err !=3D 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

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019