Re: [gtk-list] callback synchronisation



>I have a callback function which is called from the main loop whenever the
>OS hits my application with SIGPOLL.
>
>It looks like this (somewhat simplified):

   [ elided ]

>rescan(), replace_data() and kill_it() work on the same data, so I need
>to prevent them from corrupting it for each other. The functions are
>called asynchronously, whenever the OS signals come. SIGPOLL is being
>handled by functions set with g_source_add(), so it behaves the same
>way as SIGALRM, I think.
>
>I don't know if glib main loop guarantees that my callbacks can't be
>interrupted by another callback with the same priority (G_PRIORITY_DEFAULT).
>If that's the case, then everything should work.

[ Your message suggested that you have a good reason to be using SIGPOLL
  rather than having the main loop including the relevant fd's in
  its own select/poll waiting. So I'll ignore that possibility.
]

How are you installing the callback on SIGPOLL ? The current version
of glib doesn't provide direct support for callbacks on POSIX
signals. It sounds as if you are doing something very similar to Tim
Janik's stuff for Beast that provides a layer about g_source_add() for
POSIX signals. I ripped it out of Beast (well ... copied
glib_extra.[ch]:), and it works wonderfully for me.

However, Tim's code doesn't directly receive the POSIX signal;
instead, it appears to rely on the signal interrupting the glib main
loop (see below for a comment on this), at which point the g_source_()
functions get executed and the callback you set up runs. This isn't
adequate for my purposes, so I doubled up - I handle the
non-GTK-related aspects of the signal from a direct POSIX signal
handler installed with signal(2), and the GTK-related parts with a
callback installed with Tim's g_signal_add(). The only GTK-related
thing that happens in the POSIX handler is a call to Tim's
g_signal_notify(), which ensures that the GTK part will execute right
after the POSIX signal handler has returned: the glib main loop
returns from poll/select because of the signal, checks to see if any
"input" is available, which is true because I called
g_signal_notify(), and then executes the callback.

One important note with this approach: if you set up POSIX signal
handling in a way that allows reentrancy, you may well be doomed.  My
MIDI sequencer SoftWerk gets a SIGALRM from the OS every 25ms, but it
uses signal(2) to setup the handler, which prevents reentrancy; in
fact, it requires that the signal handler is "rearmed" after every
signal.  This works fine for me. That is, if my SIGALRM handler isn't
done in 25ms (hard to imagine, but not impossible), then we simply
won't get another SIGALRM when the next one is due.

>If not, I need to set up some lock for my data, which is probably possible,
>but I don't know what to do when I detect that another callback holds the
>lock, ie. how do I let it continue its job and then return to the current
>callback.

I need to do this as well sometimes, so I use <asm/atomic.h> on Linux
and equivalents on other systems. Within critical sections, I do this:

	atomic_inc (&do_not_disturb);
	.
	... do protected stuff ...
	.
	atomic_dec (&do_not_disturb);

and then from the handler:
     
        if (atomic_read (&do_not_disturb)) {
              ... rearm signal delivery ...
	      return;
	}			

To be honest, you could use an int for this on most platforms, but I
feel more comfortable with the asm-level guarantees that this provides
for SMP systems.

>And which values can't be returned by gtk_timeout_add()?

I think I assumed they were all zero-or-positive. I think I found this
in the code.

As an aside to GTK developers (and particularly Tim): I think that
using glib to handle signals will not work correctly in (some)
multithreaded programs, since it seems to assume that the signal is
delivered to the thread running the glib main loop. If thats not the
case, then the main loop will never be interrupted, and the signal
callback function will never be executed. To avoid this, it is
necessary to use pthread_sigmask() to ensure that the thread running
the main loop is the *only* thread that can receive signals that are
intended to be processed by a glib-level signal callback. If they are
delivered elsewhere, the glib main loop will continue its happy
slumbers deep with poll/select(2).

--p



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]