https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84323
Bug ID: 84323 Summary: call_once uses TLS even when once_flag is set Product: gcc Version: 7.3.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: antoshkka at gmail dot com Target Milestone: --- Disassembly of the following code: #include <mutex> std::once_flag once; int* foo() { static int* p{}; std::call_once(once,[](){ p = 0; }); return p; } shows that a lot of work is going on the hot path. TLS is used (twice) and there is a function call: mov QWORD PTR [rsp+8], rax mov rax, QWORD PTR std::__once_callable@gottpoff[rip] mov QWORD PTR fs:[rax], rdx mov rax, QWORD PTR std::__once_call@gottpoff[rip] mov QWORD PTR fs:[rax], OFFSET FLAT:void std::call_once<foo()::{lambda()#1}>(std::once_flag&, foo()::{lambda()#1}&&)::{lambda()#2}::_FUN() mov eax, OFFSET FLAT:__gthrw___pthread_key_create(unsigned int*, void (*)(void*)) test rax, rax je .L6 mov esi, OFFSET FLAT:__once_proxy mov edi, OFFSET FLAT:once call __gthrw_pthread_once(int*, void (*)()) This seems to be suboptimal, as double-checked-like locking could be used without TLS + 'call' usage on a hot path. std::call_once could be implemented just like thread safe static local variables resulting in a much better disassembly on a hot path: movzx eax, BYTE PTR once test al, al je .L9 ; not called