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



#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;
}

Reply via email to