qemu/hw/dataplane/event-poll.c
<<
>>
Prefs
   1/*
   2 * Event loop with file descriptor polling
   3 *
   4 * Copyright 2012 IBM, Corp.
   5 * Copyright 2012 Red Hat, Inc. and/or its affiliates
   6 *
   7 * Authors:
   8 *   Stefan Hajnoczi <stefanha@redhat.com>
   9 *
  10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  11 * See the COPYING file in the top-level directory.
  12 *
  13 */
  14
  15#include <sys/epoll.h>
  16#include "hw/dataplane/event-poll.h"
  17
  18/* Add an event notifier and its callback for polling */
  19void event_poll_add(EventPoll *poll, EventHandler *handler,
  20                    EventNotifier *notifier, EventCallback *callback)
  21{
  22    struct epoll_event event = {
  23        .events = EPOLLIN,
  24        .data.ptr = handler,
  25    };
  26    handler->notifier = notifier;
  27    handler->callback = callback;
  28    if (epoll_ctl(poll->epoll_fd, EPOLL_CTL_ADD,
  29                  event_notifier_get_fd(notifier), &event) != 0) {
  30        fprintf(stderr, "failed to add event handler to epoll: %m\n");
  31        exit(1);
  32    }
  33}
  34
  35/* Event callback for stopping event_poll() */
  36static void handle_stop(EventHandler *handler)
  37{
  38    /* Do nothing */
  39}
  40
  41void event_poll_init(EventPoll *poll)
  42{
  43    /* Create epoll file descriptor */
  44    poll->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
  45    if (poll->epoll_fd < 0) {
  46        fprintf(stderr, "epoll_create1 failed: %m\n");
  47        exit(1);
  48    }
  49
  50    /* Set up stop notifier */
  51    if (event_notifier_init(&poll->stop_notifier, 0) < 0) {
  52        fprintf(stderr, "failed to init stop notifier\n");
  53        exit(1);
  54    }
  55    event_poll_add(poll, &poll->stop_handler,
  56                   &poll->stop_notifier, handle_stop);
  57}
  58
  59void event_poll_cleanup(EventPoll *poll)
  60{
  61    event_notifier_cleanup(&poll->stop_notifier);
  62    close(poll->epoll_fd);
  63    poll->epoll_fd = -1;
  64}
  65
  66/* Block until the next event and invoke its callback */
  67void event_poll(EventPoll *poll)
  68{
  69    EventHandler *handler;
  70    struct epoll_event event;
  71    int nevents;
  72
  73    /* Wait for the next event.  Only do one event per call to keep the
  74     * function simple, this could be changed later. */
  75    do {
  76        nevents = epoll_wait(poll->epoll_fd, &event, 1, -1);
  77    } while (nevents < 0 && errno == EINTR);
  78    if (unlikely(nevents != 1)) {
  79        fprintf(stderr, "epoll_wait failed: %m\n");
  80        exit(1); /* should never happen */
  81    }
  82
  83    /* Find out which event handler has become active */
  84    handler = event.data.ptr;
  85
  86    /* Clear the eventfd */
  87    event_notifier_test_and_clear(handler->notifier);
  88
  89    /* Handle the event */
  90    handler->callback(handler);
  91}
  92
  93/* Stop event_poll()
  94 *
  95 * This function can be used from another thread.
  96 */
  97void event_poll_notify(EventPoll *poll)
  98{
  99    event_notifier_set(&poll->stop_notifier);
 100}
 101