aboutsummaryrefslogtreecommitdiffstats
path: root/lib/erl_interface/src/misc/ei_pthreads.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/erl_interface/src/misc/ei_pthreads.c')
-rw-r--r--lib/erl_interface/src/misc/ei_pthreads.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/lib/erl_interface/src/misc/ei_pthreads.c b/lib/erl_interface/src/misc/ei_pthreads.c
new file mode 100644
index 0000000000..a741dfd5c2
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_pthreads.c
@@ -0,0 +1,226 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2001-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ *
+
+ */
+
+/* FIXME why not use ei_malloc here? */
+
+#include "eidef.h"
+
+#include <stdlib.h>
+#include "ei.h"
+#include "ei_locking.h"
+
+#ifdef __WIN32__
+#ifdef USE_DECLSPEC_THREAD
+/* Define (and initialize) the variable __erl_errno */
+volatile __declspec(thread) int __erl_errno = 0;
+#else
+static volatile DWORD errno_tls_index = TLS_OUT_OF_INDEXES;
+static LONG volatile tls_init_mutex = 0;
+#endif
+#endif
+
+#if defined(VXWORKS)
+
+/*
+ Moved to each of the erl_*threads.c files, as they seem to know how
+ to get thread-safety.
+*/
+static volatile int __erl_errno;
+volatile int *__erl_errno_place(void)
+{
+ /* This check is somewhat insufficient, double task var entries will occur
+ if __erl_errno is actually -1, which on the other hand is an invalid
+ error code. */
+ if (taskVarGet(taskIdSelf(), &__erl_errno) == ERROR) {
+ taskVarAdd(taskIdSelf(), &__erl_errno);
+ }
+ return &__erl_errno;
+}
+#endif /* VXWORKS */
+
+#if defined(__WIN32__)
+
+#ifdef USE_DECLSPEC_THREAD
+
+volatile int *__erl_errno_place(void)
+{
+ return &__erl_errno;
+}
+
+#else
+static void tls_init_once(void)
+{
+
+ if (errno_tls_index != TLS_OUT_OF_INDEXES) {
+ return;
+ }
+ if (InterlockedExchange((LPLONG) &tls_init_mutex,1L) == 0) {
+ /* I was first */
+ errno_tls_index = TlsAlloc();
+ if (errno_tls_index == TLS_OUT_OF_INDEXES) {
+ fprintf(stderr,
+ "FATAL ERROR: can not allocate TLS index for "
+ "erl_errno (error code = %d)!\n",GetLastError());
+ exit(1);
+ }
+ } else {
+ while (errno_tls_index == TLS_OUT_OF_INDEXES) {
+ SwitchToThread();
+ }
+ }
+}
+
+volatile int *__erl_errno_place(void)
+{
+ volatile int *ptr;
+ tls_init_once();
+ ptr = TlsGetValue(errno_tls_index);
+ if (ptr == NULL) {
+ ptr = malloc(sizeof(int));
+ *ptr = 0;
+ TlsSetValue(errno_tls_index, (PVOID) ptr);
+ }
+ return ptr;
+}
+
+#endif /* USE_DECLSPEC_THREAD */
+
+#endif /* __WIN32__ */
+
+#if defined(_REENTRANT) && !defined(VXWORKS) && !defined(__WIN32__)
+
+#if defined(HAVE_PTHREAD_H) || defined(HAVE_MIT_PTHREAD_H)
+
+void *ei_m_create(void)
+{
+ pthread_mutex_t *l;
+
+ if ((l = malloc(sizeof(*l)))) { /* FIXME get memory or abort */
+ pthread_mutex_init(l,NULL);
+ }
+
+ return l;
+}
+
+int ei_m_destroy(void *l)
+{
+ int r = pthread_mutex_destroy(l);
+ free(l);
+
+ return r;
+}
+
+int ei_m_lock(void *l)
+{
+ return pthread_mutex_lock(l);
+}
+
+int ei_m_trylock(void *l)
+{
+ return pthread_mutex_trylock(l);
+}
+
+int ei_m_unlock(void *l)
+{
+ return pthread_mutex_unlock(l);
+}
+
+
+/*
+ * Thread-specific erl_errno variable.
+ *
+ * The second line below will give a "missing braces around initializer"
+ * on Solaris but the code will work.
+ */
+
+static pthread_key_t erl_errno_key;
+static pthread_once_t erl_errno_key_once = PTHREAD_ONCE_INIT;
+
+/*
+ * Destroy per-thread erl_errno locus
+ */
+static void erl_errno_destroy(void * ptr)
+{
+ free(ptr);
+}
+
+/*
+ * Allocate erl_errno key.
+ * This will be done once for all threads
+ */
+static void erl_errno_key_alloc(void)
+{
+ pthread_key_create(&erl_errno_key, erl_errno_destroy);
+}
+
+/*
+ * Return a pointer to the erl_errno locus.
+ * If pthread functions fail we fall back to using fallback_errno
+ * so that the main thread (actually not a thread in all ascpects)
+ * still will set and get an erl_errno value.
+ * Actually this is a bit to nice, it would be preferrable to exit fatal
+ * as we do on windows, but we might break some code with one thread
+ * but still compiled with -D_REENTRANT, so we'll leave it here.
+ */
+volatile int *__erl_errno_place(void)
+{
+ int *erl_errno_p;
+ static volatile int use_fallback = 0;
+ static volatile int fallback_errno = 0;
+
+ if (use_fallback) {
+ return &fallback_errno;
+ }
+
+ /* This will create the key once for all threads */
+ if (pthread_once(&erl_errno_key_once, erl_errno_key_alloc) != 0) {
+ use_fallback = 1;
+ return &fallback_errno;
+ }
+
+ /* This is the normal case, return the pointer to the data */
+ if ((erl_errno_p = pthread_getspecific(erl_errno_key)) != NULL) {
+ return erl_errno_p;
+ }
+
+ if ((erl_errno_p = malloc(sizeof(int))) == NULL) {
+ use_fallback = 1;
+ return &fallback_errno;
+ }
+
+ if (pthread_setspecific(erl_errno_key, erl_errno_p) != 0 ||
+ (erl_errno_p = pthread_getspecific(erl_errno_key)) == NULL) {
+ free(erl_errno_p);
+ return &fallback_errno;
+ }
+
+ return erl_errno_p;
+}
+
+#endif /* HAVE_PTHREAD_H || HAVE_MIT_PTHREAD_H */
+
+#endif /* _REENTRANT && !VXWORKS && !__WIN32__ */
+
+#if !defined(_REENTRANT) && !defined(VXWORKS) && !defined(__WIN32__)
+
+volatile int __erl_errno;
+
+#endif