Hello,

I found a deadlock in cygwin1.dll that occurs during process cleanup.

It happens when the following conditions are met:
- A thread is launched that will initialize the thread_local slot for a variable whose destructor is non-trivial. - The main thread waits to join that thread during global destructor calls, before the thread has initialized the thread_local slot.

The former condition refers to a function-scope static thread_local variable, or a global thread_local variable whose name has not yet been referenced by any thread.

Here is a reproducer (the same file is attached), compile with g++ 13.4.0 regardless of optimization, and run under cygwin 3.6.5-1
---------------------------------------------

#include <thread>

struct the_type {
  ~the_type() {}
};
struct myjthread {
  template <typename F>
  myjthread(F f): thr(f) {}
  ~myjthread() { thr.join(); }
  std::thread thr;
};

thread_local the_type g_v;


int main() {
// if main thread accesses the thread_local variable first, pattern2 doesn't matter
  //g_v = {};
  static myjthread t([] {
//std::this_thread::sleep_for(std::chrono::seconds(1)); //< this sleep might increase reproducibility

    // pattern1: static thread_local
    static thread_local the_type s_v;

    // pattern2: global thread_local; its slot is allocated in this thread
    //g_v = {};
  });
}

---------------------------------------------

This issue was observed as a random hang in the LLVM test suite.

Although the triggering thread_local variable in LLVM can be removed, I hope the runtime can be fixed.

Regards,

--
Tomohiro Kashiwada (@kikairoya)

#include <thread>

struct the_type {
  ~the_type() {}
};
struct myjthread {
  template <typename F>
  myjthread(F f): thr(f) {}
  ~myjthread() { thr.join(); }
  std::thread thr;
};

thread_local the_type g_v;

int main() {
  // if main thread accesses the thread_local variable first, pattern2 doesn't 
matter
  //g_v = {};
  static myjthread t([] {
    //std::this_thread::sleep_for(std::chrono::seconds(1)); //< this sleep 
might increase reproducibility

    // pattern1: static thread_local
    static thread_local the_type s_v;

    // pattern2: global thread_local; its slot is allocated in this thread
    //g_v = {};
  });
}
-- 
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple

Reply via email to