On Tue, 28 Oct 2025 at 08:34, Jonathan Wakely <[email protected]> wrote:
>
>
>
> On Tue, 28 Oct 2025, 08:28 Tomasz Kaminski, <[email protected]> wrote:
>>
>>
>>
>> On Mon, Oct 27, 2025 at 10:29 PM Jonathan Wakely <[email protected]> wrote:
>>>
>>> The test_shared_relative function deadlocks on older Glibc versions that
>>> don't have pthread_rwlock_clockrdlock, because (as already mentioned
>>> earlier in the test file) pthread_rwlock_timedrdlock returns EDEADLK if
>>> the thread that already holds a write lock attempts to acquire read
>>> lock, causing std::shared_timed_mutex to loop forever.
>>>
>>> The fix is to do the invalid try_lock_shared_for call on a different
>>> thread.
>>>
>>> Also add missing -pthread for PR122401.
>>>
>>> libstdc++-v3/ChangeLog:
>>>
>>>         PR libstdc++/122401
>>>         * testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc:
>>>         Do not call try_lock_shared_for from the thread that already
>>>         holds the exclusive lock. Add -pthread for et pthread.
>>> ---
>>>
>>> Tested x86_64-linux (Glibc 2.41) and aarch64-linux (Glibc 2.28).
>>
>> LGTM. This is problem in test, as 
>> https://eel.is/c++draft/thread.sharedmutex.class#3.2,
>> says that attempting to lock already locked, which try_lock is doing, is UB.
>
>
> Yes, it happens to work with our implementation when using a recent glibc 
> release with pthread_rwlock_clockrdlock, but we shouldn't rely on that.

Strictly speaking, we should also use a separate thread for the calls
that try to obtain the exclusive lock when the current thread already
holds the lock:

  VERIFY(stm.try_lock_for(d));
  VERIFY(!stm.try_lock_for(d));

This is undefined for the same reason, it just happens to work with
our impl (but maybe not on all POSIX systems?)

I'll fix those too, v2 patch coming up.



>
>
>>>
>>>  .../shared_timed_mutex/try_lock_until/116586.cc      | 12 +++++++++++-
>>>  1 file changed, 11 insertions(+), 1 deletion(-)
>>>
>>> diff --git 
>>> a/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc
>>>  
>>> b/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc
>>> index cebbb3a258d9..aae85487a692 100644
>>> --- 
>>> a/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc
>>> +++ 
>>> b/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc
>>> @@ -1,4 +1,7 @@
>>>  // { dg-do run { target c++14 } }
>>> +// { dg-additional-options "-pthread" { target pthread } }
>>> +// { dg-require-gthreads "" }
>>> +// { dg-require-effective-target hosted }
>>>
>>>  #include <shared_mutex>
>>>  #include <chrono>
>>> @@ -66,7 +69,14 @@ test_shared_relative(chrono::nanoseconds offset)
>>>    stm.unlock_shared();
>>>    // Should complete immediately
>>>    VERIFY(stm.try_lock_for(chrono::seconds{10}));
>>> -  VERIFY(!stm.try_lock_shared_for(d));
>>> +  {
>>> +    // NPTL will give us EDEADLK if pthread_rwlock_timedrdlock() is called 
>>> on
>>> +    // the same thread that already holds the exclusive (write) lock, so 
>>> let's
>>> +    // arrange for a different thread to try to acquire the shared lock.
>>> +    auto t = std::async(std::launch::async, [&stm, d]() {
>>> +       VERIFY(!stm.try_lock_shared_for(d));
>>> +      });
>>> +  }
>>>  }
>>>
>>>  int main()
>>> --
>>> 2.51.0
>>>

Reply via email to