erl_ddll(3erl) Erlang Module Definition erl_ddll(3erl)
NAME
erl_ddll - Dynamic driver loader and linker.
DESCRIPTION
This module provides an interface for loading and unloading Erlang
linked-in drivers in runtime.
Note:
This is a large reference document. For casual use of this module, and
for most real world applications, the descriptions of functions load/2
and unload/1 are enough to getting started.
The driver is to be provided as a dynamically linked library in an ob-
ject code format specific for the platform in use, that is, .so files
on most Unix systems and .ddl files on Windows. An Erlang linked-in
driver must provide specific interfaces to the emulator, so this module
is not designed for loading arbitrary dynamic libraries. For more in-
formation about Erlang drivers, see erts:erl_driver .
When describing a set of functions (that is, a module, a part of a mod-
ule, or an application), executing in a process and wanting to use a
ddll-driver, we use the term user. A process can have many users (dif-
ferent modules needing the same driver) and many processes running the
same code, making up many users of a driver.
In the basic scenario, each user loads the driver before starting to
use it and unloads the driver when done. The reference counting keeps
track of processes and the number of loads by each process. This way
the driver is only unloaded when no one wants it (it has no user). The
driver also keeps track of ports that are opened to it. This enables
delay of unloading until all ports are closed, or killing of all ports
that use the driver when it is unloaded.
The interface supports two basic scenarios of loading and unloading.
Each scenario can also have the option of either killing ports when the
driver is unloading, or waiting for the ports to close themselves. The
scenarios are as follows:
Load and Unload on a "When Needed Basis":
This (most common) scenario simply supports that each user of the
driver loads it when needed and unloads it when no longer needed.
The driver is always reference counted and as long as a process
keeping the driver loaded is still alive, the driver is present in
the system.
Each user of the driver use literally the same pathname for the
driver when demanding load, but the users are not concerned with if
the driver is already loaded from the file system or if the object
code must be loaded from file system.
The following two pairs of functions support this scenario:
load/2 and unload/1:
When using the load/unload interfaces, the driver is not unloaded
until the last port using the driver is closed. Function unload/1
can return immediately, as the users have no interrest in when
the unloading occurs. The driver is unloaded when no one needs it
any longer.
If a process having the driver loaded dies, it has the same ef-
fect as if unloading is done.
When loading, function load/2 returns ok when any instance of the
driver is present. Thus, if a driver is waiting to get unloaded
(because of open ports), it simply changes state to no longer
need unloading.
load_driver/2 and unload_driver/1:
These interfaces are intended to be used when it is considered an
error that ports are open to a driver that no user has loaded.
The ports that are still open when the last user calls un-
load_driver/1 or when the last process having the driver loaded
dies, are killed with reason driver_unloaded.
The function names load_driver and unload_driver are kept for
backward compatibility.
Loading and Reloading for Code Replacement:
This scenario can occur if the driver code needs replacement during
operation of the Erlang emulator. Implementing driver code replace-
ment is a little more tedious than Beam code replacement, as one
driver cannot be loaded as both "old" and "new" code. All users of
a driver must have it closed (no open ports) before the old code
can be unloaded and the new code can be loaded.
The unloading/loading is done as one atomic operation, blocking all
processes in the system from using the driver in question while in
progress.
The preferred way to do driver code replacement is to let one sin-
gle process keep track of the driver. When the process starts, the
driver is loaded. When replacement is required, the driver is
reloaded. Unload is probably never done, or done when the process
exits. If more than one user has a driver loaded when code replace-
ment is demanded, the replacement cannot occur until the last
"other" user has unloaded the driver.
Demanding reload when a reload is already in progress is always an
error. Using the high-level functions, it is also an error to de-
mand reloading when more than one user has the driver loaded.
To simplify driver replacement, avoid designing your system so that
more than one user has the driver loaded.
The two functions for reloading drivers are to be used together
with corresponding load functions to support the two different be-
haviors concerning open ports:
load/2 and reload/2:
This pair of functions is used when reloading is to be done after
the last open port to the driver is closed.
As reload/2 waits for the reloading to occur, a misbehaving
process keeping open ports to the driver (or keeping the driver
loaded) can cause infinite waiting for reload. Time-outs must be
provided outside of the process demanding the reload or by using
the low-level interface try_load/3 in combination with driver
monitors.
load_driver/2 and reload_driver/2:
This pair of functions are used when open ports to the driver are
to be killed with reason driver_unloaded to allow for new driver
code to get loaded.
However, if another process has the driver loaded, calling
reload_driver returns error code pending_process. As stated ear-
lier, the recommended design is to not allow other users than the
"driver reloader" to demand loading of the driver in question.
DATA TYPES
driver() = iolist() | atom()
path() = string() | atom()
EXPORTS
demonitor(MonitorRef) -> ok
Types:
MonitorRef = reference()
Removes a driver monitor in much the same way as erlang:demoni-
tor/1 in ERTS does with process monitors. For details about how
to create driver monitors, see monitor/2, try_load/3, and
try_unload/2.
The function throws a badarg exception if the parameter is not a
reference().
format_error(ErrorDesc) -> string()
Types:
ErrorDesc = term()
Takes an ErrorDesc returned by load, unload, or reload functions
and returns a string that describes the error or warning.
Note:
Because of peculiarities in the dynamic loading interfaces on
different platforms, the returned string is only guaranteed to
describe the correct error if format_error/1 is called in the
same instance of the Erlang virtual machine as the error ap-
peared in (meaning the same operating system process).
info() -> AllInfoList
Types:
AllInfoList = [DriverInfo]
DriverInfo = {DriverName, InfoList}
DriverName = string()
InfoList = [InfoItem]
InfoItem = {Tag :: atom(), Value :: term()}
Returns a list of tuples {DriverName, InfoList}, where InfoList
is the result of calling info/1 for that DriverName. Only dynam-
ically linked-in drivers are included in the list.
info(Name) -> InfoList
Types:
Name = driver()
InfoList = [InfoItem, ...]
InfoItem = {Tag :: atom(), Value :: term()}
Returns a list of tuples {Tag, Value}, where Tag is the informa-
tion item and Value is the result of calling info/2 with this
driver name and this tag. The result is a tuple list containing
all information available about a driver.
The following tags appears in the list:
* processes
* driver_options
* port_count
* linked_in_driver
* permanent
* awaiting_load
* awaiting_unload
For a detailed description of each value, see info/2.
The function throws a badarg exception if the driver is not
present in the system.
info(Name, Tag) -> Value
Types:
Name = driver()
Tag =
processes | driver_options | port_count |
linked_in_driver |
permanent | awaiting_load | awaiting_unload
Value = term()
Returns specific information about one aspect of a driver. Pa-
rameter Tag specifies which aspect to get information about. The
return Value differs between different tags:
processes:
Returns all processes containing users of the specific driv-
ers as a list of tuples {pid(),integer() >= 0}, where inte-
ger() denotes the number of users in process pid().
driver_options:
Returns a list of the driver options provided when loading,
and any options set by the driver during initialization. The
only valid option is kill_ports.
port_count:
Returns the number of ports (an integer() >= 0) using the
driver.
linked_in_driver:
Returns a boolean(), which is true if the driver is a stati-
cally linked-in one, otherwise false.
permanent:
Returns a boolean(), which is true if the driver has made
itself permanent (and is not a statically linked-in driver),
otherwise false.
awaiting_load:
Returns a list of all processes having monitors for loading
active. Each process is returned as {pid(),integer() >= 0},
where integer() is the number of monitors held by process
pid().
awaiting_unload:
Returns a list of all processes having monitors for unload-
ing active. Each process is returned as {pid(),integer() >=
0}, where integer() is the number of monitors held by
process pid().
If option linked_in_driver or permanent returns true, all other
options return linked_in_driver or permanent, respectively.
The function throws a badarg exception if the driver is not
present in the system or if the tag is not supported.
load(Path, Name) -> ok | {error, ErrorDesc}
Types:
Path = path()
Name = driver()
ErrorDesc = term()
Loads and links the dynamic driver Name. Path is a file path to
the directory containing the driver. Name must be a sharable ob-
ject/dynamic library. Two drivers with different Path parameters
cannot be loaded under the same name. Name is a string or atom
containing at least one character.
The Name specified is to correspond to the filename of the dy-
namically loadable object file residing in the directory speci-
fied as Path, but without the extension (that is, .so). The
driver name provided in the driver initialization routine must
correspond with the filename, in much the same way as Erlang
module names correspond to the names of the .beam files.
If the driver was previously unloaded, but is still present be-
cause of open ports to it, a call to load/2 stops the unloading
and keeps the driver (as long as Path is the same), and ok is
returned. If you really want the object code to be reloaded, use
reload/2 or the low-level interface try_load/3 instead. See also
the description of different scenarios for loading/unloading in
the introduction.
If more than one process tries to load an already loaded driver
with the same Path, or if the same process tries to load it many
times, the function returns ok. The emulator keeps track of the
load/2 calls, so that a corresponding number of unload/2 calls
must be done from the same process before the driver gets un-
loaded. It is therefore safe for an application to load a driver
that is shared between processes or applications when needed. It
can safely be unloaded without causing trouble for other parts
of the system.
It is not allowed to load multiple drivers with the same name
but with different Path parameters.
Note:
Path is interpreted literally, so that all loaders of the same
driver must specify the same literal Path string, although dif-
ferent paths can point out the same directory in the file system
(because of use of relative paths and links).
On success, the function returns ok. On failure, the return
value is {error,ErrorDesc}, where ErrorDesc is an opaque term to
be translated into human readable form by function format_er-
ror/1.
For more control over the error handling, use the try_load/3 in-
terface instead.
The function throws a badarg exception if the parameters are not
specified as described here.
load_driver(Path, Name) -> ok | {error, ErrorDesc}
Types:
Path = path()
Name = driver()
ErrorDesc = term()
Works essentially as load/2, but loads the driver with other op-
tions. All ports using the driver are killed with reason
driver_unloaded when the driver is to be unloaded.
The number of loads and unloads by different users influences
the loading and unloading of a driver file. The port killing
therefore only occurs when the last user unloads the driver, or
when the last process having loaded the driver exits.
This interface (or at least the name of the functions) is kept
for backward compatibility. Using try_load/3 with {driver_op-
tions,[kill_ports]} in the option list gives the same effect re-
garding the port killing.
The function throws a badarg exception if the parameters are not
specified as described here.
loaded_drivers() -> {ok, Drivers}
Types:
Drivers = [Driver]
Driver = string()
Returns a list of all the available drivers, both (statically)
linked-in and dynamically loaded ones.
The driver names are returned as a list of strings rather than a
list of atoms for historical reasons.
For more information about drivers, see info.
monitor(Tag, Item) -> MonitorRef
Types:
Tag = driver
Item = {Name, When}
Name = driver()
When = loaded | unloaded | unloaded_only
MonitorRef = reference()
Creates a driver monitor and works in many ways as erlang:moni-
tor/2 in ERTS, does for processes. When a driver changes state,
the monitor results in a monitor message that is sent to the
calling process. MonitorRef returned by this function is in-
cluded in the message sent.
As with process monitors, each driver monitor set only generates
one single message. The monitor is "destroyed" after the message
is sent, so it is then not needed to call demonitor/1.
MonitorRef can also be used in subsequent calls to demonitor/1
to remove a monitor.
The function accepts the following parameters:
Tag:
The monitor tag is always driver, as this function can only
be used to create driver monitors. In the future, driver
monitors will be integrated with process monitors, why this
parameter has to be specified for consistence.
Item:
Parameter Item specifies which driver to monitor (the driver
name) and which state change to monitor. The parameter is a
tuple of arity two whose first element is the driver name
and second element is one of the following:
loaded:
Notifies when the driver is reloaded (or loaded if loading
is underway). It only makes sense to monitor drivers that
are in the process of being loaded or reloaded. A future
driver name for loading cannot be monitored. That only re-
sults in a DOWN message sent immediately. Monitoring for
loading is therefore most useful when triggered by func-
tion try_load/3, where the monitor is created because the
driver is in such a pending state.
Setting a driver monitor for loading eventually leads to
one of the following messages being sent:
{'UP', reference(), driver, Name, loaded}:
This message is sent either immediately if the driver is
already loaded and no reloading is pending, or when
reloading is executed if reloading is pending.
The user is expected to know if reloading is demanded
before creating a monitor for loading.
{'UP', reference(), driver, Name, permanent}:
This message is sent if reloading was expected, but the
(old) driver made itself permanent before reloading. It
is also sent if the driver was permanent or statically
linked-in when trying to create the monitor.
{'DOWN', reference(), driver, Name, load_cancelled}:
This message arrives if reloading was underway, but the
requesting user cancelled it by dying or calling try_un-
load/2 (or unload/1/unload_driver/1) again before it was
reloaded.
{'DOWN', reference(), driver, Name, {load_failure, Fail-
ure}}:
This message arrives if reloading was underway but the
loading for some reason failed. The Failure term is one
of the errors that can be returned from try_load/3. The
error term can be passed to format_error/1 for transla-
tion into human readable form. Notice that the transla-
tion must be done in the same running Erlang virtual ma-
chine as the error was detected in.
unloaded:
Monitors when a driver gets unloaded. If one monitors a
driver that is not present in the system, one immediately
gets notified that the driver got unloaded. There is no
guarantee that the driver was ever loaded.
A driver monitor for unload eventually results in one of
the following messages being sent:
{'DOWN', reference(), driver, Name, unloaded}:
The monitored driver instance is now unloaded. As the
unload can be a result of a reload/2 request, the driver
can once again have been loaded when this message ar-
rives.
{'UP', reference(), driver, Name, unload_cancelled}:
This message is sent if unloading was expected, but
while the driver was waiting for all ports to get
closed, a new user of the driver appeared, and the un-
loading was cancelled.
This message appears if {ok, pending_driver} was re-
turned from try_unload/2 for the last user of the
driver, and then {ok, already_loaded} is returned from a
call to try_load/3.
If one really wants to monitor when the driver gets un-
loaded, this message distorts the picture, because no
unloading was done. Option unloaded_only creates a moni-
tor similar to an unloaded monitor, but never results in
this message.
{'UP', reference(), driver, Name, permanent}:
This message is sent if unloading was expected, but the
driver made itself permanent before unloading. It is
also sent if trying to monitor a permanent or statically
linked-in driver.
unloaded_only:
A monitor created as unloaded_only behaves exactly as one
created as unloaded except that the {'UP', reference(),
driver, Name, unload_cancelled} message is never sent, but
the monitor instead persists until the driver really gets
unloaded.
The function throws a badarg exception if the parameters are not
specified as described here.
reload(Path, Name) -> ok | {error, ErrorDesc}
Types:
Path = path()
Name = driver()
ErrorDesc = pending_process | OpaqueError
OpaqueError = term()
Reloads the driver named Name from a possibly different Path
than previously used. This function is used in the code change
scenario described in the introduction.
If there are other users of this driver, the function returns
{error, pending_process}, but if there are no other users, the
function call hangs until all open ports are closed.
Note:
Avoid mixing multiple users with driver reload requests.
To avoid hanging on open ports, use function try_load/3 instead.
The Name and Path parameters have exactly the same meaning as
when calling the plain function load/2.
On success, the function returns ok. On failure, the function
returns an opaque error, except the pending_process error de-
scribed earlier. The opaque errors are to be translated into hu-
man readable form by function format_error/1.
For more control over the error handling, use the try_load/3 in-
terface instead.
The function throws a badarg exception if the parameters are not
specified as described here.
reload_driver(Path, Name) -> ok | {error, ErrorDesc}
Types:
Path = path()
Name = driver()
ErrorDesc = pending_process | OpaqueError
OpaqueError = term()
Works exactly as reload/2, but for drivers loaded with the
load_driver/2 interface.
As this interface implies that ports are killed when the last
user disappears, the function does not hang waiting for ports to
get closed.
For more details, see scenarios in this module description and
the function description for reload/2.
The function throws a badarg exception if the parameters are not
specified as described here.
try_load(Path, Name, OptionList) ->
{ok, Status} |
{ok, PendingStatus, Ref} |
{error, ErrorDesc}
Types:
Path = path()
Name = driver()
OptionList = [Option]
Option =
{driver_options, DriverOptionList} |
{monitor, MonitorOption} |
{reload, ReloadOption}
DriverOptionList = [DriverOption]
DriverOption = kill_ports
MonitorOption = ReloadOption = pending_driver | pending
Status = loaded | already_loaded | PendingStatus
PendingStatus = pending_driver | pending_process
Ref = reference()
ErrorDesc = ErrorAtom | OpaqueError
ErrorAtom =
linked_in_driver | inconsistent | permanent |
not_loaded_by_this_process | not_loaded | pending_reload
|
pending_process
OpaqueError = term()
Provides more control than the load/2/reload/2 and
load_driver/2/reload_driver/2 interfaces. It never waits for
completion of other operations related to the driver, but imme-
diately returns the status of the driver as one of the follow-
ing:
{ok, loaded}:
The driver was loaded and is immediately usable.
{ok, already_loaded}:
The driver was already loaded by another process or is in
use by a living port, or both. The load by you is registered
and a corresponding try_unload is expected sometime in the
future.
{ok, pending_driver}or {ok, pending_driver, reference()}:
The load request is registered, but the loading is delayed
because an earlier instance of the driver is still waiting
to get unloaded (open ports use it). Still, unload is ex-
pected when you are done with the driver. This return value
mostly occurs when options {reload,pending_driver} or
{reload,pending} are used, but can occur when another user
is unloading a driver in parallel and driver option
kill_ports is set. In other words, this return value always
needs to be handled.
{ok, pending_process}or {ok, pending_process, reference()}:
The load request is registered, but the loading is delayed
because an earlier instance of the driver is still waiting
to get unloaded by another user (not only by a port, in
which case {ok,pending_driver} would have been returned).
Still, unload is expected when you are done with the driver.
This return value only occurs when option {reload,pending}
is used.
When the function returns {ok, pending_driver} or {ok, pend-
ing_process}, one can get information about when the driver is
actually loaded by using option {monitor, MonitorOption}.
When monitoring is requested, and a corresponding {ok, pend-
ing_driver} or {ok, pending_process} would be returned, the
function instead returns a tuple {ok, PendingStatus, refer-
ence()} and the process then gets a monitor message later, when
the driver gets loaded. The monitor message to expect is de-
scribed in the function description of monitor/2.
Note:
In case of loading, monitoring can not only get triggered by us-
ing option {reload, ReloadOption}, but also in special cases
where the load error is transient. Thus, {monitor, pend-
ing_driver} is to be used under basically all real world circum-
stances.
The function accepts the following parameters:
Path:
The file system path to the directory where the driver ob-
ject file is located. The filename of the object file (minus
extension) must correspond to the driver name (used in pa-
rameter Name) and the driver must identify itself with the
same name. Path can be provided as an iolist(), meaning it
can be a list of other iolist()s, characters (8-bit inte-
gers), or binaries, all to be flattened into a sequence of
characters.
The (possibly flattened) Path parameter must be consistent
throughout the system. A driver is to, by all users, be
loaded using the same literal Path. The exception is when
reloading is requested, in which case Path can be specified
differently. Notice that all users trying to load the driver
later need to use the new Path if Path is changed using a
reload option. This is yet another reason to have only one
loader of a driver one wants to upgrade in a running system.
Name:
This parameter is the name of the driver to be used in sub-
sequent calls to function erlang:open_port in ERTS. The name
can be specified as an iolist() or an atom(). The name spec-
ified when loading is used to find the object file (with the
help of Path and the system-implied extension suffix, that
is, .so). The name by which the driver identifies itself
must also be consistent with this Name parameter, much as
the module name of a Beam file much corresponds to its file-
name.
OptionList:
Some options can be specified to control the loading opera-
tion. The options are specified as a list of two-tuples. The
tuples have the following values and meanings:
{driver_options, DriverOptionList}:
This is to provide options that changes its general behav-
ior and "sticks" to the driver throughout its lifespan.
The driver options for a specified driver name need always
to be consistent, even when the driver is reloaded, mean-
ing that they are as much a part of the driver as the
name.
The only allowed driver option is kill_ports, which means
that all ports opened to the driver are killed with exit
reason driver_unloaded when no process any longer has the
driver loaded. This situation arises either when the last
user calls try_unload/2, or when the last process having
loaded the driver exits.
{monitor, MonitorOption}:
A MonitorOption tells try_load/3 to trigger a driver moni-
tor under certain conditions. When the monitor is trig-
gered, the function returns a three-tuple {ok, PendingSta-
tus, reference()}, where reference() is the monitor refer-
ence for the driver monitor.
Only one MonitorOption can be specified. It is one of the
following:
* The atom pending, which means that a monitor is to be
created whenever a load operation is delayed,
* The atom pending_driver, in which a monitor is created
whenever the operation is delayed because of open ports
to an otherwise unused driver.
Option pending_driver is of little use, but is present for
completeness, as it is well defined which reload options
that can give rise to which delays. However, it can be a
good idea to use the same MonitorOption as the ReloadOp-
tion, if present.
If reloading is not requested, it can still be useful to
specify option monitor, as forced unloads (driver option
kill_ports or option kill_ports to try_unload/2) trigger a
transient state where driver loading cannot be performed
until all closing ports are closed. Thus, as try_unload
can, in almost all situations, return {ok, pend-
ing_driver}, always specify at least {monitor, pend-
ing_driver} in production code (see the monitor discussion
earlier).
{reload, ReloadOption}:
This option is used to reload a driver from disk, most of-
ten in a code upgrade scenario. Having a reload option
also implies that parameter Path does not need to be con-
sistent with earlier loads of the driver.
To reload a driver, the process must have loaded the
driver before, that is, there must be an active user of
the driver in the process.
The reload option can be either of the following:
pending:
With the atom pending, reloading is requested for any
driver and is effectuated when all ports opened to the
driver are closed. The driver replacement in this case
takes place regardless if there are still pending users
having the driver loaded.
The option also triggers port-killing (if driver option
kill_ports is used) although there are pending users,
making it usable for forced driver replacement, but lay-
ing much responsibility on the driver users. The pending
option is seldom used as one does not want other users
to have loaded the driver when code change is underway.
pending_driver:
This option is more useful. Here, reloading is queued if
the driver is not loaded by any other users, but the
driver has opened ports, in which case {ok, pend-
ing_driver} is returned (a monitor option is recom-
mended).
If the driver is unloaded (not present in the system), er-
ror code not_loaded is returned. Option reload is intended
for when the user has already loaded the driver in ad-
vance.
The function can return numerous errors, some can only be re-
turned given a certain combination of options.
Some errors are opaque and can only be interpreted by passing
them to function format_error/1, but some can be interpreted di-
rectly:
{error,linked_in_driver}:
The driver with the specified name is an Erlang statically
linked-in driver, which cannot be manipulated with this API.
{error,inconsistent}:
The driver is already loaded with other DriverOptionList or
a different literal Path argument.
This can occur even if a reload option is specified, if
DriverOptionList differs from the current.
{error, permanent}:
The driver has requested itself to be permanent, making it
behave like an Erlang linked-in driver and can no longer be
manipulated with this API.
{error, pending_process}:
The driver is loaded by other users when option {reload,
pending_driver} was specified.
{error, pending_reload}:
Driver reload is already requested by another user when op-
tion {reload, ReloadOption} was specified.
{error, not_loaded_by_this_process}:
Appears when option reload is specified. The driver Name is
present in the system, but there is no user of it in this
process.
{error, not_loaded}:
Appears when option reload is specified. The driver Name is
not in the system. Only drivers loaded by this process can
be reloaded.
All other error codes are to be translated by function for-
mat_error/1. Notice that calls to format_error are to be per-
formed from the same running instance of the Erlang virtual ma-
chine as the error is detected in, because of system-dependent
behavior concerning error values.
If the arguments or options are malformed, the function throws a
badarg exception.
try_unload(Name, OptionList) ->
{ok, Status} |
{ok, PendingStatus, Ref} |
{error, ErrorAtom}
Types:
Name = driver()
OptionList = [Option]
Option = {monitor, MonitorOption} | kill_ports
MonitorOption = pending_driver | pending
Status = unloaded | PendingStatus
PendingStatus = pending_driver | pending_process
Ref = reference()
ErrorAtom =
linked_in_driver | not_loaded |
not_loaded_by_this_process |
permanent
This is the low-level function to unload (or decrement reference
counts of) a driver. It can be used to force port killing, in
much the same way as the driver option kill_ports implicitly
does. Also, it can trigger a monitor either because other users
still have the driver loaded or because open ports use the
driver.
Unloading can be described as the process of telling the emula-
tor that this particular part of the code in this particular
process (that is, this user) no longer needs the driver. That
can, if there are no other users, trigger unloading of the
driver, in which case the driver name disappears from the system
and (if possible) the memory occupied by the driver executable
code is reclaimed.
If the driver has option kill_ports set, or if kill_ports is
specified as an option to this function, all pending ports using
this driver are killed when unloading is done by the last user.
If no port-killing is involved and there are open ports, the un-
loading is delayed until no more open ports use the driver. If,
in this case, another user (or even this user) loads the driver
again before the driver is unloaded, the unloading never takes
place.
To allow the user to request unloading to wait for actual un-
loading, monitor triggers can be specified in much the same way
as when loading. However, as users of this function seldom are
interested in more than decrementing the reference counts, moni-
toring is seldom needed.
Note:
If option kill_ports is used, monitor trigging is crucial, as
the ports are not guaranteed to be killed until the driver is
unloaded. Thus, a monitor must be triggered for at least the
pending_driver case.
The possible monitor messages to expect are the same as when us-
ing option unloaded to function monitor/2.
The function returns one of the following statuses upon success:
{ok, unloaded}:
The driver was immediately unloaded, meaning that the driver
name is now free to use by other drivers and, if the under-
lying OS permits it, the memory occupied by the driver ob-
ject code is now reclaimed.
The driver can only be unloaded when there are no open ports
using it and no more users require it to be loaded.
{ok, pending_driver}or {ok, pending_driver, reference()}:
Indicates that this call removed the last user from the
driver, but there are still open ports using it. When all
ports are closed and no new users have arrived, the driver
is reloaded and the name and memory reclaimed.
This return value is valid even if option kill_ports was
used, as killing ports can be a process that does not com-
plete immediately. However, the condition is in that case
transient. Monitors are always useful to detect when the
driver is really unloaded.
{ok, pending_process}or {ok, pending_process, reference()}:
The unload request is registered, but other users still hold
the driver. Notice that the term pending_process can refer
to the running process; there can be more than one user in
the same process.
This is a normal, healthy, return value if the call was just
placed to inform the emulator that you have no further use
of the driver. It is the most common return value in the
most common scenario described in the introduction.
The function accepts the following parameters:
Name:
Name is the name of the driver to be unloaded. The name can
be specified as an iolist() or as an atom().
OptionList:
Argument OptionList can be used to specify certain behavior
regarding ports and triggering monitors under certain condi-
tions:
kill_ports:
Forces killing of all ports opened using this driver, with
exit reason driver_unloaded, if you are the last user of
the driver.
If other users have the driver loaded, this option has no
effect.
To get the consistent behavior of killing ports when the
last user unloads, use driver option kill_ports when load-
ing the driver instead.
{monitor, MonitorOption}:
Creates a driver monitor if the condition specified in
MonitorOption is true. The valid options are:
pending_driver:
Creates a driver monitor if the return value is to be
{ok, pending_driver}.
pending:
Creates a monitor if the return value is {ok, pend-
ing_driver} or {ok, pending_process}.
The pending_driver MonitorOption is by far the most use-
ful. It must be used to ensure that the driver really is
unloaded and the ports closed whenever option kill_ports
is used, or the driver can have been loaded with driver
option kill_ports.
Using the monitor triggers in the call to try_unload en-
sures that the monitor is added before the unloading is
executed, meaning that the monitor is always properly
triggered, which is not the case if monitor/2 is called
separately.
The function can return the following error conditions, all well
specified (no opaque values):
{error, linked_in_driver}:
You were trying to unload an Erlang statically linked-in
driver, which cannot be manipulated with this interface (and
cannot be unloaded at all).
{error, not_loaded}:
The driver Name is not present in the system.
{error, not_loaded_by_this_process}:
The driver Name is present in the system, but there is no
user of it in this process.
As a special case, drivers can be unloaded from processes
that have done no corresponding call to try_load/3 if, and
only if, there are no users of the driver at all, which can
occur if the process containing the last user dies.
{error, permanent}:
The driver has made itself permanent, in which case it can
no longer be manipulated by this interface (much like a
statically linked-in driver).
The function throws a badarg exception if the parameters are not
specified as described here.
unload(Name) -> ok | {error, ErrorDesc}
Types:
Name = driver()
ErrorDesc = term()
Unloads, or at least dereferences the driver named Name. If the
caller is the last user of the driver, and no more open ports
use the driver, the driver gets unloaded. Otherwise, unloading
is delayed until all ports are closed and no users remain.
If there are other users of the driver, the reference counts of
the driver is merely decreased, so that the caller is no longer
considered a user of the driver. For use scenarios, see the de-
scription in the beginning of this module.
The ErrorDesc returned is an opaque value to be passed further
on to function format_error/1. For more control over the opera-
tion, use the try_unload/2 interface.
The function throws a badarg exception if the parameters are not
specified as described here.
unload_driver(Name) -> ok | {error, ErrorDesc}
Types:
Name = driver()
ErrorDesc = term()
Unloads, or at least dereferences the driver named Name. If the
caller is the last user of the driver, all remaining open ports
using the driver are killed with reason driver_unloaded and the
driver eventually gets unloaded.
If there are other users of the driver, the reference counts of
the driver is merely decreased, so that the caller is no longer
considered a user. For use scenarios, see the description in the
beginning of this module.
The ErrorDesc returned is an opaque value to be passed further
on to function format_error/1. For more control over the opera-
tion, use the try_unload/2 interface.
The function throws a badarg exception if the parameters are not
specified as described here.
SEE ALSO
erts:erl_driver(5), erts:driver_entry(5)
Ericsson AB kernel 7.0 erl_ddll(3erl)