bassosimone/libight — pull request #11 by bassosimone (2014-06-23 13:54:56+00:00)
Title: Rewrite the poller in C++

This pull request rewrites the poller using C++. I started incrementally, reducing the complexity of the C poller, then I rewrote everything in C++ (improving the design in the process), finally I wrote a unit test (`./test/common/delayed_call.cpp`) and I applied some fixes on top of the rewrite as well.

The new code was compiled on Linux and MacOS, and tested on MacOS, by manually running the tests. I also run `valgrind ./test/common/delayed_call` and noticed no harmful leaks (there are only leaks created by global objects and I had to turn verbose mode on to see them).

- - -

As far as the design is concerned, now the user does not need to instantiate a new Poller anymore, because there is a single, global Poller instance. This is similar to the approach taken by Twisted, except that one does not need to import the global instance; rather, the approach I chose is to have some global functions that one should call to operate on the global Poller:

IghtPoller *ight_get_global_poller(void);
event_base *ight_get_global_event_base(void);
evdns_base *ight_get_global_evdns_base(void);

void ight_loop(void);
void ight_break_loop(void);

The first three functions are used within the library to access the global poller and its relevant fields (the `event_base` and the `evdns_base`). The other two functions should be invoked by library users to, respectively, start / stop the I/O loop.

Another relevant design-related point is the way in which delayed function calls are now handled. To create a delayed function call, one needs to create an instance of `IghtDelayedCall` as follows:

auto d = IghtDelayedCall(5.0, [](void) {
// do something here
});

The delayed call is active as long as the object `d` above is alive. This allows one to bind a delayed call to an object and to be sure that the delayed call is cancelled when such object dies. For example:

struct X {
IghtDelayedCall d; /* This creates an empty delayed call */
...
};

...

X *x = new X();
x->d = IghtDelayedCall(5.0, [](void) {}); /* Assign delayed call using move semantic */
delete (x);

in this case, when `delete (x)` is called, the call is also unscheduled. This property is very handy, because it allows you to bind the lifetime of a delayed call to the lifetime of a connection (which may be closed at any time by the peer).

- - -

While at it, I also improved the checks for C++11 in the `./configure` script (now we're starting to seriously use C++11) and I have removed `./src/ight_wrappers.h`, which become empty after the Poller was rewritten in C++.