CPU 100% due to G_IO_HUP

Hello All, I have this code which makes CPU to hog at 100%. (2.56.4-0ubuntu0.18.04.6 ). If I add G_IO_HUP to g_io_add_watch() then issue is resolved.

While it makes sense for user apps to watch on G_IO_HUP event, why does main_loop() has to go infinite loop and hog the CPU, forever if G_IO_HUP is not registered?

This would affect the whole system if there is a buggy user app. So like to know, was this glib behavior an intentional design or a bug?

#include <stdio.h>
#include <unistd.h>
#include <glib.h>

gboolean pipe_cb(GIOChannel *source, GIOCondition condition, gpointer data)
{
    printf("pipe_cb: %d\n", condition);
    return FALSE;
}

int main(int argc, char *argv[])
{
    int pipe_fds[2];
    pid_t cpid;
    GIOChannel *pipe_channel;
    GMainLoop *main_loop;

    pipe(pipe_fds);

    cpid = fork();

    if (cpid == 0) {
        close(pipe_fds[0]);
        close(pipe_fds[1]);
        return 0;
    }

    close(pipe_fds[1]);

    pipe_channel = g_io_channel_unix_new(pipe_fds[0]);

    g_io_add_watch(pipe_channel, G_IO_IN, pipe_cb, NULL);

    main_loop = g_main_loop_new(NULL, TRUE);

    g_main_loop_run(main_loop);

    printf("exiting\n");

    return 0;
}
 PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
11012 ravi      25   5   12356   1144   1048 R 100.0  0.0   0:06.36 poll-hup

thanks.

Run it under gdb, interrupt it while it’s hogging the CPU, print a backtrace, and see what code’s being executed.

It’s g main loop which is running infinite with poll() system call.

Seems that G_IO_HUP is unconditionally added into the poll() FD mask, which causes the wakeup, but then nothing handles it, so it continues to wake poll() up on the next main loop iteration, etc.

You should handle G_IO_HUP using g_io_add_watch().

It’s probably not an intentional design feature of GLib, but it’s not entirely a bug either, since I can’t think of a situation where it would be reasonable for an app to watch G_IO_IN but not G_IO_HUP.

Apart from G_IO_HUP are there other events that get unconditionally added into poll?

It’s probably not an intentional design feature of GLib
—> Getting into an indefinite loop can create more problems. In few other places in glib documentation it is also mentioned that
" It is meaningless to specify [Glib::IO_ERR] or [Glib::IO_HUP] in condition ; these conditions will always be reported output if they are true.

Yes, on Unix, G_IO_ERR or G_IO_NVAL are also unconditionally set. I’ve dug into it a little more, and they’re unconditionally returned by poll(). See man 2 poll:

   The field revents is an output parameter, filled by the kernel with the
   events  that  actually  occurred.   The  bits  returned  in revents can
   include any of those specified in events, or one of the values POLLERR,
   POLLHUP,  or POLLNVAL.  (These three bits are meaningless in the events
   field, and will be set in the revents field whenever the  corresponding
   condition is true.)

Best to handle G_IO_ERR and G_IO_HUP then :slight_smile:

If GLib were to ignore them if you hadn’t specified them in your g_io_add_watch() call, then there’d be no way for your code to tell that the pipe had been closed (or had errored).

If you think the g_io_add_watch() documentation should mention G_IO_ERR/G_IO_HUP/G_IO_NVAL (or should have any other improvements), please open a merge request :slight_smile:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.