
On Sun, 01 Aug 2004 16:41:18 -0500 "Aaron W. LaFramboise" <aaronrabiddog51@aaronwl.com> wrote:
Just as a FYI, I now have a copy of MSVC6, and am working on this.
MSVC6 does, in fact, have the necessary support, but there is a bug (I had noticed this before, and this was one of the reasons I wasn't able to offer more information a few months ago, and I had entirely forgotten about it. Oops.). Fortunately, the bug is in the runtime library, not in the linker or anything else.
Yes the bug is, that the TLS handlers must be in a contiguous area between the __xl_a and __xl_z symbols. I fixed this by running a small piece of code during the startup (in __xi_a .. __xi_z area). Finally I wrapped everything up into a small C file that either can be bound to boost or be linked with the user application. Despite now having everything in a single file, I think boost still should not give away the possibility of letting the user code call the process/thread startup/termination hooks directly. There always might be some code that needs this. Thanks to Aaron now now have a TLS solution that can handle any thread creation mechansim, while still reside in a statically bound library. The tsstls.c file follows: To test it compile your application with BOOST_THREAD_USE_LIB /* Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. This piece of code is a result of the work of: Aaron W.LaFramboise, who showed how to implement TLS-callback Michael Glassford, who factored out the startup code Bronek Kozicki, who showed me, that it is not harmful to access the CRT after thread end Roland Schwarz, who did the writing, runtime initialization (.CRTXxx), correct dtor behaviour and broken MSVC 6 fix 08.02.2004 */ #include <stdlib.h> #define WIN32_LEAN_AND_MEAN #include <windows.h> typedef void (__cdecl *_PVFV)(void); typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID); /* some symbols for connection to the runtime environment */ extern IMAGE_TLS_DIRECTORY _tls_used; /* the tls directory (located in .rdata segment) */ extern _TLSCB __xl_a[], __xl_z[]; /* tls initializers */ /* the boost tss startup interface */ extern void on_process_enter(void); extern void on_process_exit(void); extern void on_thread_exit(void); /* some forward declarations */ static void on_tls_prepare(void); static void on_process_init(void); static void NTAPI on_thread_callback(HINSTANCE, DWORD, PVOID); /* The .CRT$Xxx information is taken from Codeguru: */ /* http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/ */ /* The tls glue code is to be run first */ /* I don't think it is necessary to run it */ /* at .CRT$XIB level, since we are only */ /* interested in thread detachement. But */ /* this could be changed easily if required. */ #pragma data_seg(".CRT$XIU") static _PVFV p_tls_prepare = on_tls_prepare; #pragma data_seg() /* we need to get control after all global ctors */ #pragma data_seg(".CRT$XCU") static _PVFV p_process_init = on_process_init; #pragma data_seg() /* this is the TLS callback */ #pragma data_seg(".CRT$XLB") _TLSCB p_thread_callback = on_thread_callback; #pragma data_seg() /* we will run the termination late */ #pragma data_seg(".CRT$XTU") static _PVFV p_process_exit = on_process_exit; #pragma data_seg() static void on_tls_prepare(void) { _TLSCB* pfbegin; _TLSCB* pfend; _TLSCB* pfdst; pfbegin = __xl_a; pfend = __xl_z; /* the following line has an important side effect: */ /* if the TLS directory is not already there, it will */ /* be created by the linker. (_tls_used) */ pfdst = (_TLSCB*)_tls_used.AddressOfCallBacks; /* the following loop will merge the address pointers */ /* into a contiguous area, since the tlssup code seems */ /* to require this (at least on MSVC 6) */ while (pfbegin < pfend) { if (*pfbegin != 0) { *pfdst = *pfbegin; ++pfdst; } ++pfbegin; } } static void on_process_init(void) { /* This hooks the main thread exit. It will run the */ /* termination before global dtors, but will not be run */ /* when 'quick' exiting the library! However, this is the */ /* standard behaviour for all global dtors anyways. */ atexit(on_thread_exit); /* hand over to boost */ on_process_enter(); } void NTAPI on_thread_callback(HINSTANCE h, DWORD dwReason, PVOID pv) { if(dwReason == DLL_THREAD_DETACH) on_thread_exit(); } void tss_cleanup_implemented(void) {}; ----EOF--- Roland