#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "int_lib.h"
#ifdef __BIONIC__
#define EMUTLS_SKIP_DESTRUCTOR_ROUNDS …
#else
#define EMUTLS_SKIP_DESTRUCTOR_ROUNDS …
#endif
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push)
#pragma warning(disable : 4200)
#endif
emutls_address_array;
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#endif
static void emutls_shutdown(emutls_address_array *array);
#ifndef _WIN32
#include <pthread.h>
static pthread_mutex_t emutls_mutex = …;
static pthread_key_t emutls_pthread_key;
static bool emutls_key_created = …;
gcc_word __attribute__((mode …));
gcc_pointer __attribute__((mode …));
#ifndef EMUTLS_USE_POSIX_MEMALIGN
#define EMUTLS_USE_POSIX_MEMALIGN …
#endif
static __inline void *emutls_memalign_alloc(size_t align, size_t size) { … }
static __inline void emutls_memalign_free(void *base) { … }
static __inline void emutls_setspecific(emutls_address_array *value) { … }
static __inline emutls_address_array *emutls_getspecific(void) { … }
static void emutls_key_destructor(void *ptr) { … }
static __inline void emutls_init(void) { … }
static __inline void emutls_init_once(void) { … }
static __inline void emutls_lock(void) { … }
static __inline void emutls_unlock(void) { … }
#else
#include <assert.h>
#include <malloc.h>
#include <stdio.h>
#include <windows.h>
static LPCRITICAL_SECTION emutls_mutex;
static DWORD emutls_tls_index = TLS_OUT_OF_INDEXES;
typedef uintptr_t gcc_word;
typedef void *gcc_pointer;
static void win_error(DWORD last_err, const char *hint) {
char *buffer = NULL;
if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, last_err, 0, (LPSTR)&buffer, 1, NULL)) {
fprintf(stderr, "Windows error: %s\n", buffer);
} else {
fprintf(stderr, "Unknown Windows error: %s\n", hint);
}
LocalFree(buffer);
}
static __inline void win_abort(DWORD last_err, const char *hint) {
win_error(last_err, hint);
abort();
}
static __inline void *emutls_memalign_alloc(size_t align, size_t size) {
void *base = _aligned_malloc(size, align);
if (!base)
win_abort(GetLastError(), "_aligned_malloc");
return base;
}
static __inline void emutls_memalign_free(void *base) { _aligned_free(base); }
static void emutls_exit(void) {
if (emutls_mutex) {
DeleteCriticalSection(emutls_mutex);
_aligned_free(emutls_mutex);
emutls_mutex = NULL;
}
if (emutls_tls_index != TLS_OUT_OF_INDEXES) {
emutls_shutdown((emutls_address_array *)TlsGetValue(emutls_tls_index));
TlsFree(emutls_tls_index);
emutls_tls_index = TLS_OUT_OF_INDEXES;
}
}
static BOOL CALLBACK emutls_init(PINIT_ONCE p0, PVOID p1, PVOID *p2) {
(void)p0;
(void)p1;
(void)p2;
emutls_mutex =
(LPCRITICAL_SECTION)_aligned_malloc(sizeof(CRITICAL_SECTION), 16);
if (!emutls_mutex) {
win_error(GetLastError(), "_aligned_malloc");
return FALSE;
}
InitializeCriticalSection(emutls_mutex);
emutls_tls_index = TlsAlloc();
if (emutls_tls_index == TLS_OUT_OF_INDEXES) {
emutls_exit();
win_error(GetLastError(), "TlsAlloc");
return FALSE;
}
atexit(&emutls_exit);
return TRUE;
}
static __inline void emutls_init_once(void) {
static INIT_ONCE once;
InitOnceExecuteOnce(&once, emutls_init, NULL, NULL);
}
static __inline void emutls_lock(void) { EnterCriticalSection(emutls_mutex); }
static __inline void emutls_unlock(void) { LeaveCriticalSection(emutls_mutex); }
static __inline void emutls_setspecific(emutls_address_array *value) {
if (TlsSetValue(emutls_tls_index, (LPVOID)value) == 0)
win_abort(GetLastError(), "TlsSetValue");
}
static __inline emutls_address_array *emutls_getspecific(void) {
LPVOID value = TlsGetValue(emutls_tls_index);
if (value == NULL) {
const DWORD err = GetLastError();
if (err != ERROR_SUCCESS)
win_abort(err, "TlsGetValue");
}
return (emutls_address_array *)value;
}
#if !defined(__ATOMIC_RELEASE)
#include <intrin.h>
enum { __ATOMIC_ACQUIRE = 2, __ATOMIC_RELEASE = 3 };
static __inline uintptr_t __atomic_load_n(void *ptr, unsigned type) {
assert(type == __ATOMIC_ACQUIRE);
#ifdef _WIN64
return InterlockedOr64(ptr, 0);
#else
return InterlockedOr(ptr, 0);
#endif
}
static __inline void __atomic_store_n(void *ptr, uintptr_t val, unsigned type) {
assert(type == __ATOMIC_RELEASE);
InterlockedExchangePointer((void *volatile *)ptr, (void *)val);
}
#endif
#endif
static size_t emutls_num_object = …;
static void emutls_shutdown(emutls_address_array *array) { … }
__emutls_control;
static __inline void *emutls_allocate_object(__emutls_control *control) { … }
static __inline uintptr_t emutls_get_index(__emutls_control *control) { … }
static __inline void emutls_check_array_set_size(emutls_address_array *array,
uintptr_t size) { … }
static __inline uintptr_t emutls_new_data_array_size(uintptr_t index) { … }
static __inline uintptr_t emutls_asize(uintptr_t N) { … }
static __inline emutls_address_array *
emutls_get_address_array(uintptr_t index) { … }
#ifndef _WIN32
__attribute__((visibility("default"), weak))
#endif
void *__emutls_get_address(__emutls_control *control) { … }
#ifdef __BIONIC__
__attribute__((visibility("hidden"))) void __emutls_unregister_key(void) {
if (emutls_key_created) {
pthread_key_delete(emutls_pthread_key);
emutls_key_created = false;
}
}
#endif