mardi 12 avril 2022

C++ - User-Level Threads - sigaction by SIGVTALRM

I've found some evil bug in my user-level threads library.

My scheduler is actually a singleton class that initializes a signal timer this way:

  • sigAlarm_ is a member field of the scheduler, and its of type struct sigaction.

  • This is the related part of the scheduler initialization:

    sigAlarm_.sa_handler = timerHandlerGlobal; // Assign the first field of sigAlarm (sa_handler) as needed, others zeroed

    if (sigaction(SIGVTALRM, &sigAlarm_, nullptr) != 0) { uthreadSystemError("sigaction"); }

Now, this timerHandlerGlobal is a static function, and not a member function of the scheduler, as C++ doesn't permit passing function members this way.

Now, when I terminate the main thread of the library (which actually runs the scheduler), I'm invoking std::exit(1) which cleans the resources up.

When I'm running my tests with ASan (Address Sanitizer), in some executions, it gets into the timerHandlerGlobal while the scheduler is already nullptr! Now, I've been already two days on that, inspecting what's the cause.

Now I see that if I'm adding this ugly condition, no problem appears with ASAN:

void timerHandlerGlobal(int signo)
{
    if (scheduler_manager)
    {
        scheduler_manager->timerHandler(signo);
    }
}

But, why is after std::exit(1) invoked by the scheduler, the sigaction.sa_handler (which is timerHandlerGlobal), is still running? Please tell me you know why it is, I just want to omit this awful condition.

Aucun commentaire:

Enregistrer un commentaire