Re: Changes to the GLib main loop [ GMainLoop ]



Owen Taylor <otaylor redhat com> writes:

> Sebastian Wilhelmi <wilhelmi ira uka de> writes:
> 
> > > > Ok, but that could be optimized away by also telling
> > > > g_main_context_iterate, whether it was called from g_main_loop_run or
> > > > not only signalling other threads, when it was not run from
> > > > g_main_loop_run. For calls not done from g_main_loop_run it would
> > > > still need to be called, because of the scenario outlined above (the
> > > > thread A and B thingy)
> > > 
> > > This doesn't work because the thread needs to be woken up to check for
> > > loop->is_running, even before the main loop stops running its loop.
> > > 
> > > (Remember, what I want to be able to do here is use main loop to wait
> > > for a modal dialog being closed, whether or not the dialog is being
> > > shown from the main thread.)
> > 
> > Ah, I see, but the solution to this is calling g_cond_broadcast in
> > g_main_loop_quit. So I think the following is enough:
> > 
> > * Make g_main_context_iterate call g_cond_broadcast only when not called 
> >   from g_main_loop_run.
> > * Make g_main_loop_quit call g_cond_broadcast.
> 
> Isn't the right way to express this is "broadcast when releasing
> ownership of the context?" 
> 
> Other than this, yes this approach works pretty well. (Main problem
> is if you have a bunch threads waiting for ownership, they all
> wake up and try to get ownership)

Turns out, when I tried to actually make GMainLoop works this
way completely using the public interfaces, it doesn't work.
There is an inherent race condition, coming from the 
general principle:

  - if you want to wait for a condition with a condition variable,
    then you must test the condition, and then call g_cond_wait()
    without ever releasing the accompanying mutex.

That is:

  while (loop->is_running || !got_ownership)
    {
      UNLOCK_LOOP (loop);
      got_ownership = g_main_context_wait (context);
      LOCK_LOOP (loop);
    }

Is inherently broken, because loop->is_running can become
FALSE betweeen the point where it is tested, and 
g_cond_wait (loop->cond) is called. 

So, I think what I'm going to do is:

 g_main_context_wait (GMainContext *context,
                      GCond        *cond,
                      GMutex       *mutex);

Which (called holding mutex)

 a) adds the cond to a list of condition variables waiting
    on the context

 b) Calls g_cond_wait(cond,mutex)

And then, have g_main_context_release() signal exactly
one of the condition variables waiting on the context.

It should still possible to reuse context->cond for all loops
this way with a few extra checks in the implementation.

Regards,
                                        Owen




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