aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite/30_threads
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2021-06-22 13:35:19 +0100
committerJonathan Wakely <jwakely@redhat.com>2021-06-22 21:17:25 +0100
commitc556596119307f9ef1c9079ef2bd3a035dea355d (patch)
tree0292d6d165df8828a851fe18b32cf4f2698dc3c0 /libstdc++-v3/testsuite/30_threads
parentb5a29741db11007e37d8d4ff977b89a8314abfda (diff)
downloadgcc-c556596119307f9ef1c9079ef2bd3a035dea355d.zip
gcc-c556596119307f9ef1c9079ef2bd3a035dea355d.tar.gz
gcc-c556596119307f9ef1c9079ef2bd3a035dea355d.tar.bz2
libstdc++: Simplify std::try_lock and std::lock further
The std::try_lock and std::lock algorithms can use iteration instead of recursion when all lockables have the same type and can be held by an array of unique_lock<L> objects. By making this change to __detail::__try_lock_impl it also benefits __detail::__lock_impl, which uses it. For std::lock we can just put the iterative version directly in std::lock, to avoid making any call to __detail::__lock_impl. Signed-off-by: Matthias Kretz <m.kretz@gsi.de> Signed-off-by: Jonathan Wakely <jwakely@redhat.com> Co-authored-by: Matthias Kretz <m.kretz@gsi.de> libstdc++-v3/ChangeLog: * include/std/mutex (lock): Replace recursion with iteration when lockables all have the same type. (__detail::__try_lock_impl): Likewise. Pass lockables as parameters, instead of a tuple. Always lock the first one, and recurse for the rest. (__detail::__lock_impl): Adjust call to __try_lock_impl. (__detail::__try_to_lock): Remove. * testsuite/30_threads/lock/3.cc: Check that mutexes are locked. * testsuite/30_threads/lock/4.cc: Also test non-heterogeneous arguments. * testsuite/30_threads/unique_lock/cons/60497.cc: Also check std::try_lock. * testsuite/30_threads/try_lock/5.cc: New test.
Diffstat (limited to 'libstdc++-v3/testsuite/30_threads')
-rw-r--r--libstdc++-v3/testsuite/30_threads/lock/3.cc4
-rw-r--r--libstdc++-v3/testsuite/30_threads/lock/4.cc124
-rw-r--r--libstdc++-v3/testsuite/30_threads/try_lock/5.cc41
-rw-r--r--libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc6
4 files changed, 174 insertions, 1 deletions
diff --git a/libstdc++-v3/testsuite/30_threads/lock/3.cc b/libstdc++-v3/testsuite/30_threads/lock/3.cc
index 5213607..5fa1187 100644
--- a/libstdc++-v3/testsuite/30_threads/lock/3.cc
+++ b/libstdc++-v3/testsuite/30_threads/lock/3.cc
@@ -37,7 +37,7 @@ struct user_lock
is_locked = true;
}
- bool try_lock()
+ bool try_lock()
{ return is_locked ? false : (is_locked = true); }
void unlock()
@@ -62,6 +62,8 @@ int main()
{
//heterogeneous types
std::lock(m1, m2, m3);
+ VERIFY( !m1.try_lock() );
+ VERIFY( !m3.try_lock() );
m1.unlock();
m2.unlock();
m3.unlock();
diff --git a/libstdc++-v3/testsuite/30_threads/lock/4.cc b/libstdc++-v3/testsuite/30_threads/lock/4.cc
index 7ba15cb..130c1f6 100644
--- a/libstdc++-v3/testsuite/30_threads/lock/4.cc
+++ b/libstdc++-v3/testsuite/30_threads/lock/4.cc
@@ -73,6 +73,7 @@ int unreliable_lock::lock_on = -1;
void test01()
{
unreliable_lock l1, l2, l3;
+ std::mutex m1, m2, m3;
try
{
@@ -87,6 +88,60 @@ void test01()
{
VERIFY( false );
}
+
+ // Repeat with non-heterogeneous arguments
+
+ try
+ {
+ unreliable_lock::count = 0;
+ std::lock(l1, l2, l3, m1);
+ VERIFY( unreliable_lock::count == 3 );
+ l1.unlock();
+ l2.unlock();
+ l3.unlock();
+ VERIFY( !m1.try_lock() ); // already locked
+ m1.unlock();
+ }
+ catch (...)
+ {
+ VERIFY( false );
+ }
+
+ try
+ {
+ unreliable_lock::count = 0;
+ std::lock(m1, l1, l2, l3);
+ VERIFY( unreliable_lock::count == 3 );
+ VERIFY( !m1.try_lock() ); // already locked
+ m1.unlock();
+ l1.unlock();
+ l2.unlock();
+ l3.unlock();
+ }
+ catch (...)
+ {
+ VERIFY( false );
+ }
+
+ try
+ {
+ unreliable_lock::count = 0;
+ std::lock(l1, m1, l2, m2, l3, m3);
+ VERIFY( unreliable_lock::count == 3 );
+ l1.unlock();
+ l2.unlock();
+ l3.unlock();
+ VERIFY( !m1.try_lock() ); // already locked
+ VERIFY( !m2.try_lock() ); // already locked
+ VERIFY( !m3.try_lock() ); // already locked
+ m1.unlock();
+ m2.unlock();
+ m3.unlock();
+ }
+ catch (...)
+ {
+ VERIFY( false );
+ }
}
void test02()
@@ -111,6 +166,31 @@ void test02()
{
VERIFY( false );
}
+
+ // Repeat with non-heterogeneous arguments
+
+ try
+ {
+ unreliable_lock::lock_on = 1;
+ while (unreliable_lock::lock_on < 3)
+ {
+ unreliable_lock::count = 0;
+ unreliable_lock l1, l2, l3;
+ std::mutex m1;
+ std::lock(l1, l2, l3, m1);
+ VERIFY( unreliable_lock::count > 3 );
+ l1.unlock();
+ l2.unlock();
+ l3.unlock();
+ VERIFY( !m1.try_lock() ); // already locked
+ m1.unlock();
+ ++unreliable_lock::lock_on;
+ }
+ }
+ catch (...)
+ {
+ VERIFY( false );
+ }
}
void test03()
@@ -133,6 +213,50 @@ void test03()
VERIFY( test );
++unreliable_lock::throw_on;
}
+
+ // Repeat with non-heterogeneous arguments
+
+ unreliable_lock::throw_on = 0;
+ while (unreliable_lock::throw_on < 3)
+ {
+ unreliable_lock::count = 0;
+ unreliable_lock l1, l2, l3;
+ std::mutex m1;
+ bool test = false;
+ try
+ {
+ std::lock(l1, l2, l3, m1);
+ }
+ catch (...)
+ {
+ test = true;
+ }
+ VERIFY( test );
+ VERIFY( m1.try_lock() ); // m1 was not left locked by failed std::lock
+ m1.unlock();
+ ++unreliable_lock::throw_on;
+ }
+
+ unreliable_lock::throw_on = 0;
+ while (unreliable_lock::throw_on < 3)
+ {
+ unreliable_lock::count = 0;
+ unreliable_lock l1, l2, l3;
+ std::mutex m1;
+ bool test = false;
+ try
+ {
+ std::lock(m1, l1, l2, l3);
+ }
+ catch (...)
+ {
+ test = true;
+ }
+ VERIFY( test );
+ VERIFY( m1.try_lock() ); // m1 was not left locked by failed std::lock
+ m1.unlock();
+ ++unreliable_lock::throw_on;
+ }
}
int main()
diff --git a/libstdc++-v3/testsuite/30_threads/try_lock/5.cc b/libstdc++-v3/testsuite/30_threads/try_lock/5.cc
new file mode 100644
index 0000000..a5574ff
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/try_lock/5.cc
@@ -0,0 +1,41 @@
+// { dg-do run { target c++11 } }
+
+#include <mutex>
+#include <testsuite_hooks.h>
+
+struct Lockable
+{
+ static int tries;
+
+ void lock() { }
+ void unlock() { }
+ bool try_lock() { return ++tries != 2; }
+};
+
+int Lockable::tries = 0;
+
+void test01()
+{
+ Lockable l1, l2, l3;
+ std::mutex m1, m2;
+
+ VERIFY( std::try_lock(l1, l2, l3) == 1 );
+ VERIFY( Lockable::tries == 2 );
+
+ Lockable::tries = 0;
+ VERIFY( std::try_lock(m1, l1, l2, l3) == 2 );
+ VERIFY( Lockable::tries == 2 );
+
+ Lockable::tries = 0;
+ VERIFY( std::try_lock(l1, l2, l3, m1) == 1 );
+ VERIFY( Lockable::tries == 2 );
+
+ Lockable::tries = 0;
+ VERIFY( std::try_lock(m1, l1, l2, l3, m2) == 2 );
+ VERIFY( Lockable::tries == 2 );
+}
+
+int main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc b/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc
index 8603e56..08698ce 100644
--- a/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc
+++ b/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc
@@ -46,3 +46,9 @@ void test02()
test_type l1, l2, l3;
std::lock(l1, l2, l3);
}
+
+void test03()
+{
+ test_type l1, l2, l3;
+ std::try_lock(l1, l2, l3);
+}