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.xml453
1 files changed, 453 insertions, 0 deletions
diff --git a/erts/doc/src/driver_entry.xml b/erts/doc/src/driver_entry.xml
new file mode 100644
index 0000000000..6b7d2acf24
--- /dev/null
+++ b/erts/doc/src/driver_entry.xml
@@ -0,0 +1,453 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE cref SYSTEM "cref.dtd">
+
+<cref>
+ <header>
+ <copyright>
+ <year>2001</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>driver_entry</title>
+ <prepared>Jakob Cederlund</prepared>
+ <responsible>Jakob Cederlund</responsible>
+ <docno>1</docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2001-10-01</date>
+ <rev>PA1</rev>
+ <file>driver_entry.xml</file>
+ </header>
+ <lib>driver_entry</lib>
+ <libsummary>The driver-entry structure used by erlang drivers.</libsummary>
+ <description>
+ <p>As of erts version 5.5.3 the driver interface has been extended
+ (see <seealso marker="driver_entry#extended_marker">extended marker</seealso>).
+ The extended interface introduce
+ <seealso marker="erl_driver#version_management">version management</seealso>,
+ the possibility to pass capability flags
+ (see <seealso marker="driver_entry#driver_flags">driver flags</seealso>)
+ to the runtime system at driver initialization, and some new
+ driver API functions. </p>
+ <note>
+ <p>Old drivers (compiled with an <c>erl_driver.h</c> from an
+ earlier erts version than 5.5.3) have to be recompiled
+ (but does not have to use the extended interface).</p>
+ </note>
+ <p>The <c>driver_entry</c> structure is a C struct that all erlang
+ drivers defines. It contains entry points for the erlang driver
+ that are called by the erlang emulator when erlang code accesses
+ the driver.</p>
+ <p>
+ <marker id="emulator"></marker>
+ The <seealso marker="driver_entry">erl_driver</seealso> driver
+ API functions needs 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
+ not to the other functions. The <c>start</c> function returns a
+ driver-defined handle that is passed to the other functions. A
+ common practice is to have the <c>start</c> function allocating
+ 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
+ responsive.</p>
+ <p>The driver structure contains the name of the driver and some
+ 15 function pointers. These pointers 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>
+ <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>
+ <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>
+ </note>
+ </description>
+
+ <section>
+ <title>DATA TYPES</title>
+ <taglist>
+ <tag><b>ErlDrvEntry</b></tag>
+ <item>
+ <p/>
+ <code type="none">
+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, 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; /* Reserved -- Used by emulator internally */
+ int (*control)(ErlDrvData drv_data, unsigned int command, char *buf,
+ int len, char **rbuf, int 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 */
+ int (*call)(ErlDrvData drv_data, unsigned int command, char *buf,
+ int len, char **rbuf, int rlen, unsigned int *flags);
+ /* Works mostly like 'control', a syncronous
+ 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;
+ </code>
+ <p/>
+ <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>
+ </item>
+ <tag><marker id="start"/>int (*start)(ErlDrvPort port, char* command)</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 erl_errno</p>
+ <p>ERL_DRV_ERROR_BADARG - error, badarg</p>
+ <p>If an error code is returned, the port isn't started.</p>
+ </item>
+ <tag><marker id="stop"/>void (*stop)(ErlDrvData drv_data)</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\011 port.</p>
+ </item>
+ <tag><marker id="output"/>void (*output)(ErlDrvData drv_data, char *buf, int len)</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>
+ </item>
+
+ <tag><marker id="ready_input"/>void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event)</tag>
+ <tag><marker id="ready_output"/>void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event)</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
+ 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
+ function understands). (Some trickery in the emulator allows
+ more than the built-in limit of 64 <c>Events</c> to be used.)</p>
+ <p>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 <c>SetEvent</c> on
+ Windows), this will make the emulator call
+ <c>ready_input</c> or <c>ready_output</c>.</p>
+ </item>
+ <tag><marker id="driver_name"/>char *driver_name</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
+ library file (without the extension).</p>
+ </item>
+ <tag><marker id="finish"/>void (*finish)(void)</tag>
+ <item>
+ <p>This function is 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>
+ </item>
+ <tag>void *handle</tag>
+ <item>
+ <p>This field is reserved for the emulators 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>
+ </item>
+ <tag><marker id="control"></marker>int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen)</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
+ 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
+ is too slow.</p>
+ <p>If the driver wants to return data, it should 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
+ the port control flags (those that are set with
+ <seealso marker="erl_driver#set_port_control_flags">set_port_control_flags</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.
+ 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>
+ <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>
+ <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>
+ </item>
+
+ <tag><marker id="timeout"/>void (*timeout)(ErlDrvData drv_data)</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>
+ </item>
+
+ <tag><marker id="outputv"/>void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev)</tag>
+ <item>
+ <p>This function is 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
+ 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>,
+ 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
+ variable, the reference counter can be incremented.</p>
+ </item>
+ <tag><marker id="ready_async"/>void (*ready_async)(ErlDrvData drv_data, ErlDrvThreadData thread_data)</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
+ opposed to the asynchronous function, which is called in
+ some thread (if multithreading is enabled).</p>
+ </item>
+ <tag><marker id="call"/>int (*call)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen, unsigned int *flags)</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
+ 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>
+ <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
+ term and returned by <c>erlang:port_call/3</c> to the
+ 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>
+ <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>
+ </item>
+ <tag>void (*event)(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_data)</tag>
+ <item>
+ <p>Intentionally left undocumented.</p>
+ </item>
+ <tag><marker id="extended_marker"/>int extended_marker</tag>
+ <item>
+ <p>
+ This field should either 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>
+ </item>
+ <tag>int major_version</tag>
+ <item>
+ <p>This field should equal <c>ERL_DRV_EXTENDED_MAJOR_VERSION</c> if
+ the <c>extended_marker</c> field equals
+ <c>ERL_DRV_EXTENDED_MARKER</c>.</p>
+ </item>
+ <tag>int minor_version</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>
+ </item>
+
+ <tag><marker id="driver_flags"/>int driver_flags</tag>
+ <item>
+ <p>This field is used to pass driver capability 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>
+ <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>
+ <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).
+ </item>
+ </taglist>
+ </item>
+ <tag>void *handle2</tag>
+ <item>
+ <p>
+ This field is reserved for the emulators 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>
+ </item>
+ <tag><marker id="process_exit"/>void (*process_exit)(ErlDrvData drv_data, ErlDrvMonitor *monitor)</tag>
+ <item>
+ <p>This callback is 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>
+ 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
+ an <c>ErlDrvTermData</c>.</p>
+ </item>
+ <tag><marker id="stop_select"/>void (*stop_select)(ErlDrvEvent event, void* reserved)</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>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>
+ <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>
+ </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="erts:erlang">erlang(3)</seealso>,
+ kernel(3)</p>
+ </section>
+</cref>
+