https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66146

--- Comment #3 from Martin Sebor <msebor at gcc dot gnu.org> ---
On Power, both glibc and AIX pthread_once behave the same way: i.e., they fail
to clear the once flag on exception.  The test case below mimics glibc's
pthread_once and demonstrates the root cause of the problem: the cancellation
handler is not invoked when an exception is thrown unless the
pthread_cleanup_push/pop macros are compiled in C++ code. Simply recompiling
glibc's pthread_once.c using a C++ compiler (and adding the apprpriate extern
"C" decoration) should fix it.

Until it's fixed, as a workaround, it seems that libstdc++ could clear the flag
when an exception is thrown before propagating it out of call_once.

$ cat t.c && gcc -O2 -Wall -c -fasynchronous-unwind-tables -g t.c && g++ -DMAIN
-O2 -Wall t.o -pthread t.c && ./a.out 
#include <pthread.h>
#include <stdio.h>

extern int n;

#if MAIN

extern "C" void foo () { throw 0; }
extern "C" void bar (void (*)());

int main () {
    try {
        bar (foo);
    }
    catch (...) {
        printf ("caught exception: pthread cleanup handler %sinvoked\n",
                n ? "" : "not ");
    }

    return n == 1 ? 0 : 1;
}

#else

int n;
#if __cplusplus
extern "C" {
#endif

static void cleanup (void *arg) { ++n; }

void bar (void (*pf)(void)) {
    pthread_cleanup_push (cleanup, 0);
    pf ();
    pthread_cleanup_pop (0);
}

#if __cplusplus
}
#endif

#endif
caught exception: pthread cleanup handler not invoked

Reply via email to