From: Axel S. <si...@co...> - 2009-11-22 12:26:39
|
Sun Nov 22 07:08:04 EST 2009 Axel Simon <Axe...@en...> * Add finialization from the Gtk+ main loop. This patch adds a replaces the default destroy function for any GObject that is created in Gtk+ or any libraries that use Gtk+. These objects are now finalized using an idle handler that is executed by the Gtk+ main loop. By being executed by the main loop, the finalizers are run from the same thread as the main loop and, hence, the objects that hold Xlib or Win32 resources will now free these resources from the thread that normally calls into Xlib/Win32. This fixes a problem with the -threaded runtime of ghc in which finalization of objects could happen from other threads which would cause Xlib errors. hunk ./Makefile.am 796 - gtk/Graphics/UI/Gtk/General/Selection.chs.pp \ - gtk/Graphics/UI/Gtk/General/Drag.chs.pp \ - gtk/Graphics/UI/Gtk/General/DNDTypes.chs + gtk/Graphics/UI/Gtk/General/Selection.chs.pp \ + gtk/Graphics/UI/Gtk/General/Drag.chs.pp \ + gtk/Graphics/UI/Gtk/General/DNDTypes.chs \ + gtk/Graphics/UI/Gtk/General/Threading.hs + hunk ./Makefile.am 822 - gtk/Graphics/UI/Gtk/General/DNDTypes.hs + gtk/Graphics/UI/Gtk/General/DNDTypes.hs \ + gtk/Graphics/UI/Gtk/General/Threading.hs hunk ./Makefile.am 885 - --forward=*System.Glib.GObject) + --forward=*System.Glib.GObject --destructor=objectUnrefFromMainloop \ + --forward=Graphics.UI.Gtk.General.Threading ) hunk ./Makefile.am 1029 - --modname=Graphics.UI.Gtk.Glade.Types \ + --modname=Graphics.UI.Gtk.Glade.Types \ + --destructor=objectUnrefFromMainloop \ hunk ./Makefile.am 1165 + --destructor=objectUnrefFromMainloop \ hunk ./Makefile.am 1451 + --destructor=objectUnrefFromMainloop \ hunk ./Makefile.am 1593 + --destructor=objectUnrefFromMainloop \ hunk ./Makefile.am 1726 + --destructor=objectUnrefFromMainloop \ hunk ./Makefile.am 2115 + --destructor=objectUnrefFromMainloop \ addfile ./gtk/Graphics/UI/Gtk/General/Threading.hs hunk ./gtk/Graphics/UI/Gtk/General/Threading.hs 1 +-- -*-haskell-*- +-- GIMP Toolkit (GTK) General +-- +-- Author : Axel Simon +-- +-- Created: 9 May 2009 +-- +-- Copyright (C) 2009 Axel Simon +-- +-- This library is free software; you can redistribute it and/or +-- modify it under the terms of the GNU Lesser General Public +-- License as published by the Free Software Foundation; either +-- version 2.1 of the License, 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 +-- Lesser General Public License for more details. +-- +-- | +-- Maintainer : gtk...@li... +-- Stability : provisional +-- Portability : portable (depends on GHC) +-- +-- Support for the threaded RTS of ghc. +-- +module Graphics.UI.Gtk.General.Threading ( + objectUnrefFromMainloop + ) where + +import System.Glib.FFI + +foreign import ccall unsafe "hsgthread.h >k2hs_g_object_unref_from_mainloop" + objectUnrefFromMainloop :: FinalizerPtr a hunk ./gtk/Graphics/UI/Gtk/General/hsgthread.c 10 + * + * 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. hunk ./gtk/Graphics/UI/Gtk/General/hsgthread.c 23 +#include <glib.h> hunk ./gtk/Graphics/UI/Gtk/General/hsgthread.c 27 -static GStaticRecMutex gtk2hs_mutex; +#undef DEBUG hunk ./gtk/Graphics/UI/Gtk/General/hsgthread.c 29 -/* Lock the Gtk2Hs lock. */ -void gtk2hs_lock() { - g_static_rec_mutex_lock(>k2hs_mutex); -} +static GStaticMutex gtk2hs_finalizer_mutex; +static GSource* gtk2hs_finalizer_source; +static guint gtk2hs_finalizer_id; +static GArray* gtk2hs_finalizers; hunk ./gtk/Graphics/UI/Gtk/General/hsgthread.c 34 -/* Unlock the Gtk2Hs lock. */ -void gtk2hs_unlock() { - g_static_rec_mutex_unlock(>k2hs_mutex); -} +gboolean gtk2hs_run_finalizers(gpointer data); hunk ./gtk/Graphics/UI/Gtk/General/hsgthread.c 36 -/* Initialize the threads system of Gdk and Gtk. Furthermore, install the -Gtk2Hs specific lock and unlock functions. */ +/* Initialize the threads system of Gdk and Gtk. */ hunk ./gtk/Graphics/UI/Gtk/General/hsgthread.c 42 - gdk_threads_set_lock_functions((GCallback) >k2hs_lock, - (GCallback) >k2hs_unlock ); hunk ./gtk/Graphics/UI/Gtk/General/hsgthread.c 44 - g_static_rec_mutex_init(>k2hs_mutex); hunk ./gtk/Graphics/UI/Gtk/General/hsgthread.c 48 -void gtk2hs_g_object_unref_locked(gpointer object) { - g_static_rec_mutex_lock(>k2hs_mutex); - g_object_unref(object); - g_static_rec_mutex_unlock(>k2hs_mutex); +void gtk2hs_g_object_unref_from_mainloop(gpointer object) { + g_static_mutex_lock(>k2hs_finalizer_mutex); + +#ifdef DEBUG + printf("adding finalizer!\n"); +#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)); + + if (gtk2hs_finalizer_source != NULL) { + 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); + + g_static_mutex_unlock(>k2hs_finalizer_mutex); hunk ./gtk/Graphics/UI/Gtk/General/hsgthread.c 79 +/* Run the finalizers that have been accumulated. */ +gboolean gtk2hs_run_finalizers(gpointer data) { + gint index; + g_assert(gtk2hs_finalizers!=NULL); + + g_static_mutex_lock(>k2hs_finalizer_mutex); + +#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; + + g_static_mutex_unlock(>k2hs_finalizer_mutex); + + return FALSE; +} + + hunk ./gtk/Graphics/UI/Gtk/General/hsgthread.h 6 -/* Lock the Gtk2Hs lock. */ -void gtk2hs_lock(void); - -/* Unlock the Gtk2Hs lock. */ -void gtk2hs_unlock(void); - -/* Initialize the threads system of Gdk and Gtk. Furthermore, install the -Gtk2Hs specific lock and unlock functions. */ +/* Initialize the threads system of Gdk and Gtk. */ hunk ./gtk/Graphics/UI/Gtk/General/hsgthread.h 9 -/* Free an object within the Gtk2Hs lock. */ -void gtk2hs_g_object_unref_locked(gpointer object); +/* Free an object within the Gtk+ main loop. */ +void gtk2hs_g_object_unref_from_mainloop(gpointer object); |