Boost logo

Boost :

From: Roland (roland.schwarz_at_[hidden])
Date: 2004-08-01 20:11:33


On Sun, 01 Aug 2004 16:41:18 -0500 "Aaron W. LaFramboise" <aaronrabiddog51_at_[hidden]> 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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk