diff mbox

Add std::scoped_lock for C++17

Message ID 20170305183812.GA15543@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely March 5, 2017, 6:38 p.m. UTC
This was just approved at the WG21 meeting.

	* doc/xml/manual/status_cxx2017.xml: Document P0156R2 status.
	* doc/html/*: Regenerate.
	* include/std/mutex (scoped_lock): Implement new C++17 template.
	* testsuite/30_threads/scoped_lock/cons/1.cc: New test.
	* testsuite/30_threads/scoped_lock/requirements/
	explicit_instantiation.cc: New test.
	* testsuite/30_threads/scoped_lock/requirements/typedefs.cc: New test.

Tested powerpc64le-linux, committed to trunk.
commit 109ebf33d95668712c93627d523afe65354c51f9
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Sun Mar 5 17:39:00 2017 +0000

    Add std::scoped_lock for C++17
    
    	* doc/xml/manual/status_cxx2017.xml: Document P0156R2 status.
    	* doc/html/*: Regenerate.
    	* include/std/mutex (scoped_lock): Implement new C++17 template.
    	* testsuite/30_threads/scoped_lock/cons/1.cc: New test.
    	* testsuite/30_threads/scoped_lock/requirements/
    	explicit_instantiation.cc: New test.
    	* testsuite/30_threads/scoped_lock/requirements/typedefs.cc: New test.
diff mbox

Patch

diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
index add0514..1053f2d 100644
--- a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
+++ b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
@@ -719,15 +719,14 @@  Feature-testing recommendations for C++</link>.
     </row>
 
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry> Variadic <code>lock_guard</code> </entry>
       <entry>
-	<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0156r0.html">
-	P0156R0
+	<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0156r2.html">
+	P0156R2
 	</link>
       </entry>
-      <entry align="center"> No </entry>
-      <entry><code> __cpp_lib_lock_guard_variadic >= 201510 </code></entry>
+      <entry align="center"> 7 </entry>
+      <entry><code> __cpp_lib_scoped_lock >= 201703 </code></entry>
     </row>
 
   </tbody>
diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex
index d6f3899..6c3f920 100644
--- a/libstdc++-v3/include/std/mutex
+++ b/libstdc++-v3/include/std/mutex
@@ -556,6 +556,74 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
         }
     }
 
+#if __cplusplus > 201402L
+#define __cpp_lib_scoped_lock 201703
+  /** @brief A scoped lock type for multiple lockable objects.
+   *
+   * A scoped_lock controls mutex ownership within a scope, releasing
+   * ownership in the destructor.
+   */
+  template<typename... _MutexTypes>
+    class scoped_lock
+    {
+    public:
+      explicit scoped_lock(_MutexTypes&... __m) : _M_devices(std::tie(__m...))
+      { std::lock(__m...); }
+
+      explicit scoped_lock(_MutexTypes&... __m, adopt_lock_t) noexcept
+      : _M_devices(std::tie(__m...))
+      { } // calling thread owns mutex
+
+      ~scoped_lock()
+      {
+	std::apply([](_MutexTypes&... __m) {
+	  char __i[] __attribute__((__unused__)) = { (__m.unlock(), 0)... };
+	}, _M_devices);
+      }
+
+      scoped_lock(const scoped_lock&) = delete;
+      scoped_lock& operator=(const scoped_lock&) = delete;
+
+    private:
+      tuple<_MutexTypes&...> _M_devices;
+    };
+
+  template<>
+    class scoped_lock<>
+    {
+    public:
+      explicit scoped_lock() = default;
+      explicit scoped_lock(adopt_lock_t) noexcept { }
+      ~scoped_lock() = default;
+
+      scoped_lock(const scoped_lock&) = delete;
+      scoped_lock& operator=(const scoped_lock&) = delete;
+    };
+
+  template<typename _Mutex>
+    class scoped_lock<_Mutex>
+    {
+    public:
+      using mutex_type = _Mutex;
+
+      explicit scoped_lock(mutex_type& __m) : _M_device(__m)
+      { _M_device.lock(); }
+
+      explicit scoped_lock(mutex_type& __m, adopt_lock_t) noexcept
+      : _M_device(__m)
+      { } // calling thread owns mutex
+
+      ~scoped_lock()
+      { _M_device.unlock(); }
+
+      scoped_lock(const scoped_lock&) = delete;
+      scoped_lock& operator=(const scoped_lock&) = delete;
+
+    private:
+      mutex_type&  _M_device;
+    };
+#endif // C++17
+
 #ifdef _GLIBCXX_HAS_GTHREADS
   /// once_flag
   struct once_flag
diff --git a/libstdc++-v3/testsuite/30_threads/scoped_lock/cons/1.cc b/libstdc++-v3/testsuite/30_threads/scoped_lock/cons/1.cc
new file mode 100644
index 0000000..9f1b48c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/scoped_lock/cons/1.cc
@@ -0,0 +1,133 @@ 
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++1z } }
+// { dg-require-cstdint "" }
+
+// Copyright (C) 2017 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 BasicLockable
+{
+  BasicLockable() : locked(false) { }
+
+  ~BasicLockable() noexcept(false)
+  {
+    if (locked)
+      throw 0;
+  }
+
+  void lock()
+  {
+    if (locked)
+      throw 0;
+    locked = true;
+  }
+
+  void unlock()
+  {
+    if (!locked)
+      throw 0;
+    locked = false;
+  }
+
+  bool locked;
+};
+
+template<int>
+struct Lockable
+{
+  BasicLockable m;
+  void lock() { m.lock(); }
+  void unlock() { m.unlock(); }
+  bool try_lock() { if (m.locked) return false; m.lock(); return true; }
+};
+
+void test01()
+{
+  BasicLockable m;
+
+  try
+    {
+      std::scoped_lock<BasicLockable> l(m);
+      VERIFY( m.locked );
+    }
+  catch (...)
+    {
+      VERIFY( false );
+    }
+
+  VERIFY( !m.locked );
+
+  m.lock();
+
+  try
+    {
+      std::scoped_lock<BasicLockable> l(m, std::adopt_lock);
+    }
+  catch (...)
+    {
+      VERIFY( false );
+    }
+
+  VERIFY( !m.locked );
+}
+
+void test02()
+{
+  Lockable<1> m1;
+  Lockable<2> m2;
+
+  try
+    {
+      std::scoped_lock<Lockable<1>, Lockable<2>> l(m1, m2);
+      VERIFY( m1.m.locked );
+      VERIFY( m2.m.locked );
+    }
+  catch (...)
+    {
+      VERIFY( false );
+    }
+
+  VERIFY( !m1.m.locked );
+  VERIFY( !m2.m.locked );
+
+  m1.lock();
+  m2.lock();
+
+  try
+    {
+      std::scoped_lock<Lockable<1>, Lockable<2>> l(m1, m2, std::adopt_lock);
+      VERIFY( m1.m.locked );
+      VERIFY( m2.m.locked );
+    }
+  catch (...)
+    {
+      VERIFY( false );
+    }
+
+  VERIFY( !m1.m.locked );
+  VERIFY( !m2.m.locked );
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/explicit_instantiation.cc b/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/explicit_instantiation.cc
new file mode 100644
index 0000000..cbf1075
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/explicit_instantiation.cc
@@ -0,0 +1,33 @@ 
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++1z } }
+// { dg-require-cstdint "" }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2017 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/>.
+
+
+// NB: This file is for testing with NO OTHER INCLUDES.
+
+#include <mutex>
+
+namespace std
+{
+  template class scoped_lock<>;
+  template class scoped_lock<mutex>;
+  template class scoped_lock<recursive_mutex, mutex>;
+}
diff --git a/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/typedefs.cc b/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/typedefs.cc
new file mode 100644
index 0000000..55756d8
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/typedefs.cc
@@ -0,0 +1,33 @@ 
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++1z } }
+// { dg-require-cstdint "" }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2017 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/>.
+
+
+// NB: This file is for testing with NO OTHER INCLUDES.
+
+#include <mutex>
+
+void test01()
+{
+  // Check for required typedefs
+  typedef std::scoped_lock<std::mutex> test_type;
+  typedef test_type::mutex_type mutex_type;
+}