Hi,
pthreads have option to register destruct callback
for private thread keys created.
Here is the patch that allow that for WIN32 but
only when compiled as dll.
Any comments or objections?
The consequence is that the DllMain is added, and
I suppose its not possible to have that functionality
with static apr lib.
OTOH it allows to have the same behavior like with
pthreads actually calling provided callback to
the apr_threadkey_private_create instead just ignoring
it.
Regards,
Mladen.
Index: threadpriv.c
===================================================================
--- threadpriv.c (revision 432623)
+++ threadpriv.c (working copy)
@@ -21,6 +21,110 @@
#include "apr_errno.h"
#include "apr_portable.h"
+#ifdef APR_DECLARE_EXPORT
+static struct tls_key_data {
+ void (*destructor)(void *);
+ DWORD key;
+} tls_keys[1088] = {
+ NULL,
+ 0
+};
+
+static CRITICAL_SECTION tls_cs;
+
+static void threadkey_initialize()
+{
+ int i;
+ for (i = 0; i < 1088; i++) {
+ tls_keys[i].destructor = NULL;
+ tls_keys[i].key = 0;
+ }
+ InitializeCriticalSection(&tls_cs);
+}
+
+static void threadkey_terminate()
+{
+ int i;
+ for (i = 0; i < 1088; i++) {
+ if (tls_keys[i].destructor) {
+ void *data = TlsGetValue(tls_keys[i].key);
+ (*tls_keys[i].destructor)(data);
+ }
+ tls_keys[i].destructor = NULL;
+ tls_keys[i].key = 0;
+ }
+ DeleteCriticalSection(&tls_cs);
+}
+
+static DWORD threadkey_add(DWORD key, void (*dest)(void *))
+{
+ int i;
+ EnterCriticalSection(&tls_cs);
+ for (i = 0; i < 1088; i++) {
+ if (!tls_keys[i].key) {
+ tls_keys[i].destructor = dest;
+ tls_keys[i].key = key;
+ LeaveCriticalSection(&tls_cs);
+ return ERROR_SUCCESS;
+ }
+ }
+ LeaveCriticalSection(&tls_cs);
+ return TLS_OUT_OF_INDEXES;
+}
+
+static void threadkey_detach()
+{
+ int i;
+ EnterCriticalSection(&tls_cs);
+ for (i = 0; i < 1088; i++) {
+ if (tls_keys[i].destructor) {
+ void *data = TlsGetValue(tls_keys[i].key);
+ (*tls_keys[i].destructor)(data);
+ }
+ tls_keys[i].destructor = NULL;
+ tls_keys[i].key = 0;
+ }
+ LeaveCriticalSection(&tls_cs);
+}
+
+BOOL APIENTRY DllMain(HINSTANCE instance,
+ DWORD reason_for_call,
+ LPVOID lpReserved)
+{
+ switch (reason_for_call) {
+ case DLL_PROCESS_ATTACH:
+ threadkey_initialize();
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH:
+ threadkey_detach();
+ break;
+ case DLL_PROCESS_DETACH:
+ threadkey_terminate();
+ break;
+ }
+ return TRUE;
+}
+#else
+static void threadkey_initialize()
+{
+}
+
+static void threadkey_terminate()
+{
+}
+
+static DWORD threadkey_add(DWORD key, void (*dest)(void *))
+{
+ return ERROR_SUCCESS;
+}
+
+static void threadkey_detach()
+{
+}
+#endif
+
APR_DECLARE(apr_status_t) apr_threadkey_private_create(apr_threadkey_t **key,
void (*dest)(void *),
apr_pool_t *pool)
@@ -33,7 +137,10 @@
(*key)->pool = pool;
if (((*key)->key = TlsAlloc()) != 0xFFFFFFFF) {
- return APR_SUCCESS;
+ if (threadkey_add((*key)->key, dest) == ERROR_SUCCESS)
+ return APR_SUCCESS;
+ else
+ return APR_ENOMEM;
}
return apr_get_os_error();
}
@@ -59,7 +166,17 @@
APR_DECLARE(apr_status_t) apr_threadkey_private_delete(apr_threadkey_t *key)
{
if (TlsFree(key->key)) {
- return APR_SUCCESS;
+ int i;
+ EnterCriticalSection(&tls_cs);
+ for (i = 0; i < 1088; i++) {
+ if (tls_keys[i].key == key->key) {
+ tls_keys[i].destructor = NULL;
+ tls_keys[i].key = 0;
+ break;
+ }
+ }
+ LeaveCriticalSection(&tls_cs);
+ return APR_SUCCESS;
}
return apr_get_os_error();
}
@@ -97,5 +214,5 @@
}
(*key)->key = *thekey;
return APR_SUCCESS;
-}
+}