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

Reply via email to