Wednesday, February 15, 2012

libev for common lisp.

tl;dr I generated some bindings to libev. Check it out

This is something me or Slava have been meaning to get to for a while now. We’ve wanted a nice event library to replace the naive zmq_poll loop we currently have in a super secret project at work. It’s not really top secret and will be open sourced very soon. The reasoning was that we would have re-implement a subset of an event library. libev was the natural choice. It’s really well respected and has great documentation.

Approach

Common lisp has a really awesome portable (CL quite a implementations) FFI aptly called CFFI. Now writing the CFFI declarations is a pain in the ass. Thankfully (or unfortunately) there are some interface generation tools. CFFI mentions 2.

Slava took a shot at using Verrazano and didn’t have much luck or didn’t like the result. I decided to give SWIG a try. SWIG slurps in an interface file, which is nothing more than glorified C and spits out bindings. Let’s take a look at the one I used.

Interface file

%module ev
#define EV_MINPRI -2
#define EV_MAXPRI 2
%include "ev.h" %{ %}
%insert(lisphead)%{(in-package :ev)
(define-foreign-library libev 
  (:unix (:or "libev.4.dylib" "libev.4.so" 
              "libev.dylib" "libev.so"))
  (t (:default "libev")))

(use-foreign-library libev)%}

WARNING: This produces broken code.

It might be strange to see the EV_MINPRI and EV_MAXPRI in the interface file and you might ask yourself:

Aren’t those constants defined in libev?

Why yes they are! Poorly. Okay not really poorly but SWIG doesn’t like ternary and the constants can have different values depending on different options. So we can define them up front and SWIG will ignore the constants in the header.

You might have noticed some lisp in the interface file. SWIG does not generate the code needed to load the library, only to use it. I wish it would have had some option but that’s quite already it has the ability to just insert whatever we want into the generated output before any of the generated declarations. So I’ve put CFFI code for actually loading the library to use.

The problem area

SWIG generates a helper to define anonymous enums. libev’s has an anonymous enum with members that refer to other member’s values. The helper generates the enum with read time eval macros. You cannot refer to another member at read time :-\ CL does not like this. Here are the changes I made to the enum.

(EV_TIMEOUT #.TIMER)

to

(EV_TIMER #.#x00000100)

and

(EV_IO #.EV_READ)

to

(EV_IO #.#x01)

And with that we have some output that will compile and is useable.

Next steps

The interface is straight CFFI and not very lispy. So wrapping this all up into a nice API is probably the next step.

If anyone has any ideas on how to generate better code with SWIG please let me know. This has been my first time using such a tool.

Get the code

I have the library packaged up so you can download it and shove it into your asdf source registry. The documentation is really light and there are no tests (I JUST COMPLETED THIS). So go ahead and grab it from my github repo if you’re feeling adventurous.

Thursday, February 9, 2012 Monday, February 6, 2012 Saturday, February 4, 2012
A WIP grab of a slide in a deck for a presentation I’m going to give.

A WIP grab of a slide in a deck for a presentation I’m going to give.

Wednesday, February 1, 2012