• Uncategorized

About c : Add-fds-in-the-GLIB-mainloop

Question Detail

I need to attach file descriptors to the GLIB mainloop. My issue is that the list of file descriptors is not fixed during execution.

According to GLIB documentation, I can:

  • create a GIOChannel for each FD using g_io_channel_unix_new and attach it to the context with g_io_add_watch
  • Use a Gsource created with g_io_create_watch and set a callback g_source_set_callback

My question is : is it possible to modify dynamically a source or a context. And how can I do it ? I find the GSourceFuncs ability, but that doesn’t fit my issue.

Thanks for your help.

Question Answer

g_io_add_watch returns an event source ID which you can later use to dynamically remove the watch again, using g_source_remove. Use one event source per FD and instead of modifying existing watches, remove the old ones and create appropriate new ones.

I digged more into GLIB and now:

  • I create a source with callbacks functions (prepare, check, dispatch, finalize)
  • In the prepare callback, FD are deleted using g_source_remove_unix_fd() and then added to the current source using g_source_add_unix_fd().
  • I returned FALSE to set the timeout (1s for my example)

My issue is that without the FD, the prepare callback is called each 1s as expected. When FD is added, the prepare callback is called without timeout. the poll exit directly.

I have a look into GLIB source code, but don’t understand the reason why ?

Help please
Regards

amenophiks’ answer is the best.

If you want your code to work with an older glib you can use:

  • g_source_add_poll()
  • g_source_remove_poll()

Have you read the Main Event Loop documentation? The description section has a pretty good explanation of how things work.

Have you looked at the Custom GSource tutorial? This allows you to extend a GSource object to include your own state. You also can write your own prepare, dispatch, query, and check functions.

Whenever I really want to see how something should be done with GLib, GTK, etc the first place I look is the test code that lives in their git repository. Be sure to checkout the proper tag for the version of that you are targeting.

For example I currently target 2.48.2

Here are two pretty good examples
https://gitlab.gnome.org/GNOME/glib/blob/2.48.2/tests/mainloop-test.c
https://gitlab.gnome.org/GNOME/glib/blob/2.48.2/glib/tests/mainloop.c

The other nice feature is it’s a git repository so you can search it very easily.

Seems, I found a diminutive hook. Try this:

struct source {
    GSource gsrc;
    GPollFD *gpfd;
};

struct data {
    /* A something data. */
};

static gboolean gsrc_dispatch(GSource *gsrc, GSourceFunc cb, gpointer data);
static struct data * data_alloc(void);

static GSourceFuncs gsf = {
    .prepare = NULL,
    .check = NULL,
    .dispatch = gsrc_dispatch,
    .finalize = NULL
};

int main(void)
{
    struct source *src;
    int fd;
    struct data *data = data_alloc();

    /* Something other. */

    /* For example, we are want to capture video from a camera. */
    fd = open("/dev/video0", O_RDWR);
    if (fd < 0) {
        perror("open()");

        return -1;
    }

    src = (struct source *) g_source_new(&gsf, sizeof(struct source));
    src->gpfd = g_source_add_unix_fd((GSource *) src, fd, G_IO_IN);

    g_source_set_callback((GSource *) src, NULL, data, NULL);
    g_source_attach((GSource *) src, NULL);

    /* Something other and free. */

    return 0;
}

static gboolean
gsrc_dispatch(GSource *gsrc, GSourceFunc cb, gpointer data)
{
    struct source *src = (struct source *) gsrc;
    struct data *d = data;

    if (src->gpfd != NULL) {
        if (src->gpfd->revents & G_IO_IN) {
            /* Capture a frame. */
        }
    }

    g_main_context_iteration(NULL, TRUE);

    return G_SOURCE_CONTINUE;
}

static struct data *
data_alloc(void)
{
    /* Allocate a data. */
}

Yes, you can use the double gpfd pointer.

You may also like...

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.