Fix Windows build for 1.7 release (pthread stuff)

This commit is contained in:
Nicolas Williams committed 2021-09-03 14:18:18 -05:00
1 parent d18b2d078c
commit 34182cca7b
4 files changed
+420 -6

No files matched your search

+28
View File
@@ -106,3 +106,31 @@ shall not be used in advertising or otherwise to promote the sale, use
or other dealings in this Software without prior written authorization
of the copyright holder.
Portions 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.
+303
View File
@@ -1,3 +1,35 @@
/*
* Portions 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.
*
*/
#include <stdint.h>
#include <stddef.h>
#include <assert.h>
@@ -193,11 +225,278 @@ enum {
#define BIN64_DEC_PRECISION (17)
#define DEC_NUMBER_STRING_GUARD (14)
#include <jv_thread.h>
#ifdef WIN32
/* Copied from Heimdal: thread-specific keys; see lib/base/dll.c in Heimdal */
/*
* 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.
*/
/* 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 pthread_mutex_t tls_key_defs_lock = PTHREAD_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;
};
#ifdef _MSC_VER
static __declspec(thread) struct nomem_handler nomem_handler;
#else
static __thread struct tls_values values;
#endif
#define DEAD_KEY ((void *)8)
static void
w32_service_thread_detach(void *unused)
{
tls_keys *key_defs;
void (*dtor)(void*);
size_t i;
pthread_mutex_lock(&tls_key_defs_lock);
key_defs = tls_key_defs;
pthread_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) {
pthread_mutex_lock(&tls_key_defs_lock);
key_defs = key_defs->keys_next;
pthread_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;
}
}
extern void tsd_dtoa_ctx_init();
extern void tsd_dtoa_ctx_fini();
static void tsd_dec_ctx_fini();
static void tsd_dec_ctx_init();
BOOL WINAPI DllMain(HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
/*create_pt_key();*/
tsd_dtoa_ctx_init();
tsd_dec_ctx_init();
return 1;
case DLL_PROCESS_DETACH:
tsd_dtoa_ctx_fini();
tsd_dec_ctx_fini();
return 0;
case DLL_THREAD_ATTACH: return 0;
case DLL_THREAD_DETACH:
w32_service_thread_detach(NULL);
return 0;
default: return 0;
}
}
int
pthread_key_create(pthread_key_t *key, void (*dtor)(void *))
{
tls_keys *key_defs, *new_key_defs;
size_t i, k;
int ret = ENOMEM;
pthread_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) {
pthread_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) {
pthread_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;
pthread_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;
pthread_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;
}
pthread_mutex_unlock(&tls_key_defs_lock);
return ret;
}
static void
key_lookup(pthread_key_t 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;
pthread_mutex_lock(&tls_key_defs_lock);
key_defs = tls_key_defs;
pthread_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;
}
pthread_mutex_lock(&tls_key_defs_lock);
key_defs = key_defs->keys_next;
pthread_mutex_unlock(&tls_key_defs_lock);
assert(key_defs != NULL);
assert(key >= key_defs->keys_start_idx);
}
}
int
pthread_setspecific(pthread_key_t key, void *value)
{
void **new_values;
size_t new_num;
void (*dtor)(void *);
size_t i;
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 *
pthread_getspecific(pthread_key_t key)
{
if (key >= values.values_num)
return NULL;
return values.values[key];
}
#else
#include <pthread.h>
#endif
static pthread_key_t dec_ctx_key;
static pthread_key_t dec_ctx_dbl_key;
#ifndef WIN32
static pthread_once_t dec_ctx_once = PTHREAD_ONCE_INIT;
#endif
#define DEC_CONTEXT() tsd_dec_ctx_get(&dec_ctx_key)
#define DEC_CONTEXT_TO_DOUBLE() tsd_dec_ctx_get(&dec_ctx_dbl_key)
@@ -220,11 +519,15 @@ static void tsd_dec_ctx_init() {
fprintf(stderr, "error: cannot create thread specific key");
abort();
}
#ifndef WIN32
atexit(tsd_dec_ctx_fini);
#endif
}
static decContext* tsd_dec_ctx_get(pthread_key_t *key) {
#ifndef WIN32
pthread_once(&dec_ctx_once, tsd_dec_ctx_init); // cannot fail
#endif
decContext *ctx = (decContext*)pthread_getspecific(*key);
if (ctx) {
return ctx;
+17 -6
View File
@@ -1,15 +1,16 @@
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include "jv_thread.h"
#include "jv_dtoa_tsd.h"
#include "jv_dtoa.h"
#include "jv_alloc.h"
#ifndef WIN32
static pthread_once_t dtoa_ctx_once = PTHREAD_ONCE_INIT;
#endif
static pthread_key_t dtoa_ctx_key;
static pthread_once_t dtoa_ctx_once = PTHREAD_ONCE_INIT;
static void tsd_dtoa_ctx_dtor(void *ctx) {
if (ctx) {
jvp_dtoa_context_free((struct dtoa_context *)ctx);
@@ -17,22 +18,32 @@ static void tsd_dtoa_ctx_dtor(void *ctx) {
}
}
static void tsd_dtoa_ctx_fini() {
#ifndef WIN32
static
#endif
void tsd_dtoa_ctx_fini() {
struct dtoa_context *ctx = pthread_getspecific(dtoa_ctx_key);
tsd_dtoa_ctx_dtor(ctx);
pthread_setspecific(dtoa_ctx_key, NULL);
}
static void tsd_dtoa_ctx_init() {
#ifndef WIN32
static
#endif
void tsd_dtoa_ctx_init() {
if (pthread_key_create(&dtoa_ctx_key, tsd_dtoa_ctx_dtor) != 0) {
fprintf(stderr, "error: cannot create thread specific key");
abort();
}
#ifndef WIN32
atexit(tsd_dtoa_ctx_fini);
#endif
}
inline struct dtoa_context *tsd_dtoa_context_get() {
#ifndef WIN32
pthread_once(&dtoa_ctx_once, tsd_dtoa_ctx_init); // cannot fail
#endif
struct dtoa_context *ctx = (struct dtoa_context*)pthread_getspecific(dtoa_ctx_key);
if (!ctx) {
ctx = malloc(sizeof(struct dtoa_context));
@@ -43,4 +54,4 @@ inline struct dtoa_context *tsd_dtoa_context_get() {
}
}
return ctx;
}
}
+72
View File
@@ -0,0 +1,72 @@
#ifndef JV_THREAD_H
#define JV_THREAD_H
#ifdef WIN32
#include <windows.h>
#include <winnt.h>
#include <errno.h>
/* Copied from Heimdal: pthread-like mutexes for WIN32 -- see lib/base/heimbase.h in Heimdal */
typedef struct pthread_mutex {
HANDLE h;
} pthread_mutex_t;
#define PTHREAD_MUTEX_INITIALIZER { INVALID_HANDLE_VALUE }
static inline int
pthread_mutex_init(pthread_mutex_t *m)
{
m->h = CreateSemaphore(NULL, 1, 1, NULL);
if (m->h == INVALID_HANDLE_VALUE)
return EAGAIN;
return 0;
}
static inline int
pthread_mutex_lock(pthread_mutex_t *m)
{
HANDLE h, new_h;
int created = 0;
h = InterlockedCompareExchangePointer(&m->h, m->h, m->h);
if (h == INVALID_HANDLE_VALUE || h == NULL) {
created = 1;
new_h = CreateSemaphore(NULL, 0, 1, NULL);
if (new_h == INVALID_HANDLE_VALUE)
return EAGAIN;
if (InterlockedCompareExchangePointer(&m->h, new_h, h) != h) {
created = 0;
CloseHandle(new_h);
}
}
if (!created)
WaitForSingleObject(m->h, INFINITE);
return 0;
}
static inline int
pthread_mutex_unlock(pthread_mutex_t *m)
{
if (ReleaseSemaphore(m->h, 1, NULL) == FALSE)
return EPERM;
return 0;
}
static inline int
pthread_mutex_destroy(pthread_mutex_t *m)
{
HANDLE h;
h = InterlockedCompareExchangePointer(&m->h, INVALID_HANDLE_VALUE, m->h);
if (h != INVALID_HANDLE_VALUE)
CloseHandle(h);
return 0;
}
typedef unsigned long pthread_key_t;
int pthread_key_create(pthread_key_t *, void (*)(void *));
int pthread_setspecific(pthread_key_t, void *);
void *pthread_getspecific(pthread_key_t);
#else
#include <pthread.h>
#endif
#endif /* JV_THREAD_H */