vendredi 31 mai 2019

Is it safe to initialize a c++11 function-static variable from a linux signal handler?

2 questions (below) about the C++11 static initialization at [1] in this reference code (this is a complete tested c++11 example program).

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

struct Foo {
    /* complex member variables. */
};

void DoSomething(Foo *foo) {
    // Complex, but signal safe, use of foo. 
}

Foo InitFoo() {
    Foo foo;
    /* complex, but signal safe, initialization of foo */
    return foo;
}

Foo* GetFoo() {
    static Foo foo = InitFoo();   // [1]
    return &foo;
}

void Handler(int sig) {
    DoSomething(GetFoo());
}

int main() {
    // [2]

    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_handler = Handler;
    sigaction(SIGINT, &act, nullptr);

    for (;;) {
        sleep(1);
        DoSomething(GetFoo());
    }
}

Question1: Is this guaranteed safe (no deadlocks etc)? C++11 static initialization involves locks. What if the signal is delivered before/after/during the first call to GetFoo() in main?

Question2: Is this guaranteed safe if a call to GetFoo() is inserted at [2] before the signal handler is installed?

I'm assuming C++11 (g++ or clang) on recent GNU/Linux, although answers for various Unices would also be interesting. (Spoiler: I think the answer is 1:NO and 2:YES but I don't know how to prove it.)

Aucun commentaire:

Enregistrer un commentaire