Question

I have a select() to update my UI every second and also to handle user actions from X11. Here's a snippet of this source code:

XEvent e;
/* Input file descriptor */
fd_set in_fd;
/* Get the file descriptor of the link with X11 */
int dpy_fd = ConnectionNumber(disp->dpy);

while (!finish) {
  FD_ZERO(&in_fd);
  FD_SET(dpy_fd, &in_fd);

  if (select(dpy_fd+1, &in_fd, 0, 0, &tv)) {
    printf("Event Received!\n");
    XNextEvent(disp->dpy, &e);
    /* do something */
  }
  else {
    printf("Timer Fired!\n");
    /* do something else*/
  }
}

So far, everything's ok.

In parallel, I need to use an alarm to do another thing every 500 ms so I implemented this:

static void timer_handler(int sig)
{
  signal(SIGALRM, SIG_IGN); /* ignore this signal */
  printf("timer_handler\n");
  signal(SIGALRM, timer_handler); /* reinstall the handler */
}

int test_timer()
{
  printf("test_timer\n");

  signal(SIGALRM, timer_handler);
  ualarm(1, 500000); /* every 500 ms */

  return 0;
}

I get timer_handler in my console every 500 ms but it's like it consumes the event from select() because I don't have Timer Fired! anymore (no more update of the UI). If I press a key or move the mouse over the UI, I get Event Received! in the console and the alarm is still responding.

Is select() using the SIGALRM signal? What am I doing wrong? I just want to use select() to handle the UI and an alarm to call a method every 500 ms (this method multiplexes hardware performance counters).

Was it helpful?

Solution

SIGALRM is triggering an EINTR error in select(2) call. You must check whether the system call is returning a timeout, a file descriptor event or an error (and which kind of error too):

while (!finish) {
    int s;

    FD_ZERO(&in_fd);
    FD_SET(dpy_fd, &in_fd);

    s = select(dpy_fd+1, &in_fd, 0, 0, &tv)
    if (s > 0) {
        printf("Event Received!\n");
        XNextEvent(disp->dpy, &e);
        /* do something */
    } else if (s == 0) {
        /* This is probably where we should break the loop or reset the
         * select(2) timeout, so... I chose to break it. If you don't
         * do something about it you're gonna end up in a busy wait. */
        break;
    } else {
        if (errno == EINTR) {
            /* We've been interrupted by another signal, and it might be
             * because of the alarm(3) (using the SIGALRM) or any other
             * signal we have received externally. */
            continue;
        }
        perror("Select failed");
        /* Handle the error properly. */
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top