Branko Čibej wrote:

I know that boost_thread uses this method, and I've verified that it
works on AMD64 and IA64; the tric is, I believe, that Boost inserts a
single static handler into the static constructor and destructor
segments, and lets that handler maintain its own list of hooks.


Here is the entire code:


#if (_MSC_VER < 1310)
typedef void (__cdecl *_PVFV)(void);
#define INIRETSUCCESS
#define PVAPI void
#else
typedef int (__cdecl *_PVFV)(void);
#define INIRETSUCCESS 0
#define PVAPI int
#endif

typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID);
/* Symbols for connection to the runtime environment */
extern DWORD _tls_used;
extern _TLSCB __xl_a[], __xl_z[];

/* Global TLS hash table */
apr_hash_t *apr_tls_threadkeys = NULL;

typedef (apr_thredkey_destfn_t)(void *data);

static void threadkey_detach()
{
    apr_hash_index_t *hi = apr_hash_first(NULL, apr_tls_threadkeys);

    for (; hi != NULL; hi = apr_hash_next(hi)) {
        apr_thredkey_destfn_t *dest = NULL;
        LPDWORD key;
        void *data;
        apr_hash_this(hi, &key, NULL, (void **)&dest);
        data = TlsGetValue(*key);
        if (data != NULL || GetLastError() == ERROR_SUCCESS) {
            /* NULL data is a valid TLS value if explicitly set
             * by the TlsSetValue
             */
            (*dest)(data);
        }
    }
}

static PVAPI threadkey_prepare(void)
{
    DWORD volatile dw = _tls_used;

#if (_MSC_VER < 1310)
    _TLSCB* pfbegin = __xl_a;
    _TLSCB* pfend   = __xl_z;
    _TLSCB* pfdst   = pfbegin;

    while (pfbegin < pfend) {
        if (*pfbegin != 0) {
            *pfdst = *pfbegin;
            ++pfdst;
        }
        ++pfbegin;
    }
    *pfdst = 0;
#endif
    return INIRETSUCCESS;
}

static void NTAPI threadkey_callback(HINSTANCE hInstance, DWORD dwReason,
                                     PVOID pReserved)
{
    switch (dwReason) {
        case DLL_THREAD_DETACH:
            if (apr_tls_threadkeys)
                threadkey_detach();
        break;
    }
}

#if (_MSC_VER >= 1310)
#pragma data_seg(push, old_seg)
#endif
/* Callback to run tls glue code first. */
#pragma data_seg(".CRT$XIU")
static _PVFV p_threadkey_prepare = threadkey_prepare;
#pragma data_seg()

/* Callback for tls notifications. */
#pragma data_seg(".CRT$XLB")
static _TLSCB p_threadkey_callback = threadkey_callback;
#pragma data_seg()

#if (_MSC_VER >= 1310)
#pragma data_seg(pop, old_seg)
#endif

Reply via email to