Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

try to fix the call_once hang up problem, and find out some clues. #6681

Closed
dzhwinter opened this issue Dec 17, 2017 · 3 comments
Closed

try to fix the call_once hang up problem, and find out some clues. #6681

dzhwinter opened this issue Dec 17, 2017 · 3 comments

Comments

@dzhwinter
Copy link
Contributor

This issue is only a clarify for the call_once implementation. After we find the stl call_once bug(detail in below), we switch to #5553 .

Our call_once implementation add a wrapper to std::call_once. The stl built-in call_once will hang up if the first call_once throw an exception.
In fact, even the example in cppreference http://en.cppreference.com/w/cpp/thread/call_once also will hang up with latest glibc environment.

#include <iostream>
#include <thread>
#include <mutex>
 
std::once_flag flag1, flag2;
 
void simple_do_once()
{
    std::call_once(flag1, [](){ std::cout << "Simple example: called once\n"; });
}
 
void may_throw_function(bool do_throw)
{
  if (do_throw) {
    std::cout << "throw: call_once will retry\n"; // this may appear more than once
    throw std::exception();
  }
  std::cout << "Didn't throw, call_once will not attempt again\n"; // guaranteed once
}
 
void do_once(bool do_throw)
{
  try {
    std::call_once(flag2, may_throw_function, do_throw);
  }
  catch (...) {
  }
}
 
int main()
{
    std::thread st1(simple_do_once);
    std::thread st2(simple_do_once);
    std::thread st3(simple_do_once);
    std::thread st4(simple_do_once);
    st1.join();
    st2.join();
    st3.join();
    st4.join();
 
    std::thread t1(do_once, true);
    std::thread t2(do_once, true);
    std::thread t3(do_once, false);
    std::thread t4(do_once, true);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

Try with reproduce command

g++ -std=c++11 -fexceptions test_call_once_pthread.cc -lpthread && gdb -batch -q -ex "catch signal SIGALRM" -ex r -ex bt ./a.out

Then it will give you the stack unwind result.

Program received signal SIGINT, Interrupt.
0x00007ffff7bc60f7 in futex_wait (private=0, expected=1, futex_word=0x55555575602c <once>) at ../sysdeps/unix/sysv/linux/futex-internal.h:61
61	../sysdeps/unix/sysv/linux/futex-internal.h: No such file or directory.
#0  0x00007ffff7bc60f7 in futex_wait (private=0, expected=1, futex_word=0x55555575602c <once>) at ../sysdeps/unix/sysv/linux/futex-internal.h:61
#1  futex_wait_simple (private=0, expected=1, futex_word=0x55555575602c <once>) at ../sysdeps/nptl/futex-internal.h:135
#2  __pthread_once_slow (once_control=0x55555575602c <once>, init_routine=0x555555554a7a <init_routine()>) at pthread_once.c:105
#3  0x0000555555554ae6 in main ()

It goes without saying std::call_once just call the pthread implementation. Need to note that pthread is part of glibc, which is the cornerstone of *nix family software. After skimming through glibc, find that the pthread_once is not protected correctly. Unfortunately, it has a mass code of register a child function to finish initialization, pthread_once was delivered by __libc_pthread_init.

This way seems blocked, but I find this fix patch which was submitted in 2015.
https://patchwork.ozlabs.org/patch/482350/

 316# Test expected to fail on most targets (except x86_64) due to bug
 317# 18435 - pthread_once hangs when init routine throws an exception.
 318test-xfail-tst-once5 = yes

But it gives another bad news, its test case cannot pass through in ubuntu16.04, x86 arch.

@tonyyang-svail
Copy link

tonyyang-svail commented Dec 18, 2017

@dzhwinter is this related to the fix at #6182?

@dzhwinter
Copy link
Contributor Author

@tonyyang-svail Yes.
Our call_once implement still has a flaw.

@dzhwinter
Copy link
Contributor Author

This issue give our a board view of call_once implementation in glibc, close it since it's not activated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants