aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/tutorial/c_portdriver.xmlsrc
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/tutorial/c_portdriver.xmlsrc')
-rw-r--r--system/doc/tutorial/c_portdriver.xmlsrc112
1 files changed, 57 insertions, 55 deletions
diff --git a/system/doc/tutorial/c_portdriver.xmlsrc b/system/doc/tutorial/c_portdriver.xmlsrc
index 2fd6fb0aac..61187703a4 100644
--- a/system/doc/tutorial/c_portdriver.xmlsrc
+++ b/system/doc/tutorial/c_portdriver.xmlsrc
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2000</year><year>2013</year>
+ <year>2000</year><year>2015</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -21,46 +21,45 @@
</legalnotice>
- <title>Port drivers</title>
+ <title>Port Drivers</title>
<prepared></prepared>
<docno></docno>
<date></date>
<rev></rev>
<file>c_portdriver.xml</file>
</header>
- <p>This is an example of how to solve the <seealso marker="example">example problem</seealso> by using a linked in port driver.</p>
+ <p>This section outlines an example of how to solve the example problem
+ in <seealso marker="example">Problem Example</seealso>
+ by using a linked-in port driver.</p>
+ <p>A port driver is a linked-in driver that is accessible as a port
+ from an Erlang program. It is a shared library (SO in UNIX, DLL in
+ Windows), with special entry points. The Erlang runtime system
+ calls these entry points when the driver is started and when data
+ is sent to the port. The port driver can also send data to
+ Erlang.</p>
+ <p>As a port driver is dynamically linked into the emulator process,
+ this is the fastest way of calling C-code from Erlang. Calling
+ functions in the port driver requires no context switches. But it
+ is also the least safe way, because a crash in the port driver
+ brings the emulator down too.</p>
+ <p>The scenario is illustrated in the following figure:</p>
<image file="../tutorial/port_driver.gif">
- <icaption>Port Driver Communication.</icaption>
+ <icaption>Port Driver Communication</icaption>
</image>
<section>
- <title>Port Drivers</title>
- <p>A port driver is a linked in driver that is accessible as a
- port from an Erlang program. It is a shared library (SO in Unix,
- DLL in Windows), with special entry points. The Erlang runtime
- calls these entry points, when the driver is started and when
- data is sent to the port. The port driver can also send data to
- Erlang.</p>
- <p>Since a port driver is dynamically linked into the emulator
- process, this is the fastest way of calling C-code from Erlang.
- Calling functions in the port driver requires no context
- switches. But it is also the least safe, because a crash in the
- port driver brings the emulator down too.</p>
- </section>
-
- <section>
<title>Erlang Program</title>
- <p>Just as with a port program, the port communicates with a Erlang
+ <p>Like a port program, the port communicates with an Erlang
process. All communication goes through one Erlang process that
is the <em>connected process</em> of the port
driver. Terminating this process closes the port driver.</p>
<p>Before the port is created, the driver must be loaded. This is
done with the function <c>erl_dll:load_driver/1</c>, with the
name of the shared library as argument.</p>
- <p>The port is then created using the BIF <c>open_port/2</c> with
+ <p>The port is then created using the BIF <c>open_port/2</c>, with
the tuple <c>{spawn, DriverName}</c> as the first argument. The
string <c>SharedLib</c> is the name of the port driver. The second
- argument is a list of options, none in this case.</p>
+ argument is a list of options, none in this case:</p>
<pre>
-module(complex5).
-export([start/1, init/1]).
@@ -77,9 +76,9 @@ init(SharedLib) ->
register(complex, self()),
Port = open_port({spawn, SharedLib}, []),
loop(Port).</pre>
- <p>Now it is possible to implement <c>complex5:foo/1</c> and
- <c>complex5:bar/1</c>. They both send a message to the
- <c>complex</c> process and receive the reply.</p>
+ <p>Now <c>complex5:foo/1</c> and <c>complex5:bar/1</c>
+ can be implemented. Both send a message to the
+ <c>complex</c> process and receive the following reply:</p>
<pre>
foo(X) ->
call_port({foo, X}).
@@ -92,10 +91,14 @@ call_port(Msg) ->
{complex, Result} ->
Result
end.</pre>
- <p>The <c>complex</c> process encodes the message into a sequence
- of bytes, sends it to the port, waits for a reply, decodes the
- reply and sends it back to the caller.
- </p>
+ <p>The <c>complex</c> process performs the following:</p>
+ <list type="bulleted">
+ <item>Encodes the message into a sequence of bytes.</item>
+ <item>Sends it to the port.</item>
+ <item>Waits for a reply.</item>
+ <item>Decodes the reply.</item>
+ <item>Sends it back to the caller:</item>
+ </list>
<pre>
loop(Port) ->
receive
@@ -108,59 +111,58 @@ loop(Port) ->
loop(Port)
end.</pre>
<p>Assuming that both the arguments and the results from the C
- functions will be less than 256, a very simple encoding/decoding
- scheme is employed where <c>foo</c> is represented by the byte
+ functions are less than 256, a simple encoding/decoding scheme
+ is employed. In this scheme, <c>foo</c> is represented by byte
1, <c>bar</c> is represented by 2, and the argument/result is
- represented by a single byte as well.
- </p>
+ represented by a single byte as well:</p>
<pre>
encode({foo, X}) -> [1, X];
encode({bar, Y}) -> [2, Y].
-
+
decode([Int]) -> Int.</pre>
- <p>The resulting Erlang program, including functionality for
- stopping the port and detecting port failures is shown below.</p>
+ <p>The resulting Erlang program, including functions for stopping
+ the port and detecting port failures, is as follows:</p>
<codeinclude file="complex5.erl" type="erl"/>
</section>
<section>
<title>C Driver</title>
<p>The C driver is a module that is compiled and linked into a
- shared library. It uses a driver structure, and includes the
+ shared library. It uses a driver structure and includes the
header file <c>erl_driver.h</c>.</p>
<p>The driver structure is filled with the driver name and function
pointers. It is returned from the special entry point, declared
with the macro <c><![CDATA[DRIVER_INIT(<driver_name>)]]></c>.</p>
- <p>The functions for receiving and sending data, are combined into
+ <p>The functions for receiving and sending data are combined into
a function, pointed out by the driver structure. The data sent
- into the port is given as arguments, and the data the port
- sends back is sent with the C-function <c>driver_output</c>.</p>
- <p>Since the driver is a shared module, not a program, no main
- function should be present. All function pointers are not used
- in our example, and the corresponding fields in the
+ into the port is given as arguments, and the replied data is sent
+ with the C-function <c>driver_output</c>.</p>
+ <p>As the driver is a shared module, not a program, no main
+ function is present. All function pointers are not used
+ in this example, and the corresponding fields in the
<c>driver_entry</c> structure are set to NULL.</p>
- <p>All functions in the driver, takes a handle (returned from
- <c>start</c>), that is just passed along by the erlang
+ <p>All functions in the driver takes a handle (returned from
+ <c>start</c>) that is just passed along by the Erlang
process. This must in some way refer to the port driver
instance.</p>
- <p>The example_drv_start, is the only function that is called with
- a handle to the port instance, so we must save this. It is
- customary to use a allocated driver-defined structure for this
- one, and pass a pointer back as a reference.</p>
- <p>It is not a good idea to use a global variable; since the port
- driver can be spawned by multiple Erlang processes, this
- driver-structure should be instantiated multiple times.
+ <p>The <c>example_drv_start</c>, is the only function that is called with
+ a handle to the port instance, so this must be saved. It is
+ customary to use an allocated driver-defined structure for this
+ one, and to pass a pointer back as a reference.</p>
+ <p>It is not a good idea to use a global variable as the port
+ driver can be spawned by multiple Erlang processes. This
+ driver-structure is to be instantiated multiple times:
</p>
<codeinclude file="port_driver.c" tag="" type="none"></codeinclude>
</section>
<section>
<title>Running the Example</title>
- <p>1. Compile the C code.</p>
+ <p><em>Step 1.</em> Compile the C code:</p>
<pre>
unix> <input>gcc -o exampledrv -fpic -shared complex.c port_driver.c</input>
windows> <input>cl -LD -MD -Fe exampledrv.dll complex.c port_driver.c</input></pre>
- <p>2. Start Erlang and compile the Erlang code.</p>
+ <p><em>Step 2.</em> Start Erlang and compile the Erlang code:</p>
<pre>
> <input>erl</input>
Erlang (BEAM) emulator version 5.1
@@ -168,7 +170,7 @@ Erlang (BEAM) emulator version 5.1
Eshell V5.1 (abort with ^G)
1> <input>c(complex5).</input>
{ok,complex5}</pre>
- <p>3. Run the example.</p>
+ <p><em>Step 3.</em> Run the example:</p>
<pre>
2> <input>complex5:start("example_drv").</input>
&lt;0.34.0>