Today's Hot Hack

Today I got fed up of writing yet another GQueue and idle function to perform tasks incrementally in the background, with all of the bookkeeping that needs to be done. So, I wrote taku_idle_queue_add.

Using it is simple, create a GQueue and then call taku_idle_queue_add, passing the queue and a callback function. When the queue has items in it, the callback gets called. Easy! Just remember not to return FALSE from the callback unless you are sure the queue will never be used again.

I'd appreciate anyone who knows GSource programming in detail to review the code. Maybe I should even try and get this into Glib?

NP: Cliqhop IDM, Soma.fm

11:10 Wednesday, 07 Nov 2007 [#] [computers] (13 comments)

Posted by Neil Williams at Wed Nov 7 12:29:40 2007:
Instead of passing a gint * you should use the GINT_TO_POINTER macro and then GPOINTER_TO_INT to recover it.
gint* is not safe on amd64 or ia64.
Posted by Ross at Wed Nov 7 12:39:18 2007:
I presume you are talking about:

prepare (GSource source, gint timeout)

In which case you are wrong.  timeout is a pointer to an integer.
Posted by Snark at Wed Nov 7 13:34:30 2007:
I would have replaced :
if (!callback) {
  g_warning ("Queue source dispatched without callback\n"
  "You must call g_source_set_callback().");
  return FALSE;
  }
by :
g_return_val_if_fail (callback != NULL, FALSE);
and made the taku_idle_queue_add complain if the function wasn't correct.
Posted by Snark at Wed Nov 7 14:01:21 2007:
That code is verbatim from glib, and is because when I generalise it more, you'll be able to create a source without calling the current entry point (and thus have no callback).  But yes, your point is valid and I have similar changes locally.
Posted by Ross at Wed Nov 7 14:02:21 2007:
The previous comment was by me, whoops.
Posted by Tommi Komulainen at Wed Nov 7 14:51:46 2007:
Instead of GSourceFunc you should probably have an internal callback always returning TRUE and only allow the user to provide a void function (like GHookFunc) .. it's harder to make mistakes that way.
Posted by Colin Walters at Wed Nov 7 15:00:36 2007:
Doesn't this code cause the queue only to be processed when there are other pending events?
For many apps this might be fine, but if you want your application to update even when the user isn't actively interacting with it (moving mouse, typing etc) it may be a problem.

The approach I took in Hotwire for this was to have a queue wrapper where the calling thread adds an idle handler.  Check out IterableQueue here:

http://hotwire-shell.googlecode.com/svn/trunk/hotwire/async.py

Disadvantage is that it requires an extra mutex and overhead.
Posted by Ross at Wed Nov 7 15:14:24 2007:
Tommi, yes, good point.

Colin: I was wondering who would notice that. :) Yes, if the queue is manipulated without any GTK+ events then the callback isn't fired until something happens.  As "something happens" is quite loose, and in my application the queue is manipulated on startup and when the style changes, this isn't a problem for me.  Obviously its a show-stopper for some applications.
Posted by Ray Strode at Wed Nov 7 15:20:47 2007:
Right, *timeout = -1 means it will never explicitly wake up the main loop, but instead only get dispatched when other things wake up the main loop.

Ideally, you'd want to attach a pollfd to the source to wake up the main loop (assuming you have an fd), or you could have your own queue_push function that wakes up the main loop explicitly.
Posted by Ross at Wed Nov 7 15:34:02 2007:
Ray, I was considering a trivial wrapper around gqueue which would do the job.  A list data structure which supported signals would be nice to have though, so I could fake an fd for poll.
Posted by Snark at Wed Nov 7 18:43:37 2007:
tko, I'm pretty sure he wants the callback to be able to return FALSE when the processing is finished, to get rid of the now-unneeded source...

Ross, you may want to use a GAsyncQueue if you plan to use it for off-thread.

http://svn.gnome.org/viewvc/ekiga/trunk/lib/engine/framework/runtime-glib.cpp?view=markup
might be of interest too.
Posted by James at Thu Nov 8 10:01:53 2007:
Rhythmbox has some code that does basically this, if you wanted to steal it: <a href="http://svn.gnome.org/viewvc/rhythmbox/trunk/lib/rb-async-queue-watch.c?revision=5105&view=markup">http://svn.gnome.org/viewvc/rhythmbox/trunk/lib/rb-async-queue-watch.c?revision=5105&view=markup</a>  As well as using async queues, it also has a proper userdata-destroy parameter, so you can free your userdata.
Posted by Ross at Thu Nov 8 10:14:41 2007:
I see Rhythmbox's code suffers from the same problem mine does, in that if there are no other events the source isn't dispatched.

Name:


E-mail:


URL:


Add 5 and 7 (required):


Comment: