about summary refs log tree commit diff stats
path: root/src/libtools
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2021-03-02 15:18:23 +0100
committerptitSeb <sebastien.chev@gmail.com>2021-03-02 15:18:23 +0100
commiteb6c4594e1831daeddc469ed69c4dee917e627c1 (patch)
treeff8e5ec2506fde9ff69ca0850e84667669c8f471 /src/libtools
parent1b9d1dc6093028ceb0f2eeeccf9cfbc5610fcf30 (diff)
downloadbox64-eb6c4594e1831daeddc469ed69c4dee917e627c1.tar.gz
box64-eb6c4594e1831daeddc469ed69c4dee917e627c1.zip
Added basic thread infrastructure
Diffstat (limited to 'src/libtools')
-rwxr-xr-xsrc/libtools/threads.c808
1 files changed, 808 insertions, 0 deletions
diff --git a/src/libtools/threads.c b/src/libtools/threads.c
new file mode 100755
index 00000000..a245d6a9
--- /dev/null
+++ b/src/libtools/threads.c
@@ -0,0 +1,808 @@
+// __USE_UNIX98 is needed for sttype / gettype definition
+#define __USE_UNIX98
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <signal.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#include "debug.h"
+#include "box64context.h"
+#include "threads.h"
+#include "emu/x64emu_private.h"
+//#include "tools/bridge_private.h"
+#include "x64run.h"
+#include "x64emu.h"
+#include "box64stack.h"
+//#include "callback.h"
+#include "custommem.h"
+#include "khash.h"
+#include "emu/x64run_private.h"
+#include "x64trace.h"
+//#include "dynarec.h"
+//#include "bridge.h"
+#ifdef DYNAREC
+#include "dynablock.h"
+#endif
+
+//void _pthread_cleanup_push_defer(void* buffer, void* routine, void* arg);	// declare hidden functions
+//void _pthread_cleanup_pop_restore(void* buffer, int exec);
+//void _pthread_cleanup_push(void* buffer, void* routine, void* arg);	// declare hidden functions
+//void _pthread_cleanup_pop(void* buffer, int exec);
+
+typedef struct threadstack_s {
+	void* 	stack;
+	size_t 	stacksize;
+} threadstack_t;
+
+// longjmp / setjmp
+//typedef struct jump_buff_i386_s {
+// uint32_t save_ebx;
+// uint32_t save_esi;
+// uint32_t save_edi;
+// uint32_t save_ebp;
+// uint32_t save_esp;
+// uint32_t save_eip;
+//} jump_buff_i386_t;
+
+//typedef struct __jmp_buf_tag_s {
+//    jump_buff_i386_t __jmpbuf;
+//    int              __mask_was_saved;
+//    __sigset_t       __saved_mask;
+//} __jmp_buf_tag_t;
+
+//typedef struct x86_unwind_buff_s {
+//	struct {
+//		jump_buff_i386_t	__cancel_jmp_buf;	
+//		int					__mask_was_saved;
+//	} __cancel_jmp_buf[1];
+//	void *__pad[4];
+//} x86_unwind_buff_t __attribute__((__aligned__));
+
+KHASH_MAP_INIT_INT(threadstack, threadstack_t*)
+//KHASH_MAP_INIT_INT(cancelthread, __pthread_unwind_buf_t*)
+
+void CleanStackSize(box64context_t* context)
+{
+	threadstack_t *ts;
+	if(!context || !context->stacksizes)
+		return;
+	pthread_mutex_lock(&context->mutex_thread);
+	kh_foreach_value(context->stacksizes, ts, free(ts));
+	kh_destroy(threadstack, context->stacksizes);
+	context->stacksizes = NULL;
+	pthread_mutex_unlock(&context->mutex_thread);
+}
+
+void FreeStackSize(kh_threadstack_t* map, uintptr_t attr)
+{
+	pthread_mutex_lock(&my_context->mutex_thread);
+	khint_t k = kh_get(threadstack, map, attr);
+	if(k!=kh_end(map)) {
+		free(kh_value(map, k));
+		kh_del(threadstack, map, k);
+	}
+	pthread_mutex_unlock(&my_context->mutex_thread);
+}
+
+void AddStackSize(kh_threadstack_t* map, uintptr_t attr, void* stack, size_t stacksize)
+{
+	khint_t k;
+	int ret;
+	pthread_mutex_lock(&my_context->mutex_thread);
+	k = kh_put(threadstack, map, attr, &ret);
+	threadstack_t* ts = kh_value(map, k) = (threadstack_t*)calloc(1, sizeof(threadstack_t));
+	ts->stack = stack;
+	ts->stacksize = stacksize;
+	pthread_mutex_unlock(&my_context->mutex_thread);
+}
+
+// return stack from attr (or from current emu if attr is not found..., wich is wrong but approximate enough?)
+int GetStackSize(x64emu_t* emu, uintptr_t attr, void** stack, size_t* stacksize)
+{
+	if(emu->context->stacksizes && attr) {
+		pthread_mutex_lock(&my_context->mutex_thread);
+		khint_t k = kh_get(threadstack, emu->context->stacksizes, attr);
+		if(k!=kh_end(emu->context->stacksizes)) {
+			threadstack_t* ts = kh_value(emu->context->stacksizes, k);
+			*stack = ts->stack;
+			*stacksize = ts->stacksize;
+			pthread_mutex_unlock(&my_context->mutex_thread);
+			return 1;
+		}
+		pthread_mutex_unlock(&my_context->mutex_thread);
+	}
+	// should a Warning be emited?
+	*stack = emu->init_stack;
+	*stacksize = emu->size_stack;
+	return 0;
+}
+
+//static void InitCancelThread()
+//{
+//}
+
+//static void FreeCancelThread(box64context_t* context)
+//{
+//	if(!context)
+//		return;
+//}
+//static __pthread_unwind_buf_t* AddCancelThread(x86_unwind_buff_t* buff)
+//{
+//	__pthread_unwind_buf_t* r = (__pthread_unwind_buf_t*)calloc(1, sizeof(__pthread_unwind_buf_t));
+//	buff->__pad[1] = r;
+//	return r;
+//}
+
+//static __pthread_unwind_buf_t* GetCancelThread(x86_unwind_buff_t* buff)
+//{
+//	return (__pthread_unwind_buf_t*)buff->__pad[1];
+//}
+
+//static void DelCancelThread(x86_unwind_buff_t* buff)
+//{
+//	__pthread_unwind_buf_t* r = (__pthread_unwind_buf_t*)buff->__pad[1];
+//	free(r);
+//	buff->__pad[1] = NULL;
+//}
+
+typedef struct emuthread_s {
+	uintptr_t 	fnc;
+	void*		arg;
+	x64emu_t*	emu;
+} emuthread_t;
+
+static void emuthread_destroy(void* p)
+{
+	emuthread_t *et = (emuthread_t*)p;
+	FreeX64Emu(&et->emu);
+	free(et);
+}
+
+static pthread_key_t thread_key;
+static pthread_once_t thread_key_once = PTHREAD_ONCE_INIT;
+
+static void thread_key_alloc() {
+	pthread_key_create(&thread_key, emuthread_destroy);
+}
+
+void thread_set_emu(x64emu_t* emu)
+{
+	// create the key
+	pthread_once(&thread_key_once, thread_key_alloc);
+	emuthread_t *et = (emuthread_t*)pthread_getspecific(thread_key);
+	if(!et) {
+		et = (emuthread_t*)calloc(1, sizeof(emuthread_t));
+	} else {
+		if(et->emu != emu)
+			FreeX64Emu(&et->emu);
+	}
+	et->emu = emu;
+	et->emu->type = EMUTYPE_MAIN;
+	pthread_setspecific(thread_key, et);
+}
+
+x64emu_t* thread_get_emu()
+{
+	// create the key
+	pthread_once(&thread_key_once, thread_key_alloc);
+	emuthread_t *et = (emuthread_t*)pthread_getspecific(thread_key);
+	if(!et) {
+		int stacksize = 2*1024*1024;
+		// try to get stack size of the thread
+		pthread_attr_t attr;
+		if(!pthread_getattr_np(pthread_self(), &attr)) {
+			size_t stack_size;
+        	void *stack_addr;
+			if(!pthread_attr_getstack(&attr, &stack_addr, &stack_size))
+				stacksize = stack_size;
+			pthread_attr_destroy(&attr);
+		}
+		void* stack = calloc(1, stacksize);
+		x64emu_t *emu = NewX64Emu(my_context, 0, (uintptr_t)stack, stacksize, 1);
+		SetupX64Emu(emu);
+		thread_set_emu(emu);
+		return emu;
+	}
+	return et->emu;
+}
+
+static void* pthread_routine(void* p)
+{
+	// create the key
+	pthread_once(&thread_key_once, thread_key_alloc);
+	// free current emuthread if it exist
+	{
+		void* t = pthread_getspecific(thread_key);
+		if(t) {
+			// not sure how this could happens
+			printf_log(LOG_INFO, "Clean of an existing ET for Thread %04d\n", GetTID());
+			emuthread_destroy(t);
+		}
+	}
+	pthread_setspecific(thread_key, p);
+	// call the function
+	emuthread_t *et = (emuthread_t*)p;
+	et->emu->type = EMUTYPE_MAIN;
+	// setup callstack and run...
+	x64emu_t* emu = et->emu;
+    R_RSP -= 4;
+	uint64_t *sp = (uint64_t*)R_RSP;
+	*sp = (uintptr_t)et->arg;
+//	PushExit(emu);
+	R_RIP = et->fnc;
+//	DynaRun(et->emu);
+	void* ret = (void*)R_RAX;
+	//void* ret = (void*)RunFunctionWithEmu(et->emu, 0, et->fnc, 1, et->arg);
+	return ret;
+}
+
+EXPORT int my_pthread_attr_destroy(x64emu_t* emu, void* attr)
+{
+	if(emu->context->stacksizes)
+		FreeStackSize(emu->context->stacksizes, (uintptr_t)attr);
+	return pthread_attr_destroy(attr);
+}
+
+EXPORT int my_pthread_attr_getstack(x64emu_t* emu, void* attr, void** stackaddr, size_t* stacksize)
+{
+	int ret = pthread_attr_getstack(attr, stackaddr, stacksize);
+	if (ret==0)
+		GetStackSize(emu, (uintptr_t)attr, stackaddr, stacksize);
+	return ret;
+}
+
+EXPORT int my_pthread_attr_setstack(x64emu_t* emu, void* attr, void* stackaddr, size_t stacksize)
+{
+	if(!emu->context->stacksizes) {
+		emu->context->stacksizes = kh_init(threadstack);
+	}
+	AddStackSize(emu->context->stacksizes, (uintptr_t)attr, stackaddr, stacksize);
+	//Don't call actual setstack...
+	//return pthread_attr_setstack(attr, stackaddr, stacksize);
+	return pthread_attr_setstacksize(attr, stacksize);
+}
+
+//EXPORT int my_pthread_create(x64emu_t *emu, void* t, void* attr, void* start_routine, void* arg)
+//{
+//	int stacksize = 2*1024*1024;	//default stack size is 2Mo
+//	void* attr_stack;
+//	size_t attr_stacksize;
+//	int own;
+//	void* stack;
+//
+//	if(attr) {
+//		size_t stsize;
+//		if(pthread_attr_getstacksize(attr, &stsize)==0)
+//			stacksize = stsize;
+//	}
+//	if(GetStackSize(emu, (uintptr_t)attr, &attr_stack, &attr_stacksize))
+//	{
+//		stack = attr_stack;
+//		stacksize = attr_stacksize;
+//		own = 0;
+//	} else {
+//		stack = malloc(stacksize);
+//		own = 1;
+//	}
+//
+//	emuthread_t *et = (emuthread_t*)calloc(1, sizeof(emuthread_t));
+//    x64emu_t *emuthread = NewX86Emu(my_context, (uintptr_t)start_routine, (uintptr_t)stack, stacksize, own);
+//	SetupX86Emu(emuthread);
+//	SetFS(emuthread, GetFS(emu));
+//	et->emu = emuthread;
+//	et->fnc = (uintptr_t)start_routine;
+//	et->arg = arg;
+//	#ifdef DYNAREC
+//	if(box86_dynarec) {
+//		// pre-creation of the JIT code for the entry point of the thread
+//		dynablock_t *current = NULL;
+//		DBGetBlock(emu, (uintptr_t)start_routine, 1, &current);
+//	}
+//	#endif
+//	// create thread
+//	return pthread_create((pthread_t*)t, (const pthread_attr_t *)attr, 
+//		pthread_routine, et);
+//}
+
+void* my_prepare_thread(x64emu_t *emu, void* f, void* arg, int ssize, void** pet)
+{
+	int stacksize = (ssize)?ssize:(2*1024*1024);	//default stack size is 2Mo
+	void* stack = malloc(stacksize);
+	emuthread_t *et = (emuthread_t*)calloc(1, sizeof(emuthread_t));
+    x64emu_t *emuthread = NewX64Emu(emu->context, (uintptr_t)f, (uintptr_t)stack, stacksize, 1);
+	SetupX64Emu(emuthread);
+	SetFS(emuthread, GetFS(emu));
+	et->emu = emuthread;
+	et->fnc = (uintptr_t)f;
+	et->arg = arg;
+	#ifdef DYNAREC
+	// pre-creation of the JIT code for the entry point of the thread
+	dynablock_t *current = NULL;
+	DBGetBlock(emu, (uintptr_t)f, 1, &current);
+	#endif
+	*pet =  et;
+	return pthread_routine;
+}
+
+//void my_longjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val);
+
+//#define CANCEL_MAX 8
+//static __thread x64emu_t* cancel_emu[CANCEL_MAX] = {0};
+//static __thread x86_unwind_buff_t* cancel_buff[CANCEL_MAX] = {0};
+//static __thread int cancel_deep = 0;
+//EXPORT void my___pthread_register_cancel(void* E, void* B)
+//{
+//	// get a stack local copy of the args, as may be live in some register depending the architecture (like ARM)
+//	if(cancel_deep<0) {
+//		printf_log(LOG_NONE/*LOG_INFO*/, "BOX86: Warning, inconsistant value in __pthread_register_cancel (%d)\n", cancel_deep);
+//		cancel_deep = 0;
+//	}
+//	if(cancel_deep!=CANCEL_MAX-1) 
+//		++cancel_deep;
+//	else
+//		{printf_log(LOG_NONE/*LOG_INFO*/, "BOX86: Warning, calling __pthread_register_cancel(...) too many time\n");}
+//		
+//	cancel_emu[cancel_deep] = (x64emu_t*)E;
+//	// on i386, the function as __cleanup_fct_attribute attribute: so 1st parameter is in register
+//	x86_unwind_buff_t* buff = cancel_buff[cancel_deep] = (x86_unwind_buff_t*)((x64emu_t*)E)->regs[_AX].dword[0];
+//	__pthread_unwind_buf_t * pbuff = AddCancelThread(buff);
+//	if(__sigsetjmp((struct __jmp_buf_tag*)(void*)pbuff->__cancel_jmp_buf, 0)) {
+//		//DelCancelThread(cancel_buff);	// no del here, it will be delete by unwind_next...
+//		int i = cancel_deep--;
+//		x64emu_t* emu = cancel_emu[i];
+//		my_longjmp(emu, cancel_buff[i]->__cancel_jmp_buf, 1);
+//		DynaRun(emu);	// resume execution
+//		return;
+//	}
+//
+//	__pthread_register_cancel(pbuff);
+//}
+
+//EXPORT void my___pthread_unregister_cancel(x64emu_t* emu, x86_unwind_buff_t* buff)
+//{
+//	// on i386, the function as __cleanup_fct_attribute attribute: so 1st parameter is in register
+//	buff = (x86_unwind_buff_t*)R_EAX;
+//	__pthread_unwind_buf_t * pbuff = GetCancelThread(buff);
+//	__pthread_unregister_cancel(pbuff);
+//
+//	--cancel_deep;
+//	DelCancelThread(buff);
+//}
+
+//EXPORT void my___pthread_unwind_next(x64emu_t* emu, void* p)
+//{
+//	// on i386, the function as __cleanup_fct_attribute attribute: so 1st parameter is in register
+//	x86_unwind_buff_t* buff = (x86_unwind_buff_t*)R_EAX;
+//	__pthread_unwind_buf_t pbuff = *GetCancelThread(buff);
+//	DelCancelThread(buff);
+//	// function is noreturn, putting stuff on the stack to have it auto-free (is that correct?)
+//	__pthread_unwind_next(&pbuff);
+//	// just in case it does return
+//	emu->quit = 1;
+//}
+#if 0
+KHASH_MAP_INIT_INT(once, int)
+
+#define SUPER() \
+GO(0)			\
+GO(1)			\
+GO(2)			\
+GO(3)			\
+GO(4)			\
+GO(5)			\
+GO(6)			\
+GO(7)			\
+GO(8)			\
+GO(9)			\
+GO(10)			\
+GO(11)			\
+GO(12)			\
+GO(13)			\
+GO(14)			\
+GO(15)			\
+GO(16)			\
+GO(17)			\
+GO(18)			\
+GO(19)			\
+GO(20)			\
+GO(21)			\
+GO(22)			\
+GO(23)			\
+GO(24)			\
+GO(25)			\
+GO(26)			\
+GO(27)			\
+GO(28)			\
+GO(29)			
+
+// once_callback
+#define GO(A)   \
+static uintptr_t my_once_callback_fct_##A = 0;  \
+static void my_once_callback_##A()    			\
+{                                       		\
+    RunFunction(my_context, my_once_callback_fct_##A, 0, 0);\
+}
+SUPER()
+#undef GO
+static void* findonce_callbackFct(void* fct)
+{
+    if(!fct) return fct;
+    if(GetNativeFnc((uintptr_t)fct))  return GetNativeFnc((uintptr_t)fct);
+    #define GO(A) if(my_once_callback_fct_##A == (uintptr_t)fct) return my_once_callback_##A;
+    SUPER()
+    #undef GO
+    #define GO(A) if(my_once_callback_fct_##A == 0) {my_once_callback_fct_##A = (uintptr_t)fct; return my_once_callback_##A; }
+    SUPER()
+    #undef GO
+    printf_log(LOG_NONE, "Warning, no more slot for pthread once_callback callback\n");
+    return NULL;
+}
+// key_destructor
+#define GO(A)   \
+static uintptr_t my_key_destructor_fct_##A = 0;  \
+static void my_key_destructor_##A(void* a)    			\
+{                                       		\
+    RunFunction(my_context, my_key_destructor_fct_##A, 1, a);\
+}
+SUPER()
+#undef GO
+static void* findkey_destructorFct(void* fct)
+{
+    if(!fct) return fct;
+    if(GetNativeFnc((uintptr_t)fct))  return GetNativeFnc((uintptr_t)fct);
+    #define GO(A) if(my_key_destructor_fct_##A == (uintptr_t)fct) return my_key_destructor_##A;
+    SUPER()
+    #undef GO
+    #define GO(A) if(my_key_destructor_fct_##A == 0) {my_key_destructor_fct_##A = (uintptr_t)fct; return my_key_destructor_##A; }
+    SUPER()
+    #undef GO
+    printf_log(LOG_NONE, "Warning, no more slot for pthread key_destructor callback\n");
+    return NULL;
+}
+// cleanup_routine
+#define GO(A)   \
+static uintptr_t my_cleanup_routine_fct_##A = 0;  \
+static void my_cleanup_routine_##A(void* a)    			\
+{                                       		\
+    RunFunction(my_context, my_cleanup_routine_fct_##A, 1, a);\
+}
+SUPER()
+#undef GO
+static void* findcleanup_routineFct(void* fct)
+{
+    if(!fct) return fct;
+    if(GetNativeFnc((uintptr_t)fct))  return GetNativeFnc((uintptr_t)fct);
+    #define GO(A) if(my_cleanup_routine_fct_##A == (uintptr_t)fct) return my_cleanup_routine_##A;
+    SUPER()
+    #undef GO
+    #define GO(A) if(my_cleanup_routine_fct_##A == 0) {my_cleanup_routine_fct_##A = (uintptr_t)fct; return my_cleanup_routine_##A; }
+    SUPER()
+    #undef GO
+    printf_log(LOG_NONE, "Warning, no more slot for pthread cleanup_routine callback\n");
+    return NULL;
+}
+
+#undef SUPER
+
+int EXPORT my_pthread_once(x64emu_t* emu, void* once, void* cb)
+{
+	return pthread_once(once, findonce_callbackFct(cb));
+}
+EXPORT int my___pthread_once(x64emu_t* emu, void* once, void* cb) __attribute__((alias("my_pthread_once")));
+
+EXPORT int my_pthread_key_create(x64emu_t* emu, void* key, void* dtor)
+{
+	return pthread_key_create(key, findkey_destructorFct(dtor));
+}
+EXPORT int my___pthread_key_create(x64emu_t* emu, void* key, void* dtor) __attribute__((alias("my_pthread_key_create")));
+
+// phtread_cond_init with null attr seems to only write 1 (NULL) dword on x86, while it's 48 bytes on ARM. 
+// Not sure why as sizeof(pthread_cond_init) is 48 on both platform... But Neverwinter Night init seems to rely on that
+// What about cond that are statically initialized? 
+// Note, this is is a versionned function (the pthread_cond_*), and this seems to correspond to an old behaviour
+
+KHASH_MAP_INIT_INT(mapcond, pthread_cond_t*);
+
+// should all access to that map be behind a mutex?
+kh_mapcond_t *mapcond = NULL;
+
+static pthread_cond_t* add_cond(void* cond)
+{
+	pthread_mutex_lock(&my_context->mutex_thread);
+	khint_t k;
+	int ret;
+	pthread_cond_t *c;
+	k = kh_put(mapcond, mapcond, (uintptr_t)cond, &ret);
+	if(!ret)
+		c = kh_value(mapcond, k);	// already there... reinit an existing one?
+	else 
+		c = kh_value(mapcond, k) = (pthread_cond_t*)calloc(1, sizeof(pthread_cond_t));
+	*(void**)cond = cond;
+	pthread_mutex_unlock(&my_context->mutex_thread);
+	return c;
+}
+static pthread_cond_t* get_cond(void* cond)
+{
+	pthread_cond_t* ret;
+	int r;
+	pthread_mutex_lock(&my_context->mutex_thread);
+	khint_t k = kh_get(mapcond, mapcond, *(uintptr_t*)cond);
+	if(k==kh_end(mapcond)) {
+		khint_t k = kh_get(mapcond, mapcond, (uintptr_t)cond);
+		if(k==kh_end(mapcond)) {
+			printf_log(LOG_DEBUG, "BOX86: Note: phtread_cond not found, create a new empty one\n");
+			ret = (pthread_cond_t*)calloc(1, sizeof(pthread_cond_t));
+			k = kh_put(mapcond, mapcond, (uintptr_t)cond, &r);
+			kh_value(mapcond, k) = ret;
+			*(void**)cond = cond;
+			pthread_cond_init(ret, NULL);
+		} else
+			ret = kh_value(mapcond, k);
+	} else
+		ret = kh_value(mapcond, k);
+	pthread_mutex_unlock(&my_context->mutex_thread);
+	return ret;
+}
+static void del_cond(void* cond)
+{
+	if(!mapcond)
+		return;
+	pthread_mutex_lock(&my_context->mutex_thread);
+	khint_t k = kh_get(mapcond, mapcond, *(uintptr_t*)cond);
+	if(k!=kh_end(mapcond)) {
+		free(kh_value(mapcond, k));
+		kh_del(mapcond, mapcond, k);
+	}
+	pthread_mutex_unlock(&my_context->mutex_thread);
+}
+pthread_mutex_t* getAlignedMutex(pthread_mutex_t* m);
+
+EXPORT int my_pthread_cond_broadcast(x64emu_t* emu, void* cond)
+{
+	pthread_cond_t * c = get_cond(cond);
+	return pthread_cond_broadcast(c);
+}
+EXPORT int my_pthread_cond_destroy(x64emu_t* emu, void* cond)
+{
+	pthread_cond_t * c = get_cond(cond);
+	int ret = pthread_cond_destroy(c);
+	if(c!=cond) del_cond(cond);
+	return ret;
+}
+EXPORT int my_pthread_cond_init(x64emu_t* emu, void* cond, void* attr)
+{
+	pthread_cond_t *c = add_cond(cond);
+	return pthread_cond_init(c, (const pthread_condattr_t*)attr);
+}
+EXPORT int my_pthread_cond_signal(x64emu_t* emu, void* cond)
+{
+	pthread_cond_t * c = get_cond(cond);
+	return pthread_cond_signal(c);
+}
+EXPORT int my_pthread_cond_timedwait(x64emu_t* emu, void* cond, void* mutex, void* abstime)
+{
+	pthread_cond_t * c = get_cond(cond);
+	return pthread_cond_timedwait(c, getAlignedMutex((pthread_mutex_t*)mutex), (const struct timespec*)abstime);
+}
+EXPORT int my_pthread_cond_wait(x64emu_t* emu, void* cond, void* mutex)
+{
+	pthread_cond_t * c = get_cond(cond);
+	return pthread_cond_wait(c, getAlignedMutex((pthread_mutex_t*)mutex));
+}
+
+EXPORT int my_pthread_mutexattr_setkind_np(x64emu_t* emu, void* t, int kind)
+{
+    // does "kind" needs some type of translation?
+    return pthread_mutexattr_settype(t, kind);
+}
+
+EXPORT int my_pthread_attr_setscope(x64emu_t* emu, void* attr, int scope)
+{
+    if(scope!=PTHREAD_SCOPE_SYSTEM) printf_log(LOG_INFO, "Warning, scope of call to pthread_attr_setscope(...) changed from %d to PTHREAD_SCOPE_SYSTEM\n", scope);
+	return pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM);
+    //The scope is either PTHREAD_SCOPE_SYSTEM or PTHREAD_SCOPE_PROCESS
+    // but PTHREAD_SCOPE_PROCESS doesn't seem supported on ARM linux, and PTHREAD_SCOPE_SYSTEM is default
+}
+
+EXPORT void my__pthread_cleanup_push_defer(x64emu_t* emu, void* buffer, void* routine, void* arg)
+{
+	_pthread_cleanup_push_defer(buffer, findcleanup_routineFct(routine), arg);
+}
+
+EXPORT void my__pthread_cleanup_push(x64emu_t* emu, void* buffer, void* routine, void* arg)
+{
+	_pthread_cleanup_push(buffer, findcleanup_routineFct(routine), arg);
+}
+
+EXPORT void my__pthread_cleanup_pop_restore(x64emu_t* emu, void* buffer, int exec)
+{
+	_pthread_cleanup_pop_restore(buffer, exec);
+}
+
+EXPORT void my__pthread_cleanup_pop(x64emu_t* emu, void* buffer, int exec)
+{
+	_pthread_cleanup_pop(buffer, exec);
+}
+
+// getaffinity_np (pthread or attr) hav an "old" version (glibc-2.3.3) that only have 2 args, cpusetsize is omited
+EXPORT int my_pthread_getaffinity_np(x64emu_t* emu, pthread_t thread, int cpusetsize, void* cpuset)
+{
+	if(cpusetsize>0x1000) {
+		// probably old version of the function, that didn't have cpusetsize....
+		cpuset = (void*)cpusetsize;
+		cpusetsize = sizeof(cpu_set_t);
+	} 
+
+	int ret = pthread_getaffinity_np(thread, cpusetsize, cpuset);
+	if(ret<0) {
+		printf_log(LOG_INFO, "Warning, pthread_getaffinity_np(%p, %d, %p) errored, with errno=%d\n", (void*)thread, cpusetsize, cpuset, errno);
+	}
+
+    return ret;
+}
+
+EXPORT int my_pthread_setaffinity_np(x64emu_t* emu, pthread_t thread, int cpusetsize, void* cpuset)
+{
+	if(cpusetsize>0x1000) {
+		// probably old version of the function, that didn't have cpusetsize....
+		cpuset = (void*)cpusetsize;
+		cpusetsize = sizeof(cpu_set_t);
+	} 
+
+	int ret = pthread_setaffinity_np(thread, cpusetsize, cpuset);
+	if(ret<0) {
+		printf_log(LOG_INFO, "Warning, pthread_setaffinity_np(%p, %d, %p) errored, with errno=%d\n", (void*)thread, cpusetsize, cpuset, errno);
+	}
+
+    return ret;
+}
+
+EXPORT int my_pthread_attr_setaffinity_np(x64emu_t* emu, void* attr, uint32_t cpusetsize, void* cpuset)
+{
+	if(cpusetsize>0x1000) {
+		// probably old version of the function, that didn't have cpusetsize....
+		cpuset = (void*)cpusetsize;
+		cpusetsize = sizeof(cpu_set_t);
+	} 
+
+	int ret = pthread_attr_setaffinity_np(attr, cpusetsize, cpuset);
+	if(ret<0) {
+		printf_log(LOG_INFO, "Warning, pthread_attr_setaffinity_np(%p, %d, %p) errored, with errno=%d\n", attr, cpusetsize, cpuset, errno);
+	}
+
+    return ret;
+}
+
+EXPORT int my_pthread_kill(x64emu_t* emu, void* thread, int sig)
+{
+    // check for old "is everything ok?"
+    if(thread==NULL && sig==0)
+        return pthread_kill(pthread_self(), 0);
+    return pthread_kill((pthread_t)thread, sig);
+}
+
+EXPORT void my_pthread_exit(x64emu_t* emu, void* retval)
+{
+	emu->quit = 1;	// to be safe
+	pthread_exit(retval);
+}
+
+#ifndef NOALIGN
+// mutex alignment
+KHASH_MAP_INIT_INT(mutex, pthread_mutex_t*)
+
+static kh_mutex_t* unaligned_mutex = NULL;
+
+pthread_mutex_t* getAlignedMutex(pthread_mutex_t* m)
+{
+	if(!(((uintptr_t)m)&3))
+		return m;
+	khint_t k = kh_get(mutex, unaligned_mutex, (uintptr_t)m);
+	if(k!=kh_end(unaligned_mutex))
+		return kh_value(unaligned_mutex, k);
+	int r;
+	k = kh_put(mutex, unaligned_mutex, (uintptr_t)m, &r);
+	pthread_mutex_t* ret = kh_value(unaligned_mutex, k) = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+	memcpy(ret, m, sizeof(pthread_mutex_t));
+	return ret;
+}
+EXPORT int my_pthread_mutex_destroy(pthread_mutex_t *m)
+{
+	if(!(((uintptr_t)m)&3))
+		return pthread_mutex_destroy(m);
+	khint_t k = kh_get(mutex, unaligned_mutex, (uintptr_t)m);
+	if(k!=kh_end(unaligned_mutex)) {
+		pthread_mutex_t *n = kh_value(unaligned_mutex, k);
+		kh_del(mutex, unaligned_mutex, k);
+		int ret = pthread_mutex_destroy(n);
+		free(n);
+		return ret;
+	}
+	return pthread_mutex_destroy(m);
+}
+int my___pthread_mutex_destroy(pthread_mutex_t *m) __attribute__((alias("my_pthread_mutex_destroy")));
+
+EXPORT int my_pthread_mutex_init(pthread_mutex_t *m, pthread_mutexattr_t *att)
+{
+	return pthread_mutex_init(getAlignedMutex(m), att);
+}
+EXPORT int my___pthread_mutex_init(pthread_mutex_t *m, pthread_mutexattr_t *att) __attribute__((alias("my_pthread_mutex_init")));
+
+EXPORT int my_pthread_mutex_lock(pthread_mutex_t *m)
+{
+	return pthread_mutex_lock(getAlignedMutex(m));
+}
+EXPORT int my___pthread_mutex_lock(pthread_mutex_t *m) __attribute__((alias("my_pthread_mutex_lock")));
+
+EXPORT int my_pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec * t)
+{
+	return pthread_mutex_timedlock(getAlignedMutex(m), t);
+}
+EXPORT int my___pthread_mutex_trylock(pthread_mutex_t *m, const struct timespec * t) __attribute__((alias("my_pthread_mutex_timedlock")));
+
+EXPORT int my_pthread_mutex_trylock(pthread_mutex_t *m)
+{
+	return pthread_mutex_trylock(getAlignedMutex(m));
+}
+EXPORT int my___pthread_mutex_unlock(pthread_mutex_t *m) __attribute__((alias("my_pthread_mutex_trylock")));
+
+EXPORT int my_pthread_mutex_unlock(pthread_mutex_t *m)
+{
+	return pthread_mutex_unlock(getAlignedMutex(m));
+}
+
+#endif
+#endif
+//static void emujmpbuf_destroy(void* p)
+//{
+//	emu_jmpbuf_t *ej = (emu_jmpbuf_t*)p;
+//	free(ej->jmpbuf);
+//	free(ej);
+//}
+
+//static pthread_key_t jmpbuf_key;
+
+//emu_jmpbuf_t* GetJmpBuf()
+//{
+//	emu_jmpbuf_t *ejb = (emu_jmpbuf_t*)pthread_getspecific(jmpbuf_key);
+//	if(!ejb) {
+//		ejb = (emu_jmpbuf_t*)calloc(1, sizeof(emu_jmpbuf_t));
+//		ejb->jmpbuf = calloc(1, sizeof(struct __jmp_buf_tag));
+//		pthread_setspecific(jmpbuf_key, ejb);
+//	}
+//	return ejb;
+//}
+
+void init_pthread_helper()
+{
+//	InitCancelThread();
+//	mapcond = kh_init(mapcond);
+//	pthread_key_create(&jmpbuf_key, emujmpbuf_destroy);
+#ifndef NOALIGN
+//	unaligned_mutex = kh_init(mutex);
+#endif
+}
+
+void fini_pthread_helper(box64context_t* context)
+{
+//	FreeCancelThread(context);
+	CleanStackSize(context);
+//	pthread_cond_t *cond;
+//	kh_foreach_value(mapcond, cond, 
+//		pthread_cond_destroy(cond);
+//		free(cond);
+//	);
+//	kh_destroy(mapcond, mapcond);
+//	mapcond = NULL;
+#ifndef NOALIGN
+//	pthread_mutex_t *m;
+//	kh_foreach_value(unaligned_mutex, m, 
+//		pthread_mutex_destroy(m);
+//		free(m);
+//	);
+//	kh_destroy(mutex, unaligned_mutex);
+#endif
+}