From: Tor Lillqvist Date: Wed, 31 Aug 2005 21:02:47 +0000 (+0000) Subject: Wrapping atexit() is a bad idea on Windows, where the EXE and each DLL X-Git-Url: http://git.openbox.org/?a=commitdiff_plain;h=130763338c798d9df52591439e8c9d5ffed4611b;p=dana%2Fcg-glib.git Wrapping atexit() is a bad idea on Windows, where the EXE and each DLL 2005-08-31 Tor Lillqvist * glib/gutils.h: Wrapping atexit() is a bad idea on Windows, where the EXE and each DLL have their own atexit function chains. #define g_atexit as atexit instead. This means it has a better chance of doing what the caller wants. For instance, gtkhtml calls g_atexit() registering a function in gtkhtml itself. This caused a crash when g_atexit() was implemented as a function in the GLib DLL. The gtkhtml DLL was already unloaded by the time the GLib DLL got unloaded. * glib/gutils.c: #undef the #define mentioned above, to also get a real g_atexit() into the DLL for backward compatibility. Document the Windows behaviour of g_atexit(), and document the varying ways atexit() can behave in the context of dynamically loaded modules on Unix. --- diff --git a/ChangeLog b/ChangeLog index f5c482a5..c6269aae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2005-08-31 Tor Lillqvist + + * glib/gutils.h: Wrapping atexit() is a bad idea on Windows, where + the EXE and each DLL have their own atexit function chains. + + #define g_atexit as atexit instead. This means it has a + better chance of doing what the caller wants. For instance, + gtkhtml calls g_atexit() registering a function in gtkhtml + itself. This caused a crash when g_atexit() was implemented as a + function in the GLib DLL. The gtkhtml DLL was already unloaded by + the time the GLib DLL got unloaded. + + * glib/gutils.c: #undef the #define mentioned above, to also get a + real g_atexit() into the DLL for backward compatibility. Document + the Windows behaviour of g_atexit(), and document the varying ways + atexit() can behave in the context of dynamically loaded modules + on Unix. + 2005-08-31 Matthias Clasen * glib/glib.symbols: diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index f5c482a5..c6269aae 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,21 @@ +2005-08-31 Tor Lillqvist + + * glib/gutils.h: Wrapping atexit() is a bad idea on Windows, where + the EXE and each DLL have their own atexit function chains. + + #define g_atexit as atexit instead. This means it has a + better chance of doing what the caller wants. For instance, + gtkhtml calls g_atexit() registering a function in gtkhtml + itself. This caused a crash when g_atexit() was implemented as a + function in the GLib DLL. The gtkhtml DLL was already unloaded by + the time the GLib DLL got unloaded. + + * glib/gutils.c: #undef the #define mentioned above, to also get a + real g_atexit() into the DLL for backward compatibility. Document + the Windows behaviour of g_atexit(), and document the varying ways + atexit() can behave in the context of dynamically loaded modules + on Unix. + 2005-08-31 Matthias Clasen * glib/glib.symbols: diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index f5c482a5..c6269aae 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,21 @@ +2005-08-31 Tor Lillqvist + + * glib/gutils.h: Wrapping atexit() is a bad idea on Windows, where + the EXE and each DLL have their own atexit function chains. + + #define g_atexit as atexit instead. This means it has a + better chance of doing what the caller wants. For instance, + gtkhtml calls g_atexit() registering a function in gtkhtml + itself. This caused a crash when g_atexit() was implemented as a + function in the GLib DLL. The gtkhtml DLL was already unloaded by + the time the GLib DLL got unloaded. + + * glib/gutils.c: #undef the #define mentioned above, to also get a + real g_atexit() into the DLL for backward compatibility. Document + the Windows behaviour of g_atexit(), and document the varying ways + atexit() can behave in the context of dynamically loaded modules + on Unix. + 2005-08-31 Matthias Clasen * glib/glib.symbols: diff --git a/glib/gutils.c b/glib/gutils.c index 8f7adc10..ced20103 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -208,11 +208,44 @@ g_memmove (gpointer dest, } #endif /* !HAVE_MEMMOVE && !HAVE_WORKING_BCOPY */ +#ifdef G_OS_WIN32 +#undef g_atexit +#endif + /** * g_atexit: * @func: the function to call on normal program termination. * * Specifies a function to be called at normal program termination. + * + * Since GLib 2.8.2, on Windows g_atexit() actually is a preprocessor + * macro that maps to a call to the atexit() function in the C + * library. This means that in case the code that calls g_atexit(), + * i.e. atexit(), is in a DLL, the function will be called when the + * DLL is detached from the program. This typically makes more sense + * than that the function is called when the GLib DLL is detached, + * which happened earlier when g_atexit() was a function in the GLib + * DLL. + * + * The behaviour of atexit() in the context of dynamically loaded + * modules is not formally specified and varies wildly. + * + * On POSIX systems, calling g_atexit() (or atexit()) in a dynamically + * loaded module which is unloaded before the program terminates might + * well cause a crash at program exit. + * + * Some POSIX systems implement atexit() like Windows, and have each + * dynamically loaded module maintain an own atexit chain that is + * called when the module is unloaded. + * + * On other POSIX systems, before a dynamically loaded module is + * unloaded, the registered atexit functions (if any) residing in that + * module are called, regardless where the code that registered them + * resided. This is presumably the most robust approach. + * + * As can be seen from the above, for portability it's best to avoid + * calling g_atexit() (or atexit()) except in the main executable of a + * program. */ void g_atexit (GVoidFunc func) diff --git a/glib/gutils.h b/glib/gutils.h index 3cb781f0..5350b9c1 100644 --- a/glib/gutils.h +++ b/glib/gutils.h @@ -229,6 +229,17 @@ typedef void (*GVoidFunc) (void); */ void g_atexit (GVoidFunc func); +#ifdef G_OS_WIN32 +/* It's a bad idea to wrap atexit() on Windows. If the GLib DLL calls + * atexit(), the function will be called when the GLib DLL is detached + * from the program, which is not what the caller wants. The caller + * wants the function to be called when it *itself* exits (or is + * detached, in case the caller, too, is a DLL). + */ +int atexit (void (*)(void)); +#define g_atexit(func) atexit(func) +#endif + /* Look for an executable in PATH, following execvp() rules */ gchar* g_find_program_in_path (const gchar *program);