aboutsummaryrefslogtreecommitdiffstats
path: root/erts/doc/src/driver_entry.xml
diff options
context:
space:
mode:
Diffstat (limited to 'erts/doc/src/driver_entry.xml')
-rw-r--r--erts/doc/src/driver_entry.xml647
1 files changed, 353 insertions, 294 deletions
diff --git a/erts/doc/src/driver_entry.xml b/erts/doc/src/driver_entry.xml
index bad20d6343..fd7d6223f6 100644
--- a/erts/doc/src/driver_entry.xml
+++ b/erts/doc/src/driver_entry.xml
@@ -4,7 +4,7 @@
<cref>
<header>
<copyright>
- <year>2001</year><year>2015</year>
+ <year>2001</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,55 +33,64 @@
<file>driver_entry.xml</file>
</header>
<lib>driver_entry</lib>
- <libsummary>The driver-entry structure used by erlang drivers.</libsummary>
+ <libsummary>The driver-entry structure used by Erlang drivers.</libsummary>
<description>
<marker id="WARNING"/>
- <warning><p><em>Use this functionality with extreme care!</em></p>
+ <warning>
+ <p><em>Use this functionality with extreme care.</em></p>
<p>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 <em>not</em> 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.</p>
- <list>
- <item><p>A driver callback that crash will crash the whole VM.</p></item>
- <item><p>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.</p></item>
- <item><p>A driver callback that do
- <seealso marker="erl_driver#lengthy_work">lengthy work</seealso>
- 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.</p></item>
+ native code of the VM. Execution is not made in a safe environment.
+ The VM <em>cannot</em> 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.</p>
+ <list type="bulleted">
+ <item>
+ <p>A driver callback that crash will crash the whole VM.</p>
+ </item>
+ <item>
+ <p>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.</p>
+ </item>
+ <item>
+ <p>A driver callback doing
+ <seealso marker="erl_driver#lengthy_work">lengthy work</seealso>
+ 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.</p>
+ </item>
</list>
- </warning>
- <p>
- As of erts version 5.9 (OTP release R15B) the driver interface
+ </warning>
+
+ <p>As from ERTS 5.9 (Erlang/OTP R15B) the driver interface
has been changed with larger types for the callbacks
- <seealso marker="#output">output</seealso>,
- <seealso marker="#control">control</seealso> and
- <seealso marker="#call">call</seealso>.
+ <seealso marker="#output"><c>output</c></seealso>,
+ <seealso marker="#control"><c>control</c></seealso>, and
+ <seealso marker="#call"><c>call</c></seealso>.
See driver <seealso marker="erl_driver#version_management">
version management</seealso> in
- <seealso marker="erl_driver">erl_driver</seealso>.
- </p>
+ <seealso marker="erl_driver"><c>erl_driver</c></seealso>.</p>
+
<note>
<p>Old drivers (compiled with an <c>erl_driver.h</c> from an
- earlier erts version than 5.9) have to be updated and have
- to use the extended interface (with
- <seealso marker="erl_driver#version_management">version management
- </seealso>).</p>
+ ERTS version earlier than 5.9) must be updated and have
+ to use the extended interface (with
+ <seealso marker="erl_driver#version_management">version management
+ </seealso>).</p>
</note>
- <p>The <c>driver_entry</c> 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
+
+ <p>The <c>driver_entry</c> 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.</p>
- <p>
- <marker id="emulator"></marker>
- The <seealso marker="erl_driver">erl_driver</seealso> driver
+
+ <p><marker id="emulator"></marker>
+ The <seealso marker="erl_driver"><c>erl_driver</c></seealso> driver
API functions need a port handle
that identifies the driver instance (and the port in the
emulator). This is only passed to the <c>start</c> function, but
@@ -90,413 +99,463 @@
common practice is to have the <c>start</c> function allocate
some application-defined structure and stash the <c>port</c>
handle in it, to use it later with the driver API functions.</p>
- <p>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
+
+ <p>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.</p>
- <p>The driver structure contains the name of the driver and some
- 15 function pointers. These pointers are called at different
+
+ <p>The driver structure contains the driver name and some
+ 15 function pointers, which are called at different
times by the emulator.</p>
+
<p>The only exported function from the driver is
<c>driver_init</c>. This function returns the <c>driver_entry</c>
structure that points to the other functions in the driver. The
- <c>driver_init</c> function is declared with a macro
- <c>DRIVER_INIT(drivername)</c>. (This is because different OS's
- have different names for it.)</p>
- <p>When writing a driver in C++, the driver entry should be of
- <c>"C"</c> linkage. One way to do this is to put this line
- somewhere before the driver entry:
- <c>extern "C" DRIVER_INIT(drivername);</c>.</p>
+ <c>driver_init</c> function is declared with a macro,
+ <c>DRIVER_INIT(drivername)</c>. (This is because different
+ operating systems have different names for it.)</p>
+
+ <p>When writing a driver in C++, the driver entry is to be of
+ <c>"C"</c> linkage. One way to do this is to put the
+ following line somewhere before the driver entry:</p>
+
+ <pre>
+extern "C" DRIVER_INIT(drivername);</pre>
+
<p>When the driver has passed the <c>driver_entry</c> over to
the emulator, the driver is <em>not</em> allowed to modify the
<c>driver_entry</c>.</p>
- <p>If compiling a driver for static inclusion via --enable-static-drivers you
- have to define STATIC_ERLANG_DRIVER before the DRIVER_INIT declaration.</p>
+
+ <p>If compiling a driver for static inclusion through
+ <c>--enable-static-drivers</c>, you must define
+ <c>STATIC_ERLANG_DRIVER</c> before the <c>DRIVER_INIT</c> declaration.</p>
+
<note>
- <p>Do <em>not</em> declare the <c>driver_entry</c> <c>const</c>. This since the emulator needs to
- modify the <c>handle</c>, and the <c>handle2</c>
- fields. A statically allocated, and <c>const</c>
- declared <c>driver_entry</c> may be located in
- read only memory which will cause the emulator
- to crash.</p>
+ <p>Do <em>not</em> declare the <c>driver_entry</c> <c>const</c>.
+ This because the emulator must
+ modify the <c>handle</c> and the <c>handle2</c>
+ fields. A statically allocated, and <c>const</c>-declared
+ <c>driver_entry</c> can be located in
+ read-only memory, which causes the emulator to crash.</p>
</note>
</description>
<section>
- <title>DATA TYPES</title>
- <taglist>
- <tag><em>ErlDrvEntry</em></tag>
- <item>
- <p/>
+ <title>Data Types</title>
+ <p><c>ErlDrvEntry</c></p>
<code type="none">
typedef struct erl_drv_entry {
- int (*init)(void); /* called at system start up for statically
+ int (*init)(void); /* Called at system startup for statically
linked drivers, and after loading for
- dynamically loaded drivers */
-
+ 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. */
+ /* 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 */
+ /* Special options, only for system driver */
#endif
void (*stop)(ErlDrvData drv_data);
- /* called when port is closed, and when the
- emulator is halted. */
+ /* 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
+ /* 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
+ /* 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
+ /* 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 */
+ 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
+ /* "ioctl" for drivers - invoked by
port_control/3 */
- void (*timeout)(ErlDrvData drv_data); /* Handling of timeout in driver */
+ 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
+ /* 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
+ /* 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 */
+ call into the driver */
+ void* unused_event_callback;
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 *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;
- </code>
- <p/>
+ } ErlDrvEntry;</code>
<taglist>
- <tag><marker id="init"/>int (*init)(void)</tag>
- <item>
- <p>This is called directly after the driver has been loaded by
- <c>erl_ddll:load_driver/2</c>. (Actually when the driver is
- added to the driver list.) The driver should return 0, or if
- the driver can't initialize, -1.</p>
+ <tag><marker id="init"/><c>int (*init)(void)</c></tag>
+ <item>
+ <p>Called directly after the driver has been loaded by
+ <seealso marker="kernel:erl_ddll#load_driver/2">
+ <c>erl_ddll:load_driver/2</c></seealso> (actually when the driver is
+ added to the driver list). The driver is to return <c>0</c>, or, if
+ the driver cannot initialize, <c>-1</c>.</p>
</item>
- <tag><marker id="start"/>ErlDrvData (*start)(ErlDrvPort port, char* command)</tag>
+ <tag><marker id="start"/>
+ <c>ErlDrvData (*start)(ErlDrvPort port, char* command)</c></tag>
<item>
- <p>This is called when the driver is instantiated, when
- <c>open_port/2</c> is called. The driver should return a
- number &gt;= 0 or a pointer, or if the driver can't be started,
- one of three error codes should be returned:</p>
- <p>ERL_DRV_ERROR_GENERAL - general error, no error code</p>
- <p>ERL_DRV_ERROR_ERRNO - error with error code in <c>errno</c></p>
- <p>ERL_DRV_ERROR_BADARG - error, badarg</p>
- <p>If an error code is returned, the port isn't started.</p>
+ <p>Called when the driver is instantiated, when
+ <seealso marker="erlang#open_port/2">
+ <c>erlang:open_port/2</c></seealso> is called.
+ The driver is to return a number &gt;= 0 or a pointer, or, if the
+ driver cannot be started, one of three error codes:</p>
+ <taglist>
+ <tag><c>ERL_DRV_ERROR_GENERAL</c></tag>
+ <item>General error, no error code</item>
+ <tag><c>ERL_DRV_ERROR_ERRNO</c></tag>
+ <item>Error with error code in <c>errno</c></item>
+ <tag><c>ERL_DRV_ERROR_BADARG</c></tag>
+ <item>Error, <c>badarg</c></item>
+ </taglist>
+ <p>If an error code is returned, the port is not started.</p>
</item>
- <tag><marker id="stop"/>void (*stop)(ErlDrvData drv_data)</tag>
+ <tag><marker id="stop"/><c>void (*stop)(ErlDrvData drv_data)</c></tag>
<item>
- <p>This is called when the port is closed, with
- <c>port_close/1</c> or <c>Port ! {self(), close}</c>. Note
- that terminating the port owner process also closes the
+ <p>Called when the port is closed, with
+ <seealso marker="erlang#port_close/1">
+ <c>erlang:port_close/1</c></seealso> or <c>Port ! {self(), close}</c>.
+ Notice that terminating the port owner process also closes the
port. If <c>drv_data</c> is a pointer to memory allocated in
- <c>start</c>, then <c>stop</c> is the place to deallocate that
- memory.</p>
+ <c>start</c>, then <c>stop</c> is the place to deallocate that
+ memory.</p>
</item>
- <tag><marker id="output"/>void (*output)(ErlDrvData drv_data, char *buf, ErlDrvSizeT len)</tag>
+ <tag><marker id="output"/>
+ <c>void (*output)(ErlDrvData drv_data, char *buf, ErlDrvSizeT len)</c>
+ </tag>
<item>
- <p>This is called when an erlang process has sent data to the
- port. The data is pointed to by <c>buf</c>, and is
- <c>len</c> bytes. Data is sent to the port with <c>Port ! {self(), {command, Data}}</c>, or with
- <c>port_command/2</c>. Depending on how the port was opened,
- it should be either a list of integers 0...255 or a
- binary. See <c>open_port/3</c> and <c>port_command/2</c>.</p>
+ <p>Called when an Erlang process has sent data to the port. The data is
+ pointed to by <c>buf</c>, and is <c>len</c> bytes. Data is sent to
+ the port with <c>Port ! {self(), {command, Data}}</c> or with
+ <c>erlang:port_command/2</c>. Depending on how the port was
+ opened, it is to be either a list of integers <c>0...255</c> or a
+ binary. See <seealso marker="erlang#open_port/2">
+ <c>erlang:open_port/2</c></seealso> and
+ <seealso marker="erlang#port_command/2">
+ <c>erlang:port_command/2</c></seealso>.</p>
</item>
-
- <tag><marker id="ready_input"/>void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event)</tag>
- <item/>
- <tag><marker id="ready_output"/>void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event)</tag>
+ <tag><marker id="ready_input"/>
+ <c>void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event)</c>
+ </tag>
+ <item></item>
+ <tag><marker id="ready_output"/>
+ <c>void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event)</c>
+ </tag>
<item>
- <p>This is called when a driver event (given in the
- <c>event</c> parameter) is signaled. This is used to help
- asynchronous drivers "wake up" when something happens.</p>
- <p>On unix the <c>event</c> is a pipe or socket handle (or
+ <p>Called when a driver event (specified in parameter
+ <c>event</c>) is signaled. This is used to help
+ asynchronous drivers "wake up" when something occurs.</p>
+ <p>On Unix the <c>event</c> is a pipe or socket handle (or
something that the <c>select</c> system call understands).</p>
- <p>On Windows the <c>event</c> is an Event or Semaphore (or
- something that the <c>WaitForMultipleObjects</c> API
+ <p>On Windows the <c>event</c> is an <c>Event</c> or <c>Semaphore</c>
+ (or something that the <c>WaitForMultipleObjects</c> API
function understands). (Some trickery in the emulator allows
more than the built-in limit of 64 <c>Events</c> to be used.)</p>
- <p>On Enea OSE the <c>event</c> is one or more signals that can
- be retrieved using <seealso marker="ose:ose_erl_driver#erl_drv_ose_get_signal">erl_drv_ose_get_signal</seealso>.</p>
<p>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
+ pipe on Unix and an <c>Event</c> on Windows. When the routine
completes, write to the pipe (use <c>SetEvent</c> on
- Windows or send a message to the emulator process on Enea OSE),
- this will make the emulator call
+ Windows), this makes the emulator call
<c>ready_input</c> or <c>ready_output</c>.</p>
- <p>Spurious events may happen. That is, calls to <c>ready_input</c>
- or <c>ready_output</c> even though no real events are signaled. In
- reality it should be rare (and OS dependant), but a robust driver
+ <p>False events can occur. That is, calls to <c>ready_input</c>
+ or <c>ready_output</c> 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.</p>
</item>
- <tag><marker id="driver_name"/>char *driver_name</tag>
+ <tag><marker id="driver_name"/><c>char *driver_name</c></tag>
<item>
- <p>This is the name of the driver, it must correspond to the
- atom used in <c>open_port</c>, and the name of the driver
+ <p>The driver name. It must correspond to the atom used in
+ <seealso marker="erlang#open_port/2">
+ <c>erlang:open_port/2</c></seealso>, and the name of the driver
library file (without the extension).</p>
</item>
- <tag><marker id="finish"/>void (*finish)(void)</tag>
+ <tag><marker id="finish"/><c>void (*finish)(void)</c></tag>
<item>
- <p>This function is called by the <c>erl_ddll</c> driver when the
+ <p>Called by the <c>erl_ddll</c> driver when the
driver is unloaded. (It is only called in dynamic drivers.)</p>
<p>The driver is only unloaded as a result of calling
- <c>unload_driver/1</c>, or when the emulator halts.</p>
+ <seealso marker="kernel:erl_ddll#unload_driver/1">
+ <c>erl_ddll:unload_driver/1</c></seealso>,
+ or when the emulator halts.</p>
</item>
- <tag>void *handle</tag>
+ <tag><c>void *handle</c></tag>
<item>
<p>This field is reserved for the emulator's internal use. The
- emulator will modify this field; therefore, it is important
- that the <c>driver_entry</c> isn't declared <c>const</c>.</p>
+ emulator will modify this field, so it is important
+ that the <c>driver_entry</c> is not declared <c>const</c>.</p>
</item>
- <tag><marker id="control"></marker>ErlDrvSSizeT (*control)(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen)</tag>
+ <tag><marker id="control"></marker>
+ <c>ErlDrvSSizeT (*control)(ErlDrvData drv_data, unsigned int command,
+ char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen)</c></tag>
<item>
- <p>This is a special routine invoked with the erlang function
- <c>port_control/3</c>. It works a little like an "ioctl" for
- erlang drivers. The data given to <c>port_control/3</c>
- arrives in <c>buf</c> and <c>len</c>. The driver may send
+ <p>A special routine invoked with
+ <seealso marker="erlang#port_control/3">
+ <c>erlang:port_control/3</c></seealso>.
+ It works a little like an "ioctl" for
+ Erlang drivers. The data specified to <c>port_control/3</c>
+ arrives in <c>buf</c> and <c>len</c>. The driver can send
data back, using <c>*rbuf</c> and <c>rlen</c>.</p>
<p>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
+ 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.</p>
- <p>If the driver wants to return data, it should return it in
+ <p>If the driver wants to return data, it is to return it in
<c>rbuf</c>. When <c>control</c> is called,
<c>*rbuf</c> points to a default buffer of <c>rlen</c> bytes, which
- can be used to return data. Data is returned different depending on
+ can be used to return data. Data is returned differently depending on
the port control flags (those that are set with
- <seealso marker="erl_driver#set_port_control_flags">set_port_control_flags</seealso>).
- </p>
+ <seealso marker="erl_driver#set_port_control_flags">
+ <c>erl_driver:set_port_control_flags</c></seealso>).</p>
<p>If the flag is set to <c>PORT_CONTROL_FLAG_BINARY</c>,
- 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 <c>*rbuf</c> to point to a binary allocated with
- <seealso marker="erl_driver#driver_alloc_binary">driver_alloc_binary</seealso>.
- This binary will be freed automatically after <c>control</c> has returned.
+ 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 <c>*rbuf</c> to point to a binary allocated with
+ <seealso marker="erl_driver#driver_alloc_binary">
+ <c>erl_driver:driver_alloc_binary</c></seealso>.
+ This binary is freed automatically after <c>control</c> has returned.
The driver can retain the binary for <em>read only</em> access with
- <seealso marker="erl_driver#driver_binary_inc_refc">driver_binary_inc_refc</seealso> to be freed later with
- <seealso marker="erl_driver#driver_free_binary">driver_free_binary</seealso>.
- It is never allowed to alter the binary after <c>control</c> has returned.
- If <c>*rbuf</c> is set to NULL, an empty list will be returned.
- </p>
+ <seealso marker="erl_driver#driver_binary_inc_refc">
+ <c>erl_driver:driver_binary_inc_refc</c></seealso> to be freed later
+ with <seealso marker="erl_driver#driver_free_binary">
+ <c>erl_driver:driver_free_binary</c></seealso>.
+ It is never allowed to change the binary after <c>control</c> has
+ returned. If <c>*rbuf</c> is set to <c>NULL</c>, an empty list is
+ returned.</p>
<p>If the flag is set to <c>0</c>, data is returned as a
list of integers. Either use the default buffer or set
<c>*rbuf</c> to point to a larger buffer allocated with
- <seealso marker="erl_driver#driver_alloc">driver_alloc</seealso>.
- The buffer will be freed automatically after <c>control</c> has returned.</p>
+ <seealso marker="erl_driver#driver_alloc">
+ <c>erl_driver:driver_alloc</c></seealso>. The
+ buffer is freed automatically after <c>control</c> has returned.</p>
<p>Using binaries is faster if more than a few bytes are returned.</p>
- <p>The return value is the number of bytes returned in
- <c>*rbuf</c>.</p>
+ <p>The return value is the number of bytes returned in <c>*rbuf</c>.</p>
</item>
-
- <tag><marker id="timeout"/>void (*timeout)(ErlDrvData drv_data)</tag>
+ <tag><marker id="timeout"/><c>void (*timeout)(ErlDrvData drv_data)</c>
+ </tag>
<item>
- <p>This function is called any time after the driver's timer
- reaches 0. The timer is activated with
- <c>driver_set_timer</c>. 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.</p>
+ <p>Called any time after the driver's timer reaches <c>0</c>.
+ The timer is activated with
+ <seealso marker="erl_driver#driver_set_timer">
+ <c>erl_driver:driver_set_timer</c></seealso>. No priorities or
+ ordering exist among drivers, so if several drivers time out at
+ the same time, anyone of them is called first.</p>
</item>
-
- <tag><marker id="outputv"/>void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev)</tag>
+ <tag><marker id="outputv"/>
+ <c>void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev)</c></tag>
<item>
- <p>This function is called whenever the port is written to. If
+ <p>Called whenever the port is written to. If
it is <c>NULL</c>, the <c>output</c> function is called
- instead. This function is faster than <c>output</c>, because
+ instead. This function is faster than <c>output</c>, as
it takes an <c>ErlIOVec</c> directly, which requires no
- copying of the data. The port should be in binary mode, see
- <c>open_port/2</c>.</p>
- <p>The <c>ErlIOVec</c> contains both a <c>SysIOVec</c>,
+ copying of the data. The port is to be in binary mode, see
+ <seealso marker="erlang#open_port/2">
+ <c>erlang:open_port/2</c></seealso>.</p>
+ <p><c>ErlIOVec</c> contains both a <c>SysIOVec</c>,
suitable for <c>writev</c>, and one or more binaries. If
- these binaries should be retained, when the driver returns
- from <c>outputv</c>, they can be queued (using <seealso marker="erl_driver#driver_enq_bin">driver_enq_bin</seealso>
- for instance), or if they are kept in a static or global
+ these binaries are to be retained when the driver returns
+ from <c>outputv</c>, they can be queued (using, for example,
+ <seealso marker="erl_driver#driver_enq_bin">
+ <c>erl_driver:driver_enq_bin</c></seealso>)
+ or, if they are kept in a static or global
variable, the reference counter can be incremented.</p>
</item>
- <tag><marker id="ready_async"/>void (*ready_async)(ErlDrvData drv_data, ErlDrvThreadData thread_data)</tag>
+ <tag><marker id="ready_async"/>
+ <c>void (*ready_async)(ErlDrvData drv_data, ErlDrvThreadData
+ thread_data)</c></tag>
<item>
- <p>This function is called after an asynchronous call has
- completed. The asynchronous call is started with <seealso marker="erl_driver#driver_async">driver_async</seealso>.
- This function is called from the erlang emulator thread, as
+ <p>Called after an asynchronous call has completed.
+ The asynchronous call is started with
+ <seealso marker="erl_driver#driver_async">
+ <c>erl_driver:driver_async</c></seealso>.
+ 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).</p>
+ some thread (if multi-threading is enabled).</p>
</item>
- <tag><marker id="call"/>ErlDrvSSizeT (*call)(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen, unsigned int *flags)</tag>
+ <tag><c>void (*flush)(ErlDrvData drv_data)</c></tag>
<item>
- <p>This function is called from <c>erlang:port_call/3</c>. It
- works a lot like the <c>control</c> call-back, but uses the
+ <p>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.</p>
+ </item>
+ <tag><marker id="call"/><c>ErlDrvSSizeT (*call)(ErlDrvData drv_data,
+ unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf,
+ ErlDrvSizeT rlen, unsigned int *flags)</c></tag>
+ <item>
+ <p>Called from <seealso marker="erlang#port_call/3">
+ <c>erlang:port_call/3</c></seealso>.
+ It works a lot like the <c>control</c> callback, but uses the
external term format for input and output.</p>
<p><c>command</c> is an integer, obtained from the call from
- erlang (the second argument to <c>erlang:port_call/3</c>).</p>
+ Erlang (the second argument to <c>erlang:port_call/3</c>).</p>
<p><c>buf</c> and <c>len</c> provide the arguments to the call
(the third argument to <c>erlang:port_call/3</c>). They can
be decoded using <c>ei</c> functions.</p>
<p><c>rbuf</c> points to a return buffer, <c>rlen</c> bytes
- long. The return data should be a valid erlang term in the
- external (binary) format. This is converted to an erlang
+ 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 <c>erlang:port_call/3</c> to the
- caller. If more space than <c>rlen</c> bytes is needed to
+ caller. If more space than <c>rlen</c> bytes is needed to
return data, <c>*rbuf</c> can be set to memory allocated with
- <c>driver_alloc</c>. This memory will be freed automatically
- after <c>call</c> has returned.</p>
+ <seealso marker="erl_driver#driver_alloc">
+ <c>erl_driver:driver_alloc</c></seealso>.
+ This memory is freed automatically after <c>call</c> has returned.</p>
<p>The return value is the number of bytes returned in
<c>*rbuf</c>. If <c>ERL_DRV_ERROR_GENERAL</c> is returned
- (or in fact, anything &lt; 0), <c>erlang:port_call/3</c> will
- throw a <c>BAD_ARG</c>.</p>
+ (or in fact, anything &lt; 0), <c>erlang:port_call/3</c>
+ throws a <c>BAD_ARG</c>.</p>
</item>
- <tag>void (*event)(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_data)</tag>
+ <tag><c>void (*event)(ErlDrvData drv_data, ErlDrvEvent event,
+ ErlDrvEventData event_data)</c></tag>
<item>
<p>Intentionally left undocumented.</p>
</item>
- <tag><marker id="extended_marker"/>int extended_marker</tag>
+ <tag><marker id="extended_marker"/><c>int extended_marker</c></tag>
<item>
- <p>
- This field should either be equal to <c>ERL_DRV_EXTENDED_MARKER</c>
+ <p>This field is either to be equal to <c>ERL_DRV_EXTENDED_MARKER</c>
or <c>0</c>. An old driver (not aware of the extended driver
- interface) should set this field to <c>0</c>. If this field is
- equal to <c>0</c>, all the fields following this field also
- <em>have</em> to be <c>0</c>, or <c>NULL</c> in case it is a
- pointer field.
- </p>
+ interface) is to set this field to <c>0</c>. If this field is
+ <c>0</c>, all the following fields <em>must</em> also be <c>0</c>,
+ or <c>NULL</c> if it is a pointer field.</p>
</item>
- <tag>int major_version</tag>
+ <tag><c>int major_version</c></tag>
<item>
- <p>This field should equal <c>ERL_DRV_EXTENDED_MAJOR_VERSION</c> if
- the <c>extended_marker</c> field equals
+ <p>This field is to equal <c>ERL_DRV_EXTENDED_MAJOR_VERSION</c> if
+ field <c>extended_marker</c> equals
<c>ERL_DRV_EXTENDED_MARKER</c>.</p>
</item>
- <tag>int minor_version</tag>
+ <tag><c>int minor_version</c></tag>
<item>
- <p>
- This field should equal <c>ERL_DRV_EXTENDED_MINOR_VERSION</c> if
- the <c>extended_marker</c> field equals
- <c>ERL_DRV_EXTENDED_MARKER</c>.
- </p>
+ <p>This field is to equal <c>ERL_DRV_EXTENDED_MINOR_VERSION</c> if
+ field <c>extended_marker</c> equals
+ <c>ERL_DRV_EXTENDED_MARKER</c>.</p>
</item>
-
- <tag><marker id="driver_flags"/>int driver_flags</tag>
+ <tag><marker id="driver_flags"/><c>int driver_flags</c></tag>
<item>
<p>This field is used to pass driver capability and other
- information to the runtime system. If the
- <c>extended_marker</c> field equals <c>ERL_DRV_EXTENDED_MARKER</c>,
- it should contain <c>0</c> or driver flags (<c>ERL_DRV_FLAG_*</c>)
- ored bitwise. Currently the following driver flags exist:
- </p>
+ information to the runtime system. If
+ field <c>extended_marker</c> equals <c>ERL_DRV_EXTENDED_MARKER</c>,
+ it is to contain <c>0</c> or driver flags (<c>ERL_DRV_FLAG_*</c>)
+ OR'ed bitwise. The following driver flags exist:</p>
<taglist>
<tag><c>ERL_DRV_FLAG_USE_PORT_LOCKING</c></tag>
<item>
- The runtime system will use 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 the
- <seealso marker="erl_driver#smp_support">erl_driver</seealso>
- documentation.
- </item>
+ <p>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
+ <seealso marker="erl_driver#smp_support">
+ <c>erl_driver</c></seealso>.</p>
+ </item>
<tag><c>ERL_DRV_FLAG_SOFT_BUSY</c></tag>
<item>
- Marks that driver instances can handle being called
- in the <seealso marker="#output">output</seealso> and/or
- <seealso marker="#outputv">outputv</seealso> callbacks even
- though a driver instance has marked itself as busy (see
- <seealso marker="erl_driver#set_busy_port">set_busy_port()</seealso>).
- Since erts version 5.7.4 this flag is required for drivers used
- by the Erlang distribution (the behaviour has always been
- required by drivers used by the distribution).
+ <p>Marks that driver instances can handle being called
+ in the <seealso marker="#output"><c>output</c></seealso> and/or
+ <seealso marker="#outputv"><c>outputv</c></seealso> callbacks
+ although a driver instance has marked itself as busy (see
+ <seealso marker="erl_driver#set_busy_port">
+ <c>erl_driver:set_busy_port</c></seealso>).
+ 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).</p>
</item>
<tag><c>ERL_DRV_FLAG_NO_BUSY_MSGQ</c></tag>
- <item>Disable busy port message queue functionality. For
- more information, see the documentation of the
- <seealso marker="erl_driver#erl_drv_busy_msgq_limits">erl_drv_busy_msgq_limits()</seealso>
- function.
+ <item>
+ <p>Disables busy port message queue functionality. For
+ more information, see
+ <seealso marker="erl_driver#erl_drv_busy_msgq_limits">
+ <c>erl_driver:erl_drv_busy_msgq_limits</c></seealso>.</p>
+ </item>
+ <tag><c>ERL_DRV_FLAG_USE_INIT_ACK</c></tag>
+ <item>
+ <p>When this flag is specified, the linked-in driver must manually
+ acknowledge that the port has been successfully started using
+ <seealso marker="erl_driver#erl_drv_init_ack">
+ <c>erl_driver:erl_drv_init_ack()</c></seealso>.
+ This allows the implementor to make the
+ <c>erlang:open_port</c> exit with <c>badarg</c> after some
+ initial asynchronous initialization has been done.</p>
</item>
- </taglist>
+ </taglist>
</item>
- <tag>void *handle2</tag>
+ <tag><c>void *handle2</c></tag>
<item>
- <p>
- This field is reserved for the emulator's internal use. The
- emulator will modify this field; therefore, it is important
- that the <c>driver_entry</c> isn't declared <c>const</c>.
- </p>
+ <p>This field is reserved for the emulator's internal use. The
+ emulator modifies this field, so it is important
+ that the <c>driver_entry</c> is not declared <c>const</c>.</p>
</item>
- <tag><marker id="process_exit"/>void (*process_exit)(ErlDrvData drv_data, ErlDrvMonitor *monitor)</tag>
+ <tag><marker id="process_exit"/>
+ <c>void (*process_exit)(ErlDrvData drv_data, ErlDrvMonitor *monitor)</c>
+ </tag>
<item>
- <p>This callback is called when a monitored process exits. The
+ <p>Called when a monitored process exits. The
<c>drv_data</c> is the data associated with the port for which
- the process is monitored (using <seealso marker="erl_driver#driver_monitor_process">driver_monitor_process</seealso>)
- and the <c>monitor</c> corresponds to the <c>ErlDrvMonitor</c>
+ the process is monitored (using
+ <seealso marker="erl_driver#driver_monitor_process">
+ <c>erl_driver:driver_monitor_process</c></seealso>)
+ and the <c>monitor</c> corresponds to the <c>ErlDrvMonitor</c>
structure filled
in when creating the monitor. The driver interface function
- <seealso marker="erl_driver#driver_get_monitored_process">driver_get_monitored_process</seealso>
- can be used to retrieve the process id of the exiting process as
+ <seealso marker="erl_driver#driver_get_monitored_process">
+ <c>erl_driver:driver_get_monitored_process</c></seealso>
+ can be used to retrieve the process ID of the exiting process as
an <c>ErlDrvTermData</c>.</p>
</item>
- <tag><marker id="stop_select"/>void (*stop_select)(ErlDrvEvent event, void* reserved)</tag>
+ <tag><marker id="stop_select"/>
+ <c>void (*stop_select)(ErlDrvEvent event, void* reserved)</c></tag>
<item>
- <p>This function is called on behalf of
- <seealso marker="erl_driver#driver_select">driver_select</seealso>
- when it is safe to close an event object.</p>
+ <p>Called on behalf of
+ <seealso marker="erl_driver#driver_select">
+ <c>erl_driver:driver_select</c></seealso>
+ when it is safe to close an event object.</p>
<p>A typical implementation on Unix is to do
- <c>close((int)event)</c>.</p>
- <p>Argument <c>reserved</c> is intended for future use and should be ignored.</p>
- <p>In contrast to most of the other call-back functions,
- <c>stop_select</c> is called independent of any port. No
- <c>ErlDrvData</c> argument is passed to the function. No
- driver lock or port lock is guaranteed to be held. The port that
- called <c>driver_select</c> might even be closed at the
- time <c>stop_select</c> is called. But it could also be
- the case that <c>stop_select</c> is called directly by
- <c>driver_select</c>.</p>
+ <c>close((int)event)</c>.</p>
+ <p>Argument <c>reserved</c> is intended for future use and is to be
+ ignored.</p>
+ <p>In contrast to most of the other callback functions,
+ <c>stop_select</c> is called independent of any port. No
+ <c>ErlDrvData</c> argument is passed to the function. No
+ driver lock or port lock is guaranteed to be held. The port that
+ called <c>driver_select</c> can even be closed at the
+ time <c>stop_select</c> is called. But it can also be
+ the case that <c>stop_select</c> is called directly by
+ <c>erl_driver:driver_select</c>.</p>
<p>It is not allowed to call any functions in the
- <seealso marker="erl_driver">driver API</seealso> from
- <c>stop_select</c>. This strict limitation is due to the
- volatile context that <c>stop_select</c> may be called.</p>
+ <seealso marker="erl_driver">driver API</seealso> from
+ <c>stop_select</c>. This strict limitation is because the
+ volatile context that <c>stop_select</c> can be called.</p>
</item>
-
- </taglist>
- </item>
-
</taglist>
</section>
<section>
- <title>SEE ALSO</title>
- <p><seealso marker="erl_driver">erl_driver(3)</seealso>,
- <seealso marker="kernel:erl_ddll">erl_ddll(3)</seealso>,
- <seealso marker="erlang">erlang(3)</seealso>,
- kernel(3)</p>
+ <title>See Also</title>
+ <p><seealso marker="erl_driver"><c>erl_driver(3)</c></seealso>,
+ <seealso marker="erlang"><c>erlang(3)</c></seealso>,
+ <seealso marker="kernel:erl_ddll"><c>erl_ddll(3)</c></seealso></p>
</section>
</cref>