diff options
Diffstat (limited to 'erts/doc/src/erl_driver.xml')
-rw-r--r-- | erts/doc/src/erl_driver.xml | 2979 |
1 files changed, 1518 insertions, 1461 deletions
diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml index 82215ead46..d8116d4650 100644 --- a/erts/doc/src/erl_driver.xml +++ b/erts/doc/src/erl_driver.xml @@ -893,229 +893,26 @@ typedef struct ErlIOVec { <funcs> <func> - <name><ret>void</ret><nametext>driver_system_info(ErlDrvSysInfo *sys_info_ptr, size_t size)</nametext></name> - <fsummary>Get information about the Erlang runtime system</fsummary> - <desc> - <marker id="driver_system_info"></marker> - <p>This function will write information about the Erlang runtime - system into the - <seealso marker="#ErlDrvSysInfo">ErlDrvSysInfo</seealso> - structure referred to by the first argument. The second - argument should be the size of the - <seealso marker="#ErlDrvSysInfo">ErlDrvSysInfo</seealso> - structure, i.e., <c>sizeof(ErlDrvSysInfo)</c>.</p> - <p>See the documentation of the - <seealso marker="#ErlDrvSysInfo">ErlDrvSysInfo</seealso> - structure for information about specific fields.</p> - </desc> - </func> - <func> - <name><ret>int</ret><nametext>driver_output(ErlDrvPort port, char *buf, ErlDrvSizeT len)</nametext></name> - <fsummary>Send data from driver to port owner</fsummary> - <desc> - <marker id="driver_output"></marker> - <p>The <c>driver_output</c> function is used to send data from - the driver up to the emulator. The data will be received as - terms or binary data, depending on how the driver port was - opened.</p> - <p>The data is queued in the port owner process' message - queue. Note that this does not yield to the emulator. (Since - the driver and the emulator run in the same thread.)</p> - <p>The parameter <c>buf</c> points to the data to send, and - <c>len</c> is the number of bytes.</p> - <p>The return value for all output functions is 0. (Unless the - driver is used for distribution, in which case it can fail - and return -1. For normal use, the output function always - returns 0.)</p> - </desc> - </func> - <func> - <name><ret>int</ret><nametext>driver_output2(ErlDrvPort port, char *hbuf, ErlDrvSizeT hlen, char *buf, ErlDrvSizeT len)</nametext></name> - <fsummary>Send data and binary data to port owner</fsummary> - <desc> - <marker id="driver_output2"></marker> - <p>The <c>driver_output2</c> function first sends <c>hbuf</c> - (length in <c>hlen</c>) data as a list, regardless of port - settings. Then <c>buf</c> is sent as a binary or list. - E.g. if <c>hlen</c> is 3 then the port owner process will - receive <c>[H1, H2, H3 | T]</c>.</p> - <p>The point of sending data as a list header, is to facilitate - matching on the data received.</p> - <p>The return value is 0 for normal use.</p> - </desc> - </func> - <func> - <name><ret>int</ret><nametext>driver_output_binary(ErlDrvPort port, char *hbuf, ErlDrvSizeT hlen, ErlDrvBinary* bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext></name> - <fsummary>Send data from a driver binary to port owner</fsummary> - <desc> - <marker id="driver_output_binary"></marker> - <p>This function sends data to port owner process from a - driver binary, it has a header buffer (<c>hbuf</c> - and <c>hlen</c>) just like <c>driver_output2</c>. The - <c>hbuf</c> parameter can be <c>NULL</c>.</p> - <p>The parameter <c>offset</c> is an offset into the binary and - <c>len</c> is the number of bytes to send.</p> - <p>Driver binaries are created with <c>driver_alloc_binary</c>.</p> - <p>The data in the header is sent as a list and the binary as - an Erlang binary in the tail of the list.</p> - <p>E.g. if <c>hlen</c> is 2, then the port owner process will - receive <c><![CDATA[[H1, H2 | <<T>>]]]></c>.</p> - <p>The return value is 0 for normal use.</p> - <p>Note that, using the binary syntax in Erlang, the driver - application can match the header directly from the binary, - so the header can be put in the binary, and hlen can be set - to 0.</p> - </desc> - </func> - <func> - <name><ret>int</ret><nametext>driver_outputv(ErlDrvPort port, char* hbuf, ErlDrvSizeT hlen, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> - <fsummary>Send vectorized data to port owner</fsummary> - <desc> - <marker id="driver_outputv"></marker> - <p>This function sends data from an IO vector, <c>ev</c>, to - the port owner process. It has a header buffer (<c>hbuf</c> - and <c>hlen</c>), just like <c>driver_output2</c>.</p> - <p>The <c>skip</c> parameter is a number of bytes to skip of - the <c>ev</c> vector from the head.</p> - <p>You get vectors of <c>ErlIOVec</c> type from the driver - queue (see below), and the <seealso marker="driver_entry#outputv">outputv</seealso> driver entry - function. You can also make them yourself, if you want to - send several <c>ErlDrvBinary</c> buffers at once. Often - it is faster to use <c>driver_output</c> or - <c>driver_output_binary</c>.</p> - <p>E.g. if <c>hlen</c> is 2 and <c>ev</c> points to an array of - three binaries, the port owner process will receive <c><![CDATA[[H1, H2, <<B1>>, <<B2>> | <<B3>>]]]></c>.</p> - <p>The return value is 0 for normal use.</p> - <p>The comment for <c>driver_output_binary</c> applies for - <c>driver_outputv</c> too.</p> - </desc> - </func> - <func> - <name><ret>ErlDrvSizeT</ret><nametext>driver_vec_to_buf(ErlIOVec *ev, char *buf, ErlDrvSizeT len)</nametext></name> - <fsummary>Collect data segments into a buffer</fsummary> - <desc> - <marker id="driver_vec_to_buf"></marker> - <p>This function collects several segments of data, referenced - by <c>ev</c>, by copying them in order to the buffer - <c>buf</c>, of the size <c>len</c>.</p> - <p>If the data is to be sent from the driver to the port owner - process, it is faster to use <c>driver_outputv</c>.</p> - <p>The return value is the space left in the buffer, i.e. if - the <c>ev</c> contains less than <c>len</c> bytes it's the - difference, and if <c>ev</c> contains <c>len</c> bytes or - more, it's 0. This is faster if there is more than one header byte, - since the binary syntax can construct integers directly from - the binary.</p> - </desc> - </func> - <func> - <name><ret>int</ret><nametext>driver_set_timer(ErlDrvPort port, unsigned long time)</nametext></name> - <fsummary>Set a timer to call the driver</fsummary> - <desc> - <marker id="driver_set_timer"></marker> - <p>This function sets a timer on the driver, which will count - down and call the driver when it is timed out. The - <c>time</c> parameter is the time in milliseconds before the - timer expires.</p> - <p>When the timer reaches 0 and expires, the driver entry - function <seealso marker="driver_entry#timeout">timeout</seealso> is called.</p> - <p>Note that there is only one timer on each driver instance; - setting a new timer will replace an older one.</p> - <p>Return value is 0 (-1 only when the <c>timeout</c> driver - function is <c>NULL</c>).</p> - </desc> - </func> - <func> - <name><ret>int</ret><nametext>driver_cancel_timer(ErlDrvPort port)</nametext></name> - <fsummary>Cancel a previously set timer</fsummary> - <desc> - <marker id="driver_cancel_timer"></marker> - <p>This function cancels a timer set with - <c>driver_set_timer</c>.</p> - <p>The return value is 0.</p> - </desc> - </func> - <func> - <name><ret>int</ret><nametext>driver_read_timer(ErlDrvPort port, unsigned long *time_left)</nametext></name> - <fsummary>Read the time left before timeout</fsummary> - <desc> - <marker id="driver_read_timer"></marker> - <p>This function reads the current time of a timer, and places - the result in <c>time_left</c>. This is the time in - milliseconds, before the timeout will occur.</p> - <p>The return value is 0.</p> - </desc> - </func> - <func> - <name><ret>int</ret><nametext>driver_get_now(ErlDrvNowData *now)</nametext></name> - <fsummary>Read a system timestamp</fsummary> - <desc> - <marker id="driver_get_now"></marker> - <warning><p><em>This function is deprecated! Do not use it!</em> - Use <seealso marker="#erl_drv_monotonic_time"><c>erl_drv_monotonic_time()</c></seealso> - (perhaps in combination with - <seealso marker="#erl_drv_time_offset"><c>erl_drv_time_offset()</c></seealso>) - instead.</p></warning> - <p>This function reads a timestamp into the memory pointed to by - the parameter <c>now</c>. See the description of <seealso marker="#ErlDrvNowData">ErlDrvNowData</seealso> for - specification of its fields. </p> - <p>The return value is 0 unless the <c>now</c> pointer is not - valid, in which case it is < 0. </p> - </desc> - </func> - <func> - <name><ret>int</ret><nametext>driver_select(ErlDrvPort port, ErlDrvEvent event, int mode, int on)</nametext></name> - <fsummary>Provide an event for having the emulator call the driver</fsummary> + <name><ret>void</ret><nametext>add_driver_entry(ErlDrvEntry *de)</nametext></name> + <fsummary>Add a driver entry</fsummary> <desc> - <marker id="driver_select"></marker> - <p>This function is used by drivers to provide the emulator with - events to check for. This enables the emulator to call the driver - when something has happened asynchronously.</p> - <p>The <c>event</c> argument identifies an OS-specific event object. - On Unix systems, the functions <c>select</c>/<c>poll</c> are used. The - event object must be a socket or pipe (or other object that - <c>select</c>/<c>poll</c> can use). - On windows, the Win32 API function <c>WaitForMultipleObjects</c> - is used. This places other restrictions on the event object. - Refer to the Win32 SDK documentation.</p> - <p>The <c>on</c> parameter should be <c>1</c> for setting events - and <c>0</c> for clearing them.</p> - <p>The <c>mode</c> argument is a bitwise-or combination of - <c>ERL_DRV_READ</c>, <c>ERL_DRV_WRITE</c> and <c>ERL_DRV_USE</c>. - The first two specify whether to wait for read events and/or write - events. A fired read event will call - <seealso marker="driver_entry#ready_input">ready_input</seealso> - while a fired write event will call - <seealso marker="driver_entry#ready_output">ready_output</seealso>. - </p> - <note> - <p>Some OS (Windows) do not differentiate between read and write events. - The call-back for a fired event then only depends on the value of <c>mode</c>.</p> - </note> - <p><c>ERL_DRV_USE</c> specifies if we are using the event object or if we want to close it. - On an emulator with SMP support, it is not safe to clear all events - and then close the event object after <c>driver_select</c> has - returned. Another thread may still be using the event object - internally. To safely close an event object call - <c>driver_select</c> with <c>ERL_DRV_USE</c> and <c>on==0</c>. That - will clear all events and then call - <seealso marker="driver_entry#stop_select">stop_select</seealso> - when it is safe to close the event object. - <c>ERL_DRV_USE</c> should be set together with the first event - for an event object. It is harmless to set <c>ERL_DRV_USE</c> - even though it already has been done. Clearing all events but keeping - <c>ERL_DRV_USE</c> set will indicate that we are using the event - object and probably will set events for it again.</p> - <note> - <p>ERL_DRV_USE was added in OTP release R13. Old drivers will still work - as before. But it is recommended to update them to use <c>ERL_DRV_USE</c> and - <c>stop_select</c> to make sure that event objects are closed in a safe way.</p> - </note> - <p>The return value is 0 (failure, -1, only if the - <c>ready_input</c>/<c>ready_output</c> is - <c>NULL</c>).</p> + <marker id="add_driver_entry"></marker> + <p>This function adds a driver entry to the list of drivers + known by Erlang. The <seealso marker="driver_entry#init">init</seealso> function of the <c>de</c> + parameter is called.</p> + <note> + <p>To use this function for adding drivers residing in + dynamically loaded code is dangerous. If the driver code + for the added driver resides in the same dynamically + loaded module (i.e. <c>.so</c> file) as a normal + dynamically loaded driver (loaded with the <c>erl_ddll</c> + interface), the caller should call <seealso marker="#driver_lock_driver">driver_lock_driver</seealso> before + adding driver entries.</p> + <p>Use of this function is generally deprecated.</p> + </note> </desc> </func> + <func> <name><ret>void *</ret><nametext>driver_alloc(ErlDrvSizeT size)</nametext></name> <fsummary>Allocate memory</fsummary> @@ -1130,32 +927,7 @@ typedef struct ErlIOVec { <p>This function is thread-safe.</p> </desc> </func> - <func> - <name><ret>void *</ret><nametext>driver_realloc(void *ptr, ErlDrvSizeT size)</nametext></name> - <fsummary>Resize an allocated memory block</fsummary> - <desc> - <marker id="driver_realloc"></marker> - <p>This function resizes a memory block, either in place, or by - allocating a new block, copying the data and freeing the old - block. A pointer is returned to the reallocated memory. On - failure (out of memory), <c>NULL</c> is returned. (This is - most often a wrapper for <c>realloc</c>.)</p> - <p>This function is thread-safe.</p> - </desc> - </func> - <func> - <name><ret>void</ret><nametext>driver_free(void *ptr)</nametext></name> - <fsummary>Free an allocated memory block</fsummary> - <desc> - <marker id="driver_free"></marker> - <p>This function frees the memory pointed to by <c>ptr</c>. The - memory should have been allocated with - <c>driver_alloc</c>. All allocated memory should be - deallocated, just once. There is no garbage collection in - drivers.</p> - <p>This function is thread-safe.</p> - </desc> - </func> + <func> <name><ret>ErlDrvBinary *</ret><nametext>driver_alloc_binary(ErlDrvSizeT size)</nametext></name> <fsummary>Allocate a driver binary</fsummary> @@ -1176,31 +948,114 @@ typedef struct ErlIOVec { <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>ErlDrvBinary *</ret><nametext>driver_realloc_binary(ErlDrvBinary *bin, ErlDrvSizeT size)</nametext></name> - <fsummary>Resize a driver binary</fsummary> + <name><ret>long</ret><nametext>driver_async (ErlDrvPort port, unsigned int* key, void (*async_invoke)(void*), void* async_data, void (*async_free)(void*))</nametext></name> + <fsummary>Perform an asynchronous call within a driver</fsummary> <desc> - <marker id="driver_realloc_binary"></marker> - <p>This function resizes a driver binary, while keeping the - data. The resized driver binary is returned. On failure (out - of memory), <c>NULL</c> is returned.</p> - <p>This function is only thread-safe when the emulator with SMP - support is used.</p> + <marker id="driver_async"></marker> + <p>This function performs an asynchronous call. The function + <c>async_invoke</c> is invoked in a thread separate from the + emulator thread. This enables the driver to perform + time-consuming, blocking operations without blocking the + emulator.</p> + <p>The async thread pool size can be set with the + <seealso marker="erl#async_thread_pool_size">+A</seealso> + command line argument of <seealso marker="erl">erl(1)</seealso>. + If no async thread pool is available, the call is made + synchronously in the thread calling <c>driver_async()</c>. The + current number of async threads in the async thread pool can be + retrieved via + <seealso marker="#driver_system_info">driver_system_info()</seealso>.</p> + <p>If there is a thread pool available, a thread will be + used. If the <c>key</c> argument is null, the threads from the + pool are used in a round-robin way, each call to + <c>driver_async</c> uses the next thread in the pool. With the + <c>key</c> argument set, this behaviour is changed. The two + same values of <c>*key</c> always get the same thread.</p> + <p>To make sure that a driver instance always uses the same + thread, the following call can be used:</p> + <p></p> + <code type="none"><![CDATA[ + unsigned int myKey = driver_async_port_key(myPort); + + r = driver_async(myPort, &myKey, myData, myFunc); + ]]></code> + <p>It is enough to initialize <c>myKey</c> once for each + driver instance.</p> + <p>If a thread is already working, the calls will be + queued up and executed in order. Using the same thread for + each driver instance ensures that the calls will be made in + sequence.</p> + <p>The <c>async_data</c> is the argument to the functions + <c>async_invoke</c> and <c>async_free</c>. It's typically a + pointer to a structure that contains a pipe or event that + can be used to signal that the async operation completed. + The data should be freed in <c>async_free</c>.</p> + <p>When the async operation is done, <seealso marker="driver_entry#ready_async">ready_async</seealso> driver + entry function is called. If <c>ready_async</c> is null in + the driver entry, the <c>async_free</c> function is called + instead.</p> + <p>The return value is -1 if the <c>driver_async</c> call + fails.</p> + <note> + <p>As of erts version 5.5.4.3 the default stack size for + threads in the async-thread pool is 16 kilowords, + i.e., 64 kilobyte on 32-bit architectures. + This small default size has been chosen since the + amount of async-threads might be quite large. The + default stack size is enough for drivers delivered + with Erlang/OTP, but might not be sufficiently large + for other dynamically linked in drivers that use the + driver_async() functionality. A suggested stack size + for threads in the async-thread pool can be configured + via the + <seealso marker="erl#async_thread_stack_size">+a</seealso> + command line argument of + <seealso marker="erl">erl(1)</seealso>.</p> + </note> + </desc> + </func> +<func> + <name><ret>unsigned int</ret><nametext>driver_async_port_key (ErlDrvPort port)</nametext></name> + <fsummary>Calculate an async key from an ErlDrvPort</fsummary> + <desc> + <marker id="driver_async_port_key"></marker> + <p>This function calculates a key for later use in <seealso + marker="#driver_async">driver_async()</seealso>. The keys are + evenly distributed so that a fair mapping between port id's + and async thread id's is achieved.</p> + <note> + <p>Before OTP-R16, the actual port id could be used as a key + with proper casting, but after the rewrite of the port + subsystem, this is no longer the case. With this function, you + can achieve the same distribution based on port id's as before + OTP-R16.</p> + </note> </desc> </func> + <func> - <name><ret>void</ret><nametext>driver_free_binary(ErlDrvBinary *bin)</nametext></name> - <fsummary>Free a driver binary</fsummary> + <name><ret>long</ret><nametext>driver_binary_dec_refc(ErlDrvBinary *bin)</nametext></name> + <fsummary>Decrement the reference count of a driver binary</fsummary> <desc> - <marker id="driver_free_binary"></marker> - <p>This function frees a driver binary <c>bin</c>, allocated - previously with <c>driver_alloc_binary</c>. Since binaries - in Erlang are reference counted, the binary may still be - around.</p> + <marker id="driver_binary_dec_refc"></marker> + <p>Decrements the reference count on <c>bin</c> and returns + the reference count reached after the decrement.</p> <p>This function is only thread-safe when the emulator with SMP support is used.</p> + <note> + <p>You should normally decrement the reference count of a + driver binary by calling + <seealso marker="#driver_free_binary">driver_free_binary()</seealso>. + <c>driver_binary_dec_refc()</c> does <em>not</em> free + the binary if the reference count reaches zero. <em>Only</em> + use <c>driver_binary_dec_refc()</c> when you are sure + <em>not</em> to reach a reference count of zero.</p> + </note> </desc> </func> + <func> <name><ret>long</ret><nametext>driver_binary_get_refc(ErlDrvBinary *bin)</nametext></name> <fsummary>Get the reference count of a driver binary</fsummary> @@ -1211,6 +1066,7 @@ typedef struct ErlIOVec { support is used.</p> </desc> </func> + <func> <name><ret>long</ret><nametext>driver_binary_inc_refc(ErlDrvBinary *bin)</nametext></name> <fsummary>Increment the reference count of a driver binary</fsummary> @@ -1222,65 +1078,134 @@ typedef struct ErlIOVec { support is used.</p> </desc> </func> + <func> - <name><ret>long</ret><nametext>driver_binary_dec_refc(ErlDrvBinary *bin)</nametext></name> - <fsummary>Decrement the reference count of a driver binary</fsummary> + <name><ret>ErlDrvTermData</ret><nametext>driver_caller(ErlDrvPort port)</nametext></name> + <fsummary>Return the process making the driver call</fsummary> <desc> - <marker id="driver_binary_dec_refc"></marker> - <p>Decrements the reference count on <c>bin</c> and returns - the reference count reached after the decrement.</p> - <p>This function is only thread-safe when the emulator with SMP - support is used.</p> - <note> - <p>You should normally decrement the reference count of a - driver binary by calling - <seealso marker="#driver_free_binary">driver_free_binary()</seealso>. - <c>driver_binary_dec_refc()</c> does <em>not</em> free - the binary if the reference count reaches zero. <em>Only</em> - use <c>driver_binary_dec_refc()</c> when you are sure - <em>not</em> to reach a reference count of zero.</p> - </note> + <marker id="driver_caller"></marker> + <p>This function returns the process id of the process that + made the current call to the driver. The process id can be + used with <c>driver_send_term</c> to send back data to the + caller. <c>driver_caller()</c> only returns valid data + when currently executing in one of the following driver + callbacks:</p> + <taglist> + <tag><seealso marker="driver_entry#start">start</seealso></tag> + <item>Called from <c>open_port/2</c>.</item> + <tag><seealso marker="driver_entry#output">output</seealso></tag> + <item>Called from <c>erlang:send/2</c>, and + <c>erlang:port_command/2</c></item> + <tag><seealso marker="driver_entry#outputv">outputv</seealso></tag> + <item>Called from <c>erlang:send/2</c>, and + <c>erlang:port_command/2</c></item> + <tag><seealso marker="driver_entry#control">control</seealso></tag> + <item>Called from <c>erlang:port_control/3</c></item> + <tag><seealso marker="driver_entry#call">call</seealso></tag> + <item>Called from <c>erlang:port_call/3</c></item> + </taglist> + <p>Note that this function is <em>not</em> thread-safe, not + even when the emulator with SMP support is used.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>driver_enq(ErlDrvPort port, char* buf, ErlDrvSizeT len)</nametext></name> - <fsummary>Enqueue data in the driver queue</fsummary> + <name><ret>int</ret><nametext>driver_cancel_timer(ErlDrvPort port)</nametext></name> + <fsummary>Cancel a previously set timer</fsummary> <desc> - <marker id="driver_enq"></marker> - <p>This function enqueues data in the driver queue. The data in - <c>buf</c> is copied (<c>len</c> bytes) and placed at the - end of the driver queue. The driver queue is normally used - in a FIFO way.</p> - <p>The driver queue is available to queue output from the - emulator to the driver (data from the driver to the emulator - is queued by the emulator in normal erlang message - queues). This can be useful if the driver has to wait for - slow devices etc, and wants to yield back to the - emulator. The driver queue is implemented as an ErlIOVec.</p> - <p>When the queue contains data, the driver won't close, until - the queue is empty.</p> + <marker id="driver_cancel_timer"></marker> + <p>This function cancels a timer set with + <c>driver_set_timer</c>.</p> <p>The return value is 0.</p> - <p>This function can be called from an arbitrary thread if a - <seealso marker="#ErlDrvPDL">port data lock</seealso> - associated with the <c>port</c> is locked by the calling - thread during the call.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>driver_pushq(ErlDrvPort port, char* buf, ErlDrvSizeT len)</nametext></name> - <fsummary>Push data at the head of the driver queue</fsummary> + <name><ret>int</ret><nametext>driver_compare_monitors(const ErlDrvMonitor *monitor1, const ErlDrvMonitor *monitor2)</nametext></name> + <fsummary>Compare two monitors</fsummary> <desc> - <marker id="driver_pushq"></marker> - <p>This function puts data at the head of the driver queue. The - data in <c>buf</c> is copied (<c>len</c> bytes) and placed - at the beginning of the queue.</p> - <p>The return value is 0.</p> - <p>This function can be called from an arbitrary thread if a - <seealso marker="#ErlDrvPDL">port data lock</seealso> - associated with the <c>port</c> is locked by the calling - thread during the call.</p> + <marker id="driver_compare_monitors"></marker> + <p>This function is used to compare two <c>ErlDrvMonitor</c>s. It + can also be used to imply some artificial order on monitors, + for whatever reason.</p> + <p>The function returns 0 if <c>monitor1</c> and + <c>monitor2</c> are equal, < 0 if <c>monitor1</c> is less + than <c>monitor2</c> and > 0 if <c>monitor1</c> is greater + than <c>monitor2</c>.</p> </desc> </func> + + <func> + <name><ret>ErlDrvTermData</ret><nametext>driver_connected(ErlDrvPort port)</nametext></name> + <fsummary>Return the port owner process</fsummary> + <desc> + <marker id="driver_connected"></marker> + <p>This function returns the port owner process.</p> + <p>Note that this function is <em>not</em> thread-safe, not + even when the emulator with SMP support is used.</p> + </desc> + </func> + + <func> + <name><ret>ErlDrvPort</ret><nametext>driver_create_port(ErlDrvPort port, ErlDrvTermData owner_pid, char* name, ErlDrvData drv_data)</nametext></name> + <fsummary>Create a new port (driver instance)</fsummary> + <desc> + <p>This function creates a new port executing the same driver + code as the port creating the new port. + A short description of the arguments:</p> + <taglist> + <tag><c>port</c></tag> + <item>The port handle of the port (driver instance) creating + the new port.</item> + <tag><c>owner_pid</c></tag> + <item>The process id of the Erlang process which will be + owner of the new port. This process will be linked + to the new port. You usually want to use + <c>driver_caller(port)</c> as <c>owner_pid</c>.</item> + <tag><c>name</c></tag> + <item>The port name of the new port. You usually want to + use the same port name as the driver name + (<seealso marker="driver_entry#driver_name">driver_name</seealso> + field of the + <seealso marker="driver_entry">driver_entry</seealso>).</item> + <tag><c>drv_data</c></tag> + <item>The driver defined handle that will be passed in subsequent + calls to driver call-backs. Note, that the + <seealso marker="driver_entry#start">driver start call-back</seealso> + will not be called for this new driver instance. + The driver defined handle is normally created in the + <seealso marker="driver_entry#start">driver start call-back</seealso> + when a port is created via + <seealso marker="erlang#open_port/2">erlang:open_port/2</seealso>. </item> + </taglist> + <p>The caller of <c>driver_create_port()</c> is allowed to + manipulate the newly created port when <c>driver_create_port()</c> + has returned. When + <seealso marker="#smp_support">port level locking</seealso> + is used, the creating port is, however, only allowed to + manipulate the newly created port until the current driver + call-back that was called by the emulator returns.</p> + <note> + <p>When + <seealso marker="#smp_support">port level locking</seealso> + is used, the creating port is only allowed to manipulate + the newly created port until the current driver call-back + returns.</p> + </note> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>driver_demonitor_process(ErlDrvPort port, const ErlDrvMonitor *monitor)</nametext></name> + <fsummary>Stop monitoring a process from a driver</fsummary> + <desc> + <marker id="driver_demonitor_process"></marker> + <p>This function cancels a monitor created earlier. </p> + <p>The function returns 0 if a monitor was removed and > 0 + if the monitor did no longer exist.</p> + </desc> + </func> + <func> <name><ret>ErlDrvSizeT</ret><nametext>driver_deq(ErlDrvPort port, ErlDrvSizeT size)</nametext></name> <fsummary>Dequeue data from the head of the driver queue</fsummary> @@ -1297,19 +1222,32 @@ typedef struct ErlIOVec { thread during the call.</p> </desc> </func> + <func> - <name><ret>ErlDrvSizeT</ret><nametext>driver_sizeq(ErlDrvPort port)</nametext></name> - <fsummary>Return the size of the driver queue</fsummary> + <name><ret>int</ret><nametext>driver_enq(ErlDrvPort port, char* buf, ErlDrvSizeT len)</nametext></name> + <fsummary>Enqueue data in the driver queue</fsummary> <desc> - <marker id="driver_sizeq"></marker> - <p>This function returns the number of bytes currently in the - driver queue.</p> + <marker id="driver_enq"></marker> + <p>This function enqueues data in the driver queue. The data in + <c>buf</c> is copied (<c>len</c> bytes) and placed at the + end of the driver queue. The driver queue is normally used + in a FIFO way.</p> + <p>The driver queue is available to queue output from the + emulator to the driver (data from the driver to the emulator + is queued by the emulator in normal erlang message + queues). This can be useful if the driver has to wait for + slow devices etc, and wants to yield back to the + emulator. The driver queue is implemented as an ErlIOVec.</p> + <p>When the queue contains data, the driver won't close, until + the queue is empty.</p> + <p>The return value is 0.</p> <p>This function can be called from an arbitrary thread if a <seealso marker="#ErlDrvPDL">port data lock</seealso> associated with the <c>port</c> is locked by the calling thread during the call.</p> </desc> </func> + <func> <name><ret>int</ret><nametext>driver_enq_bin(ErlDrvPort port, ErlDrvBinary *bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext></name> <fsummary>Enqueue binary in the driver queue</fsummary> @@ -1327,96 +1265,280 @@ typedef struct ErlIOVec { <p>The return value is 0.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>driver_pushq_bin(ErlDrvPort port, ErlDrvBinary *bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext></name> - <fsummary>Push binary at the head of the driver queue</fsummary> + <name><ret>int</ret><nametext>driver_enqv(ErlDrvPort port, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> + <fsummary>Enqueue vector in the driver queue</fsummary> <desc> - <marker id="driver_pushq_bin"></marker> - <p>This function puts data in the binary <c>bin</c>, at - <c>offset</c> with length <c>len</c> at the head of the - driver queue. It is most often faster than - <c>driver_pushq</c>, because the data doesn't have to be - copied.</p> + <marker id="driver_enqv"></marker> + <p>This function enqueues the data in <c>ev</c>, skipping the + first <c>skip</c> bytes of it, at the end of the driver + queue. It is faster than <c>driver_enq</c>, because the data + doesn't have to be copied.</p> + <p>The return value is 0.</p> <p>This function can be called from an arbitrary thread if a <seealso marker="#ErlDrvPDL">port data lock</seealso> associated with the <c>port</c> is locked by the calling thread during the call.</p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>driver_failure_atom(ErlDrvPort port, char *string)</nametext></name> + <name><ret>int</ret><nametext>driver_failure_posix(ErlDrvPort port, int error)</nametext></name> + <name><ret>int</ret><nametext>driver_failure(ErlDrvPort port, int error)</nametext></name> + <fsummary>Fail with error</fsummary> + <desc> + <marker id="driver_failure_atom"></marker> + <marker id="driver_failure_posix"></marker> + <marker id="driver_failure"></marker> + <p>These functions signal to Erlang that the driver has + encountered an error and should be closed. The port is + closed and the tuple <c>{'EXIT', error, Err}</c>, is sent to + the port owner process, where error is an error atom + (<c>driver_failure_atom</c> and + <c>driver_failure_posix</c>), or an integer + (<c>driver_failure</c>).</p> + <p>The driver should fail only when in severe error situations, + when the driver cannot possibly keep open, for instance + buffer allocation gets out of memory. For normal errors + it is more appropriate to send error codes with + <c>driver_output</c>.</p> <p>The return value is 0.</p> </desc> </func> + <func> - <name><ret>ErlDrvSizeT</ret><nametext>driver_peekqv(ErlDrvPort port, ErlIOVec *ev)</nametext></name> - <fsummary>Get the driver queue as an IO vector</fsummary> + <name><ret>int</ret><nametext>driver_failure_eof(ErlDrvPort port)</nametext></name> + <fsummary>Fail with EOF</fsummary> <desc> - <marker id="driver_peekqv"></marker> - <p> - This function retrieves the driver queue into a supplied - <c>ErlIOVec</c> <c>ev</c>. It also returns the queue size. - This is one of two ways to get data out of the queue. - </p> - <p> - If <c>ev</c> is <c>NULL</c> all ones i.e. <c>-1</c> type cast to - <c>ErlDrvSizeT</c> is returned. - </p> - <p>Nothing is removed from the queue by this function, that must be done - with <c>driver_deq</c>.</p> - <p>This function can be called from an arbitrary thread if a - <seealso marker="#ErlDrvPDL">port data lock</seealso> - associated with the <c>port</c> is locked by the calling - thread during the call.</p> + <marker id="driver_failure_eof"></marker> + <p>This function signals to erlang that the driver has + encountered an EOF and should be closed, unless the port was + opened with the <c>eof</c> option, in that case eof is sent + to the port. Otherwise, the port is closed and an + <c>'EXIT'</c> message is sent to the port owner process.</p> + <p>The return value is 0.</p> </desc> </func> + <func> - <name><ret>SysIOVec *</ret><nametext>driver_peekq(ErlDrvPort port, int *vlen)</nametext></name> - <fsummary>Get the driver queue as a vector</fsummary> + <name><ret>void</ret><nametext>driver_free(void *ptr)</nametext></name> + <fsummary>Free an allocated memory block</fsummary> <desc> - <marker id="driver_peekq"></marker> - <p>This function retrieves the driver queue as a pointer to an - array of <c>SysIOVec</c>s. It also returns the number of - elements in <c>vlen</c>. This is one of two ways to get data - out of the queue.</p> - <p>Nothing is removed from the queue by this function, that must be done - with <c>driver_deq</c>.</p> - <p>The returned array is suitable to use with the Unix system - call <c>writev</c>.</p> - <p>This function can be called from an arbitrary thread if a - <seealso marker="#ErlDrvPDL">port data lock</seealso> - associated with the <c>port</c> is locked by the calling - thread during the call.</p> + <marker id="driver_free"></marker> + <p>This function frees the memory pointed to by <c>ptr</c>. The + memory should have been allocated with + <c>driver_alloc</c>. All allocated memory should be + deallocated, just once. There is no garbage collection in + drivers.</p> + <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>driver_enqv(ErlDrvPort port, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> - <fsummary>Enqueue vector in the driver queue</fsummary> + <name><ret>void</ret><nametext>driver_free_binary(ErlDrvBinary *bin)</nametext></name> + <fsummary>Free a driver binary</fsummary> <desc> - <marker id="driver_enqv"></marker> - <p>This function enqueues the data in <c>ev</c>, skipping the - first <c>skip</c> bytes of it, at the end of the driver - queue. It is faster than <c>driver_enq</c>, because the data - doesn't have to be copied.</p> - <p>The return value is 0.</p> - <p>This function can be called from an arbitrary thread if a - <seealso marker="#ErlDrvPDL">port data lock</seealso> - associated with the <c>port</c> is locked by the calling - thread during the call.</p> + <marker id="driver_free_binary"></marker> + <p>This function frees a driver binary <c>bin</c>, allocated + previously with <c>driver_alloc_binary</c>. Since binaries + in Erlang are reference counted, the binary may still be + around.</p> + <p>This function is only thread-safe when the emulator with SMP + support is used.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>driver_pushqv(ErlDrvPort port, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> - <fsummary>Push vector at the head of the driver queue</fsummary> + <name><ret>ErlDrvTermData</ret><nametext>driver_get_monitored_process(ErlDrvPort port, const ErlDrvMonitor *monitor)</nametext></name> + <fsummary>Retrieve the process id from a monitor</fsummary> <desc> - <marker id="driver_pushqv"></marker> - <p>This function puts the data in <c>ev</c>, skipping the first - <c>skip</c> bytes of it, at the head of the driver queue. - It is faster than <c>driver_pushq</c>, because the data - doesn't have to be copied.</p> - <p>The return value is 0.</p> - <p>This function can be called from an arbitrary thread if a - <seealso marker="#ErlDrvPDL">port data lock</seealso> - associated with the <c>port</c> is locked by the calling - thread during the call.</p> + <marker id="driver_get_monitored_process"></marker> + <p>The function returns the process id associated with a living + monitor. It can be used in the <c>process_exit</c> call-back to + get the process identification for the exiting process.</p> + <p>The function returns <c>driver_term_nil</c> if the monitor + no longer exists.</p> </desc> </func> + + <func> + <name><ret>int</ret><nametext>driver_get_now(ErlDrvNowData *now)</nametext></name> + <fsummary>Read a system timestamp</fsummary> + <desc> + <marker id="driver_get_now"></marker> + <warning><p><em>This function is deprecated! Do not use it!</em> + Use <seealso marker="#erl_drv_monotonic_time"><c>erl_drv_monotonic_time()</c></seealso> + (perhaps in combination with + <seealso marker="#erl_drv_time_offset"><c>erl_drv_time_offset()</c></seealso>) + instead.</p></warning> + <p>This function reads a timestamp into the memory pointed to by + the parameter <c>now</c>. See the description of <seealso marker="#ErlDrvNowData">ErlDrvNowData</seealso> for + specification of its fields. </p> + <p>The return value is 0 unless the <c>now</c> pointer is not + valid, in which case it is < 0. </p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>driver_lock_driver(ErlDrvPort port)</nametext></name> + <fsummary>Make sure the driver is never unloaded</fsummary> + <desc> + <marker id="driver_lock_driver"></marker> + <p>This function locks the driver used by the port <c>port</c> + in memory for the rest of the emulator process' + lifetime. After this call, the driver behaves as one of Erlang's + statically linked in drivers.</p> + </desc> + </func> + + <func> + <name><ret>ErlDrvTermData</ret><nametext>driver_mk_atom(char* string)</nametext></name> + <fsummary>Make an atom from a name</fsummary> + <desc> + <marker id="driver_mk_atom"></marker> + <p>This function returns an atom given a name + <c>string</c>. The atom is created and won't change, so the + return value may be saved and reused, which is faster than + looking up the atom several times.</p> + <p>Note that this function is <em>not</em> thread-safe, not + even when the emulator with SMP support is used.</p> + </desc> + </func> + + <func> + <name><ret>ErlDrvTermData</ret><nametext>driver_mk_port(ErlDrvPort port)</nametext></name> + <fsummary>Make a erlang term port from a port</fsummary> + <desc> + <marker id="driver_mk_port"></marker> + <p>This function converts a port handle to the erlang term + format, usable in the <seealso marker="#erl_drv_output_term">erl_drv_output_term()</seealso>, and <seealso marker="#erl_drv_send_term">erl_drv_send_term()</seealso> functions.</p> + <p>Note that this function is <em>not</em> thread-safe, not + even when the emulator with SMP support is used.</p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>driver_monitor_process(ErlDrvPort port, ErlDrvTermData process, ErlDrvMonitor *monitor)</nametext></name> + <fsummary>Monitor a process from a driver</fsummary> + <desc> + <marker id="driver_monitor_process"></marker> + <p>Start monitoring a process from a driver. When a process is + monitored, a process exit will result in a call to the + provided <seealso marker="driver_entry#process_exit">process_exit</seealso> call-back + in the <seealso marker="driver_entry">ErlDrvEntry</seealso> + structure. The <c>ErlDrvMonitor</c> structure is filled in, for later + removal or compare.</p> + <p>The <c>process</c> parameter should be the return value of an + earlier call to <seealso marker="#driver_caller">driver_caller</seealso> or <seealso marker="#driver_connected">driver_connected</seealso> call.</p> + <p>The function returns 0 on success, < 0 if no call-back is + provided and > 0 if the process is no longer alive.</p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>driver_output(ErlDrvPort port, char *buf, ErlDrvSizeT len)</nametext></name> + <fsummary>Send data from driver to port owner</fsummary> + <desc> + <marker id="driver_output"></marker> + <p>The <c>driver_output</c> function is used to send data from + the driver up to the emulator. The data will be received as + terms or binary data, depending on how the driver port was + opened.</p> + <p>The data is queued in the port owner process' message + queue. Note that this does not yield to the emulator. (Since + the driver and the emulator run in the same thread.)</p> + <p>The parameter <c>buf</c> points to the data to send, and + <c>len</c> is the number of bytes.</p> + <p>The return value for all output functions is 0. (Unless the + driver is used for distribution, in which case it can fail + and return -1. For normal use, the output function always + returns 0.)</p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>driver_output_binary(ErlDrvPort port, char *hbuf, ErlDrvSizeT hlen, ErlDrvBinary* bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext></name> + <fsummary>Send data from a driver binary to port owner</fsummary> + <desc> + <marker id="driver_output_binary"></marker> + <p>This function sends data to port owner process from a + driver binary, it has a header buffer (<c>hbuf</c> + and <c>hlen</c>) just like <c>driver_output2</c>. The + <c>hbuf</c> parameter can be <c>NULL</c>.</p> + <p>The parameter <c>offset</c> is an offset into the binary and + <c>len</c> is the number of bytes to send.</p> + <p>Driver binaries are created with <c>driver_alloc_binary</c>.</p> + <p>The data in the header is sent as a list and the binary as + an Erlang binary in the tail of the list.</p> + <p>E.g. if <c>hlen</c> is 2, then the port owner process will + receive <c><![CDATA[[H1, H2 | <<T>>]]]></c>.</p> + <p>The return value is 0 for normal use.</p> + <p>Note that, using the binary syntax in Erlang, the driver + application can match the header directly from the binary, + so the header can be put in the binary, and hlen can be set + to 0.</p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>driver_output_term(ErlDrvPort port, ErlDrvTermData* term, int n)</nametext></name> + <fsummary>Send term data from driver to port owner</fsummary> + <desc> + <marker id="driver_output_term"></marker> + <warning><p><c>driver_output_term()</c> is deprecated and will + be removed in the OTP-R17 release. Use + <seealso marker="#erl_drv_send_term">erl_drv_output_term()</seealso> + instead.</p> + </warning> + <p>The parameters <c>term</c> and <c>n</c> do the same thing + as in <seealso marker="#erl_drv_output_term">erl_drv_output_term()</seealso>.</p> + <p>Note that this function is <em>not</em> thread-safe, not + even when the emulator with SMP support is used.</p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>driver_output2(ErlDrvPort port, char *hbuf, ErlDrvSizeT hlen, char *buf, ErlDrvSizeT len)</nametext></name> + <fsummary>Send data and binary data to port owner</fsummary> + <desc> + <marker id="driver_output2"></marker> + <p>The <c>driver_output2</c> function first sends <c>hbuf</c> + (length in <c>hlen</c>) data as a list, regardless of port + settings. Then <c>buf</c> is sent as a binary or list. + E.g. if <c>hlen</c> is 3 then the port owner process will + receive <c>[H1, H2, H3 | T]</c>.</p> + <p>The point of sending data as a list header, is to facilitate + matching on the data received.</p> + <p>The return value is 0 for normal use.</p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>driver_outputv(ErlDrvPort port, char* hbuf, ErlDrvSizeT hlen, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> + <fsummary>Send vectorized data to port owner</fsummary> + <desc> + <marker id="driver_outputv"></marker> + <p>This function sends data from an IO vector, <c>ev</c>, to + the port owner process. It has a header buffer (<c>hbuf</c> + and <c>hlen</c>), just like <c>driver_output2</c>.</p> + <p>The <c>skip</c> parameter is a number of bytes to skip of + the <c>ev</c> vector from the head.</p> + <p>You get vectors of <c>ErlIOVec</c> type from the driver + queue (see below), and the <seealso marker="driver_entry#outputv">outputv</seealso> driver entry + function. You can also make them yourself, if you want to + send several <c>ErlDrvBinary</c> buffers at once. Often + it is faster to use <c>driver_output</c> or + <c>driver_output_binary</c>.</p> + <p>E.g. if <c>hlen</c> is 2 and <c>ev</c> points to an array of + three binaries, the port owner process will receive <c><![CDATA[[H1, H2, <<B1>>, <<B2>> | <<B3>>]]]></c>.</p> + <p>The return value is 0 for normal use.</p> + <p>The comment for <c>driver_output_binary</c> applies for + <c>driver_outputv</c> too.</p> + </desc> + </func> + <func> <name><ret>ErlDrvPDL</ret><nametext>driver_pdl_create(ErlDrvPort port)</nametext></name> <fsummary>Create a port data lock</fsummary> @@ -1432,26 +1554,20 @@ typedef struct ErlIOVec { been associated with the <c>port</c>.</p> </desc> </func> + <func> - <name><ret>void</ret><nametext>driver_pdl_lock(ErlDrvPDL pdl)</nametext></name> - <fsummary>Lock port data lock</fsummary> - <desc> - <marker id="driver_pdl_lock"></marker> - <p>This function locks the port data lock passed as argument - (<c>pdl</c>).</p> - <p>This function is thread-safe.</p> - </desc> - </func> - <func> - <name><ret>void</ret><nametext>driver_pdl_unlock(ErlDrvPDL pdl)</nametext></name> - <fsummary>Unlock port data lock</fsummary> + <name><ret>long</ret><nametext>driver_pdl_dec_refc(ErlDrvPDL pdl)</nametext></name> + <fsummary></fsummary> <desc> - <marker id="driver_pdl_unlock"></marker> - <p>This function unlocks the port data lock passed as argument - (<c>pdl</c>).</p> + <marker id="driver_pdl_dec_refc"></marker> + <p>This function decrements the reference count of + the port data lock passed as argument (<c>pdl</c>).</p> + <p>The current reference count after the decrement has + been performed is returned.</p> <p>This function is thread-safe.</p> </desc> </func> + <func> <name><ret>long</ret><nametext>driver_pdl_get_refc(ErlDrvPDL pdl)</nametext></name> <fsummary></fsummary> @@ -1462,6 +1578,7 @@ typedef struct ErlIOVec { <p>This function is thread-safe.</p> </desc> </func> + <func> <name><ret>long</ret><nametext>driver_pdl_inc_refc(ErlDrvPDL pdl)</nametext></name> <fsummary></fsummary> @@ -1474,113 +1591,306 @@ typedef struct ErlIOVec { <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>long</ret><nametext>driver_pdl_dec_refc(ErlDrvPDL pdl)</nametext></name> - <fsummary></fsummary> + <name><ret>void</ret><nametext>driver_pdl_lock(ErlDrvPDL pdl)</nametext></name> + <fsummary>Lock port data lock</fsummary> <desc> - <marker id="driver_pdl_dec_refc"></marker> - <p>This function decrements the reference count of - the port data lock passed as argument (<c>pdl</c>).</p> - <p>The current reference count after the decrement has - been performed is returned.</p> + <marker id="driver_pdl_lock"></marker> + <p>This function locks the port data lock passed as argument + (<c>pdl</c>).</p> <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>driver_monitor_process(ErlDrvPort port, ErlDrvTermData process, ErlDrvMonitor *monitor)</nametext></name> - <fsummary>Monitor a process from a driver</fsummary> + <name><ret>void</ret><nametext>driver_pdl_unlock(ErlDrvPDL pdl)</nametext></name> + <fsummary>Unlock port data lock</fsummary> <desc> - <marker id="driver_monitor_process"></marker> - <p>Start monitoring a process from a driver. When a process is - monitored, a process exit will result in a call to the - provided <seealso marker="driver_entry#process_exit">process_exit</seealso> call-back - in the <seealso marker="driver_entry">ErlDrvEntry</seealso> - structure. The <c>ErlDrvMonitor</c> structure is filled in, for later - removal or compare.</p> - <p>The <c>process</c> parameter should be the return value of an - earlier call to <seealso marker="#driver_caller">driver_caller</seealso> or <seealso marker="#driver_connected">driver_connected</seealso> call.</p> - <p>The function returns 0 on success, < 0 if no call-back is - provided and > 0 if the process is no longer alive.</p> + <marker id="driver_pdl_unlock"></marker> + <p>This function unlocks the port data lock passed as argument + (<c>pdl</c>).</p> + <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>driver_demonitor_process(ErlDrvPort port, const ErlDrvMonitor *monitor)</nametext></name> - <fsummary>Stop monitoring a process from a driver</fsummary> + <name><ret>SysIOVec *</ret><nametext>driver_peekq(ErlDrvPort port, int *vlen)</nametext></name> + <fsummary>Get the driver queue as a vector</fsummary> <desc> - <marker id="driver_demonitor_process"></marker> - <p>This function cancels a monitor created earlier. </p> - <p>The function returns 0 if a monitor was removed and > 0 - if the monitor did no longer exist.</p> + <marker id="driver_peekq"></marker> + <p>This function retrieves the driver queue as a pointer to an + array of <c>SysIOVec</c>s. It also returns the number of + elements in <c>vlen</c>. This is one of two ways to get data + out of the queue.</p> + <p>Nothing is removed from the queue by this function, that must be done + with <c>driver_deq</c>.</p> + <p>The returned array is suitable to use with the Unix system + call <c>writev</c>.</p> + <p>This function can be called from an arbitrary thread if a + <seealso marker="#ErlDrvPDL">port data lock</seealso> + associated with the <c>port</c> is locked by the calling + thread during the call.</p> </desc> </func> + <func> - <name><ret>ErlDrvTermData</ret><nametext>driver_get_monitored_process(ErlDrvPort port, const ErlDrvMonitor *monitor)</nametext></name> - <fsummary>Retrieve the process id from a monitor</fsummary> + <name><ret>ErlDrvSizeT</ret><nametext>driver_peekqv(ErlDrvPort port, ErlIOVec *ev)</nametext></name> + <fsummary>Get the driver queue as an IO vector</fsummary> <desc> - <marker id="driver_get_monitored_process"></marker> - <p>The function returns the process id associated with a living - monitor. It can be used in the <c>process_exit</c> call-back to - get the process identification for the exiting process.</p> - <p>The function returns <c>driver_term_nil</c> if the monitor - no longer exists.</p> + <marker id="driver_peekqv"></marker> + <p> + This function retrieves the driver queue into a supplied + <c>ErlIOVec</c> <c>ev</c>. It also returns the queue size. + This is one of two ways to get data out of the queue. + </p> + <p> + If <c>ev</c> is <c>NULL</c> all ones i.e. <c>-1</c> type cast to + <c>ErlDrvSizeT</c> is returned. + </p> + <p>Nothing is removed from the queue by this function, that must be done + with <c>driver_deq</c>.</p> + <p>This function can be called from an arbitrary thread if a + <seealso marker="#ErlDrvPDL">port data lock</seealso> + associated with the <c>port</c> is locked by the calling + thread during the call.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>driver_compare_monitors(const ErlDrvMonitor *monitor1, const ErlDrvMonitor *monitor2)</nametext></name> - <fsummary>Compare two monitors</fsummary> + <name><ret>int</ret><nametext>driver_pushq(ErlDrvPort port, char* buf, ErlDrvSizeT len)</nametext></name> + <fsummary>Push data at the head of the driver queue</fsummary> <desc> - <marker id="driver_compare_monitors"></marker> - <p>This function is used to compare two <c>ErlDrvMonitor</c>s. It - can also be used to imply some artificial order on monitors, - for whatever reason.</p> - <p>The function returns 0 if <c>monitor1</c> and - <c>monitor2</c> are equal, < 0 if <c>monitor1</c> is less - than <c>monitor2</c> and > 0 if <c>monitor1</c> is greater - than <c>monitor2</c>.</p> + <marker id="driver_pushq"></marker> + <p>This function puts data at the head of the driver queue. The + data in <c>buf</c> is copied (<c>len</c> bytes) and placed + at the beginning of the queue.</p> + <p>The return value is 0.</p> + <p>This function can be called from an arbitrary thread if a + <seealso marker="#ErlDrvPDL">port data lock</seealso> + associated with the <c>port</c> is locked by the calling + thread during the call.</p> </desc> </func> + <func> - <name><ret>void</ret><nametext>add_driver_entry(ErlDrvEntry *de)</nametext></name> - <fsummary>Add a driver entry</fsummary> + <name><ret>int</ret><nametext>driver_pushq_bin(ErlDrvPort port, ErlDrvBinary *bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext></name> + <fsummary>Push binary at the head of the driver queue</fsummary> <desc> - <marker id="add_driver_entry"></marker> - <p>This function adds a driver entry to the list of drivers - known by Erlang. The <seealso marker="driver_entry#init">init</seealso> function of the <c>de</c> - parameter is called.</p> - <note> - <p>To use this function for adding drivers residing in - dynamically loaded code is dangerous. If the driver code - for the added driver resides in the same dynamically - loaded module (i.e. <c>.so</c> file) as a normal - dynamically loaded driver (loaded with the <c>erl_ddll</c> - interface), the caller should call <seealso marker="#driver_lock_driver">driver_lock_driver</seealso> before - adding driver entries.</p> - <p>Use of this function is generally deprecated.</p> - </note> + <marker id="driver_pushq_bin"></marker> + <p>This function puts data in the binary <c>bin</c>, at + <c>offset</c> with length <c>len</c> at the head of the + driver queue. It is most often faster than + <c>driver_pushq</c>, because the data doesn't have to be + copied.</p> + <p>This function can be called from an arbitrary thread if a + <seealso marker="#ErlDrvPDL">port data lock</seealso> + associated with the <c>port</c> is locked by the calling + thread during the call.</p> + <p>The return value is 0.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>remove_driver_entry(ErlDrvEntry *de)</nametext></name> - <fsummary>Remove a driver entry</fsummary> + <name><ret>int</ret><nametext>driver_pushqv(ErlDrvPort port, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> + <fsummary>Push vector at the head of the driver queue</fsummary> <desc> - <marker id="remove_driver_entry"></marker> - <p>This function removes a driver entry <c>de</c> previously - added with <c>add_driver_entry</c>.</p> - <p>Driver entries added by the <c>erl_ddll</c> erlang interface can - not be removed by using this interface.</p> + <marker id="driver_pushqv"></marker> + <p>This function puts the data in <c>ev</c>, skipping the first + <c>skip</c> bytes of it, at the head of the driver queue. + It is faster than <c>driver_pushq</c>, because the data + doesn't have to be copied.</p> + <p>The return value is 0.</p> + <p>This function can be called from an arbitrary thread if a + <seealso marker="#ErlDrvPDL">port data lock</seealso> + associated with the <c>port</c> is locked by the calling + thread during the call.</p> </desc> </func> + <func> - <name><ret>char *</ret><nametext>erl_errno_id(int error)</nametext></name> - <fsummary>Get erlang error atom name from error number</fsummary> + <name><ret>int</ret><nametext>driver_read_timer(ErlDrvPort port, unsigned long *time_left)</nametext></name> + <fsummary>Read the time left before timeout</fsummary> <desc> - <marker id="erl_errno_id"></marker> - <p>This function returns the atom name of the erlang error, - given the error number in <c>error</c>. Error atoms are: - <c>einval</c>, <c>enoent</c>, etc. It can be used to make - error terms from the driver.</p> + <marker id="driver_read_timer"></marker> + <p>This function reads the current time of a timer, and places + the result in <c>time_left</c>. This is the time in + milliseconds, before the timeout will occur.</p> + <p>The return value is 0.</p> + </desc> + </func> + + <func> + <name><ret>void *</ret><nametext>driver_realloc(void *ptr, ErlDrvSizeT size)</nametext></name> + <fsummary>Resize an allocated memory block</fsummary> + <desc> + <marker id="driver_realloc"></marker> + <p>This function resizes a memory block, either in place, or by + allocating a new block, copying the data and freeing the old + block. A pointer is returned to the reallocated memory. On + failure (out of memory), <c>NULL</c> is returned. (This is + most often a wrapper for <c>realloc</c>.)</p> + <p>This function is thread-safe.</p> + </desc> + </func> + + <func> + <name><ret>ErlDrvBinary *</ret><nametext>driver_realloc_binary(ErlDrvBinary *bin, ErlDrvSizeT size)</nametext></name> + <fsummary>Resize a driver binary</fsummary> + <desc> + <marker id="driver_realloc_binary"></marker> + <p>This function resizes a driver binary, while keeping the + data. The resized driver binary is returned. On failure (out + of memory), <c>NULL</c> is returned.</p> + <p>This function is only thread-safe when the emulator with SMP + support is used.</p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>driver_select(ErlDrvPort port, ErlDrvEvent event, int mode, int on)</nametext></name> + <fsummary>Provide an event for having the emulator call the driver</fsummary> + <desc> + <marker id="driver_select"></marker> + <p>This function is used by drivers to provide the emulator with + events to check for. This enables the emulator to call the driver + when something has happened asynchronously.</p> + <p>The <c>event</c> argument identifies an OS-specific event object. + On Unix systems, the functions <c>select</c>/<c>poll</c> are used. The + event object must be a socket or pipe (or other object that + <c>select</c>/<c>poll</c> can use). + On windows, the Win32 API function <c>WaitForMultipleObjects</c> + is used. This places other restrictions on the event object. + Refer to the Win32 SDK documentation.</p> + <p>The <c>on</c> parameter should be <c>1</c> for setting events + and <c>0</c> for clearing them.</p> + <p>The <c>mode</c> argument is a bitwise-or combination of + <c>ERL_DRV_READ</c>, <c>ERL_DRV_WRITE</c> and <c>ERL_DRV_USE</c>. + The first two specify whether to wait for read events and/or write + events. A fired read event will call + <seealso marker="driver_entry#ready_input">ready_input</seealso> + while a fired write event will call + <seealso marker="driver_entry#ready_output">ready_output</seealso>. + </p> + <note> + <p>Some OS (Windows) do not differentiate between read and write events. + The call-back for a fired event then only depends on the value of <c>mode</c>.</p> + </note> + <p><c>ERL_DRV_USE</c> specifies if we are using the event object or if we want to close it. + On an emulator with SMP support, it is not safe to clear all events + and then close the event object after <c>driver_select</c> has + returned. Another thread may still be using the event object + internally. To safely close an event object call + <c>driver_select</c> with <c>ERL_DRV_USE</c> and <c>on==0</c>. That + will clear all events and then call + <seealso marker="driver_entry#stop_select">stop_select</seealso> + when it is safe to close the event object. + <c>ERL_DRV_USE</c> should be set together with the first event + for an event object. It is harmless to set <c>ERL_DRV_USE</c> + even though it already has been done. Clearing all events but keeping + <c>ERL_DRV_USE</c> set will indicate that we are using the event + object and probably will set events for it again.</p> + <note> + <p>ERL_DRV_USE was added in OTP release R13. Old drivers will still work + as before. But it is recommended to update them to use <c>ERL_DRV_USE</c> and + <c>stop_select</c> to make sure that event objects are closed in a safe way.</p> + </note> + <p>The return value is 0 (failure, -1, only if the + <c>ready_input</c>/<c>ready_output</c> is + <c>NULL</c>).</p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>driver_send_term(ErlDrvPort port, ErlDrvTermData receiver, ErlDrvTermData* term, int n)</nametext></name> + <fsummary>Send term data to other process than port owner process</fsummary> + <desc> + <marker id="driver_send_term"></marker> + <warning><p><c>driver_send_term()</c> is deprecated and will + be removed in the OTP-R17 release. Use + <seealso marker="#erl_drv_send_term">erl_drv_send_term()</seealso> + instead.</p> + <p>Also note that parameters of <c>driver_send_term()</c> + cannot be properly checked by the runtime system when + executed by arbitrary threads. This may cause the + <c>driver_send_term()</c> function not to fail when + it should.</p> + </warning> + <p>The parameters <c>term</c> and <c>n</c> do the same thing + as in <seealso marker="#erl_drv_output_term">erl_drv_output_term()</seealso>.</p> + <p>This function is only thread-safe when the emulator with SMP + support is used.</p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>driver_set_timer(ErlDrvPort port, unsigned long time)</nametext></name> + <fsummary>Set a timer to call the driver</fsummary> + <desc> + <marker id="driver_set_timer"></marker> + <p>This function sets a timer on the driver, which will count + down and call the driver when it is timed out. The + <c>time</c> parameter is the time in milliseconds before the + timer expires.</p> + <p>When the timer reaches 0 and expires, the driver entry + function <seealso marker="driver_entry#timeout">timeout</seealso> is called.</p> + <p>Note that there is only one timer on each driver instance; + setting a new timer will replace an older one.</p> + <p>Return value is 0 (-1 only when the <c>timeout</c> driver + function is <c>NULL</c>).</p> + </desc> + </func> + + <func> + <name><ret>ErlDrvSizeT</ret><nametext>driver_sizeq(ErlDrvPort port)</nametext></name> + <fsummary>Return the size of the driver queue</fsummary> + <desc> + <marker id="driver_sizeq"></marker> + <p>This function returns the number of bytes currently in the + driver queue.</p> + <p>This function can be called from an arbitrary thread if a + <seealso marker="#ErlDrvPDL">port data lock</seealso> + associated with the <c>port</c> is locked by the calling + thread during the call.</p> + </desc> + </func> + + <func> + <name><ret>void</ret><nametext>driver_system_info(ErlDrvSysInfo *sys_info_ptr, size_t size)</nametext></name> + <fsummary>Get information about the Erlang runtime system</fsummary> + <desc> + <marker id="driver_system_info"></marker> + <p>This function will write information about the Erlang runtime + system into the + <seealso marker="#ErlDrvSysInfo">ErlDrvSysInfo</seealso> + structure referred to by the first argument. The second + argument should be the size of the + <seealso marker="#ErlDrvSysInfo">ErlDrvSysInfo</seealso> + structure, i.e., <c>sizeof(ErlDrvSysInfo)</c>.</p> + <p>See the documentation of the + <seealso marker="#ErlDrvSysInfo">ErlDrvSysInfo</seealso> + structure for information about specific fields.</p> </desc> </func> +<func> + <name><ret>ErlDrvSizeT</ret><nametext>driver_vec_to_buf(ErlIOVec *ev, char *buf, ErlDrvSizeT len)</nametext></name> + <fsummary>Collect data segments into a buffer</fsummary> + <desc> + <marker id="driver_vec_to_buf"></marker> + <p>This function collects several segments of data, referenced + by <c>ev</c>, by copying them in order to the buffer + <c>buf</c>, of the size <c>len</c>.</p> + <p>If the data is to be sent from the driver to the port owner + process, it is faster to use <c>driver_outputv</c>.</p> + <p>The return value is the space left in the buffer, i.e. if + the <c>ev</c> contains less than <c>len</c> bytes it's the + difference, and if <c>ev</c> contains <c>len</c> bytes or + more, it's 0. This is faster if there is more than one header byte, + since the binary syntax can construct integers directly from + the binary.</p> + </desc> + </func> + <func> <name><ret>void</ret><nametext>erl_drv_busy_msgq_limits(ErlDrvPort port, ErlDrvSizeT *low, ErlDrvSizeT *high)</nametext></name> <fsummary>Set and get limits for busy port message queue</fsummary> @@ -1640,128 +1950,449 @@ typedef struct ErlIOVec { function.</p> </desc> </func> + <func> - <name><ret>void</ret><nametext>set_busy_port(ErlDrvPort port, int on)</nametext></name> - <fsummary>Signal or unsignal port as busy</fsummary> + <name><ret>void</ret><nametext>erl_drv_cond_broadcast(ErlDrvCond *cnd)</nametext></name> + <fsummary>Broadcast on a condition variable</fsummary> <desc> - <marker id="set_busy_port"></marker> - <p>This function set and unset the busy state of the port. If - <c>on</c> is non-zero, the port is set to busy, if it's zero the port - is set to not busy. You typically want to combine - this feature with the <seealso marker="#erl_drv_busy_msgq_limits">busy - port message queue</seealso> functionality.</p> - <p>Processes sending command data to the port will be suspended - if either the port is busy or if the port message queue - is busy. Suspended processes will be resumed when neither the - port is busy, nor the port message queue is busy. Command data - is in this context data passed to the port using either - <c>Port ! {Owner, {command, Data}}</c>, or - <c>port_command/[2,3]</c>.</p> - <p>If the - <seealso marker="driver_entry#driver_flags"><![CDATA[ERL_DRV_FLAG_SOFT_BUSY]]></seealso> - has been set in the - <seealso marker="driver_entry">driver_entry</seealso>, - data can be forced into the driver via - <seealso marker="erlang#port_command/3">port_command(Port, Data, [force])</seealso> - even though the driver has signaled that it is busy. + <marker id="erl_drv_cond_broadcast"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>cnd</c></tag> + <item>A pointer to a condition variable to broadcast on.</item> + </taglist> + <p>This function broadcasts on a condition variable. That is, if + other threads are waiting on the condition variable being + broadcast on, <em>all</em> of them will be woken. </p> - <p>For information about busy port message queue functionality - see the documentation of the - <seealso marker="#erl_drv_busy_msgq_limits">erl_drv_busy_msgq_limits()</seealso> - function.</p> + <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>void</ret><nametext>set_port_control_flags(ErlDrvPort port, int flags)</nametext></name> - <fsummary>Set flags on how to handle control entry function</fsummary> + <name><ret>ErlDrvCond *</ret><nametext>erl_drv_cond_create(char *name)</nametext></name> + <fsummary>Create a condition variable</fsummary> <desc> - <marker id="set_port_control_flags"></marker> - <p>This function sets flags for how the <seealso marker="driver_entry#control">control</seealso> driver entry - function will return data to the port owner process. (The - <c>control</c> function is called from <c>port_control/3</c> - in erlang.)</p> - <p>Currently there are only two meaningful values for - <c>flags</c>: 0 means that data is returned in a list, and - <c>PORT_CONTROL_FLAG_BINARY</c> means data is returned as - a binary from <c>control</c>.</p> + <marker id="erl_drv_cond_create"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>name</c></tag> + <item>A string identifying the created condition variable. It + will be used to identify the condition variable in planned + future debug functionality. + </item> + </taglist> + <p>This function creates a condition variable and returns a + pointer to it. On failure <c>NULL</c> is returned. The driver + creating the condition variable has the responsibility of + destroying it before the driver is unloaded.</p> + <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>driver_failure_eof(ErlDrvPort port)</nametext></name> - <fsummary>Fail with EOF</fsummary> + <name><ret>void</ret><nametext>erl_drv_cond_destroy(ErlDrvCond *cnd)</nametext></name> + <fsummary>Destroy a condition variable</fsummary> <desc> - <marker id="driver_failure_eof"></marker> - <p>This function signals to erlang that the driver has - encountered an EOF and should be closed, unless the port was - opened with the <c>eof</c> option, in that case eof is sent - to the port. Otherwise, the port is closed and an - <c>'EXIT'</c> message is sent to the port owner process.</p> - <p>The return value is 0.</p> + <marker id="erl_drv_cond_destroy"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>cnd</c></tag> + <item>A pointer to a condition variable to destroy.</item> + </taglist> + <p>This function destroys a condition variable previously + created by + <seealso marker="#erl_drv_cond_create">erl_drv_cond_create()</seealso>. + </p> + <p>This function is thread-safe.</p> </desc> </func> + <func> + <name><ret>char *</ret><nametext>erl_drv_cond_name(ErlDrvCond *cnd)</nametext></name> + <fsummary>Get name of driver mutex.</fsummary> + <desc> + <marker id="erl_drv_cnd_name"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>cnd</c></tag> + <item>A pointer to an initialized condition.</item> + </taglist> + <p> + Returns a pointer to the name of the condition. + </p> + <note> + <p>This function is intended for debugging purposes only.</p> + </note> + </desc> + </func> + <func> - <name><ret>int</ret><nametext>driver_failure_atom(ErlDrvPort port, char *string)</nametext></name> - <name><ret>int</ret><nametext>driver_failure_posix(ErlDrvPort port, int error)</nametext></name> - <name><ret>int</ret><nametext>driver_failure(ErlDrvPort port, int error)</nametext></name> - <fsummary>Fail with error</fsummary> + <name><ret>void</ret><nametext>erl_drv_cond_signal(ErlDrvCond *cnd)</nametext></name> + <fsummary>Signal on a condition variable</fsummary> <desc> - <marker id="driver_failure_atom"></marker> - <marker id="driver_failure_posix"></marker> - <marker id="driver_failure"></marker> - <p>These functions signal to Erlang that the driver has - encountered an error and should be closed. The port is - closed and the tuple <c>{'EXIT', error, Err}</c>, is sent to - the port owner process, where error is an error atom - (<c>driver_failure_atom</c> and - <c>driver_failure_posix</c>), or an integer - (<c>driver_failure</c>).</p> - <p>The driver should fail only when in severe error situations, - when the driver cannot possibly keep open, for instance - buffer allocation gets out of memory. For normal errors - it is more appropriate to send error codes with - <c>driver_output</c>.</p> - <p>The return value is 0.</p> + <marker id="erl_drv_cond_signal"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>cnd</c></tag> + <item>A pointer to a condition variable to signal on.</item> + </taglist> + <p>This function signals on a condition variable. That is, if + other threads are waiting on the condition variable being + signaled, <em>one</em> of them will be woken. + </p> + <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>ErlDrvTermData</ret><nametext>driver_connected(ErlDrvPort port)</nametext></name> - <fsummary>Return the port owner process</fsummary> + <name><ret>void</ret><nametext>erl_drv_cond_wait(ErlDrvCond *cnd, ErlDrvMutex *mtx)</nametext></name> + <fsummary>Wait on a condition variable</fsummary> <desc> - <marker id="driver_connected"></marker> - <p>This function returns the port owner process.</p> - <p>Note that this function is <em>not</em> thread-safe, not - even when the emulator with SMP support is used.</p> + <marker id="erl_drv_cond_wait"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>cnd</c></tag> + <item>A pointer to a condition variable to wait on.</item> + <tag><c>mtx</c></tag> + <item>A pointer to a mutex to unlock while waiting.</item> + <tag><c></c></tag> + <item></item> + </taglist> + <p>This function waits on a condition variable. The calling + thread is blocked until another thread wakes it by signaling + or broadcasting on the condition variable. Before the calling + thread is blocked it unlocks the mutex passed as argument, and + when the calling thread is woken it locks the same mutex before + returning. That is, the mutex currently has to be locked by + the calling thread when calling this function. + </p> + <note><p><c>erl_drv_cond_wait()</c> might return even though + no-one has signaled or broadcast on the condition + variable. Code calling <c>erl_drv_cond_wait()</c> should + always be prepared for <c>erl_drv_cond_wait()</c> + returning even though the condition that the thread was + waiting for hasn't occurred. That is, when returning from + <c>erl_drv_cond_wait()</c> always check if the condition + has occurred, and if not call <c>erl_drv_cond_wait()</c> + again. + </p></note> + <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>ErlDrvTermData</ret><nametext>driver_caller(ErlDrvPort port)</nametext></name> - <fsummary>Return the process making the driver call</fsummary> + <name><ret>int</ret><nametext>erl_drv_consume_timeslice(ErlDrvPort port, int percent)</nametext></name> + <fsummary>Give the runtime system a hint about how much CPU time the + current driver callback call has consumed</fsummary> <desc> - <marker id="driver_caller"></marker> - <p>This function returns the process id of the process that - made the current call to the driver. The process id can be - used with <c>driver_send_term</c> to send back data to the - caller. <c>driver_caller()</c> only returns valid data - when currently executing in one of the following driver - callbacks:</p> - <taglist> - <tag><seealso marker="driver_entry#start">start</seealso></tag> - <item>Called from <c>open_port/2</c>.</item> - <tag><seealso marker="driver_entry#output">output</seealso></tag> - <item>Called from <c>erlang:send/2</c>, and - <c>erlang:port_command/2</c></item> - <tag><seealso marker="driver_entry#outputv">outputv</seealso></tag> - <item>Called from <c>erlang:send/2</c>, and - <c>erlang:port_command/2</c></item> - <tag><seealso marker="driver_entry#control">control</seealso></tag> - <item>Called from <c>erlang:port_control/3</c></item> - <tag><seealso marker="driver_entry#call">call</seealso></tag> - <item>Called from <c>erlang:port_call/3</c></item> - </taglist> - <p>Note that this function is <em>not</em> thread-safe, not - even when the emulator with SMP support is used.</p> + <marker id="erl_drv_consume_timeslice"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>port</c></tag> + <item>Port handle of the executing port.</item> + <tag><c>percent</c></tag> + <item>Approximate consumed fraction of a full + time-slice in percent.</item> + </taglist> + <p>Give the runtime system a hint about how much CPU time the + current driver callback call has consumed since last hint, or + since the start of the callback if no previous hint has been given. + The time is given as a fraction, in percent, of a full time-slice + that a port is allowed to execute before it should surrender the + CPU to other runnable ports or processes. Valid range is + <c>[1, 100]</c>. The scheduling time-slice is not an exact entity, + but can usually be approximated to about 1 millisecond.</p> + + <p>Note that it is up to the runtime system to determine if and + how to use this information. Implementations on some platforms + may use other means in order to determine the consumed fraction + of the time-slice. Lengthy driver callbacks should regardless of + this frequently call the <c>erl_drv_consume_timeslice()</c> + function in order to determine if it is allowed to continue + execution or not.</p> + + <p><c>erl_drv_consume_timeslice()</c> returns a non-zero value + if the time-slice has been exhausted, and zero if the callback is + allowed to continue execution. If a non-zero value is + returned the driver callback should return as soon as possible in + order for the port to be able to yield.</p> + + <p>This function is provided to better support co-operative scheduling, + improve system responsiveness, and to make it easier to prevent + misbehaviors of the VM due to a port monopolizing a scheduler thread. + It can be used when dividing length work into a number of repeated + driver callback calls without the need to use threads. Also see the + important <seealso marker="#WARNING">warning</seealso> text at the + beginning of this document.</p> </desc> </func> + + <func> + <name><ret>ErlDrvTime</ret><nametext>erl_drv_convert_time_unit(ErlDrvTime val, ErlDrvTimeUnit from, ErlDrvTimeUnit to)</nametext></name> + <fsummary>Convert time unit of a time value</fsummary> + <desc> + <marker id="erl_drv_convert_time_unit"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>val</c></tag> + <item>Value to convert time unit for.</item> + <tag><c>from</c></tag> + <item>Time unit of <c>val</c>.</item> + <tag><c>to</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p>Converts the <c>val</c> value of time unit <c>from</c> to + the corresponding value of time unit <c>to</c>. The result is + rounded using the floor function.</p> + <p>Returns <c>ERL_DRV_TIME_ERROR</c> if called with an invalid + time unit argument.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> + <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> + </list> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>erl_drv_equal_tids(ErlDrvTid tid1, ErlDrvTid tid2)</nametext></name> + <fsummary>Compare thread identifiers for equality</fsummary> + <desc> + <marker id="erl_drv_equal_tids"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>tid1</c></tag> + <item>A thread identifier.</item> + <tag><c>tid2</c></tag> + <item>A thread identifier.</item> + </taglist> + <p>This function compares two thread identifiers for equality, + and returns <c>0</c> it they aren't equal, and + a value not equal to <c>0</c> if they are equal.</p> + <note><p>A Thread identifier may be reused very quickly after + a thread has terminated. Therefore, if a thread + corresponding to one of the involved thread identifiers + has terminated since the thread identifier was saved, + the result of <c>erl_drv_equal_tids()</c> might not give + the expected result. + </p></note> + <p>This function is thread-safe.</p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>erl_drv_getenv(const char *key, char *value, size_t *value_size)</nametext></name> + <fsummary>Get the value of an environment variable</fsummary> + <desc> + <marker id="erl_drv_getenv"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>key</c></tag> + <item>A null terminated string containing the + name of the environment variable.</item> + <tag><c>value</c></tag> + <item>A pointer to an output buffer.</item> + <tag><c>value_size</c></tag> + <item>A pointer to an integer. The integer is both used for + passing input and output sizes (see below). + </item> + </taglist> + <p>This function retrieves the value of an environment variable. + When called, <c>*value_size</c> should contain the size of + the <c>value</c> buffer. On success <c>0</c> is returned, + the value of the environment variable has been written to + the <c>value</c> buffer, and <c>*value_size</c> contains the + string length (excluding the terminating null character) of + the value written to the <c>value</c> buffer. On failure, + i.e., no such environment variable was found, a value less than + <c>0</c> is returned. When the size of the <c>value</c> + buffer is too small, a value greater than <c>0</c> is returned + and <c>*value_size</c> has been set to the buffer size needed. + </p> + <warning><p>Do <em>not</em> use libc's <c>getenv</c> or similar + C library interfaces from a driver. + </p></warning> + <p>This function is thread-safe.</p> + </desc> + </func> + + <func> + <name><ret>void</ret><nametext>erl_drv_init_ack(ErlDrvPort port, ErlDrvData res)</nametext></name> + <fsummary>Acknowledge the start of the port</fsummary> + <desc> + <marker id="erl_drv_init_ack"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>port</c></tag> + <item>The port handle of the port (driver instance) creating + doing the acknowledgment. + </item> + <tag><c>res</c></tag> + <item>The result of the port initialization. This can be the same values + as the return value of <seealso marker="driver_entry#start">start</seealso>, + i.e any of the error codes or the ErlDrvData that is to be used for this + port. + </item> + </taglist> + <p> + When this function is called the initiating erlang:open_port call is + returned as if the <seealso marker="driver_entry#start">start</seealso> + function had just been called. It can only be used when the + <seealso marker="driver_entry#driver_flags">ERL_DRV_FLAG_USE_INIT_ACK</seealso> + flag has been set on the linked-in driver. + </p> + </desc> + </func> + + <func> + <name><ret>ErlDrvTime</ret><nametext>erl_drv_monotonic_time(ErlDrvTimeUnit time_unit)</nametext></name> + <fsummary>Get Erlang Monotonic Time</fsummary> + <desc> + <marker id="erl_drv_monotonic_time"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>time_unit</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p> + Returns + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso>. Note that it is not uncommon with + negative values. + </p> + <p>Returns <c>ERL_DRV_TIME_ERROR</c> if called with an invalid + time unit argument, or if called from a thread that is not a + scheduler thread.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> + <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> + </list> + </desc> + </func> + + <func> + <name><ret>ErlDrvMutex *</ret><nametext>erl_drv_mutex_create(char *name)</nametext></name> + <fsummary>Create a mutex</fsummary> + <desc> + <marker id="erl_drv_mutex_create"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>name</c></tag> + <item>A string identifying the created mutex. It will be used + to identify the mutex in planned future debug functionality. + </item> + </taglist> + <p>This function creates a mutex and returns a pointer to it. On + failure <c>NULL</c> is returned. The driver creating the mutex + has the responsibility of destroying it before the driver is + unloaded. + </p> + <p>This function is thread-safe.</p> + </desc> + </func> + + <func> + <name><ret>void</ret><nametext>erl_drv_mutex_destroy(ErlDrvMutex *mtx)</nametext></name> + <fsummary>Destroy a mutex</fsummary> + <desc> + <marker id="erl_drv_mutex_destroy"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>mtx</c></tag> + <item>A pointer to a mutex to destroy.</item> + </taglist> + <p>This function destroys a mutex previously created by + <seealso marker="#erl_drv_mutex_create">erl_drv_mutex_create()</seealso>. + The mutex has to be in an unlocked state before being + destroyed. + </p> + <p>This function is thread-safe.</p> + </desc> + </func> + + <func> + <name><ret>void</ret><nametext>erl_drv_mutex_lock(ErlDrvMutex *mtx)</nametext></name> + <fsummary>Lock a mutex</fsummary> + <desc> + <marker id="erl_drv_mutex_lock"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>mtx</c></tag> + <item>A pointer to a mutex to lock.</item> + </taglist> + <p>This function locks a mutex. The calling thread will be + blocked until the mutex has been locked. A thread + which currently has locked the mutex may <em>not</em> lock + the same mutex again. + </p> + <warning><p>If you leave a mutex locked in an emulator thread + when you let the thread out of your control, you will + <em>very likely</em> deadlock the whole emulator. + </p></warning> + <p>This function is thread-safe.</p> + </desc> + </func> + + <func> + <name><ret>char *</ret><nametext>erl_drv_mutex_name(ErlDrvMutex *mtx)</nametext></name> + <fsummary>Get name of driver mutex.</fsummary> + <desc> + <marker id="erl_drv_mutex_name"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>mtx</c></tag> + <item>A pointer to an initialized mutex.</item> + </taglist> + <p> + Returns a pointer to the name of the mutex. + </p> + <note> + <p>This function is intended for debugging purposes only.</p> + </note> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>erl_drv_mutex_trylock(ErlDrvMutex *mtx)</nametext></name> + <fsummary>Try lock a mutex</fsummary> + <desc> + <marker id="erl_drv_mutex_trylock"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>mtx</c></tag> + <item>A pointer to a mutex to try to lock.</item> + </taglist> + <p>This function tries to lock a mutex. If successful <c>0</c>, + is returned; otherwise, <c>EBUSY</c> is returned. A thread + which currently has locked the mutex may <em>not</em> try to + lock the same mutex again. + </p> + <warning><p>If you leave a mutex locked in an emulator thread + when you let the thread out of your control, you will + <em>very likely</em> deadlock the whole emulator. + </p></warning> + <p>This function is thread-safe.</p> + </desc> + </func> + + <func> + <name><ret>void</ret><nametext>erl_drv_mutex_unlock(ErlDrvMutex *mtx)</nametext></name> + <fsummary>Unlock a mutex</fsummary> + <desc> + <marker id="erl_drv_mutex_unlock"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>mtx</c></tag> + <item>A pointer to a mutex to unlock.</item> + </taglist> + <p>This function unlocks a mutex. The mutex currently has to be + locked by the calling thread. + </p> + <p>This function is thread-safe.</p> + </desc> + </func> + <func> <name><ret>int</ret><nametext>erl_drv_output_term(ErlDrvTermData port, ErlDrvTermData* term, int n)</nametext></name> <fsummary>Send term data from driver to port owner</fsummary> @@ -1939,255 +2570,237 @@ ERL_DRV_MAP int sz support is used.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>driver_output_term(ErlDrvPort port, ErlDrvTermData* term, int n)</nametext></name> - <fsummary>Send term data from driver to port owner</fsummary> + <name><ret>int</ret><nametext>erl_drv_putenv(const char *key, char *value)</nametext></name> + <fsummary>Set the value of an environment variable</fsummary> <desc> - <marker id="driver_output_term"></marker> - <warning><p><c>driver_output_term()</c> is deprecated and will - be removed in the OTP-R17 release. Use - <seealso marker="#erl_drv_send_term">erl_drv_output_term()</seealso> - instead.</p> - </warning> - <p>The parameters <c>term</c> and <c>n</c> do the same thing - as in <seealso marker="#erl_drv_output_term">erl_drv_output_term()</seealso>.</p> - <p>Note that this function is <em>not</em> thread-safe, not - even when the emulator with SMP support is used.</p> + <marker id="erl_drv_putenv"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>key</c></tag> + <item>A null terminated string containing the + name of the environment variable.</item> + <tag><c>value</c></tag> + <item>A null terminated string containing the + new value of the environment variable.</item> + </taglist> + <p>This function sets the value of an environment variable. + It returns <c>0</c> on success, and a value <c>!= 0</c> on + failure. + </p> + <note><p>The result of passing the empty string ("") as a value + is platform dependent. On some platforms the value of the + variable is set to the empty string, on others, the + environment variable is removed.</p> + </note> + <warning><p>Do <em>not</em> use libc's <c>putenv</c> or similar + C library interfaces from a driver. + </p></warning> + <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>ErlDrvTermData</ret><nametext>driver_mk_atom(char* string)</nametext></name> - <fsummary>Make an atom from a name</fsummary> + <name><ret>ErlDrvRWLock *</ret><nametext>erl_drv_rwlock_create(char *name)</nametext></name> + <fsummary>Create an rwlock</fsummary> <desc> - <marker id="driver_mk_atom"></marker> - <p>This function returns an atom given a name - <c>string</c>. The atom is created and won't change, so the - return value may be saved and reused, which is faster than - looking up the atom several times.</p> - <p>Note that this function is <em>not</em> thread-safe, not - even when the emulator with SMP support is used.</p> + <marker id="erl_drv_rwlock_create"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>name</c></tag> + <item>A string identifying the created rwlock. It will be used to + identify the rwlock in planned future debug functionality. + </item> + </taglist> + <p>This function creates an rwlock and returns a pointer to it. On + failure <c>NULL</c> is returned. The driver creating the rwlock + has the responsibility of destroying it before the driver is + unloaded. + </p> + <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>ErlDrvTermData</ret><nametext>driver_mk_port(ErlDrvPort port)</nametext></name> - <fsummary>Make a erlang term port from a port</fsummary> + <name><ret>void</ret><nametext>erl_drv_rwlock_destroy(ErlDrvRWLock *rwlck)</nametext></name> + <fsummary>Destroy an rwlock</fsummary> <desc> - <marker id="driver_mk_port"></marker> - <p>This function converts a port handle to the erlang term - format, usable in the <seealso marker="#erl_drv_output_term">erl_drv_output_term()</seealso>, and <seealso marker="#erl_drv_send_term">erl_drv_send_term()</seealso> functions.</p> - <p>Note that this function is <em>not</em> thread-safe, not - even when the emulator with SMP support is used.</p> + <marker id="erl_drv_rwlock_destroy"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>rwlck</c></tag> + <item>A pointer to an rwlock to destroy.</item> + </taglist> + <p>This function destroys an rwlock previously created by + <seealso marker="#erl_drv_rwlock_create">erl_drv_rwlock_create()</seealso>. + The rwlock has to be in an unlocked state before being destroyed. + </p> + <p>This function is thread-safe.</p> </desc> </func> + + <func> + <name><ret>char *</ret><nametext>erl_drv_rwlock_name(ErlDrvRWLock *rwlck)</nametext></name> + <fsummary>Get name of driver mutex.</fsummary> + <desc> + <marker id="erl_drv_rwlock_name"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>rwlck</c></tag> + <item>A pointer to an initialized r/w-lock.</item> + </taglist> + <p> + Returns a pointer to the name of the r/w-lock. + </p> + <note> + <p>This function is intended for debugging purposes only.</p> + </note> + </desc> + </func> + <func> - <name><ret>int</ret><nametext>erl_drv_send_term(ErlDrvTermData port, ErlDrvTermData receiver, ErlDrvTermData* term, int n)</nametext></name> - <fsummary>Send term data to other process than port owner process</fsummary> + <name><ret>void</ret><nametext>erl_drv_rwlock_rlock(ErlDrvRWLock *rwlck)</nametext></name> + <fsummary>Read lock an rwlock</fsummary> <desc> - <marker id="erl_drv_send_term"></marker> - <p>This function is the only way for a driver to send data to - <em>other</em> processes than the port owner process. The - <c>receiver</c> parameter specifies the process to receive - the data.</p> - <note><p>Note that the <c>port</c> parameter is <em>not</em> - an ordinary port handle, but a port handle converted using - <c>driver_mk_port()</c>.</p></note> - <p>The parameters <c>port</c>, <c>term</c> and <c>n</c> do the same thing - as in <seealso marker="#erl_drv_output_term">erl_drv_output_term()</seealso>.</p> - <p>This function is only thread-safe when the emulator with SMP - support is used.</p> + <marker id="erl_drv_rwlock_rlock"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>rwlck</c></tag> + <item>A pointer to an rwlock to read lock.</item> + </taglist> + <p>This function read locks an rwlock. The calling thread will be + blocked until the rwlock has been read locked. A thread + which currently has read or read/write locked the rwlock may + <em>not</em> lock the same rwlock again. + </p> + <warning><p>If you leave an rwlock locked in an emulator thread + when you let the thread out of your control, you will + <em>very likely</em> deadlock the whole emulator. + </p></warning> + <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>driver_send_term(ErlDrvPort port, ErlDrvTermData receiver, ErlDrvTermData* term, int n)</nametext></name> - <fsummary>Send term data to other process than port owner process</fsummary> + <name><ret>void</ret><nametext>erl_drv_rwlock_runlock(ErlDrvRWLock *rwlck)</nametext></name> + <fsummary>Read unlock an rwlock</fsummary> <desc> - <marker id="driver_send_term"></marker> - <warning><p><c>driver_send_term()</c> is deprecated and will - be removed in the OTP-R17 release. Use - <seealso marker="#erl_drv_send_term">erl_drv_send_term()</seealso> - instead.</p> - <p>Also note that parameters of <c>driver_send_term()</c> - cannot be properly checked by the runtime system when - executed by arbitrary threads. This may cause the - <c>driver_send_term()</c> function not to fail when - it should.</p> - </warning> - <p>The parameters <c>term</c> and <c>n</c> do the same thing - as in <seealso marker="#erl_drv_output_term">erl_drv_output_term()</seealso>.</p> - <p>This function is only thread-safe when the emulator with SMP - support is used.</p> + <marker id="erl_drv_rwlock_runlock"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>rwlck</c></tag> + <item>A pointer to an rwlock to read unlock.</item> + </taglist> + <p>This function read unlocks an rwlock. The rwlock currently + has to be read locked by the calling thread. + </p> + <p>This function is thread-safe.</p> </desc> </func> - <func> - <name><ret>long</ret><nametext>driver_async (ErlDrvPort port, unsigned int* key, void (*async_invoke)(void*), void* async_data, void (*async_free)(void*))</nametext></name> - <fsummary>Perform an asynchronous call within a driver</fsummary> - <desc> - <marker id="driver_async"></marker> - <p>This function performs an asynchronous call. The function - <c>async_invoke</c> is invoked in a thread separate from the - emulator thread. This enables the driver to perform - time-consuming, blocking operations without blocking the - emulator.</p> - <p>The async thread pool size can be set with the - <seealso marker="erl#async_thread_pool_size">+A</seealso> - command line argument of <seealso marker="erl">erl(1)</seealso>. - If no async thread pool is available, the call is made - synchronously in the thread calling <c>driver_async()</c>. The - current number of async threads in the async thread pool can be - retrieved via - <seealso marker="#driver_system_info">driver_system_info()</seealso>.</p> - <p>If there is a thread pool available, a thread will be - used. If the <c>key</c> argument is null, the threads from the - pool are used in a round-robin way, each call to - <c>driver_async</c> uses the next thread in the pool. With the - <c>key</c> argument set, this behaviour is changed. The two - same values of <c>*key</c> always get the same thread.</p> - <p>To make sure that a driver instance always uses the same - thread, the following call can be used:</p> - <p></p> - <code type="none"><![CDATA[ - unsigned int myKey = driver_async_port_key(myPort); - r = driver_async(myPort, &myKey, myData, myFunc); - ]]></code> - <p>It is enough to initialize <c>myKey</c> once for each - driver instance.</p> - <p>If a thread is already working, the calls will be - queued up and executed in order. Using the same thread for - each driver instance ensures that the calls will be made in - sequence.</p> - <p>The <c>async_data</c> is the argument to the functions - <c>async_invoke</c> and <c>async_free</c>. It's typically a - pointer to a structure that contains a pipe or event that - can be used to signal that the async operation completed. - The data should be freed in <c>async_free</c>.</p> - <p>When the async operation is done, <seealso marker="driver_entry#ready_async">ready_async</seealso> driver - entry function is called. If <c>ready_async</c> is null in - the driver entry, the <c>async_free</c> function is called - instead.</p> - <p>The return value is -1 if the <c>driver_async</c> call - fails.</p> - <note> - <p>As of erts version 5.5.4.3 the default stack size for - threads in the async-thread pool is 16 kilowords, - i.e., 64 kilobyte on 32-bit architectures. - This small default size has been chosen since the - amount of async-threads might be quite large. The - default stack size is enough for drivers delivered - with Erlang/OTP, but might not be sufficiently large - for other dynamically linked in drivers that use the - driver_async() functionality. A suggested stack size - for threads in the async-thread pool can be configured - via the - <seealso marker="erl#async_thread_stack_size">+a</seealso> - command line argument of - <seealso marker="erl">erl(1)</seealso>.</p> - </note> - </desc> - </func> <func> - <name><ret>unsigned int</ret><nametext>driver_async_port_key (ErlDrvPort port)</nametext></name> - <fsummary>Calculate an async key from an ErlDrvPort</fsummary> + <name><ret>void</ret><nametext>erl_drv_rwlock_rwlock(ErlDrvRWLock *rwlck)</nametext></name> + <fsummary>Read/Write lock an rwlock</fsummary> <desc> - <marker id="driver_async_port_key"></marker> - <p>This function calculates a key for later use in <seealso - marker="#driver_async">driver_async()</seealso>. The keys are - evenly distributed so that a fair mapping between port id's - and async thread id's is achieved.</p> - <note> - <p>Before OTP-R16, the actual port id could be used as a key - with proper casting, but after the rewrite of the port - subsystem, this is no longer the case. With this function, you - can achieve the same distribution based on port id's as before - OTP-R16.</p> - </note> + <marker id="erl_drv_rwlock_rwlock"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>rwlck</c></tag> + <item>A pointer to an rwlock to read/write lock.</item> + </taglist> + <p>This function read/write locks an rwlock. The calling thread + will be blocked until the rwlock has been read/write locked. + A thread which currently has read or read/write locked the + rwlock may <em>not</em> lock the same rwlock again. + </p> + <warning><p>If you leave an rwlock locked in an emulator thread + when you let the thread out of your control, you will + <em>very likely</em> deadlock the whole emulator. + </p></warning> + <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>driver_lock_driver(ErlDrvPort port)</nametext></name> - <fsummary>Make sure the driver is never unloaded</fsummary> + <name><ret>void</ret><nametext>erl_drv_rwlock_rwunlock(ErlDrvRWLock *rwlck)</nametext></name> + <fsummary>Read/Write unlock an rwlock</fsummary> <desc> - <marker id="driver_lock_driver"></marker> - <p>This function locks the driver used by the port <c>port</c> - in memory for the rest of the emulator process' - lifetime. After this call, the driver behaves as one of Erlang's - statically linked in drivers.</p> + <marker id="erl_drv_rwlock_rwunlock"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>rwlck</c></tag> + <item>A pointer to an rwlock to read/write unlock.</item> + </taglist> + <p>This function read/write unlocks an rwlock. The rwlock + currently has to be read/write locked by the calling thread. + </p> + <p>This function is thread-safe.</p> </desc> </func> + <func> - <name><ret>ErlDrvPort</ret><nametext>driver_create_port(ErlDrvPort port, ErlDrvTermData owner_pid, char* name, ErlDrvData drv_data)</nametext></name> - <fsummary>Create a new port (driver instance)</fsummary> + <name><ret>int</ret><nametext>erl_drv_rwlock_tryrlock(ErlDrvRWLock *rwlck)</nametext></name> + <fsummary>Try to read lock an rwlock</fsummary> <desc> - <p>This function creates a new port executing the same driver - code as the port creating the new port. - A short description of the arguments:</p> + <marker id="erl_drv_rwlock_tryrlock"></marker> + <p>Arguments:</p> <taglist> - <tag><c>port</c></tag> - <item>The port handle of the port (driver instance) creating - the new port.</item> - <tag><c>owner_pid</c></tag> - <item>The process id of the Erlang process which will be - owner of the new port. This process will be linked - to the new port. You usually want to use - <c>driver_caller(port)</c> as <c>owner_pid</c>.</item> - <tag><c>name</c></tag> - <item>The port name of the new port. You usually want to - use the same port name as the driver name - (<seealso marker="driver_entry#driver_name">driver_name</seealso> - field of the - <seealso marker="driver_entry">driver_entry</seealso>).</item> - <tag><c>drv_data</c></tag> - <item>The driver defined handle that will be passed in subsequent - calls to driver call-backs. Note, that the - <seealso marker="driver_entry#start">driver start call-back</seealso> - will not be called for this new driver instance. - The driver defined handle is normally created in the - <seealso marker="driver_entry#start">driver start call-back</seealso> - when a port is created via - <seealso marker="erlang#open_port/2">erlang:open_port/2</seealso>. </item> + <tag><c>rwlck</c></tag> + <item>A pointer to an rwlock to try to read lock.</item> </taglist> - <p>The caller of <c>driver_create_port()</c> is allowed to - manipulate the newly created port when <c>driver_create_port()</c> - has returned. When - <seealso marker="#smp_support">port level locking</seealso> - is used, the creating port is, however, only allowed to - manipulate the newly created port until the current driver - call-back that was called by the emulator returns.</p> - <note> - <p>When - <seealso marker="#smp_support">port level locking</seealso> - is used, the creating port is only allowed to manipulate - the newly created port until the current driver call-back - returns.</p> - </note> + <p>This function tries to read lock an rwlock. If successful + <c>0</c>, is returned; otherwise, <c>EBUSY</c> is returned. + A thread which currently has read or read/write locked the + rwlock may <em>not</em> try to lock the same rwlock again. + </p> + <warning><p>If you leave an rwlock locked in an emulator thread + when you let the thread out of your control, you will + <em>very likely</em> deadlock the whole emulator. + </p></warning> + <p>This function is thread-safe.</p> </desc> </func> <func> - <name><ret>void</ret><nametext>erl_drv_init_ack(ErlDrvPort port, ErlDrvData res)</nametext></name> - <fsummary>Acknowledge the start of the port</fsummary> + <name><ret>int</ret><nametext>erl_drv_rwlock_tryrwlock(ErlDrvRWLock *rwlck)</nametext></name> + <fsummary>Try to read/write lock an rwlock</fsummary> <desc> - <marker id="erl_drv_init_ack"></marker> + <marker id="erl_drv_rwlock_tryrwlock"></marker> <p>Arguments:</p> <taglist> - <tag><c>port</c></tag> - <item>The port handle of the port (driver instance) creating - doing the acknowledgment. - </item> - <tag><c>res</c></tag> - <item>The result of the port initialization. This can be the same values - as the return value of <seealso marker="driver_entry#start">start</seealso>, - i.e any of the error codes or the ErlDrvData that is to be used for this - port. - </item> + <tag><c>rwlck</c></tag> + <item>A pointer to an rwlock to try to read/write lock.</item> </taglist> - <p> - When this function is called the initiating erlang:open_port call is - returned as if the <seealso marker="driver_entry#start">start</seealso> - function had just been called. It can only be used when the - <seealso marker="driver_entry#driver_flags">ERL_DRV_FLAG_USE_INIT_ACK</seealso> - flag has been set on the linked-in driver. - </p> + <p>This function tries to read/write lock an rwlock. If successful + <c>0</c>, is returned; otherwise, <c>EBUSY</c> is returned. + A thread which currently has read or read/write locked the + rwlock may <em>not</em> try to lock the same rwlock again. + </p> + <warning><p>If you leave an rwlock locked in an emulator thread + when you let the thread out of your control, you will + <em>very likely</em> deadlock the whole emulator. + </p></warning> + <p>This function is thread-safe.</p> + </desc> + </func> + + <func> + <name><ret>int</ret><nametext>erl_drv_send_term(ErlDrvTermData port, ErlDrvTermData receiver, ErlDrvTermData* term, int n)</nametext></name> + <fsummary>Send term data to other process than port owner process</fsummary> + <desc> + <marker id="erl_drv_send_term"></marker> + <p>This function is the only way for a driver to send data to + <em>other</em> processes than the port owner process. The + <c>receiver</c> parameter specifies the process to receive + the data.</p> + <note><p>Note that the <c>port</c> parameter is <em>not</em> + an ordinary port handle, but a port handle converted using + <c>driver_mk_port()</c>.</p></note> + <p>The parameters <c>port</c>, <c>term</c> and <c>n</c> do the same thing + as in <seealso marker="#erl_drv_output_term">erl_drv_output_term()</seealso>.</p> + <p>This function is only thread-safe when the emulator with SMP + support is used.</p> </desc> </func> @@ -2275,53 +2888,6 @@ ERL_DRV_MAP int sz </func> <func> - <name><ret>ErlDrvThreadOpts *</ret><nametext>erl_drv_thread_opts_create(char *name)</nametext></name> - <fsummary>Create thread options</fsummary> - <desc> - <marker id="erl_drv_thread_opts_create"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>name</c></tag> - <item>A string identifying the created thread options. It will be used - to identify the thread options in planned future debug - functionality. - </item> - </taglist> - <p>This function allocates and initialize a thread option - structure. On failure <c>NULL</c> is returned. A thread option - structure is used for passing options to - <seealso marker="#erl_drv_thread_create">erl_drv_thread_create()</seealso>. - If the structure isn't modified before it is passed to - <seealso marker="#erl_drv_thread_create">erl_drv_thread_create()</seealso>, - the default values will be used. - </p> - <warning><p>You are not allowed to allocate the - <seealso marker="#ErlDrvThreadOpts">ErlDrvThreadOpts</seealso> - structure by yourself. It has to be allocated and - initialized by <c>erl_drv_thread_opts_create()</c>. - </p></warning> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>void</ret><nametext>erl_drv_thread_opts_destroy(ErlDrvThreadOpts *opts)</nametext></name> - <fsummary>Destroy thread options</fsummary> - <desc> - <marker id="erl_drv_thread_opts_destroy"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>opts</c></tag> - <item>A pointer to thread options to destroy.</item> - </taglist> - <p>This function destroys thread options previously created by - <seealso marker="#erl_drv_thread_opts_create">erl_drv_thread_opts_create()</seealso>. - </p> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> <name><ret>void</ret><nametext>erl_drv_thread_exit(void *exit_value)</nametext></name> <fsummary>Terminate calling thread</fsummary> <desc> @@ -2368,418 +2934,124 @@ ERL_DRV_MAP int sz </desc> </func> - <func> - <name><ret>ErlDrvTid</ret><nametext>erl_drv_thread_self(void)</nametext></name> - <fsummary>Get the thread identifier of the current thread</fsummary> - <desc> - <marker id="erl_drv_thread_self"></marker> - <p>This function returns the thread identifier of the - calling thread. - </p> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>int</ret><nametext>erl_drv_equal_tids(ErlDrvTid tid1, ErlDrvTid tid2)</nametext></name> - <fsummary>Compare thread identifiers for equality</fsummary> - <desc> - <marker id="erl_drv_equal_tids"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>tid1</c></tag> - <item>A thread identifier.</item> - <tag><c>tid2</c></tag> - <item>A thread identifier.</item> - </taglist> - <p>This function compares two thread identifiers for equality, - and returns <c>0</c> it they aren't equal, and - a value not equal to <c>0</c> if they are equal.</p> - <note><p>A Thread identifier may be reused very quickly after - a thread has terminated. Therefore, if a thread - corresponding to one of the involved thread identifiers - has terminated since the thread identifier was saved, - the result of <c>erl_drv_equal_tids()</c> might not give - the expected result. - </p></note> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>ErlDrvMutex *</ret><nametext>erl_drv_mutex_create(char *name)</nametext></name> - <fsummary>Create a mutex</fsummary> - <desc> - <marker id="erl_drv_mutex_create"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>name</c></tag> - <item>A string identifying the created mutex. It will be used - to identify the mutex in planned future debug functionality. - </item> - </taglist> - <p>This function creates a mutex and returns a pointer to it. On - failure <c>NULL</c> is returned. The driver creating the mutex - has the responsibility of destroying it before the driver is - unloaded. - </p> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>void</ret><nametext>erl_drv_mutex_destroy(ErlDrvMutex *mtx)</nametext></name> - <fsummary>Destroy a mutex</fsummary> - <desc> - <marker id="erl_drv_mutex_destroy"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>mtx</c></tag> - <item>A pointer to a mutex to destroy.</item> - </taglist> - <p>This function destroys a mutex previously created by - <seealso marker="#erl_drv_mutex_create">erl_drv_mutex_create()</seealso>. - The mutex has to be in an unlocked state before being - destroyed. - </p> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>void</ret><nametext>erl_drv_mutex_lock(ErlDrvMutex *mtx)</nametext></name> - <fsummary>Lock a mutex</fsummary> - <desc> - <marker id="erl_drv_mutex_lock"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>mtx</c></tag> - <item>A pointer to a mutex to lock.</item> - </taglist> - <p>This function locks a mutex. The calling thread will be - blocked until the mutex has been locked. A thread - which currently has locked the mutex may <em>not</em> lock - the same mutex again. - </p> - <warning><p>If you leave a mutex locked in an emulator thread - when you let the thread out of your control, you will - <em>very likely</em> deadlock the whole emulator. - </p></warning> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>int</ret><nametext>erl_drv_mutex_trylock(ErlDrvMutex *mtx)</nametext></name> - <fsummary>Try lock a mutex</fsummary> - <desc> - <marker id="erl_drv_mutex_trylock"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>mtx</c></tag> - <item>A pointer to a mutex to try to lock.</item> - </taglist> - <p>This function tries to lock a mutex. If successful <c>0</c>, - is returned; otherwise, <c>EBUSY</c> is returned. A thread - which currently has locked the mutex may <em>not</em> try to - lock the same mutex again. - </p> - <warning><p>If you leave a mutex locked in an emulator thread - when you let the thread out of your control, you will - <em>very likely</em> deadlock the whole emulator. - </p></warning> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>void</ret><nametext>erl_drv_mutex_unlock(ErlDrvMutex *mtx)</nametext></name> - <fsummary>Unlock a mutex</fsummary> - <desc> - <marker id="erl_drv_mutex_unlock"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>mtx</c></tag> - <item>A pointer to a mutex to unlock.</item> - </taglist> - <p>This function unlocks a mutex. The mutex currently has to be - locked by the calling thread. - </p> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>ErlDrvCond *</ret><nametext>erl_drv_cond_create(char *name)</nametext></name> - <fsummary>Create a condition variable</fsummary> - <desc> - <marker id="erl_drv_cond_create"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>name</c></tag> - <item>A string identifying the created condition variable. It - will be used to identify the condition variable in planned - future debug functionality. - </item> - </taglist> - <p>This function creates a condition variable and returns a - pointer to it. On failure <c>NULL</c> is returned. The driver - creating the condition variable has the responsibility of - destroying it before the driver is unloaded.</p> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>void</ret><nametext>erl_drv_cond_destroy(ErlDrvCond *cnd)</nametext></name> - <fsummary>Destroy a condition variable</fsummary> - <desc> - <marker id="erl_drv_cond_destroy"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>cnd</c></tag> - <item>A pointer to a condition variable to destroy.</item> - </taglist> - <p>This function destroys a condition variable previously - created by - <seealso marker="#erl_drv_cond_create">erl_drv_cond_create()</seealso>. - </p> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>void</ret><nametext>erl_drv_cond_signal(ErlDrvCond *cnd)</nametext></name> - <fsummary>Signal on a condition variable</fsummary> - <desc> - <marker id="erl_drv_cond_signal"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>cnd</c></tag> - <item>A pointer to a condition variable to signal on.</item> - </taglist> - <p>This function signals on a condition variable. That is, if - other threads are waiting on the condition variable being - signaled, <em>one</em> of them will be woken. - </p> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>void</ret><nametext>erl_drv_cond_broadcast(ErlDrvCond *cnd)</nametext></name> - <fsummary>Broadcast on a condition variable</fsummary> - <desc> - <marker id="erl_drv_cond_broadcast"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>cnd</c></tag> - <item>A pointer to a condition variable to broadcast on.</item> - </taglist> - <p>This function broadcasts on a condition variable. That is, if - other threads are waiting on the condition variable being - broadcast on, <em>all</em> of them will be woken. - </p> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>void</ret><nametext>erl_drv_cond_wait(ErlDrvCond *cnd, ErlDrvMutex *mtx)</nametext></name> - <fsummary>Wait on a condition variable</fsummary> - <desc> - <marker id="erl_drv_cond_wait"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>cnd</c></tag> - <item>A pointer to a condition variable to wait on.</item> - <tag><c>mtx</c></tag> - <item>A pointer to a mutex to unlock while waiting.</item> - <tag><c></c></tag> - <item></item> - </taglist> - <p>This function waits on a condition variable. The calling - thread is blocked until another thread wakes it by signaling - or broadcasting on the condition variable. Before the calling - thread is blocked it unlocks the mutex passed as argument, and - when the calling thread is woken it locks the same mutex before - returning. That is, the mutex currently has to be locked by - the calling thread when calling this function. - </p> - <note><p><c>erl_drv_cond_wait()</c> might return even though - no-one has signaled or broadcast on the condition - variable. Code calling <c>erl_drv_cond_wait()</c> should - always be prepared for <c>erl_drv_cond_wait()</c> - returning even though the condition that the thread was - waiting for hasn't occurred. That is, when returning from - <c>erl_drv_cond_wait()</c> always check if the condition - has occurred, and if not call <c>erl_drv_cond_wait()</c> - again. - </p></note> - <p>This function is thread-safe.</p> - </desc> - </func> + <func> + <name><ret>char *</ret><nametext>erl_drv_thread_name(ErlDrvTid tid)</nametext></name> + <fsummary>Get name of driver mutex.</fsummary> + <desc> + <marker id="erl_drv_rwlock_name"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>tid</c></tag> + <item>A thread identifier.</item> + </taglist> + <p> + Returns a pointer to the name of the thread. + </p> + <note> + <p>This function is intended for debugging purposes only.</p> + </note> + </desc> + </func> <func> - <name><ret>ErlDrvRWLock *</ret><nametext>erl_drv_rwlock_create(char *name)</nametext></name> - <fsummary>Create an rwlock</fsummary> + <name><ret>ErlDrvThreadOpts *</ret><nametext>erl_drv_thread_opts_create(char *name)</nametext></name> + <fsummary>Create thread options</fsummary> <desc> - <marker id="erl_drv_rwlock_create"></marker> + <marker id="erl_drv_thread_opts_create"></marker> <p>Arguments:</p> <taglist> <tag><c>name</c></tag> - <item>A string identifying the created rwlock. It will be used to - identify the rwlock in planned future debug functionality. + <item>A string identifying the created thread options. It will be used + to identify the thread options in planned future debug + functionality. </item> </taglist> - <p>This function creates an rwlock and returns a pointer to it. On - failure <c>NULL</c> is returned. The driver creating the rwlock - has the responsibility of destroying it before the driver is - unloaded. - </p> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>void</ret><nametext>erl_drv_rwlock_destroy(ErlDrvRWLock *rwlck)</nametext></name> - <fsummary>Destroy an rwlock</fsummary> - <desc> - <marker id="erl_drv_rwlock_destroy"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>rwlck</c></tag> - <item>A pointer to an rwlock to destroy.</item> - </taglist> - <p>This function destroys an rwlock previously created by - <seealso marker="#erl_drv_rwlock_create">erl_drv_rwlock_create()</seealso>. - The rwlock has to be in an unlocked state before being destroyed. - </p> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>void</ret><nametext>erl_drv_rwlock_rlock(ErlDrvRWLock *rwlck)</nametext></name> - <fsummary>Read lock an rwlock</fsummary> - <desc> - <marker id="erl_drv_rwlock_rlock"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>rwlck</c></tag> - <item>A pointer to an rwlock to read lock.</item> - </taglist> - <p>This function read locks an rwlock. The calling thread will be - blocked until the rwlock has been read locked. A thread - which currently has read or read/write locked the rwlock may - <em>not</em> lock the same rwlock again. - </p> - <warning><p>If you leave an rwlock locked in an emulator thread - when you let the thread out of your control, you will - <em>very likely</em> deadlock the whole emulator. - </p></warning> - <p>This function is thread-safe.</p> - </desc> - </func> - - <func> - <name><ret>int</ret><nametext>erl_drv_rwlock_tryrlock(ErlDrvRWLock *rwlck)</nametext></name> - <fsummary>Try to read lock an rwlock</fsummary> - <desc> - <marker id="erl_drv_rwlock_tryrlock"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>rwlck</c></tag> - <item>A pointer to an rwlock to try to read lock.</item> - </taglist> - <p>This function tries to read lock an rwlock. If successful - <c>0</c>, is returned; otherwise, <c>EBUSY</c> is returned. - A thread which currently has read or read/write locked the - rwlock may <em>not</em> try to lock the same rwlock again. + <p>This function allocates and initialize a thread option + structure. On failure <c>NULL</c> is returned. A thread option + structure is used for passing options to + <seealso marker="#erl_drv_thread_create">erl_drv_thread_create()</seealso>. + If the structure isn't modified before it is passed to + <seealso marker="#erl_drv_thread_create">erl_drv_thread_create()</seealso>, + the default values will be used. </p> - <warning><p>If you leave an rwlock locked in an emulator thread - when you let the thread out of your control, you will - <em>very likely</em> deadlock the whole emulator. + <warning><p>You are not allowed to allocate the + <seealso marker="#ErlDrvThreadOpts">ErlDrvThreadOpts</seealso> + structure by yourself. It has to be allocated and + initialized by <c>erl_drv_thread_opts_create()</c>. </p></warning> <p>This function is thread-safe.</p> </desc> </func> <func> - <name><ret>void</ret><nametext>erl_drv_rwlock_runlock(ErlDrvRWLock *rwlck)</nametext></name> - <fsummary>Read unlock an rwlock</fsummary> + <name><ret>void</ret><nametext>erl_drv_thread_opts_destroy(ErlDrvThreadOpts *opts)</nametext></name> + <fsummary>Destroy thread options</fsummary> <desc> - <marker id="erl_drv_rwlock_runlock"></marker> + <marker id="erl_drv_thread_opts_destroy"></marker> <p>Arguments:</p> <taglist> - <tag><c>rwlck</c></tag> - <item>A pointer to an rwlock to read unlock.</item> + <tag><c>opts</c></tag> + <item>A pointer to thread options to destroy.</item> </taglist> - <p>This function read unlocks an rwlock. The rwlock currently - has to be read locked by the calling thread. + <p>This function destroys thread options previously created by + <seealso marker="#erl_drv_thread_opts_create">erl_drv_thread_opts_create()</seealso>. </p> <p>This function is thread-safe.</p> </desc> </func> <func> - <name><ret>void</ret><nametext>erl_drv_rwlock_rwlock(ErlDrvRWLock *rwlck)</nametext></name> - <fsummary>Read/Write lock an rwlock</fsummary> + <name><ret>ErlDrvTid</ret><nametext>erl_drv_thread_self(void)</nametext></name> + <fsummary>Get the thread identifier of the current thread</fsummary> <desc> - <marker id="erl_drv_rwlock_rwlock"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>rwlck</c></tag> - <item>A pointer to an rwlock to read/write lock.</item> - </taglist> - <p>This function read/write locks an rwlock. The calling thread - will be blocked until the rwlock has been read/write locked. - A thread which currently has read or read/write locked the - rwlock may <em>not</em> lock the same rwlock again. + <marker id="erl_drv_thread_self"></marker> + <p>This function returns the thread identifier of the + calling thread. </p> - <warning><p>If you leave an rwlock locked in an emulator thread - when you let the thread out of your control, you will - <em>very likely</em> deadlock the whole emulator. - </p></warning> <p>This function is thread-safe.</p> </desc> </func> - <func> - <name><ret>int</ret><nametext>erl_drv_rwlock_tryrwlock(ErlDrvRWLock *rwlck)</nametext></name> - <fsummary>Try to read/write lock an rwlock</fsummary> - <desc> - <marker id="erl_drv_rwlock_tryrwlock"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>rwlck</c></tag> - <item>A pointer to an rwlock to try to read/write lock.</item> - </taglist> - <p>This function tries to read/write lock an rwlock. If successful - <c>0</c>, is returned; otherwise, <c>EBUSY</c> is returned. - A thread which currently has read or read/write locked the - rwlock may <em>not</em> try to lock the same rwlock again. - </p> - <warning><p>If you leave an rwlock locked in an emulator thread - when you let the thread out of your control, you will - <em>very likely</em> deadlock the whole emulator. - </p></warning> - <p>This function is thread-safe.</p> - </desc> - </func> + <func> + <name><ret>ErlDrvTime</ret><nametext>erl_drv_time_offset(ErlDrvTimeUnit time_unit)</nametext></name> + <fsummary>Get current Time Offset</fsummary> + <desc> + <marker id="erl_drv_time_offset"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>time_unit</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p>Returns the current time offset between + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang monotonic time</seealso> + and + <seealso marker="time_correction#Erlang_System_Time">Erlang system time</seealso> + converted into the <c>time_unit</c> passed as argument.</p> + <p>Returns <c>ERL_DRV_TIME_ERROR</c> if called with an invalid + time unit argument, or if called from a thread that is not a + scheduler thread.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> + <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> + </list> + </desc> + </func> <func> - <name><ret>void</ret><nametext>erl_drv_rwlock_rwunlock(ErlDrvRWLock *rwlck)</nametext></name> - <fsummary>Read/Write unlock an rwlock</fsummary> + <name><ret>void *</ret><nametext>erl_drv_tsd_get(ErlDrvTSDKey key)</nametext></name> + <fsummary>Get thread specific data</fsummary> <desc> - <marker id="erl_drv_rwlock_rwunlock"></marker> + <marker id="erl_drv_tsd_get"></marker> <p>Arguments:</p> <taglist> - <tag><c>rwlck</c></tag> - <item>A pointer to an rwlock to read/write unlock.</item> + <tag><c>key</c></tag> + <item>A thread specific data key.</item> </taglist> - <p>This function read/write unlocks an rwlock. The rwlock - currently has to be read/write locked by the calling thread. + <p>This function returns the thread specific data + associated with <c>key</c> for the calling thread. + If no data has been associated with <c>key</c> for + the calling thread, <c>NULL</c> is returned. </p> <p>This function is thread-safe.</p> </desc> @@ -2870,291 +3142,76 @@ ERL_DRV_MAP int sz </func> <func> - <name><ret>void *</ret><nametext>erl_drv_tsd_get(ErlDrvTSDKey key)</nametext></name> - <fsummary>Get thread specific data</fsummary> + <name><ret>char *</ret><nametext>erl_errno_id(int error)</nametext></name> + <fsummary>Get erlang error atom name from error number</fsummary> <desc> - <marker id="erl_drv_tsd_get"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>key</c></tag> - <item>A thread specific data key.</item> - </taglist> - <p>This function returns the thread specific data - associated with <c>key</c> for the calling thread. - If no data has been associated with <c>key</c> for - the calling thread, <c>NULL</c> is returned. - </p> - <p>This function is thread-safe.</p> + <marker id="erl_errno_id"></marker> + <p>This function returns the atom name of the erlang error, + given the error number in <c>error</c>. Error atoms are: + <c>einval</c>, <c>enoent</c>, etc. It can be used to make + error terms from the driver.</p> </desc> </func> <func> - <name><ret>int</ret><nametext>erl_drv_putenv(const char *key, char *value)</nametext></name> - <fsummary>Set the value of an environment variable</fsummary> + <name><ret>int</ret><nametext>remove_driver_entry(ErlDrvEntry *de)</nametext></name> + <fsummary>Remove a driver entry</fsummary> <desc> - <marker id="erl_drv_putenv"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>key</c></tag> - <item>A null terminated string containing the - name of the environment variable.</item> - <tag><c>value</c></tag> - <item>A null terminated string containing the - new value of the environment variable.</item> - </taglist> - <p>This function sets the value of an environment variable. - It returns <c>0</c> on success, and a value <c>!= 0</c> on - failure. - </p> - <note><p>The result of passing the empty string ("") as a value - is platform dependent. On some platforms the value of the - variable is set to the empty string, on others, the - environment variable is removed.</p> - </note> - <warning><p>Do <em>not</em> use libc's <c>putenv</c> or similar - C library interfaces from a driver. - </p></warning> - <p>This function is thread-safe.</p> + <marker id="remove_driver_entry"></marker> + <p>This function removes a driver entry <c>de</c> previously + added with <c>add_driver_entry</c>.</p> + <p>Driver entries added by the <c>erl_ddll</c> erlang interface can + not be removed by using this interface.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>erl_drv_getenv(const char *key, char *value, size_t *value_size)</nametext></name> - <fsummary>Get the value of an environment variable</fsummary> + <name><ret>void</ret><nametext>set_busy_port(ErlDrvPort port, int on)</nametext></name> + <fsummary>Signal or unsignal port as busy</fsummary> <desc> - <marker id="erl_drv_getenv"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>key</c></tag> - <item>A null terminated string containing the - name of the environment variable.</item> - <tag><c>value</c></tag> - <item>A pointer to an output buffer.</item> - <tag><c>value_size</c></tag> - <item>A pointer to an integer. The integer is both used for - passing input and output sizes (see below). - </item> - </taglist> - <p>This function retrieves the value of an environment variable. - When called, <c>*value_size</c> should contain the size of - the <c>value</c> buffer. On success <c>0</c> is returned, - the value of the environment variable has been written to - the <c>value</c> buffer, and <c>*value_size</c> contains the - string length (excluding the terminating null character) of - the value written to the <c>value</c> buffer. On failure, - i.e., no such environment variable was found, a value less than - <c>0</c> is returned. When the size of the <c>value</c> - buffer is too small, a value greater than <c>0</c> is returned - and <c>*value_size</c> has been set to the buffer size needed. + <marker id="set_busy_port"></marker> + <p>This function set and unset the busy state of the port. If + <c>on</c> is non-zero, the port is set to busy, if it's zero the port + is set to not busy. You typically want to combine + this feature with the <seealso marker="#erl_drv_busy_msgq_limits">busy + port message queue</seealso> functionality.</p> + <p>Processes sending command data to the port will be suspended + if either the port is busy or if the port message queue + is busy. Suspended processes will be resumed when neither the + port is busy, nor the port message queue is busy. Command data + is in this context data passed to the port using either + <c>Port ! {Owner, {command, Data}}</c>, or + <c>port_command/[2,3]</c>.</p> + <p>If the + <seealso marker="driver_entry#driver_flags"><![CDATA[ERL_DRV_FLAG_SOFT_BUSY]]></seealso> + has been set in the + <seealso marker="driver_entry">driver_entry</seealso>, + data can be forced into the driver via + <seealso marker="erlang#port_command/3">port_command(Port, Data, [force])</seealso> + even though the driver has signaled that it is busy. </p> - <warning><p>Do <em>not</em> use libc's <c>getenv</c> or similar - C library interfaces from a driver. - </p></warning> - <p>This function is thread-safe.</p> + <p>For information about busy port message queue functionality + see the documentation of the + <seealso marker="#erl_drv_busy_msgq_limits">erl_drv_busy_msgq_limits()</seealso> + function.</p> </desc> </func> + <func> - <name><ret>int</ret><nametext>erl_drv_consume_timeslice(ErlDrvPort port, int percent)</nametext></name> - <fsummary>Give the runtime system a hint about how much CPU time the - current driver callback call has consumed</fsummary> + <name><ret>void</ret><nametext>set_port_control_flags(ErlDrvPort port, int flags)</nametext></name> + <fsummary>Set flags on how to handle control entry function</fsummary> <desc> - <marker id="erl_drv_consume_timeslice"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>port</c></tag> - <item>Port handle of the executing port.</item> - <tag><c>percent</c></tag> - <item>Approximate consumed fraction of a full - time-slice in percent.</item> - </taglist> - <p>Give the runtime system a hint about how much CPU time the - current driver callback call has consumed since last hint, or - since the start of the callback if no previous hint has been given. - The time is given as a fraction, in percent, of a full time-slice - that a port is allowed to execute before it should surrender the - CPU to other runnable ports or processes. Valid range is - <c>[1, 100]</c>. The scheduling time-slice is not an exact entity, - but can usually be approximated to about 1 millisecond.</p> - - <p>Note that it is up to the runtime system to determine if and - how to use this information. Implementations on some platforms - may use other means in order to determine the consumed fraction - of the time-slice. Lengthy driver callbacks should regardless of - this frequently call the <c>erl_drv_consume_timeslice()</c> - function in order to determine if it is allowed to continue - execution or not.</p> - - <p><c>erl_drv_consume_timeslice()</c> returns a non-zero value - if the time-slice has been exhausted, and zero if the callback is - allowed to continue execution. If a non-zero value is - returned the driver callback should return as soon as possible in - order for the port to be able to yield.</p> - - <p>This function is provided to better support co-operative scheduling, - improve system responsiveness, and to make it easier to prevent - misbehaviors of the VM due to a port monopolizing a scheduler thread. - It can be used when dividing length work into a number of repeated - driver callback calls without the need to use threads. Also see the - important <seealso marker="#WARNING">warning</seealso> text at the - beginning of this document.</p> + <marker id="set_port_control_flags"></marker> + <p>This function sets flags for how the <seealso marker="driver_entry#control">control</seealso> driver entry + function will return data to the port owner process. (The + <c>control</c> function is called from <c>port_control/3</c> + in erlang.)</p> + <p>Currently there are only two meaningful values for + <c>flags</c>: 0 means that data is returned in a list, and + <c>PORT_CONTROL_FLAG_BINARY</c> means data is returned as + a binary from <c>control</c>.</p> </desc> </func> - - <func> - <name><ret>char *</ret><nametext>erl_drv_cond_name(ErlDrvCond *cnd)</nametext></name> - <fsummary>Get name of driver mutex.</fsummary> - <desc> - <marker id="erl_drv_cnd_name"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>cnd</c></tag> - <item>A pointer to an initialized condition.</item> - </taglist> - <p> - Returns a pointer to the name of the condition. - </p> - <note> - <p>This function is intended for debugging purposes only.</p> - </note> - </desc> - </func> - - <func> - <name><ret>char *</ret><nametext>erl_drv_mutex_name(ErlDrvMutex *mtx)</nametext></name> - <fsummary>Get name of driver mutex.</fsummary> - <desc> - <marker id="erl_drv_mutex_name"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>mtx</c></tag> - <item>A pointer to an initialized mutex.</item> - </taglist> - <p> - Returns a pointer to the name of the mutex. - </p> - <note> - <p>This function is intended for debugging purposes only.</p> - </note> - </desc> - </func> - - <func> - <name><ret>char *</ret><nametext>erl_drv_rwlock_name(ErlDrvRWLock *rwlck)</nametext></name> - <fsummary>Get name of driver mutex.</fsummary> - <desc> - <marker id="erl_drv_rwlock_name"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>rwlck</c></tag> - <item>A pointer to an initialized r/w-lock.</item> - </taglist> - <p> - Returns a pointer to the name of the r/w-lock. - </p> - <note> - <p>This function is intended for debugging purposes only.</p> - </note> - </desc> - </func> - - <func> - <name><ret>char *</ret><nametext>erl_drv_thread_name(ErlDrvTid tid)</nametext></name> - <fsummary>Get name of driver mutex.</fsummary> - <desc> - <marker id="erl_drv_rwlock_name"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>tid</c></tag> - <item>A thread identifier.</item> - </taglist> - <p> - Returns a pointer to the name of the thread. - </p> - <note> - <p>This function is intended for debugging purposes only.</p> - </note> - </desc> - </func> - - <func> - <name><ret>ErlDrvTime</ret><nametext>erl_drv_monotonic_time(ErlDrvTimeUnit time_unit)</nametext></name> - <fsummary>Get Erlang Monotonic Time</fsummary> - <desc> - <marker id="erl_drv_monotonic_time"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>time_unit</c></tag> - <item>Time unit of returned value.</item> - </taglist> - <p> - Returns - <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang - monotonic time</seealso>. Note that it is not uncommon with - negative values. - </p> - <p>Returns <c>ERL_DRV_TIME_ERROR</c> if called with an invalid - time unit argument, or if called from a thread that is not a - scheduler thread.</p> - <p>See also:</p> - <list> - <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> - <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> - </list> - </desc> - </func> - - <func> - <name><ret>ErlDrvTime</ret><nametext>erl_drv_time_offset(ErlDrvTimeUnit time_unit)</nametext></name> - <fsummary>Get current Time Offset</fsummary> - <desc> - <marker id="erl_drv_time_offset"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>time_unit</c></tag> - <item>Time unit of returned value.</item> - </taglist> - <p>Returns the current time offset between - <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang monotonic time</seealso> - and - <seealso marker="time_correction#Erlang_System_Time">Erlang system time</seealso> - converted into the <c>time_unit</c> passed as argument.</p> - <p>Returns <c>ERL_DRV_TIME_ERROR</c> if called with an invalid - time unit argument, or if called from a thread that is not a - scheduler thread.</p> - <p>See also:</p> - <list> - <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> - <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> - </list> - </desc> - </func> - - <func> - <name><ret>ErlDrvTime</ret><nametext>erl_drv_convert_time_unit(ErlDrvTime val, ErlDrvTimeUnit from, ErlDrvTimeUnit to)</nametext></name> - <fsummary>Convert time unit of a time value</fsummary> - <desc> - <marker id="erl_drv_convert_time_unit"></marker> - <p>Arguments:</p> - <taglist> - <tag><c>val</c></tag> - <item>Value to convert time unit for.</item> - <tag><c>from</c></tag> - <item>Time unit of <c>val</c>.</item> - <tag><c>to</c></tag> - <item>Time unit of returned value.</item> - </taglist> - <p>Converts the <c>val</c> value of time unit <c>from</c> to - the corresponding value of time unit <c>to</c>. The result is - rounded using the floor function.</p> - <p>Returns <c>ERL_DRV_TIME_ERROR</c> if called with an invalid - time unit argument.</p> - <p>See also:</p> - <list> - <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> - <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> - </list> - </desc> - </func> - </funcs> <section> <title>SEE ALSO</title> |