From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- erts/doc/src/erl_driver.xml | 2465 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2465 insertions(+) create mode 100644 erts/doc/src/erl_driver.xml (limited to 'erts/doc/src/erl_driver.xml') diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml new file mode 100644 index 0000000000..0b11f4bbcb --- /dev/null +++ b/erts/doc/src/erl_driver.xml @@ -0,0 +1,2465 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + erl_driver + Jakob Cederlund + Jakob Cederlund + 1 + + + 2000-11-27 + PA1 + erl_driver.xml +
+ erl_driver + API functions for an Erlang driver + +

As of erts version 5.5.3 the driver interface has been extended + (see extended marker). + The extended interface introduce + version management, + the possibility to pass capability flags + (see driver flags) + to the runtime system at driver initialization, and some new + driver API functions.

+ +

Old drivers (compiled with an erl_driver.h from an + earlier erts version than 5.5.3) have to be recompiled + (but does not have to use the extended interface).

+
+

The driver calls back to the emulator, using the API + functions declared in erl_driver.h. They are used for + outputting data from the driver, using timers, etc.

+

A driver is a library with a set of function that the emulator + calls, in response to Erlang functions and message + sending. There may be multiple instances of a driver, each + instance is connected to an Erlang port. Every port has a port + owner process. Communication with the port is normally done + through the port owner process.

+

Most of the functions takes the port handle as an + argument. This identifies the driver instance. Note that this + port handle must be stored by the driver, it is not given when + the driver is called from the emulator (see + driver_entry).

+

Some of the functions takes a parameter of type + ErlDrvBinary, a driver binary. It should be both + allocated and freed by the caller. Using a binary directly avoid + one extra copying of data.

+

Many of the output functions has a "header buffer", with + hbuf and hlen parameters. This buffer is sent as a + list before the binary (or list, depending on port mode) that is + sent. This is convenient when matching on messages received from + the port. (Although in the latest versions of Erlang, there is + the binary syntax, that enables you to match on the beginning of + a binary.) + +

+

In the runtime system with SMP support, drivers are locked either + on driver level or port level (driver instance level). By default + driver level locking will be used, i.e., only one emulator thread + will execute code in the driver at a time. If port level locking + is used, multiple emulator threads may execute code in the driver + at the same time. There will only be one thread at a time calling + driver call-backs corresponding to the same port, though. In order + to enable port level locking set the ERL_DRV_FLAG_USE_PORT_LOCKING + driver flag in + the driver_entry + used by the driver. When port level locking is used it is the + responsibility of the driver writer to synchronize all accesses + to data shared by the ports (driver instances).

+

Most drivers written before the runtime system with SMP + support existed will be able to run in the runtime system + with SMP support without being rewritten if driver + level locking is used.

+ +

It is assumed that drivers does not access other drivers. If + drivers should access each other they have to provide their own + mechanism for thread safe synchronization. Such "inter driver + communication" is strongly discouraged.

+
+

Previously, in the runtime system without SMP support, + specific driver call-backs were always called from the same + thread. This is not the case in the runtime system + with SMP support. Regardless of locking scheme used, calls + to driver call-backs may be made from different threads, e.g., + two consecutive calls to exactly the same call-back for exactly + the same port may be made from two different threads. This + will for most drivers not be a problem, but it might. + Drivers that depend on all call-backs being called in the + same thread, have to be rewritten before being used + in the runtime system with SMP support.

+ +

Regardless of locking scheme used, calls to driver + call-backs may be made from different threads.

+
+

Most functions in this API are not thread-safe, i.e., + they may not be called from an arbitrary thread. Function + that are not documented as thread-safe may only be called from + driver call-backs or function calls descending from a driver + call-back call. Note that driver call-backs may be called from + different threads. This, however, is not a problem for any + functions in this API, since the emulator have control over + these threads.

+ +

Functions not explicitly documented as thread-safe are + not thread-safe. Also note that some functions + are only thread safe when used in a runtime + system with SMP support.

+
+
+ +
+ FUNCTIONALITY +

All functions that a driver needs to do with Erlang are + performed through driver API functions. There are functions + for the following functionality:

+ + Timer functions + Timer functions are used to control the timer that a driver + may use. The timer will have the emulator call the + timeout entry + function after a specified time. Only one timer is available + for each driver instance. + Queue handling + +

Every driver instance has an associated queue. This queue is a + SysIOVec that works as a buffer. It's mostly used for + the driver to buffer data that should be written to a device, + it is a byte stream. If the port owner process closes the + driver, and the queue is not empty, the driver will not be + closed. This enables the driver to flush its buffers before + closing.

+

The queue can be manipulated from arbitrary threads if + a port data lock is used. See documentation of the + ErlDrvPDL type for + more information.

+
+ Output functions + With the output functions, the driver sends data back + the emulator. They will be received as messages by the port owner + process, see open_port/2. The vector function and the + function taking a driver binary is faster, because that avoid + copying the data buffer. There is also a fast way of sending + terms from the driver, without going through the binary term + format. + Failure + The driver can exit and signal errors up to Erlang. This is + only for severe errors, when the driver can't possibly keep + open. + Asynchronous calls + The latest Erlang versions (R7B and later) has provision for + asynchronous function calls, using a thread pool provided by + Erlang. There is also a select call, that can be used for + asynchronous drivers. + Multi-threading + +

A POSIX thread like API for multi-threading is provided. The + Erlang driver thread API only provide a subset of the functionality + provided by the POSIX thread API. The subset provided is + more or less the basic functionality needed for multi-threaded + programming: +

+ + Threads + Mutexes + Condition variables + Read/Write locks + Thread specific data + +

The Erlang driver thread API can be used in conjunction with + the POSIX thread API on UN-ices and with the Windows native thread + API on Windows. The Erlang driver thread API has the advantage of + being portable, but there might exist situations where you want to + use functionality from the POSIX thread API or the Windows + native thread API. +

+

The Erlang driver thread API only return error codes when it is + reasonable to recover from an error condition. If it isn't reasonable + to recover from an error condition, the whole runtime system is + terminated. For example, if a create mutex operation fails, an error + code is returned, but if a lock operation on a mutex fails, the + whole runtime system is terminated. +

+

Note that there exist no "condition variable wait with timeout" in + the Erlang driver thread API. This is due to issues with + pthread_cond_timedwait(). When the system clock suddenly + is changed, it isn't always guaranteed that you will wake up from + the call as expected. An Erlang runtime system has to be able to + cope with sudden changes of the system clock. Therefore, we have + omitted it from the Erlang driver thread API. In the Erlang driver + case, timeouts can and should be handled with the timer functionality + of the Erlang driver API. +

+

In order for the Erlang driver thread API to function, thread + support has to be enabled in the runtime system. An Erlang driver + can check if thread support is enabled by use of + driver_system_info(). + Note that some functions in the Erlang driver API are thread-safe + only when the runtime system has SMP support, also this + information can be retrieved via + driver_system_info(). + Also note that a lot of functions in the Erlang driver API are + not thread-safe regardless of whether SMP support is + enabled or not. If a function isn't documented as thread-safe it + is not thread-safe. +

+

NOTE: When executing in an emulator thread, it is + very important that you unlock all locks you + have locked before letting the thread out of your control; + otherwise, you are very likely to deadlock the whole + emulator. If you need to use thread specific data in an emulator + thread, only have the thread specific data set while the thread is + under your control, and clear the thread specific data before + you let the thread out of your control. +

+

In the future there will probably be debug functionality + integrated with the Erlang driver thread API. All functions + that create entities take a name argument. Currently + the name argument is unused, but it will be used when + the debug functionality has been implemented. If you name all + entities created well, the debug functionality will be able + to give you better error reports. +

+
+ Adding / remove drivers + A driver can add and later remove drivers. + Monitoring processes + A driver can monitor a process that does not own a port. + Version management + + +

Version management is enabled for drivers that have set the + extended_marker + field of their + driver_entry + to ERL_DRV_EXTENDED_MARKER. erl_driver.h defines + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, and + ERL_DRV_EXTENDED_MINOR_VERSION. + ERL_DRV_EXTENDED_MAJOR_VERSION will be incremented when + driver incompatible changes are made to the Erlang runtime + system. Normally it will suffice to recompile drivers when the + ERL_DRV_EXTENDED_MAJOR_VERSION has changed, but it + could, under rare circumstances, mean that drivers have to + be slightly modified. If so, this will of course be documented. + ERL_DRV_EXTENDED_MINOR_VERSION will be incremented when + new features are added. The runtime system use the minor version + of the driver to determine what features to use. + The runtime system will refuse to load a driver if the major + versions differ, or if the major versions are equal and the + minor version used by the driver is greater than the one used + by the runtime system.

+

The emulator tries to check that a driver that doesn't use the + extended driver interface isn't incompatible when loading it. + It can, however, not make sure that it isn't incompatible. Therefore, + when loading a driver that doesn't use the extended driver + interface, there is a risk that it will be loaded also when + the driver is incompatible. When the driver use the extended driver + interface, the emulator can verify that it isn't of an incompatible + driver version. You are therefore advised to use the extended driver + interface.

+
+
+
+ +
+ DATA TYPES + + + ErlDrvSysInfo + +

+ +typedef struct ErlDrvSysInfo { + int driver_major_version; + int driver_minor_version; + char *erts_version; + char *otp_release; + int thread_support; + int smp_support; + int async_threads; + int scheduler_threads; +} ErlDrvSysInfo; + + +

+ The ErlDrvSysInfo structure is used for storage of + information about the Erlang runtime system. + driver_system_info() + will write the system information when passed a reference to + a ErlDrvSysInfo structure. A description of the + fields in the structure follow: +

+ + driver_major_version + The value of + ERL_DRV_EXTENDED_MAJOR_VERSION + when the runtime system was compiled. This value is the same + as the value of + ERL_DRV_EXTENDED_MAJOR_VERSION + used when compiling the driver; otherwise, the runtime system + would have refused to load the driver. + + driver_minor_version + The value of + ERL_DRV_EXTENDED_MINOR_VERSION + when the runtime system was compiled. This value might differ + from the value of + ERL_DRV_EXTENDED_MINOR_VERSION + used when compiling the driver. + + erts_version + A string containing the version number of the runtime system + (the same as returned by + erlang:system_info(version)). + + otp_release + A string containing the OTP release number + (the same as returned by + erlang:system_info(otp_release)). + + thread_support + A value != 0 if the runtime system has thread support; + otherwise, 0. + + smp_support + A value != 0 if the runtime system has SMP support; + otherwise, 0. + + thread_support + A value != 0 if the runtime system has thread support; + otherwise, 0. + + smp_support + A value != 0 if the runtime system has SMP support; + otherwise, 0. + + async_threads + The number of async threads in the async thread pool used + by driver_async() + (the same as returned by + erlang:system_info(thread_pool_size)). + + scheduler_threads + The number of scheduler threads used by the runtime system + (the same as returned by + erlang:system_info(schedulers)). + + +
+ + ErlDrvBinary + +

+ +typedef struct ErlDrvBinary { + int orig_size; + char orig_bytes[]; +} ErlDrvBinary; + +

The ErlDrvBinary structure is a binary, as sent + between the emulator and the driver. All binaries are + reference counted; when driver_binary_free is called, + the reference count is decremented, when it reaches zero, + the binary is deallocated. The orig_size is the size + of the binary, and orig_bytes is the buffer. The + ErlDrvBinary does not have a fixed size, its size is + orig_size + 2 * sizeof(int).

+ +

The refc field has been removed. The reference count of + an ErlDrvBinary is now stored elsewhere. The + reference count of an ErlDrvBinary can be accessed via + driver_binary_get_refc(), + driver_binary_inc_refc(), + and + driver_binary_dec_refc().

+
+

Some driver calls, such as driver_enq_binary, + increments the driver reference count, and others, such as + driver_deq decrements it.

+

Using a driver binary instead of a normal buffer, is often + faster, since the emulator doesn't need to copy the data, + only the pointer is used.

+

A driver binary allocated in the driver, with + driver_alloc_binary, should be freed in the driver (unless otherwise stated), + with driver_free_binary. (Note that this doesn't + necessarily deallocate it, if the driver is still referred + in the emulator, the ref-count will not go to zero.)

+

Driver binaries are used in the driver_output2 and + driver_outputv calls, and in the queue. Also the + driver call-back outputv uses driver + binaries.

+

If the driver of some reason or another, wants to keep a + driver binary around, in a static variable for instance, the + reference count should be incremented, + and the binary can later be freed in the stop call-back, with + driver_free_binary.

+

Note that since a driver binary is shared by the driver and + the emulator, a binary received from the emulator or sent to + the emulator, must not be changed by the driver.

+

From erts version 5.5 (OTP release R11B), orig_bytes is + guaranteed to be properly aligned for storage of an array of + doubles (usually 8-byte aligned).

+
+ ErlDrvData + +

The ErlDrvData is a handle to driver-specific data, + passed to the driver call-backs. It is a pointer, and is + most often casted to a specific pointer in the driver.

+
+ SysIOVec + +

This is a system I/O vector, as used by writev on + unix and WSASend on Win32. It is used in + ErlIOVec.

+
+ ErlIOVec + +

+ +typedef struct ErlIOVec { + int vsize; + int size; + SysIOVec* iov; + >ErlDrvBinary** binv; +} ErlIOVec; + +

The I/O vector used by the emulator and drivers, is a list + of binaries, with a SysIOVec pointing to the buffers + of the binaries. It is used in driver_outputv and the + outputv + driver call-back. Also, the driver queue is an + ErlIOVec.

+
+ + ErlDrvMonitor + +

When a driver creates a monitor for a process, a + ErlDrvMonitor is filled in. This is an opaque + data-type which can be assigned to but not compared without + using the supplied compare function (i.e. it behaves like a struct).

+

The driver writer should provide the memory for storing the + monitor when calling driver_monitor_process. The + address of the data is not stored outside of the driver, so + the ErlDrvMonitor can be used as any other datum, it + can be copied, moved in memory, forgotten etc.

+
+ ErlDrvNowData + +

The ErlDrvNowData structure holds a timestamp + consisting of three values measured from some arbitrary + point in the past. The three structure members are:

+ + megasecs + The number of whole megaseconds elapsed since the arbitrary + point in time + secs + The number of whole seconds elapsed since the arbitrary + point in time + microsecs + The number of whole microseconds elapsed since the arbitrary + point in time + +
+ ErlDrvPDL + +

If certain port specific data have to be accessed from other + threads than those calling the driver call-backs, a port data lock + can be used in order to synchronize the operations on the data. + Currently, the only port specific data that the emulator + associates with the port data lock is the driver queue.

+

Normally a driver instance does not have a port data lock. If + the driver instance want to use a port data lock, it has to + create the port data lock by calling + driver_pdl_create(). + NOTE: Once the port data lock has been created, every + access to data associated with the port data lock have to be done + while having the port data lock locked. The port data lock is + locked, and unlocked, respectively, by use of + driver_pdl_lock(), and + driver_pdl_unlock().

+

A port data lock is reference counted, and when the reference + count reach zero, it will be destroyed. The emulator will at + least increment the reference count once when the lock is + created and decrement it once when the port associated with + the lock terminates. The emulator will also increment the + reference count when an async job is enqueued and decrement + it after an async job has been invoked, or canceled. Besides + this, it is the responsibility of the driver to ensure that + the reference count does not reach zero before the last use + of the lock by the driver has been made. The reference count + can be read, incremented, and decremented, respectively, by + use of + driver_pdl_get_refc(), + driver_pdl_inc_refc(), and + driver_pdl_dec_refc().

+
+ + ErlDrvTid + +

Thread identifier.

+

See also: + erl_drv_thread_create(), + erl_drv_thread_exit(), + erl_drv_thread_join(), + erl_drv_thread_self(), + and + erl_drv_equal_tids(). +

+
+ ErlDrvThreadOpts + +

+ + int suggested_stack_size; + +

Thread options structure passed to + erl_drv_thread_create(). + Currently the following fields exist: +

+ + suggested_stack_size + A suggestion, in kilo-words, on how large stack to use. A value less + than zero means default size. + + +

See also: + erl_drv_thread_opts_create(), + erl_drv_thread_opts_destroy(), + and + erl_drv_thread_create(). +

+
+ + ErlDrvMutex + +

Mutual exclusion lock. Used for synchronizing access to shared data. + Only one thread at a time can lock a mutex. +

+

See also: + erl_drv_mutex_create(), + erl_drv_mutex_destroy(), + erl_drv_mutex_lock(), + erl_drv_mutex_trylock(), + and + erl_drv_mutex_unlock(). +

+
+ ErlDrvCond + +

Condition variable. Used when threads need to wait for a specific + condition to appear before continuing execution. Condition variables + need to be used with associated mutexes. +

+

See also: + erl_drv_cond_create(), + erl_drv_cond_destroy(), + erl_drv_cond_signal(), + erl_drv_cond_broadcast(), + and + erl_drv_cond_wait(). +

+
+ ErlDrvRWLock + +

Read/write lock. Used to allow multiple threads to read shared data + while only allowing one thread to write the same data. Multiple threads + can read lock an rwlock at the same time, while only one thread can + read/write lock an rwlock at a time. +

+

See also: + erl_drv_rwlock_create(), + erl_drv_rwlock_destroy(), + erl_drv_rwlock_rlock(), + erl_drv_rwlock_tryrlock(), + erl_drv_rwlock_runlock(), + erl_drv_rwlock_rwlock(), + erl_drv_rwlock_tryrwlock(), + and + erl_drv_rwlock_rwunlock(). +

+
+ ErlDrvTSDKey + +

Key which thread specific data can be associated with.

+

See also: + erl_drv_tsd_key_create(), + erl_drv_tsd_key_destroy(), + erl_drv_tsd_set(), + and + erl_drv_tsd_get(). +

+
+
+
+ + + + voiddriver_system_info(ErlDrvSysInfo *sys_info_ptr, size_t size) + Get information about the Erlang runtime system + + +

This function will write information about the Erlang runtime + system into the + ErlDrvSysInfo + structure referred to by the first argument. The second + argument should be the size of the + ErlDrvSysInfo + structure, i.e., sizeof(ErlDrvSysInfo).

+

See the documentation of the + ErlDrvSysInfo + structure for information about specific fields.

+
+
+ + intdriver_output(ErlDrvPort port, char *buf, int len) + Send data from driver to port owner + + +

The driver_output 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.

+

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 runs in the same thread.)

+

The parameter buf points to the data to send, and + len is the number of bytes.

+

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.)

+
+
+ + intdriver_output2(ErlDrvPort port, char *hbuf, int hlen, char *buf, int len) + Send data and binary data to port owner + + +

The driver_output2 function first sends hbuf + (length in hlen) data as a list, regardless of port + settings. Then buf is sent as a binary or list. + E.g. if hlen is 3 then the port owner process will + receive [H1, H2, H3 | T].

+

The point of sending data as a list header, is to facilitate + matching on the data received.

+

The return value is 0 for normal use.

+
+
+ + intdriver_output_binary(ErlDrvPort port, char *hbuf, int hlen, ErlDrvBinary* bin, int offset, int len) + Send data from a driver binary to port owner + + +

This function sends data to port owner process from a + driver binary, it has a header buffer (hbuf + and hlen) just like driver_output2. The + hbuf parameter can be NULL.

+

The parameter offset is an offset into the binary and + len is the number of bytes to send.

+

Driver binaries are created with driver_alloc_binary.

+

The data in the header is sent as a list and the binary as + an Erlang binary in the tail of the list.

+

E.g. if hlen is 2, then the port owner process will + receive >]]]>.

+

The return value is 0 for normal use.

+

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.

+
+
+ + intdriver_outputv(ErlDrvPort port, char* hbuf, int hlen, ErlIOVec *ev, int skip) + Send vectorized data to port owner + + +

This function sends data from an IO vector, ev, to + the port owner process. It has a header buffer (hbuf + and hlen), just like driver_output2.

+

The skip parameter is a number of bytes to skip of + the ev vector from the head.

+

You get vectors of ErlIOVec type from the driver + queue (see below), and the outputv driver entry + function. You can also make them yourself, if you want to + send several ErlDrvBinary buffers at once. Often + it is faster to use driver_output or + driver_output_binary.

+

E.g. if hlen is 2 and ev points to an array of + three binaries, the port owner process will receive >, <> | <>]]]>.

+

The return value is 0 for normal use.

+

The comment for driver_output_binary applies for + driver_outputv too.

+
+
+ + intdriver_vec_to_buf(ErlIOVec *ev, char *buf, int len) + Collect data segments into a buffer + + +

This function collects several segments of data, referenced + by ev, by copying them in order to the buffer + buf, of the size len.

+

If the data is to be sent from the driver to the port owner + process, it is faster to use driver_outputv.

+

The return value is the space left in the buffer, i.e. if + the ev contains less than len bytes it's the + difference, and if ev contains len 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.

+
+
+ + intdriver_set_timer(ErlDrvPort port, unsigned long time) + Set a timer to call the driver + + +

This function sets a timer on the driver, which will count + down and call the driver when it is timed out. The + time parameter is the time in milliseconds before the + timer expires.

+

When the timer reaches 0 and expires, the driver entry + function timeout is called.

+

Note that there is only one timer on each driver instance; + setting a new timer will replace an older one.

+

Return value i 0 (-1 only when the timeout driver + function is NULL).

+
+
+ + intdriver_cancel_timer(ErlDrvPort port) + Cancel a previously set timer + + +

This function cancels a timer set with + driver_set_timer.

+

The return value is 0.

+
+
+ + intdriver_read_timer(ErlDrvPort port, unsigned long *time_left) + Read the time left before timeout + + +

This function reads the current time of a timer, and places + the result in time_left. This is the time in + milliseconds, before the timeout will occur.

+

The return value is 0.

+
+
+ + intdriver_get_now(ErlDrvNowData *now) + Read a system timestamp + + +

This function reads a timestamp into the memory pointed to by + the parameter now. See the description of ErlDrvNowData for + specification of it's fields.

+

The return value is 0 unless the now pointer is not + valid, in which case it is < 0.

+
+
+ + intdriver_select(ErlDrvPort port, ErlDrvEvent event, int mode, int on) + Provide an event for having the emulator call the driver + + +

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.

+

The event argument identifies an OS-specific event object. + On Unix systems, the functions select/poll are used. The + event object must be a socket or pipe (or other object that + select/poll can use). + On windows, the Win32 API function WaitForMultipleObjects + is used. This places other restriction on the event object. + Refer to the Win32 SDK documentation.

+

The on parameter should be 1 for setting events + and 0 for clearing them.

+

The mode argument is bitwise-or combination of + ERL_DRV_READ, ERL_DRV_WRITE and ERL_DRV_USE. + The first two specifies whether to wait for read events and/or write + events. A fired read event will call + ready_input + while a fired write event will call + ready_output. +

+ +

Some OS (Windows) does not differ between read and write events. + The call-back for a fired event then only depends on the value of mode.

+
+

ERL_DRV_USE 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 driver_select has + returned. Another thread may still be using the event object + internally. To safely close an event object call + driver_select with ERL_DRV_USE and on==0. That + will clear all events and then call + stop_select + when it is safe to close the event object. + ERL_DRV_USE should be set together with the first event + for an event object. It is harmless to set ERL_DRV_USE + even though it already has been done. Clearing all events but keeping + ERL_DRV_USE set will indicate that we are using the event + object and probably will set events for it again.

+ +

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 ERL_DRV_USE and + stop_select to make sure that event objects are closed in a safe way.

+
+

The return value is 0 (Failure, -1, only if the + ready_input/ready_output is + NULL.

+
+
+ + void *driver_alloc(size_t size) + Allocate memory + + +

This function allocates a memory block of the size specified + in size, and returns it. This only fails on out of + memory, in that case NULL is returned. (This is most + often a wrapper for malloc).

+

Memory allocated must be explicitly freed with a corresponding + call to driver_free (unless otherwise stated).

+

This function is thread-safe.

+
+
+ + void *driver_realloc(void *ptr, size_t size) + Resize an allocated memory block + + +

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), NULL is returned. (This is + most often a wrapper for realloc.)

+

This function is thread-safe.

+
+
+ + voiddriver_free(void *ptr) + Free an allocated memory block + + +

This function frees the memory pointed to by ptr. The + memory should have been allocated with + driver_alloc. All allocated memory should be + deallocated, just once. There is no garbage collection in + drivers.

+

This function is thread-safe.

+
+
+ + ErlDrvBinary*driver_alloc_binary(int size) + Allocate a driver binary + + +

This function allocates a driver binary with a memory block + of at least size bytes, and returns a pointer to it, + or NULL on failure (out of memory). When a driver binary has + been sent to the emulator, it must not be altered. Every + allocated binary should be freed by a corresponding call to + driver_free_binary (unless otherwise stated).

+

Note that a driver binary has an internal reference counter, + this means that calling driver_free_binary it may not + actually dispose of it. If it's sent to the emulator, it may + be referenced there.

+

The driver binary has a field, orig_bytes, which + marks the start of the data in the binary.

+

This function is thread-safe.

+
+
+ + ErlDrvBinary*driver_realloc_binary(ErlDrvBinary *bin, int size) + Resize a driver binary + + +

This function resizes a driver binary, while keeping the + data. The resized driver binary is returned. On failure (out + of memory), NULL is returned.

+

This function is only thread-safe when the emulator with SMP + support is used.

+
+
+ + voiddriver_free_binary(ErlDrvBinary *bin) + Free a driver binary + + +

This function frees a driver binary bin, allocated + previously with driver_alloc_binary. Since binaries + in Erlang are reference counted, the binary may still be + around.

+

This function is only thread-safe when the emulator with SMP + support is used.

+
+
+ + longdriver_binary_get_refc(ErlDrvBinary *bin) + Get the reference count of a driver binary + + +

Returns current reference count on bin.

+

This function is only thread-safe when the emulator with SMP + support is used.

+
+
+ + longdriver_binary_inc_refc(ErlDrvBinary *bin) + Increment the reference count of a driver binary + + +

Increments the reference count on bin and returns + the reference count reached after the increment.

+

This function is only thread-safe when the emulator with SMP + support is used.

+
+
+ + longdriver_binary_dec_refc(ErlDrvBinary *bin) + Decrement the reference count of a driver binary + + +

Decrements the reference count on bin and returns + the reference count reached after the decrement.

+

This function is only thread-safe when the emulator with SMP + support is used.

+ +

You should normally decrement the reference count of a + driver binary by calling + driver_free_binary(). + driver_binary_dec_refc() does not free + the binary if the reference count reaches zero. Only + use driver_binary_dec_refc() when you are sure + not to reach a reference count of zero.

+
+
+
+ + intdriver_enq(ErlDrvPort port, char* buf, int len) + Enqueue data in the driver queue + + +

This function enqueues data in the driver queue. The data in + buf is copied (len bytes) and placed at the + end of the driver queue. The driver queue is normally used + in a FIFO way.

+

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.

+

When the queue contains data, the driver won't close, until + the queue is empty.

+

The return value is 0.

+

This function can be called from an arbitrary thread if a + port data lock + associated with the port is locked by the calling + thread during the call.

+
+
+ + intdriver_pushq(ErlDrvPort port, char* buf, int len) + Push data at the head of the driver queue + + +

This function puts data at the head of the driver queue. The + data in buf is copied (len bytes) and placed + at the beginning of the queue.

+

The return value is 0.

+

This function can be called from an arbitrary thread if a + port data lock + associated with the port is locked by the calling + thread during the call.

+
+
+ + intdriver_deq(ErlDrvPort port, int size) + Dequeue data from the head of the driver queue + + +

This function dequeues data by moving the head pointer + forward in the driver queue by size bytes. The data + in the queue will be deallocated.

+

The return value is the number of bytes remaining in the queue + or -1 on failure.

+

This function can be called from an arbitrary thread if a + port data lock + associated with the port is locked by the calling + thread during the call.

+
+
+ + intdriver_sizeq(ErlDrvPort port) + Return the size of the driver queue + + +

This function returns the number of bytes currently in the + driver queue.

+

This function can be called from an arbitrary thread if a + port data lock + associated with the port is locked by the calling + thread during the call.

+
+
+ + intdriver_enq_bin(ErlDrvPort port, ErlDrvBinary *bin, int offset, int len) + Enqueue binary in the driver queue + + +

This function enqueues a driver binary in the driver + queue. The data in bin at offset with length + len is placed at the end of the queue. This function + is most often faster than driver_enq, because the + data doesn't have to be copied.

+

This function can be called from an arbitrary thread if a + port data lock + associated with the port is locked by the calling + thread during the call.

+

The return value is 0.

+
+
+ + intdriver_pushq_bin(ErlDrvPort port, ErlDrvBinary *bin, int offset, int len) + Push binary at the head of the driver queue + + +

This function puts data in the binary bin, at + offset with length len at the head of the + driver queue. It is most often faster than + driver_pushq, because the data doesn't have to be + copied.

+

This function can be called from an arbitrary thread if a + port data lock + associated with the port is locked by the calling + thread during the call.

+

The return value is 0.

+
+
+ + SysIOVec*driver_peekq(ErlDrvPort port, int *vlen) + Get the driver queue as a vector + + +

This function retrieves the driver queue as a pointer to an + array of SysIOVecs. It also returns the number of + elements in vlen. This is the only way to get data + out of the queue.

+

Nothing is remove from the queue by this function, that must be done + with driver_deq.

+

The returned array is suitable to use with the Unix system + call writev.

+

This function can be called from an arbitrary thread if a + port data lock + associated with the port is locked by the calling + thread during the call.

+
+
+ + intdriver_enqv(ErlDrvPort port, ErlIOVec *ev, int skip) + Enqueue vector in the driver queue + + +

This function enqueues the data in ev, skipping the + first skip bytes of it, at the end of the driver + queue. It is faster than driver_enq, because the data + doesn't have to be copied.

+

The return value is 0.

+

This function can be called from an arbitrary thread if a + port data lock + associated with the port is locked by the calling + thread during the call.

+
+
+ + intdriver_pushqv(ErlDrvPort port, ErlIOVec *ev, int skip) + Push vector at the head of the driver queue + + +

This function puts the data in ev, skipping the first + skip bytes of it, at the head of the driver queue. + It is faster than driver_pushq, because the data + doesn't have to be copied.

+

The return value is 0.

+

This function can be called from an arbitrary thread if a + port data lock + associated with the port is locked by the calling + thread during the call.

+
+
+ + ErlDrvPDLdriver_pdl_create(ErlDrvPort port) + Create a port data lock + + +

This function creates a port data lock associated with + the port. NOTE: Once a port data lock has + been created, it has to be locked during all operations + on the driver queue of the port.

+

On success a newly created port data lock is returned. On + failure NULL is returned. driver_pdl_create() will + fail if port is invalid or if a port data lock already has + been associated with the port.

+
+
+ + voiddriver_pdl_lock(ErlDrvPDL pdl) + Lock port data lock + + +

This function locks the port data lock passed as argument + (pdl).

+

This function is thread-safe.

+
+
+ + voiddriver_pdl_unlock(ErlDrvPDL pdl) + Unlock port data lock + + +

This function unlocks the port data lock passed as argument + (pdl).

+

This function is thread-safe.

+
+
+ + longdriver_pdl_get_refc(ErlDrvPDL pdl) + + + +

This function returns the current reference count of + the port data lock passed as argument (pdl).

+

This function is thread-safe.

+
+
+ + longdriver_pdl_inc_refc(ErlDrvPDL pdl) + + + +

This function increments the reference count of + the port data lock passed as argument (pdl).

+

The current reference count after the increment has + been performed is returned.

+

This function is thread-safe.

+
+
+ + longdriver_pdl_dec_refc(ErlDrvPDL pdl) + + + +

This function decrements the reference count of + the port data lock passed as argument (pdl).

+

The current reference count after the decrement has + been performed is returned.

+

This function is thread-safe.

+
+
+ + intdriver_monitor_process(ErlDrvPort port, ErlDrvTermData process, ErlDrvMonitor *monitor) + Monitor a process from a driver + + +

Start monitoring a process from a driver. When a process is + monitored, a process exit will result in a call to the + provided process_exit call-back + in the ErlDrvEntry + structure. The ErlDrvMonitor structure is filled in, for later + removal or compare.

+

The process parameter should be the return value of an + earlier call to driver_caller or driver_connected call.

+

The function returns 0 on success, < 0 if no call-back is + provided and > 0 if the process is no longer alive.

+
+
+ + intdriver_demonitor_process(ErlDrvPort port, const ErlDrvMonitor *monitor) + Stop monitoring a process from a driver + + +

This function cancels an monitor created earlier.

+

The function returns 0 if a monitor was removed and > 0 + if the monitor did no longer exist.

+
+
+ + ErlDrvTermDatadriver_get_monitored_process(ErlDrvPort port, const ErlDrvMonitor *monitor) + Retrieve the process id from a monitor + + +

The function returns the process id associated with a living + monitor. It can be used in the process_exit call-back to + get the process identification for the exiting process.

+

The function returns driver_term_nil if the monitor + no longer exists.

+
+
+ + intdriver_compare_monitors(const ErlDrvMonitor *monitor1, const ErlDrvMonitor *monitor2) + Compare two monitors + + +

This function is used to compare two ErlDrvMonitors. It + can also be used to imply some artificial order on monitors, + for whatever reason.

+

The function returns 0 if monitor1 and + monitor2 are equal, < 0 if monitor1 is less + than monitor2 and > 0 if monitor1 is greater + than monitor2.

+
+
+ + voidadd_driver_entry(ErlDrvEntry *de) + Add a driver entry + + +

This function adds a driver entry to the list of drivers + known by Erlang. The init function of the de + parameter is called.

+ +

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. .so file) as a normal + dynamically loaded driver (loaded with the erl_ddll + interface), the caller should call driver_lock_driver before + adding driver entries.

+

Use of this function is generally deprecated.

+
+
+
+ + intremove_driver_entry(ErlDrvEntry *de) + Remove a driver entry + + +

This function removes a driver entry de previously + added with add_driver_entry.

+

Driver entries added by the erl_ddll erlang interface can + not be removed by using this interface.

+
+
+ + char*erl_errno_id(int error) + Get erlang error atom name from error number + + +

This function returns the atom name of the erlang error, + given the error number in error. Error atoms are: + einval, enoent, etc. It can be used to make + error terms from the driver.

+
+
+ + voidset_busy_port(ErlDrvPort port, int on) + Signal or unsignal port as busy + + +

This function set and resets the busy status of the port. If + on is 1, the port is set to busy, if it's 0 the port + is set to not busy.

+

When the port is busy, sending to it with Port ! Data + or port_command/2, will block the port owner process, + until the port is signaled as not busy.

+

If the + + has been set in the + driver_entry, + data can be forced into the driver via + port_command(Port, Data, [force]) + even though the driver has signaled that it is busy. +

+
+
+ + voidset_port_control_flags(ErlDrvPort port, int flags) + Set flags on how to handle control entry function + + +

This function sets flags for how the control driver entry + function will return data to the port owner process. (The + control function is called from port_control/3 + in erlang.)

+

Currently there are only two meaningful values for + flags: 0 means that data is returned in a list, and + PORT_CONTROL_FLAG_BINARY means data is returned as + a binary from control.

+
+
+ + intdriver_failure_eof(ErlDrvPort port) + Fail with EOF + + +

This function signals to erlang that the driver has + encountered an EOF and should be closed, unless the port was + opened with the eof option, in that case eof is sent + to the port. Otherwise, the port is close and an + 'EXIT' message is sent to the port owner process.

+

The return value is 0.

+
+
+ + intdriver_failure_atom(ErlDrvPort port, char *string) + intdriver_failure_posix(ErlDrvPort port, int error) + intdriver_failure(ErlDrvPort port, int error) + Fail with error + + + + +

These functions signal to Erlang that the driver has + encountered an error and should be closed. The port is + closed and the tuple {'EXIT', error, Err}, is sent to + the port owner process, where error is an error atom + (driver_failure_atom and + driver_failure_posix), or an integer + (driver_failure).

+

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. Normal errors is more + appropriate to handle with sending error codes with + driver_output.

+

The return value is 0.

+
+
+ + ErlDrvTermDatadriver_connected(ErlDrvPort port) + Return the port owner process + + +

This function returns the port owner process.

+
+
+ + ErlDrvTermDatadriver_caller(ErlDrvPort port) + Return the process making the driver call + + +

This function returns the process id of the process that + made the current call to the driver. The process id can be + used with driver_send_term to send back data to the + caller. driver_caller() only return valid data + when currently executing in one of the following driver + callbacks:

+ + start + Called from open_port/2. + output + Called from erlang:send/2, and + erlang:port_command/2 + outputv + Called from erlang:send/2, and + erlang:port_command/2 + control + Called from erlang:port_control/3 + call + Called from erlang:port_call/3 + +
+
+ + intdriver_output_term(ErlDrvPort port, ErlDrvTermData* term, int n) + Send term data from driver to port owner + + +

This functions sends data in the special driver term + format. This is a fast way to deliver term data from a + driver. It also needs no binary conversion, so the port + owner process receives data as normal Erlang terms.

+

The term parameter points to an array of + ErlDrvTermData, with n elements. This array + contains terms described in the driver term format. Every + term consists of one to four elements in the array. The + term first has a term type, and then arguments.

+

Tuple and lists (with the exception of strings, see below), + are built in reverse polish notation, so that to build a + tuple, the elements are given first, and then the tuple + term, with a count. Likewise for lists.

+

A tuple must be specified with the number of elements. (The + elements precedes the ERL_DRV_TUPLE term.)

+

A list must be specified with the number of elements, + including the tail, which is the last term preceding + ERL_DRV_LIST.

+

The special term ERL_DRV_STRING_CONS is used to + "splice" in a string in a list, a string given this way is + not a list per se, but the elements are elements of the + surrounding list.

+
+Term type            Argument(s)
+===========================================
+ERL_DRV_NIL          
+ERL_DRV_ATOM         ErlDrvTermData atom (from driver_mk_atom(char *string))
+ERL_DRV_INT          ErlDrvSInt integer
+ERL_DRV_UINT         ErlDrvUInt integer
+ERL_DRV_INT64        ErlDrvSInt64 *integer_ptr
+ERL_DRV_UINT64       ErlDrvUInt64 *integer_ptr
+ERL_DRV_PORT         ErlDrvTermData port (from driver_mk_port(ErlDrvPort port))
+ERL_DRV_BINARY       ErlDrvBinary *bin, ErlDrvUInt len, ErlDrvUInt offset
+ERL_DRV_BUF2BINARY   char *buf, ErlDrvUInt len
+ERL_DRV_STRING       char *str, int len
+ERL_DRV_TUPLE        int sz
+ERL_DRV_LIST         int sz
+ERL_DRV_PID          ErlDrvTermData pid (from driver_connected(ErlDrvPort port) or driver_caller(ErlDrvPort port))
+ERL_DRV_STRING_CONS  char *str, int len
+ERL_DRV_FLOAT        double *dbl
+ERL_DRV_EXT2TERM     char *buf, ErlDrvUInt len
+        
+

The unsigned integer data type ErlDrvUInt and the + signed integer data type ErlDrvSInt are 64 bits wide + on a 64 bit runtime system and 32 bits wide on a 32 bit + runtime system. They were introduced in erts version 5.6, + and replaced some of the int arguments in the list above. +

+

The unsigned integer data type ErlDrvUInt64 and the + signed integer data type ErlDrvSInt64 are always 64 bits + wide. They were introduced in erts version 5.7.4. +

+ +

To build the tuple {tcp, Port, [100 | Binary]}, the + following call could be made.

+ + +

Where bin is a driver binary of length at least 50 + and port is a port handle. Note that the ERL_DRV_LIST + comes after the elements of the list, likewise the + ERL_DRV_TUPLE.

+

The term ERL_DRV_STRING_CONS is a way to construct + strings. It works differently from how ERL_DRV_STRING + works. ERL_DRV_STRING_CONS builds a string list in + reverse order, (as opposed to how ERL_DRV_LIST + works), concatenating the strings added to a list. The tail + must be given before ERL_DRV_STRING_CONS.

+

The ERL_DRV_STRING constructs a string, and ends + it. (So it's the same as ERL_DRV_NIL followed by + ERL_DRV_STRING_CONS.)

+ +

+ +

The ERL_DRV_EXT2TERM term type is used for passing a + term encoded with the + external format, + i.e., a term that has been encoded by + erlang:term_to_binary, + erl_interface, etc. + For example, if binp is a pointer to an ErlDrvBinary + that contains the term {17, 4711} encoded with the + external format + and you want to wrap it in a two tuple with the tag my_tag, + i.e., {my_tag, {17, 4711}}, you can do as follows: +

+ orig_bytes, binp->orig_size + ERL_DRV_TUPLE, 2, + }; + driver_output_term(port, spec, sizeof(spec) / sizeof(spec[0])); + ]]> +

If you want to pass a binary and doesn't already have the content + of the binary in an ErlDrvBinary, you can benefit from using + ERL_DRV_BUF2BINARY instead of creating an ErlDrvBinary + via driver_alloc_binary() and then pass the binary via + ERL_DRV_BINARY. The runtime system will often allocate + binaries smarter if ERL_DRV_BUF2BINARY is used. + However, if the content of the binary to pass already resides in + an ErlDrvBinary, it is normally better to pass the binary + using ERL_DRV_BINARY and the ErlDrvBinary in question. +

+

The ERL_DRV_UINT, ERL_DRV_BUF2BINARY, and + ERL_DRV_EXT2TERM term types were introduced in the 5.6 + version of erts. +

+

Note that this function is not thread-safe, not + even when the emulator with SMP support is used.

+
+
+ + ErlDrvTermDatadriver_mk_atom(char* string) + Make an atom from a name + + +

This function returns an atom given a name + string. 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.

+
+
+ + ErlDrvTermDatadriver_mk_port(ErlDrvPort port) + Make a erlang term port from a port + + +

This function converts a port handle to the erlang term + format, usable in the driver_output_send function.

+
+
+ + intdriver_send_term(ErlDrvPort port, ErlDrvTermData receiver, ErlDrvTermData* term, int n) + Send term data to other process than port owner process + + +

This function is the only way for a driver to send data to + other processes than the port owner process. The + receiver parameter specifies the process to receive + the data.

+

The parameters term and n does the same thing + as in driver_output_term.

+

This function is only thread-safe when the emulator with SMP + support is used.

+
+
+ + longdriver_async (ErlDrvPort port, unsigned int* key, void (*async_invoke)(void*), void* async_data, void (*async_free)(void*)) + Perform an asynchronous call within a driver + + +

This function performs an asynchronous call. The function + async_invoke is invoked in a thread separate from the + emulator thread. This enables the driver to perform + time-consuming, blocking operations without blocking the + emulator.

+

Erlang is by default started without an async thread pool. The + number of async threads that the runtime system should use + is specified by the + +A + command line argument of erl(1). + If no async thread pool is available, the call is made + synchronously in the thread calling driver_async(). The + current number of async threads in the async thread pool can be + retrieved via + driver_system_info().

+

If there is a thread pool available, a thread will be + used. If the key argument is null, the threads from the + pool are used in a round-robin way, each call to + driver_async uses the next thread in the pool. With the + key argument set, this behaviour is changed. The two + same values of *key always get the same thread.

+

To make sure that a driver instance always uses the same + thread, the following call can be used:

+

+ +

It is enough to initialize myKey once for each + driver instance.

+

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.

+

The async_data is the argument to the functions + async_invoke and async_free. 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 async_free, because it's + called if driver_async_cancel is called.

+

When the async operation is done, ready_async driver + entry function is called. If async_ready is null in + the driver entry, the async_free function is called + instead.

+

The return value is a handle to the asynchronous task, which + can be used as argument to driver_async_cancel.

+ +

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 + +a + command line argument of + erl(1).

+
+
+
+ + intdriver_async_cancel(long id) + Cancel an asynchronous call + + +

This function cancels an asynchronous operation, by removing + it from the queue. Only functions in the queue can be + cancelled; if a function is executing, it's too late to + cancel it. The async_free function is also called.

+

The return value is 1 if the operation was removed from the + queue, otherwise 0.

+
+
+ + intdriver_lock_driver(ErlDrvPort port) + Make sure the driver is never unloaded + + +

This function locks the driver used by the port port + 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.

+
+
+ + ErlDrvPortdriver_create_port(ErlDrvPort port, ErlDrvTermData owner_pid, char* name, ErlDrvData drv_data) + Create a new port (driver instance) + +

This function creates a new port executing the same driver + code as the port creating the new port. + A short description of the arguments:

+ + port + The port handle of the port (driver instance) creating + the new port. + owner_pid + 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 + driver_caller(port) as owner_pid. + name + The port name of the new port. You usually want to + use the same port name as the driver name + (driver_name + field of the + driver_entry). + drv_data + The driver defined handle that will be passed in subsequent + calls to driver call-backs. Note, that the + driver start call-back + will not be called for this new driver instance. + The driver defined handle is normally created in the + driver start call-back + when a port is created via + erlang:open_port/2. + +

The caller of driver_create_port() is allowed to + manipulate the newly created port when driver_create_port() + has returned. When + port level locking + 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.

+ +

When + port level locking + is used, the creating port is only allowed to manipulate + the newly created port until the current driver call-back + returns.

+
+
+
+ + + interl_drv_thread_create(char *name, + ErlDrvTid *tid, + void * (*func)(void *), + void *arg, + ErlDrvThreadOpts *opts) + Create a thread + + +

Arguments:

+ + name + A string identifying the created thread. It will be used + to identify the thread in planned future debug + functionality. + + tid + A pointer to a thread identifier variable. + func + A pointer to a function to execute in the created thread. + arg + A pointer to argument to the func function. + opts + A pointer to thread options to use or NULL. + +

This function creates a new thread. On success 0 is returned; + otherwise, an errno value is returned to indicate the error. + The newly created thread will begin executing in the function pointed + to by func, and func will be passed arg as + argument. When erl_drv_thread_create() returns the thread + identifier of the newly created thread will be available in + *tid. opts can be either a NULL pointer, or a + pointer to an + ErlDrvThreadOpts + structure. If opts is a NULL pointer, default options + will be used; otherwise, the passed options will be used. +

+

You are not allowed to allocate the + ErlDrvThreadOpts + structure by yourself. It has to be allocated and + initialized by + erl_drv_thread_opts_create(). +

+

The created thread will terminate either when func returns + or if + erl_drv_thread_exit() + is called by the thread. The exit value of the thread is either + returned from func or passed as argument to + erl_drv_thread_exit(). + The driver creating the thread has the responsibility of joining the + thread, via + erl_drv_thread_join(), + before the driver is unloaded. It is not possible to create + "detached" threads, i.e., threads that don't need to be joined. +

+

All created threads need to be joined by the driver before + it is unloaded. If the driver fails to join all threads + created before it is unloaded, the runtime system will + most likely crash when the code of the driver is unloaded. +

+

This function is thread-safe.

+
+
+ + + ErlDrvThreadOpts *erl_drv_thread_opts_create(char *name) + Create thread options + + +

Arguments:

+ + name + A string identifying the created thread options. It will be used + to identify the thread options in planned future debug + functionality. + + +

This function allocates and initialize a thread option + structure. On failure NULL is returned. A thread option + structure is used for passing options to + erl_drv_thread_create(). + If the structure isn't modified before it is passed to + erl_drv_thread_create(), + the default values will be used. +

+

You are not allowed to allocate the + ErlDrvThreadOpts + structure by yourself. It has to be allocated and + initialized by erl_drv_thread_opts_create(). +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_thread_opts_destroy(ErlDrvThreadOpts *opts) + Destroy thread options + + +

Arguments:

+ + opts + A pointer to thread options to destroy. + +

This function destroys thread options previously created by + erl_drv_thread_opts_create(). +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_thread_exit(void *exit_value) + Terminate calling thread + + +

Arguments:

+ + exit_value + A pointer to an exit value or NULL. + +

This function terminates the calling thread with the exit + value passed as argument. You are only allowed to terminate + threads created with + erl_drv_thread_create(). + The exit value can later be retrieved by another thread via + erl_drv_thread_join(). +

+

This function is thread-safe.

+
+
+ + + interl_drv_thread_join(ErlDrvTid tid, void **exit_value) + Join with another thread + + +

Arguments:

+ + tid + The thread identifier of the thread to join. + exit_value + A pointer to a pointer to an exit value, or NULL. + +

This function joins the calling thread with another thread, i.e., + the calling thread is blocked until the thread identified by + tid has terminated. On success 0 is returned; + otherwise, an errno value is returned to indicate the error. + A thread can only be joined once. The behavior of joining + more than once is undefined, an emulator crash is likely. If + exit_value == NULL, the exit value of the terminated thread + will be ignored; otherwise, the exit value of the terminated thread + will be stored at *exit_value. +

+

This function is thread-safe.

+
+
+ + + ErlDrvTiderl_drv_thread_self(void) + Get the thread identifier of the current thread + + +

This function returns the thread identifier of the + calling thread. +

+

This function is thread-safe.

+
+
+ + + interl_drv_equal_tids(ErlDrvTid tid1, ErlDrvTid tid2) + Compare thread identifiers for equality + + +

Arguments:

+ + tid1 + A thread identifier. + tid2 + A thread identifier. + +

This function compares two thread identifiers for equality, + and returns 0 it they aren't equal, and + a value not equal to 0 if they are equal.

+

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 erl_drv_equal_tids() might not give + expected result. +

+

This function is thread-safe.

+
+
+ + + ErlDrvMutex *erl_drv_mutex_create(char *name) + Create a mutex + + +

Arguments:

+ + name + A string identifying the created mutex. It will be used + to identify the mutex in planned future debug functionality. + + +

This function creates a mutex and returns a pointer to it. On + failure NULL is returned. The driver creating the mutex + has the responsibility of destroying it before the driver is + unloaded. +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_mutex_destroy(ErlDrvMutex *mtx) + Destroy a mutex + + +

Arguments:

+ + mtx + A pointer to a mutex to destroy. + +

This function destroys a mutex previously created by + erl_drv_mutex_create(). + The mutex has to be in an unlocked state before being + destroyed. +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_mutex_lock(ErlDrvMutex *mtx) + Lock a mutex + + +

Arguments:

+ + mtx + A pointer to a mutex to lock. + +

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 not lock + the same mutex again. +

+

If you leave a mutex locked in an emulator thread + when you let the thread out of your control, you will + very likely deadlock the whole emulator. +

+

This function is thread-safe.

+
+
+ + + interl_drv_mutex_trylock(ErlDrvMutex *mtx) + Try lock a mutex + + +

Arguments:

+ + mtx + A pointer to a mutex to try to lock. + +

This function tries to lock a mutex. If successful 0, + is returned; otherwise, EBUSY is returned. A thread + which currently has locked the mutex may not try to + lock the same mutex again. +

+

If you leave a mutex locked in an emulator thread + when you let the thread out of your control, you will + very likely deadlock the whole emulator. +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_mutex_unlock(ErlDrvMutex *mtx) + Unlock a mutex + + +

Arguments:

+ + mtx + A pointer to a mutex to unlock. + +

This function unlocks a mutex. The mutex currently has to be + locked by the calling thread. +

+

This function is thread-safe.

+
+
+ + + ErlDrvCond *erl_drv_cond_create(char *name) + Create a condition variable + + +

Arguments:

+ + name + A string identifying the created condition variable. It + will be used to identify the condition variable in planned + future debug functionality. + + +

This function creates a condition variable and returns a + pointer to it. On failure NULL is returned. The driver + creating the condition variable has the responsibility of + destroying it before the driver is unloaded.

+

This function is thread-safe.

+
+
+ + + voiderl_drv_cond_destroy(ErlDrvCond *cnd) + Destroy a condition variable + + +

Arguments:

+ + cnd + A pointer to a condition variable to destroy. + +

This function destroys a condition variable previously + created by + erl_drv_cond_create(). +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_cond_signal(ErlDrvCond *cnd) + Signal on a condition variable + + +

Arguments:

+ + cnd + A pointer to a condition variable to signal on. + +

This function signals on a condition variable. That is, if + other threads are waiting on the condition variable being + signaled, one of them will be woken. +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_cond_broadcast(ErlDrvCond *cnd) + Broadcast on a condition variable + + +

Arguments:

+ + cnd + A pointer to a condition variable to broadcast on. + +

This function broadcasts on a condition variable. That is, if + other threads are waiting on the condition variable being + broadcasted on, all of them will be woken. +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_cond_wait(ErlDrvCond *cnd, ErlDrvMutex *mtx) + Wait on a condition variable + + +

Arguments:

+ + cnd + A pointer to a condition variable to wait on. + mtx + A pointer to a mutex to unlock while waiting. + + + +

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. +

+

erl_drv_cond_wait() might return even though + no-one has signaled or broadcasted on the condition + variable. Code calling erl_drv_cond_wait() should + always be prepared for erl_drv_cond_wait() + returning even though the condition that the thread was + waiting for hasn't occurred. That is, when returning from + erl_drv_cond_wait() always check if the condition + has occurred, and if not call erl_drv_cond_wait() + again. +

+

This function is thread-safe.

+
+
+ + + ErlDrvRWLock *erl_drv_rwlock_create(char *name) + Create an rwlock + + +

Arguments:

+ + name + A string identifying the created rwlock. It will be used to + identify the rwlock in planned future debug functionality. + + +

This function creates an rwlock and returns a pointer to it. On + failure NULL is returned. The driver creating the rwlock + has the responsibility of destroying it before the driver is + unloaded. +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_rwlock_destroy(ErlDrvRWLock *rwlck) + Destroy an rwlock + + +

Arguments:

+ + rwlck + A pointer to an rwlock to destroy. + +

This function destroys an rwlock previously created by + erl_drv_rwlock_create(). + The rwlock has to be in an unlocked state before being destroyed. +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_rwlock_rlock(ErlDrvRWLock *rwlck) + Read lock an rwlock + + +

Arguments:

+ + rwlck + A pointer to an rwlock to read lock. + +

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 + not lock the same rwlock again. +

+

If you leave an rwlock locked in an emulator thread + when you let the thread out of your control, you will + very likely deadlock the whole emulator. +

+

This function is thread-safe.

+
+
+ + + interl_drv_rwlock_tryrlock(ErlDrvRWLock *rwlck) + Try to read lock an rwlock + + +

Arguments:

+ + rwlck + A pointer to an rwlock to try to read lock. + +

This function tries to read lock an rwlock. If successful + 0, is returned; otherwise, EBUSY is returned. + A thread which currently has read or read/write locked the + rwlock may not try to lock the same rwlock again. +

+

If you leave an rwlock locked in an emulator thread + when you let the thread out of your control, you will + very likely deadlock the whole emulator. +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_rwlock_runlock(ErlDrvRWLock *rwlck) + Read unlock an rwlock + + +

Arguments:

+ + rwlck + A pointer to an rwlock to read unlock. + +

This function read unlocks an rwlock. The rwlock currently + has to be read locked by the calling thread. +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_rwlock_rwlock(ErlDrvRWLock *rwlck) + Read/Write lock an rwlock + + +

Arguments:

+ + rwlck + A pointer to an rwlock to read/write lock. + +

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 not lock the same rwlock again. +

+

If you leave an rwlock locked in an emulator thread + when you let the thread out of your control, you will + very likely deadlock the whole emulator. +

+

This function is thread-safe.

+
+
+ + + interl_drv_rwlock_tryrwlock(ErlDrvRWLock *rwlck) + Try to read/write lock an rwlock + + +

Arguments:

+ + rwlck + A pointer to an rwlock to try to read/write lock. + +

This function tries to read/write lock an rwlock. If successful + 0, is returned; otherwise, EBUSY is returned. + A thread which currently has read or read/write locked the + rwlock may not try to lock the same rwlock again. +

+

If you leave an rwlock locked in an emulator thread + when you let the thread out of your control, you will + very likely deadlock the whole emulator. +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_rwlock_rwunlock(ErlDrvRWLock *rwlck) + Read/Write unlock an rwlock + + +

Arguments:

+ + rwlck + A pointer to an rwlock to read/write unlock. + +

This function read/write unlocks an rwlock. The rwlock + currently has to be read/write locked by the calling thread. +

+

This function is thread-safe.

+
+
+ + + interl_drv_tsd_key_create(char *name, ErlDrvTSDKey *key) + Create a thread specific data key + + +

Arguments:

+ + name + A string identifying the created key. It will be used + to identify the key in planned future debug + functionality. + + key + A pointer to a thread specific data key variable. + +

This function creates a thread specific data key. On success + 0 is returned; otherwise, an errno value is returned + to indicate the error. The driver creating the key has the + responsibility of destroying it before the driver is unloaded. +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_tsd_key_destroy(ErlDrvTSDKey key) + Destroy a thread specific data key + + +

Arguments:

+ + key + A thread specific data key to destroy. + +

This function destroys a thread specific data key + previously created by + erl_drv_tsd_key_create(). + All thread specific data using this key in all threads + have to be cleared (see + erl_drv_tsd_set()) + prior to the call to erl_drv_tsd_key_destroy(). +

+

A destroyed key is very likely to be reused soon. + Therefore, if you fail to clear the thread specific + data using this key in a thread prior to destroying + the key, you will very likely get unexpected + errors in other parts of the system. +

+

This function is thread-safe.

+
+
+ + + voiderl_drv_tsd_set(ErlDrvTSDKey key, void *data) + Set thread specific data + + +

Arguments:

+ + key + A thread specific data key. + data + A pointer to data to associate with key + in calling thread. + + +

This function sets thread specific data associated with + key for the calling thread. You are only allowed to set + thread specific data for threads while they are fully under your + control. For example, if you set thread specific data in a thread + calling a driver call-back function, it has to be cleared, i.e. + set to NULL, before returning from the driver call-back + function. +

+

If you fail to clear thread specific data in an + emulator thread before letting it out of your control, + you might not ever be able to clear this data with + later unexpected errors in other parts of the system as + a result. +

+

This function is thread-safe.

+
+
+ + + void *erl_drv_tsd_get(ErlDrvTSDKey key) + Get thread specific data + + +

Arguments:

+ + key + A thread specific data key. + +

This function returns the thread specific data + associated with key for the calling thread. + If no data has been associated with key for + the calling thread, NULL is returned. +

+

This function is thread-safe.

+
+
+ + + interl_drv_putenv(char *key, char *value) + Set the value of an environment variable + + +

Arguments:

+ + key + A null terminated string containing the + name of the environment variable. + value + A null terminated string containing the + new value of the environment variable. + +

This function sets the value of an environment variable. + It returns 0 on success, and a value != 0 on + failure. +

+

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.

+
+

Do not use libc's putenv or similar + C library interfaces from a driver. +

+

This function is thread-safe.

+
+
+ + + interl_drv_getenv(char *key, char *value, size_t *value_size) + Get the value of an environment variable + + +

Arguments:

+ + key + A null terminated string containing the + name of the environment variable. + value + A pointer to an output buffer. + value_size + A pointer to an integer. The integer is both used for + passing input and output sizes (see below). + + +

This function retrieves the value of an environment variable. + When called, *value_size should contain the size of + the value buffer. On success 0 is returned, + the value of the environment variable has been written to + the value buffer, and *value_size contains the + string length (excluding the terminating null character) of + the value written to the value buffer. On failure, + i.e., no such environment variable was found, a value less than + 0 is returned. When the size of the value + buffer is too small, a value greater than 0 is returned + and *value_size has been set to the buffer size needed. +

+

Do not use libc's getenv or similar + C library interfaces from a driver. +

+

This function is thread-safe.

+
+
+
+ +
+ SEE ALSO +

driver_entry(3), + erl_ddll(3), + erlang(3)

+

An Alternative Distribution Driver (ERTS User's + Guide Ch. 3)

+
+
+ -- cgit v1.2.3