libev and libevent

Andy Green andy at warmcat.com
Wed Feb 21 00:26:03 CET 2018



On 20/02/18 19:50, Marc Lehmann wrote:
> On Tue, Feb 20, 2018 at 10:35:01AM +0800, Andy Green <andy at warmcat.com> wrote:
>>> Not really, even C supports opaque types.
>>
>> No, there is no "not really" about it.
>>
>> C supports opaque type pointers because the size of a pointer is known
>> regardless of the details of what it points to.
> 
> To be pedantic, C supports opaque pointers because it is defined to do so,
> not because pointers naturally all have the same size (they don't).
> 
> Anyhow, I don't think this is the right place for introductory programming

You brought this subject up.

> in C, but the solution, as already mentioned, is to move libev code into
> e.g. lws-libev.c, libevent code into lws-libevent.c and so on, and then
> define an abstraction to those, e.g.
> 
>     struct lws_ev_watcher;
> 
>     lws_ev_io_watcher *
>     lws_ev_io_new (...);
> 
>     void
>     lws_ev_io_start (lws_ev_watcher *, ...);
> 
>     ...
> 
> lws_ev_watcher is your opaque data type, and lws_ev_new etc. are the
> methods used to access them.
> 
> Then you can use those in your lws_io_watcher struct:
> 
>     struct lws_io_watcher {
>     #ifdef LWS_WITH_LIBEV
>             lws_ev_io_watcher *ev_watcher;
>     #endif
> 
> Quite possibly, lws_ev_io_watcher could even be identical to
> struct ev_io, and with some work, it doesn't even have to be a pointer, and
> lws_ev_watcher might not need to be a separate data type either.

That is the first constructive suggestion, thanks.  It adds another 
layer of indirection.  But actually that is probably a good idea. 
Reducing the scope of the includes if it is possible is also a good way.

There are other event-lib api types that are exposed in event-lib 
specific lws apis, eg, pass in an external loop object as the active 
event loop.  If these are all pointers then it can be solved with 
forward references.

> Since you are not really telling us why you think you need this, it's hard to
> tell you which solution might be best.
> 
>> However you cannot compose an opaque / forward-referenced struct into
>> another struct with type safety, because the size of the undefined thing is
>> unknown.
> 
> Yes, you can, multiple ways.

Note the word "compose" has a specific meaning here...

>> I must have your struct definition and that means I must have your headers.
> 
> Yes, but not in the same source file as the headers for libevent. This is a
> pretty standard problem with pretty standard solutions.
> 
> You can do away with pointers with some tricks, as the libev ABI has a
> fixed watcher size that you could determine at compile time and reserve
> enough space in your lws_io_watcher struct. This would result in virtually
> no performance loss due to the indirection.
> 
> It's not trivial, but certainly possible with commonly used programming
> techniques. It probbaly wouldn't buy you anything that you couldn't beat
> by embedding libev, though.
> 
> The other problem, the ABI clash, can either be fixed with a custom libev
> version not compiling in the event code (easy to do), or by using e.g.
> shared libraries and dlopen, which allows you to open both libevent and
> libev despite symbol clashes.
> 
> Again, not trivial, but what you are trying to do is hardly typical.

All of these event loop things are contributed.  I don't think any of 
these extreme tricks to workaround your header clash problem will help 
with maintainability or source code clarity.  They are just not needed 
to be considered with, eg, libuv.

> Embedding libev, would enable a lot of other possible solutions as well.
> 
> A last comment on your style here - I have looked hard, but I still
> couldn't find a good explanation (or any explanation) of why you need to
> do it this way as opposed to separate builds or even backends for each
> event library, which might be faster, more efficient, and easier to extend
> than your current approach (compare e.g. how gtk+ selects backends, how
> opengl/opencl work and so on).
> 
> Nothing you said explains why you need to be able to switch event
> libraries at runtime, as opposed to e.g. select it at runtime by loading
> the correct backend library.
> 
> To say it bluntly, you come about as very tight-lipped about your needs
> and a bit arrogant, when considering that your programming skills are
> comparatively limited, given you are quite troubled by even simple
> abstraction problems in C...

Wow!  You are living down to my expectations :-)

> Both Harald and I have tried to help you, and it would suit you well if you
> would explain your problem a bit more and would use rational arguments
> instead of shouting at people...

No... you preferred to attack the user and find a way that nothing 
needed to change on your side, even when a comparable, more popular 
library has no problem with its header hygiene doing the same thing.

As I said I will just leave it unselectable for choose-at-runtime in 
cmake - and suggest people avoid using libev.

-Andy



More information about the libev mailing list