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

Till Kamppeter till.kamppeter at gmail.com
Fri Dec 2 18:13:22 UTC 2016


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




More information about the ubuntu-devel mailing list