driver_entry
Warning!
Use this functionality with extreme care!
A driver callback is executed as a direct extension of the native code of the VM. Execution is not made in a safe environment. The VM can not provide the same services as provided when executing Erlang code, such as preemptive scheduling or memory protection. If the driver callback function doesn't behave well, the whole VM will misbehave.
A driver callback that crash will crash the whole VM.
An erroneously implemented driver callback might cause a VM internal state inconsistency which may cause a crash of the VM, or miscellaneous misbehaviors of the VM at any point after the call to the driver callback.
A driver callback that do lengthy work before returning will degrade responsiveness of the VM, and may cause miscellaneous strange behaviors. Such strange behaviors include, but are not limited to, extreme memory usage, and bad load balancing between schedulers. Strange behaviors that might occur due to lengthy work may also vary between OTP releases.
As of erts version 5.9 (OTP release R15B) the driver interface has been changed with larger types for the callbacks output, control and call. See driver version management in erl_driver.
Note!
Old drivers (compiled with an erl_driver.h from an
      earlier erts version than 5.9) have to be updated and have
      to use the extended interface (with
      version management
      ).
The driver_entry structure is a C struct that all erlang
      drivers define. It contains entry points for the erlang driver
      that are called by the erlang emulator when erlang code accesses
      the driver.
      
       
      The erl_driver driver
      API functions need a port handle
      that identifies the driver instance (and the port in the
      emulator). This is only passed to the start function, but
      not to the other functions. The start function returns a
      driver-defined handle that is passed to the other functions. A
      common practice is to have the start function allocate
      some application-defined structure and stash the port
      handle in it, to use it later with the driver API functions.
The driver call-back functions are called synchronously from the erlang emulator. If they take too long before completing, they can cause timeouts in the emulator. Use the queue or asynchronous calls if necessary, since the emulator must be responsive.
The driver structure contains the name of the driver and some 15 function pointers. These pointers are called at different times by the emulator.
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.)
When writing a driver in C++, the driver entry should be of
      "C" linkage. One way to do this is to put this line
      somewhere before the driver entry:
      extern "C" DRIVER_INIT(drivername);.
When the driver has passed the driver_entry over to
      the emulator, the driver is not allowed to modify the
      driver_entry.
If compiling a driver for static inclusion via --enable-static-drivers you have to define STATIC_ERLANG_DRIVER before the DRIVER_INIT declaration.
Note!
Do not declare the driver_entry const. This since the emulator needs to
        modify the handle, and the handle2
        fields. A statically allocated, and const
        declared driver_entry may be located in
        read only memory which will cause the emulator
        to crash.
DATA TYPES
typedef struct erl_drv_entry {
    int (*init)(void);          /* called at system start up for statically
                                   linked drivers, and after loading for
                                   dynamically loaded drivers */ 
#ifndef ERL_SYS_DRV
    ErlDrvData (*start)(ErlDrvPort port, char *command);
                                /* called when open_port/2 is invoked.
                                   return value -1 means failure. */
#else
    ErlDrvData (*start)(ErlDrvPort port, char *command, SysDriverOpts* opts);
                                /* special options, only for system driver */
#endif
    void (*stop)(ErlDrvData drv_data);
                                /* called when port is closed, and when the
                                   emulator is halted. */
    void (*output)(ErlDrvData drv_data, char *buf, ErlDrvSizeT 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;               /* Reserved -- Used by emulator internally */
    ErlDrvSSizeT (*control)(ErlDrvData drv_data, unsigned int command,
                            char *buf, ErlDrvSizeT len,
			    char **rbuf, ErlDrvSizeT rlen);
                                /* "ioctl" for drivers - invoked by 
                                   port_control/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 thread_data);
    void (*flush)(ErlDrvData drv_data);
                                /* called when the port is about to be 
                                   closed, and there is data in the 
                                   driver queue that needs to be flushed
                                   before 'stop' can be called */
    ErlDrvSSizeT (*call)(ErlDrvData drv_data, unsigned int command,
                         char *buf, ErlDrvSizeT len,
			 char **rbuf, ErlDrvSizeT rlen, unsigned int *flags);
                                /* Works mostly like 'control', a synchronous
                                   call into the driver. */
    void (*event)(ErlDrvData drv_data, ErlDrvEvent event,
                  ErlDrvEventData event_data);
                                /* Called when an event selected by 
                                   driver_event() has occurred */
    int extended_marker;        /* ERL_DRV_EXTENDED_MARKER */
    int major_version;          /* ERL_DRV_EXTENDED_MAJOR_VERSION */
    int minor_version;          /* ERL_DRV_EXTENDED_MINOR_VERSION */
    int driver_flags;           /* ERL_DRV_FLAGs */
    void *handle2;              /* Reserved -- Used by emulator internally */
    void (*process_exit)(ErlDrvData drv_data, ErlDrvMonitor *monitor);
                                /* Called when a process monitor fires */
    void (*stop_select)(ErlDrvEvent event, void* reserved);
                                /* Called to close an event object */
 } ErlDrvEntry;
    
    
    This is called directly after the driver has been loaded by
          erl_ddll:load_driver/2. (Actually when the driver is
          added to the driver list.) The driver should return 0, or if
          the driver can't initialize, -1.
This is called when the driver is instantiated, when
          open_port/2 is called. The driver should return a
          number >= 0 or a pointer, or if the driver can't be started,
          one of three error codes should be returned:
ERL_DRV_ERROR_GENERAL - general error, no error code
ERL_DRV_ERROR_ERRNO - error with error code in erl_errno
ERL_DRV_ERROR_BADARG - error, badarg
If an error code is returned, the port isn't started.
This is called when the port is closed, with
          port_close/1 or Port ! {self(), close}. Note
          that terminating the port owner process also closes the
          port. If drv_data is a pointer to memory allocated in
	  start, then stop is the place to deallocate that
	  memory.
This is called when an erlang process has sent data to the
          port. The data is pointed to by buf, and is
          len bytes.  Data is sent to the port with Port ! {self(), {command, Data}}, or with
          port_command/2. Depending on how the port was opened,
          it should be either a list of integers 0...255 or a
          binary. See open_port/3 and port_command/2.
This is called when a driver event (given in the
          event parameter) is signaled. This is used to help
          asynchronous drivers "wake up" when something happens.
On unix the event is a pipe or socket handle (or
          something that the select system call understands).
On Windows the event is an Event or Semaphore (or
          something that the WaitForMultipleObjects API
          function understands). (Some trickery in the emulator allows
          more than the built-in limit of 64 Events to be used.)
On Enea OSE the event is one or more signals that can
	  be retrieved using erl_drv_ose_get_signal.
To use this with threads and asynchronous routines, create a
          pipe on unix, an Event on Windows or a unique signal number on
	  Enea OSE. When the routine
          completes, write to the pipe (use SetEvent on
          Windows or send a message to the emulator process on Enea OSE),
	  this will make the emulator call
          ready_input or ready_output.
Spurious events may happen. That is, calls to ready_input
          or ready_output even though no real events are signaled. In
          reality it should be rare (and OS dependant), but a robust driver
          must nevertheless be able to handle such cases.
This is the name of the driver, it must correspond to the
          atom used in open_port, and the name of the driver
          library file (without the extension).
This function is called by the erl_ddll driver when the
          driver is unloaded. (It is only called in dynamic drivers.)
The driver is only unloaded as a result of calling
          unload_driver/1, or when the emulator halts.
This field is reserved for the emulator's internal use. The
          emulator will modify this field; therefore, it is important
          that the driver_entry isn't declared const.
This is a special routine invoked with the erlang function
          port_control/3. It works a little like an "ioctl" for
          erlang drivers. The data given to port_control/3
          arrives in buf and len. The driver may send
          data back, using *rbuf and rlen.
This is the fastest way of calling a driver and get a response. It won't make any context switch in the erlang emulator, and requires no message passing. It is suitable for calling C function to get faster execution, when erlang is too slow.
If the driver wants to return data, it should return it in
          rbuf. When control is called,
          *rbuf points to a default buffer of rlen bytes, which
          can be used to return data. Data is returned different depending on
          the port control flags (those that are set with
          set_port_control_flags).
          
If the flag is set to PORT_CONTROL_FLAG_BINARY,
           a binary will be returned. Small binaries can be returned by writing
           the raw data into the default buffer. A binary can also be
           returned by setting *rbuf to point to a binary allocated with
          driver_alloc_binary.
          This binary will be freed automatically after control has returned.
          The driver can retain the binary for read only access with
          driver_binary_inc_refc to be freed later with
          driver_free_binary.
          It is never allowed to alter the binary after control has returned.
          If *rbuf is set to NULL, an empty list will be returned.
          
If the flag is set to 0, data is returned as a
          list of integers. Either use the default buffer or set
          *rbuf to point to a larger buffer allocated with
          driver_alloc.
          The buffer will be freed automatically after control has returned.
Using binaries is faster if more than a few bytes are returned.
The return value is the number of bytes returned in
          *rbuf.
This function is called any time after the driver's timer
          reaches 0. The timer is activated with
          driver_set_timer. There are no priorities or ordering
          among drivers, so if several drivers time out at the same
          time, any one of them is called first.
This function is called whenever the port is written to. If
          it is NULL, the output function is called
          instead. This function is faster than output, because
          it takes an ErlIOVec directly, which requires no
          copying of the data. The port should be in binary mode, see
          open_port/2.
The ErlIOVec contains both a SysIOVec,
          suitable for writev, and one or more binaries. If
          these binaries should be retained, when the driver returns
          from outputv, they can be queued (using driver_enq_bin
          for instance), or if they are kept in a static or global
          variable, the reference counter can be incremented.
This function is called after an asynchronous call has completed. The asynchronous call is started with driver_async. This function is called from the erlang emulator thread, as opposed to the asynchronous function, which is called in some thread (if multithreading is enabled).
This function is called from erlang:port_call/3. It
          works a lot like the control call-back, but uses the
          external term format for input and output.
command is an integer, obtained from the call from
          erlang (the second argument to erlang:port_call/3).
buf and len provide the arguments to the call
          (the third argument to erlang:port_call/3). They can
          be decoded using ei functions.
rbuf points to a return buffer, rlen bytes
          long. The return data should be a valid erlang term in the
          external (binary) format. This is converted to an erlang
          term and returned by erlang:port_call/3 to the
          caller.  If more space than rlen bytes is needed to
          return data, *rbuf can be set to memory allocated with
          driver_alloc. This memory will be freed automatically
          after call has returned.
The return value is the number of bytes returned in
          *rbuf. If ERL_DRV_ERROR_GENERAL is returned
          (or in fact, anything < 0), erlang:port_call/3 will
          throw a BAD_ARG.
Intentionally left undocumented.
          This field should either be equal to ERL_DRV_EXTENDED_MARKER
          or 0. An old driver (not aware of the extended driver
          interface) should set this field to 0. If this field is
          equal to 0, all the fields following this field also
          have to be 0, or NULL in case it is a
          pointer field.
        
This field should equal ERL_DRV_EXTENDED_MAJOR_VERSION if
          the extended_marker field equals
          ERL_DRV_EXTENDED_MARKER.
          This field should equal ERL_DRV_EXTENDED_MINOR_VERSION if
          the extended_marker field equals
          ERL_DRV_EXTENDED_MARKER.
        
This field is used to pass driver capability and other
	  information to the runtime system. If the
	  extended_marker field equals ERL_DRV_EXTENDED_MARKER,
	  it should contain 0 or  driver flags (ERL_DRV_FLAG_*)
	  ored bitwise. Currently the following driver flags exist:
        
ERL_DRV_FLAG_USE_PORT_LOCKINGERL_DRV_FLAG_SOFT_BUSYERL_DRV_FLAG_NO_BUSY_MSGQ
          This field is reserved for the emulator's internal use. The
          emulator will modify this field; therefore, it is important
          that the driver_entry isn't declared const.
        
This callback is called when a monitored process exits. The
          drv_data is the data associated with the port for which
          the process is monitored (using driver_monitor_process)
          and the monitor corresponds to the ErlDrvMonitor 
          structure filled
          in when creating the monitor. The driver interface function
          driver_get_monitored_process
          can be used to retrieve the process id of the exiting process as
          an ErlDrvTermData.
This function is called on behalf of driver_select when it is safe to close an event object.
A typical implementation on Unix is to do
           close((int)event).
Argument reserved is intended for future use and should be ignored.
In contrast to most of the other call-back functions,
           stop_select is called independent of any port. No
           ErlDrvData argument is passed to the function. No
           driver lock or port lock is guaranteed to be held. The port that
           called driver_select might even be closed at the
           time stop_select is called. But it could also be
           the case that stop_select is called directly by
           driver_select.
It is not allowed to call any functions in the
           driver API from
           stop_select. This strict limitation is due to the
           volatile context that stop_select may be called.
SEE ALSO
erl_driver(3), erl_ddll(3), erlang(3), kernel(3)