public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
* sigpending() incorrectly returns signals pending on other threads
@ 2019-07-06 22:46 Kenton Varda
  2019-07-07  2:16 ` Kenton Varda
  2019-07-12 15:31 ` Corinna Vinschen
  0 siblings, 2 replies; 7+ messages in thread
From: Kenton Varda @ 2019-07-06 22:46 UTC (permalink / raw)
  To: cygwin

[-- Attachment #1: Type: text/plain, Size: 1033 bytes --]

Hello Cygwin,

According to the (Linux) man page: "sigpending() returns the set of
signals that are pending for delivery to the calling thread"

However, on Cygwin, sigpending() seems to return the set of signals
pending on any thread, as shown in the attached test program.

Among other things, this can cause deadlocks in programs which use
sigpending() to check for pending signals, then use sigsuspend() to
induce delivery of the specific signals that are pending. Because the
signal is not actually pending on the current thread, sigsuspend()
will unexpectedly block, potentially forever.

Output of test program:
$ uname -srv
CYGWIN_NT-6.1 3.0.7(0.338/5/3) 2019-04-30 18:08
$ gcc -std=c11 -Wall test-sigpending.c -o test-sigpending -pthread &&
./test-sigpending
sending signal to child thread with pthread_kill()...
sigpending() says signal is pending in main thread (WRONG)
sigpending() says signal is pending in child thread (CORRECT)
received signal in child thread (CORRECT)

The program works correctly on Linux.

-Kenton

[-- Attachment #2: test-sigpending.c --]
[-- Type: text/x-csrc, Size: 2518 bytes --]

#define _GNU_SOURCE 1

#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define sys(code) if ((code) < 0) { perror(#code); exit(1); }

pthread_t mainThread;
pthread_t childThread;

void handler(int signo, siginfo_t* siginfo, void* context) {
  if (pthread_equal(pthread_self(), mainThread)) {
    printf("received signal in main thread (WRONG)\n");
  } else if (pthread_equal(pthread_self(), childThread)) {
    printf("received signal in child thread (CORRECT)\n");
  } else {
    printf("received signal in other thread (?)\n");
  }
}

void* threadMain(void* param) {
  // Give main thread time to send us SIGUSR1.
  usleep(100000);

  // Check what signals are pending with sigpending().
  sigset_t pending;
  sys(sigpending(&pending));
  if (sigismember(&pending, SIGUSR1)) {
    printf("sigpending() says signal is pending in child thread (CORRECT)\n");
  } else {
    printf("sigpending() says signal is NOT pending in child thread (WRONG)\n");
  }

  // Unblock SIGUSR1 to see if it gets delivered.
  sigset_t mask;
  sys(sigemptyset(&mask));
  sys(sigaddset(&mask, SIGUSR1));
  sys(sigprocmask(SIG_UNBLOCK, &mask, NULL));

  return NULL;
}

int main() {
  // Register a signal handler for SIGUSR1.
  struct sigaction action;
  memset(&action, 0, sizeof(action));
  action.sa_sigaction = &handler;
  action.sa_flags = SA_SIGINFO;
  sys(sigaction(SIGUSR1, &action, NULL));

  // Block SIGUSR1.
  sigset_t mask;
  sys(sigemptyset(&mask));
  sys(sigaddset(&mask, SIGUSR1));
  sys(sigprocmask(SIG_BLOCK, &mask, NULL));

  // Start child thread.
  mainThread = pthread_self();
  if (pthread_create(&childThread, NULL, &threadMain, NULL) < 0) {
    fprintf(stderr, "pthread_create failed\n");
    exit(1);
  }

  // Send SIGUSR1 to child thread.
  printf("sending signal to child thread with pthread_kill()...\n");
  if (pthread_kill(childThread, SIGUSR1) < 0) {
    fprintf(stderr, "pthread_kill failed\n");
    exit(1);
  }

  // Check if sigpending() returns SIGUSR1.
  sigset_t pending;
  sys(sigpending(&pending));
  if (sigismember(&pending, SIGUSR1)) {
    printf("sigpending() says signal is pending in main thread (WRONG)\n");
  } else {
    printf("sigpending() says signal is NOT pending in main thread (CORRECT)\n");
  }

  // Unblock SIGUSR1 to see if it gets delivered to this thread.
  sys(sigemptyset(&mask));
  sys(sigaddset(&mask, SIGUSR1));
  sys(sigprocmask(SIG_UNBLOCK, &mask, NULL));

  pthread_join(childThread, NULL);
}


[-- Attachment #3: Type: text/plain, Size: 219 bytes --]


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

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-07-15  9:54 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-06 22:46 sigpending() incorrectly returns signals pending on other threads Kenton Varda
2019-07-07  2:16 ` Kenton Varda
2019-07-12 15:34   ` Corinna Vinschen
2019-07-14 13:19     ` Houder
2019-07-15  7:53       ` Corinna Vinschen
2019-07-15  9:54         ` Houder
2019-07-12 15:31 ` Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).