diff options
Diffstat (limited to 'erts/doc/src/driver_entry.xml')
-rw-r--r-- | erts/doc/src/driver_entry.xml | 647 |
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 >= 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 >= 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 < 0), <c>erlang:port_call/3</c> will - throw a <c>BAD_ARG</c>.</p> + (or in fact, anything < 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> |