Hello, In winpthreads, since we integrated test suite with Automake, we have a few tests marked as XFAIL:
- Some mutex tests - Two spinlock tests (spin1.c and spin3.c) The first two attached patches address issues with mutex tests; more details are in commit messages. Current spinlock implementation in winpthreads does not keep track of lock ownership. It has an effect that thread A can unlock lock held by thread B; this behavior does not conform to POSIX specification and causes spin3.c to fail. The rest of attached patches contain new spinlock implementation and updates for pthread_spinlock/* tests. These changes passed CI: https://github.com/maiddaisuki/mingw-w64/actions/runs/25665243044. FYI, first run failed because of spurious failure in "gcc (msvcrt, x86_64)" job, so I had to re-run it. - Kirill Makurin
From c4afcff61729a7099b71a88aad708ec370e4e29e Mon Sep 17 00:00:00 2001 From: Kirill Makurin <[email protected]> Date: Mon, 11 May 2026 19:40:15 +0900 Subject: [PATCH 01/11] winpthreads: fix return value of pthread_mutex_unlock If `pthread_mutex_t` object passed to `pthread_mutex_unlock` is a valid but unlocked mutex of type `PTHREAD_MUTEX_ERRORCHECK` or `PTHREAD_MUTEX_RECURSIVE`, `pthread_mutex_unlock` would fail with `EINVAL`. This behavior caused tests mutex{6e,6es,7e}.c to fail since they expected `pthread_mutex_unlock` to fail with `EPERM` in such case. POSIX[1] says the following about `pthread_mutex_unlock`: The pthread_mutex_unlock() function shall fail if: [EPERM] The mutex type is PTHREAD_MUTEX_ERRORCHECK or PTHREAD_MUTEX_RECURSIVE, or the mutex is a robust mutex, and the current thread does not own the mutex. It mentions `EINVAL` in RATIONALE: If an implementation detects that the value specified by the mutex argument does not refer to an initialized mutex object, it is recommended that the function should fail and report an [EINVAL] error. Error condition for `EPERM` fits situation when `pthread_mutex_t` object is a valid but unlocked mutex; it has no owner which means that the calling thread does not own it and as such the calling thread cannot unlock it. [1] https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/pthread_mutex_lock.html Signed-off-by: Kirill Makurin <[email protected]> --- mingw-w64-libraries/winpthreads/src/mutex.c | 2 +- mingw-w64-libraries/winpthreads/tests/Makefile.am | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/mingw-w64-libraries/winpthreads/src/mutex.c b/mingw-w64-libraries/winpthreads/src/mutex.c index 4022bdbbf..ae4785866 100644 --- a/mingw-w64-libraries/winpthreads/src/mutex.c +++ b/mingw-w64-libraries/winpthreads/src/mutex.c @@ -231,7 +231,7 @@ int pthread_mutex_unlock(pthread_mutex_t *m) if (unlikely(mi->type != Normal)) { if (mi->state == Unlocked) - return EINVAL; + return EPERM; if (mi->owner != GetCurrentThreadId()) return EPERM; if (mi->rec_lock > 0) { diff --git a/mingw-w64-libraries/winpthreads/tests/Makefile.am b/mingw-w64-libraries/winpthreads/tests/Makefile.am index dc30446cb..8cbbf3816 100644 --- a/mingw-w64-libraries/winpthreads/tests/Makefile.am +++ b/mingw-w64-libraries/winpthreads/tests/Makefile.am @@ -175,10 +175,7 @@ TESTS = $(check_PROGRAMS) # TODO: investigate why these tests fail XFAIL_TESTS = \ pthread_mutex/mutex4 \ - pthread_mutex/mutex6e \ - pthread_mutex/mutex6es \ pthread_mutex/mutex7 \ - pthread_mutex/mutex7e \ pthread_mutex/mutex7n \ pthread_spinlock/spin1 \ pthread_spinlock/spin3 -- 2.51.0.windows.1
From ff55b7efc48d18532779a69a728233ff163a8493 Mon Sep 17 00:00:00 2001 From: Kirill Makurin <[email protected]> Date: Mon, 11 May 2026 19:40:16 +0900 Subject: [PATCH 02/11] winpthreads: tests: fix pthread_mutex/mutex{4,7,7n}.c POSIX[1] states that calling `pthread_mutex_unlock` on mutex of type `PTHREAD_MUTEX_NORMAL` that is not owned by the calling thread is undefined behavior. An unlocked mutex fits into this category; it has no owner which means that the calling thread does not own it. With current, event-based implementation, `pthread_mutex_unlock` does not check ownership for mutexes of type `PTHREAD_MUTEX_NORMAL`; this has effect that `pthread_mutex_unlock` always succeeds as long as passed `pthread_mutex_t` object is a valid mutex of type `PTHREAD_MUTEX_NORMAL`. Tests mutex{4,7,7n}.c call `pthread_mutex_unlock` on an unlocked mutex of type `PTHREAD_MUTEX_NORMAL`; they falied as they expected the old behavior, when `pthread_mutex_unlock` would fail with `EPERM` in such case. Update tests mutex{4,7,7n}.c to keep up with the current behavior and document that we test winpthreads-specific behavior for a case when POSIX explicitly specifies undefined behavior. [1] https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/pthread_mutex_lock.html Signed-off-by: Kirill Makurin <[email protected]> --- .../winpthreads/tests/Makefile.am | 3 --- .../winpthreads/tests/pthread_mutex/mutex4.c | 18 ++++++++++++++++-- .../winpthreads/tests/pthread_mutex/mutex7.c | 9 ++++++++- .../winpthreads/tests/pthread_mutex/mutex7n.c | 9 ++++++++- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/mingw-w64-libraries/winpthreads/tests/Makefile.am b/mingw-w64-libraries/winpthreads/tests/Makefile.am index 8cbbf3816..711b7ff8e 100644 --- a/mingw-w64-libraries/winpthreads/tests/Makefile.am +++ b/mingw-w64-libraries/winpthreads/tests/Makefile.am @@ -174,8 +174,5 @@ TESTS = $(check_PROGRAMS) # TODO: investigate why these tests fail XFAIL_TESTS = \ - pthread_mutex/mutex4 \ - pthread_mutex/mutex7 \ - pthread_mutex/mutex7n \ pthread_spinlock/spin1 \ pthread_spinlock/spin3 diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_mutex/mutex4.c b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/mutex4.c index 0a5dca36a..38342b56d 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_mutex/mutex4.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/mutex4.c @@ -76,7 +76,14 @@ main() */ assert(pthread_create(&t, NULL, unlocker, (void *) 0) == 0); assert(pthread_join(t, NULL) == 0); - assert(pthread_mutex_unlock(&mutex1) == EPERM); + /** + * POSIX states that calling `pthread_mutex_unlock` on NORMAL mutex that is + * not owned by the calling thread is undefined behavior. + * + * Out implementation for NORMAL mutexes does not check ownership at all, + * so call to `pthread_mutex_unlock` on a valid NORMAL mutex always succeeds. + */ + assert(pthread_mutex_unlock(&mutex1) == 0); assert(wasHere == 2); wasHere = 0; @@ -89,7 +96,14 @@ main() */ assert(pthread_create(&t, NULL, unlocker, (void *) 0) == 0); assert(pthread_join(t, NULL) == 0); - assert(pthread_mutex_unlock(&mutex1) == EPERM); + /** + * POSIX states that calling `pthread_mutex_unlock` on NORMAL mutex that is + * not owned by the calling thread is undefined behavior. + * + * Out implementation for NORMAL mutexes does not check ownership at all, + * so call to `pthread_mutex_unlock` on a valid NORMAL mutex always succeeds. + */ + assert(pthread_mutex_unlock(&mutex1) == 0); assert(wasHere == 2); wasHere = 0; diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_mutex/mutex7.c b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/mutex7.c index 8772b9712..f64f06ce8 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_mutex/mutex7.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/mutex7.c @@ -57,7 +57,14 @@ void * locker(void * arg) assert(pthread_mutex_trylock(&mutex) == EBUSY); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); - assert(pthread_mutex_unlock(&mutex) == EPERM); + /** + * POSIX states that calling `pthread_mutex_unlock` on NORMAL mutex that is + * not owned by the calling thread is undefined behavior. + * + * Out implementation for NORMAL mutexes does not check ownership at all, + * so call to `pthread_mutex_unlock` on a valid NORMAL mutex always succeeds. + */ + assert(pthread_mutex_unlock(&mutex) == 0); return 0; } diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_mutex/mutex7n.c b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/mutex7n.c index 174355fca..b703f1d2d 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_mutex/mutex7n.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/mutex7n.c @@ -61,7 +61,14 @@ void * locker(void * arg) assert(pthread_mutex_trylock(&mutex) == EBUSY); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); - assert(pthread_mutex_unlock(&mutex) == EPERM); + /** + * POSIX states that calling `pthread_mutex_unlock` on NORMAL mutex that is + * not owned by the calling thread is undefined behavior. + * + * Out implementation for NORMAL mutexes does not check ownership at all, + * so call to `pthread_mutex_unlock` on a valid NORMAL mutex always succeeds. + */ + assert(pthread_mutex_unlock(&mutex) == 0); return (void *) 555; } -- 2.51.0.windows.1
From e891f3244e63f7bf0ebf8295aa098259e6c6146a Mon Sep 17 00:00:00 2001 From: Kirill Makurin <[email protected]> Date: Mon, 11 May 2026 19:40:16 +0900 Subject: [PATCH 03/11] winpthreads: reformat spinlock.c Signed-off-by: Kirill Makurin <[email protected]> --- .../winpthreads/src/spinlock.c | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/mingw-w64-libraries/winpthreads/src/spinlock.c b/mingw-w64-libraries/winpthreads/src/spinlock.c index 452c36528..0fd8d256d 100644 --- a/mingw-w64-libraries/winpthreads/src/spinlock.c +++ b/mingw-w64-libraries/winpthreads/src/spinlock.c @@ -39,40 +39,34 @@ without breaking binary compatibility.) */ typedef intptr_t spinlock_word_t; -int -pthread_spin_init (pthread_spinlock_t *lock, int pshared) +int pthread_spin_init (pthread_spinlock_t *lock, int pshared) { spinlock_word_t *lk = (spinlock_word_t *)lock; *lk = -1; return 0; } - -int -pthread_spin_destroy (pthread_spinlock_t *lock) +int pthread_spin_destroy (pthread_spinlock_t *lock) { return 0; } -int -pthread_spin_lock (pthread_spinlock_t *lock) +int pthread_spin_lock (pthread_spinlock_t *lock) { spinlock_word_t *lk = (spinlock_word_t *)lock; - while (unlikely(InterlockedExchangePointer((PVOID*)lk, 0) == 0)) + while (unlikely(InterlockedExchangePointer((PVOID*)lk, 0) == 0)) { YieldProcessor(); + } return 0; } -int -pthread_spin_trylock (pthread_spinlock_t *lock) +int pthread_spin_trylock (pthread_spinlock_t *lock) { spinlock_word_t *lk = (spinlock_word_t *)lock; return InterlockedExchangePointer((PVOID*)lk, 0) == 0 ? EBUSY : 0; } - -int -pthread_spin_unlock (pthread_spinlock_t *lock) +int pthread_spin_unlock (pthread_spinlock_t *lock) { spinlock_word_t *lk = (spinlock_word_t *)lock; #if defined(__GNUC__) || defined(__clang__) -- 2.51.0.windows.1
From 73dc36ae5f3da1d9ac31fb318497f6b7d1039dec Mon Sep 17 00:00:00 2001 From: Kirill Makurin <[email protected]> Date: Mon, 11 May 2026 19:40:16 +0900 Subject: [PATCH 04/11] winpthreads: new spinlock implementation Previous spinlock implementation did not keep track of lock ownership. It had effect that calling `pthread_spin_unlock` from thread A would always unlock lock held by thread B. The old implementation caused tests spin1.c and spin3.c to fail; they expected that implementation properly keeps track of lock ownership, which was not true. Signed-off-by: Kirill Makurin <[email protected]> --- .../winpthreads/src/spinlock.c | 305 ++++++++++++++++-- .../winpthreads/tests/Makefile.am | 5 - 2 files changed, 285 insertions(+), 25 deletions(-) diff --git a/mingw-w64-libraries/winpthreads/src/spinlock.c b/mingw-w64-libraries/winpthreads/src/spinlock.c index 0fd8d256d..8e52db714 100644 --- a/mingw-w64-libraries/winpthreads/src/spinlock.c +++ b/mingw-w64-libraries/winpthreads/src/spinlock.c @@ -1,6 +1,5 @@ /* - Copyright (c) 2013 mingw-w64 project - Copyright (c) 2015 Intel Corporation + Copyright (c) 2026 mingw-w64 project Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +24,8 @@ #include "config.h" #endif +#include <stdlib.h> + #define WIN32_LEAN_AND_MEAN #include <windows.h> @@ -33,46 +34,310 @@ /* internal header files */ #include "misc.h" -/* We use the pthread_spinlock_t itself as a lock: - -1 is free, 0 is locked. - (This is dictated by PTHREAD_SPINLOCK_INITIALIZER, which we can't change - without breaking binary compatibility.) */ -typedef intptr_t spinlock_word_t; +/** + * Reference: + * + * pthread_spin_init(), pthread_spin_destroy(): + * <https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/pthread_spin_destroy.html> + * + * pthread_spin_lock(), pthread_spin_trylock(): + * <https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/pthread_spin_lock.html> + * + * pthread_spin_unlock(): + * <https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/pthread_spin_unlock.html> + */ + +/** + * To yield or not to yield? + * + * Our implementation of `pthread_spin_lock` does not yield calling thread's + * CPU time if it was unable to immediately obtain the lock. + * + * One reason for this is to reduce amount of the following situations: + * + * Threads A, B and C use spin lock S. Thread A acquires S, then thread B + * attempts to acquire S; since A owns S, B yields its CPU time. + * + * There is a chance that A will release S and C will acquire S while B is + * suspended. If B is resumed while C holds S, B will yield its CPU time again. + * While B is suspended again, C may release S and A may acquire S again. + * + * The result is that B missed two opportunities to acquire S. + */ + +/** + * Internal structure pointed to by `pthread_spinlock_t` objects. + */ +typedef struct { + /** + * This value is used to indicate that spin lock has no owner. + */ +#define THREAD_ID_NO_OWNER ((DWORD)-1) + DWORD ThreadId; + /** + * Spin lock is unlocked; `ThreadId` must be `THREAD_ID_NO_OWNER`. + */ +#define LOCK_UNLOCKED ((LONG)0) + /** + * Spin lock is locked; owned by `ThreadId`. + */ +#define LOCK_LOCKED ((LONG)1) + LONG Lock; +} WinpthreadsSpinlock; + +#define WINPTHREADS_SPINLOCK_INITIALIZER ((WinpthreadsSpinlock *)PTHREAD_SPINLOCK_INITIALIZER) + +/** + * Obtain pointer to `WinpthreadsSpinlock` structure pointed to by `lock`. + * + * If `lock` points to statically initialzied `pthread_spinlock_t` object, + * allocate `WinpthreadsSpinlock` structure and store its address in `*lock`. + * + * On success, stores pointer to `WinpthreadsSpinlock` structure in `*spinlock`. + * + * Returns zero on success and an error-code on failure. + */ +static WINPTHREADS_INLINE int WinpthreadsSpinlockGet (pthread_spinlock_t *lock, WinpthreadsSpinlock **spinlock) { + WinpthreadsSpinlock **pSpinlock = (WinpthreadsSpinlock **) lock; + + /** + * POSIX: + * + * If an implementation detects that the value specified by the lock argument + * to pthread_spin_*() does not refer to an initialized spin lock object, + * it is recommended that the function should fail and report an [EINVAL] error. + */ + if (unlikely (pSpinlock == NULL)) { + return EINVAL; + } + + if (*pSpinlock == WINPTHREADS_SPINLOCK_INITIALIZER) { + int error_code = pthread_spin_init ((pthread_spinlock_t *) spinlock, PTHREAD_PROCESS_PRIVATE); + + if (error_code) { + return error_code; + } + + void *oldLock = InterlockedCompareExchangePointer ( + (void **) pSpinlock, *spinlock, WINPTHREADS_SPINLOCK_INITIALIZER + ); + + /** + * Some other thread was faster than us. + */ + if (unlikely (oldLock != WINPTHREADS_SPINLOCK_INITIALIZER)) { + free (*spinlock); + *spinlock = *pSpinlock; + } + } else { + *spinlock = *pSpinlock; + } + + if (unlikely (*spinlock == NULL)) { + return EINVAL; + } + + return 0; +} int pthread_spin_init (pthread_spinlock_t *lock, int pshared) { - spinlock_word_t *lk = (spinlock_word_t *)lock; - *lk = -1; + WinpthreadsSpinlock **pSpinlock = (WinpthreadsSpinlock **) lock; + + if (unlikely (pSpinlock == NULL)) { + return EINVAL; + } + + if (unlikely (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)) { + return EINVAL; + } + + if (unlikely (pshared == PTHREAD_PROCESS_SHARED)) { + return ENOSYS; + } + + WinpthreadsSpinlock *wSpinlock = calloc (1, sizeof (WinpthreadsSpinlock)); + + /** + * The pthread_spin_init() function shall fail if: + * + * [ENOMEM] + * Insufficient memory exists to initialize the lock. + */ + if (wSpinlock == NULL) { + return ENOMEM; + } + + wSpinlock->ThreadId = THREAD_ID_NO_OWNER; + wSpinlock->Lock = LOCK_UNLOCKED; + MemoryBarrier (); + *pSpinlock = wSpinlock; + return 0; } int pthread_spin_destroy (pthread_spinlock_t *lock) { + WinpthreadsSpinlock **pSpinlock = (WinpthreadsSpinlock **) lock; + + /** + * POSIX: + * + * If an implementation detects that the value specified by the lock argument + * to pthread_spin_destroy() does not refer to an initialized spin lock object, + * it is recommended that the function should fail and report an [EINVAL] error. + */ + if (unlikely (pSpinlock == NULL)) { + return EINVAL; + } + + /** + * If `lock` points to statically initialized `pthread_spinlock_t` object, + * this will immediately invalidate it, minimizing the window for + * `pthread_spin_lock` and `pthread_spin_trylock` to attempt using it. + */ + WinpthreadsSpinlock *wSpinlock = InterlockedCompareExchangePointer ( + (void **) pSpinlock, NULL, WINPTHREADS_SPINLOCK_INITIALIZER + ); + + if (unlikely (wSpinlock == NULL)) { + return EINVAL; + } + + if (unlikely (wSpinlock == WINPTHREADS_SPINLOCK_INITIALIZER)) { + return 0; + } + + /** + * POSIX: + * + * If an implementation detects that the value specified by the lock argument + * to pthread_spin_destroy() or pthread_spin_init() refers to a locked spin + * lock object, or detects that the value specified by the lock argument to + * pthread_spin_init() refers to an already initialized spin lock object, + * it is recommended that the function should fail and report an [EBUSY] error. + */ + if (unlikely (InterlockedExchange (&wSpinlock->Lock, LOCK_LOCKED) != LOCK_UNLOCKED)) { + return EBUSY; + } + + /** + * Invalidate `pthread_spinlock_t` object pointed by `lock`. + */ + InterlockedExchangePointer ((void **) pSpinlock, NULL); + + /** + * Release the lock we are currently holding. + */ + InterlockedExchange (&wSpinlock->Lock, LOCK_UNLOCKED); + + /** + * Release all threads which still may wait for `wSpinlock`. + */ + do { + /** + * We yield so other threads can acquire the lock. + */ + YieldProcessor (); + } while (unlikely (InterlockedExchange (&wSpinlock->Lock, LOCK_UNLOCKED) == LOCK_LOCKED)); + + free (wSpinlock); + return 0; } int pthread_spin_lock (pthread_spinlock_t *lock) { - spinlock_word_t *lk = (spinlock_word_t *)lock; - while (unlikely(InterlockedExchangePointer((PVOID*)lk, 0) == 0)) { - YieldProcessor(); + WinpthreadsSpinlock *wSpinlock = NULL; + + int error_code = WinpthreadsSpinlockGet (lock, &wSpinlock); + + if (error_code) { + return error_code; + } + + DWORD threadId = GetCurrentThreadId (); + + /** + * The pthread_spin_lock() function may fail if: + * + * [EDEADLK] + * A deadlock condition was detected. + */ + if (unlikely (wSpinlock->ThreadId == threadId)) { + return EDEADLK; + } + + while (InterlockedExchange (&wSpinlock->Lock, LOCK_LOCKED) != LOCK_UNLOCKED) { +#if 0 + YieldProcessor (); +#endif } + + wSpinlock->ThreadId = threadId; + return 0; } int pthread_spin_trylock (pthread_spinlock_t *lock) { - spinlock_word_t *lk = (spinlock_word_t *)lock; - return InterlockedExchangePointer((PVOID*)lk, 0) == 0 ? EBUSY : 0; + WinpthreadsSpinlock *wSpinlock = NULL; + + int error_code = WinpthreadsSpinlockGet (lock, &wSpinlock); + + if (error_code) { + return error_code; + } + + /** + * Unlike `pthread_spin_lock`, no deadlock can occur even if calling thread + * owns the lock. + * + * The pthread_spin_trylock() function shall fail if: + * + * [EBUSY] + * A thread currently holds the lock. + */ + if (InterlockedExchange (&wSpinlock->Lock, LOCK_LOCKED) != LOCK_UNLOCKED) { + return EBUSY; + } + + wSpinlock->ThreadId = GetCurrentThreadId (); + + return 0; } int pthread_spin_unlock (pthread_spinlock_t *lock) { - spinlock_word_t *lk = (spinlock_word_t *)lock; -#if defined(__GNUC__) || defined(__clang__) - __atomic_store_n(lk, -1, __ATOMIC_RELEASE); -#else - InterlockedExchangePointer((PVOID*)lk, (void*)-1); -#endif + WinpthreadsSpinlock *wSpinlock = NULL; + + int error_code = WinpthreadsSpinlockGet (lock, &wSpinlock); + + if (error_code) { + return error_code; + } + + if (unlikely (wSpinlock->Lock == LOCK_UNLOCKED)) { + return 0; + } + + DWORD threadId = GetCurrentThreadId (); + + /** + * POSIX: + * + * If an implementation detects that the value specified by the lock argument + * to pthread_spin_unlock() refers to a spin lock object for which the + * current thread does not hold the lock, it is recommended that the function + * should fail and report an [EPERM] error. + */ + if (unlikely (wSpinlock->ThreadId != threadId)) { + return EPERM; + } + + wSpinlock->ThreadId = THREAD_ID_NO_OWNER; + MemoryBarrier (); + wSpinlock->Lock = LOCK_UNLOCKED; + return 0; } diff --git a/mingw-w64-libraries/winpthreads/tests/Makefile.am b/mingw-w64-libraries/winpthreads/tests/Makefile.am index 711b7ff8e..218999d94 100644 --- a/mingw-w64-libraries/winpthreads/tests/Makefile.am +++ b/mingw-w64-libraries/winpthreads/tests/Makefile.am @@ -171,8 +171,3 @@ check_PROGRAMS = \ semaphore/semaphore5 TESTS = $(check_PROGRAMS) - -# TODO: investigate why these tests fail -XFAIL_TESTS = \ - pthread_spinlock/spin1 \ - pthread_spinlock/spin3 -- 2.51.0.windows.1
From 0171e466422dfb9eeb7f748c7c9f8ebedc62390e Mon Sep 17 00:00:00 2001 From: Kirill Makurin <[email protected]> Date: Mon, 11 May 2026 19:40:16 +0900 Subject: [PATCH 05/11] winpthreads: tests: reformat pthread_spinlock/* tests Signed-off-by: Kirill Makurin <[email protected]> --- .../tests/pthread_spinlock/spin1.c | 19 ++++------- .../tests/pthread_spinlock/spin2.c | 31 +++++++---------- .../tests/pthread_spinlock/spin3.c | 22 ++++++------ .../tests/pthread_spinlock/spin4.c | 34 ++++++++----------- 4 files changed, 45 insertions(+), 61 deletions(-) diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin1.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin1.c index 00ecd11b1..a3bc0e183 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin1.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin1.c @@ -1,4 +1,4 @@ -/* +/* * spin1.c * * @@ -7,25 +7,25 @@ * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors - * + * * Contact Email: [email protected] - * + * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., @@ -42,17 +42,12 @@ pthread_spinlock_t lock; -int -main() +int main(void) { assert(pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE) == 0); - assert(pthread_spin_lock(&lock) == 0); - assert(pthread_spin_unlock(&lock) == 0); - assert(pthread_spin_destroy(&lock) == 0); - assert(pthread_spin_lock(&lock) == EINVAL); return 0; diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c index b1d809097..939ef2c8d 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c @@ -1,4 +1,4 @@ -/* +/* * spin2.c * * @@ -7,25 +7,25 @@ * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors - * + * * Contact Email: [email protected] - * + * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., @@ -33,41 +33,34 @@ * * -------------------------------------------------------------------------- * - * Declare a spinlock object, lock it, trylock it, + * Declare a spinlock object, lock it, trylock it, * and then unlock it again. * */ #include "test.h" - + static int washere = 0; -void * func(void * arg) +void *func(void *arg) { assert(pthread_spin_trylock((pthread_spinlock_t *) arg) == EBUSY); - washere = 1; - return 0; + return 0; } - -int -main() + +int main(void) { static pthread_spinlock_t lock; pthread_t t; assert(pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE) == 0); - assert(pthread_spin_lock(&lock) == 0); - assert(pthread_create(&t, NULL, func, &lock) == 0); assert(pthread_join(t, NULL) == 0); - assert(pthread_spin_unlock(&lock) == 0); - assert(pthread_spin_destroy(&lock) == 0); - assert(washere == 1); return 0; diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c index 4f2ca5f0d..e0a9f28fc 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c @@ -1,4 +1,4 @@ -/* +/* * spin3.c * * @@ -7,25 +7,25 @@ * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors - * + * * Contact Email: [email protected] - * + * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., @@ -43,19 +43,19 @@ static int wasHere = 0; static pthread_spinlock_t spin; - -void * unlocker(void * arg) + +void *unlocker(void *arg) { int expectedResult = (int) (size_t) arg; wasHere++; assert(pthread_spin_unlock(&spin) == (int) expectedResult); wasHere++; + return NULL; } - -int -main() + +int main(void) { pthread_t t; diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin4.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin4.c index f0a5abd23..0dbb111da 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin4.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin4.c @@ -1,4 +1,4 @@ -/* +/* * spin4.c * * @@ -7,25 +7,25 @@ * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors - * + * * Contact Email: [email protected] - * + * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., @@ -33,23 +33,24 @@ * * -------------------------------------------------------------------------- * - * Declare a static spinlock object, lock it, spin on it, + * Declare a static spinlock object, lock it, spin on it, * and then unlock it again. */ #include "test.h" #include <sys/timeb.h> - + pthread_spinlock_t lock = PTHREAD_SPINLOCK_INITIALIZER; + struct _timeb currSysTimeStart; struct _timeb currSysTimeStop; -#define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \ - - (_TStart.time*1000+_TStart.millitm)) +#define GetDurationMilliSecs(_TStart, _TStop) \ + ((_TStop.time * 1000 + _TStop.millitm) - (_TStart.time * 1000 + _TStart.millitm)) static int washere = 0; -void * func(void * arg) +void *func(void *arg) { _ftime(&currSysTimeStart); washere = 1; @@ -59,9 +60,8 @@ void * func(void * arg) return (void *) (size_t) GetDurationMilliSecs(currSysTimeStart, currSysTimeStop); } - -int -main() + +int main(void) { intptr_t result = 0; pthread_t t; @@ -71,11 +71,10 @@ main() if ((CPUs = pthread_num_processors_np()) == 1) { printf("Test not run - it requires multiple CPUs.\n"); - exit(0); + exit(0); } assert(pthread_spin_lock(&lock) == 0); - assert(pthread_create(&t, NULL, func, NULL) == 0); while (washere == 0) @@ -91,12 +90,9 @@ main() while (GetDurationMilliSecs(currSysTimeStart, sysTime) <= 1000); assert(pthread_spin_unlock(&lock) == 0); - assert(pthread_join(t, (void **) &result) == 0); assert(result > 1000); - assert(pthread_spin_destroy(&lock) == 0); - assert(washere == 1); return 0; -- 2.51.0.windows.1
From ea2bb4d81df5c447e98d207d257190d7e1b0d4b7 Mon Sep 17 00:00:00 2001 From: Kirill Makurin <[email protected]> Date: Mon, 11 May 2026 19:40:16 +0900 Subject: [PATCH 06/11] winpthreads: tests: update pthread_spinlock/spin1.c Signed-off-by: Kirill Makurin <[email protected]> --- .../tests/pthread_spinlock/spin1.c | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin1.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin1.c index a3bc0e183..839e333eb 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin1.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin1.c @@ -1,14 +1,10 @@ /* - * spin1.c - * - * - * -------------------------------------------------------------------------- - * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors + * Copyright(C) 2026 mingw-w64 project * - * Contact Email: [email protected] + * Contact Email: [email protected] * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source @@ -30,22 +26,26 @@ * License along with this library in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * -------------------------------------------------------------------------- - * - * Create a simple spinlock object, lock it, and then unlock it again. - * This is the simplest test of the pthread mutex family that we can do. - * */ #include "test.h" -pthread_spinlock_t lock; +/** + * Test Summary: + * + * Create spinlock object and test basic assumptions about lock ownership + * and lifetime. + */ int main(void) { + pthread_spinlock_t lock; + assert(pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE) == 0); assert(pthread_spin_lock(&lock) == 0); + assert(pthread_spin_lock(&lock) == EDEADLK); + assert(pthread_spin_trylock(&lock) == EBUSY); + assert(pthread_spin_destroy(&lock) == EBUSY); assert(pthread_spin_unlock(&lock) == 0); assert(pthread_spin_destroy(&lock) == 0); assert(pthread_spin_lock(&lock) == EINVAL); -- 2.51.0.windows.1
From 0f5968c143abc52642de4506d03d6eb625cf3b77 Mon Sep 17 00:00:00 2001 From: Kirill Makurin <[email protected]> Date: Mon, 11 May 2026 19:40:16 +0900 Subject: [PATCH 07/11] winpthreads: tests: update pthread_spinlock/spin2.c Signed-off-by: Kirill Makurin <[email protected]> --- .../tests/pthread_spinlock/spin2.c | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c index 939ef2c8d..ed771b6f5 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c @@ -1,14 +1,10 @@ /* - * spin2.c - * - * - * -------------------------------------------------------------------------- - * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors + * Copyright(C) 2026 mingw-w64 project * - * Contact Email: [email protected] + * Contact Email: [email protected] * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source @@ -30,38 +26,40 @@ * License along with this library in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * -------------------------------------------------------------------------- - * - * Declare a spinlock object, lock it, trylock it, - * and then unlock it again. - * */ #include "test.h" -static int washere = 0; +/** + * Test Summary: + * + * Main thread M create spinlock object S and locks it. + * + * Thread A attempts to lock S; since S is locked by M, + * `pthread_spin_trylock` must fail with `EBUSY`. + * + * Thread M unlocks and destroys S. + */ -void *func(void *arg) +static void *thread(void *arg) { assert(pthread_spin_trylock((pthread_spinlock_t *) arg) == EBUSY); - washere = 1; - - return 0; + return arg; } int main(void) { - static pthread_spinlock_t lock; + pthread_spinlock_t lock; pthread_t t; + void *result; assert(pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE) == 0); assert(pthread_spin_lock(&lock) == 0); - assert(pthread_create(&t, NULL, func, &lock) == 0); - assert(pthread_join(t, NULL) == 0); + assert(pthread_create(&t, NULL, thread, &lock) == 0); + assert(pthread_join(t, &result) == 0); + assert(result == &lock); assert(pthread_spin_unlock(&lock) == 0); assert(pthread_spin_destroy(&lock) == 0); - assert(washere == 1); return 0; } -- 2.51.0.windows.1
From 0e683a6c89b097c7b11025719abb58deac981853 Mon Sep 17 00:00:00 2001 From: Kirill Makurin <[email protected]> Date: Mon, 11 May 2026 19:40:16 +0900 Subject: [PATCH 08/11] winpthreads: tests: update pthread_spinlock/spin3.c Signed-off-by: Kirill Makurin <[email protected]> --- .../tests/pthread_spinlock/spin3.c | 47 ++++++++----------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c index e0a9f28fc..1b82c7571 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c @@ -1,14 +1,10 @@ /* - * spin3.c - * - * - * -------------------------------------------------------------------------- - * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors + * Copyright(C) 2026 mingw-w64 project * - * Contact Email: [email protected] + * Contact Email: [email protected] * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source @@ -30,43 +26,40 @@ * License along with this library in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * -------------------------------------------------------------------------- - * - * Thread A locks spin - thread B tries to unlock. - * This should result in a EPERM as adviced in the spec. - * */ #include "test.h" -static int wasHere = 0; - -static pthread_spinlock_t spin; +/** + * Test Summary: + * + * Main thread M create spinlock object S and locks it. + * + * Thread A attempts to unlock S; since S is owned by M, + * `pthread_spin_unlock` must fail with `EPERM`. + * + * Thread M unlocks and destroys S. + */ -void *unlocker(void *arg) +static void *thread(void *arg) { - int expectedResult = (int) (size_t) arg; - - wasHere++; - assert(pthread_spin_unlock(&spin) == (int) expectedResult); - wasHere++; - - return NULL; + assert(pthread_spin_unlock((pthread_spinlock_t *) arg) == EPERM); + return arg; } int main(void) { + pthread_spinlock_t spin; pthread_t t; + void *result; - wasHere = 0; assert(pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE) == 0); assert(pthread_spin_lock(&spin) == 0); - assert(pthread_create(&t, NULL, unlocker, (void *) EPERM) == 0); - assert(pthread_join(t, NULL) == 0); + assert(pthread_create(&t, NULL, thread, &spin) == 0); + assert(pthread_join(t, &result) == 0); + assert(result == &spin); assert(pthread_spin_unlock(&spin) == 0); assert(pthread_spin_destroy(&spin) == 0); - assert(wasHere == 2); return 0; } -- 2.51.0.windows.1
From 644335573e40dc1b912b0d82a7039a6e288679b6 Mon Sep 17 00:00:00 2001 From: Kirill Makurin <[email protected]> Date: Mon, 11 May 2026 19:40:16 +0900 Subject: [PATCH 09/11] winpthreads: tests: update pthread_spinlock/spin4.c Signed-off-by: Kirill Makurin <[email protected]> --- .../tests/pthread_spinlock/spin4.c | 109 +++++++++--------- 1 file changed, 54 insertions(+), 55 deletions(-) diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin4.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin4.c index 0dbb111da..263133727 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin4.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin4.c @@ -1,14 +1,10 @@ /* - * spin4.c - * - * - * -------------------------------------------------------------------------- - * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors + * Copyright(C) 2026 mingw-w64 project * - * Contact Email: [email protected] + * Contact Email: [email protected] * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source @@ -30,70 +26,73 @@ * License along with this library in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * -------------------------------------------------------------------------- - * - * Declare a static spinlock object, lock it, spin on it, - * and then unlock it again. */ #include "test.h" -#include <sys/timeb.h> -pthread_spinlock_t lock = PTHREAD_SPINLOCK_INITIALIZER; +/** + * Test Summary: + * + * Main thread M statically initializes spin lock S and creates two threads + * A and B. + * + * Threads A and B both try to lock S and unlock S. Since S is statically + * initialized, `pthread_spin_lock` must perform actual initialization. + * Only one thread must complete initialization and both A and B must use + * the same spinlock object to perform synchronization. + * + * After both A and B terminate, M verifies that A and B used the same spinlock + * object, and then destroys it. + */ -struct _timeb currSysTimeStart; -struct _timeb currSysTimeStop; +static struct timespec ThreadAEntryTime; +static struct timespec ThreadBEntryTime; -#define GetDurationMilliSecs(_TStart, _TStop) \ - ((_TStop.time * 1000 + _TStop.millitm) - (_TStart.time * 1000 + _TStart.millitm)) +static void *ThreadA(void *arg) +{ + pthread_spinlock_t lock; -static int washere = 0; + assert(pthread_spin_lock((pthread_spinlock_t *) arg) == 0); + assert (clock_gettime (CLOCK_REALTIME, &ThreadAEntryTime) == 0); + lock = *(pthread_spinlock_t *) arg; + assert(pthread_spin_unlock((pthread_spinlock_t *) arg) == 0); -void *func(void *arg) + return (void *) lock; +} + +static void *ThreadB(void *arg) { - _ftime(&currSysTimeStart); - washere = 1; - assert(pthread_spin_lock(&lock) == 0); - assert(pthread_spin_unlock(&lock) == 0); - _ftime(&currSysTimeStop); + pthread_spinlock_t lock; + + assert(pthread_spin_lock((pthread_spinlock_t *) arg) == 0); + assert (clock_gettime (CLOCK_REALTIME, &ThreadBEntryTime) == 0); + lock = *(pthread_spinlock_t *) arg; + assert(pthread_spin_unlock((pthread_spinlock_t *) arg) == 0); - return (void *) (size_t) GetDurationMilliSecs(currSysTimeStart, currSysTimeStop); + return (void *) lock; } int main(void) { - intptr_t result = 0; - pthread_t t; - int CPUs; - struct _timeb sysTime; - - if ((CPUs = pthread_num_processors_np()) == 1) - { - printf("Test not run - it requires multiple CPUs.\n"); - exit(0); - } - - assert(pthread_spin_lock(&lock) == 0); - assert(pthread_create(&t, NULL, func, NULL) == 0); - - while (washere == 0) - { - sched_yield(); - } - - do - { - sched_yield(); - _ftime(&sysTime); - } - while (GetDurationMilliSecs(currSysTimeStart, sysTime) <= 1000); - - assert(pthread_spin_unlock(&lock) == 0); - assert(pthread_join(t, (void **) &result) == 0); - assert(result > 1000); + pthread_spinlock_t lock = PTHREAD_SPINLOCK_INITIALIZER; + + pthread_t threadA; + pthread_spinlock_t threadALock; + + pthread_t threadB; + pthread_spinlock_t threadBLock; + + assert(pthread_create(&threadA, NULL, ThreadA, &lock) == 0); + assert(pthread_create(&threadB, NULL, ThreadB, &lock) == 0); + + assert(pthread_join(threadA, (void **) &threadALock) == 0); + assert(pthread_join(threadB, (void **) &threadBLock) == 0); + + wprintf(L"Thread A lock entry time: %.0f.%ld\n", (double) ThreadAEntryTime.tv_sec, ThreadAEntryTime.tv_nsec); + wprintf(L"Thread B lock entry time: %.0f.%ld\n", (double) ThreadBEntryTime.tv_sec, ThreadBEntryTime.tv_nsec); + + assert(threadALock == threadBLock); assert(pthread_spin_destroy(&lock) == 0); - assert(washere == 1); return 0; } -- 2.51.0.windows.1
From 4fcc6af19328ed32d2166bc47db9bcfd9b676139 Mon Sep 17 00:00:00 2001 From: Kirill Makurin <[email protected]> Date: Mon, 11 May 2026 19:40:17 +0900 Subject: [PATCH 10/11] winpthreads: tests: combine pthread_spinlock/spin2.c and pthread_spinlock/spin3.c Tests spin2.c and spin3.c are nearly equivalent, except they call different `pthread_spin_*` function from new thread. Extend spin2.c with extra checks, including those from spin3.c. Update spin3.c to test statically initialized `pthread_spinlock_t` object. Signed-off-by: Kirill Makurin <[email protected]> --- .../tests/pthread_spinlock/spin2.c | 8 +++++ .../tests/pthread_spinlock/spin3.c | 32 ++++++------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c index ed771b6f5..77161aa90 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c @@ -38,12 +38,20 @@ * Thread A attempts to lock S; since S is locked by M, * `pthread_spin_trylock` must fail with `EBUSY`. * + * Thread A attempts to unlock S; since S is owned by M, + * `pthread_spin_unlock` must fail with `EPERM`. + * + * Thread A attempts to destroy S; since S is locked by M, + * `pthread_spin_destroy` must fail with `EBUSY`. + * * Thread M unlocks and destroys S. */ static void *thread(void *arg) { assert(pthread_spin_trylock((pthread_spinlock_t *) arg) == EBUSY); + assert(pthread_spin_unlock((pthread_spinlock_t *) arg) == EPERM); + assert(pthread_spin_destroy((pthread_spinlock_t *) arg) == EBUSY); return arg; } diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c index 1b82c7571..789712a7c 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c @@ -33,33 +33,21 @@ /** * Test Summary: * - * Main thread M create spinlock object S and locks it. - * - * Thread A attempts to unlock S; since S is owned by M, - * `pthread_spin_unlock` must fail with `EPERM`. - * - * Thread M unlocks and destroys S. + * This test is equivalent to `spin1.c`, except it uses statically initialized + * `pthread_spinlock_t` object. */ -static void *thread(void *arg) -{ - assert(pthread_spin_unlock((pthread_spinlock_t *) arg) == EPERM); - return arg; -} - int main(void) { - pthread_spinlock_t spin; - pthread_t t; - void *result; + pthread_spinlock_t lock = PTHREAD_SPINLOCK_INITIALIZER; - assert(pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE) == 0); - assert(pthread_spin_lock(&spin) == 0); - assert(pthread_create(&t, NULL, thread, &spin) == 0); - assert(pthread_join(t, &result) == 0); - assert(result == &spin); - assert(pthread_spin_unlock(&spin) == 0); - assert(pthread_spin_destroy(&spin) == 0); + assert(pthread_spin_lock(&lock) == 0); + assert(pthread_spin_lock(&lock) == EDEADLK); + assert(pthread_spin_trylock(&lock) == EBUSY); + assert(pthread_spin_destroy(&lock) == EBUSY); + assert(pthread_spin_unlock(&lock) == 0); + assert(pthread_spin_destroy(&lock) == 0); + assert(pthread_spin_lock(&lock) == EINVAL); return 0; } -- 2.51.0.windows.1
From 728ee849c0fda0d1f1edce773f6f8486d024c80c Mon Sep 17 00:00:00 2001 From: Kirill Makurin <[email protected]> Date: Mon, 11 May 2026 19:40:17 +0900 Subject: [PATCH 11/11] winpthreads: tests: rename pthread_spinlock/* tests New names now reflect the purpose of each test. Signed-off-by: Kirill Makurin <[email protected]> --- mingw-w64-libraries/winpthreads/tests/Makefile.am | 8 ++++---- .../tests/pthread_spinlock/{spin1.c => spinlock-basic.c} | 0 .../pthread_spinlock/{spin3.c => spinlock-static-basic.c} | 4 ++-- .../pthread_spinlock/{spin4.c => spinlock-static-race.c} | 0 .../pthread_spinlock/{spin2.c => spinlock-threaded.c} | 0 5 files changed, 6 insertions(+), 6 deletions(-) rename mingw-w64-libraries/winpthreads/tests/pthread_spinlock/{spin1.c => spinlock-basic.c} (100%) rename mingw-w64-libraries/winpthreads/tests/pthread_spinlock/{spin3.c => spinlock-static-basic.c} (93%) rename mingw-w64-libraries/winpthreads/tests/pthread_spinlock/{spin4.c => spinlock-static-race.c} (100%) rename mingw-w64-libraries/winpthreads/tests/pthread_spinlock/{spin2.c => spinlock-threaded.c} (100%) diff --git a/mingw-w64-libraries/winpthreads/tests/Makefile.am b/mingw-w64-libraries/winpthreads/tests/Makefile.am index 218999d94..395b598f0 100644 --- a/mingw-w64-libraries/winpthreads/tests/Makefile.am +++ b/mingw-w64-libraries/winpthreads/tests/Makefile.am @@ -155,10 +155,10 @@ check_PROGRAMS = \ pthread_rwlock/rwlock6_t2 \ pthread_rwlock/rwlock7 \ pthread_rwlock/rwlock8 \ - pthread_spinlock/spin1 \ - pthread_spinlock/spin2 \ - pthread_spinlock/spin3 \ - pthread_spinlock/spin4 \ + pthread_spinlock/spinlock-basic \ + pthread_spinlock/spinlock-threaded \ + pthread_spinlock/spinlock-static-basic \ + pthread_spinlock/spinlock-static-race \ pthread_tls/tsd1 \ pthread_tls/tsd2 \ sched/priority1 \ diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin1.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spinlock-basic.c similarity index 100% rename from mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin1.c rename to mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spinlock-basic.c diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spinlock-static-basic.c similarity index 93% rename from mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c rename to mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spinlock-static-basic.c index 789712a7c..f754f1f24 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin3.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spinlock-static-basic.c @@ -33,8 +33,8 @@ /** * Test Summary: * - * This test is equivalent to `spin1.c`, except it uses statically initialized - * `pthread_spinlock_t` object. + * This test is equivalent to `spinlock-basic.c`, except it uses statically + * initialized `pthread_spinlock_t` object. */ int main(void) diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin4.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spinlock-static-race.c similarity index 100% rename from mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin4.c rename to mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spinlock-static-race.c diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c b/mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spinlock-threaded.c similarity index 100% rename from mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spin2.c rename to mingw-w64-libraries/winpthreads/tests/pthread_spinlock/spinlock-threaded.c -- 2.51.0.windows.1
_______________________________________________ Mingw-w64-public mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
