Join GitHub today
mcfgthread is an experimental support library for MinGW targets of GCC, providing basic
HANDLE-style thread manipulation, as well as native and lightweight in-process synchronization primitives including mutexes, condition variables and once-initialization flags. These synchronization primitives, being as lightweight as those on Linux which rely on futex, consume few resources. In particular, they consume no resources other than the bytes they reside in.
It turns out that Microsoft has plagiarized the Linux futex somehow, however these APIs are available only since Windows 8.
Windows 7 has the awesome slim reader/writer (SRW) locks, condition variables and one-time initialization, which, as usual, are over-specific for Microsoft people's own usage. Their SRW locks do not support timed waits and their condition variables do not support any mutexes other than SRW locks or critical sections.
Behind SRW locks and condition variables are the keyed events, a powerful but otherwise not officially documented feature described in articles from Lockless Inc. and Joe Duffy's Blog. If Microsoft people haven't implemented timed mutexes or generic condition variables, then it is we that should implement them.
In addition to the set of native interfaces (those with the common prefix
_MCFCRT_), a set of
__gthread_* interfaces (implementation of most threading support in GCC libraries) and another set of C11 interfaces are provided, providing full threading support for GCC.
Notes on Integration with GCC
If you wish to use mcfgthread without hacking GCC, you can use these APIs directly. You just need to install these headers and libraries, then write your program and compile and link it with
-lmcfgthread, as what you typically do with other libraries.
If you wish to have GCC make use of mcfgthread, you must hack GCC source and build GCC from it, which is described below. It should be noted that certain construction of GCC and GCC libraries, for example,
__thread, the C11
_Thread_local, the C++11
thread_localand the C++ exception handler, would require a gthread library to work. This is usually done with a header that redirects
__gthread_*()calls to other libraries such as winpthreads or the gthr-win32.c one in libgcc, and here it is mcfgthread that does the trick.
According to the C11 standard, an implementation may, but is not otherwise required to, generate
SIGTERM, except as a result of explicit calls to the
raise()function. With a mcfgthread library that uses Windows SEH, such signals are not guaranteed to be generated, except as a result of explicit calls to the
raise()function. In particular, the mingw-w64 CRT sets up a top-level exception handler upon program startup, which translates specific exceptions caught by SEH into signals. If you replace it using the
SetUnhandledExceptionFilter()function, these exceptions, when generated by a thread created by
thrd_create(), will not be translated into signals and will result in immediate abnormal termination.
How to Integrate with GCC
Depending on whether you are using a toolchain targeting x86 or x64, copy the contents of
release/mingw64to the prefix directory of your toolchain (for example, saying your
/foo/bar/bin, the prefix directory is
/foo/bar). The contents of directories
libshould merge with those of existent ones.
[ N.B. The prefix directories for x86 and x64 toolchain packages from the MSYS2 project are
/mingw64, respectively. ]
Patch GCC source code. This is usually done with
git am. Different patches have been created for different branches. Patches available are:
Configure GCC with option
--enable-threads=mcf, but without
--enable-languages=, as Objective-C interfaces are currently unimplemented and will cause libobjc to fail to build.
makeit as usual.
At the moment, mcfgthread can't be linked statically and the file
libmcfgthread.a is a copy of
libmcfgthread.dll.a. Hence, if you want to distribute a program linked againast mcfgthread, you must always distribute
mcfgthread-*.dll with it.
The reason why mcfgthread can't be linked statically is a bit complex:
The gthread and c11 thread interfaces use global AVL trees to translate thread IDs into
*_detach()calls, which would be problematic if mcfgthread was linked statically, since each dynamic library as well as the executable would have a separated map. As a result, calls to such functions have to be done in the same module that has created the thread, otherwise they will fail with
It is essential to use the DLL entry point function to clean up TLS objects and invoke thread exit callbacks. Without a dynamic library (for example, when mingw-w64 is linked statically), a TLS callback is an option but it would require an
IMAGE_TLS_DIRECTORYto work. The mingw-w64 CRT places it in one of the startup files (crt?.o). It is also possible to place it in a static library then reference it somewhere in the startup files (if it is not referenced, the linker will ignore it or strip it). In both cases the startup code has to be modified which requires extra inter-project work that I am not very willing to bother myself to do.