From: Grigory Vasilyev h0tc0d3@gmail.com
--- include/Makefile.in | 1 + include/wine/mutex.h | 132 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 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..f9d54cce956 --- /dev/null +++ b/include/wine/mutex.h @@ -0,0 +1,132 @@ +#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 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 __wine_mutex_expected = WINE_MUTEX_UNLOCKED; \ + if (!atomic_compare_exchange_strong(RESOURCE, &__wine_mutex_expected, WINE_MUTEX_LOCKED_NOWAIT)) { \ + if (__wine_mutex_expected == WINE_MUTEX_LOCKED_NOWAIT) { \ + __wine_mutex_expected = atomic_exchange(RESOURCE, WINE_MUTEX_LOCKED_WAIT); \ + } \ + while (__wine_mutex_expected != WINE_MUTEX_UNLOCKED) { \ + syscall(SYS_futex, RESOURCE, FUTEX_WAIT, WINE_MUTEX_LOCKED_WAIT, NULL, NULL, 0); \ + __wine_mutex_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) + +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(RESOURCE) \ + do { \ + WINE_MUTEX_RECURSIVE_TYPE *__wine_mutex = RESOURCE; \ + atomic_store(&__wine_mutex->owner, 0); \ + atomic_store(&__wine_mutex->mutex, WINE_MUTEX_UNLOCKED); \ + } while (0) + +#define WINE_MUTEX_RECURSIVE_LOCK(RESOURCE) \ + do { \ + pid_t tid = 0; \ + unsigned int __wine_mutex_expected = WINE_MUTEX_UNLOCKED; \ + WINE_MUTEX_RECURSIVE_TYPE *__wine_mutex = RESOURCE; \ + tid = syscall(SYS_gettid); \ + if (atomic_load(&__wine_mutex->owner) != tid) { \ + if (!atomic_load(&__wine_mutex->owner)) { \ + atomic_store(&__wine_mutex->owner, 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(RESOURCE) \ + do { \ + pid_t tid = 0; \ + WINE_MUTEX_RECURSIVE_TYPE *__wine_mutex = RESOURCE; \ + tid = syscall(SYS_gettid); \ + if (atomic_load(&__wine_mutex->owner) == tid) { \ + if (atomic_fetch_sub(&__wine_mutex->mutex, 1) != WINE_MUTEX_LOCKED_NOWAIT) { \ + atomic_store(&__wine_mutex->owner, 0); \ + atomic_store(&__wine_mutex->mutex, 0); \ + syscall(SYS_futex, &__wine_mutex->mutex, FUTEX_WAKE, 1, NULL, NULL, 0); \ + } \ + } \ + } while (0) + +#define WINE_MUTEX_RECURSIVE_DESTROY(RESOURCE) \ + do { \ + WINE_MUTEX_RECURSIVE_TYPE *__wine_mutex = RESOURCE; \ + 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(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 */