This chapter tells you how to build your own driver for erlang.
A driver in erlang is a library written in C, that is linked to the erlang emulator and called from erlang. Drivers can be used when C is more suitable than erlang, to speed things up, or to provide access to OS resources not directly accessible from erlang.
A driver can be dynamically loaded, as a shared library (DLL), or statically loaded, linked with the emulator when it is compiled and linked. Only dynamically loaded drivers are described here, statically linked drivers are beyond the scope of this chapter.
When a driver is loaded it is executed in the context of the emulator, shares the same memory and the same thread. This means that all operations in the driver must be non-blocking, and that any crash in the driver will bring the whole emulator down. In short: you have to be extremely careful!
The header file erl_driver.h
contains all types, macros
and prototypes needed for the driver.
The only exported function from the driver is
driver_init
. This function returns the driver_entry
structure that points to the other functions in the driver. The
driver_init function is declared with a macro
DRIVER_INIT(drivername)
. (This is because different OS's
have different names for it.)
The driver structure contains the name of the driver and some 15 function pointers. These pointers are called at different times by the emulator. Here is the declaration of driver_entry
:
typedef struct erl_drv_entry { int (*init)(void); /* called at system start up for statically linked drivers, and after loading for dynamically loaded drivers */ ErlDrvData (*start)(ErlDrvPort port, char *command); /* called when open_port/2 is invoked. return value -1 means failure. */ void (*stop)(ErlDrvData drv_data); /* called when port is closed, and when the emulator is halted. */ void (*output)(ErlDrvData drv_data, char *buf, int len); /* called when we have output from erlang to the port */ void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event); /* called when we have input from one of the driver's handles) */ void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event); /* called when output is possible to one of the driver's handles */ char *driver_name; /* name supplied as command in open_port XXX ? */ void (*finish)(void); /* called before unloading the driver - DYNAMIC DRIVERS ONLY */ void *handle; /* not used -- here for backwards compatibility */ int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen); /* "ioctl" for drivers - invoked by port_command/3) */ void (*timeout)(ErlDrvData drv_data); /* Handling of timeout in driver */ void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev); /* called when we have output from erlang to the port */ void (*ready_async)(ErlDrvData drv_data, ErlDrvThreadData thred_data); } ErlDrvEntry;
The erlang emulator has callbacks that the driver uses.
ei
is a small set of C routines to encode and decode
the erlang binary term format. It is just some small functions
that encodes and decodes terms in the binary format. It is
generally a lot faster than erl_interface
and suitable
to use in drivers and port programs.
The functions in ei is provided in library, with some header files. Each function is described in the reference manual.
...