Friday 2 December 2016

Re: cups-browsed uses GMainLoop and global variables, how to introduce locks against race conditions?

On 12/02/2016 02:28 PM, Ted Gould wrote:
> On Fri, 2016-12-02 at 12:58 -0200, Till Kamppeter wrote:
>> The solution would be to acquire a lock when starting to manipulate the
>> printer list and releasing the lock when done.
>>
>> Now my qestion is, which functions I have to use for acquiring and
>> releasing locks when using GLib and GMainLoop? Probably it is not
>> correct to use the locks of pthread. Also it is probably best to use
>> Read/Write locks where only writing is exclusive but reading is allowed
>> to more than one thread at a time.
>
> Generally speaking the best way to do this is to use the mainloop itself
> as the lock. The mainloop is always on a single thread, so you should
> have the other threads put events into the main loop context and have
> them operate there on the data structure. So you'd, for instance, get
> all the information together on your Bonjour thread and when you're
> ready to add it put an action on the main loop with all that information.
>
> The functions you're probably looking for are (as starting points):
>
> g_main_context_get_thread_default()
> g_idle_source_new()
> g_source_attach()
>

The way how cups-browsed works is the following:

First, a GMainLoop is created:

gmainloop = g_main_loop_new (NULL, FALSE);

Browsing for legacy CUPS broadcasts is attached to the mail loop via

GIOChannel *browse_channel = g_io_channel_unix_new (browsesocket);
g_io_channel_set_close_on_unref (browse_channel, FALSE);
g_io_add_watch (browse_channel, G_IO_IN, process_browse_data, NULL);

Many other things are added via

g_idle_add ()

and

g_timeout_add_seconds ()

Reaction to D-Bus notifications is added via the

g_signal_connect()

function.

Avahi browsing is set up with these calls

/* Allocate main loop object */
if (!glib_poll)
if (!(glib_poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT)))
{
debug_printf("ERROR: Failed to create glib poll object.\n");
goto avahi_init_fail;
}

/* Allocate a new client */
if (!client)
client = avahi_client_new(avahi_glib_poll_get(glib_poll),
AVAHI_CLIENT_NO_FAIL,
client_callback, NULL, &error);

/* Check wether creating the client object succeeded */
if (!client) {
debug_printf("ERROR: Failed to create client: %s\n",
avahi_strerror(error));
goto avahi_init_fail;
}

Strange is that this Avahi browsing setup is done before creation of the
main loop. Also some g_timeout_add_seconds () calls are done before
creating the main loop.

After that, the main loop gets started via

g_main_loop_run (gmainloop);

My questions are now:

- Is this way everything attached to the main loop?

- Do I have to do function calls in the beginning and in the end of each
callback function to acquire and release a lock? Which ones?

- If something of this is not attached to the main loop, how do I attach it?

I do not explicitly start any new threads.

Till


--
ubuntu-devel mailing list
ubuntu-devel@lists.ubuntu.com
Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/ubuntu-devel