This is the mail archive of the
cygwin
mailing list for the Cygwin project.
RE: pthread_kill: signals remain pending after target thread exits
- From: John Carey <aeolus at electric-cloud dot com>
- To: "cygwin at cygwin dot com" <cygwin at cygwin dot com>
- Date: Tue, 27 Oct 2015 19:06:39 +0000
- Subject: RE: pthread_kill: signals remain pending after target thread exits
- Authentication-results: sourceware.org; auth=none
- References: <28F5B565B6F6424C87E4AC0DCC84316575D71070 at S1P5DAG5C dot EXCHPROD dot USA dot NET> <20151021114810 dot GQ5319 at calimero dot vinschen dot de> <28F5B565B6F6424C87E4AC0DCC84316575D73A86 at S1P5DAG5C dot EXCHPROD dot USA dot NET>,<20151023125540 dot GI5319 at calimero dot vinschen dot de>
Sorry for the delay.
From: Corinna Vinschen [corinna-cygwin@cygwin.com]
Sent: Friday, October 23, 2015 5:55 AM
> > I've attached a test case that I *think* gets into the right spot, at
> > least for 64-bit Cygwin 2.0.4. That is, it hangs trying to receive
> > the signal, instead of terminating. (This test passes (terminates) in
> > 32-bit Cygwin 1.7.9 and 64-bit Ubuntu 14.04.3 LTS.)
>
> Thanks for the testcase. I applied a patch which hopefully works as
> desired, at least to fix the immediate problem of the remaining pending
> signal when a thread exits. I uploaded a new developer snapshot to
> https://cygwin.com/snapshots. Please give it a try.
Thanks; that was fast! I tried replacing cygwin1.dll with cygwin1-20151023.dll .
The original test case now works. I checked some of my other tests,
and unfortunately some of them failed, so I extracted out a new test
case, which is attached. My guess is that something is subtly different
about the timing on this test.
This new test hangs about half the time, and I have to use Windows Task Manager
to kill it (not Cygwin "kill"). Sometimes I see "pthread_kill: Unknown error -1" while
it hangs (meaning that pthread_kill returned -1 instead of an error number).
> > > > - Multiple pending signals targeting different threads could
> > > > coexist, even if they shared the same signal number. This happens
> > > > on Linux (Ubuntu 14.04.3), where I can generate two signals for two
> > > > different threads, then sleep for a bit in each target thread, and
> > > > finally have each thread receive its signal with sigwait()--neither
> > > > signal is lost during the sleeping period.
> > >
> > > That requires to extend the handling for pending signals. That's
> > > a rather bigger task...
> >
> > Yeah. It's nice if threads don't interfere with each other, but this
> > part would indeed be harder to change.
>
> I added that to my neverending TODO list. Maybe I get around to it at
> one point.
I know the feeling. No worries, and thanks.
-- John Carey
/* Copyright (c) 2015, Electric Cloud, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* This test program demonstates a Cygwin bug in which a signal sent
* to a particular thread remains pending after the thread terminates.
*
* Somehow even though the original fix worked for test_pending_signal.c,
* about half the time this test case triggers a hang that must be killed
* using the Windows Task Manager instead of Cygwin "kill". Sometimes we
* see "pthread_kill: Unknown error -1" during the hang.
*/
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
static void check_syscall(char const *context, int result)
{
if (result == -1) {
fprintf(stderr, "%s: %s\n", context, strerror(errno));
exit(EXIT_FAILURE);
}
}
static void check_threadcall(char const *context, int error_number)
{
if (error_number) {
fprintf(stderr, "%s: %s\n", context, strerror(error_number));
exit(EXIT_FAILURE);
}
}
typedef struct shared_struct {
sigset_t signal_mask; /* signals to block */
pthread_mutex_t mutex;
pthread_cond_t cond;
int eat;
int done;
} shared_t;
static void *phage_thread (void *arg)
{
shared_t *shared = (shared_t *)arg;
check_threadcall("pthread_mutex_lock",
pthread_mutex_lock(&shared->mutex));
if (shared->eat <= 1) {
shared->eat = 1;
check_threadcall("pthread_cond_broadcast",
pthread_cond_broadcast(&shared->cond));
while (shared->eat <= 1) {
check_threadcall("pthread_cond_wait",
pthread_cond_wait(&shared->cond, &shared->mutex));
}
}
check_threadcall("pthread_mutex_unlock",
pthread_mutex_unlock(&shared->mutex));
return NULL;
}
static void *signal_thread (void *arg)
{
shared_t *shared = (shared_t *)arg;
int sig_caught;
int ern;
check_threadcall("sigwait",
sigwait(&shared->signal_mask, &sig_caught));
if (sig_caught == SIGUSR2) {
puts("Received SIGUSR2");
fflush(stdout);
} else {
fprintf (stderr, "\nUnexpected signal %d\n", sig_caught);
}
check_threadcall("pthread_mutex_lock",
pthread_mutex_lock(&shared->mutex));
shared->done = 1;
check_threadcall("pthread_cond_broadcast",
pthread_cond_broadcast(&shared->cond));
check_threadcall("pthread_mutex_unlock",
pthread_mutex_unlock(&shared->mutex));
return NULL;
}
int main(int argc, char **argv)
{
shared_t *shared = (shared_t *)malloc(sizeof(shared_t));
pthread_t phage_tid, signal_tid;
struct timespec ts;
int ern;
sigemptyset(&shared->signal_mask);
sigaddset(&shared->signal_mask, SIGUSR2);
check_threadcall("pthread_mutex_init",
pthread_mutex_init(&shared->mutex, NULL));
check_threadcall("pthread_cond_init",
pthread_cond_init(&shared->cond, NULL));
check_threadcall("pthread_sigmask",
pthread_sigmask(SIG_BLOCK, &shared->signal_mask, NULL));
shared->eat = 0;
shared->done = 0;
check_threadcall("pthread_create",
pthread_create(&phage_tid, NULL, phage_thread, shared));
check_threadcall("pthread_mutex_lock",
pthread_mutex_lock(&shared->mutex));
while (shared->eat == 0) {
check_threadcall("pthread_cond_wait",
pthread_cond_wait(&shared->cond, &shared->mutex));
}
check_threadcall("pthread_kill",
pthread_kill(phage_tid, SIGUSR2));
shared->eat = 2;
check_threadcall("pthread_cond_broadcast",
pthread_cond_broadcast(&shared->cond));
check_threadcall("pthread_mutex_unlock",
pthread_mutex_unlock(&shared->mutex));
check_threadcall("pthread_join",
pthread_join(phage_tid, NULL));
check_threadcall("pthread_create",
pthread_create(&signal_tid, NULL, signal_thread, shared));
check_threadcall("pthread_mutex_lock",
pthread_mutex_lock(&shared->mutex));
for (;;) {
if (shared->done) {
check_threadcall("pthread_join",
pthread_join(signal_tid, NULL));
break;
} {
ern = pthread_kill(signal_tid, SIGUSR2);
if (ern != ESRCH) {
check_threadcall("pthread_kill", ern);
}
check_syscall("clock_gettime",
clock_gettime(CLOCK_REALTIME, &ts));
ts.tv_nsec += 100000000;
if (ts.tv_nsec >= 1000000000) {
ts.tv_nsec -= 1000000000;
ts.tv_sec += 1;
}
check_threadcall("pthread_cond_timedwait",
pthread_cond_timedwait(&shared->cond, &shared->mutex, &ts));
}
}
check_threadcall("pthread_mutex_unlock",
pthread_mutex_unlock(&shared->mutex));
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