0

I am interested in listening to incoming connections and when there is no active connections I want to do background processing. I have not found any examples of both these together.

I want to do something similar like this:

From one of the examples:

//ev_io callback

static void server_cb(EV_P_ ev_io *w, int revents)
{
  //Accept new client connection
  //Read from client socket

  //stop event loop
  ev_io_stop(EV_A_ &client->io);

  //send back to client

  //start event loop again
  ev_io_start(EV_A_ &client->io);

}

main()
{
  // To be sure that we aren't actually blocking
  ev_periodic_init(&every_few_seconds, not_blocked, 0, 5, 0);
  ev_periodic_start(EV_A_ &every_few_seconds);

  // Get notified whenever the socket is ready to read
  ev_io_init(&server.io, server_cb, server.fd, EV_READ);
  ev_io_start(EV_A_ &server.io);

 }

Now in this example where should I add the idle event and where and when should I start and stop the idle event so that it does not interfere in the main event handler and should be invoked only when it is idle.

Thanks.

2 Answers2

1

Well, I am also new to libev, but I put together this simple demo of a server which recieves data on a socket while also processing timeouts and idle events.

#include <ev.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

static struct ev_loop *loop;
static ev_timer timeout_watcher;
static ev_io in_watcher;
static ev_idle idle_watcher;
static int sock_fd;

// socket input watcher
static void in_cb(EV_P_ ev_io *watcher, int revents) {
    int r, t;
    char buf[1024];
    for (t = 0; (r = read(sock_fd, buf, sizeof(buf))) > 0;) {
        t += r;
        write(STDOUT_FILENO, buf, r); // copy input to stdout
        if (buf[r-1] == '\n') break; // operate line-at-a-time
    }
    fprintf(stderr, "in: count = %d\n", t);
    if (r == 0) {
        fputs("in: connection closed\n", stderr);
        ev_io_stop(loop, &in_watcher); // stop the socket watcher
        ev_break(loop, EVBREAK_ALL); // exit the loop
    } else if (r < 0) {
        perror("read");
    }
}

static void timeout_cb(EV_P_ ev_timer *watcher, int revents) {
    fprintf(stderr, "timeout: now = %f\n", ev_now(loop));
}

static void idle_cb(EV_P_ ev_idle *watcher, int revents) {
    static long idle_count = 0;
    fprintf(stderr, "idle: count = %ld\n", ++idle_count);
    sleep(1); // simulate doing stuff
}

int main() {

    extern int errno;

    int master_fd;
    int sock_opt = 1;
    int conn_port = 7000;
    struct sockaddr_in addr;
    socklen_t addrlen;

    // **** the following is needed to set up a socket to receive data ****
    master_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (master_fd == -1) {
        perror("socket");
        return errno;
    }
    if (setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &sock_opt, sizeof(sock_opt)) == -1) {
        perror("setsockopt");
        return errno;
    }
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(conn_port);
    addrlen = sizeof(addr);
    if (bind(master_fd, (struct sockaddr *) &addr, addrlen) != 0) {
        perror("bind");
        return errno;
    }
    if (listen(master_fd, 3) != 0) {
        perror("listen");
        return errno;
    }

    fprintf(stderr, "awaiting a connection on port %d\n", conn_port);
    sock_fd = accept(master_fd, (struct sockaddr *) &addr, &addrlen);
    if (sock_fd == -1) {
        perror("accept");
        return errno;
    }
    fputs("in: connection established\n", stderr);
    // **** end of socket setup code ****

    // define a loop
    loop = ev_default_loop(0);

    // define a repeating timer
    ev_timer_init (&timeout_watcher, timeout_cb, 5.0, 5.0);
    ev_timer_start (loop, &timeout_watcher);

    // define an idle process
    ev_idle_init(&idle_watcher, idle_cb);
    ev_idle_start (loop, &idle_watcher);

    // define the socket data receiver
    ev_io_init(&in_watcher, in_cb, sock_fd, EV_READ);
    ev_io_start (loop, &in_watcher);

    // run the loop
    ev_run(loop, 0);

    // clean up
    close(sock_fd);
    close(master_fd);
    return 0;
}
user9645
  • 6,286
  • 6
  • 29
  • 43
0

You should add ev_idle just before you call ev_loop() which is for entering the main loop. (Actually, you can add it at anywhere you want. But for the above case, I think it is ok.)

And the callback you bind with the idle watcher will be called only when there is no other event pending. And it will not interfere any other event's callbacks. Callbacks will be called sequentially.

By the way, I would suggest you carefully use idle event in libev. Because it will consume the whole cpu if you don't control it. A periodic event would be better. And if it is the case you want to use it, (e.g. in a computing intensive program), it would be better to do one little piece of thing at one callback. So that it will drop the control back to the main loop to response other events. (e.g. io event)

PS: You don't have to call ev_io_stop at the server_cb callback and call ev_io_start again. Because the callback will not be interfered at all.

Kai Zhang
  • 1,028
  • 8
  • 9