[Gc] Problems with GC_INIT and GC_WIN32_THREADS under mingw

Boehm, Hans hans_boehm@hp.com
Fri, 8 Aug 2003 17:07:41 -0700

> -----Original Message-----
> From: Stewart Greenhill [mailto:sgreenhill@iprimus.com.au]
> Hi,
> I'm trying to make a threaded GC for Win32 using GNU mingw32 
> (gcc 3.2). 
> It looks like the documentation is rather old, and I've had to 
> experiment quite a bit to get it working.
> For the moment, I'm building a statically linked application. I added 
> -DGC_WIN32_THREADS to the CFLAGS for the library and client builds.
> Problem #1.
> In win32_threads.c the compiler complains about the redeclaration of 
> GC_CreateThread, so I changed:
>    HANDLE WINAPI GC_CreateThread(
> to:
>    GCAPI HANDLE GC_CreateThread(
> WIth that fix, it will compile and link, and gctest runs OK.
Thanks.  That was recently reported on the gcj mailing list and fixed in my version.
> Problem #2.
> My application linked to the library crashes in 
> GC_REGISTER_DISPLACEMENT. Eventually, I traced this down to LOCK() 
> which is defined to EnterCriticalSection which is operating on an 
> uninitialised Win32 CRITICALSECTION variable. It looks like this is 
> supposed to be initialised in GC_init. However, the application calls 
> GC_INIT and this is not correctly being redirected to GC_init in gc.h.
> I guess there are a number of workarounds possible here:
> - have the application call GC_init rather than GC_INIT
> - adjust gc.h to redirect GC_INIT to GC_init
> - explore other options for LOCK() that don't require initialisation
> My questions:
> Assuming gcc for Win32, are critical sections the preferred 
> implementation for LOCK()?
> Under what circumstances should GC_init be called? It seems that in 
> most cases, the GC can be used without initialisation, except in this 
> kind of situation. I guess this is probably the place where 
> things need 
> to be fixed.
The current convention is supposed to be:

1) GC_init() is called to explicitly initialize the collector.  This is documented to be needed only if thread-local allocation is used.  Otherwise this can be and is done with minimal overhead during the first allocation.

2) GC_INIT() is an ugly workaround for platforms that insist you do something from the main program as opposed to a dynamic libarary, typically because a linker-defined symbol like &end or &etext has a different value when seen from a dynamic library.  If you need to support one or more of these platforms, you need to invoke this FROM THE MAIN PROGRAM.

Looking at this now, I think the documentation for GC_init() is wrong.  With win32 threads, it needs to be called explicitly.  I just changed the comment.  I also defined GC_INIT() to do GC_init() for GC_WIN32_THREADS.

It would probably be better to build a spin-yield-sleep lock out of atomic exchanges, analogously to the one implemented in pthread_support.c.  Locks that can't be statically initialized are a pain, and it's probably best just to avoid them.