2

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).

3
  • Your symptoms are consistent with blocking in XNextEvent(), but we don't have enough information to help you troubleshoot.
    – pilcrow
    Commented May 9, 2014 at 14:13
  • Another nice example on how not testing function calls for error could lead to quiet some irritation ... - the code misses to test whether select() failed. It returns -1 on error.
    – alk
    Commented May 9, 2014 at 14:58
  • OT: At least on Linux you need to reset the timer values (in tv) passed to select() during each iteration, as they might get modified by select() itself.
    – alk
    Commented May 9, 2014 at 15:04

1 Answer 1

2

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. */
    }
}
6
  • What is the idea behind this timer_fired flag?
    – alk
    Commented May 9, 2014 at 15:00
  • Thanks Fernando. With your code I get the following error Select failed: Interrupted system call which I don't really understand. I also agree with alk, could you please give us more information about the flag solution? Commented May 9, 2014 at 15:05
  • I'm sorry, I misunderstood the timer reason. I thought you wanted to do something in the while loop every time the timer was fired. Now I removed it. Commented May 9, 2014 at 17:02
  • 1
    EAGAIN? From select(2)? Are you sure?
    – pilcrow
    Commented May 9, 2014 at 17:21
  • With your solution, it seems to work but only if the alarm value is less than the select value. If I set ualarm(1,1000000) (or alarm(1)) and select(...) to trigger every second, the alarm handler is never called. Commented May 12, 2014 at 8:23

Not the answer you're looking for? Browse other questions tagged or ask your own question.