Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 31 Jan 2015 00:12:25 +0000
From:      bugzilla-noreply@freebsd.org
To:        freebsd-bugs@FreeBSD.org
Subject:   [Bug 197216] incorrect signal delivery for linux apps
Message-ID:  <bug-197216-8@https.bugs.freebsd.org/bugzilla/>

next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=197216

            Bug ID: 197216
           Summary: incorrect signal delivery for linux apps
           Product: Base System
           Version: 11.0-CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: freebsd-bugs@FreeBSD.org
          Reporter: henry.hu.sh@gmail.com

FreeBSD's Linux emulation tries to translate between Linux signals and FreeBSD
signals. However, this is not a one-to-one mapping, which results in some
incorrect behavior.

For example, if an application sets a signal handler for SIGPWR(30), and sends
SIGPWR to itself, then the signal handler would be called, but the signal
number passed in is not 30, but 23(SIGURG).
The reason is that FreeBSD translates Linux's SIGPWR(30) to FreeBSD's
SIGURG(16), but FreeBSD's SIGURG(16) is translated back to Linux's SIGURG(23).
A simple test program:

#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

const int SIGNAL_TO_TEST = SIGPWR;

void handler(int signum) {
    if (signum != SIGNAL_TO_TEST) {
        printf("Error! got signal %d expected %d\n", signum, SIGNAL_TO_TEST);
    } else {
        printf("Got signal %d as expected\n", signum);
    }
}

int main() {
    struct sigaction sigact;
    sigact.sa_handler = handler;
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    if (sigaction(SIGNAL_TO_TEST, &sigact, NULL) == -1) {
        perror("fail to call sigaction");
    }

    kill(getpid(), SIGNAL_TO_TEST);

    sleep(1);
}

It should output

Got signal 30 as expected

but on FreeBSD it says

Error! got signal 23 expected 30

instead.

A real example can be found at 
https://github.com/mono/mono/blob/master/libgc/pthread_stop_world.c
where it uses SIG_SUSPEND to pause threads. SIG_SUSPEND is defined to be
SIGPWR.
The signal handler checks the value of signal passed in:
  if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");

A reasonable fix would be mapping SIGPWR to some currently unmapped FreeBSD
signal, like SIGEMT. Although it's not completely correct in semantics, at
least it works for signal delivery between Linux applications.

For the uncommon signals like SIGURG and SIGPWR, usually they are not sent
between FreeBSD and Linux applications. I think that we'd better keep them
working as expected when being sent between Linux applications.

-- 
You are receiving this mail because:
You are the assignee for the bug.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-197216-8>