Boost logo

Boost :

From: Roland (roland.schwarz_at_[hidden])
Date: 2004-08-01 07:39:55


On Fri, 30 Jul 2004 23:34:54 -0500 "Aaron W. LaFramboise" <aaronrabiddog51_at_[hidden]> wrote:
> There was also mention of some sort of runtime library floating point
> hook. I was unable to figure out anything about this; however, if this
> is possible, and the ptd is still valid when this hook is called, that
> method is probably superior.

This is indeed the case. The tiddata structure is still vaild at the time this "hook"
is beeing called. Below I am posting a variant on a statically linked
thread cleanup. Also I think I got the dtor order to work correct.

However the implementation requires that the c-runtime is linked against.
(This I consider no serious restriction since there are only rare cases where
one does not need CRT especially when using boost.)

// file: tss.c linked statically to your application, define ,BOOST_THREAD_USE_LIB globally

#include <stdlib.h>

typedef void (__cdecl *_PVFV)(void);

extern void on_process_enter(void);
extern void on_process_exit(void);
extern void on_thread_exit(void);

static void on_process_init(void);
static void on_process_term(void);
static void on_thread_term(void);
static void on_mainthread_term(void);

/* following is taken from Codeguru: */
/* http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/ */
/* we get control after all global ctors */
#pragma data_seg(".CRT$XCU")
static _PVFV pinit = on_process_init;
#pragma data_seg()

#pragma data_seg(".CRT$XTU")
static _PVFV pterm = on_process_term;
#pragma data_seg()

/* This is the FP kook */
static _PVFV _FPmttermOrig = 0;
extern _PVFV _FPmtterm;

static void on_process_init(void)
{
        /* hook the main thread exit, will run before global dtors */
        /* but will not run when 'quick' exiting the library! */
        /* this is the same behaviour as for global dtors */
        atexit(on_mainthread_term);

        /* hook the normal threads exit */
        _FPmttermOrig = _FPmtterm;
        _FPmtterm = on_thread_term;

        on_process_enter();
}

static void on_mainthread_term(void)
{
        on_thread_exit();
}

static void on_process_term(void)
{
        on_process_exit();
}

static void on_thread_term(void)
{
        on_thread_exit();
    /* chain to the original termination handler code */
    if ( _FPmttermOrig != 0 )
            (*_FPmttermOrig)();
}

void tss_cleanup_implemented(void) {};

Some comments:
While the fp hook works fine, I am not sure yet whether any fp calls might alter the pointer.
This would definitely be very bad, and surely has to be investigated more thuroughly.
(Some fp gurus out there?)
Since this trick is not documented in the user-part (I took the information from the CRT sources)
there also might be a chance that this "feature" will not be available sometime in the
future.
But: as far as I can see the behaviour is the same in MSVC6 as in MSVC7.
(Sidebar: .CRT$XLB does not work in MSVC6. I am afraid this has to do with CRT, and
not with the OS loader calling the TLS callbacks. Did anyone try the PE TLS-callback
without the CRT linked in?)

The above approach will work for any threads that have been created by
_beginthread or _beginthreadex.

> As far as I can tell, FlsCallback() offers no advantage with regards to
> the ptd issue. It is also called "too late."

As already discussed, the "too late" argument actually is not a very important one
at all. The tiddata structure is dynamically created by the CRT when needed.
The worst thing that may happen is, that (only when using certain functions in the
destructor) the thread leaves with a memory leak.

>
> Another problem with this method is that it gets destructor order wrong.
> For example, in the case of termination of the main thread, global
> destructors will be called before the TSS destructors are. This also
> could lead to silent misbehavior. It is likely that a better method for
> handling termination of the main thread could be found, such as a global
> destructor.

I think my proposal addresses this problem in the correct way.
The only problem is when the main thread exits (destructing the
thread_specific_ptr) leaving other threads behind. But however
I consider this wrong program behaviour anyways.

>
> Note that, with this method, it doesn't particular matter how the thread
> was created. There will be no ptd regardless of whether the thread was
> created with _beginthread or not.
>

This (unfortunately?) isn't the case with my solution, but however, relying on
_beinthread or _beginthreadex having been called is a much less restrictive
requirement.

BTW.: While perhaps not the most clean solution it also might be possible
to 'clean up' the tiddata of the thread from withing DLL_THREAD_DETACH?
Of course this still would require to even more fiddle around with internal CRT structures.

Roland


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