2 /* $Id: exceptionhandler.cc 291 2006-05-12 08:08:45Z murrayc $ */
6 * Copyright 2002 The gtkmm Development Team
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <glibmmconfig.h>
28 #include <glibmm/error.h>
29 #include <glibmm/exceptionhandler.h>
30 #include <glibmm/thread.h>
32 GLIBMM_USING_STD(exception)
33 GLIBMM_USING_STD(list)
35 #ifdef GLIBMM_EXCEPTIONS_ENABLED
40 typedef sigc::signal<void> HandlerList;
42 // Each thread has its own list of exception handlers
43 // to avoid thread synchronization problems.
44 static Glib::StaticPrivate<HandlerList> thread_specific_handler_list = GLIBMM_STATIC_PRIVATE_INIT;
47 static void glibmm_exception_warning(const GError* error)
52 "unhandled exception (type Glib::Error) in signal handler:\n"
56 g_quark_to_string(error->domain), error->code,
57 (error->message) ? error->message : "(null)");
60 static void glibmm_unexpected_exception()
64 throw; // re-throw current exception
66 catch(const Glib::Error& error)
68 // Access the GError directly, to avoid possible exceptions from C++ code.
69 glibmm_exception_warning(error.gobj());
71 // For most failures that cause a Glib::Error exception, aborting the
72 // program seems too harsh. Instead, give control back to the main loop.
75 catch(const std::exception& except)
78 "unhandled exception (type std::exception) in signal handler:\n"
79 "what: %s\n", except.what());
83 g_error("\nunhandled exception (type unknown) in signal handler\n");
87 } // anonymous namespace
93 sigc::connection add_exception_handler(const sigc::slot<void>& slot)
95 HandlerList* handler_list = thread_specific_handler_list.get();
99 handler_list = new HandlerList();
100 thread_specific_handler_list.set(handler_list);
103 handler_list->slots().push_front(slot);
104 return handler_list->slots().begin();
108 void exception_handlers_invoke() throw()
110 // This function will be called from our GLib signal handler proxies
111 // if an exception has been caught. It's not possible to throw C++
112 // exceptions through C signal handlers. To handle this situation, the
113 // programmer can install slots to global Reusable Exception Handlers.
115 // A handler has to re-throw the current exception in a try block, and then
116 // catch the exceptions it knows about. Any unknown exceptions should just
117 // fall through, i.e. the handler must not do catch(...).
119 // We now invoke each of the installed slots until the exception has been
120 // handled. If there are no more handlers in the list and the exception
121 // is still unhandled, call glibmm_unexpected_exception().
123 if(HandlerList *const handler_list = thread_specific_handler_list.get())
125 HandlerList::iterator pslot = handler_list->slots().begin();
127 while(pslot != handler_list->slots().end())
129 // Calling an empty slot would mean ignoring the exception,
130 // thus we have to check for dead slots explicitly.
133 pslot = handler_list->slots().erase(pslot);
137 // Call the Reusable Exception Handler, which should re-throw
138 // the exception that's currently on the stack.
143 catch(...) // unhandled, try next slot
149 // The exception has either been handled or ignored.
150 // Give control back to the GLib main loop.
155 // Critical: The exception is still unhandled.
156 glibmm_unexpected_exception();
161 #endif //GLIBMM_EXCEPTIONS_ENABLED