mirror of git://gcc.gnu.org/git/gcc.git
mutex (try_lock, [...]): Fix.
2010-12-04 Jonathan Wakely <jwakely.gcc@gmail.com> * include/std/mutex (try_lock, __try_lock_impl): Fix. (lock): Implement using __try_lock_impl. * testsuite/30_threads/try_lock/2.cc: Fix logic. * testsuite/30_threads/try_lock/4.cc: New. * testsuite/30_threads/lock/1.cc: New. * testsuite/30_threads/lock/2.cc: New. * testsuite/30_threads/lock/3.cc: New. * testsuite/30_threads/lock/4.cc: New. From-SVN: r167452
This commit is contained in:
parent
3dcdeeb24b
commit
9b2b801af5
|
@ -1,3 +1,14 @@
|
|||
2010-12-04 Jonathan Wakely <jwakely.gcc@gmail.com>
|
||||
|
||||
* include/std/mutex (try_lock, __try_lock_impl): Fix.
|
||||
(lock): Implement using __try_lock_impl.
|
||||
* testsuite/30_threads/try_lock/2.cc: Fix logic.
|
||||
* testsuite/30_threads/try_lock/4.cc: New.
|
||||
* testsuite/30_threads/lock/1.cc: New.
|
||||
* testsuite/30_threads/lock/2.cc: New.
|
||||
* testsuite/30_threads/lock/3.cc: New.
|
||||
* testsuite/30_threads/lock/4.cc: New.
|
||||
|
||||
2010-12-02 Jonathan Wakely <jwakely.gcc@gmail.com>
|
||||
|
||||
* src/future.cc (future_category): Export compatibility symbol.
|
||||
|
|
|
@ -656,23 +656,27 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
|
|||
{ }
|
||||
};
|
||||
|
||||
template<typename _Lock>
|
||||
unique_lock<_Lock>
|
||||
__try_to_lock(_Lock& __l)
|
||||
{ return unique_lock<_Lock>(__l, try_to_lock); }
|
||||
|
||||
template<int _Idx, bool _Continue = true>
|
||||
struct __try_lock_impl
|
||||
{
|
||||
template<typename... _Lock>
|
||||
static int
|
||||
__do_try_lock(tuple<_Lock&...>& __locks)
|
||||
static void
|
||||
__do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
|
||||
{
|
||||
if(std::get<_Idx>(__locks).try_lock())
|
||||
{
|
||||
return __try_lock_impl<_Idx + 1,
|
||||
_Idx + 2 < sizeof...(_Lock)>::__do_try_lock(__locks);
|
||||
}
|
||||
else
|
||||
{
|
||||
__unlock_impl<_Idx>::__do_unlock(__locks);
|
||||
return _Idx;
|
||||
}
|
||||
__idx = _Idx;
|
||||
auto __lock = __try_to_lock(std::get<_Idx>(__locks));
|
||||
if (__lock.owns_lock())
|
||||
{
|
||||
__try_lock_impl<_Idx + 1, _Idx + 2 < sizeof...(_Lock)>::
|
||||
__do_try_lock(__locks, __idx);
|
||||
if (__idx == -1)
|
||||
__lock.release();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -680,16 +684,16 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
|
|||
struct __try_lock_impl<_Idx, false>
|
||||
{
|
||||
template<typename... _Lock>
|
||||
static int
|
||||
__do_try_lock(tuple<_Lock&...>& __locks)
|
||||
static void
|
||||
__do_try_lock(tuple<_Lock&...>& __locks, int& __idx)
|
||||
{
|
||||
if(std::get<_Idx>(__locks).try_lock())
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
__unlock_impl<_Idx>::__do_unlock(__locks);
|
||||
return _Idx;
|
||||
}
|
||||
__idx = _Idx;
|
||||
auto __lock = __try_to_lock(std::get<_Idx>(__locks));
|
||||
if (__lock.owns_lock())
|
||||
{
|
||||
__idx = -1;
|
||||
__lock.release();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -707,14 +711,43 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
|
|||
int
|
||||
try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
|
||||
{
|
||||
tuple<_Lock1&, _Lock2&, _Lock3&...> __locks(__l1, __l2, __l3...);
|
||||
return __try_lock_impl<0>::__do_try_lock(__locks);
|
||||
int __idx;
|
||||
auto __locks = std::tie(__l1, __l2, __l3...);
|
||||
__try
|
||||
{ __try_lock_impl<0>::__do_try_lock(__locks, __idx); }
|
||||
__catch(...)
|
||||
{ }
|
||||
return __idx;
|
||||
}
|
||||
|
||||
/// lock
|
||||
/** @brief Generic lock.
|
||||
* @param __l1 Meets Mutex requirements (try_lock() may throw).
|
||||
* @param __l2 Meets Mutex requirements (try_lock() may throw).
|
||||
* @param __l3 Meets Mutex requirements (try_lock() may throw).
|
||||
* @throw An exception thrown by an argument's lock() or try_lock() member.
|
||||
* @post All arguments are locked.
|
||||
*
|
||||
* All arguments are locked via a sequence of calls to lock(), try_lock()
|
||||
* and unlock(). If the call exits via an exception any locks that were
|
||||
* obtained will be released.
|
||||
*/
|
||||
template<typename _L1, typename _L2, typename ..._L3>
|
||||
void
|
||||
lock(_L1&, _L2&, _L3&...);
|
||||
lock(_L1& __l1, _L2& __l2, _L3&... __l3)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
unique_lock<_L1> __first(__l1);
|
||||
int __idx;
|
||||
auto __locks = std::tie(__l2, __l3...);
|
||||
__try_lock_impl<0, sizeof...(_L3)>::__do_try_lock(__locks, __idx);
|
||||
if (__idx == -1)
|
||||
{
|
||||
__first.release();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// once_flag
|
||||
struct once_flag
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
// { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* alpha*-*-osf* mips-sgi-irix6* } }
|
||||
// { dg-options " -std=gnu++0x -pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* alpha*-*-osf* mips-sgi-irix6* } }
|
||||
// { dg-options " -std=gnu++0x -pthreads" { target *-*-solaris* } }
|
||||
// { dg-options " -std=gnu++0x " { target *-*-cygwin *-*-darwin* } }
|
||||
// { dg-require-cstdint "" }
|
||||
// { dg-require-gthreads "" }
|
||||
|
||||
// Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, 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 General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include <mutex>
|
||||
#include <system_error>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
typedef std::mutex mutex_type;
|
||||
typedef std::unique_lock<mutex_type> lock_type;
|
||||
|
||||
try
|
||||
{
|
||||
mutex_type m1, m2, m3;
|
||||
lock_type l1(m1, std::defer_lock),
|
||||
l2(m2, std::defer_lock),
|
||||
l3(m3, std::defer_lock);
|
||||
|
||||
try
|
||||
{
|
||||
std::lock(l1, l2, l3);
|
||||
VERIFY( l1.owns_lock() );
|
||||
VERIFY( l2.owns_lock() );
|
||||
VERIFY( l3.owns_lock() );
|
||||
}
|
||||
catch (const std::system_error& e)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
}
|
||||
catch (const std::system_error& e)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* alpha*-*-osf* mips-sgi-irix6* } }
|
||||
// { dg-options " -std=gnu++0x -pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* alpha*-*-osf* mips-sgi-irix6* } }
|
||||
// { dg-options " -std=gnu++0x -pthreads" { target *-*-solaris* } }
|
||||
// { dg-options " -std=gnu++0x " { target *-*-cygwin *-*-darwin* } }
|
||||
// { dg-require-cstdint "" }
|
||||
// { dg-require-gthreads "" }
|
||||
|
||||
// Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, 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 General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void locker(std::mutex& m1, std::mutex& m2, std::mutex& m3)
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
||||
typedef std::unique_lock<std::mutex> lock_type;
|
||||
|
||||
lock_type l1(m1, std::defer_lock);
|
||||
lock_type l2(m2, std::defer_lock);
|
||||
lock_type l3(m3, std::defer_lock);
|
||||
std::lock(l1, l2, l3);
|
||||
VERIFY( l1.owns_lock() );
|
||||
VERIFY( l2.owns_lock() );
|
||||
VERIFY( l3.owns_lock() );
|
||||
}
|
||||
|
||||
void test01()
|
||||
{
|
||||
std::mutex m1, m2, m3;
|
||||
std::thread t1(locker, std::ref(m1), std::ref(m2), std::ref(m3));
|
||||
std::thread t2(locker, std::ref(m3), std::ref(m2), std::ref(m1));
|
||||
t1.join();
|
||||
t2.join();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
// { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* alpha*-*-osf* mips-sgi-irix6* } }
|
||||
// { dg-options " -std=gnu++0x -pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* alpha*-*-osf* mips-sgi-irix6* } }
|
||||
// { dg-options " -std=gnu++0x -pthreads" { target *-*-solaris* } }
|
||||
// { dg-options " -std=gnu++0x " { target *-*-cygwin *-*-darwin* } }
|
||||
// { dg-require-cstdint "" }
|
||||
// { dg-require-gthreads "" }
|
||||
|
||||
// Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, 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 General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include <mutex>
|
||||
#include <system_error>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
struct user_lock
|
||||
{
|
||||
user_lock() : is_locked(false) { }
|
||||
~user_lock() = default;
|
||||
user_lock(const user_lock&) = default;
|
||||
|
||||
void lock()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
VERIFY( !is_locked );
|
||||
is_locked = true;
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{ return is_locked ? false : (is_locked = true); }
|
||||
|
||||
void unlock()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
VERIFY( is_locked );
|
||||
is_locked = false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_locked;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
||||
try
|
||||
{
|
||||
std::mutex m1;
|
||||
std::recursive_mutex m2;
|
||||
user_lock m3;
|
||||
|
||||
try
|
||||
{
|
||||
//heterogeneous types
|
||||
std::lock(m1, m2, m3);
|
||||
m1.unlock();
|
||||
m2.unlock();
|
||||
m3.unlock();
|
||||
}
|
||||
catch (const std::system_error& e)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
}
|
||||
catch (const std::system_error& e)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
// { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* alpha*-*-osf* mips-sgi-irix6* } }
|
||||
// { dg-options " -std=gnu++0x -pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* alpha*-*-osf* mips-sgi-irix6* } }
|
||||
// { dg-options " -std=gnu++0x -pthreads" { target *-*-solaris* } }
|
||||
// { dg-options " -std=gnu++0x " { target *-*-cygwin *-*-darwin* } }
|
||||
// { dg-require-cstdint "" }
|
||||
// { dg-require-gthreads "" }
|
||||
|
||||
// Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, 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 General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include <mutex>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
struct unreliable_lock
|
||||
{
|
||||
std::mutex m;
|
||||
std::unique_lock<std::mutex> l;
|
||||
|
||||
static int count;
|
||||
static int throw_on;
|
||||
static int lock_on;
|
||||
|
||||
unreliable_lock() : l(m, std::defer_lock) { }
|
||||
|
||||
~unreliable_lock()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
VERIFY( !l.owns_lock() );
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (count == throw_on)
|
||||
throw throw_on;
|
||||
++count;
|
||||
l.lock();
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if (count == throw_on)
|
||||
throw throw_on;
|
||||
std::unique_lock<std::mutex> l2(m, std::defer_lock);
|
||||
if (count == lock_on)
|
||||
l2.lock();
|
||||
++count;
|
||||
return l.try_lock();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
VERIFY( l.owns_lock() );
|
||||
l.unlock();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int unreliable_lock::count = 0;
|
||||
int unreliable_lock::throw_on = -1;
|
||||
int unreliable_lock::lock_on = -1;
|
||||
|
||||
void test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
||||
unreliable_lock l1, l2, l3;
|
||||
|
||||
try
|
||||
{
|
||||
unreliable_lock::count = 0;
|
||||
std::lock(l1, l2, l3);
|
||||
VERIFY( unreliable_lock::count == 3 );
|
||||
l1.unlock();
|
||||
l2.unlock();
|
||||
l3.unlock();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
}
|
||||
|
||||
void test02()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
||||
// test behaviour when a lock is already held
|
||||
try
|
||||
{
|
||||
unreliable_lock::lock_on = 1;
|
||||
while (unreliable_lock::lock_on < 3)
|
||||
{
|
||||
unreliable_lock::count = 0;
|
||||
unreliable_lock l1, l2, l3;
|
||||
std::lock(l1, l2, l3);
|
||||
VERIFY( unreliable_lock::count > 3 );
|
||||
l1.unlock();
|
||||
l2.unlock();
|
||||
l3.unlock();
|
||||
++unreliable_lock::lock_on;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
}
|
||||
|
||||
void test03()
|
||||
{
|
||||
// test behaviour when an exception is thrown
|
||||
unreliable_lock::throw_on = 0;
|
||||
while (unreliable_lock::throw_on < 3)
|
||||
{
|
||||
unreliable_lock::count = 0;
|
||||
unreliable_lock l1, l2, l3;
|
||||
bool test = false;
|
||||
try
|
||||
{
|
||||
std::lock(l1, l2, l3);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
test = true;
|
||||
}
|
||||
VERIFY( test );
|
||||
++unreliable_lock::throw_on;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
test03();
|
||||
return 0;
|
||||
}
|
|
@ -27,6 +27,8 @@
|
|||
#include <system_error>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
typedef std::unique_lock<std::mutex> lock_type;
|
||||
|
||||
void test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
@ -34,12 +36,12 @@ void test01()
|
|||
try
|
||||
{
|
||||
std::mutex m1, m2, m3;
|
||||
m1.lock();
|
||||
lock_type l1(m1);
|
||||
int result = std::try_lock(m1, m2, m3);
|
||||
VERIFY( result == 0 );
|
||||
m1.lock();
|
||||
m2.lock();
|
||||
m3.lock();
|
||||
VERIFY( l1.owns_lock() );
|
||||
lock_type l2(m2);
|
||||
lock_type l3(m3);
|
||||
}
|
||||
catch (const std::system_error& e)
|
||||
{
|
||||
|
@ -58,12 +60,12 @@ void test02()
|
|||
try
|
||||
{
|
||||
std::mutex m1, m2, m3;
|
||||
m2.lock();
|
||||
lock_type l2(m2);
|
||||
int result = std::try_lock(m1, m2, m3);
|
||||
VERIFY( result == 1 );
|
||||
m1.lock();
|
||||
m2.lock();
|
||||
m3.lock();
|
||||
VERIFY( l2.owns_lock() );
|
||||
lock_type l1(m1);
|
||||
lock_type l3(m3);
|
||||
}
|
||||
catch (const std::system_error& e)
|
||||
{
|
||||
|
@ -82,12 +84,12 @@ void test03()
|
|||
try
|
||||
{
|
||||
std::mutex m1, m2, m3;
|
||||
m3.lock();
|
||||
lock_type l3(m3);
|
||||
int result = std::try_lock(m1, m2, m3);
|
||||
VERIFY( result == 2 );
|
||||
m1.lock();
|
||||
m2.lock();
|
||||
m3.lock();
|
||||
VERIFY( l3.owns_lock() );
|
||||
lock_type l1(m1);
|
||||
lock_type l2(m2);
|
||||
}
|
||||
catch (const std::system_error& e)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
// { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* alpha*-*-osf* mips-sgi-irix6* } }
|
||||
// { dg-options " -std=gnu++0x -pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* alpha*-*-osf* mips-sgi-irix6* } }
|
||||
// { dg-options " -std=gnu++0x -pthreads" { target *-*-solaris* } }
|
||||
// { dg-options " -std=gnu++0x " { target *-*-cygwin *-*-darwin* } }
|
||||
// { dg-require-cstdint "" }
|
||||
// { dg-require-gthreads "" }
|
||||
|
||||
// Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, 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 General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include <mutex>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
struct unreliable_lock
|
||||
{
|
||||
std::mutex m;
|
||||
std::unique_lock<std::mutex> l;
|
||||
|
||||
static int count;
|
||||
static int throw_on;
|
||||
static int lock_on;
|
||||
|
||||
unreliable_lock() : l(m, std::defer_lock) { }
|
||||
|
||||
~unreliable_lock()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
VERIFY( !l.owns_lock() );
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (count == throw_on)
|
||||
throw throw_on;
|
||||
++count;
|
||||
l.lock();
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if (count == throw_on)
|
||||
throw throw_on;
|
||||
std::unique_lock<std::mutex> l2(m, std::defer_lock);
|
||||
if (count == lock_on)
|
||||
l2.lock();
|
||||
++count;
|
||||
return l.try_lock();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
VERIFY( l.owns_lock() );
|
||||
l.unlock();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int unreliable_lock::count = 0;
|
||||
int unreliable_lock::throw_on = -1;
|
||||
int unreliable_lock::lock_on = -1;
|
||||
|
||||
void test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
||||
unreliable_lock l1, l2, l3;
|
||||
|
||||
try
|
||||
{
|
||||
unreliable_lock::count = 0;
|
||||
int result = std::try_lock(l1, l2, l3);
|
||||
VERIFY( result == -1 );
|
||||
VERIFY( unreliable_lock::count == 3 );
|
||||
l1.unlock();
|
||||
l2.unlock();
|
||||
l3.unlock();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
}
|
||||
|
||||
void test02()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
||||
unreliable_lock l1, l2, l3;
|
||||
|
||||
try
|
||||
{
|
||||
// test behaviour when a lock is already held
|
||||
unreliable_lock::lock_on = 0;
|
||||
while (unreliable_lock::lock_on < 3)
|
||||
{
|
||||
unreliable_lock::count = 0;
|
||||
int failed = std::try_lock(l1, l2, l3);
|
||||
VERIFY( failed == unreliable_lock::lock_on );
|
||||
++unreliable_lock::lock_on;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
}
|
||||
|
||||
void test03()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
||||
unreliable_lock l1, l2, l3;
|
||||
|
||||
try
|
||||
{
|
||||
// test behaviour when an exception is thrown
|
||||
unreliable_lock::throw_on = 0;
|
||||
while (unreliable_lock::throw_on < 3)
|
||||
{
|
||||
unreliable_lock::count = 0;
|
||||
int failed = std::try_lock(l1, l2, l3);
|
||||
VERIFY( failed == unreliable_lock::throw_on );
|
||||
++unreliable_lock::throw_on;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
test03();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue