Hi Simon,

On Nov 2, 2009, at 16:14, Simon Marlow wrote:

> Dear gtk2hs developers,
>
> What's the current state of gtk2hs with respect to the threaded RTS  
> and
> C finalizers?  Should we expect 0.10.1 to work?

Well, everything's brittle since ghc's garbage collector went  
concurrent.

The story is as follows:

Calling g_object_unref, the principal finalizer we attach to any  
ForeignPtr, will decrement the reference count and immediately  
finalize an object if this counter is zero. This can pose problems in  
three ways:

a) Storing any callback or other memory region in the GObject will  
install a Haskell finalizer (freeStablePtr or free function pointer)  
that is called when the GObject is finalized. After our last long  
conversation about the new concurrent GC, we changed Gtk2Hs so that  
it passes the addresses of the C functions of the ghc runtime as  
finalizers, so Haskell is not called and all is well. (I hope I  
recall this correctly.)

b) It is possible to add a Haskell finalizer function to a GObject.  
Since these Haskell finalizers are called from the GC, they have to  
re-enter the Haskell RTS which will bomb. Solution: remove the  
possibility to add such a finalizer function.

c) Xlib is not thread-safe but has no thread-local storage so it can  
be called from several threads if they don't access Xlib at the same  
time. Win32 API is not thread-safe *and* uses thread-local storage so  
that it is impossible to call it from more than one thread.

Since a GObject may contain X or Win32 ressources, these might be  
freed from a thread calling g_object_unref. Thus, if the ghc GC calls  
g_object_unref from several threads, it is inevitable that Xlib or  
Win32 is called from several threads. This is what you observe below  
when get an Xlib error. I have a patched version of Gtk2Hs lying  
around that replaces the finalizer 'g_object_unref' with a wrapper  
function that first acquires a global Gtk lock before calling  
g_object_unref. This may severely stall the GC but works well for  
Xlib. On Windows, this still doesn't work. Nor does it solve b).

The only solution I can think of is to insert all GObjects that are  
finalized during GC into a list and to finialize all these objects by  
calling a function (say 'runFinalizers') from the main Gtk thread.  
This function can be called from Haskell in a 'safe' way so that  
callbacks to Haskell are no problem.

The problem that remains is how to ensure that 'runFinalizers' is  
called after each GC. When using Gtk+, I could add the 'runFinalizer'  
function to the main loop of Gtk. Thus, when the GUI resumes after a  
GC, it will finalize all objects that were dead during the last GC.

However, if we ever split off Cairo or Pango (two modules that may be  
used independently of the GUI stuff) then there is no more Gtk+ main  
loop. Thus, we would need another way to run the 'runFinalizers' C  
function.

One idea I had to this end is a hook into the ghc runtime: We need to  
install a C pointer to a function that is called at the end of each  
GC. Additionally, we need to ensure that this function is called by  
one specific OS thread. Alternatively, we would need a Haskell-side  
hook to install a OS-thread bound Haskell function that, in turn,  
calls the C function. I talked to Duncan about this but he was  
skeptical that GHC headquarters would be happy about this.

<rant>
In fact, the situation is a bit contradictory: As an application  
developer you are responsible to carefully call all your functions  
from an (OS-)bounded thread if your C library isn't thread-safe and  
then the GC comes along and calls concurrently with any number of OS  
threads into the C library to run the finalizers. This is not quite  
fair onto the programmer.
<rant/>

Another idea would be to have a new type of finalizers that takes a  
thread id and that the GC then guarantees to only run from the given  
thread id. This would push the burden into the GC implementation.

Any thoughts appreciated. With the current solution, I don't think  
there's a way for us to make Gtk2Hs thread-safe except for the hack  
of using the Gtk+ main loop to run finalizers.

Cheers,
Axel.



> As you may know, we're working on ThreadScope, a gtk2hs-based tool for
> parallel performance visualisation in GHC.  I recently switched to use
> the threaded RTS so that I could do some work while displaying a
> progress bar - I know there are ways to do this without -threaded,  
> but I
> thought -threaded would be the neatest way to do it, and eventually
> we'll want to have background threads doing things anyway.
>
> Now I have weird problems - usually hangs/deadlocks, but  
> occasionally I
> get an Xlib error.  Here's my latest hang, which is 100%  
> reproducible on
> exiting ThreadScope right now:
>
> (gdb) where
> #0  0x0000003c0aa0af19 in pthread_cond_wait@@GLIBC_2.3.2 () from
> /lib64/libpthread.so.0
> #1  0x00000000005b2c0e in waitCondition (pCond=0x1a43918,
> pMut=0x1a43948) at posix/OSThreads.c:65
> #2  0x00000000005d72d9 in waitForReturnCapability  
> (pCap=0x7ffffe1499f0,
> task=0x1a438e0) at Capability.c:445
> #3  0x00000000005a5934 in rts_lock () at RtsAPI.c:572
> #4  0x00000000004cf247 in SystemziGlibziGObject_d1wV ()
> #5  0x0000003c10cd8eed in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
> #6  0x0000003c0ba0d6a8 in g_object_unref () from /lib64/ 
> libgobject-2.0.so.0
> .... various stuff omitted ....
> #41 0x0000003c0ba0d632 in g_object_unref () from /lib64/ 
> libgobject-2.0.so.0
> #42 0x00000000005b20fd in runCFinalizer (fn=0x408968, ptr=0x1a69440,
> env=0x0, flag=0) at Weak.c:34
> #43 0x00000000005b216a in runAllCFinalizers (list=0x2afbacb5f060) at
> Weak.c:50
> #44 0x00000000005a8077 in hs_exit_ (wait_foreign=rtsFalse) at
> RtsStartup.c:413
> #45 0x00000000005a81a8 in shutdownHaskellAndExit (n=0) at  
> RtsStartup.c:557
> #46 0x00000000005a4c6a in real_main () at Main.c:144
> #47 0x00000000005a4ca4 in main (argc=5, argv=0x7ffffe14b338) at  
> Main.c:156
>
> So clearly g_object_unref is being called from a C finalizer, and it
> ends up calling back into Haskell via something in System.Glib.Object,
> this leads to a deadlock because the RTS is shutting down and can't  
> run
> any Haskell code.
>
> Any help appreciated.  In the meantime I'll probably go back to the
> single-threaded RTS.
>
> Cheers,
>       Simon
>
> ---------------------------------------------------------------------- 
> --------
> Come build with us! The BlackBerry(R) Developer Conference in SF, CA
> is the only developer event you need to attend this year. Jumpstart  
> your
> developing skills, take BlackBerry mobile applications to market  
> and stay
> ahead of the curve. Join us from November 9 - 12, 2009. Register now!
> http://p.sf.net/sfu/devconference
> _______________________________________________
> Gtk2hs-devel mailing list
> Gtk2hs-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/gtk2hs-devel


------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Gtk2hs-devel mailing list
Gtk2hs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/gtk2hs-devel

Reply via email to