Sorry for the delay. From: Corinna Vinschen [corinna-cyg...@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