aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/doc/src/erl_ddll.xml
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/doc/src/erl_ddll.xml')
-rw-r--r--lib/kernel/doc/src/erl_ddll.xml1165
1 files changed, 1165 insertions, 0 deletions
diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml
new file mode 100644
index 0000000000..75dca8a85d
--- /dev/null
+++ b/lib/kernel/doc/src/erl_ddll.xml
@@ -0,0 +1,1165 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>erl_ddll</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <module>erl_ddll</module>
+ <modulesummary>Dynamic Driver Loader and Linker</modulesummary>
+ <description>
+ <p>The <c>erl_ddll</c> module provides an interface for loading
+ and unloading <em>erlang linked in drivers</em> in runtime.</p>
+ <note>
+ <p>This is a large reference document. For casual use of the
+ module, as well as for most real world applications, the
+ descriptions of the functions <seealso marker="#load/2">load/2</seealso> and <seealso marker="#unload/1">unload/1</seealso> are enough to get
+ going. </p>
+ </note>
+ <p>The driver should be provided as a dynamically linked library
+ in a object code format specific for the platform in use,
+ i. e. <c>.so</c> files on most Unix systems and <c>.ddl</c>
+ files on windows. An erlang linked in driver has to provide
+ specific interfaces to the emulator, so this module is not
+ designed for loading arbitrary dynamic libraries. For further
+ information about erlang drivers, refer to the ERTS reference
+ manual section <seealso marker="erts:erl_driver">erl_driver</seealso>.</p>
+ <marker id="users"></marker>
+ <p>When describing a set of functions, (i.e. a module, a part of a
+ module or an application) executing in a process and wanting to
+ use a ddll-driver, we use the term <em>user</em>. There can be
+ several users in one process (different modules needing the same
+ driver) and several processes running the same code, making up
+ several <em>users</em> 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 as well as the number of loads by each process, so that
+ the driver will only be unloaded when no one wants it
+ (it has no user). The driver also keeps track of ports that are
+ opened towards it, so that one can delay unloading until all
+ ports are closed or kill all ports using the driver when it is
+ unloaded. </p>
+ <marker id="scenarios"></marker>
+ <p>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:</p>
+ <taglist>
+ <tag><em>Load and unload on a "when needed basis"</em></tag>
+ <item>
+ <p>This (most common) scenario simply supports that each
+ <seealso marker="#users">user</seealso> of the driver loads
+ it when it is needed and unloads it when the <seealso marker="#users">user</seealso> no longer have any use for
+ it. 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.</p>
+ <p>Each <seealso marker="#users">user</seealso> of the driver
+ use <em>literally</em> the same pathname for the driver when
+ demanding load, but the <seealso marker="#users">users</seealso> are not really concerned
+ with if the driver is already loaded from the filesystem or
+ if the object code has to be loaded from filesystem.</p>
+ <p>Two pairs of functions support this scenario:</p>
+ <taglist>
+ <tag><em>load/2 and unload/1</em></tag>
+ <item>
+ <p>When using the <c>load/unload</c> interfaces, the
+ driver will not <em>actually</em> get unloaded until the
+ <em>last port</em> using the driver is closed. The function
+ <c>unload/1</c> can return immediately, as the <seealso marker="#users">users</seealso> are not really concerned
+ with when the actual unloading occurs. The
+ driver will actually get unloaded when no one needs it any longer.</p>
+ <p>If a process having the driver loaded dies, it will have
+ the same effect as if unloading was done. </p>
+ <p>When loading, the function <c>load/2</c> returns
+ <c>ok</c> as soon as there is any instance of the driver
+ present, so that if a driver is waiting to get unloaded
+ (due to open ports), it will simply change state to no
+ longer need unloading.</p>
+ </item>
+ <tag><em>load_driver/2 and unload_driver/1</em></tag>
+ <item>
+ <p>These interfaces is intended to be used when it is considered an
+ error that ports are open towards a driver that no <seealso marker="#users">user</seealso>
+ has loaded. The ports still open when the
+ last <seealso marker="#users">user</seealso> calls
+ <c>unload_driver/1</c> or when the last process having the
+ driver loaded dies, will get killed with reason
+ <c>driver_unloaded</c>.</p>
+ <p>The function names <c>load_driver</c> and
+ <c>unload_driver</c> are kept for backward
+ compatibility.</p>
+ </item>
+ </taglist>
+ </item>
+ <tag><em>Loading and reloading for code replacement</em></tag>
+ <item>
+ <p>This scenario occurs when the driver code might need
+ replacement during operation of the Erlang
+ emulator. Implementing driver code replacement is somewhat
+ more tedious than beam code replacement, as one driver
+ cannot be loaded as both "old" and "new" code. All <seealso marker="#users">users</seealso> of a driver must have it
+ closed (no open ports) before the old code can be unloaded
+ and the new code can be loaded.</p>
+ <p>The actual unloading/loading is done as one atomic
+ operation, blocking all processes in the system from using
+ the driver concerned while in progress.</p>
+ <p>The preferred way to do driver code replacement is to let
+ <em>one single process</em> keep track of the driver. When
+ the process start, 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 <seealso marker="#users">user</seealso> has a driver loaded when code
+ replacement is demanded, the replacement cannot occur until
+ the last "other" <seealso marker="#users">user</seealso> has
+ unloaded the driver.</p>
+ <p>Demanding reload when a reload is already in progress is
+ always an error. Using the high level functions, it is also
+ an error to demand reloading when more than one <seealso marker="#users">user</seealso> has the driver loaded. To
+ simplify driver replacement, avoid designing your system so
+ that more than than one <seealso marker="#users">user</seealso> has the driver loaded.</p>
+ <p>The two functions for reloading drivers should be used
+ together with corresponding load functions, to support the two
+ different behaviors concerning open ports:</p>
+ <taglist>
+ <tag><em>load/2 and reload/2</em></tag>
+ <item>
+ <p>This pair of functions is used when reloading should be
+ done after the last open port towards the driver is
+ closed.</p>
+ <p>As <c>reload/2</c> actually waits for the reloading to
+ occur, a misbehaving process keeping open ports towards
+ the driver (or keeping the driver loaded) might cause
+ infinite waiting for reload. Timeouts has to be provided
+ outside of the process demanding the reload or by using
+ the low-level interface <seealso marker="#try_load/3">try_load/3</seealso> in combination
+ with driver monitors (see below).</p>
+ </item>
+ <tag><em>load_driver/2 and reload_driver/2</em></tag>
+ <item>
+ <p>This pair of functions are used when open ports towards
+ the driver should be killed with reason
+ <c>driver_unloaded</c> to allow for new driver code to
+ get loaded.</p>
+ <p>If, however, another process has the driver loaded,
+ calling <c>reload_driver</c> returns the error code
+ <c>pending_process</c>. As stated earlier,
+ the recommended design is to not allow other <seealso marker="#users">users</seealso> than the "driver
+ reloader" to actually demand loading of the concerned
+ driver.</p>
+ </item>
+ </taglist>
+ </item>
+ </taglist>
+ </description>
+ <funcs>
+ <func>
+ <name>demonitor(MonitorRef) -> ok</name>
+ <fsummary>Remove a monitor for a driver</fsummary>
+ <type>
+ <v>MonitorRef = ref()</v>
+ </type>
+ <desc>
+ <p>Removes a driver monitor in much the same way as
+ <seealso marker="erts:erlang#erlang:demonitor/1">erlang:demonitor/1</seealso> does with process
+ monitors. See <seealso marker="#monitor/2">monitor/2</seealso>, <seealso marker="#try_load/3">try_load/3</seealso> and <seealso marker="#try_unload/2">try_unload/2</seealso> for details
+ about how to create driver monitors.</p>
+ <p>The function throws a <c>badarg</c> exception if the
+ parameter is not a ref(). </p>
+ </desc>
+ </func>
+ <func>
+ <name>info() -> AllInfoList</name>
+ <fsummary>Retrieve information about all drivers</fsummary>
+ <type>
+ <v>AllInfoList = [ DriverInfo ]</v>
+ <v>DriverInfo = {DriverName, InfoList}</v>
+ <v>DriverName = string()</v>
+ <v>InfoList = [ InfoItem ]</v>
+ <v>InfoItem = {Tag, Value}</v>
+ <v>Tag = atom()</v>
+ <v>Value = term()</v>
+ </type>
+ <desc>
+ <p>Returns a list of tuples <c>{DriverName, InfoList}</c>, where
+ <c>InfoList</c> is the result of calling <seealso marker="#info/1">info/1</seealso> for that
+ <c>DriverName</c>. Only dynamically linked in drivers are
+ included in the list.</p>
+ </desc>
+ </func>
+ <func>
+ <name>info(Name) -> InfoList</name>
+ <fsummary>Retrieve information about one driver</fsummary>
+ <type>
+ <v>Name = string() | atom()</v>
+ <v>InfoList = [ InfoItem ]</v>
+ <v>InfoItem = {Tag, Value}</v>
+ <v>Tag = atom()</v>
+ <v>Value = term()</v>
+ </type>
+ <desc>
+ <p>Returns a list of tuples <c>{Tag, Value}</c>, where
+ <c>Tag</c> is the information item and <c>Value</c> is the result
+ of calling <seealso marker="#info/2">info/2</seealso> with this driver name and
+ this tag. The result being a tuple list containing all
+ information available about a driver. </p>
+ <p>The different tags that will appear in the list are:</p>
+ <list type="bulleted">
+ <item>processes</item>
+ <item>driver_options</item>
+ <item>port_count</item>
+ <item>linked_in_driver</item>
+ <item>permanent</item>
+ <item>awaiting_load</item>
+ <item>awaiting_unload</item>
+ </list>
+ <p>For a detailed description of each value, please read the
+ description of <seealso marker="#info/2">info/2</seealso> below.</p>
+ <p>The function throws a <c>badarg</c> exception if the driver
+ is not present in the system.</p>
+ </desc>
+ </func>
+ <func>
+ <name>info(Name, Tag) -> Value</name>
+ <fsummary>Retrieve specific information about one driver</fsummary>
+ <type>
+ <v>Name = string() | atom()</v>
+ <v>Tag = processes | driver_options | port_count | linked_in_driver | permanent | awaiting_load | awaiting_unload</v>
+ <v>Value = term()</v>
+ </type>
+ <desc>
+ <p>This function returns specific information about one aspect
+ of a driver. The <c>Tag</c> parameter specifies which aspect
+ to get information about. The <c>Value</c> return differs
+ between different tags:</p>
+ <taglist>
+ <tag><em>processes</em></tag>
+ <item>
+ <p>Return all processes containing <seealso marker="#users">users</seealso> of the specific drivers
+ as a list of tuples <c>{pid(),int()}</c>, where the
+ <c>int()</c> denotes the number of users in the process
+ <c>pid()</c>.</p>
+ </item>
+ <tag><em>driver_options</em></tag>
+ <item>
+ <p>Return a list of the driver options provided when
+ loading, as well as any options set by the driver itself
+ during initialization. The currently only valid option
+ being <c>kill_ports</c>.</p>
+ </item>
+ <tag><em>port_count</em></tag>
+ <item>
+ <p>Return the number of ports (an <c>int()</c>) using the driver.</p>
+ </item>
+ <tag><em>linked_in_driver</em></tag>
+ <item>
+ <p>Return a <c>bool()</c>, being <c>true</c> if the driver is a
+ statically linked in one and <c>false</c> otherwise.</p>
+ </item>
+ <tag><em>permanent</em></tag>
+ <item>
+ <p>Return a <c>bool()</c>, being <c>true</c> if the driver has made
+ itself permanent (and is <em>not</em> a statically
+ linked in driver). <c>false</c> otherwise.</p>
+ </item>
+ <tag><em>awaiting_load</em></tag>
+ <item>
+ <p>Return a list of all processes having monitors for
+ <c>loading</c> active, each process returned as
+ <c>{pid(),int()}</c>, where the <c>int()</c> is the
+ number of monitors held by the process <c>pid()</c>.</p>
+ </item>
+ <tag><em>awaiting_unload</em></tag>
+ <item>
+ <p>Return a list of all processes having monitors for
+ <c>unloading</c> active, each process returned as
+ <c>{pid(),int()}</c>, where the <c>int()</c> is the
+ number of monitors held by the process <c>pid()</c>.</p>
+ </item>
+ </taglist>
+ <p>If the options <c>linked_in_driver</c> or <c>permanent</c>
+ return true, all other options will return the value
+ <c>linked_in_driver</c> or <c>permanent</c> respectively.</p>
+ <p>The function throws a <c>badarg</c> exception if the driver
+ is not present in the system or the tag is not supported.</p>
+ </desc>
+ </func>
+ <func>
+ <name>load(Path, Name) -> ok | {error, ErrorDesc}</name>
+ <fsummary>Load a driver</fsummary>
+ <type>
+ <v>Path = Name = string() | atom()</v>
+ <v>ErrorDesc = term()</v>
+ </type>
+ <desc>
+ <p>Loads and links the dynamic driver <c>Name</c>. <c>Path</c>
+ is a file path to the directory containing the driver.
+ <c>Name</c> must be a sharable object/dynamic library. Two
+ drivers with different <c>Path</c> parameters cannot be
+ loaded under the same name. The <c>Name</c> is a string or
+ atom containing at least one character.</p>
+ <p>The <c>Name</c> given should correspond to the filename
+ of the actual dynamically loadable object file residing in
+ the directory given as <c>Path</c>, but <em>without</em> the
+ extension (i.e. <c>.so</c>). 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 <c>.beam</c> files.</p>
+ <p>If the driver has been previously unloaded, but is still
+ present due to open ports against it, a call to
+ <c>load/2</c> will stop the unloading and keep the driver
+ (as long as the <c>Path</c> is the same) and <c>ok</c> is
+ returned. If one actually wants the object code to be
+ reloaded, one uses <seealso marker="#reload/2">reload/2</seealso> or the low-level
+ interface <seealso marker="#try_load/3">try_load/3</seealso>
+ instead. Please refer to the description of <seealso marker="#scenarios">different scenarios</seealso> for
+ loading/unloading in the introduction.</p>
+ <p>If more than one process tries to load an already loaded
+ driver withe the same <c>Path</c>, or if the same process
+ tries to load it several times, the function will return
+ <c>ok</c>. The emulator will keep track of the
+ <c>load/2</c> calls, so that a corresponding number of
+ <c>unload/2</c> calls will have to be done from the same
+ process before the driver will actually get unloaded. 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. </p>
+ <p>It is not allowed to load
+ several drivers with the same name but with different
+ <c>Path</c> parameters.</p>
+ <note>
+ <p>Note especially that the <c>Path</c> is interpreted
+ literally, so that all loaders of the same driver needs to
+ give the same <em>literal</em><c>Path</c> string, even
+ though different paths might point out the same directory
+ in the filesystem (due to use of relative paths and
+ links).</p>
+ </note>
+ <p>On success, the function returns <c>ok</c>. On
+ failure, the return value is <c>{error,ErrorDesc}</c>,
+ where <c>ErrorDesc</c> is an opaque term to be
+ translated into human readable form by the <seealso marker="#format_error/1">format_error/1</seealso>
+ function.</p>
+ <p>For more control over the error handling, again use the
+ <seealso marker="#try_load/3">try_load/3</seealso>
+ interface instead.</p>
+ <p>The function throws a <c>badarg</c> exception if the
+ parameters are not given as described above. </p>
+ </desc>
+ </func>
+ <func>
+ <name>load_driver(Path, Name) -> ok | {error, ErrorDesc}</name>
+ <fsummary>Load a driver</fsummary>
+ <type>
+ <v>Path = Name = string() | atom()</v>
+ <v>ErrorDesc = term()</v>
+ </type>
+ <desc>
+ <p>Works essentially as <c>load/2</c>, but will load the driver
+ with options other options. All ports that are using the
+ driver will get killed with the reason
+ <c>driver_unloaded</c> when the driver is to be unloaded.</p>
+ <p>The number of loads and unloads by different <seealso marker="#users">users</seealso> influence the actual loading
+ and unloading of a driver file. The port killing will
+ therefore only happen when the <em>last</em><seealso marker="#users">user</seealso> unloads the driver, or the
+ last process having loaded the driver exits.</p>
+ <p>This interface (or at least the name of the functions) is
+ kept for backward compatibility. Using <seealso marker="#try_load/3">try_load/3</seealso> with
+ <c>{driver_options,[kill_ports]} </c> in the option list will
+ give the same effect regarding the port killing.</p>
+ <p>The function throws a <c>badarg</c> exception if the
+ parameters are not given as described above. </p>
+ </desc>
+ </func>
+ <func>
+ <name>monitor(Tag, Item) -> MonitorRef</name>
+ <fsummary>Create a monitor for a driver</fsummary>
+ <type>
+ <v>Tag = driver </v>
+ <v>Item = {Name, When}</v>
+ <v>Name = atom() | string()</v>
+ <v>When = loaded | unloaded | unloaded_only</v>
+ <v>MonitorRef = ref()</v>
+ </type>
+ <desc>
+ <p>This function creates a driver monitor and works in many
+ ways as the function <seealso marker="erts:erlang#erlang:monitor/2">erlang:monitor/2</seealso>,
+ does for processes. When a driver changes state, the monitor
+ results in a monitor-message being sent to the calling
+ process. The <c>MonitorRef</c> returned by this function is
+ included in the message sent.</p>
+ <p>As with process monitors, each driver monitor set will only
+ generate <em>one single message</em>. The monitor is
+ "destroyed" after the message is sent and there is then no
+ need to call <seealso marker="#demonitor/1">demonitor/1</seealso>.</p>
+ <p>The <c>MonitorRef</c> can also be used in subsequent calls
+ to <seealso marker="#demonitor/1">demonitor/1</seealso> to
+ remove a monitor.</p>
+ <p>The function accepts the following parameters:</p>
+ <taglist>
+ <tag><em>Tag</em></tag>
+ <item>
+ <p>The monitor tag is always <c>driver</c> 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 given for consistence.</p>
+ </item>
+ <tag><em>Item</em></tag>
+ <item>
+ <p>The <c>Item</c> parameter specifies which driver one
+ wants to monitor (the name of the driver) as well as
+ which state change one wants to monitor. The parameter
+ is a tuple of arity two whose first element is the
+ driver name and second element is either of:</p>
+ <taglist>
+ <tag><em>loaded</em></tag>
+ <item>
+ <p>Notify me 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. One cannot monitor a future-to-be driver
+ name for loading, that will only result in a
+ <c>'DOWN'</c> message being immediately sent.
+ Monitoring for loading is therefore most useful when
+ triggered by the <seealso marker="#try_load/3">try_load/3</seealso> function,
+ where the monitor is created <em>because</em> the
+ driver is in such a pending state.</p>
+ <p>Setting a driver monitor for <c>loading</c> will
+ eventually lead to one of the following messages
+ being sent:</p>
+ <taglist>
+ <tag><em>{'UP', ref(), driver, Name, loaded}</em></tag>
+ <item>
+ <p>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. </p>
+ <p>The <seealso marker="#users">user</seealso> is
+ expected to know if reloading is demanded prior
+ to creating a monitor for loading.</p>
+ </item>
+ <tag><em>{'UP', ref(), driver, Name, permanent}</em></tag>
+ <item>
+ <p>This message will be sent if reloading was
+ expected, but the (old) driver made itself
+ permanent prior to reloading. It will also be
+ sent if the driver was permanent or statically
+ linked in when trying to create the monitor.</p>
+ </item>
+ <tag><em>{'DOWN', ref(), driver, Name, load_cancelled}</em></tag>
+ <item>
+ <p>This message will arrive if reloading was
+ underway, but the <seealso marker="#users">user</seealso> having requested
+ reload cancelled it by either dying or calling
+ <seealso marker="#try_unload/2">try_unload/2</seealso>
+ (or <c>unload/1</c>/<c>unload_driver/1</c>)
+ again before it was reloaded.</p>
+ </item>
+ <tag><em>{'DOWN', ref(), driver, Name, {load_failure, Failure}}</em></tag>
+ <item>
+ <p>This message will arrive if reloading was
+ underway but the loading for some reason
+ failed. The <c>Failure</c> term is one of the
+ errors that can be returned from <seealso marker="#try_load/3">try_load/3</seealso>. The
+ error term can be passed to <seealso marker="#format_error/1">format_error/1</seealso>
+ for translation into human readable form. Note
+ that the translation has to be done in the same
+ running erlang virtual machine as the error
+ was detected in.</p>
+ </item>
+ </taglist>
+ </item>
+ <tag><em>unloaded</em></tag>
+ <item>
+ <p>Monitor when a driver gets unloaded. If one
+ monitors a driver that is not present in the system,
+ one will immediately get notified that the driver got
+ unloaded. There is no guarantee that the driver was
+ actually ever loaded.</p>
+ <p>A driver monitor for unload will eventually result
+ in one of the following messages being sent:</p>
+ <taglist>
+ <tag><em>{'DOWN', ref(), driver, Name, unloaded}</em></tag>
+ <item>
+ <p>The driver instance monitored is now
+ unloaded. As the unload might have been due to a
+ <c>reload/2</c> request, the driver might once
+ again have been loaded when this message
+ arrives.</p>
+ </item>
+ <tag><em>{'UP', ref(), driver, Name, unload_cancelled}</em></tag>
+ <item>
+ <p>This message will be sent if unloading was
+ expected, but while the driver was waiting for
+ all ports to get closed, a new <seealso marker="#users">user</seealso> of the driver
+ appeared and the unloading was cancelled.</p>
+ <p>This message appears when an <c>{ok, pending_driver}</c>) was returned from <seealso marker="#try_unload/2">try_unload/2</seealso>)
+ for the last <seealso marker="#users">user</seealso> of the driver and
+ then a <c>{ok, already_loaded}</c> is returned
+ from a call to <seealso marker="#try_load/3">try_load/3</seealso>.</p>
+ <p>If one wants to <em>really</em> monitor when the
+ driver gets unloaded, this message will distort
+ the picture, no unloading was really done.
+ The <c>unloaded_only</c> option creates a monitor
+ similar to an <c>unloaded</c> monitor, but does
+ never result in this message.</p>
+ </item>
+ <tag><em>{'UP', ref(), driver, Name, permanent}</em></tag>
+ <item>
+ <p>This message will be sent if unloading was
+ expected, but the driver made itself
+ permanent prior to unloading. It will also be
+ sent if trying to monitor a permanent or
+ statically linked in driver.</p>
+ </item>
+ </taglist>
+ </item>
+ <tag><em>unloaded_only</em></tag>
+ <item>
+ <p>A monitor created as <c>unloaded_only</c> behaves
+ exactly as one created as <c>unloaded</c> with the
+ exception that the <c>{'UP', ref(), driver, Name, unload_cancelled}</c> message will never be
+ sent, but the monitor instead persists until the
+ driver <em>really</em> gets unloaded.</p>
+ </item>
+ </taglist>
+ </item>
+ </taglist>
+ <p>The function throws a <c>badarg</c> exception if the
+ parameters are not given as described above. </p>
+ </desc>
+ </func>
+ <func>
+ <name>reload(Path, Name) -> ok | {error, ErrorDesc}</name>
+ <fsummary>Replace a driver</fsummary>
+ <type>
+ <v>Path = Name = string() | atom()</v>
+ <v>ErrorDesc = pending_process | OpaqueError</v>
+ <v>OpaqueError = term()</v>
+ </type>
+ <desc>
+ <p>Reloads the driver named <c>Name</c> from a possibly
+ different <c>Path</c> than was previously used. This
+ function is used in the code change <seealso marker="#scenarios">scenario</seealso> described in the
+ introduction.</p>
+ <p>If there are other <seealso marker="#users">users</seealso>
+ of this driver, the function will return <c>{error, pending_process}</c>, but if there are no more users, the
+ function call will hang until all open ports are closed.</p>
+ <note>
+ <p>Avoid mixing
+ several <seealso marker="#users">users</seealso>
+ with driver reload requests.</p>
+ </note>
+ <p>If one wants to avoid hanging on open ports, one should use
+ the <seealso marker="#try_load/3">try_load/3</seealso>
+ function instead.</p>
+ <p>The <c>Name</c> and <c>Path</c> parameters have exactly the
+ same meaning as when calling the plain <seealso marker="#load/2">load/2</seealso> function.</p>
+ <note>
+ <p>Avoid mixing
+ several <seealso marker="#users">users</seealso>
+ with driver reload requests.</p>
+ </note>
+ <p>On success, the function returns <c>ok</c>. On
+ failure, the function returns an opaque error, with the
+ exception of the <c>pending_process</c> error described
+ above. The opaque errors are to be translated into human
+ readable form by the <seealso marker="#format_error/1">format_error/1</seealso> function.</p>
+ <p>For more control over the error handling, again use the
+ <seealso marker="#try_load/3">try_load/3</seealso>
+ interface instead.</p>
+ <p>The function throws a <c>badarg</c> exception if the
+ parameters are not given as described above. </p>
+ </desc>
+ </func>
+ <func>
+ <name>reload_driver(Path, Name) -> ok | {error, ErrorDesc}</name>
+ <fsummary>Replace a driver</fsummary>
+ <type>
+ <v>Path = Name = string() | atom()</v>
+ <v>ErrorDesc = pending_process | OpaqueError</v>
+ <v>OpaqueError = term()</v>
+ </type>
+ <desc>
+ <p>Works exactly as <seealso marker="#reload/2">reload/2</seealso>, but for drivers
+ loaded with the <seealso marker="#load_driver/2">load_driver/2</seealso> interface. </p>
+ <p>As this interface implies that ports are being killed when
+ the last user disappears, the function wont hang waiting for
+ ports to get closed.</p>
+ <p>For further details, see the <seealso marker="#scenarios">scenarios</seealso> in the module
+ description and refer to the <seealso marker="#reload/2">reload/2</seealso> function description.</p>
+ <p>The function throws a <c>badarg</c> exception if the
+ parameters are not given as described above. </p>
+ </desc>
+ </func>
+ <func>
+ <name>try_load(Path, Name, OptionList) -> {ok,Status} | {ok, PendingStatus, Ref} | {error, ErrorDesc}</name>
+ <fsummary>Load a driver</fsummary>
+ <type>
+ <v>Path = Name = string() | atom()</v>
+ <v>OptionList = [ Option ]</v>
+ <v>Option = {driver_options, DriverOptionList} | {monitor, MonitorOption} | {reload, ReloadOption}</v>
+ <v>DriverOptionList = [ DriverOption ]</v>
+ <v>DriverOption = kill_ports</v>
+ <v>MonitorOption = pending_driver | pending</v>
+ <v>ReloadOption = pending_driver | pending</v>
+ <v>Status = loaded | already_loaded | PendingStatus </v>
+ <v>PendingStatus = pending_driver | pending_process</v>
+ <v>Ref = ref()</v>
+ <v>ErrorDesc = ErrorAtom | OpaqueError</v>
+ <v>ErrorAtom = linked_in_driver | inconsistent | permanent | not_loaded_by_this_process | not_loaded | pending_reload | pending_process</v>
+ </type>
+ <desc>
+ <p>This function provides more control than the
+ <c>load/2</c>/<c>reload/2</c> and
+ <c>load_driver/2</c>/<c>reload_driver/2</c> interfaces. It
+ will never wait for completion of other operations related
+ to the driver, but immediately return the status of the
+ driver as either:</p>
+ <taglist>
+ <tag><em>{ok, loaded}</em></tag>
+ <item>
+ <p>The driver was actually loaded and is immediately
+ usable.</p>
+ </item>
+ <tag><em>{ok, already_loaded}</em></tag>
+ <item>
+ <p>The driver was already loaded by another process
+ and/or is in use by a living port. The load by you is
+ registered and a corresponding <c>try_unload</c> is
+ expected sometime in the future.</p>
+ </item>
+ <tag><em>{ok, pending_driver}</em>or <em>{ok, pending_driver, ref()}</em></tag>
+ <item>
+ <p>The load request is registered, but the loading is
+ delayed due to the fact that an earlier instance of the
+ driver is still waiting to get unloaded (there are open
+ ports using it). Still, unload is expected when you are
+ done with the driver. This return value will
+ <em>mostly</em> happen when the
+ <c>{reload,pending_driver}</c> or
+ <c>{reload,pending}</c> options are used, but
+ <em>can</em> happen when another <seealso marker="#users">user</seealso> is unloading a driver in
+ parallel and the <c>kill_ports</c> driver option is
+ set. In other words, this return value will always need
+ to be handled!</p>
+ </item>
+ <tag><em>{ok, pending_process}</em>or <em>{ok, pending_process, ref()}</em></tag>
+ <item>
+ <p>The load request is registered, but the loading is
+ delayed due to the fact that an earlier instance of the
+ driver is still waiting to get unloaded by another
+ <seealso marker="#users">user</seealso> (not only by a
+ port, in which case <c>{ok,pending_driver}</c> would
+ have been returned). Still, unload is expected when you
+ are done with the driver. This return value will
+ <em>only</em> happen when the <c>{reload,pending}</c>
+ option is used.</p>
+ </item>
+ </taglist>
+ <p>When the function returns <c>{ok, pending_driver}</c> or
+ <c>{ok, pending_process}</c>, one might want to get information
+ about when the driver is <em>actually</em> loaded. This can
+ be achieved by using the <c>{monitor, PendingOption}</c> option.</p>
+ <p>When monitoring is requested, and a corresponding <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c> would be
+ returned, the function will instead return a tuple <c>{ok, PendingStatus, ref()}</c> and the process will, at a later
+ time when the driver actually gets loaded, get a monitor
+ message. The monitor message one can expect is described in
+ the <seealso marker="#monitor/2">monitor/2</seealso>
+ function description. </p>
+ <note>
+ <p>Note that in case of loading, monitoring can
+ <em>not</em> only get triggered by using the <c>{reload, ReloadOption}</c> option, but also in special cases where
+ the load-error is transient, why <c>{monitor, pending_driver}</c> should be used under basically
+ <em>all</em> real world circumstances!</p>
+ </note>
+ <p>The function accepts the following parameters:</p>
+ <taglist>
+ <tag><em>Path</em></tag>
+ <item>
+ <p>The filesystem path to the directory where the driver
+ object file is situated. The filename of the object file
+ (minus extension) must correspond to the driver name
+ (used in the name parameter) and the driver must
+ identify itself with the very same name. The
+ <c>Path</c> might be provided as an <em>io_list</em>,
+ meaning it can be a list of other io_lists, characters
+ (eight bit integers) or binaries, all to be flattened
+ into a sequence of characters.</p>
+ <p>The (possibly flattened) <c>Path</c> parameter must be
+ consistent throughout the system, a driver should, by
+ all <seealso marker="#users">users</seealso>, be loaded
+ using the same <em>literal</em><c>Path</c>. The
+ exception is when <em>reloading</em> is requested, in
+ which case the <c>Path</c> may be specified
+ differently. Note that all <seealso marker="#users">users</seealso> trying to load the
+ driver at a later time will need to use the <em>new</em><c>Path</c> if the <c>Path</c> is changed using a
+ <c>reload</c> option. This is yet another reason
+ to have <em>only one loader</em> of a driver one wants to
+ upgrade in a running system! </p>
+ </item>
+ <tag><em>Name</em></tag>
+ <item>
+ <p>The name parameter is the name of the driver to be used
+ in subsequent calls to <seealso marker="erts:erlang#open_port/2">open_port</seealso>. The
+ name can be specified either as an <c>io_list()</c> or
+ as an <c>atom()</c>. The name given when loading is used
+ to find the actual object file (with the
+ help of the <c>Path</c> and the system implied
+ extension suffix, i.e. <c>.so</c>). The name by which
+ the driver identifies itself must also be consistent
+ with this <c>Name</c> parameter, much as a beam-file's
+ module name much correspond to it's filename.</p>
+ </item>
+ <tag><em>OptionList</em></tag>
+ <item>
+ <p>A number of options can be specified to control the
+ loading operation. The options are given as a list of
+ two-tuples, the tuples having the following values and
+ meanings:</p>
+ <taglist>
+ <tag><em>{driver_options, DriverOptionsList}</em></tag>
+ <item>
+ <p>This option is to provide options that will change
+ it's general behavior and will "stick" to the driver
+ throughout it's lifespan.</p>
+ <p>The driver options for a given driver name need
+ always to be consistent, <em>even when the driver is reloaded</em>, meaning that they are as much a part
+ of the driver as the actual name.</p>
+ <p>Currently the only allowed driver option is
+ <c>kill_ports</c>, which means that all ports opened
+ towards the driver are killed with the exit-reason
+ <c>driver_unloaded</c> when no process any longer
+ has the driver loaded. This situation arises either
+ when the last <seealso marker="#users">user</seealso> calls <seealso marker="#try_unload/2">try_unload/2</seealso>, or
+ the last process having loaded the driver exits.</p>
+ </item>
+ <tag><em>{monitor, MonitorOption}</em></tag>
+ <item>
+ <p>A <c>MonitorOption</c> tells <c>try_load/3</c> to
+ trigger a driver monitor under certain
+ conditions. When the monitor is triggered, the
+ function will return a three-tuple <c>{ok, PendingStatus, ref()}</c>, where the <c>ref()</c> is
+ the monitor ref for the driver monitor.</p>
+ <p>Only one <c>MonitorOption</c> can be specified and
+ it is either the atom <c>pending</c>, which means
+ that a monitor should be created whenever a load
+ operation is delayed, and the atom
+ <c>pending_driver</c>, in which a monitor is
+ created whenever the operation is delayed due to
+ open ports towards an otherwise unused driver. The
+ <c>pending_driver</c> option is of little use, but
+ is present for completeness, it is very well defined
+ which reload-options might give rise to which
+ delays. It might, however, be a good idea to use the
+ same <c>MonitorOption</c> as the <c>ReloadOption</c>
+ if present.</p>
+ <p>If reloading is not requested, it might still be
+ useful to specify the <c>monitor</c> option, as
+ forced unloads (<c>kill_ports</c> driver option or
+ the <c>kill_ports</c> option to <seealso marker="#try_unload/2">try_unload/2</seealso>) will
+ trigger a transient state where driver loading
+ cannot be performed until all closing ports are
+ actually closed. So, as <c>try_unload</c> can, in
+ almost all situations, return <c>{ok, pending_driver}</c>, one should always specify at least
+ <c>{monitor, pending_driver}</c> in production
+ code (see the monitor discussion above). </p>
+ </item>
+ <tag><em>{reload,RealoadOption}</em></tag>
+ <item>
+ <p>This option is used when one wants to
+ <em>reload</em> a driver from disk, most often in a
+ code upgrade scenario. Having a <c>reload</c> option
+ also implies that the <c>Path</c> parameter need
+ <em>not</em> be consistent with earlier loads of
+ the driver.</p>
+ <p>To reload a driver, the process needs to have previously
+ loaded the driver, i.e there has to be an active <seealso marker="#users">user</seealso> of the driver in the process. </p>
+ <p>The <c>reload</c> option can be either the atom
+ <c>pending</c>, in which reloading is requested for
+ any driver and will be effectuated when <em>all</em>
+ ports opened against the driver are closed. The
+ replacement of the driver will in this case take
+ place regardless of if there are still
+ pending <seealso marker="#users">users</seealso>
+ having the driver loaded!
+ The option also triggers port-killing (if the
+ <c>kill_ports</c> driver option is used) even though
+ there are pending users, making it usable for forced
+ driver replacement, but laying a lot of
+ responsibility on the driver <seealso marker="#users">users</seealso>. The pending option is
+ seldom used as one does not want other <seealso marker="#users">users</seealso> to have loaded the
+ driver when code change is underway. </p>
+ <p>The more useful option is <c>pending_driver</c>,
+ which means that reloading will be queued if the
+ driver is <em>not</em> loaded by any other <seealso marker="#users">users</seealso>, but the driver has
+ opened ports, in which case <c>{ok, pending_driver}</c> will be returned (a
+ <c>monitor</c> option is of course recommended).</p>
+ <p>If the driver is unloaded (not present in the
+ system), the error code
+ <c>not_loaded</c> will be returned. The
+ <c>reload</c> option is intended for when the user
+ has already loaded the driver in advance.</p>
+ </item>
+ </taglist>
+ </item>
+ </taglist>
+ <p>The function might return numerous errors, of which some
+ only can be returned given a certain combination of options.</p>
+ <p>A number of errors are opaque and can only be interpreted by
+ passing them to the <seealso marker="#format_error/1">format_error/1</seealso> function,
+ but some can be interpreted directly:</p>
+ <taglist>
+ <tag><em>{error,linked_in_driver}</em></tag>
+ <item>
+ <p>The driver with the specified name is an erlang
+ statically linked in driver, which cannot be manipulated
+ with this API.</p>
+ </item>
+ <tag><em>{error,inconsistent}</em></tag>
+ <item>
+ <p>The driver has already been loaded with either other
+ <c>DriverOptions</c> or a different <em>literal</em><c>Path</c> argument.</p>
+ <p>This can happen even if a <c>reload</c> option is given,
+ if the <c>DriverOptions</c> differ from the current.</p>
+ </item>
+ <tag><em>{error, permanent}</em></tag>
+ <item>
+ <p>The driver has requested itself to be permanent, making
+ it behave like an erlang linked in driver and it can no
+ longer be manipulated with this API.</p>
+ </item>
+ <tag><em>{error, pending_process}</em></tag>
+ <item>
+ <p>The driver is loaded by other <seealso marker="#users">users</seealso> when the <c>{reload, pending_driver}</c> option was given.</p>
+ </item>
+ <tag><em>{error, pending_reload}</em></tag>
+ <item>
+ <p>Driver reload is already requested by another <seealso marker="#users">user</seealso> when the <c>{reload, ReloadOption}</c> option was given.</p>
+ </item>
+ <tag><em>{error, not_loaded_by_this_process}</em></tag>
+ <item>
+ <p>Appears when the <c>reload</c> option is given. The
+ driver <c>Name</c> is present in the system, but there is no
+ <seealso marker="#users">user</seealso> of it in this
+ process.</p>
+ </item>
+ <tag><em>{error, not_loaded}</em></tag>
+ <item>
+ <p>Appears when the <c>reload</c> option is given. The
+ driver <c>Name</c> is not in the system. Only drivers
+ loaded by this process can be reloaded.</p>
+ </item>
+ </taglist>
+ <p>All other error codes are to be translated by the <seealso marker="#format_error/1">format_error/1</seealso>
+ function. Note that calls to <c>format_error</c> should be
+ performed from the same running instance of the erlang
+ virtual machine as the error was detected in, due to system
+ dependent behavior concerning error values.</p>
+ <p>If the arguments or options are malformed, the function will
+ throw a <c>badarg</c> exception.</p>
+ </desc>
+ </func>
+ <func>
+ <name>try_unload(Name, OptionList) -> {ok,Status} | {ok, PendingStatus, Ref} | {error, ErrorAtom}</name>
+ <fsummary>Unload a driver</fsummary>
+ <type>
+ <v>Name = string() | atom()</v>
+ <v>OptionList = [ Option ]</v>
+ <v>Option = {monitor, MonitorOption} | kill_ports</v>
+ <v>MonitorOption = pending_driver | pending</v>
+ <v>Status = unloaded | PendingStatus </v>
+ <v>PendingStatus = pending_driver | pending_process</v>
+ <v>Ref = ref()</v>
+ <v>ErrorAtom = linked_in_driver | not_loaded | not_loaded_by_this_process | permanent</v>
+ </type>
+ <desc>
+ <p>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
+ <c>kill_ports</c> implicitly does, and it can trigger a
+ monitor either due to other <seealso marker="#users">users</seealso> still having the driver
+ loaded or that there are open ports using the driver.</p>
+ <p>Unloading can be described as the process of telling the
+ emulator that this particular part of the code in this
+ particular process (i.e. this <seealso marker="#users">user</seealso>) no longer needs the
+ driver. That can, if there are no other users, trigger
+ actual 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 the <c>kill_ports</c> option set, or if
+ <c>kill_ports</c> was specified as an option to this
+ function, all pending ports using this driver will get
+ killed when unloading is done by the last <seealso marker="#users">user</seealso>. If no port-killing is
+ involved and there are open ports, the actual unloading
+ is delayed until there are no more open ports using the
+ driver. If, in this case, another <seealso marker="#users">user</seealso> (or even this user) loads the
+ driver again before the driver is actually unloaded, the
+ unloading will never take place.</p>
+ <p>To allow the <seealso marker="#users">user</seealso> that
+ <em>requests unloading</em> to wait for <em>actual unloading</em> to
+ take place, <c>monitor</c> triggers can be specified in much
+ the same way as when loading. As <seealso marker="#users">users</seealso> of this function however
+ seldom are interested in more than decrementing the
+ reference counts, monitoring is more seldom needed. If the
+ <c>kill_ports</c> option is used however, monitor trigging is
+ crucial, as the ports are not guaranteed to have been killed
+ until the driver is unloaded, why a monitor should be
+ triggered for at least the <c>pending_driver</c> case.</p>
+ <p>The possible monitor messages that can be expected are the
+ same as when using the <c>unloaded</c> option to the
+ <seealso marker="#monitor/2">monitor/2</seealso> function.</p>
+ <p>The function will return one of the following statuses upon
+ success:</p>
+ <taglist>
+ <tag><em>{ok, unloaded}</em></tag>
+ <item>
+ <p>The driver was immediately unloaded, meaning that the
+ driver name is now free to use by other drivers and, if
+ the underlying OS permits it, the memory occupied by the
+ driver object code is now reclaimed.</p>
+ <p>The driver can only be unloaded when there are no open
+ ports using it and there are no more <seealso marker="#users">users</seealso> requiring it to be
+ loaded.</p>
+ </item>
+ <tag><em>{ok, pending_driver}</em>or <em>{ok, pending_driver, ref()}</em></tag>
+ <item>
+ <p>This return value indicates that this call removed the
+ last <seealso marker="#users">user</seealso> from the
+ driver, but there are still open ports using it.
+ When all ports are closed and no new <seealso marker="#users">users</seealso> have arrived, the driver
+ will actually be reloaded and the name and memory
+ reclaimed.</p>
+ <p>This return value is valid even when the option
+ <c>kill_ports</c> was used, as killing ports may not be
+ a process that completes immediately. The condition is,
+ in that case, however transient. Monitors are as always
+ useful to detect when the driver is really unloaded.</p>
+ </item>
+ <tag><em>{ok, pending_process}</em>or <em>{ok, pending_process, ref()}</em></tag>
+ <item>
+ <p>The unload request is registered, but there are still
+ other <seealso marker="#users">users</seealso> holding
+ the driver. Note that the term <c>pending_process</c>
+ might refer to the running process, there might be more
+ than one <seealso marker="#users">user</seealso> in the
+ same process.</p>
+ <p>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 actually the most
+ common return value in the most common <seealso marker="#scenarios">scenario</seealso>
+ described in the introduction.</p>
+ </item>
+ </taglist>
+ <p>The function accepts the following parameters:</p>
+ <taglist>
+ <tag><em>Name</em></tag>
+ <item>
+ <p>The name parameter is the name of the driver to be
+ unloaded. The name can be specified either as an
+ <c>io_list()</c> or as an <c>atom()</c>. </p>
+ </item>
+ <tag><em>OptionList</em></tag>
+ <item>
+ <p>The <c>OptionList</c> argument can be used to specify
+ certain behavior regarding ports as well as triggering
+ monitors under certain conditions:</p>
+ <taglist>
+ <tag><em>kill_ports</em></tag>
+ <item>
+ <p>Force killing of all ports opened using this driver,
+ with the exit reason <c>driver_unloaded</c>, if you are
+ the <em>last</em><seealso marker="#users">user</seealso> of the driver.</p>
+ <p>If there are other <seealso marker="#users">users</seealso> having the driver
+ loaded, this option will have no effect.</p>
+ <p>If one wants the consistent behavior of killing ports
+ when the last <seealso marker="#users">user</seealso>
+ unloads, one should use the driver option
+ <c>kill_ports</c> when loading the driver instead.</p>
+ </item>
+ <tag><em>{monitor, MonitorOption}</em></tag>
+ <item>
+ <p>This option creates a driver monitor if the condition
+ given in <c>MonitorOptions</c> is true. The valid
+ options are:</p>
+ <taglist>
+ <tag><em>pending_driver</em></tag>
+ <item>
+ <p>Create a driver monitor if the return value is to
+ be <c>{ok, pending_driver}</c>.</p>
+ </item>
+ <tag><em>pending</em></tag>
+ <item>
+ <p>Create a monitor if the return value will be either
+ <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c>.</p>
+ </item>
+ </taglist>
+ <p>The <c>pending_driver</c><c>MonitorOption</c> is by far
+ the most useful and it has to be used to ensure that the
+ driver has really been unloaded and the ports closed
+ whenever the <c>kill_ports</c> option is used or the
+ driver may have been loaded with the <c>kill_ports</c>
+ driver option.</p>
+ <p>By using the monitor-triggers in the call to
+ <c>try_unload</c> one can be sure that the monitor is
+ actually added before the unloading is executed, meaning
+ that the monitor will always get properly triggered,
+ which would not be the case if one called
+ <c>erl_ddll:monitor/2</c> separately.</p>
+ </item>
+ </taglist>
+ </item>
+ </taglist>
+ <p>The function may return several error conditions, of which
+ all are well specified (no opaque values):</p>
+ <taglist>
+ <tag><em>{error, linked_in_driver}</em></tag>
+ <item>
+ <p>You were trying to unload an erlang statically linked in
+ driver, which cannot be manipulated with this interface
+ (and cannot be unloaded at all).</p>
+ </item>
+ <tag><em>{error, not_loaded}</em></tag>
+ <item>
+ <p>The driver <c>Name</c> is not present in the system.</p>
+ </item>
+ <tag><em>{error, not_loaded_by_this_process}</em></tag>
+ <item>
+ <p>The driver <c>Name</c> is present in the system, but
+ there is no <seealso marker="#users">user</seealso> of
+ it in this process. </p>
+ <p>As a special case, drivers can be unloaded from
+ processes that has done no corresponding call to
+ <c>try_load/3</c> if, and only if, there are <em>no users of the driver at all</em>, which may happen if the
+ process containing the last user dies.</p>
+ </item>
+ <tag><em>{error, permanent}</em></tag>
+ <item>
+ <p>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).</p>
+ </item>
+ </taglist>
+ <p>The function throws a <c>badarg</c> exception if the
+ parameters are not given as described above. </p>
+ </desc>
+ </func>
+ <func>
+ <name>unload(Name) -> ok | {error, ErrorDesc}</name>
+ <fsummary>Unload a driver</fsummary>
+ <type>
+ <v>Name = string() | atom()</v>
+ <v>ErrorDesc = term()</v>
+ </type>
+ <desc>
+ <p>Unloads, or at least dereferences the driver named
+ <c>Name</c>. If the caller is the last <seealso marker="#users">user</seealso> of the driver, and there
+ are no more open ports using the driver, the driver will
+ actually get unloaded. In all other cases, actual unloading
+ will be delayed until all ports are closed and there are no
+ remaining <seealso marker="#users">users</seealso>.</p>
+ <p>If there are other <seealso marker="#users">users</seealso> 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 usage
+ scenarios, see the <seealso marker="#scenarios">description</seealso> in the beginning
+ of this document. </p>
+ <p>The <c>ErrorDesc</c> returned is an opaque value to be
+ passed further on to the <seealso marker="#format_error/1">format_error/1</seealso>
+ function. For more control over the operation, use the
+ <seealso marker="#try_unload/2">try_unload/2</seealso>
+ interface.</p>
+ <p>The function throws a <c>badarg</c> exception if the
+ parameters are not given as described above. </p>
+ </desc>
+ </func>
+ <func>
+ <name>unload_driver(Name) -> ok | {error, ErrorDesc}</name>
+ <fsummary>Unload a driver</fsummary>
+ <type>
+ <v>Name = string() | atom()</v>
+ <v>ErrorDesc = term()</v>
+ </type>
+ <desc>
+ <p>Unloads, or at least dereferences the driver named
+ <c>Name</c>. If the caller is the last <seealso marker="#users">user</seealso> of the driver, all
+ remaining open ports using the driver will get killed with
+ the reason <c>driver_unloaded</c> and the driver will
+ eventually get unloaded.</p>
+ <p>If there are other <seealso marker="#users">users</seealso>
+ of the driver, the reference counts of the driver is merely
+ decreased, so that the caller is no longer considered a
+ <seealso marker="#users">user</seealso>. For
+ usage scenarios, see the <seealso marker="#scenarios">description</seealso> in the beginning
+ of this document.</p>
+ <p>The <c>ErrorDesc</c> returned is an opaque value to be
+ passed further on to the <seealso marker="#format_error/1">format_error/1</seealso>
+ function. For more control over the operation, use the
+ <seealso marker="#try_unload/2">try_unload/2</seealso>
+ interface.</p>
+ <p>The function throws a <c>badarg</c> exception if the
+ parameters are not given as described above. </p>
+ </desc>
+ </func>
+ <func>
+ <name>loaded_drivers() -> {ok, Drivers}</name>
+ <fsummary>List loaded drivers</fsummary>
+ <type>
+ <v>Drivers = [Driver()]</v>
+ <v>Driver = string()</v>
+ </type>
+ <desc>
+ <p>Returns a list of all the available drivers, both
+ (statically) linked-in and dynamically loaded ones.</p>
+ <p>The driver names are returned as a list of strings rather
+ than a list of atoms for historical reasons.</p>
+ <p>More information about drivers can be obtained using one of
+ the <seealso marker="#info/0">info</seealso> functions.</p>
+ </desc>
+ </func>
+ <func>
+ <name>format_error(ErrorDesc) -> string()</name>
+ <fsummary>Format an error descriptor</fsummary>
+ <type>
+ <v>ErrorDesc -- see below</v>
+ </type>
+ <desc>
+ <p>Takes an <c>ErrorDesc</c> returned by load, unload or
+ reload functions and returns a string which
+ describes the error or warning.</p>
+ <note>
+ <p>Due to peculiarities in the dynamic loading interfaces on
+ different platform, the returned string is only guaranteed
+ to describe the correct error <em>if format_error/1 is called in the same instance of the erlang virtual machine as the error appeared in</em> (meaning the same operating
+ system process)!</p>
+ </note>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>SEE ALSO</title>
+ <p>erl_driver(4), driver_entry(4)</p>
+ </section>
+</erlref>
+