[PATCH] Cygwin: signa: Redesign signal queue handling

Christian Franke Christian.Franke@t-online.de
Fri Mar 7 16:35:23 GMT 2025


Christian Franke wrote:
> Takashi Yano wrote:
>> The previous implementation of the signal queue behaves as:
>> 1) Signals in the queue are processed in a disordered manner.
>> 2) If the same signal is already in the queue, new signal is discarded.
>>
>> Strictly speaking, these behaviours do not violate POSIX. However,
>> these could be a cause of unexpected behaviour in some software. In
>> Linux, some important signals such as SIGSTOP/SIGCONT do not seem to
>> behave like that.
>>
>> With this patch prevents all signals from that issues by redesigning
>> the signal queue, Only the exception is the case that the process is
>> in the PID_STOPPED state. In this case, SIGCONT/SIGKILL should be
>> processed prior to the other signals in the queue.
>>
>> Addresses:https://cygwin.com/pipermail/cygwin/2025-March/257582.html
>> ...
>
> A quick test with many runs of 'lostsig' testcase with or without 
> 'taskset 0x1' no longer shows any problems. No SIGALRM were lost (not 
> required), [SIGTERM] is always printed after all [SIGALRM] (not 
> required), SIGCONT is never lost. The previous 'timersig' testcase 
> also still succeeds.
>
>

Unfortunately with another testcase (attached) without SIGSTOP/CONT but 
two different signals sent in a loop it does not work:

$ ./swapsigs
remaining 5
1891: fork()=1892
SIGALRM 0
remaining 4
SIGTERM 0
SIGALRM 1
SIGTERM 1
SIGALRM 2
[ALRM]
SIGTERM 2
SIGALRM 3
SIGTERM 3
SIGALRM 4
[TERM]
SIGTERM 4
[ALRM]
SIGALRM 5
SIGTERM 5
SIGALRM 6
SIGTERM 6
[TERM]
[ALRM]
SIGALRM 7
... both processes hang ...

Could not be reproduced with 'taskset 0x1' or with original 
3.6.0-0.423.ga3863bfeb73f.x86_64.

-- 
Regards,
Christian



-------------- next part --------------
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>

static volatile sig_atomic_t sigcnt1, sigcnt2;

static void sighandler1(int sig)
{
  (void)sig;
  ++sigcnt1;
  write(1, "[ALRM]\n", 7);
}

static void sighandler2(int sig)
{
  (void)sig;
  ++sigcnt2;
  write(1, "[TERM]\n", 7);
}

int main()
{
  pid_t pid = fork();
  if (pid == (pid_t)-1) {
    perror("fork"); return 1;
  }

  if (!pid) {
    signal(SIGALRM, sighandler1);
    signal(SIGTERM, sighandler2);

    time_t start = time(NULL), t = 5;
    do {
      printf("remaining %d\n", t); fflush(stdout);
      sleep(1);
      t -= time(NULL) - start;
    } while (t > 0);

    printf("%d: %d SIGALRM %d SIGTERM received, exit(42)\n",
      (int)getpid(), sigcnt1, sigcnt2);
    fflush(stdout);
    _exit(42);
  }

  printf("%d: fork()=%d\n", (int)getpid(), (int)pid);
  sleep(1);

  const int n = 10;
  for (int i = 0; i < n; i++) {
    const union sigval sv = {0};
    printf("SIGALRM %d\n", i); fflush(stdout);
    if (sigqueue(pid, SIGALRM, sv))
      perror("SIGALRM");
    printf("SIGTERM %d\n", i); fflush(stdout);
    if (sigqueue(pid, SIGTERM, sv))
      perror("SIGTERM");
  }

  printf("waitpid()...\n"); fflush(stdout);
  int status = -1;
  int wp = waitpid(pid, &status, 0);
  printf("waidpid()=%d, status=0x%04x\n", wp, status);
  return 0;
}


More information about the Cygwin-patches mailing list