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