From: Grigory Vasilyev h0tc0d3@gmail.com
--- include/Makefile.in | 1 + include/wine/mutex.h | 80 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 include/wine/mutex.h
diff --git a/include/Makefile.in b/include/Makefile.in index bbf28cfc87e..84742dded5c 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -920,6 +920,7 @@ SOURCES = \ wine/mmsystem16.h \ wine/mscvpdb.h \ wine/mssign.h \ + wine/mutex.h \ wine/nsi.h \ wine/orpc.idl \ wine/plugplay.idl \ diff --git a/include/wine/mutex.h b/include/wine/mutex.h new file mode 100644 index 00000000000..ff58281cb3c --- /dev/null +++ b/include/wine/mutex.h @@ -0,0 +1,80 @@ +#ifndef __WINE_WINE_MUTEX_H +#define __WINE_WINE_MUTEX_H + +#if defined(WINE_USE_ATOMIC_LOCKS) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#ifndef __STDC_NO_ATOMICS__ + +#include <stdatomic.h> +#include <stdint.h> +#include <unistd.h> +#include <linux/futex.h> +#include <sys/syscall.h> + +#define WINE_MUTEX_TYPE _Atomic unsigned int +#if __STDC_VERSION__ >= 201710L +#define WINE_MUTEX_INIT 0 +#else +#define WINE_MUTEX_INIT ATOMIC_VAR_INIT(0) +#endif + +#define WINE_MUTEX_UNLOCKED 0 // Mutex Unlocked +#define WINE_MUTEX_LOCKED_NOWAIT 1 // Mutex Locked and no waiters +#define WINE_MUTEX_LOCKED_WAIT 2 // Mutex Locked and have waiters + +#define WINE_MUTEX_LOCK(RESOURCE) do { \ + unsigned int expected = 0; \ + if (!atomic_compare_exchange_strong(RESOURCE, &expected, WINE_MUTEX_LOCKED_NOWAIT)) { \ + if (expected == WINE_MUTEX_LOCKED_NOWAIT) { \ + expected = atomic_exchange(RESOURCE, WINE_MUTEX_LOCKED_WAIT); \ + } \ + while(expected != WINE_MUTEX_UNLOCKED) { \ + syscall(SYS_futex, RESOURCE, FUTEX_WAIT, WINE_MUTEX_LOCKED_WAIT, NULL, NULL, 0); \ + expected = atomic_exchange(RESOURCE, WINE_MUTEX_LOCKED_WAIT); \ + } \ + } \ +} while(0) + +#define WINE_MUTEX_UNLOCK(RESOURCE) do { \ + if(atomic_fetch_sub(RESOURCE, 1) != WINE_MUTEX_LOCKED_NOWAIT) { \ + atomic_store(RESOURCE, 0); \ + syscall(SYS_futex, RESOURCE, FUTEX_WAKE, 1, NULL, NULL, 0); \ + } \ +} while(0) + +#define WINE_MUTEX_DESTROY(RESOURCE) WINE_MUTEX_UNLOCK(RESOURCE) + +#define WINE_MUTEX_RECURSIVE_TYPE pthread_mutex_t +#define WINE_MUTEX_RECURSIVE_INIT(RESOURCE) do { \ + pthread_mutexattr_t attr; \ + pthread_mutexattr_init( &attr ); \ + pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); \ + pthread_mutex_init( RESOURCE, &attr ); \ + pthread_mutexattr_destroy( &attr ); \ +} while(0) +#define WINE_MUTEX_RECURSIVE_LOCK(RESOURCE) pthread_mutex_lock(RESOURCE) +#define WINE_MUTEX_RECURSIVE_UNLOCK(RESOURCE) pthread_mutex_unlock(RESOURCE) +#define WINE_MUTEX_RECURSIVE_DESTROY(RESOURCE) pthread_mutex_destroy(RESOURCE) +#else +#error C11 Atomic operations not supported. Compiler defined __STDC_NO_ATOMICS__. +#endif +#else +#error C11 Atomic operations not supported. C version is lower than C11 or WINE_USE_ATOMIC_LOCKS not defined. +#define WINE_MUTEX_TYPE pthread_mutex_t +#define WINE_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER +#define WINE_MUTEX_LOCK(RESOURCE) pthread_mutex_lock(RESOURCE) +#define WINE_MUTEX_UNLOCK(RESOURCE) pthread_mutex_unlock(RESOURCE) +#define WINE_MUTEX_DESTROY(RESOURCE) pthread_mutex_destroy(RESOURCE) +#define WINE_MUTEX_RECURSIVE_TYPE pthread_mutex_t +#define WINE_MUTEX_RECURSIVE_INIT(RESOURCE) do { \ + pthread_mutexattr_t attr; \ + pthread_mutexattr_init( &attr ); \ + pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); \ + pthread_mutex_init( RESOURCE, &attr ); \ + pthread_mutexattr_destroy( &attr ); \ +} while(0) +#define WINE_MUTEX_RECURSIVE_LOCK(RESOURCE) pthread_mutex_lock(RESOURCE) +#define WINE_MUTEX_RECURSIVE_UNLOCK(RESOURCE) pthread_mutex_unlock(RESOURCE) +#define WINE_MUTEX_RECURSIVE_DESTROY(RESOURCE) pthread_mutex_destroy(RESOURCE) +#endif + +#endif /* __WINE_WINE_MUTEX_H */