On 10/11/2009 13:52, Axel Simon wrote:
> On Tue, 2009-11-10 at 13:13 +0000, Simon Marlow wrote:
>> On 04/11/2009 18:31, Axel Simon wrote:
>>
>>> I just realized that we haven't changed everything to use direct calls
>>> to C finalizers but to Haskell finalizers. I assume that this is because
>>> Haskell still got called from within the GC. If it is still called from
>>> within the GC, then some signals are being emitted as a result of
>>> finalizing an object. I probably need an example where this goes wrong.
>>> I don't know if it is possible to run the Haskell program in gdb and get
>>> a traceback of the C functions that called Haskell during GC. However,
>>> it might just be a very plain bug in that we bound a function as
>>> 'unsafe' when, in fact, it may trigger a callback to Haskell.
>>
>> Does the traceback in my original message give you enough information?
>> (reproduced at the end of this message)
>
> Well, you omitted 'various' stuff. I agree that something is calling
> back into C when it shouldn't. Are there any function names between
> frame 6 and 44 that would give me a clue where we've been negligent?

Ah yes, sorry.  Here's the full trace:

(gdb) where
#0  0x0000003c0aa0af19 in pthread_cond_wait@@GLIBC_2.3.2 () from 
/lib64/libpthread.so.0
#1  0x00000000005ac6e9 in waitCondition ()
#2  0x00000000005c67ab in waitForReturnCapability ()
#3  0x00000000005a3f17 in rts_lock ()
#4  0x00000000004ce397 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
#7  0x0000003c10ccebc7 in gtk_tree_view_remove_column () from 
/usr/lib64/libgtk-x11-2.0.so.0
#8  0x0000003c10cb749c in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#9  0x0000003c0ba0b62f in g_closure_invoke () from 
/lib64/libgobject-2.0.so.0
#10 0x0000003c0ba1faa3 in ?? () from /lib64/libgobject-2.0.so.0
#11 0x0000003c0ba20b9c in g_signal_emit_valist () from 
/lib64/libgobject-2.0.so.0
#12 0x0000003c0ba210e3 in g_signal_emit () from /lib64/libgobject-2.0.so.0
#13 0x0000003c10bb426a in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#14 0x0000003c10cfa6c3 in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#15 0x0000003c0ba0dad0 in g_object_run_dispose () from 
/lib64/libgobject-2.0.so.0
#16 0x0000003c10bb421a in gtk_object_destroy () from 
/usr/lib64/libgtk-x11-2.0.so.0
#17 0x0000003c10cf1be9 in gtk_widget_destroy () from 
/usr/lib64/libgtk-x11-2.0.so.0
#18 0x0000003c10a7a8b8 in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#19 0x0000003c10bfee1c in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#20 0x0000003c10ad0aa9 in gtk_container_foreach () from 
/usr/lib64/libgtk-x11-2.0.so.0
#21 0x0000003c10acf9af in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#22 0x0000003c10bfe5c2 in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#23 0x0000003c0ba0b62f in g_closure_invoke () from 
/lib64/libgobject-2.0.so.0
#24 0x0000003c0ba1faa3 in ?? () from /lib64/libgobject-2.0.so.0
#25 0x0000003c0ba20b9c in g_signal_emit_valist () from 
/lib64/libgobject-2.0.so.0
#26 0x0000003c0ba210e3 in g_signal_emit () from /lib64/libgobject-2.0.so.0
#27 0x0000003c10bb426a in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#28 0x0000003c10cfa6c3 in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#29 0x0000003c0ba0dad0 in g_object_run_dispose () from 
/lib64/libgobject-2.0.so.0
#30 0x0000003c10bb421a in gtk_object_destroy () from 
/usr/lib64/libgtk-x11-2.0.so.0
#31 0x0000003c10cf1be9 in gtk_widget_destroy () from 
/usr/lib64/libgtk-x11-2.0.so.0
#32 0x0000003c10a7f340 in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#33 0x0000003c10ad0aa9 in gtk_container_foreach () from 
/usr/lib64/libgtk-x11-2.0.so.0
#34 0x0000003c10acf9af in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#35 0x0000003c0ba0b6dd in g_closure_invoke () from 
/lib64/libgobject-2.0.so.0
#36 0x0000003c0ba1faa3 in ?? () from /lib64/libgobject-2.0.so.0
#37 0x0000003c0ba20b9c in g_signal_emit_valist () from 
/lib64/libgobject-2.0.so.0
#38 0x0000003c0ba210e3 in g_signal_emit () from /lib64/libgobject-2.0.so.0
#39 0x0000003c10bb426a in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#40 0x0000003c10cfa6c3 in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#41 0x0000003c0ba0d632 in g_object_unref () from /lib64/libgobject-2.0.so.0
#42 0x00000000005abdfd in runAllCFinalizers ()
#43 0x00000000005a5ca8 in hs_exit_ ()
#44 0x00000000005a5e1a in shutdownHaskellAndExit ()
#45 0x00000000005a3cd8 in real_main ()
#46 0x00000000005a3d18 in main ()

>>> As I said, the problems with this is that I cannot guarantee that the
>>> application program will every run the Gtk main loop. I can only
>>> guarantee that in real GUI programs, not in those that use Gtk2Hs to
>>> render some graphics into a file. Since the problems only really occur
>>> when objects with handles to Xlib or Win32 are finalized this would be a
>>> solution and is implementable without any change to ghc. I'm just weary
>>> that there is some object whose finalizer I do not enqueue in the main
>>> Gtk loop and which for some reason calls either Xlib/Win32 or Haskell.
>>
>> In any program that uses gtk2hs/cairo/whatever there must be a single
>> distinguished thread that is allowed to perform GUI operations, correct?
>
> No, unfortunately not. Once we've cabalised the parts of Gtk2Hs, it is
> perfectly reasonable to build programs without GUI, say using Cairo to
> create PDFs. However, Cairo (and other non-GUI sub-libaries in Gtk2Hs)
> can cope with other threads calling g_object_unref. Now, g_object_unref
> is thread-safe and hence, the current way of directly caling
> g_object_unref from the GC is perfectly fine.

Ok I see - as long as g_object_unref doesn't end up calling into Haskell 
eventually.

>>    So the task is just to arrange somehow that it is possible to
>> communicate with that thread that it has some finalization actions to
>> perform.  I'm not sure how you do that, but I'm not really familiar with
>> the structure of these kinds of applications.
>
> Yes, for the GUI part of Gtk2Hs, this is the only way to go. I think
> what I would like is a hook in the RTS of ghc that allows me to run a C
> function each time the GC has finished. This C function can be run from
> any OS thread. I would make this function call g_idle_add (which is
> thread-safe) to add a function that empties the list of finalizers that
> I've accumulated during GC. If the main Gtk+ loop is currently running
> or will run at some point in the future, the finalizers form the list
> will be executed. If the Gtk+ is never run again then I probably don't
> care anyway that the finalizers are not run since the program is stuck
> or about to end.

Could you not do this without a hook, by adding a call to g_idle_add to 
each finalizer?  Perhaps with some intelligence so you don't add 
multiple g_idle_adds if one is already pending.

Calling it once per GC might be too much: there are lots of GCs.

>>>> I wonder if for the time being you should just revert to using Haskell
>>>> finalizers. They are less efficient and prompt, but they do support
>>>> proper synchronisation.
>>>
>>> It seems I'm using Haskell finalizer. So you might just have observed an
>>> unsafe/safe declaration bug in Gtk2Hs. However, the Xlib warning is the
>>> real thing that cannot so easily be worked around.
>>
>> If you consistently use Haskell finalizers, and the finalizers always
>> use idleAdd, then you can avoid all these problems for now, at the
>> expense of some performance.
>>
>> But there is evidence that gtk2hs is not using Haskell finalizers, or at
>> least not consistently: see the gdb backtrace below.
>
> We certainly do not call g_idle_add to run the finalizer the objects. We
> do it immeditely, thereby triggering the occasional callback to Haskell
> or a call to Xlib/Win32 which is likely to crash the program. We can fix
> this using the queue/list approach.

Ok, then I misunderstood what you were saying above.

I'm suggesting that you could use Haskell finalizers everywhere, as a 
way to work around the current problems for the time being, meanwhile 
work on the queue/list approach as a long-term solution.

> Oh, I think I understand our different perception of what we want. The
> main loop of Gtk+ will always return at some point. Thus, all I was
> asking is that the Haskell GC should keep a per-OS-thread list of
> finalizers to run and *only* if the GHC runtime has this OS thread
> avaiable to itself, it would run the associated finalizers.
>
> Thus, I thought adding thread-bound finalizers would be as easy as
> adding a function to the running queue of the Haskell thread that is
> associated with the OS thread of the finalizer.
>
> So I can see two ways forward:
>
> (1) a hook in GHC to install a C function that is run by the RTS after
> each GC. The RTS may call this function from any thread.

Or have each finalizer call g_idle_add after enqueing the item.

> (2) have a new Finalizer type that takes an OS thread id. If this
> finalizer is due to be run, the GC enqueues it into running queue of the
> Haskell thread that is bound to the OS thread. The finalizer then has to
> be called using a 'safe' call, so that the finalizer may call back into
> Haskell land.

Hmm, there isn't such a thing as a "running queue of the Haskell 
thread", a Haskell thread is just a stack and a bit of state.  A run 
queue is a list of Haskell threads, and there is one run queue per HEC 
(Haskell Execution Context, ie. a virtual CPU).

My argument is that if you're going to do this, you might as well just 
use Haskell finalizers and have each one be a call to idleAdd, because 
the end result is the same and it doesn't require any changes to the RTS.

> (1) is easier for you, (2) for me. If there's no other libraries that
> have these kind of threading problems, then maybe (1) is enough.

and

   (3) use Haskell finalizers with idleAdd as a temporary workaround.

(3) is by far the easiest solution, but it may have unacceptable 
performance, I'd interested to know if that's the case.  The runtime 
does batch multiple finalizers so they don't each get a separate Haskell 
thread, so it might not be too bad.

I'm not completely averse to doing (1) if it's absolutely necessary, but 
I'd like to do something that avoids having a dependency on a future 
version of GHC.  And all things being equal, we should avoid adding new 
features to GHC because they're hard to remove again.

Cheers,
        Simon

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Gtk2hs-devel mailing list
Gtk2hs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/gtk2hs-devel

Reply via email to