Add thread-locals for WIN32
This commit is contained in:
@@ -46,6 +46,24 @@
|
||||
#ifndef HEIM_THREADS_H
|
||||
#define HEIM_THREADS_H 1
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define HEIMDAL_THREAD_LOCAL __declspec(thread)
|
||||
|
||||
#else
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__) || defined(__SUNPRO_CC)
|
||||
#define HEIMDAL_THREAD_LOCAL __thread
|
||||
#else
|
||||
#error "thread-local attribute not defined for your compiler"
|
||||
#endif /* clang or gcc */
|
||||
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
/* For testing the for-Windows implementation of thread keys on non-Windows */
|
||||
typedef unsigned long HEIM_PRIV_thread_key;
|
||||
|
||||
|
||||
/* assume headers already included */
|
||||
|
||||
#if defined(__NetBSD__) && __NetBSD_Version__ >= 106120000 && __NetBSD_Version__< 299001200 && defined(ENABLE_PTHREAD_SUPPORT)
|
||||
@@ -102,11 +120,20 @@
|
||||
#define HEIMDAL_RWLOCK_unlock(l) pthread_rwlock_unlock(l)
|
||||
#define HEIMDAL_RWLOCK_destroy(l) pthread_rwlock_destroy(l)
|
||||
|
||||
#ifdef HEIM_BASE_MAINTAINER
|
||||
#define HEIMDAL_thread_key unsigned long
|
||||
#define HEIM_PRIV_thread_key HEIMDAL_thread_key
|
||||
#define HEIMDAL_key_create(k,d,r) do { r = heim_w32_key_create(k,d); } while(0)
|
||||
#define HEIMDAL_setspecific(k,s,r) do { r = heim_w32_setspecific(k,s); } while(0)
|
||||
#define HEIMDAL_getspecific(k) (heim_w32_getspecific(k))
|
||||
#define HEIMDAL_key_delete(k) (heim_w32_delete_key(k))
|
||||
#else
|
||||
#define HEIMDAL_thread_key pthread_key_t
|
||||
#define HEIMDAL_key_create(k,d,r) do { r = pthread_key_create(k,d); } while(0)
|
||||
#define HEIMDAL_setspecific(k,s,r) do { r = pthread_setspecific(k,s); } while(0)
|
||||
#define HEIMDAL_getspecific(k) pthread_getspecific(k)
|
||||
#define HEIMDAL_key_delete(k) pthread_key_delete(k)
|
||||
#endif
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
@@ -246,7 +273,12 @@ heim_rwlock_destroy(heim_rwlock_t *l)
|
||||
#define HEIMDAL_RWLOCK_unlock(l) heim_rwlock_unlock((l))
|
||||
#define HEIMDAL_RWLOCK_destroy(l) heim_rwlock_destroy((l))
|
||||
|
||||
#define HEIMDAL_internal_thread_key 1
|
||||
#define HEIMDAL_thread_key unsigned long
|
||||
#define HEIM_PRIV_thread_key HEIMDAL_thread_key
|
||||
#define HEIMDAL_key_create(k,d,r) do { r = heim_w32_key_create(k,d); } while(0)
|
||||
#define HEIMDAL_setspecific(k,s,r) do { r = heim_w32_setspecific(k,s); } while(0)
|
||||
#define HEIMDAL_getspecific(k) (heim_w32_getspecific(k))
|
||||
#define HEIMDAL_key_delete(k) (heim_w32_delete_key(k))
|
||||
|
||||
#elif defined(HEIMDAL_DEBUG_THREADS)
|
||||
|
||||
@@ -312,4 +344,9 @@ typedef struct heim_thread_key {
|
||||
#undef HEIMDAL_internal_thread_key
|
||||
#endif /* HEIMDAL_internal_thread_key */
|
||||
|
||||
int heim_w32_key_create(HEIM_PRIV_thread_key *, void (*)(void *));
|
||||
int heim_w32_delete_key(HEIM_PRIV_thread_key);
|
||||
int heim_w32_setspecific(HEIM_PRIV_thread_key, void *);
|
||||
void *heim_w32_getspecific(HEIM_PRIV_thread_key);
|
||||
|
||||
#endif /* HEIM_THREADS_H */
|
||||
|
@@ -5,6 +5,12 @@ if do_roken_rename
|
||||
ES = base64.c
|
||||
endif
|
||||
|
||||
IMPLEMENT_TLS=
|
||||
if MAINTAINER_MODE
|
||||
IMPLEMENT_TLS += dll.c
|
||||
AM_CPPFLAGS += -DHEIM_BASE_MAINTAINER
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS += $(ROKEN_RENAME)
|
||||
|
||||
lib_LTLIBRARIES = libheimbase.la
|
||||
@@ -28,6 +34,7 @@ dist_libheimbase_la_SOURCES = \
|
||||
data.c \
|
||||
db.c \
|
||||
dict.c \
|
||||
$(IMPLEMENT_TLS) \
|
||||
error.c \
|
||||
heimbase.c \
|
||||
heimbasepriv.h \
|
||||
|
@@ -46,6 +46,7 @@ libheimbase_OBJS = \
|
||||
$(OBJ)\data.obj \
|
||||
$(OBJ)\db.obj \
|
||||
$(OBJ)\dict.obj \
|
||||
$(OBJ)\dll.obj \
|
||||
$(OBJ)\error.obj \
|
||||
$(OBJ)\heimbase.obj \
|
||||
$(OBJ)\json.obj \
|
||||
|
348
lib/base/dll.c
Normal file
348
lib/base/dll.c
Normal file
@@ -0,0 +1,348 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2016 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
/*
|
||||
* This is an implementation of thread-specific storage with
|
||||
* destructors. WIN32 doesn't quite have this. Instead it has
|
||||
* DllMain(), an entry point in every DLL that gets called to notify the
|
||||
* DLL of thread/process "attach"/"detach" events.
|
||||
*
|
||||
* We use __thread (or __declspec(thread)) for the thread-local itself
|
||||
* and DllMain() DLL_THREAD_DETACH events to drive destruction of
|
||||
* thread-local values.
|
||||
*
|
||||
* When building in maintainer mode on non-Windows pthread systems this
|
||||
* uses a single pthread key instead to implement multiple keys. This
|
||||
* keeps the code from rotting when modified by non-Windows developers.
|
||||
*/
|
||||
|
||||
#include "baselocl.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef HEIM_WIN32_TLS
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <heim_threads.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
/* Logical array of keys that grows lock-lessly */
|
||||
typedef struct tls_keys tls_keys;
|
||||
struct tls_keys {
|
||||
void (**keys_dtors)(void *); /* array of destructors */
|
||||
size_t keys_start_idx; /* index of first destructor */
|
||||
size_t keys_num;
|
||||
tls_keys *keys_next;
|
||||
};
|
||||
|
||||
/*
|
||||
* Well, not quite locklessly. We need synchronization primitives to do
|
||||
* this locklessly. An atomic CAS will do.
|
||||
*/
|
||||
static HEIMDAL_MUTEX tls_key_defs_lock = HEIMDAL_MUTEX_INITIALIZER;
|
||||
static tls_keys *tls_key_defs;
|
||||
|
||||
/* Logical array of values (per-thread; no locking needed here) */
|
||||
struct tls_values {
|
||||
void **values; /* realloc()ed */
|
||||
size_t values_num;
|
||||
};
|
||||
|
||||
static HEIMDAL_THREAD_LOCAL struct tls_values values;
|
||||
|
||||
#define DEAD_KEY ((void *)8)
|
||||
|
||||
static void
|
||||
del_tls_for_thread(void *unused)
|
||||
{
|
||||
tls_keys *key_defs;
|
||||
void (*dtor)(void*);
|
||||
size_t i;
|
||||
|
||||
HEIMDAL_MUTEX_lock(&tls_key_defs_lock);
|
||||
key_defs = tls_key_defs;
|
||||
HEIMDAL_MUTEX_unlock(&tls_key_defs_lock);
|
||||
|
||||
if (key_defs == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < values.values_num; i++) {
|
||||
assert(i >= key_defs->keys_start_idx);
|
||||
if (i >= key_defs->keys_start_idx + key_defs->keys_num) {
|
||||
HEIMDAL_MUTEX_lock(&tls_key_defs_lock);
|
||||
key_defs = key_defs->keys_next;
|
||||
HEIMDAL_MUTEX_unlock(&tls_key_defs_lock);
|
||||
|
||||
assert(key_defs != NULL);
|
||||
assert(i >= key_defs->keys_start_idx);
|
||||
assert(i < key_defs->keys_start_idx + key_defs->keys_num);
|
||||
}
|
||||
dtor = key_defs->keys_dtors[i - key_defs->keys_start_idx];
|
||||
if (values.values[i] != NULL && dtor != NULL && dtor != DEAD_KEY)
|
||||
dtor(values.values[i]);
|
||||
values.values[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(WIN32)
|
||||
static pthread_key_t pt_key;
|
||||
pthread_once_t pt_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void
|
||||
atexit_del_tls_for_thread(void)
|
||||
{
|
||||
del_tls_for_thread(NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
create_pt_key(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* The main thread may not execute TLS destructors */
|
||||
atexit(atexit_del_tls_for_thread);
|
||||
ret = pthread_key_create(&pt_key, del_tls_for_thread);
|
||||
if (ret != 0)
|
||||
err(1, "pthread_key_create() failed");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
heim_w32_key_create(HEIM_PRIV_thread_key *key, void (*dtor)(void *))
|
||||
{
|
||||
tls_keys *key_defs, *new_key_defs;
|
||||
size_t i, k;
|
||||
int ret = ENOMEM;
|
||||
|
||||
#if !defined(WIN32)
|
||||
(void) pthread_once(&pt_once, create_pt_key);
|
||||
(void) pthread_setspecific(pt_key, DEAD_KEY);
|
||||
#endif
|
||||
|
||||
HEIMDAL_MUTEX_lock(&tls_key_defs_lock);
|
||||
if (tls_key_defs == NULL) {
|
||||
/* First key */
|
||||
new_key_defs = calloc(1, sizeof(*new_key_defs));
|
||||
if (new_key_defs == NULL) {
|
||||
HEIMDAL_MUTEX_unlock(&tls_key_defs_lock);
|
||||
return ENOMEM;
|
||||
}
|
||||
new_key_defs->keys_num = 8;
|
||||
new_key_defs->keys_dtors = calloc(new_key_defs->keys_num,
|
||||
sizeof(*new_key_defs->keys_dtors));
|
||||
if (new_key_defs->keys_dtors == NULL) {
|
||||
HEIMDAL_MUTEX_unlock(&tls_key_defs_lock);
|
||||
free(new_key_defs);
|
||||
return ENOMEM;
|
||||
}
|
||||
tls_key_defs = new_key_defs;
|
||||
new_key_defs->keys_dtors[0] = dtor;
|
||||
for (i = 1; i < new_key_defs->keys_num; i++)
|
||||
new_key_defs->keys_dtors[i] = NULL;
|
||||
HEIMDAL_MUTEX_unlock(&tls_key_defs_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (key_defs = tls_key_defs;
|
||||
key_defs != NULL;
|
||||
key_defs = key_defs->keys_next) {
|
||||
k = key_defs->keys_start_idx;
|
||||
for (i = 0; i < key_defs->keys_num; i++, k++) {
|
||||
if (key_defs->keys_dtors[i] == NULL) {
|
||||
/* Found free slot; use it */
|
||||
key_defs->keys_dtors[i] = dtor;
|
||||
*key = k;
|
||||
HEIMDAL_MUTEX_unlock(&tls_key_defs_lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (key_defs->keys_next != NULL)
|
||||
continue;
|
||||
|
||||
/* Grow the registration array */
|
||||
/* XXX DRY */
|
||||
new_key_defs = calloc(1, sizeof(*new_key_defs));
|
||||
if (new_key_defs == NULL)
|
||||
break;
|
||||
|
||||
new_key_defs->keys_dtors =
|
||||
calloc(key_defs->keys_num + key_defs->keys_num / 2,
|
||||
sizeof(*new_key_defs->keys_dtors));
|
||||
if (new_key_defs->keys_dtors == NULL) {
|
||||
free(new_key_defs);
|
||||
break;
|
||||
}
|
||||
new_key_defs->keys_start_idx = key_defs->keys_start_idx +
|
||||
key_defs->keys_num;
|
||||
new_key_defs->keys_num = key_defs->keys_num + key_defs->keys_num / 2;
|
||||
new_key_defs->keys_dtors[i] = dtor;
|
||||
for (i = 1; i < new_key_defs->keys_num; i++)
|
||||
new_key_defs->keys_dtors[i] = NULL;
|
||||
key_defs->keys_next = new_key_defs;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
HEIMDAL_MUTEX_unlock(&tls_key_defs_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
key_lookup(HEIM_PRIV_thread_key key, tls_keys **kd,
|
||||
size_t *dtor_idx, void (**dtor)(void *))
|
||||
{
|
||||
tls_keys *key_defs;
|
||||
|
||||
if (kd != NULL)
|
||||
*kd = NULL;
|
||||
if (dtor_idx != NULL)
|
||||
*dtor_idx = 0;
|
||||
if (dtor != NULL)
|
||||
*dtor = NULL;
|
||||
|
||||
HEIMDAL_MUTEX_lock(&tls_key_defs_lock);
|
||||
key_defs = tls_key_defs;
|
||||
HEIMDAL_MUTEX_unlock(&tls_key_defs_lock);
|
||||
|
||||
while (key_defs != NULL) {
|
||||
if (key >= key_defs->keys_start_idx &&
|
||||
key < key_defs->keys_start_idx + key_defs->keys_num) {
|
||||
if (kd != NULL)
|
||||
*kd = key_defs;
|
||||
if (dtor_idx != NULL)
|
||||
*dtor_idx = key - key_defs->keys_start_idx;
|
||||
if (dtor != NULL)
|
||||
*dtor = key_defs->keys_dtors[key - key_defs->keys_start_idx];
|
||||
return;
|
||||
}
|
||||
|
||||
HEIMDAL_MUTEX_lock(&tls_key_defs_lock);
|
||||
key_defs = key_defs->keys_next;
|
||||
HEIMDAL_MUTEX_unlock(&tls_key_defs_lock);
|
||||
assert(key_defs != NULL);
|
||||
assert(key >= key_defs->keys_start_idx);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
heim_w32_delete_key(HEIM_PRIV_thread_key key)
|
||||
{
|
||||
tls_keys *key_defs;
|
||||
size_t dtor_idx;
|
||||
|
||||
key_lookup(key, &key_defs, &dtor_idx, NULL);
|
||||
if (key_defs == NULL)
|
||||
return EINVAL;
|
||||
key_defs->keys_dtors[dtor_idx] = DEAD_KEY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
heim_w32_setspecific(HEIM_PRIV_thread_key key, void *value)
|
||||
{
|
||||
void **new_values;
|
||||
size_t new_num;
|
||||
void (*dtor)(void *);
|
||||
size_t i;
|
||||
|
||||
#if !defined(WIN32)
|
||||
(void) pthread_setspecific(pt_key, DEAD_KEY);
|
||||
#endif
|
||||
|
||||
key_lookup(key, NULL, NULL, &dtor);
|
||||
if (dtor == NULL)
|
||||
return EINVAL;
|
||||
|
||||
if (key >= values.values_num) {
|
||||
if (values.values_num == 0) {
|
||||
values.values = NULL;
|
||||
new_num = 8;
|
||||
} else {
|
||||
new_num = (values.values_num + values.values_num / 2);
|
||||
}
|
||||
new_values = realloc(values.values, sizeof(void *) * new_num);
|
||||
if (new_values == NULL)
|
||||
return ENOMEM;
|
||||
for (i = values.values_num; i < new_num; i++)
|
||||
new_values[i] = NULL;
|
||||
values.values = new_values;
|
||||
values.values_num = new_num;
|
||||
}
|
||||
|
||||
assert(key < values.values_num);
|
||||
|
||||
if (values.values[key] != NULL && dtor != NULL && dtor != DEAD_KEY)
|
||||
dtor(values.values[key]);
|
||||
|
||||
values.values[key] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *
|
||||
heim_w32_getspecific(HEIM_PRIV_thread_key key)
|
||||
{
|
||||
if (key >= values.values_num)
|
||||
return NULL;
|
||||
return values.values[key];
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL,
|
||||
DWORD fdwReason,
|
||||
LPVOID lpvReserved)
|
||||
{
|
||||
switch (fdwReason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
return TRUE;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
return FALSE;
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
return FALSE;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
del_tls_for_thread(NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
|
||||
#else
|
||||
static char dummy;
|
||||
#endif /* HEIM_WIN32_TLS */
|
@@ -533,8 +533,14 @@ static void
|
||||
ar_tls_delete(void *ptr)
|
||||
{
|
||||
struct ar_tls *tls = ptr;
|
||||
if (tls->head)
|
||||
heim_release(tls->head);
|
||||
heim_auto_release_t next = NULL;
|
||||
|
||||
if (tls == NULL)
|
||||
return;
|
||||
for (; tls->current != NULL; tls->current = next) {
|
||||
next = tls->current->parent;
|
||||
heim_release(tls->current);
|
||||
}
|
||||
free(tls);
|
||||
}
|
||||
|
||||
@@ -593,8 +599,7 @@ autorel_dealloc(void *ptr)
|
||||
if (tls->current != ptr)
|
||||
heim_abort("autorelease not releaseing top pool");
|
||||
|
||||
if (tls->current != tls->head)
|
||||
tls->current = ar->parent;
|
||||
tls->current = ar->parent;
|
||||
HEIMDAL_MUTEX_unlock(&tls->tls_mutex);
|
||||
}
|
||||
|
||||
|
@@ -33,6 +33,10 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if defined(HEIM_BASE_MAINTAINER) && !defined(WIN33) && defined(ENABLE_PTHREAD_SUPPORT)
|
||||
#define HEIM_WIN32_TLS
|
||||
#endif
|
||||
|
||||
typedef void (*heim_type_init)(void *);
|
||||
typedef heim_object_t (*heim_type_copy)(void *);
|
||||
typedef int (*heim_type_cmp)(void *, void *);
|
||||
|
@@ -7,6 +7,7 @@ HEIMDAL_BASE_1.0 {
|
||||
_bsearch_file_open;
|
||||
_bsearch_text;
|
||||
__heim_string_constant;
|
||||
DllMain;
|
||||
heim_abort;
|
||||
heim_abortv;
|
||||
heim_alloc;
|
||||
|
Reference in New Issue
Block a user