How does cgo handle signals?
Asked Answered
P

1

15

I ran into a problem where the Go program uses a .so lib, and the c code needs to deal with a signal SIGALRM. But it seems that once a signal SIGALRM is released, the program crashes. From "The Go Programming Language" I see this:

If the non-Go code installs any signal handlers, it must use the SA_ONSTACK flag with sigaction. Failing to do so is likely to cause the program to crash if the signal is received.

Can anyone please show the correct usage of SA_ONSTACK flag with sigaction. I would appreciate it very much.

Below is my code:

// LIC_TIMER_CALLBACK_FUNC is a function pointer

static LIC_TIMER_CALLBACK_FUNC s_pfnTmCallBack;

static void _OS_TriggerTask(int iSig)
{
    logInfo("_OS_TriggerTask start...");
    if (LIC_NULL_PTR != s_pfnTmCallBack)
    {
        logInfo("call timer callback...");
        s_pfnTmCallBack(0);    
    }
    logInfo("_OS_TriggerTask end...");
}

// set the trigger
int OS_StartTrigger(int ulLength, LIC_TIMER_CALLBACK_FUNC pfnTmCallBack)
{    
    logInfo("OS_StartTrigger start...");

s_pfnTmCallBack = pfnTmCallBack;

struct sigaction stSigact; 

stSigact.sa_handler = _OS_TriggerTask;
stSigact.sa_flags   = SA_ONSTACK;
sigemptyset(&stSigact.sa_mask);
int iRet = sigaction(SIGALRM, &stSigact, NULL);

if(0 != iRet)
{
    logError("set signal failed...");
}
else
{
    logInfo("set signal success...");
}

/* set time interval */
struct itimerval stItimerVal;
stItimerVal.it_value.tv_sec = 60;
stItimerVal.it_value.tv_usec = 0;
stItimerVal.it_interval = stItimerVal.it_value;

iRet = setitimer(ITIMER_REAL, &stItimerVal, NULL);

if(0 != iRet)
{
    logError("set timer failed...");
    return -1;
}

logInfo("OS_StartTrigger end...");
return 0;
}
Phraseograph answered 18/12, 2017 at 13:55 Comment(5)
This may help: https://mcmap.net/q/826595/-go-get-signal-origin/…Supernal
I run your code on Ubuntu17.10 x64, Go1.8.3, and its work very well. Even I add GoRoutine on go side.Protestantism
which OS are you running your code?Frankel
I've seen ...sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART; used successfully.Maladjusted
I think this is specific enough that for reproduction certainty we need to know the system and go version.Telles
M
1

Looks like there is an test in the Go repository that has what you need. The test works like this: main.c is meant to test signal handling in cgo for all distros. Looking at the handlers for unix distros (main_unix.c), you get:

int install_handler() {
    // Install our own signal handler.
    memset(&sa, 0, sizeof sa);
    sa.sa_sigaction = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
    memset(&osa, 0, sizeof osa);
    sigemptyset(&osa.sa_mask);
    if (sigaction(SIGSEGV, &sa, &osa) < 0) {
        perror("sigaction");
        return 2;
    }
    if (osa.sa_handler == SIG_DFL) {
        fprintf(stderr, "Go runtime did not install signal handler\n");
        return 2;
    }
    // gccgo does not set SA_ONSTACK for SIGSEGV.
    if (getenv("GCCGO") == NULL && (osa.sa_flags&SA_ONSTACK) == 0) {
        fprintf(stderr, "Go runtime did not install signal handler\n");
        return 2;
    }
    oldHandler = osa.sa_sigaction;

    return 0;
}

Now the test is adding handlers to SIGSEGV, so replace that with the signal in question.

Minerva answered 10/1, 2023 at 16:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.