summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Williams <nico@cryptonector.com>2021-09-03 09:49:34 -0500
committerNicolas Williams <nico@cryptonector.com>2021-09-03 14:18:18 -0500
commit34182cca7babec086bbc93dec209275be896ca9e (patch)
tree847a8968e4a5863b96480e25ad4ad9de23e8f1cf
parentd18b2d078c2383d9472d0a0a226e07009025574f (diff)
downloadjq-34182cca7babec086bbc93dec209275be896ca9e.tar.gz
Fix Windows build for 1.7 release (pthread stuff)
-rw-r--r--COPYING28
-rw-r--r--src/jv.c303
-rw-r--r--src/jv_dtoa_tsd.c23
-rw-r--r--src/jv_thread.h72
4 files changed, 420 insertions, 6 deletions
diff --git a/COPYING b/COPYING
index 3e1dd1f..8236b6b 100644
--- a/COPYING
+++ b/COPYING
@@ -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.
+
diff --git a/src/jv.c b/src/jv.c
index 3d92f87..10eff41 100644
--- a/src/jv.c
+++ b/src/jv.c
@@ -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;
diff --git a/src/jv_dtoa_tsd.c b/src/jv_dtoa_tsd.c
index 85d5beb..cafd141 100644
--- a/src/jv_dtoa_tsd.c
+++ b/src/jv_dtoa_tsd.c
@@ -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"
-
-static pthread_key_t dtoa_ctx_key;
+#ifndef WIN32
static pthread_once_t dtoa_ctx_once = PTHREAD_ONCE_INIT;
+#endif
+static pthread_key_t dtoa_ctx_key;
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;
-} \ No newline at end of file
+}
diff --git a/src/jv_thread.h b/src/jv_thread.h
new file mode 100644
index 0000000..a34cd08
--- /dev/null
+++ b/src/jv_thread.h
@@ -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 */