From 32de2832db27db99f6c416b146684891034366c4 Mon Sep 17 00:00:00 2001 From: Mike Kestner Date: Tue, 6 Mar 2007 20:10:15 +0000 Subject: [PATCH] 2007-03-06 Mike Kestner * generator/Signal.cs : add try/catch blocks to native callback delegates so that exceptions are not propagated across the native boundary. Now raises GLib.ExceptionManager.UnhandledException. * glib/ExceptionManager.cs : new class with UnhandledException event and a static method to raise it. * glib/Signal.cs : wrap the generic EventHandler callback delegate with try/catch blocks and raise the UnhandledException event. svn path=/trunk/gtk-sharp/; revision=73840 --- ChangeLog | 10 ++++ doc/Makefile.am | 9 ++- doc/en/GLib/ExceptionManager.xml | 46 ++++++++++++++ doc/en/GLib/UnhandledExceptionArgs.xml | 44 ++++++++++++++ doc/en/GLib/UnhandledExceptionHandler.xml | 22 +++++++ generator/Signal.cs | 60 ++++++++++++------- glib/ExceptionManager.cs | 73 +++++++++++++++++++++++ glib/Makefile.am | 1 + glib/Signal.cs | 16 +++-- 9 files changed, 251 insertions(+), 30 deletions(-) create mode 100644 doc/en/GLib/ExceptionManager.xml create mode 100644 doc/en/GLib/UnhandledExceptionArgs.xml create mode 100644 doc/en/GLib/UnhandledExceptionHandler.xml create mode 100644 glib/ExceptionManager.cs diff --git a/ChangeLog b/ChangeLog index e6221fe99..dd16c343e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2007-03-06 Mike Kestner + + * generator/Signal.cs : add try/catch blocks to native callback + delegates so that exceptions are not propagated across the native + boundary. Now raises GLib.ExceptionManager.UnhandledException. + * glib/ExceptionManager.cs : new class with UnhandledException + event and a static method to raise it. + * glib/Signal.cs : wrap the generic EventHandler callback delegate + with try/catch blocks and raise the UnhandledException event. + 2007-03-05 Mike Kestner * gtk/Application.custom : set prgname in Init methods so diff --git a/doc/Makefile.am b/doc/Makefile.am index 98904188d..750e62d62 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -17,7 +17,7 @@ ASSEMBLIES = \ UPDATE_ASSEMBLIES = $(addprefix -assembly:lib/, $(ASSEMBLIES)) -UPDATER = $(MONODOCER) -path:en $(UPDATE_ASSEMBLIES) +UPDATER = $(MONODOCER) -path:en -pretty $(UPDATE_ASSEMBLIES) if ENABLE_MONODOC SOURCESDIR=$(prefix)/lib/monodoc/sources @@ -36,11 +36,14 @@ gtk-sharp-docs.zip gtk-sharp-docs.tree: $(srcdir)/en/*/*.xml $(srcdir)/en/*.xml $(MDASSEMBLER) --ecma $(srcdir)/en -o gtk-sharp-docs get-assemblies: + echo "assumes gnome-sharp and gtk-sharp checkouts in same parent" mkdir -p lib cp $(top_builddir)/*/*.dll lib cp $(top_builddir)/*/*.dll.config lib - cp $(top_builddir)/gconf/*/*.dll lib - cp $(top_builddir)/gconf/*/*.dll.config lib + cp $(top_builddir)/../gnome-sharp/*/*.dll lib + cp $(top_builddir)/../gnome-sharp/*/*.dll.config lib + cp $(top_builddir)/../gnome-sharp/gconf/*/*.dll lib + cp $(top_builddir)/../gnome-sharp/gconf/*/*.dll.config lib update: get-assemblies $(UPDATER) diff --git a/doc/en/GLib/ExceptionManager.xml b/doc/en/GLib/ExceptionManager.xml new file mode 100644 index 000000000..8d8787388 --- /dev/null +++ b/doc/en/GLib/ExceptionManager.xml @@ -0,0 +1,46 @@ + + + + glib-sharp + 2.10.0.0 + + + System.Object + + + + + + Method + + System.Void + + + + + + + Exception. + If , the exception terminates the application. + Raise Unhandled Exception method. + This method is generally only useful to language bindings. If is set, or a user event handler requests application exit, this method does not return. + + + + + Event + + GLib.UnhandledExceptionHandler + + + UnhandledException event. + Attach a delegate to this event to receive notification of Exceptions throw within managed callback delegates. If the contain information regarding whether the Exception is terminal and can be used to request termination of the application via the property. + + + + + Exception management class. + + + + diff --git a/doc/en/GLib/UnhandledExceptionArgs.xml b/doc/en/GLib/UnhandledExceptionArgs.xml new file mode 100644 index 000000000..5a5ae2156 --- /dev/null +++ b/doc/en/GLib/UnhandledExceptionArgs.xml @@ -0,0 +1,44 @@ + + + + glib-sharp + 2.10.0.0 + + + System.UnhandledExceptionEventArgs + + + + + + Constructor + + + + + + Exception. + If , the application is terminating. + Public constructor. + + + + + + Property + + System.Boolean + + + ExitApplication property. + If , the application will exit. + Indicates if an application wants to exit after event propagation is complete. + + + + + UnhandledExceptionArgs event arguments. + Event arguments for events. + + + diff --git a/doc/en/GLib/UnhandledExceptionHandler.xml b/doc/en/GLib/UnhandledExceptionHandler.xml new file mode 100644 index 000000000..193d6e28e --- /dev/null +++ b/doc/en/GLib/UnhandledExceptionHandler.xml @@ -0,0 +1,22 @@ + + + + glib-sharp + 2.10.0.0 + + + System.Delegate + + + + + + System.Void + + + Event arguments. + Reports unhandled exceptions. + Attach to event to receive notification of exceptions in managed callback delegates. + + + diff --git a/generator/Signal.cs b/generator/Signal.cs index d2580019b..1dffdcc70 100644 --- a/generator/Signal.cs +++ b/generator/Signal.cs @@ -199,42 +199,58 @@ namespace GtkSharp.Generation { sw.WriteLine (); sw.WriteLine ("\t\tstatic " + retval.ToNativeType + " " + CallbackName + " (" + CallbackSig + ")"); sw.WriteLine("\t\t{"); - sw.WriteLine("\t\t\tGLib.Signal sig = ((GCHandle) gch).Target as GLib.Signal;"); - sw.WriteLine("\t\t\tif (sig == null)"); - sw.WriteLine("\t\t\t\tthrow new Exception(\"Unknown signal GC handle received \" + gch);"); - sw.WriteLine(); sw.WriteLine("\t\t\t{0} args = new {0} ();", EventArgsQualifiedName); + sw.WriteLine("\t\t\ttry {"); + sw.WriteLine("\t\t\t\tGLib.Signal sig = ((GCHandle) gch).Target as GLib.Signal;"); + sw.WriteLine("\t\t\t\tif (sig == null)"); + sw.WriteLine("\t\t\t\t\tthrow new Exception(\"Unknown signal GC handle received \" + gch);"); + sw.WriteLine(); if (parms.Count > 1) - sw.WriteLine("\t\t\targs.Args = new object[" + (parms.Count - 1) + "];"); + sw.WriteLine("\t\t\t\targs.Args = new object[" + (parms.Count - 1) + "];"); string finish = ""; for (int idx = 1; idx < parms.Count; idx++) { Parameter p = parms [idx]; IGeneratable igen = p.Generatable; if (p.PassAs != "out") { if (igen is ManualGen) { - sw.WriteLine("\t\t\tif (arg{0} == IntPtr.Zero)", idx); - sw.WriteLine("\t\t\t\targs.Args[{0}] = null;", idx - 1); - sw.WriteLine("\t\t\telse {"); - sw.WriteLine("\t\t\t\targs.Args[" + (idx - 1) + "] = " + p.FromNative ("arg" + idx) + ";"); - sw.WriteLine("\t\t\t}"); + sw.WriteLine("\t\t\t\tif (arg{0} == IntPtr.Zero)", idx); + sw.WriteLine("\t\t\t\t\targs.Args[{0}] = null;", idx - 1); + sw.WriteLine("\t\t\t\telse {"); + sw.WriteLine("\t\t\t\t\targs.Args[" + (idx - 1) + "] = " + p.FromNative ("arg" + idx) + ";"); + sw.WriteLine("\t\t\t\t}"); } else - sw.WriteLine("\t\t\targs.Args[" + (idx - 1) + "] = " + p.FromNative ("arg" + idx) + ";"); + sw.WriteLine("\t\t\t\targs.Args[" + (idx - 1) + "] = " + p.FromNative ("arg" + idx) + ";"); } if (p.PassAs != "") - finish += "\t\t\targ" + idx + " = " + igen.ToNativeReturn ("((" + p.CSType + ")args.Args[" + (idx - 1) + "])") + ";\n"; + finish += "\t\t\t\targ" + idx + " = " + igen.ToNativeReturn ("((" + p.CSType + ")args.Args[" + (idx - 1) + "])") + ";\n"; } - sw.WriteLine("\t\t\t{0} handler = ({0}) sig.Handler;", EventHandlerQualifiedName); - sw.WriteLine("\t\t\thandler (GLib.Object.GetObject (arg0), args);"); - sw.WriteLine (finish); - if (!IsVoid) { - sw.WriteLine ("\t\t\tif (args.RetVal == null)"); - if (retval.CSType == "bool") - sw.WriteLine ("\t\t\t\treturn false;"); - else - sw.WriteLine ("\t\t\t\tthrow new Exception(\"args.RetVal unset in callback\");"); + sw.WriteLine("\t\t\t\t{0} handler = ({0}) sig.Handler;", EventHandlerQualifiedName); + sw.WriteLine("\t\t\t\thandler (GLib.Object.GetObject (arg0), args);"); + sw.WriteLine("\t\t\t} catch (Exception e) {"); + sw.WriteLine("\t\t\t\tGLib.ExceptionManager.RaiseUnhandledException (e, false);"); + sw.WriteLine("\t\t\t}"); - sw.WriteLine("\t\t\treturn " + table.ToNativeReturn (retval.CType, "((" + retval.CSType + ")args.RetVal)") + ";"); + if (IsVoid && finish.Length == 0) { + sw.WriteLine("\t\t}\n"); + return; } + + sw.WriteLine("\n\t\t\ttry {"); + sw.Write (finish); + if (!IsVoid) { + if (retval.CSType == "bool") { + sw.WriteLine ("\t\t\t\tif (args.RetVal == null)"); + sw.WriteLine ("\t\t\t\t\treturn false;"); + } + sw.WriteLine("\t\t\t\treturn " + table.ToNativeReturn (retval.CType, "((" + retval.CSType + ")args.RetVal)") + ";"); + } + sw.WriteLine("\t\t\t} catch (Exception) {"); + sw.WriteLine ("\t\t\t\tException ex = new Exception (\"args.RetVal or 'out' property unset or set to incorrect type in " + EventHandlerQualifiedName + " callback\");"); + sw.WriteLine("\t\t\t\tGLib.ExceptionManager.RaiseUnhandledException (ex, true);"); + + sw.WriteLine ("\t\t\t\t// NOTREACHED: above call doesn't return."); + sw.WriteLine ("\t\t\t\tthrow ex;"); + sw.WriteLine("\t\t\t}"); sw.WriteLine("\t\t}"); sw.WriteLine(); } diff --git a/glib/ExceptionManager.cs b/glib/ExceptionManager.cs new file mode 100644 index 000000000..d275a9f79 --- /dev/null +++ b/glib/ExceptionManager.cs @@ -0,0 +1,73 @@ +// GLib.Application.cs - static Application class +// +// Authors: Mike Kestner +// +// Copyright (c) 2007 Novell, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the Lesser GNU General +// Public License as published by the Free Software Foundation. +// +// This program 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + + +namespace GLib { + + using System; + + public delegate void UnhandledExceptionHandler (UnhandledExceptionArgs args); + + public class UnhandledExceptionArgs : System.UnhandledExceptionEventArgs { + + bool exit_app = false; + + public UnhandledExceptionArgs (Exception e, bool is_terminal) : base (e, is_terminal) {} + + public bool ExitApplication { + get { + return exit_app; + } + set { + if (value) + exit_app = value; + } + } + } + + public class ExceptionManager { + + + private ExceptionManager () {} + + public static event UnhandledExceptionHandler UnhandledException; + + public static void RaiseUnhandledException (Exception e, bool is_terminal) + { + if (UnhandledException == null) { + Console.Error.WriteLine ("Exception in Gtk# callback delegate"); + Console.Error.WriteLine (" Note: Applications can use GLib.ExceptionManager.UnhandledException to handle the exception."); + Console.Error.WriteLine (e); + Environment.Exit (1); + } + + UnhandledExceptionArgs args = new UnhandledExceptionArgs (e, is_terminal); + try { + UnhandledException (args); + } catch (Exception ex) { + Console.Error.WriteLine (ex); + Environment.Exit (1); + } + + if (is_terminal || args.ExitApplication) + Environment.Exit (1); + } + } +} diff --git a/glib/Makefile.am b/glib/Makefile.am index ef41307c2..eac05d5e5 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -25,6 +25,7 @@ sources = \ DelegateWrapper.cs \ DestroyNotify.cs \ EnumWrapper.cs \ + ExceptionManager.cs \ FileUtils.cs \ GException.cs \ GString.cs \ diff --git a/glib/Signal.cs b/glib/Signal.cs index daa61beca..2e7d6a58b 100644 --- a/glib/Signal.cs +++ b/glib/Signal.cs @@ -173,12 +173,18 @@ namespace GLib { static void voidObjectCallback (IntPtr handle, IntPtr gch) { - Signal sig = ((GCHandle) gch).Target as Signal; - if (sig == null) - throw new Exception ("Unknown signal class GC handle received."); + try { + Signal sig = ((GCHandle) gch).Target as Signal; + if (sig == null) { + ExceptionManager.RaiseUnhandledException (new Exception ("Unknown signal class GC handle received."), false); + return; + } - EventHandler handler = (EventHandler) sig.Handler; - handler (Object.GetObject (handle), EventArgs.Empty); + EventHandler handler = (EventHandler) sig.Handler; + handler (Object.GetObject (handle), EventArgs.Empty); + } catch (Exception e) { + ExceptionManager.RaiseUnhandledException (e, false); + } } static voidObjectDelegate event_handler_delegate;