Patchwork Define accessors for handler functions (Was [patch] update libstdc++ C++11 status table)

login
register
mail settings
Submitter Jonathan Wakely
Date Jan. 8, 2013, 10:58 p.m.
Message ID <CAH6eHdQwSAF3dctDEyPTiTN=DLnhRn1igxrHNt84xoOuHKYR7A@mail.gmail.com>
Download mbox | patch
Permalink /patch/210557/
State New
Headers show

Comments

Jonathan Wakely - Jan. 8, 2013, 10:58 p.m.
On 8 January 2013 21:33, Jonathan Wakely wrote:
> I was going to fix this missing feature, but as Richard just announced
> Stage 3 has ended I'll just update the docs and wait for trunk to
> reopen.
>
>         * doc/xml/manual/status_cxx2011.xml: Document that N3189 is missing.
>
> Committed to trunk and 4.7

Here's a patch to implement N3189, in case I get hit by a bus before
Stage 1. This adds get_new_handler, get_unexpected and get_terminate,
and makes all stores and loads of the handlers atomic.

I think this is safe and backwards compatible, because all stores and
loads of the handlers happen in the library, but I'll wait for Stage
1.
commit d9a509e2ea86b9689e1029f9d648edc5ada8196b
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.
    	* libsupc++/Makefile.am: Compile above files with -std=gnu++11.
    	* libsupc++/Makefile.in: Regenerate.
    	* config/abi/pre/gnu.ver: Add new exports.
    	* 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.

Patch

diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 35b4c44..9c13e1a 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -1345,6 +1345,15 @@  GLIBCXX_3.4.18 {
     # std::bad_function_call::what()
     _ZNKSt17bad_function_call4whatEv;
 
+    # std::get_new_handler()
+    _ZSt15get_new_handlerv;
+
+    # std::get_terminate()
+    _ZSt13get_terminatev;
+
+    # std::get_unexpected()
+    _ZSt14get_unexpectedv;
+
 } GLIBCXX_3.4.17;
 
 # Symbols in the support library (libsupc++) have their own tag.
diff --git a/libstdc++-v3/libsupc++/Makefile.am b/libstdc++-v3/libsupc++/Makefile.am
index a019bd8..0207746 100644
--- a/libstdc++-v3/libsupc++/Makefile.am
+++ b/libstdc++-v3/libsupc++/Makefile.am
@@ -108,31 +108,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 87359d0..35e43c2 100644
--- a/libstdc++-v3/libsupc++/eh_terminate.cc
+++ b/libstdc++-v3/libsupc++/eh_terminate.cc
@@ -1,7 +1,5 @@ 
 // -*- C++ -*- std::terminate, std::unexpected and friends.
-// Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2009,
-// 2011
-// Free Software Foundation
+// Copyright (C) 1994-2013 Free Software Foundation
 //
 // This file is part of GCC.
 //
@@ -47,7 +45,7 @@  __cxxabiv1::__terminate (std::terminate_handler handler) throw ()
 void
 std::terminate () throw()
 {
-  __terminate (__terminate_handler);
+  __terminate (get_terminate ());
 }
 
 void
@@ -60,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 9763ede..cd12816 100644
--- a/libstdc++-v3/libsupc++/exception
+++ b/libstdc++-v3/libsupc++/exception
@@ -1,8 +1,6 @@ 
 // Exception Handling support header for -*- C++ -*-
 
-// Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-// 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
-// Free Software Foundation
+// Copyright (C) 1995-2013 Free Software Foundation
 //
 // This file is part of GCC.
 //
@@ -94,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__));
@@ -101,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 1c25800..d787f51 100644
--- a/libstdc++-v3/libsupc++/new
+++ b/libstdc++-v3/libsupc++/new
@@ -1,8 +1,6 @@ 
 // The -*- C++ -*- dynamic memory management header.
 
-// Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-// 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011
-// Free Software Foundation
+// Copyright (C) 1994-2013 Free Software Foundation
 
 // This file is part of GCC.
 //
@@ -77,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 4e3c935..f17e993 100644
--- a/libstdc++-v3/libsupc++/new_handler.cc
+++ b/libstdc++-v3/libsupc++/new_handler.cc
@@ -1,8 +1,6 @@ 
 // Implementation file for the -*- C++ -*- dynamic memory management header.
 
-// Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-// 2005, 2006, 2007, 2008, 2009, 2010
-// Free Software Foundation
+// Copyright (C) 1996-2013 Free Software Foundation
 //
 // This file is part of GCC.
 //
@@ -30,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 7366d55..3134e53 100644
--- a/libstdc++-v3/libsupc++/new_op.cc
+++ b/libstdc++-v3/libsupc++/new_op.cc
@@ -1,6 +1,6 @@ 
 // Support routines for the -*- C++ -*- dynamic memory management.
 
-// Copyright (C) 1997-2012 Free Software Foundation
+// Copyright (C) 1997-2013 Free Software Foundation
 //
 // This file is part of GCC.
 //
@@ -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 71600a6..20ca104 100644
--- a/libstdc++-v3/libsupc++/new_opnt.cc
+++ b/libstdc++-v3/libsupc++/new_opnt.cc
@@ -1,6 +1,5 @@ 
 // Support routines for the -*- C++ -*- dynamic memory management.
-// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2004, 2009, 2011
-// Free Software Foundation
+// Copyright (C) 1997-2013 Free Software Foundation
 //
 // This file is part of GCC.
 //
@@ -31,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
@@ -44,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 6c64eb2..acbd832 100644
--- a/libstdc++-v3/testsuite/18_support/headers/exception/synopsis.cc
+++ b/libstdc++-v3/testsuite/18_support/headers/exception/synopsis.cc
@@ -1,6 +1,7 @@ 
 // { dg-do compile }
+// { dg-options "-std=gnu++11" }
 
-// Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+// Copyright (C) 2007-2013 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
@@ -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 f21dd1d..8ce8992 100644
--- a/libstdc++-v3/testsuite/18_support/headers/new/synopsis.cc
+++ b/libstdc++-v3/testsuite/18_support/headers/new/synopsis.cc
@@ -1,6 +1,7 @@ 
 // { dg-do compile }
+// { dg-options "-std=gnu++11" }
 
-// Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+// Copyright (C) 2007-2013 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
@@ -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;
+}