bionic (3) driver_entry.3erl.gz

Provided by: erlang-manpages_20.2.2+dfsg-1ubuntu2_all bug

NAME

       driver_entry - The driver-entry structure used by Erlang drivers.

DESCRIPTION

   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 cannot provide the same services as provided when  executing  Erlang  code,
       such  as  pre-emptive  scheduling  or  memory protection. If the driver callback function does not behave
       well, the whole VM will misbehave.

         * A driver callback that crash will crash the whole VM.

         * An erroneously implemented driver callback can cause a VM internal  state  inconsistency,  which  can
           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 doing lengthy work before returning degrades responsiveness  of  the  VM,  and  can
           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  can  occur
           because of lengthy work can also vary between Erlang/OTP releases.

       As  from  ERTS  5.9  (Erlang/OTP  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 ERTS version earlier than 5.9)  must  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, which 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 callback functions are called synchronously from the Erlang emulator. If they  take  too  long
       before  completing,  they  can  cause  time-outs  in the emulator. Use the queue or asynchronous calls if
       necessary, as the emulator must be responsive.

       The driver structure contains the driver name  and  some  15  function  pointers,  which  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 operating systems have different names for
       it.)

       When writing a driver in C++, the driver entry is to be of "C" linkage. One way to do this is to put  the
       following 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  through  --enable-static-drivers,   you   must   define
       STATIC_ERLANG_DRIVER before the DRIVER_INIT declaration.

   Note:
       Do  not  declare the driver_entry const. This because the emulator must modify the handle and the handle2
       fields. A statically allocated, and const-declared driver_entry can be located in read-only memory, which
       causes the emulator to crash.

DATA TYPES

       ErlDrvEntry

       typedef struct erl_drv_entry {
           int (*init)(void);          /* Called at system startup 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
                                          erlang:open_port/2 */
           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 time-out 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 must 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;

         int (*init)(void):
           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 is to return 0, or, if the driver cannot initialize, -1.

         ErlDrvData (*start)(ErlDrvPort port, char* command):
           Called when the driver is instantiated, when erlang:open_port/2 is called. The driver is to return  a
           number >= 0 or a pointer, or, if the driver cannot be started, one of three error codes:

           ERL_DRV_ERROR_GENERAL:
             General error, no error code

           ERL_DRV_ERROR_ERRNO:
             Error with error code in errno

           ERL_DRV_ERROR_BADARG:
             Error, badarg

           If an error code is returned, the port is not started.

         void (*stop)(ErlDrvData drv_data):
           Called  when  the  port  is  closed,  with erlang:port_close/1 or Port ! {self(), close}. Notice 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.

         void (*output)(ErlDrvData drv_data, char *buf, ErlDrvSizeT len):
           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  erlang:port_command/2.
           Depending  on how the port was opened, it is to be either a list of integers 0...255 or a binary. See
           erlang:open_port/2 and erlang:port_command/2.

         void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event):

         void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event):
           Called when a driver event (specified  in  parameter  event)  is  signaled.  This  is  used  to  help
           asynchronous drivers "wake up" when something occurs.

           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.)

           To  use  this  with threads and asynchronous routines, create a pipe on Unix and an Event on Windows.
           When the routine completes, write to the pipe (use SetEvent on Windows), this makes the emulator call
           ready_input or ready_output.

           False  events  can  occur.  That is, calls to ready_input or ready_output although no real events are
           signaled. In reality, it is rare (and OS-dependant), but a robust driver must nevertheless be able to
           handle such cases.

         char *driver_name:
           The  driver  name.  It  must  correspond  to the atom used in erlang:open_port/2, and the name of the
           driver library file (without the extension).

         void (*finish)(void):
           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 erl_ddll:unload_driver/1,  or  when  the  emulator
           halts.

         void *handle:
           This field is reserved for the emulator's internal use. The emulator will modify this field, so it is
           important that the driver_entry is not declared const.

         ErlDrvSSizeT (*control)(ErlDrvData drv_data, unsigned int command, char  *buf,  ErlDrvSizeT  len,  char
         **rbuf, ErlDrvSizeT rlen):
           A  special  routine  invoked with erlang:port_control/3. It works a little like an "ioctl" for Erlang
           drivers. The data specified to port_control/3 arrives in buf and len. The driver can send data  back,
           using *rbuf and rlen.

           This  is  the  fastest  way of calling a driver and get a response. It makes no 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 is to 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  differently
           depending on the port control flags (those that are set with erl_driver:set_port_control_flags).

           If  the flag is set to PORT_CONTROL_FLAG_BINARY, a binary is 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 erl_driver:driver_alloc_binary. This binary is freed automatically
           after  control  has  returned.  The  driver  can  retain  the  binary  for  read  only  access   with
           erl_driver:driver_binary_inc_refc  to  be freed later with erl_driver:driver_free_binary. It is never
           allowed to change the binary after control has returned. If *rbuf is set to NULL, an  empty  list  is
           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  erl_driver:driver_alloc.  The  buffer  is  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.

         void (*timeout)(ErlDrvData drv_data):
           Called   any   time   after   the   driver's   timer   reaches   0.   The  timer  is  activated  with
           erl_driver:driver_set_timer. No priorities or ordering exist among drivers,  so  if  several  drivers
           time out at the same time, anyone of them is called first.

         void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev):
           Called  whenever  the  port is written to. If it is NULL, the output function is called instead. This
           function is faster than output, as it takes an ErlIOVec directly, which requires no  copying  of  the
           data. The port is to be in binary mode, see erlang:open_port/2.

           ErlIOVec  contains  both a SysIOVec, suitable for writev, and one or more binaries. If these binaries
           are to be retained when the driver returns from outputv, they can  be  queued  (using,  for  example,
           erl_driver:driver_enq_bin) or, if they are kept in a static or global variable, the reference counter
           can be incremented.

         void (*ready_async)(ErlDrvData drv_data, ErlDrvThreadData thread_data):
           Called  after  an  asynchronous  call  has  completed.  The  asynchronous  call   is   started   with
           erl_driver:driver_async.  This  function is called from the Erlang emulator thread, as opposed to the
           asynchronous function, which is called in some thread (if multi-threading is enabled).

         void (*flush)(ErlDrvData drv_data):
           Called when the port is about to be closed, and there is data  in  the  driver  queue  that  must  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):
           Called from erlang:port_call/3. It works a lot like the control callback, 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 is to 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 erl_driver:driver_alloc. This memory is 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 throws a BAD_ARG.

         void (*event)(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_data):
           Intentionally left undocumented.

         int extended_marker:
           This  field  is  either  to be equal to ERL_DRV_EXTENDED_MARKER or 0. An old driver (not aware of the
           extended driver interface) is to set this field to 0. If this field is 0, all  the  following  fields
           must also be 0, or NULL if it is a pointer field.

         int major_version:
           This   field   is   to   equal   ERL_DRV_EXTENDED_MAJOR_VERSION   if   field  extended_marker  equals
           ERL_DRV_EXTENDED_MARKER.

         int minor_version:
           This  field  is   to   equal   ERL_DRV_EXTENDED_MINOR_VERSION   if   field   extended_marker   equals
           ERL_DRV_EXTENDED_MARKER.

         int driver_flags:
           This  field  is  used to pass driver capability and other information to the runtime system. If field
           extended_marker equals ERL_DRV_EXTENDED_MARKER, it is to contain 0 or driver  flags  (ERL_DRV_FLAG_*)
           OR'ed bitwise. The following driver flags exist:

           ERL_DRV_FLAG_USE_PORT_LOCKING:
             The  runtime  system  uses port-level locking on all ports executing this driver instead of driver-
             level locking when the driver is run in a runtime system with SMP support.  For  more  information,
             see erl_driver.

           ERL_DRV_FLAG_SOFT_BUSY:
             Marks that driver instances can handle being called in the output and/or outputv callbacks although
             a driver instance has marked itself as busy (see erl_driver:set_busy_port). As from ERTS 5.7.4 this
             flag is required for drivers used by the Erlang distribution (the behavior has always been required
             by drivers used by the distribution).

           ERL_DRV_FLAG_NO_BUSY_MSGQ:
             Disables   busy    port    message    queue    functionality.    For    more    information,    see
             erl_driver:erl_drv_busy_msgq_limits.

           ERL_DRV_FLAG_USE_INIT_ACK:
             When  this flag is specified, the linked-in driver must manually acknowledge that the port has been
             successfully started using erl_driver:erl_drv_init_ack(). This allows the implementor to  make  the
             erlang:open_port exit with badarg after some initial asynchronous initialization has been done.

         void *handle2:
           This  field  is  reserved for the emulator's internal use. The emulator modifies this field, so it is
           important that the driver_entry is not declared const.

         void (*process_exit)(ErlDrvData drv_data, ErlDrvMonitor *monitor):
           Called when a monitored process exits. The drv_data is the data associated with the  port  for  which
           the process is monitored (using erl_driver:driver_monitor_process) and the monitor corresponds to the
           ErlDrvMonitor  structure  filled  in  when  creating  the  monitor.  The  driver  interface  function
           erl_driver:driver_get_monitored_process can be used to retrieve the process ID of the exiting process
           as an ErlDrvTermData.

         void (*stop_select)(ErlDrvEvent event, void* reserved):
           Called on behalf of erl_driver: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 is to be ignored.

           In contrast to most of the other callback 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 can even be closed at the time stop_select is called. But it
           can also be the case that stop_select is called directly by erl_driver:driver_select.

           It is not allowed to call any functions in the driver API from stop_select. This strict limitation is
           because the volatile context that stop_select can be called.

SEE ALSO

       erl_driver(3erl), erlang(3erl), erl_ddll(3erl)