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