From: Grigory Vasilyev h0tc0d3@gmail.com
--- include/Makefile.in | 1 + include/wine/mutex.h | 130 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 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..ab407269b15 --- /dev/null +++ b/include/wine/mutex.h @@ -0,0 +1,130 @@ +#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 <stdint.h> +#include <unistd.h> +#include <stdatomic.h> +#include <sys/types.h> +#include <sys/syscall.h> +#include <linux/futex.h> + +#define WINE_MUTEX_TYPE _Atomic 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(__WINE_MUTEX__) \ + do { \ + int __wine_mutex_expected = WINE_MUTEX_UNLOCKED; \ + if (!atomic_compare_exchange_strong(__WINE_MUTEX__, &__wine_mutex_expected, WINE_MUTEX_LOCKED_NOWAIT)) { \ + if (__wine_mutex_expected == WINE_MUTEX_LOCKED_NOWAIT) { \ + __wine_mutex_expected = atomic_exchange(__WINE_MUTEX__, WINE_MUTEX_LOCKED_WAIT); \ + } \ + while (__wine_mutex_expected != WINE_MUTEX_UNLOCKED) { \ + syscall(SYS_futex, __WINE_MUTEX__, FUTEX_WAIT, WINE_MUTEX_LOCKED_WAIT, NULL, NULL, 0); \ + __wine_mutex_expected = atomic_exchange(__WINE_MUTEX__, WINE_MUTEX_LOCKED_WAIT); \ + } \ + } \ + } while (0) + +#define WINE_MUTEX_UNLOCK(__WINE_MUTEX__) \ + do { \ + if (atomic_load(__WINE_MUTEX__) && atomic_fetch_sub(__WINE_MUTEX__, 1) == WINE_MUTEX_LOCKED_WAIT) { \ + atomic_store(__WINE_MUTEX__, WINE_MUTEX_UNLOCKED); \ + syscall(SYS_futex, __WINE_MUTEX__, FUTEX_WAKE, 1, NULL, NULL, 0); \ + } \ + } while (0) + +#define WINE_MUTEX_DESTROY(__WINE_MUTEX__) WINE_MUTEX_UNLOCK(__WINE_MUTEX__) + +struct __wine_mutex_recursive +{ + _Atomic pid_t owner; + WINE_MUTEX_TYPE mutex; +}; + +#define WINE_MUTEX_RECURSIVE_TYPE struct __wine_mutex_recursive + +#define WINE_MUTEX_RECURSIVE_INIT(__WINE_MUTEX__) \ + do { \ + WINE_MUTEX_RECURSIVE_TYPE *__wine_mutex = __WINE_MUTEX__; \ + atomic_store(&__wine_mutex->owner, 0); \ + atomic_store(&__wine_mutex->mutex, WINE_MUTEX_UNLOCKED); \ + } while (0) + +#define WINE_MUTEX_RECURSIVE_LOCK(__WINE_MUTEX__) \ + do { \ + pid_t tid = 0; \ + int __wine_mutex_expected = WINE_MUTEX_UNLOCKED; \ + WINE_MUTEX_RECURSIVE_TYPE *__wine_mutex = __WINE_MUTEX__; \ + tid = syscall(SYS_gettid); \ + if (atomic_load(&__wine_mutex->owner) != tid) { \ + if (atomic_compare_exchange_strong(&__wine_mutex->owner, &__wine_mutex_expected, tid)) { \ + atomic_store(&__wine_mutex->mutex, WINE_MUTEX_LOCKED_NOWAIT); \ + } else { \ + if (atomic_load(&__wine_mutex->mutex) == WINE_MUTEX_LOCKED_NOWAIT) { \ + __wine_mutex_expected = atomic_exchange(&__wine_mutex->mutex, WINE_MUTEX_LOCKED_WAIT); \ + } \ + while (__wine_mutex_expected != WINE_MUTEX_UNLOCKED) { \ + syscall(SYS_futex, &__wine_mutex->mutex, FUTEX_WAIT, WINE_MUTEX_LOCKED_WAIT, NULL, NULL, 0); \ + __wine_mutex_expected = atomic_exchange(&__wine_mutex->mutex, WINE_MUTEX_LOCKED_WAIT); \ + } \ + atomic_store(&__wine_mutex->owner, tid); \ + } \ + } \ + } while (0) + +#define WINE_MUTEX_RECURSIVE_UNLOCK(__WINE_MUTEX__) \ + do { \ + pid_t tid = 0; \ + WINE_MUTEX_RECURSIVE_TYPE *__wine_mutex = __WINE_MUTEX__; \ + tid = syscall(SYS_gettid); \ + if (atomic_load(&__wine_mutex->owner) == tid && atomic_load(&__wine_mutex->mutex) \ + && atomic_fetch_sub(&__wine_mutex->mutex, 1) == WINE_MUTEX_LOCKED_WAIT) { \ + atomic_store(&__wine_mutex->mutex, WINE_MUTEX_UNLOCKED); \ + atomic_store(&__wine_mutex->owner, 0); \ + syscall(SYS_futex, &__wine_mutex->mutex, FUTEX_WAKE, 1, NULL, NULL, 0); \ + } \ + } while (0) + +#define WINE_MUTEX_RECURSIVE_DESTROY(__WINE_MUTEX__) \ + do { \ + WINE_MUTEX_RECURSIVE_TYPE *__wine_mutex = __WINE_MUTEX__; \ + atomic_store(&__wine_mutex->owner, 0); \ + atomic_store(&__wine_mutex->mutex, 0); \ + } while (0) + +#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(__WINE_MUTEX__) pthread_mutex_lock(__WINE_MUTEX__) +#define WINE_MUTEX_UNLOCK(__WINE_MUTEX__) pthread_mutex_unlock(__WINE_MUTEX__) +#define WINE_MUTEX_DESTROY(__WINE_MUTEX__) pthread_mutex_destroy(__WINE_MUTEX__) +#define WINE_MUTEX_RECURSIVE_TYPE pthread_mutex_t +#define WINE_MUTEX_RECURSIVE_INIT(__WINE_MUTEX__) \ + do { \ + pthread_mutexattr_t attr; \ + pthread_mutexattr_init(&attr); \ + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \ + pthread_mutex_init(__WINE_MUTEX__, &attr); \ + pthread_mutexattr_destroy(&attr); \ + } while (0) +#define WINE_MUTEX_RECURSIVE_LOCK(__WINE_MUTEX__) pthread_mutex_lock(__WINE_MUTEX__) +#define WINE_MUTEX_RECURSIVE_UNLOCK(__WINE_MUTEX__) pthread_mutex_unlock(__WINE_MUTEX__) +#define WINE_MUTEX_RECURSIVE_DESTROY(__WINE_MUTEX__) pthread_mutex_destroy(__WINE_MUTEX__) +#endif + +#endif /* __WINE_WINE_MUTEX_H */