gtk 0.12.5.4 → 0.12.5.5
raw patch · 3 files changed
+203/−206 lines, 3 files
Files
- Graphics/UI/Gtk/General/hsgthread.c +201/−0
- Graphics/UI/Gtk/General/hsgthread.cpp +0/−204
- gtk.cabal +2/−2
+ Graphics/UI/Gtk/General/hsgthread.c view
@@ -0,0 +1,201 @@+/* We would use the g_thread_supported macro here, but unfortunately on+ * windows GHCi's dynamic linker cannot cope with references to global+ * variables imported from dlls.+ *+ * So instead of asking glib if we (or indeed) anyone else has initialised+ * the glib gthread system, we keep track of it ourselves. We still have to+ * do it in C land so the state survives :reload in GHCi. So there is the+ * danger in a mixed language program, of someone else initialising the+ * glib thread system and us not being aware of it. :-(+ *+ * Besides the interaction with ghci, we provide a variant of g_object_unref+ * that is used in all objects of Gtk+ and those libraries that build on Gtk+.+ * This variant enqueues the object to be finalized and adds an idle handler+ * into the main loop of Gtk+ that will call the actual finalizers on the+ * enqueued objects. The aim is to ensure that finalizers for objects that+ * may hold Xlib or Win32 resources are only run from the thread that runs the+ * main Gtk+ loop. If this is not ensured then bad things happen at least on+ * Win32 since that API is making use of thread-local storage that is not+ * present if the finalizers, that are run by the GC in a different thread,+ * call back into Win32 without this thread-local storage.+ *+ * Also g_static_mutex_lock and g_static_mutex_unlock cause linking problems+ * in ghci on Windows 7 (namely: HSgtk-0.10.5.o: unknown symbol+ * `__imp__g_threads_got_initialized'), so we use a Win32 critical section+ * instead.+ */++#define DEFINED_LPTYPELIB+#define DEFINDE_LPTYPEINFO+#define DEFINED_LPTYPECOMP+#define DEFINE_LPCREATETYPEINFO+#define DEFINED_LPDISPATCH++#include <glib.h>+#include <gdk/gdk.h>+#include "hsgthread.h"++#if defined( WIN32 )+#include <windows.h>+#include <stdlib.h>+#include <fcntl.h>+#endif++#undef DEBUG++static int threads_initialised = 0;+#if defined( WIN32 )+static CRITICAL_SECTION gtk2hs_finalizer_mutex;+#else+static GStaticMutex gtk2hs_finalizer_mutex;+#endif+static GSource* gtk2hs_finalizer_source;+static guint gtk2hs_finalizer_id;+static GArray* gtk2hs_finalizers;++gboolean gtk2hs_run_finalizers(gpointer data);++/* Initialize the default _fmode on WIN32. */+void gtk2hs_initialise (void) {+#if defined( WIN32 ) && defined( GTK2HS_SET_FMODE_BINARY )+ /* Some Windows GTK binraries (current Fedora MinGW ones) do */+ /* not open files in binary mode. This is a work around. */+ _fmode = _O_BINARY;+#endif+}++/* Initialize the threads system of Gdk and Gtk. */+void gtk2hs_threads_initialise (void) {++#ifdef DEBUG+ printf("gtk2hs_threads_initialise: threads_initialised=%i, g_thread_get_initialized=%i\n",+ threads_initialised, g_thread_get_initialized());+#endif++ if (!threads_initialised) {+ threads_initialised = 1;+#if defined( WIN32 )+ InitializeCriticalSection(>k2hs_finalizer_mutex);+#else+ g_static_mutex_init(>k2hs_finalizer_mutex);+#endif+ g_thread_init(NULL);+ gdk_threads_init();++ /* from here onwards, the Gdk lock is held */+ gdk_threads_enter();++ }+}++/* Free an object within the Gtk2Hs lock. */+void gtk2hs_g_object_unref_from_mainloop(gpointer object) {++ int mutex_locked = 0;+ if (threads_initialised) {+#ifdef DEBUG+ printf("acquiring lock to add a %s object at %lx\n",+ g_type_name(G_OBJECT_TYPE(object)), (unsigned long) object);+ printf("value of lock function is %lx\n",+ (unsigned long) g_thread_functions_for_glib_use.mutex_lock);+#endif+#if defined( WIN32 )+ EnterCriticalSection(>k2hs_finalizer_mutex);+#else+ g_static_mutex_lock(>k2hs_finalizer_mutex);+#endif+ mutex_locked = 1;+ }++#ifdef DEBUG+ if (mutex_locked) printf("within mutex: ");+ printf("adding finalizer to a %s object!\n", g_type_name(G_OBJECT_TYPE(object)));+#endif++ /* Ensure that the idle handler is still installed and that+ the array of objects that are to be finalized exists. */+ if (gtk2hs_finalizer_id==0) {++ if (gtk2hs_finalizers == NULL)+ gtk2hs_finalizers = g_array_new(0, 0, sizeof(gpointer));+#ifdef DEBUG+ printf("creating finalizer list.\n");+#endif++ if (gtk2hs_finalizer_source != NULL) {+#ifdef DEBUG+ printf("re-initializing finalizer source.\n");+#endif+ g_source_destroy(gtk2hs_finalizer_source);+ g_source_unref(gtk2hs_finalizer_source);+ };++ gtk2hs_finalizer_source = g_idle_source_new();+ g_source_set_callback(gtk2hs_finalizer_source, >k2hs_run_finalizers, 0, 0);+ gtk2hs_finalizer_id = g_source_attach(gtk2hs_finalizer_source, NULL);++ };++ /* Add the object to the list. */+ g_array_append_val(gtk2hs_finalizers, object);++ if (mutex_locked) {+#ifdef DEBUG+ printf("releasing lock to add a %s object at %lx\n",+ g_type_name(G_OBJECT_TYPE(object)), (unsigned long) object);+#endif+#if defined( WIN32 )+ LeaveCriticalSection(>k2hs_finalizer_mutex);+#else+ g_static_mutex_unlock(>k2hs_finalizer_mutex);+#endif+ }+}++/* Run the finalizers that have been accumulated. */+gboolean gtk2hs_run_finalizers(gpointer data) {+ gint index;+ g_assert(gtk2hs_finalizers!=NULL);++ gdk_threads_enter();+ + int mutex_locked = 0;+ if (threads_initialised) {+#ifdef DEBUG+ printf("acquiring lock to kill objects\n");+#endif+#if defined( WIN32 )+ EnterCriticalSection(>k2hs_finalizer_mutex);+#else+ g_static_mutex_lock(>k2hs_finalizer_mutex);+#endif+ mutex_locked = 1;+ }++#ifdef DEBUG+ printf("running %i finalizers!\n", gtk2hs_finalizers->len);+#endif++ for (index = 0; index < gtk2hs_finalizers->len; index++)+ g_object_unref(g_array_index (gtk2hs_finalizers, GObject*, index));++ g_array_set_size(gtk2hs_finalizers, 0);++ gtk2hs_finalizer_id = 0;++ if (mutex_locked) {+#ifdef DEBUG+ printf("releasing lock to kill objects\n");+#endif+#if defined( WIN32 )+ LeaveCriticalSection(>k2hs_finalizer_mutex);+#else+ g_static_mutex_unlock(>k2hs_finalizer_mutex);+#endif+ }++ gdk_threads_leave();++ return FALSE;+}+
− Graphics/UI/Gtk/General/hsgthread.cpp
@@ -1,204 +0,0 @@-/* We would use the g_thread_supported macro here, but unfortunately on- * windows GHCi's dynamic linker cannot cope with references to global- * variables imported from dlls.- *- * So instead of asking glib if we (or indeed) anyone else has initialised- * the glib gthread system, we keep track of it ourselves. We still have to- * do it in C land so the state survives :reload in GHCi. So there is the- * danger in a mixed language program, of someone else initialising the- * glib thread system and us not being aware of it. :-(- *- * Besides the interaction with ghci, we provide a variant of g_object_unref- * that is used in all objects of Gtk+ and those libraries that build on Gtk+.- * This variant enqueues the object to be finalized and adds an idle handler- * into the main loop of Gtk+ that will call the actual finalizers on the- * enqueued objects. The aim is to ensure that finalizers for objects that- * may hold Xlib or Win32 resources are only run from the thread that runs the- * main Gtk+ loop. If this is not ensured then bad things happen at least on- * Win32 since that API is making use of thread-local storage that is not- * present if the finalizers, that are run by the GC in a different thread,- * call back into Win32 without this thread-local storage.- *- * Also g_static_mutex_lock and g_static_mutex_unlock cause linking problems- * in ghci on Windows 7 (namely: HSgtk-0.10.5.o: unknown symbol- * `__imp__g_threads_got_initialized'), so we use a Win32 critical section- * instead.- */--extern "C" {--#define DEFINED_LPTYPELIB-#define DEFINDE_LPTYPEINFO-#define DEFINED_LPTYPECOMP-#define DEFINE_LPCREATETYPEINFO-#define DEFINED_LPDISPATCH--#include <glib.h>-#include <gdk/gdk.h>-#include "hsgthread.h"--#if defined( WIN32 )-#include <windows.h>-#include <stdlib.h>-#include <fcntl.h>-#endif--#undef DEBUG--static int threads_initialised = 0;-#if defined( WIN32 )-static CRITICAL_SECTION gtk2hs_finalizer_mutex;-#else-static GStaticMutex gtk2hs_finalizer_mutex;-#endif-static GSource* gtk2hs_finalizer_source;-static guint gtk2hs_finalizer_id;-static GArray* gtk2hs_finalizers;--gboolean gtk2hs_run_finalizers(gpointer data);--/* Initialize the default _fmode on WIN32. */-void gtk2hs_initialise (void) {-#if defined( WIN32 ) && defined( GTK2HS_SET_FMODE_BINARY )- /* Some Windows GTK binraries (current Fedora MinGW ones) do */- /* not open files in binary mode. This is a work around. */- _fmode = _O_BINARY;-#endif-}--/* Initialize the threads system of Gdk and Gtk. */-void gtk2hs_threads_initialise (void) {--#ifdef DEBUG- printf("gtk2hs_threads_initialise: threads_initialised=%i, g_thread_get_initialized=%i\n",- threads_initialised, g_thread_get_initialized());-#endif-- if (!threads_initialised) {- threads_initialised = 1;-#if defined( WIN32 )- InitializeCriticalSection(>k2hs_finalizer_mutex);-#else- g_static_mutex_init(>k2hs_finalizer_mutex);-#endif- g_thread_init(NULL);- gdk_threads_init();-- /* from here onwards, the Gdk lock is held */- gdk_threads_enter();-- }-}--/* Free an object within the Gtk2Hs lock. */-void gtk2hs_g_object_unref_from_mainloop(gpointer object) {-- int mutex_locked = 0;- if (threads_initialised) {-#ifdef DEBUG- printf("acquiring lock to add a %s object at %lx\n",- g_type_name(G_OBJECT_TYPE(object)), (unsigned long) object);- printf("value of lock function is %lx\n",- (unsigned long) g_thread_functions_for_glib_use.mutex_lock);-#endif-#if defined( WIN32 )- EnterCriticalSection(>k2hs_finalizer_mutex);-#else- g_static_mutex_lock(>k2hs_finalizer_mutex);-#endif- mutex_locked = 1;- }--#ifdef DEBUG- if (mutex_locked) printf("within mutex: ");- printf("adding finalizer to a %s object!\n", g_type_name(G_OBJECT_TYPE(object)));-#endif-- /* Ensure that the idle handler is still installed and that- the array of objects that are to be finalized exists. */- if (gtk2hs_finalizer_id==0) {-- if (gtk2hs_finalizers == NULL)- gtk2hs_finalizers = g_array_new(0, 0, sizeof(gpointer));-#ifdef DEBUG- printf("creating finalizer list.\n");-#endif-- if (gtk2hs_finalizer_source != NULL) {-#ifdef DEBUG- printf("re-initializing finalizer source.\n");-#endif- g_source_destroy(gtk2hs_finalizer_source);- g_source_unref(gtk2hs_finalizer_source);- };-- gtk2hs_finalizer_source = g_idle_source_new();- g_source_set_callback(gtk2hs_finalizer_source, >k2hs_run_finalizers, 0, 0);- gtk2hs_finalizer_id = g_source_attach(gtk2hs_finalizer_source, NULL);-- };-- /* Add the object to the list. */- g_array_append_val(gtk2hs_finalizers, object);-- if (mutex_locked) {-#ifdef DEBUG- printf("releasing lock to add a %s object at %lx\n",- g_type_name(G_OBJECT_TYPE(object)), (unsigned long) object);-#endif-#if defined( WIN32 )- LeaveCriticalSection(>k2hs_finalizer_mutex);-#else- g_static_mutex_unlock(>k2hs_finalizer_mutex);-#endif- }-}--/* Run the finalizers that have been accumulated. */-gboolean gtk2hs_run_finalizers(gpointer data) {- gint index;- g_assert(gtk2hs_finalizers!=NULL);-- gdk_threads_enter();- - int mutex_locked = 0;- if (threads_initialised) {-#ifdef DEBUG- printf("acquiring lock to kill objects\n");-#endif-#if defined( WIN32 )- EnterCriticalSection(>k2hs_finalizer_mutex);-#else- g_static_mutex_lock(>k2hs_finalizer_mutex);-#endif- mutex_locked = 1;- }--#ifdef DEBUG- printf("running %i finalizers!\n", gtk2hs_finalizers->len);-#endif-- for (index = 0; index < gtk2hs_finalizers->len; index++)- g_object_unref(g_array_index (gtk2hs_finalizers, GObject*, index));-- g_array_set_size(gtk2hs_finalizers, 0);-- gtk2hs_finalizer_id = 0;-- if (mutex_locked) {-#ifdef DEBUG- printf("releasing lock to kill objects\n");-#endif-#if defined( WIN32 )- LeaveCriticalSection(>k2hs_finalizer_mutex);-#else- g_static_mutex_unlock(>k2hs_finalizer_mutex);-#endif- }-- gdk_threads_leave();-- return FALSE;-}--}
gtk.cabal view
@@ -1,5 +1,5 @@ Name: gtk-Version: 0.12.5.4+Version: 0.12.5.5 License: LGPL-2.1 License-file: COPYING Copyright: (c) 2001-2010 The Gtk2Hs Team@@ -362,7 +362,7 @@ extensions: ForeignFunctionInterface c-sources: Graphics/UI/Gtk/ModelView/Gtk2HsStore.c- Graphics/UI/Gtk/General/hsgthread.cpp+ Graphics/UI/Gtk/General/hsgthread.c -- Due to http://hackage.haskell.org/trac/ghc/ticket/781 -- we need to compile the hsgthread.c module with -fPIC to ensure that a global -- variable in GLib that holds the address for the mutex lock and unlock functions