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]

Re: Sending SIGUSR1 to thread in nanosleep causes segfault


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.

/**
 * 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);
	}
}
/**
 * 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);
	}
}
/**
 * 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);
	}
}
/**
 * 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);
	}
}
/**
 * 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);
	}
}
/**
 * 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);
	}
}
/**
 * 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);
	}
}
/**
 * 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);
	}
}

--
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]