2

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.

amenophiks
  • 73
  • 2
  • 6

5 Answers5

2

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.

Phillip
  • 13,448
  • 29
  • 41
  • Thanks. But in where part of the code should I realize the remove/add feature ? Because If I work with GIOChannel, I only have the main and the callbacks. – amenophiks May 21 '14 at 12:18
  • That depends on your code. Since you don't know where to add it, am I assuming correct that you don't have control over the list? (If you have, the answer is that you should add the code wherever you alter the list.) Could you expand your question with some background? – Phillip May 21 '14 at 13:24
1

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
  • 73
  • 2
  • 6
0

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()
Janek Olszak
  • 4,067
  • 1
  • 28
  • 22
0

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.

f3xy
  • 737
  • 11
  • 15
0

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.

Kassi
  • 151
  • 2
  • 12