aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/tutorial
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/tutorial')
-rw-r--r--system/doc/tutorial/c_port.xmlsrc86
-rw-r--r--system/doc/tutorial/c_portdriver.xmlsrc112
-rw-r--r--system/doc/tutorial/cnode.xmlsrc162
-rw-r--r--system/doc/tutorial/erl_interface.xmlsrc108
-rw-r--r--system/doc/tutorial/example.xmlsrc21
-rw-r--r--system/doc/tutorial/introduction.xml26
-rw-r--r--system/doc/tutorial/nif.xmlsrc127
-rw-r--r--system/doc/tutorial/overview.xml235
8 files changed, 623 insertions, 254 deletions
diff --git a/system/doc/tutorial/c_port.xmlsrc b/system/doc/tutorial/c_port.xmlsrc
index 8579da8520..0631293237 100644
--- a/system/doc/tutorial/c_port.xmlsrc
+++ b/system/doc/tutorial/c_port.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>
@@ -28,16 +28,34 @@
<rev></rev>
<file>c_port.xml</file>
</header>
- <p>This is an example of how to solve the <seealso marker="example">example problem</seealso> by using a port.</p>
+ <p>This section outlines an example of how to solve the example
+ problem in the <seealso marker="example">previous section</seealso>
+ by using a port.</p>
+ <p>The scenario is illustrated in the following figure:</p>
<image file="../tutorial/port.gif">
- <icaption>Port Communication.</icaption>
+ <icaption>Port Communication</icaption>
</image>
<section>
<title>Erlang Program</title>
- <p>First of all communication between Erlang and C must be established by creating the port. The Erlang process which creates a port is said to be <em>the connected process</em> of the port. All communication to and from the port should go via the connected process. If the connected process terminates, so will the port (and the external program, if it is written correctly).</p>
- <p>The port is created using the BIF <c>open_port/2</c> with <c>{spawn,ExtPrg}</c> as the first argument. The string <c>ExtPrg</c> is the name of the external program, including any command line arguments. The second argument is a list of options, in this case only <c>{packet,2}</c>. This option says that a two byte length indicator will be used to simplify the communication between C and Erlang. Adding the length indicator will be done automatically by the Erlang port, but must be done explicitly in the external C program.</p>
- <p>The process is also set to trap exits which makes it possible to detect if the external program fails.</p>
+ <p>All communication between Erlang and C must be established by
+ creating the port. The Erlang process that creates a port is
+ said to be <em>the connected process</em> of the port. All
+ communication to and from the port must go through the connected
+ process. If the connected process terminates, the port also
+ terminates (and the external program, if it is written
+ properly).</p>
+ <p>The port is created using the BIF <c>open_port/2</c> with
+ <c>{spawn,ExtPrg}</c> as the first argument. The string
+ <c>ExtPrg</c> is the name of the external program, including any
+ command line arguments. The second argument is a list of
+ options, in this case only <c>{packet,2}</c>. This option says
+ that a 2 byte length indicator is to be used to simplify the
+ communication between C and Erlang. The Erlang port
+ automatically adds the length indicator, but this must be done
+ explicitly in the external C program.</p>
+ <p>The process is also set to trap exits, which enables detection
+ of failure of the external program:</p>
<pre>
-module(complex1).
-export([start/1, init/1]).
@@ -50,7 +68,9 @@ init(ExtPrg) ->
process_flag(trap_exit, true),
Port = open_port({spawn, ExtPrg}, [{packet, 2}]),
loop(Port).</pre>
- <p>Now it is possible to implement <c>complex1:foo/1</c> and <c>complex1:bar/1</c>. They both send a message to the <c>complex</c> process and receive the reply.</p>
+ <p>Now <c>complex1:foo/1</c> and <c>complex1:bar/1</c> can be
+ implemented. Both send a message to the <c>complex</c> process
+ and receive the following replies:</p>
<pre>
foo(X) ->
call_port({foo, X}).
@@ -63,7 +83,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 does 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
@@ -75,37 +102,52 @@ loop(Port) ->
end,
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 1, <c>bar</c> is represented by 2, and the argument/result is represented by a single byte as well.</p>
+ <p>Assuming that both the arguments and the results from the C
+ 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>
<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>The resulting Erlang program, including functionality for
+ stopping the port and detecting port failures, is as follows:
</p>
<codeinclude file="complex1.erl" type="erl"/>
</section>
<section>
<title>C Program</title>
- <p>On the C side, it is necessary to write functions for receiving and sending
- data with two byte length indicators from/to Erlang. By default, the C program
- should read from standard input (file descriptor 0) and write to standard output
- (file descriptor 1). Examples of such functions, <c>read_cmd/1</c> and
- <c>write_cmd/2</c>, are shown below.</p>
+ <p>On the C side, it is necessary to write functions for receiving
+ and sending data with 2 byte length indicators from/to Erlang.
+ By default, the C program is to read from standard input (file
+ descriptor 0) and write to standard output (file descriptor 1).
+ Examples of such functions, <c>read_cmd/1</c> and
+ <c>write_cmd/2</c>, follows:</p>
<codeinclude file="erl_comm.c" type="erl"/>
- <p>Note that <c>stdin</c> and <c>stdout</c> are for buffered input/output and should not be used for the communication with Erlang!</p>
- <p>In the <c>main</c> function, the C program should listen for a message from Erlang and, according to the selected encoding/decoding scheme, use the first byte to determine which function to call and the second byte as argument to the function. The result of calling the function should then be sent back to Erlang.</p>
+ <p>Notice that <c>stdin</c> and <c>stdout</c> are for buffered
+ input/output and must <em>not</em> be used for the communication
+ with Erlang.</p>
+ <p>In the <c>main</c> function, the C program is to listen for a
+ message from Erlang and, according to the selected
+ encoding/decoding scheme, use the first byte to determine which
+ function to call and the second byte as argument to the
+ function. The result of calling the function is then to be sent
+ back to Erlang:</p>
<codeinclude file="port.c" tag="" type="none"></codeinclude>
- <p>Note that the C program is in a <c>while</c>-loop checking for the return value of <c>read_cmd/1</c>. The reason for this is that the C program must detect when the port gets closed and terminate.</p>
+ <p>Notice that the C program is in a <c>while</c>-loop, checking
+ for the return value of <c>read_cmd/1</c>. This is because the C
+ program must detect when the port closes and terminates.</p>
</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 extprg complex.c erl_comm.c port.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>
unix> <input>erl</input>
Erlang (BEAM) emulator version 4.9.1.2
@@ -113,7 +155,7 @@ Erlang (BEAM) emulator version 4.9.1.2
Eshell V4.9.1.2 (abort with ^G)
1> <input>c(complex1).</input>
{ok,complex1}</pre>
- <p>3. Run the example.</p>
+ <p><em>Step 3.</em> Run the example:</p>
<pre>
2> <input>complex1:start("extprg").</input>
&lt;0.34.0>
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>
diff --git a/system/doc/tutorial/cnode.xmlsrc b/system/doc/tutorial/cnode.xmlsrc
index 293406160f..bcdd1298de 100644
--- a/system/doc/tutorial/cnode.xmlsrc
+++ b/system/doc/tutorial/cnode.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>
@@ -28,19 +28,39 @@
<rev></rev>
<file>cnode.xml</file>
</header>
- <p>This is an example of how to solve the <seealso marker="example">example problem</seealso> by using a C node. Note that a C node would not typically be used for solving a simple problem like this, a port would suffice.</p>
+ <p>This section outlines an example of how to solve the example
+ problem in <seealso marker="example">Problem Example</seealso>
+ by using a C node. Notice that a C node is not typically
+ used for solving simple problems like this, a port is
+ sufficient.</p>
<section>
<title>Erlang Program</title>
- <p>From Erlang's point of view, the C node is treated like a normal Erlang node. Therefore, calling the functions <c>foo</c> and <c>bar</c> only involves sending a message to the C node asking for the function to be called, and receiving the result. Sending a message requires a recipient; a process which can be defined using either a pid or a tuple consisting of a registered name and a node name. In this case a tuple is the only alternative as no pid is known.</p>
+ <p>From Erlang's point of view, the C node is treated like a
+ normal Erlang node. Thus, calling the functions <c>foo</c> and
+ <c>bar</c> only involves sending a message to the C node asking
+ for the function to be called, and receiving the result. Sending
+ a message requires a recipient, that is, a process that can be
+ defined using either a pid or a tuple, consisting of a
+ registered name and a node name. In this case, a tuple is the
+ only alternative as no pid is known:</p>
<pre>
{RegName, Node} ! Msg</pre>
- <p>The node name <c>Node</c> should be the name of the C node. If short node names are used, the plain name of the node will be <c>cN</c> where <c>N</c> is an integer. If long node names are used, there is no such restriction. An example of a C node name using short node names is thus <c>c1@idril</c>, an example using long node names is <c>[email protected]</c>.</p>
- <p>The registered name <c>RegName</c> could be any atom. The name can be ignored by the C code, or it could be used for example to distinguish between different types of messages. Below is an example of what the Erlang code could look like when using short node names.
+ <p>The node name <c>Node</c> is to be the name of the C node. If
+ short node names are used, the plain name of the node is
+ <c>cN</c>, where <c>N</c> is an integer. If long node names are
+ used, there is no such restriction. An example of a C node name
+ using short node names is thus <c>c1@idril</c>, an example using
+ long node names is <c>[email protected]</c>.</p>
+ <p>The registered name, <c>RegName</c>, can be any atom. The name
+ can be ignored by the C code, or, for example, be used to
+ distinguish between different types of messages. An example of
+ Erlang code using short node names follows:
</p>
<codeinclude file="complex3.erl" tag="" type="erl"></codeinclude>
<p>
- When using long node names the code is slightly different as shown in the following example:
+ When using long node names, the code is slightly different as
+ shown in the following example:
</p>
<codeinclude file="complex4.erl" tag="" type="erl"></codeinclude>
@@ -50,39 +70,77 @@
<title>C Program</title>
<section>
- <title>Setting Up the Communication</title>
- <p>Before calling any other Erl_Interface function, the memory handling must be initiated.</p>
+ <title>Setting Up Communication</title>
+ <p>Before calling any other function in Erl_Interface, the
+ memory handling must be initiated:</p>
<pre>
erl_init(NULL, 0);</pre>
- <p>Now the C node can be initiated. If short node names are used, this is done by calling <c>erl_connect_init()</c>.</p>
+ <p>Now the C node can be initiated. If short node names are
+ used, this is done by calling <c>erl_connect_init()</c>:</p>
<pre>
erl_connect_init(1, "secretcookie", 0);</pre>
- <p>The first argument is the integer which is used to construct the node name. In the example the plain node name will be <c>c1</c>. <br></br>
-
- The second argument is a string defining the magic cookie. <br></br>
-
- The third argument is an integer which is used to identify a particular instance of a C node.</p>
- <p>If long node node names are used, initiation is done by calling <c>erl_connect_xinit()</c>.</p>
+ <p>Here:</p>
+ <list type="bulleted">
+ <item>The first argument is the integer used to construct the node name.
+ <p>In the example, the plain node name is <c>c1</c>.</p></item>
+ <item>The second argument is a string defining the magic cookie.</item>
+ <item>The third argument is an integer that is used to identify
+ a particular instance of a C node.</item>
+ </list>
+ <p>If long node node names are used, initiation is done by
+ calling <c>erl_connect_xinit()</c>:</p>
<pre>
erl_connect_xinit("idril", "cnode", "[email protected]",
&amp;addr, "secretcookie", 0);</pre>
- <p>The first three arguments are the host name, the plain node name, and the full node name. The fourth argument is a pointer to an <c>in_addr</c> struct with the IP address of the host, and the fifth and sixth arguments are the magic cookie and instance number.</p>
- <p>The C node can act as a server or a client when setting up the communication Erlang-C. If it acts as a client, it connects to an Erlang node by calling <c>erl_connect()</c>, which will return an open file descriptor at success.</p>
+ <p>Here:</p>
+ <list type="bulleted">
+ <item>The first argument is the host name.</item>
+ <item>The second argument is the plain node name.</item>
+ <item>The third argument is the full node name.</item>
+ <item>The fourth argument is a pointer to an <c>in_addr</c>
+ struct with the IP address of the host.</item>
+ <item>The fifth argument is the magic cookie.</item>
+ <item>The sixth argument is the instance number.</item>
+ </list>
+ <p>The C node can act as a server or a client when setting up
+ the Erlang-C communication. If it acts as a client, it
+ connects to an Erlang node by calling <c>erl_connect()</c>,
+ which returns an open file descriptor at success:</p>
<pre>
fd = erl_connect("e1@idril");</pre>
- <p>If the C node acts as a server, it must first create a socket (call <c>bind()</c> and <c>listen()</c>) listening to a certain port number <c>port</c>. It then publishes its name and port number with <c>epmd</c> (the Erlang port mapper daemon, see the man page for <c>epmd</c>).</p>
+ <p>If the C node acts as a server, it must first create a socket
+ (call <c>bind()</c> and <c>listen()</c>) listening to a
+ certain port number <c>port</c>. It then publishes its name
+ and port number with <c>epmd</c>, the Erlang port mapper
+ daemon. For details, see the <seealso
+ marker="erts:epmd">epmd</seealso> manual page in ERTS:</p>
<pre>
erl_publish(port);</pre>
- <p>Now the C node server can accept connections from Erlang nodes.</p>
+ <p>Now the C node server can accept connections from Erlang nodes:</p>
<pre>
fd = erl_accept(listen, &amp;conn);</pre>
- <p>The second argument to <c>erl_accept</c> is a struct <c>ErlConnect</c> that will contain useful information when a connection has been established; for example, the name of the Erlang node.</p>
+ <p>The second argument to <c>erl_accept</c> is a struct
+ <c>ErlConnect</c> which contains useful information when a
+ connection has been established, for example, the name of the
+ Erlang node.</p>
</section>
<section>
<title>Sending and Receiving Messages</title>
- <p>The C node can receive a message from Erlang by calling <c>erl_receive msg()</c>. This function reads data from the open file descriptor <c>fd</c> into a buffer and puts the result in an <c>ErlMessage</c> struct <c>emsg</c>. <c>ErlMessage</c> has a field <c>type</c> defining which kind of data was received. In this case the type of interest is <c>ERL_REG_SEND</c> which indicates that Erlang sent a message to a registered process at the C node. The actual message, an <c>ETERM</c>, will be in the <c>msg</c> field.</p>
- <p>It is also necessary to take care of the types <c>ERL_ERROR</c> (an error occurred) and <c>ERL_TICK</c> (alive check from other node, should be ignored). Other possible types indicate process events such as link/unlink and exit.</p>
+ <p>The C node can receive a message from Erlang by calling
+ <c>erl_receive msg()</c>. This function reads data from the
+ open file descriptor <c>fd</c> into a buffer and puts the
+ result in an <c>ErlMessage</c> struct <c>emsg</c>.
+ <c>ErlMessage</c> has a field <c>type</c> defining what kind
+ of data is received. In this case, the type of interest is
+ <c>ERL_REG_SEND</c> which indicates that Erlang sent a message
+ to a registered process at the C node. The actual message, an
+ <c>ETERM</c>, is in the <c>msg</c> field.</p>
+ <p>It is also necessary to take care of the types
+ <c>ERL_ERROR</c> (an error occurred) and <c>ERL_TICK</c>
+ (alive check from other node, is to be ignored). Other
+ possible types indicate process events such as link, unlink,
+ and exit:</p>
<pre>
while (loop) {
@@ -93,7 +151,16 @@ fd = erl_accept(listen, &amp;conn);</pre>
loop = 0; /* exit while loop */
} else {
if (emsg.type == ERL_REG_SEND) {</pre>
- <p>Since the message is an <c>ETERM</c> struct, Erl_Interface functions can be used to manipulate it. In this case, the message will be a 3-tuple (because that was how the Erlang code was written, see above). The second element will be the pid of the caller and the third element will be the tuple <c>{Function,Arg}</c> determining which function to call with which argument. The result of calling the function is made into an <c>ETERM</c> struct as well and sent back to Erlang using <c>erl_send()</c>, which takes the open file descriptor, a pid and a term as arguments.</p>
+ <p>As the message is an <c>ETERM</c> struct, Erl_Interface
+ functions can be used to manipulate it. In this case, the
+ message becomes a 3-tuple, because that is how the Erlang code
+ is written. The second element will be the pid of the caller
+ and the third element will be the tuple <c>{Function,Arg}</c>
+ determining which function to call, and with which argument.
+ The result of calling the function is made into an
+ <c>ETERM</c> struct as well and sent back to Erlang using
+ <c>erl_send()</c>, which takes the open file descriptor, a
+ pid, and a term as arguments:</p>
<pre>
fromp = erl_element(2, emsg.msg);
tuplep = erl_element(3, emsg.msg);
@@ -108,29 +175,30 @@ fd = erl_accept(listen, &amp;conn);</pre>
resp = erl_format("{cnode, ~i}", res);
erl_send(fd, fromp, resp);</pre>
- <p>Finally, the memory allocated by the <c>ETERM</c> creating functions (including <c>erl_receive_msg()</c> must be freed.</p>
+ <p>Finally, the memory allocated by the <c>ETERM</c> creating
+ functions (including <c>erl_receive_msg()</c> must be
+ freed:</p>
<pre>
erl_free_term(emsg.from); erl_free_term(emsg.msg);
erl_free_term(fromp); erl_free_term(tuplep);
erl_free_term(fnp); erl_free_term(argp);
erl_free_term(resp);</pre>
- <p>The resulting C programs can be found in looks like the following examples. First a C node server using short node names.</p>
+ <p>The following examples show the resulting C programs.
+ First a C node server using short node names:</p>
<codeinclude file="cnode_s.c" type="c"/>
- <p>Below follows a C node server using long node names.</p>
+ <p>A C node server using long node names:</p>
<codeinclude file="cnode_s2.c" type="c"/>
- <p>And finally we have the code for the C node client.</p>
+ <p>Finally, the code for the C node client:</p>
<codeinclude file="cnode_c.c" type="c"/>
</section>
</section>
<section>
<title>Running the Example</title>
- <p>1. Compile the C code, providing the paths to the Erl_Interface include files and libraries, and to the <c>socket</c> and <c>nsl</c> libraries.</p>
- <p>In R5B and later versions of OTP, the <c>include</c> and <c>lib</c> directories are situated under <c>OTPROOT/lib/erl_interface-VSN</c>, where <c>OTPROOT</c> is the root directory of the OTP installation (<c>/usr/local/otp</c> in the example above) and <c>VSN</c> is the version of the <c>erl_interface</c> application (3.2.1 in the example above). <br></br>
-
- In R4B and earlier versions of OTP, <c>include</c> and <c>lib</c> are situated under <c>OTPROOT/usr</c>.</p>
+ <p><em>Step 1.</em> Compile the C code. This provides the paths to
+ the Erl_Interface include files and libraries, and to the
+ <c>socket</c> and <c>nsl</c> libraries:</p>
<pre>
-
> <input>gcc -o cserver \\ </input>
<input>-I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </input>
<input>-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input>
@@ -148,11 +216,29 @@ unix> <input>gcc -o cclient \\ </input>
<input>-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input>
<input>complex.c cnode_c.c \\ </input>
<input>-lerl_interface -lei -lsocket -lnsl</input></pre>
- <p>2. Compile the Erlang code.</p>
+ <p>In Erlang/OTP R5B and later versions of OTP, the
+ <c>include</c> and <c>lib</c> directories are situated under
+ <c>OTPROOT/lib/erl_interface-VSN</c>, where <c>OTPROOT</c> is
+ the root directory of the OTP installation
+ (<c>/usr/local/otp</c> in the recent example) and <c>VSN</c> is
+ the version of the Erl_Interface application (3.2.1 in the
+ recent example).</p>
+ <p>In R4B and earlier versions of OTP, <c>include</c> and
+ <c>lib</c> are situated under <c>OTPROOT/usr</c>.</p>
+ <p><em>Step 2.</em> Compile the Erlang code:</p>
<pre>
unix> <input>erl -compile complex3 complex4</input></pre>
- <p>3. Run the C node server example with short node names.</p>
- <p>Start the C program <c>cserver</c> and Erlang in different windows. <c>cserver</c> takes a port number as argument and must be started before trying to call the Erlang functions. The Erlang node should be given the short name <c>e1</c> and must be set to use the same magic cookie as the C node, <c>secretcookie</c>.</p>
+ <p><em>Step 3.</em> Run the C node server example with short node names.</p>
+ <p>Do as follows:</p>
+ <list type="bulleted">
+ <item>Start the C program <c>cserver</c> and Erlang in
+ different windows.</item>
+ <item><c>cserver</c> takes a port number as argument and must
+ be started before trying to call the Erlang functions.</item>
+ <item>The Erlang node is to be given the short name <c>e1</c>
+ and must be set to use the same magic cookie as the C node,
+ <c>secretcookie</c>:</item>
+ </list>
<pre>
unix> <input>cserver 3456</input>
@@ -164,7 +250,9 @@ Eshell V4.9.1.2 (abort with ^G)
4
(e1@idril)2> <input>complex3:bar(5).</input>
10</pre>
- <p>4. Run the C node client example. Terminate <c>cserver</c> but not Erlang and start <c>cclient</c>. The Erlang node must be started before the C node client is.</p>
+ <p><em>Step 4.</em> Run the C node client example. Terminate
+ <c>cserver</c>, but not Erlang, and start <c>cclient</c>. The
+ Erlang node must be started before the C node client:</p>
<pre>
unix> <input>cclient</input>
@@ -172,7 +260,7 @@ unix> <input>cclient</input>
4
(e1@idril)4> <input>complex3:bar(5).</input>
10</pre>
- <p>5. Run the C node server, long node names, example.</p>
+ <p><em>Step 5.</em> Run the C node server example with long node names:</p>
<pre>
unix> <input>cserver2 3456</input>
diff --git a/system/doc/tutorial/erl_interface.xmlsrc b/system/doc/tutorial/erl_interface.xmlsrc
index 0c4c5a99c2..5751a945d6 100644
--- a/system/doc/tutorial/erl_interface.xmlsrc
+++ b/system/doc/tutorial/erl_interface.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>
@@ -28,14 +28,29 @@
<rev></rev>
<file>erl_interface.xml</file>
</header>
- <p>This is an example of how to solve the <seealso marker="example">example problem</seealso> by using a port and <c>erl_interface</c>. It is necessary to read the <seealso marker="c_port">port example</seealso> before reading this chapter.</p>
+
+ <p>This section outlines an example of how to solve the example
+ problem in <seealso marker="example">Problem Example</seealso> by
+ using a port and Erl_Interface. It is necessary to read the port
+ example in <seealso marker="c_port">Ports</seealso> before reading
+ this section.</p>
<section>
<title>Erlang Program</title>
- <p>The example below shows an Erlang program communicating with a C program over a plain port with home made encoding.</p>
- <codeinclude file="complex1.erl" type="erl"/>
- <p>Compared to the Erlang module
- above used for the plain port, there are two differences when using Erl_Interface on the C side: Since Erl_Interface operates on the Erlang external term format the port must be set to use binaries and, instead of inventing an encoding/decoding scheme, the BIFs <c>term_to_binary/1</c> and <c>binary_to_term/1</c> should be used. That is:</p>
+ <p>The following example shows an Erlang program communicating
+ with a C program over a plain port with home made encoding:</p>
+ <codeinclude file="complex1.erl" type="erl"/>
+ <p>There are two differences when using Erl_Interface on the C
+ side compared to the example in <seealso marker="c_port">
+ Ports</seealso>, using only the plain port:</p>
+ <list type="bulleted">
+ <item>As Erl_Interface operates on the Erlang external term format,
+ the port must be set to use binaries.</item>
+ <item>Instead of inventing an encoding/decoding scheme, the
+ <c>term_to_binary/1</c> and <c>binary_to_term/1</c> BIFs are to
+ be used.</item>
+ </list>
+ <p>That is:</p>
<pre>
open_port({spawn, ExtPrg}, [{packet, 2}])</pre>
<p>is replaced with:</p>
@@ -55,69 +70,110 @@ receive
{Port, {data, Data}} ->
Caller ! {complex, binary_to_term(Data)}
end</pre>
- <p>The resulting Erlang program is shown below.</p>
+ <p>The resulting Erlang program is as follows:</p>
<codeinclude file="complex2.erl" type="erl"/>
- <p>Note that calling <c>complex2:foo/1</c> and <c>complex2:bar/1</c> will result in the tuple <c>{foo,X}</c> or <c>{bar,Y}</c> being sent to the <c>complex</c> process, which will code them as binaries and send them to the port. This means that the C program must be able to handle these two tuples.</p>
+ <p>Notice that calling <c>complex2:foo/1</c> and
+ <c>complex2:bar/1</c> results in the tuple <c>{foo,X}</c> or
+ <c>{bar,Y}</c> being sent to the <c>complex</c> process, which
+ codes them as binaries and sends them to the port. This means
+ that the C program must be able to handle these two tuples.</p>
</section>
<section>
<title>C Program</title>
- <p>The example below shows a C program communicating with an Erlang program over a plain port with home made encoding.</p>
+ <p>The following example shows a C program communicating with an
+ Erlang program over a plain port with home made encoding:</p>
<codeinclude file="port.c" type="c"/>
- <p>Compared to the C program above
- used for the plain port the <c>while</c>-loop must be rewritten. Messages coming from the port will be on the Erlang external term format. They should be converted into an <c>ETERM</c> struct, a C struct similar to an Erlang term. The result of calling <c>foo()</c> or <c>bar()</c> must be converted to the Erlang external term format before being sent back to the port. But before calling any other <c>erl_interface</c> function, the memory handling must be initiated.</p>
+ <p>Compared to the C program in <seealso marker="c_port">
+ Ports</seealso>, using only the plain port, the
+ <c>while</c>-loop must be rewritten. Messages coming from the
+ port is on the Erlang external term format. They must be
+ converted into an <c>ETERM</c> struct, which is a C struct
+ similar to an Erlang term. The result of calling <c>foo()</c> or
+ <c>bar()</c> must be converted to the Erlang external term
+ format before being sent back to the port. But before calling
+ any other Erl_Interface function, the memory handling must be
+ initiated:</p>
<pre>
erl_init(NULL, 0);</pre>
- <p>For reading from and writing to the port the functions <c>read_cmd()</c> and <c>write_cmd()</c> from the erl_comm.c example below
- can still be used.
+ <p>The following functions, <c>read_cmd()</c> and
+ <c>write_cmd()</c>, from the <c>erl_comm.c</c> example in
+ <seealso marker="c_port">Ports</seealso> can still be
+ used for reading from and writing to the port:
</p>
<codeinclude file="erl_comm.c" type="c"/>
- <p>The function <c>erl_decode()</c> from <c>erl_marshal</c> will convert the binary into an <c>ETERM</c> struct.</p>
+ <p>The function <c>erl_decode()</c> from <c>erl_marshal</c>
+ converts the binary into an <c>ETERM</c> struct:</p>
<pre>
int main() {
ETERM *tuplep;
while (read_cmd(buf) > 0) {
tuplep = erl_decode(buf);</pre>
- <p>In this case <c>tuplep</c> now points to an <c>ETERM</c> struct representing a tuple with two elements; the function name (atom) and the argument (integer). By using the function <c>erl_element()</c> from <c>erl_eterm</c> it is possible to extract these elements, which also must be declared as pointers to an <c>ETERM</c> struct.</p>
+ <p>Here, <c>tuplep</c> points to an <c>ETERM</c> struct
+ representing a tuple with two elements; the function name (atom)
+ and the argument (integer). Using the function
+ <c>erl_element()</c> from <c>erl_eterm</c>, these elements can
+ be extracted, but they must also be declared as pointers to an
+ <c>ETERM</c> struct:</p>
<pre>
fnp = erl_element(1, tuplep);
argp = erl_element(2, tuplep);</pre>
- <p>The macros <c>ERL_ATOM_PTR</c> and <c>ERL_INT_VALUE</c> from <c>erl_eterm</c> can be used to obtain the actual values of the atom and the integer. The atom value is represented as a string. By comparing this value with the strings "foo" and "bar" it can be decided which function to call.</p>
+ <p>The macros <c>ERL_ATOM_PTR</c> and <c>ERL_INT_VALUE</c> from
+ <c>erl_eterm</c> can be used to obtain the actual values of the
+ atom and the integer. The atom value is represented as a string.
+ By comparing this value with the strings "foo" and "bar", it can
+ be decided which function to call:</p>
<pre>
if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) {
res = foo(ERL_INT_VALUE(argp));
} else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) {
res = bar(ERL_INT_VALUE(argp));
}</pre>
- <p>Now an <c>ETERM</c> struct representing the integer result can be constructed using the function <c>erl_mk_int()</c> from <c>erl_eterm</c>. It is also possible to use the function <c>erl_format()</c> from the module <c>erl_format</c>.</p>
+ <p>Now an <c>ETERM</c> struct that represents the integer result
+ can be constructed using the function <c>erl_mk_int()</c> from
+ <c>erl_eterm</c>. The function
+ <c>erl_format()</c> from the module <c>erl_format</c> can also
+ be used:</p>
<pre>
intp = erl_mk_int(res);</pre>
- <p>The resulting <c>ETERM</c> struct is converted into the Erlang external term format using the function <c>erl_encode()</c> from <c>erl_marshal</c> and sent to Erlang using <c>write_cmd()</c>.</p>
+ <p>The resulting <c>ETERM</c> struct is converted into the Erlang
+ external term format using the function <c>erl_encode()</c> from
+ <c>erl_marshal</c> and sent to Erlang using
+ <c>write_cmd()</c>:</p>
<pre>
erl_encode(intp, buf);
write_cmd(buf, erl_eterm_len(intp));</pre>
- <p>Last, the memory allocated by the <c>ETERM</c> creating functions must be freed.</p>
+ <p>Finally, the memory allocated by the <c>ETERM</c> creating
+ functions must be freed:</p>
<pre>
erl_free_compound(tuplep);
erl_free_term(fnp);
erl_free_term(argp);
erl_free_term(intp);</pre>
- <p>The resulting C program is shown below:</p>
+ <p>The resulting C program is as follows:</p>
<codeinclude file="ei.c" type="c"/>
</section>
<section>
<title>Running the Example</title>
- <p>1. Compile the C code, providing the paths to the include files <c>erl_interface.h</c> and <c>ei.h</c>, and to the libraries <c>erl_interface</c> and <c>ei</c>.</p>
+ <p><em>Step 1.</em> Compile the C code. This provides the paths to
+ the include files <c>erl_interface.h</c> and <c>ei.h</c>, and
+ also to the libraries <c>erl_interface</c> and <c>ei</c>:</p>
<pre>
unix> <input>gcc -o extprg -I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </input>
<input> -L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input>
<input> complex.c erl_comm.c ei.c -lerl_interface -lei</input></pre>
- <p>In R5B and later versions of OTP, the <c>include</c> and <c>lib</c> directories are situated under <c>OTPROOT/lib/erl_interface-VSN</c>, where <c>OTPROOT</c> is the root directory of the OTP installation (<c>/usr/local/otp</c> in the example above) and <c>VSN</c> is the version of the <c>erl_interface</c> application (3.2.1 in the example above). <br></br>
-
- In R4B and earlier versions of OTP, <c>include</c> and <c>lib</c> are situated under <c>OTPROOT/usr</c>.</p>
- <p>2. Start Erlang and compile the Erlang code.</p>
+ <p>In Erlang/OTP R5B and later versions of OTP, the <c>include</c>
+ and <c>lib</c> directories are situated under
+ <c>OTPROOT/lib/erl_interface-VSN</c>, where <c>OTPROOT</c> is
+ the root directory of the OTP installation
+ (<c>/usr/local/otp</c> in the recent example) and <c>VSN</c> is
+ the version of the Erl_interface application (3.2.1 in the
+ recent example).</p>
+ <p>In R4B and earlier versions of OTP, <c>include</c> and <c>lib</c>
+ are situated under <c>OTPROOT/usr</c>.</p>
+ <p><em>Step 2.</em> Start Erlang and compile the Erlang code:</p>
<pre>
unix> <input>erl</input>
Erlang (BEAM) emulator version 4.9.1.2
@@ -125,7 +181,7 @@ Erlang (BEAM) emulator version 4.9.1.2
Eshell V4.9.1.2 (abort with ^G)
1> <input>c(complex2).</input>
{ok,complex2}</pre>
- <p>3. Run the example.</p>
+ <p><em>Step 3.</em> Run the example:</p>
<pre>
2> <input>complex2:start("extprg").</input>
&lt;0.34.0>
diff --git a/system/doc/tutorial/example.xmlsrc b/system/doc/tutorial/example.xmlsrc
index f87eb217e9..e205ca189e 100644
--- a/system/doc/tutorial/example.xmlsrc
+++ b/system/doc/tutorial/example.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>
@@ -31,16 +31,25 @@
<section>
<title>Description</title>
- <p>A common interoperability situation is when there exists a piece of code solving some complex problem, and we would like to incorporate this piece of code in our Erlang program. Suppose for example we have the following C functions that we would like to be able to call from Erlang.</p>
- <codeinclude file="complex.c" tag="" type="none"></codeinclude>
- <p>(For the sake of keeping the example as simple as possible, the functions are not very complicated in this case).</p>
- <p>Preferably we would like to able to call <c>foo</c> and <c>bar</c> without having to bother about them actually being C functions.</p>
+ <p>A common interoperability situation is when you want to incorporate
+ a piece of code, solving a complex problem, in your Erlang
+ program. Suppose for example, that you have the following C
+ functions that you would like to call from Erlang:</p>
+ <codeinclude file="complex.c" tag="" type="none"></codeinclude>
+ <p>The functions are deliberately kept as simple as possible, for
+ readability reasons.</p>
+ <p>From an Erlang perspektive, it is preferable to be able to call
+ <c>foo</c> and <c>bar</c> without having to bother about that
+ they are C functions:</p>
<pre>
% Erlang code
...
Res = complex:foo(X),
...</pre>
- <p>The communication with C is hidden in the implementation of <c>complex.erl</c>. In the following chapters it is shown how this module can be implemented using the different interoperability mechanisms.</p>
+ <p>Here, the communication with C is hidden in the implementation
+ of <c>complex.erl</c>.
+ In the following sections, it is shown how this module can be
+ implemented using the different interoperability mechanisms.</p>
</section>
</chapter>
diff --git a/system/doc/tutorial/introduction.xml b/system/doc/tutorial/introduction.xml
index ed86a00f76..dcf462e311 100644
--- a/system/doc/tutorial/introduction.xml
+++ b/system/doc/tutorial/introduction.xml
@@ -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>
@@ -28,18 +28,34 @@
<rev></rev>
<file>introduction.xml</file>
</header>
+ <marker id="interoperability tutorial"></marker>
+ <p>This section informs on interoperability, that is, information
+ exchange, between Erlang and other programming languages. The
+ included examples mainly treat interoperability between Erlang and
+ C.</p>
<section>
<title>Purpose</title>
- <p>The purpose of this tutorial is to give the reader an orientation of the different interoperability mechanisms that can be used when integrating a program written in Erlang with a program written in another programming language, from the Erlang programmer's point of view.</p>
+ <p>The purpose of this tutorial is to describe different
+ interoperability mechanisms that can be used when integrating a
+ program written in Erlang with a program written in another
+ programming language, from the Erlang programmer's
+ perspective.</p>
</section>
<section>
<title>Prerequisites</title>
- <p>It is assumed that the reader is a skilled Erlang programmer, familiar with concepts such as Erlang data types, processes, messages and error handling.</p>
- <p>To illustrate the interoperability principles C programs running in a UNIX environment have been used. It is assumed that the reader has enough knowledge to be able to apply these principles to the relevant programming languages and platforms.</p>
+ <p>It is assumed that you are a skilled Erlang programmer,
+ familiar with concepts such as Erlang data types, processes,
+ messages, and error handling.</p>
+ <p>To illustrate the interoperability principles, C programs
+ running in a UNIX environment have been used. It is assumed that
+ you have enough knowledge to apply these principles to the
+ relevant programming languages and platforms.</p>
<note>
- <p>For the sake of readability, the example code has been kept as simple as possible. It does not include functionality such as error handling, which might be vital in a real-life system.</p>
+ <p>For readability, the example code is kept as simple as
+ possible. For example, it does not include error handling,
+ which might be vital in a real-life system.</p>
</note>
</section>
</chapter>
diff --git a/system/doc/tutorial/nif.xmlsrc b/system/doc/tutorial/nif.xmlsrc
index 8ddad60f74..c79370e8c8 100644
--- a/system/doc/tutorial/nif.xmlsrc
+++ b/system/doc/tutorial/nif.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>
@@ -28,92 +28,105 @@
<rev></rev>
<file>nif.xml</file>
</header>
- <p>This is an example of how to solve the <seealso marker="example">example problem</seealso>
- by using NIFs. NIFs were introduced in R13B03 as an experimental
- feature. It is a simpler and more efficient way of calling C-code
- than using port drivers. NIFs are most suitable for synchronous functions like
- <c>foo</c> and <c>bar</c> in the example, that does some
- relatively short calculations without side effects and return the result.</p>
- <section>
- <title>NIFs</title>
- <p>A NIF (Native Implemented Function) is a function that is
- implemented in C instead of Erlang. NIFs appear as any other functions to
- the callers. They belong to a module and are called like any other Erlang
- functions. The NIFs of a module are compiled and linked into a dynamic
- loadable shared library (SO in Unix, DLL in Windows). The NIF library must
- be loaded in runtime by the Erlang code of the module.</p>
- <p>Since a NIF library is dynamically linked into the emulator
- process, this is the fastest way of calling C-code from Erlang (alongside
- port drivers). Calling NIFs requires no context switches. But it is also
- the least safe, because a crash in a NIF will bring the emulator down
- too.</p>
- </section>
+ <p>This section outlines an example of how to solve the example
+ problem in <seealso marker="example">Problem Example</seealso>
+ by using Native Implemented Functions (NIFs).</p>
+ <p>NIFs were introduced in Erlang/OTP R13B03 as an experimental
+ feature. It is a simpler and more efficient way of calling C-code
+ than using port drivers. NIFs are most suitable for synchronous
+ functions, such as <c>foo</c> and <c>bar</c> in the example, that
+ do some relatively short calculations without side effects and
+ return the result.</p>
+ <p>A NIF is a function that is implemented in C instead of Erlang.
+ NIFs appear as any other functions to the callers. They belong to
+ a module and are called like any other Erlang functions. The NIFs
+ of a module are compiled and linked into a dynamic loadable,
+ shared library (SO in UNIX, DLL in Windows). The NIF library must
+ be loaded in runtime by the Erlang code of the module.</p>
+ <p>As a NIF library is dynamically linked into the emulator process,
+ this is the fastest way of calling C-code from Erlang (alongside
+ port drivers). Calling NIFs requires no context switches. But it
+ is also the least safe, because a crash in a NIF brings the
+ emulator down too.</p>
<section>
<title>Erlang Program</title>
- <p>Even if all functions of a module will be NIFs, you still need an Erlang
- module for two reasons. First, the NIF library must be explicitly loaded
- by Erlang code in the same module. Second, all NIFs of a module must have
- an Erlang implementation as well. Normally these are minimal stub
- implementations that throw an exception. But it can also be used as
- fallback implementations for functions that do not have native
- implemenations on some architectures.</p>
- <p>NIF libraries are loaded by calling <c>erlang:load_nif/2</c>, with the
- name of the shared library as argument. The second argument can be any
- term that will be passed on to the library and used for
- initialization.</p>
+ <p>Even if all functions of a module are NIFs, an Erlang
+ module is still needed for two reasons:</p>
+ <list type="bulleted">
+ <item>The NIF library must be explicitly loaded by
+ Erlang code in the same module.</item>
+ <item>All NIFs of a module must have an Erlang implementation
+ as well.</item>
+ </list>
+ <p>Normally these are minimal stub implementations that throw an
+ exception. But they can also be used as fallback implementations
+ for functions that do not have native implemenations on some
+ architectures.</p>
+ <p>NIF libraries are loaded by calling <c>erlang:load_nif/2</c>,
+ with the name of the shared library as argument. The second
+ argument can be any term that will be passed on to the library
+ and used for initialization:</p>
<codeinclude file="complex6.erl" tag="" type="none"></codeinclude>
- <p>We use the directive <c>on_load</c> to get function <c>init</c> to be
- automatically called when the module is loaded. If <c>init</c>
- returns anything other than <c>ok</c>, such when the loading of
- the NIF library fails in this example, the module will be
- unloaded and calls to functions within it will fail.</p>
- <p>Loading the NIF library will override the stub implementations
+ <p>Here, the directive <c>on_load</c> is used to get function
+ <c>init</c> to be automatically called when the module is
+ loaded. If <c>init</c> returns anything other than <c>ok</c>,
+ such when the loading of the NIF library fails in this example,
+ the module is unloaded and calls to functions within it,
+ fail.</p>
+ <p>Loading the NIF library overrides the stub implementations
and cause calls to <c>foo</c> and <c>bar</c> to be dispatched to
the NIF implementations instead.</p>
</section>
<section>
- <title>NIF library code</title>
+ <title>NIF Library Code</title>
<p>The NIFs of the module are compiled and linked into a
shared library. Each NIF is implemented as a normal C function. The macro
<c>ERL_NIF_INIT</c> together with an array of structures defines the names,
- arity and function pointers of all the NIFs in the module. The header
- file <c>erl_nif.h</c> must be included. Since the library is a shared
- module, not a program, no main function should be present.</p>
+ arity, and function pointers of all the NIFs in the module. The header
+ file <c>erl_nif.h</c> must be included. As the library is a shared
+ module, not a program, no main function is to be present.</p>
<p>The function arguments passed to a NIF appears in an array <c>argv</c>,
- with <c>argc</c> as the length of the array and thus the arity of the
+ with <c>argc</c> as the length of the array, and thus the arity of the
function. The Nth argument of the function can be accessed as
<c>argv[N-1]</c>. NIFs also take an environment argument that
serves as an opaque handle that is needed to be passed on to
most API functions. The environment contains information about
- the calling Erlang process.</p>
+ the calling Erlang process:</p>
<codeinclude file="complex6_nif.c" tag="" type="none"></codeinclude>
- <p>The first argument to <c>ERL_NIF_INIT</c> must be the name of the
+ <p>Here,<c>ERL_NIF_INIT</c> has the following arguments:</p>
+ <list type="bulleted">
+ <item><p>The first argument must be the name of the
Erlang module as a C-identifier. It will be stringified by the
- macro. The second argument is the array of <c>ErlNifFunc</c>
- structures containing name, arity and function pointer of
- each NIF. The other arguments are pointers to callback functions
- that can be used to initialize the library. We do not use them
- in this simple example so we set them all to <c>NULL</c>.</p>
+ macro.</p>
+ </item>
+ <item>The second argument is the array of <c>ErlNifFunc</c>
+ structures containing name, arity, and function pointer of
+ each NIF.</item>
+ <item>The remaining arguments are pointers to callback functions
+ that can be used to initialize the library. They are not used
+ in this simple example, hence they are all set to <c>NULL</c>.</item>
+ </list>
<p>Function arguments and return values are represented as values
- of type <c>ERL_NIF_TERM</c>. We use functions like <c>enif_get_int</c>
- and <c>enif_make_int</c> to convert between Erlang term and C-type.
- If the function argument <c>argv[0]</c> is not an integer then
- <c>enif_get_int</c> will return false, in which case we return
+ of type <c>ERL_NIF_TERM</c>. Here, functions like <c>enif_get_int</c>
+ and <c>enif_make_int</c> are used to convert between Erlang term
+ and C-type.
+ If the function argument <c>argv[0]</c> is not an integer,
+ <c>enif_get_int</c> returns false, in which case it returns
by throwing a <c>badarg</c>-exception with <c>enif_make_badarg</c>.</p>
</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 complex6_nif.so -fpic -shared complex.c complex6_nif.c</input>
windows> <input>cl -LD -MD -Fe complex6_nif.dll complex.c complex6_nif.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 R13B04 (erts-5.7.5) [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false]
@@ -121,7 +134,7 @@ Erlang R13B04 (erts-5.7.5) [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-p
Eshell V5.7.5 (abort with ^G)
1> <input>c(complex6).</input>
{ok,complex6}</pre>
- <p>3. Run the example.</p>
+ <p><em>Step 3:</em> Run the example:</p>
<pre>
3> <input>complex6:foo(3).</input>
4
diff --git a/system/doc/tutorial/overview.xml b/system/doc/tutorial/overview.xml
index 1fe1aad22b..3814a135b4 100644
--- a/system/doc/tutorial/overview.xml
+++ b/system/doc/tutorial/overview.xml
@@ -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>
@@ -31,35 +31,90 @@
<section>
<title>Built-In Mechanisms</title>
- <p>There are two interoperability mechanisms built into the Erlang runtime system. One is <em>distributed Erlang</em> and the other one is <em>ports</em>. A variation of ports is <em>linked-in drivers</em>.</p>
+ <p>Two interoperability mechanisms are built into the Erlang
+ runtime system, <em>distributed Erlang</em> and <em>ports</em>.
+ A variation of ports is <em>linked-in drivers</em>.</p>
<marker id="dist"></marker>
<section>
<title>Distributed Erlang</title>
- <p>An Erlang runtime system is made into a distributed Erlang node by giving it a name. A distributed Erlang node can connect to and monitor other nodes, it is also possible to spawn processes at other nodes. Message passing and error handling between processes at different nodes are transparent. There exists a number of useful <c>stdlib</c> modules intended for use in a distributed Erlang system; for example, <c>global</c> which provides global name registration. The distribution mechanism is implemented using TCP/IP sockets.</p>
- <p><em>When to use:</em> Distributed Erlang is primarily used for communication Erlang-Erlang. It can also be used for communication between Erlang and C, if the C program is implemented as a <seealso marker="#cnode">C node</seealso>, see below.</p>
- <p><em>Where to read more:</em> Distributed Erlang and some distributed programming techniques are described in the Erlang book. <br></br>
-
- In the Erlang/OTP documentation there is a chapter about distributed Erlang in "Getting Started" (User's Guide). <br></br>
-
- Relevant man pages are <c>erlang</c> (describes the BIFs) and <c>global</c>, <c>net_adm</c>, <c>pg2</c>, <c>rpc</c>, <c>pool</c> and <c>slave</c>.</p>
+ <p>An Erlang runtime system is made a distributed Erlang node by
+ giving it a name. A distributed Erlang node can connect to,
+ and monitor, other nodes. It can also spawn processes at other
+ nodes. Message passing and error handling between processes at
+ different nodes are transparent. A number of useful STDLIB
+ modules are available in a distributed Erlang system. For
+ example, <c>global</c>, which provides global name
+ registration. The distribution mechanism is implemented using
+ TCP/IP sockets.</p>
+ <p><em>When to use:</em> Distributed Erlang is primarily used
+ for Erlang-Erlang communication. It can also be used for
+ communication between Erlang and C, if the C program is
+ implemented as a C node, see
+ <seealso marker="#cnode">C and Java Libraries</seealso>.</p>
+ <p><em>Where to read more:</em> Distributed Erlang and some distributed
+ programming techniques are described in the Erlang book.</p>
+ <p>For more information, see <seealso
+ marker="doc/getting_started:conc_prog#Distributed Programming">
+ Distributed Programming.</seealso></p>
+ <p>Relevant manual pages are the following:</p>
+ <list type="bulleted">
+ <item><seealso marker="erts:erlang">erlang</seealso> manual page in ERTS
+ (describes the BIFs)</item>
+ <item><seealso marker="kernel:global">global</seealso> manual page in Kernel</item>
+ <item><seealso marker="kernel:net_adm">net_adm</seealso> manual page in Kernel</item>
+ <item><seealso marker="kernel:pg2">pg2</seealso> manual page in Kernel</item>
+ <item><seealso marker="kernel:rpc">rpc</seealso> manual page in Kernel</item>
+ <item><seealso marker="stdlib:pool">pool</seealso> manual page in STDLIB</item>
+ <item><seealso marker="stdlib:slave">slave</seealso> manual page in STDLIB</item>
+ </list>
</section>
<section>
<title>Ports and Linked-In Drivers</title>
- <p>Ports provide the basic mechanism for communication with the external world, from Erlang's point of view. They provide a byte-oriented interface to an external program. When a port has been created, Erlang can communicate with it by sending and receiving lists of bytes (not Erlang terms). This means that the programmer may have to invent a suitable encoding and decoding scheme.</p>
- <p>The actual implementation of the port mechanism depends on the platform. In the Unix case, pipes are used and the external program should as default read from standard input and write to standard output. Theoretically, the external program could be written in any programming language as long as it can handle the interprocess communication mechanism with which the port is implemented.</p>
- <p>The external program resides in another OS process than the Erlang runtime system. In some cases this is not acceptable, consider for example drivers with very hard time requirements. It is therefore possible to write a program in C according to certain principles and dynamically link it to the Erlang runtime system, this is called a linked-in driver.</p>
- <p><em>When to use:</em> Being the basic mechanism, ports can be used for all kinds of interoperability situations where the Erlang program and the other program runs on the same machine. Programming is fairly straight-forward. <br></br>
-
- Linked-in drivers involves writing certain call-back functions in C. Very good skills are required as the code is linked to the Erlang runtime system.</p>
+ <p>Ports provide the basic mechanism for communication with the
+ external world, from Erlang's point of view. The ports provide
+ a byte-oriented interface to an external program. When a port
+ is created, Erlang can communicate with it by sending and
+ receiving lists of bytes (not Erlang terms). This means that
+ the programmer might have to invent a suitable encoding and
+ decoding scheme.</p>
+ <p>The implementation of the port mechanism depends on the
+ platform. For UNIX, pipes are used and the external program is
+ assumed to read from standard input and write to standard
+ output. The external program can be written in any programming
+ language as long as it can handle the interprocess
+ communication mechanism with which the port is
+ implemented.</p>
+ <p>The external program resides in another OS process than the
+ Erlang runtime system. In some cases this is not acceptable.
+ Consider, for example, drivers with very hard time
+ requirements. It is therefore possible to write a program in C
+ according to certain principles, and dynamically link it to
+ the Erlang runtime system. This is called a <em>linked-in
+ driver</em>.</p>
+ <p><em>When to use:</em> Ports can be used for all kinds of
+ interoperability situations where the Erlang program and the
+ other program runs on the same machine. Programming is fairly
+ straight-forward.</p>
+ <p>Linked-in drivers involves writing certain call-back
+ functions in C. This requires very good skills as the code is
+ linked to the Erlang runtime system.</p>
<warning>
- <p>An erroneous linked-in driver will cause the entire Erlang runtime system to leak memory, hang or crash.</p>
+ <p>A faulty linked-in driver causes the entire Erlang runtime
+ system to leak memory, hang, or crash.</p>
</warning>
- <p><em>Where to read more:</em> Ports are described in the "Miscellaneous Items" chapter of the Erlang book. Linked-in drivers are described in Appendix E. <br></br>
-
- The BIF <c>open_port/2</c> is documented in the man page for <c>erlang</c>. For linked-in drivers, the programmer needs to read the information in the man page for <c>erl_ddll</c>.</p>
- <p><em>Examples:</em><seealso marker="c_port">Port example</seealso>.</p>
+ <p><em>Where to read more:</em> Ports are described in section
+ "Miscellaneous Items" of the Erlang book. Linked-in drivers
+ are described in Appendix E.</p>
+ <p>The BIF <c>open_port/2</c> is documented in the
+ <seealso marker="erts:erlang">erlang</seealso> manual page in
+ ERTS.</p>
+ <p>For linked-in drivers, the programmer needs to read the
+ <seealso marker="kernel:erl_ddll">erl_ddll</seealso> manual
+ page in Kernel.</p>
+ <p><em>Examples:</em> Port example in <seealso marker="c_port">
+ Ports</seealso>.</p>
</section>
</section>
@@ -68,64 +123,152 @@
<section>
<title>Erl_Interface</title>
- <p>Very often the program at the other side of a port is a C program. To help the C programmer a library called Erl_Interface has been developed. It consists of five parts:</p>
+ <p>The program at the other side of a port is often a C program.
+ To help the C programmer, the Erl_Interface library
+ has been developed, including the following five parts:</p>
<list type="bulleted">
- <item><c>erl_marshal</c>, <c>erl_eterm</c>, <c>erl_format</c>, <c>erl_malloc</c> Handling of the Erlang external term format.</item>
- <item><c>erl_connect</c> Communication with distributed Erlang, see <seealso marker="#cnode">C nodes</seealso> below.</item>
- <item><c>erl_error</c> Error print routines.</item>
- <item><c>erl_global</c> Access globally registered names.</item>
- <item><c>Registry</c> Store and backup of key-value pairs.</item>
+ <item>
+ <c>erl_marshal</c>, <c>erl_eterm</c>, <c>erl_format</c>, and
+ <c>erl_malloc</c>: Handling of the Erlang external term format</item>
+ <item>
+ <c>erl_connect</c>:
+ Communication with distributed Erlang, see <seealso
+ marker="#cnode">C nodes</seealso> below</item>
+ <item>
+ <c>erl_error</c>:
+ Error print routines</item>
+ <item>
+ <c>erl_global</c>:
+ Access globally registered names</item>
+ <item>
+ <c>Registry</c>:
+ Store and backup of key-value pairs</item>
</list>
- <p>The Erlang external term format is a representation of an Erlang term as a sequence of bytes, a binary. Conversion between the two representations is done using BIFs.</p>
+ <p>The Erlang external term format is a representation of an
+ Erlang term as a sequence of bytes, that is, a binary.
+ Conversion between the two representations is done using the
+ following BIFs:</p>
<pre>
Binary = term_to_binary(Term)
Term = binary_to_term(Binary)</pre>
- <p>A port can be set to use binaries instead of lists of bytes. It is then not necessary to invent any encoding/decoding scheme. Erl_Interface functions are used for unpacking the binary and convert it into a struct similar to an Erlang term. Such a struct can be manipulated in different ways and be converted to the Erlang external format and sent to Erlang.</p>
+ <p>A port can be set to use binaries instead of lists of bytes.
+ It is then not necessary to invent any encoding/decoding
+ scheme. Erl_Interface functions are used for unpacking the
+ binary and convert it into a struct similar to an Erlang term.
+ Such a struct can be manipulated in different ways, be
+ converted to the Erlang external format, and sent to
+ Erlang.</p>
<p><em>When to use:</em> In C code, in conjunction with Erlang binaries.</p>
- <p><em>Where to read more:</em> Read about the Erl_Interface User's Guide; Command Reference and Library Reference. In R5B and earlier versions the information can be found under the Kernel application.</p>
- </section>
- <p><em>Examples:</em><seealso marker="erl_interface">erl_interface example</seealso>.</p>
+ <p><em>Where to read more:</em> See the Erlang Interface User's
+ Guide, Command Reference, and Library Reference. In Erlang/OTP
+ R5B, and earlier versions, the information is part of the
+ Kernel application.</p> </section>
+ <p><em>Examples:</em> Erl_Interface example in
+ <seealso marker="erl_interface">Erl_Interface</seealso>.</p>
<marker id="cnode"></marker>
<section>
<title>C Nodes</title>
- <p>A C program which uses the Erl_Interface functions for setting up a connection to and communicating with a distributed Erlang node is called a <em>C node</em>, or a <em>hidden node</em>. The main advantage with a C node is that the communication from the Erlang programmer's point of view is extremely easy, since the C program behaves as a distributed Erlang node.</p>
- <p><em>When to use:</em> C nodes can typically be used on device processors (as opposed to control processors) where C is a better choice than Erlang due to memory limitations and/or application characteristics.</p>
- <p><em>Where to read more:</em> In the <c>erl_connect</c> part of the Erl_Interface documentation, see above. The programmer also needs to be familiar with TCP/IP sockets, see <seealso marker="#sockets">below</seealso>, and distributed Erlang, see <seealso marker="#dist">above</seealso>.</p>
- <p><em>Examples:</em><seealso marker="cnode">C node example</seealso>.</p>
+ <p>A C program that uses the Erl_Interface functions for setting
+ up a connection to, and communicating with, a distributed
+ Erlang node is called a <em>C node</em>, or a <em>hidden
+ node</em>. The main advantage with a C node is that the
+ communication from the Erlang programmer's perspective is
+ extremely easy, as the C program behaves as a distributed
+ Erlang node.</p>
+ <p><em>When to use:</em> C nodes can typically be used on device
+ processors (as opposed to control processors) where C is a
+ better choice than Erlang due to memory limitations or
+ application characteristics, or both.</p>
+ <p><em>Where to read more:</em> See the <c>erl_connect</c> part
+ of the Erl_Interface documentation. The programmer also needs
+ to be familiar with TCP/IP sockets, see Sockets in <seealso
+ marker="#sockets">Standard
+ Protocols</seealso> and Distributed Erlang in <seealso
+ marker="#dist">Built-In Mechanisms</seealso>.</p>
+ <p><em>Example:</em> C node example in <seealso marker="cnode">
+ C Nodes</seealso>.</p>
</section>
<section>
<title>Jinterface</title>
- <p>In Erlang/OTP R6B, a library similar to Erl_Interface for Java was added called <em>jinterface</em>.</p>
+ <p>In Erlang/OTP R6B, a library similar to Erl_Interface for
+ Java was added called <em>jinterface</em>. It provides a tool
+ for Java programs to communicate with Erlang nodes.</p>
</section>
</section>
<section>
<title>Standard Protocols</title>
- <p>Sometimes communication between an Erlang program and another program using a standard protocol is desirable. Erlang/OTP currently supports TCP/IP and UDP <em>sockets</em>, SNMP, HTTP and IIOP (CORBA). Using one of the latter three requires good knowledge about the protocol and is not covered by this tutorial. Please refer to the documentation for the SNMP, Inets and Orber applications, respectively.</p>
+ <p>Sometimes communication between an Erlang program and another
+ program using a standard protocol is desirable. Erlang/OTP
+ currently supports TCP/IP and UDP <em>sockets</em>: as
+ follows:</p>
+ <list type="bulleted">
+ <item>SNMP</item>
+ <item>HTTP</item>
+ <item>IIOP (CORBA)</item>
+ </list>
+ <p>Using one of the latter three requires good knowledge about the
+ protocol and is not covered by this tutorial. See the SNMP,
+ Inets, and Orber applications, respectively.</p>
<marker id="sockets"></marker>
<section>
<title>Sockets</title>
- <p>Simply put, connection-oriented socket communication (TCP/IP) consists of an initiator socket ("server") started at a certain host with a certain port number. A connector socket ("client") aware of the initiator's host name and port number can connect to it and data can be sent between them. Connection-less socket communication (UDP) consists of an initiator socket at a certain host with a certain port number and a connector socket sending data to it. For a detailed description of the socket concept, please refer to a suitable book about network programming. A suggestion is <em>UNIX Network Programming, Volume 1: Networking APIs - Sockets and XTI</em> by W. Richard Stevens, ISBN: 013490012X.</p>
- <p>In Erlang/OTP, access to TCP/IP and UDP sockets is provided by the
- Kernel modules <c>gen_tcp</c> and <c>gen_udp</c>. Both are easy to
- use and do not require any deeper knowledge about the socket concept.</p>
- <p><em>When to use:</em> For programs running on the same or on another machine than the Erlang program.</p>
- <p><em>Where to read more:</em> The man pages for <c>gen_tcp</c> and <c>gen_udp</c>.</p>
+ <p>Simply put, connection-oriented socket communication (TCP/IP)
+ consists of an initiator socket ("server") started at a
+ certain host with a certain port number. A connector socket
+ ("client"), which is aware of the initiator host name and port
+ number, can connect to it and data can be sent between
+ them.</p>
+ <p>Connection-less socket communication (UDP) consists of an
+ initiator socket at a certain host with a certain port number
+ and a connector socket sending data to it.</p>
+ <p>For a detailed description of the socket concept, refer to a
+ suitable book about network programming. A suggestion is
+ <em>UNIX Network Programming, Volume 1: Networking APIs -
+ Sockets and XTI</em> by W. Richard Stevens, ISBN:
+ 013490012X.</p>
+ <p>In Erlang/OTP, access to TCP/IP and UDP sockets is provided
+ by the modules <c>gen_tcp</c> and <c>gen_udp</c> in
+ Kernel. Both are easy to use and do not require
+ detailed knowledge about the socket concept.</p>
+ <p><em>When to use:</em> For programs running on the same or on
+ another machine than the Erlang program.</p>
+ <p><em>Where to read more:</em> See the <seealso
+ marker="kernel:gen_tcp">gen_tcp</seealso> and the <seealso
+ marker="kernel:gen_udp">gen_udp</seealso> manual pages in
+ Kernel.</p>
</section>
</section>
<section>
<title>IC</title>
- <p>IC (IDL Compiler) is an interface generator which given an IDL interface specification automatically generates stub code in Erlang, C or Java. Please refer to the IC User's Guide and IC Reference Manual.</p>
+ <p>IC (Erlang IDL Compiler) is an interface generator that, given
+ an IDL interface specification, automatically generates stub
+ code in Erlang, C, or Java. See the IC User's Guide and IC
+ Reference Manual.</p>
+ <p>For details, see the <seealso marker="ic:ic">ic</seealso>
+ manual page in IC.</p>
</section>
<section>
<title>Old Applications</title>
- <p>There are two old applications of interest when talking about interoperability: <em>IG</em> which was removed in Erlang/OTP R6B and <em>Jive</em> which was removed in Erlang/OTP R7B. Both applications have been replaced by IC and are mentioned here for reference only.</p>
- <p>IG (Interface Generator) automatically generated code for port or socket communication between an Erlang program and a C program, given a C header file with certain keywords. Jive provided a simple interface between an Erlang program and a Java program.</p>
+ <p>Two old applications are of interest regarding
+ interoperability. Both have been replaced by IC and are
+ mentioned here for reference only:</p>
+ <list type="bulleted">
+ <item><p>IG - Removed from Erlang/OTP R6B.</p>
+ <p>IG (Interface Generator) automatically generated code for
+ port or socket communication between an Erlang program and a
+ C program, given a C header file with certain keywords.</p>
+ </item>
+ <item><p>Jive - Removed from Erlang/OTP R7B.</p>
+ <p>Jive provided a simple interface between an Erlang program
+ and a Java program.</p>
+ </item>
+ </list>
</section>
</chapter>