ivmai / bdwgc

The Boehm-Demers-Weiser conservative C/C++ Garbage Collector (bdwgc, also known as bdw-gc, boehm-gc, libgc)
https://www.hboehm.info/gc/
Other
2.94k stars 405 forks source link

GC_allow_register_threads get stuck when it's called implicitly when DLL is loaded (on Windows) #659

Open butterunderflow opened 2 weeks ago

butterunderflow commented 2 weeks ago

Recently, I try to make bdwgc get initialized when I load a library, so I wrote these code in my shared library test.cpp:

#include <iostream>
extern "C" {
extern void GC_init();
extern void GC_allow_register_threads();
}
void test() { std::cout << "Hello! I'm from a dll lib" << std::endl; }

class dllInitializer {
public:
  dllInitializer() {
    GC_init();
    GC_allow_register_threads();
  }
};
dllInitializer dllInitializerInstance;

and compile it to a dll library like this(the bdwgc/build/libgc.dll is compiled by cmake toolchain):

g++ test.cpp bdwgc/build/libgc.dll -o libtest.dll --shared

But unfortunately, when I load this library from my main executable main.cpp:

// compile this file with: 
//      g++ main.cpp libtest.dll -o main.exe

#include <cstdio>
void test();

int main()
{
    printf("Started!\n");
    test();
}

it get stuck:

$ ./main.exe
# it just hangs there

Then I enter gdb, it shows some information now, but the process still hangs, which looks like a dead lock:

GNU gdb (GDB) 11.2
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-w64-mingw32".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from main.exe...
(gdb) run
Starting program: <path-to-exe's-dir>main.exe
[New Thread 8116.0xae4c]
[New Thread 8116.0x7914]
[New Thread 8116.0x4e4c]
[New Thread 8116.0xa018]
[New Thread 8116.0x28dc]
[New Thread 8116.0x570]
[New Thread 8116.0x9cc0]
[New Thread 8116.0x7184]
[New Thread 8116.0x8324]
[New Thread 8116.0x6d60]
[New Thread 8116.0x7fd4]
[New Thread 8116.0xb0a0]
[New Thread 8116.0xa73c]
[New Thread 8116.0x7ad4]

Any help or suggestion is appreciated!

PS

The build configuration of bdwgc:

 cmake -B build -Denable_disclaim=ON -Denable_atomic_uncollectable=ON -Denable_java_finalization=ON -Denable_mmap=ON -Denable_munmap=ON -Denable_threads=ON -Denable_parallel_mark=ON -Denable_thread_local_alloc=ON  -DCMAKE_USE_WIN32_THREADS_INIT=true -G "MinGW Makefiles"
butterunderflow commented 2 weeks ago

I created a repository to reproduce the behavior in this issue. I hope that will illustrate my question more clear.

https://github.com/butterunderflow/bdwgc-issue-659-reproduce

ivmai commented 2 weeks ago

Is this reproduced on bdwgc master?

butterunderflow commented 2 weeks ago

Is this reproduced on bdwgc master?

I just tried on the latest master, the program still stuck at dll loading.

butterunderflow commented 6 days ago

Would anyone help me verify if this is a bug or if some configuration of mine is wrong?

ivmai commented 6 days ago

As mentioned in win32_threads.c, code invoked from a dll initializer should be lock-free, but code of GC_allow_register_threads() is not. I think, if you want to perform the GC initialization implicitly, you should compile bdwgc with -Denable_threads_discovery=ON and remove GC_init and GC_allow_register_threads() calls.