Boost logo

Boost :

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


On Fri, 30 Jul 2004 23:34:54 -0500 "Aaron W. LaFramboise" <aaronrabiddog51_at_[hidden]> wrote:
> > It is likely that a better method for
>> handling termination of the main thread could be found,
>> such as a global destructor.

I didn't answer corrcetcly to this one in my first post. Here it goes:
I am using the clibs atexit function for termination in the main thread.

Below I am posting a variation on my previous proposal, which builds on
the "piggy-pack" DLL proposal I've posted some time ago.
This version does not need to fiddle around with the fp termination and works
on foreign threads too. However the same caveats as Aaron already pointed out, apply.

While I agree that Aarons solution is much more cleaner and elegant (and should
be preferred where possible), I think it will not be able to make it work
on MSVC6. I am afraid, the ".CRT$XLB" segment is not recognized as a
TLS code pointer table in linkers previous to 7.1.

Since the boost code on tss now has the process/thread specific stuff
factored out very nicely (Thanks to Mike?) it was easy to port my piggy-dll to support it.
Also my concerns about locking have gone, since the piggy-dll is doing
exactly the same as the other solutions accomplish.

// file: tssdll.c linked statically to your application, define BOOST_THREAD_USE_LIB globally
#include <stdlib.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

/* the boost handlers */
extern void on_process_enter(void);
extern void on_process_exit(void);
extern void on_thread_exit(void);

/* locally defined handlers */
static void on_process_init(void);
static void on_process_term(void);
static void on_thread_term(void);
static void on_mainthread_term(void);

typedef void (__cdecl *_PVFV)(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()

/* these are the module and filename of the temporary DLL */
static HMODULE hm = NULL;
static LPTSTR fn = NULL;

/* This is the piggy-pack DLL hook */
/*
 * The embedded 'dllmain_dll' image has been generated from the commented out small
 * DLL stub file with the command: (VC6.0)
 * NB.: it does not depend on CRT in any way.
 * cl /W3 /O1 DllMain.c /link /out:DllMain.dll /dll /align:64 /ignore:4108 /nodefaultlib /machine:I386
 */
#if 0
__declspec(dllexport)
void (__cdecl *thread_detach)(void);

void __cdecl dummy(void) {};

int __stdcall _DllMainCRTStartup(
                void * hDllHandle,
                unsigned long dwReason,
                void* lpreserved
        )
{
    switch (dwReason)
        {
        case 1: thread_detach = &dummy; break;
        case 3: thread_detach(); break;
    }
    return 1;
}
#endif

/* the following could be put in a data segment that is discarded after
 * startup. If anyone knows about such a thing, please let me know. */
static const unsigned char dllmain_dll[] = /* 960 */
{0x4D,0x5A,0x90,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xFF,0xFF,0x00
,0x00,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0xC0,0x00,0x00,0x00,0x0E,0x1F,0xBA,0x0E,0x00,0xB4,0x09,0xCD,0x21,0xB8,0x01
,0x4C,0xCD,0x21,0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D
,0x20,0x63,0x61,0x6E,0x6E,0x6F,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6E,0x20
,0x69,0x6E,0x20,0x44,0x4F,0x53,0x20,0x6D,0x6F,0x64,0x65,0x2E,0x0D,0x0D,0x0A
,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6F,0xDD,0x05,0xDB,0x2B,0xBC,0x6B
,0x88,0x2B,0xBC,0x6B,0x88,0x2B,0xBC,0x6B,0x88,0x2D,0x9F,0x61,0x88,0x2A,0xBC
,0x6B,0x88,0xD4,0x9C,0x6F,0x88,0x2A,0xBC,0x6B,0x88,0x52,0x69,0x63,0x68,0x2B
,0xBC,0x6B,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x45,0x00
,0x00,0x4C,0x01,0x04,0x00,0xCF,0xC9,0xC8,0x3F,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0xE0,0x00,0x0E,0x21,0x0B,0x01,0x06,0x00,0x40,0x00,0x00,0x00,0x00
,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x02,0x00,0x00,0x80,0x02,0x00,0x00
,0xC0,0x02,0x00,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x00,0x00,0x40,0x00,0x00
,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0xC0,0x03,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x02
,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x00
,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0xC0,0x02,0x00
,0x00,0x4C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x00,0x10,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x2E,0x74,0x65,0x78,0x74,0x00,0x00,0x00,0x24,0x00
,0x00,0x00,0x80,0x02,0x00,0x00,0x40,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x60
,0x2E,0x72,0x64,0x61,0x74,0x61,0x00,0x00,0x4C,0x00,0x00,0x00,0xC0,0x02,0x00
,0x00,0x80,0x00,0x00,0x00,0xC0,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x40,0x2E,0x64,0x61,0x74,0x61
,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x40,0x03,0x00,0x00,0x40,0x00,0x00,0x00
,0x40,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x40,0x00,0x00,0xC0,0x2E,0x72,0x65,0x6C,0x6F,0x63,0x00,0x00,0x10,0x00
,0x00,0x00,0x80,0x03,0x00,0x00,0x40,0x00,0x00,0x00,0x80,0x03,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x42
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC3,0x8B,0x44,0x24,0x08
,0x48,0x74,0x0C,0x48,0x48,0x75,0x12,0xFF,0x15,0x40,0x03,0x00,0x10,0xEB,0x0A
,0xC7,0x05,0x40,0x03,0x00,0x10,0x80,0x02,0x00,0x10,0x6A,0x01,0x58,0xC2,0x0C
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0xCF,0xC9,0xC8,0x3F,0x00,0x00,0x00,0x00,0xF2,0x02,0x00,0x00
,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xE8,0x02,0x00
,0x00,0xEC,0x02,0x00,0x00,0xF0,0x02,0x00,0x00,0x40,0x03,0x00,0x00,0xFE,0x02
,0x00,0x00,0x00,0x00,0x44,0x6C,0x6C,0x4D,0x61,0x69,0x6E,0x2E,0x64,0x6C,0x6C
,0x00,0x74,0x68,0x72,0x65,0x61,0x64,0x5F,0x64,0x65,0x74,0x61,0x63,0x68,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x10,0x00,0x00,0x00,0x8E,0x32,0x96,0x32,0x9A,0x32,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

static void on_process_init(void)
{
DWORD dw;
LPTSTR path;
HANDLE hf;

        /* 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 */
        /* we do this by dynamically writing out a small DLL stub and loading it */
        /* during process startup */
        dw = GetTempPath(0,NULL);
        path = (LPTSTR)malloc(dw);
        GetTempPath(dw,path);
        fn = (LPTSTR)malloc(dw+32);
        GetTempFileName(path,"AET", 0, fn);
        free(path);
        hf = CreateFile(fn,
                GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
                FILE_ATTRIBUTE_TEMPORARY,NULL);
        if (INVALID_HANDLE_VALUE != hf) {
                WriteFile(hf, dllmain_dll, sizeof(dllmain_dll), &dw, NULL); /* don't forget to adjust the size! */
                CloseHandle(hf);
                hm = LoadLibrary(fn);
                if (NULL != hm) {
                        *(_PVFV*)GetProcAddress(hm, "thread_detach") = on_thread_term;
                }
                else {
                        DeleteFile(fn);
                        free(fn);
                        fn = 0;
                }
        }
        else {
                free(fn);
                fn = 0;
        }

        /* do the boost stuff */
        on_process_enter();
}

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

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

static void on_process_term(void)
{
        on_process_exit();

        FreeLibrary(hm);
        DeleteFile(fn);
        free(fn);
}

void tss_cleanup_implemented(void) {};

---EOF---

In summary there are now three variations on the exithtread theme available.
(actually 4 when counting the user supplied calls to process/thread init/term).

I hope this should be enough to reintroduce the static linking feature in
the next version :-)

Roland


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