diff options
Diffstat (limited to 'lib/kernel/doc/src/erl_ddll.xml')
-rw-r--r-- | lib/kernel/doc/src/erl_ddll.xml | 1165 |
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> + |