delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2010/07/12/17:06:10

X-Recipient: archive-cygwin AT delorie DOT com
X-SWARE-Spam-Status: No, hits=1.4 required=5.0 tests=BAYES_50,SARE_BAYES_5x7,T_RP_MATCHES_RCVD
X-Spam-Check-By: sourceware.org
X-cybertrench.com-virus-scan: clean
Date: Mon, 12 Jul 2010 23:05:19 +0200
From: Corvus Corax <corvuscorax AT cybertrench DOT com>
To: cygwin AT cygwin DOT com
Subject: Re: Sending SIGUSR1 to thread in nanosleep causes segfault
Message-ID: <20100712230519.4e871a91@CorvusMC.home>
Mime-Version: 1.0
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

--MP_//2QRbacSOBFpiqJpH/m8fPe
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

FYI

Just to update some details.

I am working with James Cotton on the OpenPilot project.
We are trying to port the POSIX simulation port of FreeRTOS to cygwin.

We run into issues with signal handling in cygwin 1.7.5 that are
currently blocking our development, since every method to suspend a
running thread via signals either causes:

- random segfaults within Cygwin DLL.
or
- failure to execute the signal handler.

For the sake of narrowing down the source of our problems,
we created 8 demo test cases.

Each of them works the same way:

1. A thread is spawned via pthread_create(), which then executes some
   code that is supposed to "sleep the thread" in background.
2. Signals are repeatedly sent to that thread using pthread_kill()
   which are supposed to be handled by a signal handler.
3. Each succesful call to the signal handler writes a dot (.) to stderr
   (using the write() system call to be thread safe)

Obviously what this is supposed to create is a neverending line of dots.
(Tested and working on Linux and Mac OS X on several architectures)

We believe this is a sign of a major flaw in cygwin signal handling and
may possibly affect many applications.
(Any application that uses signal handlers is potentially affected!)

SEGFAULTS usually occur only once in several thousand signals, so it is
a problem that won't appear on normal applications in a very frequent
way. However it is definitely reproducable!

All 8 test cases usually reach a stable state (segfault or freeze of
output) within less than 10 seconds (usually less than 1s) of run time.


The 8 test cases are as follows:

----

test_case_1_sleep.c

- The thread sleeps (literally) calling sleep() from <unistd.h>
Bug:
- After a couple thousand dots, the program ends with SIGSEGV in
  cygwin1.dll. The backtrace leads to garbage due to stack corruption!

----

test_case_2_nanosleep.c

- The thread sleeps calling nanosleep() from <time.h>
Bug:
- After a couple thousand dots, the program ends with SIGSEGV in
  cygwin1.dll. The backtrace leads to garbage due to stack corruption!

----

test_case_3_select.c

- The thread sleeps calling select() from <unistd.h>
Bug:
- Once select() is executed, cygwin blocks signals, failing to execute
  the signal handler. No dots are printed (There is a violation to
  POSIX specification. select() is supposed to return prematurely on
  receiving any signal, whether handled or not. This does not happen.)

----

test_case_4_mutex_lock.c

- The thread sleeps calling pthread_mutex_lock() from <pthread.h>
Bug:
- Once mutex_lock() is executed, cygwin blocks signals, failing to
  execute the signal handler. No dots are printed. This is a major
  issue for the porting of FreeRTOS, because it causes deadlocks we
  cannot resolve.

----

test_case_5_pselect.c

- The thread sleeps calling pselect() from <unistd.h>. Pselect allows
  to specify a signal mask of signals to be (or not to be) blocked
  during the pselect() call. The mask is deliberate set EMPTY to make
  pselect() interrupt on ALL signals.
Bug:
- Once pselect() is executed, cygwin blocks signals, failing to execute
  the signal handler. No dots are printed (pselect() completely
  ignores its signal mask argument !!!!! )

----

test_case_6_sched_yield.c

- The thread "sleeps" repeatedly calling sched_yield() from <pthread.h>
Bug:
- The signal handler is not executed in a reliable fashion.

----

test_case_7_busy_waiting.c
- The thread runs like crazy in a busy loop.
Bug:
- The signal handler is not executed in a reliable fashion.

----

test_case_8_io.c
- The thread "sleeps" by executing a blocking "read()" call from stdin
Bug:
- The signal handler is not executed in a reliable fashion.
- Occasional segfaults in cygwin dll.


--MP_//2QRbacSOBFpiqJpH/m8fPe
Content-Type: text/x-c++src
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=test_case_1_sleep.c

/**
 * small test program whether signals between threads work as they should
 */

#include <unistd.h>
#include <pthread.h>
#include <signal.h>

void sighandler(int sig) {
	write(2,".",1);
	return;
}

void* threadstart(void* arg) {

	while (1) {
		sleep(1);
	}
}

int main(char** argc, int argv) {

	pthread_t testthread1;	
	struct sigaction action;

	action.sa_handler=sighandler;
	action.sa_flags=0;
	sigfillset( &action.sa_mask );
	sigaction(SIGUSR1,&action,NULL);

	pthread_create(&testthread1,NULL,threadstart,NULL);
	while (1) {
		pthread_kill(testthread1,SIGUSR1);
	}
}

--MP_//2QRbacSOBFpiqJpH/m8fPe
Content-Type: text/x-c++src
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=test_case_2_nanosleep.c

/**
 * small test program whether signals between threads work as they should
 */

#include <time.h>
#include <pthread.h>
#include <signal.h>

void sighandler(int sig) {
	write(2,".",1);
	return;
}

void* threadstart(void* arg) {
struct timespec sleeptime;

	while (1) {
		sleeptime.tv_sec=1;
		sleeptime.tv_nsec=0;
		nanosleep(&sleeptime,NULL);
	}
}

int main(char** argc, int argv) {

	pthread_t testthread1;	
	struct sigaction action;

	action.sa_handler=sighandler;
	action.sa_flags=0;
	sigfillset( &action.sa_mask );
	sigaction(SIGUSR1,&action,NULL);

	pthread_create(&testthread1,NULL,threadstart,NULL);
	while (1) {
		pthread_kill(testthread1,SIGUSR1);
	}
}

--MP_//2QRbacSOBFpiqJpH/m8fPe
Content-Type: text/x-c++src
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=test_case_3_select.c

/**
 * small test program whether signals between threads work as they should
 */

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>

void sighandler(int sig) {
	write(2,".",1);
	return;
}

void* threadstart(void* arg) {
struct timeval sleeptime;

	while (1) {
		sleeptime.tv_sec=1;
		sleeptime.tv_usec=0;
		select(0,NULL,NULL,NULL,&sleeptime);
	}
}

int main(char** argc, int argv) {

	pthread_t testthread1;	
	struct sigaction action;

	action.sa_handler=sighandler;
	action.sa_flags=0;
	sigfillset( &action.sa_mask );
	sigaction(SIGUSR1,&action,NULL);

	pthread_create(&testthread1,NULL,threadstart,NULL);
	while (1) {
		pthread_kill(testthread1,SIGUSR1);
	}
}

--MP_//2QRbacSOBFpiqJpH/m8fPe
Content-Type: text/x-c++src
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=test_case_4_mutex_lock.c

/**
 * small etst program whether signals between threads work as they should
 */

#include <pthread.h>
#include <signal.h>

static pthread_mutex_t Mutex = PTHREAD_MUTEX_INITIALIZER;

/**
 * actual test program
 */

void sighandler(int sig) {
	write(2,".",1);
	return;
}

void* threadstart(void* arg) {

	while (1) {
		pthread_mutex_lock(&Mutex);
	}
}

int main(char** argc, int argv) {

	pthread_t testthread1;	
	struct sigaction action;

	action.sa_handler=sighandler;
	action.sa_flags=0;
	sigfillset( &action.sa_mask );
	sigaction(SIGUSR1,&action,NULL);

	pthread_mutex_lock(&Mutex);
	pthread_create(&testthread1,NULL,threadstart,NULL);
	while (1) {
		pthread_kill(testthread1,SIGUSR1);
	}
}

--MP_//2QRbacSOBFpiqJpH/m8fPe
Content-Type: text/x-c++src
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=test_case_5_pselect.c

/**
 * small test program whether signals between threads work as they should
 */

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>

void sighandler(int sig) {
	write(2,".",1);
	return;
}

void* threadstart(void* arg) {
sigset_t sigset;
struct timespec sleeptime;

	while (1) {
		sleeptime.tv_sec=1;
		sleeptime.tv_nsec=0;
		sigemptyset(&sigset);
		pselect(0,NULL,NULL,NULL,&sleeptime,&sigset);
	}
}

int main(char** argc, int argv) {

	pthread_t testthread1;	
	struct sigaction action;

	action.sa_handler=sighandler;
	action.sa_flags=0;
	sigfillset( &action.sa_mask );
	sigaction(SIGUSR1,&action,NULL);

	pthread_create(&testthread1,NULL,threadstart,NULL);
	while (1) {
		pthread_kill(testthread1,SIGUSR1);
	}
}

--MP_//2QRbacSOBFpiqJpH/m8fPe
Content-Type: text/x-c++src
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=test_case_6_sched_yield.c

/**
 * small test program whether signals between threads work as they should
 */

#include <unistd.h>
#include <pthread.h>
#include <signal.h>

void sighandler(int sig) {
	write(2,".",1);
	return;
}

void* threadstart(void* arg) {

	while (1) {
		sched_yield();
	}
}

int main(char** argc, int argv) {

	pthread_t testthread1;	
	struct sigaction action;

	action.sa_handler=sighandler;
	action.sa_flags=0;
	sigfillset( &action.sa_mask );
	sigaction(SIGUSR1,&action,NULL);

	pthread_create(&testthread1,NULL,threadstart,NULL);
	while (1) {
		pthread_kill(testthread1,SIGUSR1);
	}
}

--MP_//2QRbacSOBFpiqJpH/m8fPe
Content-Type: text/x-c++src
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=test_case_7_busy_waiting.c

/**
 * small test program whether signals between threads work as they should
 */

#include <unistd.h>
#include <pthread.h>
#include <signal.h>

void sighandler(int sig) {
	write(2,".",1);
	return;
}

void* threadstart(void* arg) {

	while (1) {
	}
}

int main(char** argc, int argv) {

	pthread_t testthread1;	
	struct sigaction action;

	action.sa_handler=sighandler;
	action.sa_flags=0;
	sigfillset( &action.sa_mask );
	sigaction(SIGUSR1,&action,NULL);

	pthread_create(&testthread1,NULL,threadstart,NULL);
	while (1) {
		pthread_kill(testthread1,SIGUSR1);
	}
}

--MP_//2QRbacSOBFpiqJpH/m8fPe
Content-Type: text/x-c++src
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=test_case_8_io.c

/**
 * small test program whether signals between threads work as they should
 */

#include <unistd.h>
#include <pthread.h>
#include <signal.h>

void sighandler(int sig) {
	write(2,".",1);
	return;
}

void* threadstart(void* arg) {
	char buf[1024];

	while (1) {
		read(1,buf,512);
	}
}

int main(char** argc, int argv) {

	pthread_t testthread1;	
	struct sigaction action;

	action.sa_handler=sighandler;
	action.sa_flags=0;
	sigfillset( &action.sa_mask );
	sigaction(SIGUSR1,&action,NULL);

	pthread_create(&testthread1,NULL,threadstart,NULL);
	while (1) {
		pthread_kill(testthread1,SIGUSR1);
	}
}


--MP_//2QRbacSOBFpiqJpH/m8fPe
Content-Type: text/plain; charset=us-ascii

--
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
--MP_//2QRbacSOBFpiqJpH/m8fPe--

- Raw text -


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