diff options
Diffstat (limited to 'erts/doc/src/driver_entry.xml')
-rw-r--r-- | erts/doc/src/driver_entry.xml | 453 |
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 >= 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 < 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> + |