抄书 Drivers in general

3.2 The driver
Although Erlang drivers in general may be beyond the scope of this document, a brief introduction seems to be in place.

3.2.1 Drivers in general
An Erlang driver is a native code module written in C (or assembler) which serves as an interface for some special operating system service. This is a general mechanism that is used throughout the Erlang emulator for all kinds of I/O. An Erlang driver can be dynamically linked (or loaded) to the Erlang emulator at runtime by using the erl_ddll Erlang module. Some of the drivers in OTP are however statically linked to the runtime system, but that's more an optimization than a necessity.

The driver data-types and the functions available to the driver writer are defined in the header file erl_driver.h (there is also an deprecated version called driver.h, don't use that one.) seated in Erlang's include directory (and in $ERL_TOP/erts/emulator/beam in the source code distribution). Refer to that file for function prototypes etc.

When writing a driver to make a communications protocol available to Erlang, one should know just about everything worth knowing about that particular protocol. All operation has to be non blocking and all possible situations should be accounted for in the driver. A non stable driver will affect and/or crash the whole Erlang runtime system, which is seldom what's wanted.

The emulator calls the driver in the following situations:

1. When the driver is loaded. This call-back has to have a special name and will inform the emulator of what call-backs should be used by returning a pointer to a ErlDrvEntry struct, which should be properly filled in (see below).

2. When a port to the driver is opened (by a open_port call from Erlang). This routine should set up internal data structures and return an opaque data entity of the type ErlDrvData, which is a data-type large enough to hold a pointer. The pointer returned by this function will be the first argument to all other call-backs concerning this particular port. It is usually called the port handle. The emulator only stores the handle and does never try to interpret it, why it can be virtually anything (well anything not larger than a pointer that is) and can point to anything if it is a pointer. Usually this pointer will refer to a structure holding information about the particular port, as i t does in our example.

3. When an Erlang process sends data to the port. The data will arrive as a buffer of bytes, the interpretation is not defined, but is up to the implementor. This call-back returns nothing to the caller, answers are sent to the caller as messages (using a routine called driver_output available to all drivers). There is also a way to talk in a synchronous way to drivers, described below. There can be an additional call-back function for handling data that is fragmented (sent in a deep io-list). That interface will get the data in a form suitable for Unix writev rather than in a single buffer. There is no need for a distribution driver to implement such a call-back, so we wont.

4. When a file descriptor is signaled for input. This call-back is called when the emulator detects input on a file descriptor which the driver has marked for monitoring by using the interface driver_select. The mechanism of driver select makes it possible to read non blocking from file descriptors by calling driver_select when reading is needed and then do the actual reading in this call-back (when reading is actually possible). The typical scenario is that driver_select is called when an Erlang process orders a read operation, and that this routine sends the answer when data is available on the file descriptor.

5. When a file descriptor is signaled for output. This call-back is called in a similar way as the previous, but when writing to a file descriptor is possible. The usual scenario is that Erlang orders writing on a file descriptor and that the driver calls driver_select. When the descriptor is ready for output, this call-back is called an the driver can try to send the output. There may of course be queuing involved in such operations, and there are some convenient queue routines available to the driver writer to use in such situations.

6. When a port is closed, either by an Erlang process or by the driver calling one of the driver_failure_XXX routines. This routine should clean up everything connected to one particular port. Note that when other call-backs call a driver_failure_XXX routine, this routine will be immediately called and the call-back routine issuing the error can make no more use of the data structures for the port, as this routine surely has freed all associated data and closed all file descriptors. If the queue utility available to driver writes is used, this routine will however not be called until the queue is empty.

7. When an Erlang process calls erlang:driver_control/2, which is a synchronous interface to drivers. The control interface is used to set driver options, change states of ports etc. We'll use this interface quite a lot in our example.

8. When a timer expires. The driver can set timers with the function driver_set_timer. When such timers expire, a specific call-back function is called. We will not use timers in our example.

9. When the whole driver is unloaded. Every resource allocated by the driver should be freed.


你可能感兴趣的:(erlang,unix,UP)