[patch] C++11: Observers for the three 'handler functions'

Jonathan Wakely jwakely.gcc@gmail.com
Wed Apr 3 08:00:00 GMT 2013


This patch implements
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3189.htm

The function pointer holding the current new handler was exposed as an
extern variable, which is unnecessary now there's an accessor for it.
Atomic operations are used to set and retrieve the handlers to avoid
data races, as required by the standard.

        * libsupc++/exception (get_terminate(), get_unexpected()): Declare.
        * libsupc++/eh_terminate.cc (get_terminate() , set_unexpected()):
        Define.
        (set_terminate(terminate_handler)): Set atomically.
        (set_unexpected(terminate_handler)): Likewise.
        * libsupc++/new (get_new_handler()): Declare.
        * libsupc++/new_handler.cc (get_new_handler()): Define.
        (set_new_handler(new_handler)): Set atomically.
        (__new_handler): Use internal linkage.
        * libsupc++/new_op.cc (operator new): Use get_new_handler().
        * libsupc++/new_opnt.cc (operator new): Likewise.
        * acinclude.m4: Bump libtool_VERSION to 6:19:0.
        * configure: Regenerate.
        * libsupc++/Makefile.am: Compile above files with -std=gnu++11.
        * libsupc++/Makefile.in: Regenerate.
        * config/abi/pre/gnu.ver: Add new exports.
        * doc/xml/manual/status_cxx2011.xml: Update.
        * testsuite/18_support/headers/exception/synopsis.cc: Check accessors
        for handlers.
        * testsuite/18_support/headers/new/synopsis.cc: Likewise.
        * testsuite/18_support/new_handler.cc: New.
        * testsuite/18_support/terminate_handler.cc: New.
        * testsuite/18_support/unexpected_handler.cc: New.

Tested x86_64-linux, committed to trunk.
-------------- next part --------------
commit d4f5cdbeae653bf4fa2dcf29a6e3d02a2752ef20
Author: Jonathan Wakely <jwakely.gcc@gmail.com>
Date:   Tue Jan 8 19:50:13 2013 +0000

    	* libsupc++/exception (get_terminate(), get_unexpected()): Declare.
    	* libsupc++/eh_terminate.cc (get_terminate() , set_unexpected()):
    	Define.
    	(set_terminate(terminate_handler)): Set atomically.
    	(set_unexpected(terminate_handler)): Likewise.
    	* libsupc++/new (get_new_handler()): Declare.
    	* libsupc++/new_handler.cc (get_new_handler()): Define.
    	(set_new_handler(new_handler)): Set atomically.
    	(__new_handler): Use internal linkage.
    	* libsupc++/new_op.cc (operator new): Use get_new_handler().
    	* libsupc++/new_opnt.cc (operator new): Likewise.
    	* acinclude.m4: Bump libtool_VERSION to 6:19:0.
    	* configure: Regenerate.
    	* libsupc++/Makefile.am: Compile above files with -std=gnu++11.
    	* libsupc++/Makefile.in: Regenerate.
    	* config/abi/pre/gnu.ver: Add new exports.
    	* doc/xml/manual/status_cxx2011.xml: Update.
    	* testsuite/18_support/headers/exception/synopsis.cc: Check accessors
    	for handlers.
    	* testsuite/18_support/headers/new/synopsis.cc: Likewise.
    	* testsuite/18_support/new_handler.cc: New.
    	* testsuite/18_support/terminate_handler.cc: New.
    	* testsuite/18_support/unexpected_handler.cc: New.

diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 0871a6a..4d06b20 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -3241,7 +3241,7 @@ changequote([,])dnl
 fi
 
 # For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=6:18:0
+libtool_VERSION=6:19:0
 
 # Everything parsed; figure out what files and settings to use.
 case $enable_symvers in
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 2a9d582..978641f 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -1344,6 +1344,19 @@ GLIBCXX_3.4.18 {
 
 } GLIBCXX_3.4.17;
 
+GLIBCXX_3.4.19 {
+
+    # std::get_new_handler()
+    _ZSt15get_new_handlerv;
+
+    # std::get_terminate()
+    _ZSt13get_terminatev;
+
+    # std::get_unexpected()
+    _ZSt14get_unexpectedv;
+
+} GLIBCXX_3.4.18;
+
 # Symbols in the support library (libsupc++) have their own tag.
 CXXABI_1.3 {
 
diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2011.xml b/libstdc++-v3/doc/xml/manual/status_cxx2011.xml
index 5693bfd..d8caf0f 100644
--- a/libstdc++-v3/doc/xml/manual/status_cxx2011.xml
+++ b/libstdc++-v3/doc/xml/manual/status_cxx2011.xml
@@ -154,13 +154,10 @@ particular release.
       <entry>C library dependency for quick_exit, at_quick_exit</entry>
     </row>
     <row>
-      <?dbhtml bgcolor="#B0B0B0" ?>
       <entry>18.6</entry>
       <entry>Dynamic memory management</entry>
-      <entry>Partial</entry>
-      <entry>Missing <code>get_new_handler</code>.
-             <code>set_new_handler</code> is not thread-safe.
-      </entry>
+      <entry>Y</entry>
+      <entry/>
     </row>
     <row>
       <entry>18.7</entry>
@@ -205,13 +202,10 @@ particular release.
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#B0B0B0" ?>
       <entry>18.8.3</entry>
       <entry>Abnormal termination</entry>
-      <entry>Partial</entry>
-      <entry>Missing <code>get_terminate</code>.
-             <code>set_terminate</code> is not thread-safe.
-      </entry>
+      <entry>Y</entry>
+      <entry/>
     </row>
     <row>
       <entry>18.8.4</entry>
@@ -2616,12 +2610,9 @@ particular release.
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#B0B0B0" ?>
       <entry>D.11</entry>
       <entry>Violating exception-specifications</entry>
-      <entry>Partial</entry>
-      <entry>Missing <code>get_unexpected</code>.
-             <code>set_unexpected</code> is not thread-safe.
+      <entry/>
       </entry>
     </row>
 
diff --git a/libstdc++-v3/libsupc++/Makefile.am b/libstdc++-v3/libsupc++/Makefile.am
index f276eda..25c58fb 100644
--- a/libstdc++-v3/libsupc++/Makefile.am
+++ b/libstdc++-v3/libsupc++/Makefile.am
@@ -106,31 +106,51 @@ cp-demangle.o: cp-demangle.c
 	$(C_COMPILE) -DIN_GLIBCPP_V3 -Wno-error -c $<
 
 
-# Use special rules for the C++0x sources so that the proper flags are passed.
+# Use special rules for the C++11 sources so that the proper flags are passed.
 eh_ptr.lo: eh_ptr.cc
-	$(LTCXXCOMPILE) -std=gnu++0x -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -c $<
 eh_ptr.o: eh_ptr.cc
-	$(CXXCOMPILE) -std=gnu++0x -c $<
+	$(CXXCOMPILE) -std=gnu++11 -c $<
+
+eh_terminate.lo: eh_terminate.cc
+	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+eh_terminate.o: eh_terminate.cc
+	$(CXXCOMPILE) -std=gnu++11 -c $<
 
 eh_throw.lo: eh_throw.cc
-	$(LTCXXCOMPILE) -std=gnu++0x -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -c $<
 eh_throw.o: eh_throw.cc
-	$(CXXCOMPILE) -std=gnu++0x -c $<
+	$(CXXCOMPILE) -std=gnu++11 -c $<
 
 guard.lo: guard.cc
-	$(LTCXXCOMPILE) -std=gnu++0x -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -c $<
 guard.o: guard.cc
-	$(CXXCOMPILE) -std=gnu++0x -c $<
+	$(CXXCOMPILE) -std=gnu++11 -c $<
 
 atexit_thread.lo: atexit_thread.cc
-	$(LTCXXCOMPILE) -std=gnu++0x -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -c $<
 atexit_thread.o: atexit_thread.cc
-	$(CXXCOMPILE) -std=gnu++0x -c $<
+	$(CXXCOMPILE) -std=gnu++11 -c $<
 
 nested_exception.lo: nested_exception.cc
-	$(LTCXXCOMPILE) -std=gnu++0x -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -c $<
 nested_exception.o: nested_exception.cc
-	$(CXXCOMPILE) -std=gnu++0x -c $<
+	$(CXXCOMPILE) -std=gnu++11 -c $<
+
+new_handler.lo: new_handler.cc
+	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+new_handler.o: new_handler.cc
+	$(CXXCOMPILE) -std=gnu++11 -c $<
+
+new_op.lo: new_op.cc
+	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+new_op.o: new_op.cc
+	$(CXXCOMPILE) -std=gnu++11 -c $<
+
+new_opnt.lo: new_opnt.cc
+	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+new_opnt.o: new_opnt.cc
+	$(CXXCOMPILE) -std=gnu++11 -c $<
 
 # AM_CXXFLAGS needs to be in each subdirectory so that it can be
 # modified in a per-library or per-sub-library way.  Need to manually
diff --git a/libstdc++-v3/libsupc++/eh_terminate.cc b/libstdc++-v3/libsupc++/eh_terminate.cc
index b54c859..bc38e1d 100644
--- a/libstdc++-v3/libsupc++/eh_terminate.cc
+++ b/libstdc++-v3/libsupc++/eh_terminate.cc
@@ -45,7 +45,7 @@ __cxxabiv1::__terminate (std::terminate_handler handler) throw ()
 void
 std::terminate () throw()
 {
-  __terminate (__terminate_handler);
+  __terminate (get_terminate ());
 }
 
 void
@@ -58,21 +58,37 @@ __cxxabiv1::__unexpected (std::unexpected_handler handler)
 void
 std::unexpected ()
 {
-  __unexpected (__unexpected_handler);
+  __unexpected (get_unexpected ());
 }
 
 std::terminate_handler
 std::set_terminate (std::terminate_handler func) throw()
 {
-  std::terminate_handler old = __terminate_handler;
-  __terminate_handler = func;
+  std::terminate_handler old;
+  __atomic_exchange (&__terminate_handler, &func, &old, __ATOMIC_ACQ_REL);
   return old;
 }
 
+std::terminate_handler
+std::get_terminate () noexcept
+{
+  std::terminate_handler func;
+  __atomic_load (&__terminate_handler, &func, __ATOMIC_ACQUIRE);
+  return func;
+}
+
 std::unexpected_handler
 std::set_unexpected (std::unexpected_handler func) throw()
 {
-  std::unexpected_handler old = __unexpected_handler;
-  __unexpected_handler = func;
+  std::unexpected_handler old;
+  __atomic_exchange (&__unexpected_handler, &func, &old, __ATOMIC_ACQ_REL);
   return old;
 }
+
+std::unexpected_handler
+std::get_unexpected () noexcept
+{
+  std::unexpected_handler func;
+  __atomic_load (&__unexpected_handler, &func, __ATOMIC_ACQUIRE);
+  return func;
+}
diff --git a/libstdc++-v3/libsupc++/exception b/libstdc++-v3/libsupc++/exception
index f30cda9..6bd9770 100644
--- a/libstdc++-v3/libsupc++/exception
+++ b/libstdc++-v3/libsupc++/exception
@@ -92,6 +92,11 @@ namespace std
   /// Takes a new handler function as an argument, returns the old function.
   terminate_handler set_terminate(terminate_handler) _GLIBCXX_USE_NOEXCEPT;
 
+#if __cplusplus >= 201103L
+  /// Return the current terminate handler.
+  terminate_handler get_terminate() noexcept;
+#endif
+
   /** The runtime will call this function if %exception handling must be
    *  abandoned for any reason.  It can also be called by the user.  */
   void terminate() _GLIBCXX_USE_NOEXCEPT __attribute__ ((__noreturn__));
@@ -99,6 +104,11 @@ namespace std
   /// Takes a new handler function as an argument, returns the old function.
   unexpected_handler set_unexpected(unexpected_handler) _GLIBCXX_USE_NOEXCEPT;
 
+#if __cplusplus >= 201103L
+  /// Return the current unexpected handler.
+  unexpected_handler get_unexpected() noexcept;
+#endif
+
   /** The runtime will call this function if an %exception is thrown which
    *  violates the function's %exception specification.  */
   void unexpected() __attribute__ ((__noreturn__));
diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new
index 2a92603..e3f0f77 100644
--- a/libstdc++-v3/libsupc++/new
+++ b/libstdc++-v3/libsupc++/new
@@ -75,6 +75,11 @@ namespace std
   /// Takes a replacement handler as the argument, returns the
   /// previous handler.
   new_handler set_new_handler(new_handler) throw();
+
+#if __cplusplus >= 201103L
+  /// Return the current new handler.
+  new_handler get_new_handler() noexcept;
+#endif
 } // namespace std
 
 //@{
diff --git a/libstdc++-v3/libsupc++/new_handler.cc b/libstdc++-v3/libsupc++/new_handler.cc
index bbce0bd..2f6bb5e 100644
--- a/libstdc++-v3/libsupc++/new_handler.cc
+++ b/libstdc++-v3/libsupc++/new_handler.cc
@@ -28,12 +28,24 @@
 const std::nothrow_t std::nothrow = { };
 
 using std::new_handler;
-new_handler __new_handler;
+namespace
+{
+  new_handler __new_handler;
+}
 
 new_handler
 std::set_new_handler (new_handler handler) throw()
 {
-  new_handler prev_handler = __new_handler;
-  __new_handler = handler;
+  new_handler prev_handler;
+  __atomic_exchange (&__new_handler, &handler, &prev_handler,
+		     __ATOMIC_ACQ_REL);
   return prev_handler;
 }
+
+new_handler
+std::get_new_handler () noexcept
+{
+  new_handler handler;
+  __atomic_load (&__new_handler, &handler, __ATOMIC_ACQUIRE);
+  return handler;
+}
diff --git a/libstdc++-v3/libsupc++/new_op.cc b/libstdc++-v3/libsupc++/new_op.cc
index 9781596..903b347 100644
--- a/libstdc++-v3/libsupc++/new_op.cc
+++ b/libstdc++-v3/libsupc++/new_op.cc
@@ -38,8 +38,6 @@ using std::malloc;
 extern "C" void *malloc (std::size_t);
 #endif
 
-extern new_handler __new_handler;
-
 _GLIBCXX_WEAK_DEFINITION void *
 operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
 {
@@ -51,7 +49,7 @@ operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
   p = (void *) malloc (sz);
   while (p == 0)
     {
-      new_handler handler = __new_handler;
+      new_handler handler = std::get_new_handler ();
       if (! handler)
 	_GLIBCXX_THROW_OR_ABORT(bad_alloc());
       handler ();
diff --git a/libstdc++-v3/libsupc++/new_opnt.cc b/libstdc++-v3/libsupc++/new_opnt.cc
index 3e22624..d72feff 100644
--- a/libstdc++-v3/libsupc++/new_opnt.cc
+++ b/libstdc++-v3/libsupc++/new_opnt.cc
@@ -30,7 +30,6 @@ using std::new_handler;
 using std::bad_alloc;
 
 extern "C" void *malloc (std::size_t);
-extern new_handler __new_handler;
 
 _GLIBCXX_WEAK_DEFINITION void *
 operator new (std::size_t sz, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
@@ -43,7 +42,7 @@ operator new (std::size_t sz, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
   p = (void *) malloc (sz);
   while (p == 0)
     {
-      new_handler handler = __new_handler;
+      new_handler handler = std::get_new_handler ();
       if (! handler)
 	return 0;
       __try
diff --git a/libstdc++-v3/testsuite/18_support/headers/exception/synopsis.cc b/libstdc++-v3/testsuite/18_support/headers/exception/synopsis.cc
index 3a417b2..acbd832 100644
--- a/libstdc++-v3/testsuite/18_support/headers/exception/synopsis.cc
+++ b/libstdc++-v3/testsuite/18_support/headers/exception/synopsis.cc
@@ -1,4 +1,5 @@
 // { dg-do compile }
+// { dg-options "-std=gnu++11" }
 
 // Copyright (C) 2007-2013 Free Software Foundation, Inc.
 //
@@ -25,10 +26,12 @@ namespace std {
 
   typedef void (*unexpected_handler)();
   unexpected_handler set_unexpected(unexpected_handler  f ) throw();
+  unexpected_handler get_unexpected() noexcept;
   void unexpected();
 
   typedef void (*terminate_handler)();
   terminate_handler set_terminate(terminate_handler  f ) throw();
+  terminate_handler get_terminate() noexcept;
   void terminate() throw();
 
   bool uncaught_exception() throw();
diff --git a/libstdc++-v3/testsuite/18_support/headers/new/synopsis.cc b/libstdc++-v3/testsuite/18_support/headers/new/synopsis.cc
index 47d8f15..8ce8992 100644
--- a/libstdc++-v3/testsuite/18_support/headers/new/synopsis.cc
+++ b/libstdc++-v3/testsuite/18_support/headers/new/synopsis.cc
@@ -1,4 +1,5 @@
 // { dg-do compile }
+// { dg-options "-std=gnu++11" }
 
 // Copyright (C) 2007-2013 Free Software Foundation, Inc.
 //
@@ -25,6 +26,7 @@ namespace std {
   extern const nothrow_t nothrow;
   typedef void (*new_handler)();
   new_handler set_new_handler(new_handler new_p) throw();
+  new_handler get_new_handler() noexcept;
 }
 
 void* operator new(std::size_t size) throw(std::bad_alloc);
diff --git a/libstdc++-v3/testsuite/18_support/new_handler.cc b/libstdc++-v3/testsuite/18_support/new_handler.cc
new file mode 100644
index 0000000..97cb61e
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/new_handler.cc
@@ -0,0 +1,39 @@
+// Copyright (C) 2013 Free Software Foundation
+//
+// 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/>.
+
+// { dg-options "-std=gnu++11" }
+
+// 18.6.2 Storage allocation errors
+
+#include <new>
+#include <testsuite_hooks.h>
+
+void handler() { throw std::bad_alloc(); }
+
+void test01()
+{
+  auto prev = std::set_new_handler(handler);
+  VERIFY( prev == nullptr );
+  auto curr = std::get_new_handler();
+  VERIFY( curr == handler );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/18_support/terminate_handler.cc b/libstdc++-v3/testsuite/18_support/terminate_handler.cc
new file mode 100644
index 0000000..f3112b1
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/terminate_handler.cc
@@ -0,0 +1,40 @@
+// Copyright (C) 2013 Free Software Foundation
+//
+// 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/>.
+
+// { dg-options "-std=gnu++11" }
+
+// 18.8.3 Abnormal termination
+
+#include <exception>
+#include <cstdlib>
+#include <testsuite_hooks.h>
+
+void handler() { std::abort(); }
+
+void test01()
+{
+  auto prev = std::set_terminate(handler);
+  VERIFY( prev != handler );
+  auto curr = std::get_terminate();
+  VERIFY( curr == handler );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/18_support/unexpected_handler.cc b/libstdc++-v3/testsuite/18_support/unexpected_handler.cc
new file mode 100644
index 0000000..f5a9250
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/unexpected_handler.cc
@@ -0,0 +1,40 @@
+// Copyright (C) 2013 Free Software Foundation
+//
+// 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/>.
+
+// { dg-options "-std=gnu++11" }
+
+// D.11 Violating exception-specifications
+
+#include <exception>
+#include <cstdlib>
+#include <testsuite_hooks.h>
+
+void handler() { std::abort(); }
+
+void test01()
+{
+  auto prev = std::set_unexpected(handler);
+  VERIFY( prev != handler );
+  auto curr = std::get_unexpected();
+  VERIFY( curr == handler );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}


More information about the Gcc-patches mailing list