Integrating ghc's rts into other single-threaded frameworks

Duncan Coutts duncan.coutts at worcester.oxford.ac.uk
Mon May 3 22:56:43 EDT 2004


All,

I'm thinking about how to make threaded Haskell program work nicely with
Gtk+ (the widget toolkit) and whether the new threaded rts will help or
not.

Graphics toolkits (X windows or win32 GDI) typically have pretty strict
requirements on threads. While it is possible to make use of multiple
OS/kernel threads, the locking issues are non-trivial and it is
generally not encouraged. It is probably best to consider them as single
threaded libraries.

So while my initial thought was to make a blocking call to Gtk's main
loop in another OS thread using the threadsafe atribute so that it runs
in a separate thread, I now think this is not the best approach. The
problem is that calls to Gtk functions in other Haskell threads will be
made in a different OS thread from the one running the Gtk main loop.

Would bound threads help? I'm not sure I understand the idea very well.

(It is possible to set up a polling system where gtk periodically calls
back to Haskell land and we call ghc's yield function. As you might
expect, this works but performs poorly and consumes cpu time when idle.)

So a better approach might be to try and integrate the main loops of
gtk+ and the ghc rts. Gtk provides a fairly flexible API for controlling
it's main loop. You can either run it as a single blocking function or
run a single iteration at a time or even split up each iteration into
phases.

So the question is which main loop gets to block? Unfortunately, neither
can do so unless it knows the full set of file descriptors and timeouts
of both main loops. So the question is which would be easier?

The glib main loop could act as the master main loop since there are
functions for registering callbacks for fds and timeouts. At the moment,
I don't believe there is any way to ask the ghc rts what fds & timeouts
it is interested in.

The glib main loop is designed so that it can integrate into an external
main loop (though no doubt with some difficulty). See:
http://www.gtk.org/~otaylor/gtk/2.0/main-loop.html
also an older message
http://mail.gnome.org/archives/gtk-devel-list/1999-March/msg00145.html

The glib main loop can be split up into phases (prepare, query, check,
dispatch), see:
http://developer.gnome.org/doc/API/2.0/glib/glib-The-Main-Event-Loop.html#mainloop-states
It's not clear to me how one would use that to integrate two main loops,
but perhaps it's clearer to the ghc rts gurus. There is also a function
for changing the 'poll' function that the glib main loop uses. This
might be another way to allow the ghc rts main loop to be the master
one.

I'd guess that it would be easier to expose some rts function that tells
us what fds & timeouts ghc's rts is interested in at any particular time
and write some glue code (in C) to install ghc's rts events sources in
an external main loop.

What would such an API look like? Presumably we'd need to know if there
are runnable Haskell threads and we'd need to be able to run them for
one timeslice. If there were no runnable threads, we'd want to know the
set of fds & timeouts that the rts would want to block upon.

[sorry, this next bit is a bit implementation specific]
http://developer.gnome.org/doc/API/2.0/glib/glib-The-Main-Event-Loop.html#GSource
To create a GSource from this we would need to implement a prepare,
check & dispatch to fill out a GSourceFuncs struct. In prepare we'd
check to see if there are currently any runnable Haskell threads
(returning true if there were). It would also set up the set of fds to
be polled. It would also return the timeout of the soonest timeout that
the ghc rts has (or -1). In check we'd return true if any fds were ready
or a timeout had expired. In dispatch we'd ask the ghc rts to run for
one timeslice.

Any simpler / better ideas anyone?

Duncan



More information about the Glasgow-haskell-users mailing list