From 2d3ab68c60e8bacf9e0efe403895e7065ef683be Mon Sep 17 00:00:00 2001
From: Hans Bolinder This is an example of how to solve the This section outlines an example of how to solve the example
+ problem in the The scenario is illustrated in the following figure: 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 the connected process 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). The port is created using the BIF The process is also set to trap exits which makes it possible to detect if the external program fails. All communication between Erlang and C must be established by
+ creating the port. The Erlang process that creates a port is
+ said to be the connected process 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). The port is created using the BIF The process is also set to trap exits, which enables detection
+ of failure of the external program: Now it is possible to implement Now The The 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 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, The resulting Erlang program, including functionality for stopping the port and detecting port failures is shown below.
+ The resulting Erlang program, including functionality for
+ stopping the port and detecting port failures, is as follows:
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, 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, Note that In the Notice that In the Note that the C program is in a Notice that the C program is in a 1. Compile the C code. Step 1. Compile the C code: 2. Start Erlang and compile the Erlang code. Step 2. Start Erlang and compile the Erlang code: 3. Run the example. Step 3. Run the example: This is an example of how to solve the This section outlines an example of how to solve the example problem
+ in 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. 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. The scenario is illustrated in the following figure: 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. 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. Just as with a port program, the port communicates with a Erlang
+ Like a port program, the port communicates with an Erlang
process. All communication goes through one Erlang process that
is the connected process of the port
driver. Terminating this process closes the port driver. Before the port is created, the driver must be loaded. This is
done with the function The port is then created using the BIF The port is then created using the BIF
-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).
-
foo(X) ->
call_port({foo, X}).
@@ -63,7 +83,14 @@ call_port(Msg) ->
{complex, Result} ->
Result
end.
-
+
loop(Port) ->
receive
@@ -75,37 +102,52 @@ loop(Port) ->
end,
loop(Port)
end.
-
encode({foo, X}) -> [1, X];
encode({bar, Y}) -> [2, Y].
-
+
decode([Int]) -> Int.
-
unix> gcc -o extprg complex.c erl_comm.c port.c
-
unix> erl
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> c(complex1).
{ok,complex1}
-
2> complex1:start("extprg").
<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 @@
-module(complex5). -export([start/1, init/1]). @@ -77,9 +76,9 @@ init(SharedLib) -> register(complex, self()), Port = open_port({spawn, SharedLib}, []), loop(Port).-
Now it is possible to implement
Now
foo(X) -> call_port({foo, X}). @@ -92,10 +91,14 @@ call_port(Msg) -> {complex, Result} -> Result end.-
The
The
loop(Port) -> receive @@ -108,59 +111,58 @@ loop(Port) -> loop(Port) end.
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
encode({foo, X}) -> [1, X]; encode({bar, Y}) -> [2, Y]. - + decode([Int]) -> Int.-
The resulting Erlang program, including functionality for - stopping the port and detecting port failures is shown below.
+The resulting Erlang program, including functions for stopping + the port and detecting port failures, is as follows:
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
The driver structure is filled with the driver name and function
pointers. It is returned from the special entry point, declared
with the macro
The functions for receiving and sending data, are combined into +
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
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
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
All functions in the driver, takes a handle (returned from
-
All functions in the driver takes a handle (returned from
+
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.
-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. +
The
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:
1. Compile the C code.
+Step 1. Compile the C code:
unix> gcc -o exampledrv -fpic -shared complex.c port_driver.c windows> cl -LD -MD -Fe exampledrv.dll complex.c port_driver.c-
2. Start Erlang and compile the Erlang code.
+Step 2. Start Erlang and compile the Erlang code:
> erl Erlang (BEAM) emulator version 5.1 @@ -168,7 +170,7 @@ Erlang (BEAM) emulator version 5.1 Eshell V5.1 (abort with ^G) 1> c(complex5). {ok,complex5}-
3. Run the example.
+Step 3. Run the example:
2> complex5:start("example_drv"). <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 @@-- - 2000 2013 +2000 2015 Ericsson AB. All Rights Reserved. @@ -28,19 +28,39 @@ cnode.xml This is an example of how to solve the
+example problem 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.This section outlines an example of how to solve the example + problem in
Problem Example + by using a C node. Notice that a C node is not typically + used for solving simple problems like this, a port is + sufficient.Erlang Program -From Erlang's point of view, the C node is treated like a normal Erlang node. Therefore, calling the functions
+foo andbar 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.From Erlang's point of view, the C node is treated like a + normal Erlang node. Thus, calling the functions
foo and +bar 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:{RegName, Node} ! Msg-The node name
-Node should be the name of the C node. If short node names are used, the plain name of the node will becN whereN 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 thusc1@idril , an example using long node names iscnode@idril.ericsson.se .The registered name
RegName 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. +The node name
+Node is to be the name of the C node. If + short node names are used, the plain name of the node is +cN , whereN 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 thusc1@idril , an example using + long node names iscnode@idril.ericsson.se .The registered name,
RegName , 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:- 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:
@@ -50,39 +70,77 @@ C Program - Setting Up the Communication -Before calling any other Erl_Interface function, the memory handling must be initiated.
+Setting Up Communication +Before calling any other function in Erl_Interface, the + memory handling must be initiated:
erl_init(NULL, 0);-Now the C node can be initiated. If short node names are used, this is done by calling
+erl_connect_init() .Now the C node can be initiated. If short node names are + used, this is done by calling
erl_connect_init() :erl_connect_init(1, "secretcookie", 0);-The first argument is the integer which is used to construct the node name. In the example the plain node name will be
-c1 .
- - The second argument is a string defining the magic cookie.
- - The third argument is an integer which is used to identify a particular instance of a C node.If long node node names are used, initiation is done by calling
+erl_connect_xinit() .Here:
++
+- The first argument is the integer used to construct the node name. +
+In the example, the plain node name is
c1 .- The second argument is a string defining the magic cookie.
+- The third argument is an integer that is used to identify + a particular instance of a C node.
+If long node node names are used, initiation is done by + calling
erl_connect_xinit() :erl_connect_xinit("idril", "cnode", "cnode@idril.ericsson.se", &addr, "secretcookie", 0);-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
-in_addr struct with the IP address of the host, and the fifth and sixth arguments are the magic cookie and instance number.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
+erl_connect() , which will return an open file descriptor at success.Here:
++
+- The first argument is the host name.
+- The second argument is the plain node name.
+- The third argument is the full node name.
+- The fourth argument is a pointer to an
+in_addr + struct with the IP address of the host.- The fifth argument is the magic cookie.
+- The sixth argument is the instance number.
+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
erl_connect() , + which returns an open file descriptor at success:fd = erl_connect("e1@idril");-If the C node acts as a server, it must first create a socket (call
+bind() andlisten() ) listening to a certain port numberport . It then publishes its name and port number withepmd (the Erlang port mapper daemon, see the man page forepmd ).If the C node acts as a server, it must first create a socket + (call
bind() andlisten() ) listening to a + certain port numberport . It then publishes its name + and port number withepmd , the Erlang port mapper + daemon. For details, see theepmd manual page in ERTS:erl_publish(port);-Now the C node server can accept connections from Erlang nodes.
+Now the C node server can accept connections from Erlang nodes:
fd = erl_accept(listen, &conn);-The second argument to
+erl_accept is a structErlConnect that will contain useful information when a connection has been established; for example, the name of the Erlang node.The second argument to
erl_accept is a struct +ErlConnect which contains useful information when a + connection has been established, for example, the name of the + Erlang node.Sending and Receiving Messages -The C node can receive a message from Erlang by calling
-erl_receive msg() . This function reads data from the open file descriptorfd into a buffer and puts the result in anErlMessage structemsg .ErlMessage has a fieldtype defining which kind of data was received. In this case the type of interest isERL_REG_SEND which indicates that Erlang sent a message to a registered process at the C node. The actual message, anETERM , will be in themsg field.It is also necessary to take care of the types
+ERL_ERROR (an error occurred) andERL_TICK (alive check from other node, should be ignored). Other possible types indicate process events such as link/unlink and exit.The C node can receive a message from Erlang by calling +
+erl_receive msg() . This function reads data from the + open file descriptorfd into a buffer and puts the + result in anErlMessage structemsg . +ErlMessage has a fieldtype defining what kind + of data is received. In this case, the type of interest is +ERL_REG_SEND which indicates that Erlang sent a message + to a registered process at the C node. The actual message, an +ETERM , is in themsg field.It is also necessary to take care of the types +
ERL_ERROR (an error occurred) andERL_TICK + (alive check from other node, is to be ignored). Other + possible types indicate process events such as link, unlink, + and exit:while (loop) { @@ -93,7 +151,16 @@ fd = erl_accept(listen, &conn);loop = 0; /* exit while loop */ } else { if (emsg.type == ERL_REG_SEND) {
Since the message is an
As the message is an
fromp = erl_element(2, emsg.msg); tuplep = erl_element(3, emsg.msg); @@ -108,29 +175,30 @@ fd = erl_accept(listen, &conn);resp = erl_format("{cnode, ~i}", res); erl_send(fd, fromp, resp); -
Finally, the memory allocated by the
Finally, the memory allocated by the
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);-
The resulting C programs can be found in looks like the following examples. First a C node server using short node names.
+The following examples show the resulting C programs. + First a C node server using short node names:
Below follows a C node server using long node names.
+A C node server using long node names:
And finally we have the code for the C node client.
+Finally, the code for the C node client:
1. Compile the C code, providing the paths to the Erl_Interface include files and libraries, and to the
In R5B and later versions of OTP, the
-
- In R4B and earlier versions of OTP,
Step 1. Compile the C code. This provides the paths to
+ the Erl_Interface include files and libraries, and to the
+
- > gcc -o cserver \\ -I/usr/local/otp/lib/erl_interface-3.2.1/include \\ -L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ @@ -148,11 +216,29 @@ unix> gcc -o cclient \\ -L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ complex.c cnode_c.c \\ -lerl_interface -lei -lsocket -lnsl-
2. Compile the Erlang code.
+In Erlang/OTP R5B and later versions of OTP, the
+
In R4B and earlier versions of OTP,
Step 2. Compile the Erlang code:
unix> erl -compile complex3 complex4-
3. Run the C node server example with short node names.
-Start the C program
Step 3. Run the C node server example with short node names.
+Do as follows:
+unix> cserver 3456 @@ -164,7 +250,9 @@ Eshell V4.9.1.2 (abort with ^G) 4 (e1@idril)2> complex3:bar(5). 10-
4. Run the C node client example. Terminate
Step 4. Run the C node client example. Terminate
+
unix> cclient @@ -172,7 +260,7 @@ unix> cclient 4 (e1@idril)4> complex3:bar(5). 10-
5. Run the C node server, long node names, example.
+Step 5. Run the C node server example with long node names:
unix> cserver2 3456 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 @@-- - 2000 2013 +2000 2015 Ericsson AB. All Rights Reserved. @@ -28,14 +28,29 @@ erl_interface.xml This is an example of how to solve the
+ +example problem by using a port anderl_interface . It is necessary to read theport example before reading this chapter.This section outlines an example of how to solve the example + problem in
Problem Example by + using a port and Erl_Interface. It is necessary to read the port + example inPorts before reading + this section.Erlang Program -The example below shows an Erlang program communicating with a C program over a plain port with home made encoding.
-- 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
+term_to_binary/1 andbinary_to_term/1 should be used. That is:The following example shows an Erlang program communicating + with a C program over a plain port with home made encoding:
++ There are two differences when using Erl_Interface on the C + side compared to the example in
++ Ports , using only the plain port:+
+- As Erl_Interface operates on the Erlang external term format, + the port must be set to use binaries.
+- Instead of inventing an encoding/decoding scheme, the +
+term_to_binary/1 andbinary_to_term/1 BIFs are to + be used.That is:
open_port({spawn, ExtPrg}, [{packet, 2}])is replaced with:
@@ -55,69 +70,110 @@ receive {Port, {data, Data}} -> Caller ! {complex, binary_to_term(Data)} end
The resulting Erlang program is shown below.
+The resulting Erlang program is as follows:
Note that calling
Notice that calling
The example below shows a C program communicating with an Erlang program over a plain port with home made encoding.
+The following example shows a C program communicating with an + Erlang program over a plain port with home made encoding:
Compared to the C program above
- used for the plain port the
Compared to the C program in
erl_init(NULL, 0);-
For reading from and writing to the port the functions
The following functions,
The function
The function
int main() { ETERM *tuplep; while (read_cmd(buf) > 0) { tuplep = erl_decode(buf);-
In this case
Here,
fnp = erl_element(1, tuplep); argp = erl_element(2, tuplep);-
The macros
The macros
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)); }-
Now an
Now an
intp = erl_mk_int(res);-
The resulting
The resulting
erl_encode(intp, buf); write_cmd(buf, erl_eterm_len(intp));-
Last, the memory allocated by the
Finally, the memory allocated by the
erl_free_compound(tuplep); erl_free_term(fnp); erl_free_term(argp); erl_free_term(intp);-
The resulting C program is shown below:
+The resulting C program is as follows:
1. Compile the C code, providing the paths to the include files
Step 1. Compile the C code. This provides the paths to
+ the include files
unix> gcc -o extprg -I/usr/local/otp/lib/erl_interface-3.2.1/include \\ -L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ complex.c erl_comm.c ei.c -lerl_interface -lei-
In R5B and later versions of OTP, the
-
- In R4B and earlier versions of OTP,
2. Start Erlang and compile the Erlang code.
+In Erlang/OTP R5B and later versions of OTP, the
In R4B and earlier versions of OTP,
Step 2. Start Erlang and compile the Erlang code:
unix> erl 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> c(complex2). {ok,complex2}-
3. Run the example.
+Step 3. Run the example:
2> complex2:start("extprg"). <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 @@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 @@ - 2000 2013 +2000 2015 Ericsson AB. All Rights Reserved. @@ -31,16 +31,25 @@ Description -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.
-- (For the sake of keeping the example as simple as possible, the functions are not very complicated in this case).
-Preferably we would like to able to call
+foo andbar without having to bother about them actually being C functions.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:
++ The functions are deliberately kept as simple as possible, for + readability reasons.
+From an Erlang perspektive, it is preferable to be able to call +
foo andbar without having to bother about that + they are C functions:% Erlang code ... Res = complex:foo(X), ...-The communication with C is hidden in the implementation of
+complex.erl . In the following chapters it is shown how this module can be implemented using the different interoperability mechanisms.Here, the communication with C is hidden in the implementation + of
complex.erl . + In the following sections, it is shown how this module can be + implemented using the different interoperability mechanisms.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 @@ + - 2000 2013 +2000 2015 Ericsson AB. All Rights Reserved. @@ -28,18 +28,34 @@ introduction.xml + 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.
Purpose -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.
+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.
Prerequisites -It is assumed that the reader is a skilled Erlang programmer, familiar with concepts such as Erlang data types, processes, messages and error handling.
-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.
+It is assumed that you are a skilled Erlang programmer, + familiar with concepts such as Erlang data types, processes, + messages, and error handling.
+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.
- 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.
+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.
- - 2000 2013 +2000 2015 Ericsson AB. All Rights Reserved. @@ -28,92 +28,105 @@ nif.xml This is an example of how to solve the
-example problem - 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 -foo andbar in the example, that does some - relatively short calculations without side effects and return the result.- +NIFs -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.
-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.
-This section outlines an example of how to solve the example + problem in
+Problem Example + by using Native Implemented Functions (NIFs).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
+foo andbar in the example, that + do some relatively short calculations without side effects and + return the result.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.
+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.
Erlang Program -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.
-NIF libraries are loaded by calling
+erlang:load_nif/2 , 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.Even if all functions of a module are NIFs, an Erlang + module is still needed for two reasons:
++
+- The NIF library must be explicitly loaded by + Erlang code in the same module.
+- All NIFs of a module must have an Erlang implementation + as well.
+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.
+NIF libraries are loaded by calling
erlang:load_nif/2 , + 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:- We use the directive
-on_load to get functioninit to be - automatically called when the module is loaded. Ifinit - returns anything other thanok , 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.Loading the NIF library will override the stub implementations +
Here, the directive
+on_load is used to get function +init to be automatically called when the module is + loaded. Ifinit returns anything other thanok , + such when the loading of the NIF library fails in this example, + the module is unloaded and calls to functions within it, + fail.Loading the NIF library overrides the stub implementations and cause calls to
foo andbar to be dispatched to the NIF implementations instead.- NIF library code +NIF Library Code The NIFs of the module are compiled and linked into a shared library. Each NIF is implemented as a normal C function. The macro
+ arity, and function pointers of all the NIFs in the module. The header + fileERL_NIF_INIT together with an array of structures defines the names, - arity and function pointers of all the NIFs in the module. The header - fileerl_nif.h must be included. Since the library is a shared - module, not a program, no main function should be present.erl_nif.h must be included. As the library is a shared + module, not a program, no main function is to be present.The function arguments passed to a NIF appears in an array
+ the calling Erlang process:argv , - withargc as the length of the array and thus the arity of the + withargc as the length of the array, and thus the arity of the function. The Nth argument of the function can be accessed asargv[N-1] . 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.- The first argument to
ERL_NIF_INIT must be the name of the +Here,
+ERL_NIF_INIT has the following arguments:+
- +
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
+ macro. +ErlNifFunc - 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 toNULL .- The second argument is the array of
+ErlNifFunc + structures containing name, arity, and function pointer of + each NIF.- 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
+NULL .Function arguments and return values are represented as values - of type
ERL_NIF_TERM . We use functions likeenif_get_int - andenif_make_int to convert between Erlang term and C-type. - If the function argumentargv[0] is not an integer then -enif_get_int will return false, in which case we return + of typeERL_NIF_TERM . Here, functions likeenif_get_int + andenif_make_int are used to convert between Erlang term + and C-type. + If the function argumentargv[0] is not an integer, +enif_get_int returns false, in which case it returns by throwing abadarg -exception withenif_make_badarg .+ Running the Example -1. Compile the C code.
+Step 1. Compile the C code:
unix> gcc -o complex6_nif.so -fpic -shared complex.c complex6_nif.c windows> cl -LD -MD -Fe complex6_nif.dll complex.c complex6_nif.c-2. Start Erlang and compile the Erlang code.
+Step 2: Start Erlang and compile the Erlang code:
> erl 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> c(complex6). {ok,complex6}-3. Run the example.
+Step 3: Run the example:
3> complex6:foo(3). 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 @@- 2000 2013 +2000 2015 Ericsson AB. All Rights Reserved. @@ -31,35 +31,90 @@ @@ -68,64 +123,152 @@ Built-In Mechanisms -There are two interoperability mechanisms built into the Erlang runtime system. One is distributed Erlang and the other one is ports. A variation of ports is linked-in drivers.
+Two interoperability mechanisms are built into the Erlang + runtime system, distributed Erlang and ports. + A variation of ports is linked-in drivers.
Distributed Erlang -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
-stdlib modules intended for use in a distributed Erlang system; for example,global which provides global name registration. The distribution mechanism is implemented using TCP/IP sockets.When to use: 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
-C node , see below.Where to read more: Distributed Erlang and some distributed programming techniques are described in the Erlang book.
+
- - In the Erlang/OTP documentation there is a chapter about distributed Erlang in "Getting Started" (User's Guide).
- - Relevant man pages areerlang (describes the BIFs) andglobal ,net_adm ,pg2 ,rpc ,pool andslave .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,
+global , which provides global name + registration. The distribution mechanism is implemented using + TCP/IP sockets.When to use: 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 +
+C and Java Libraries .Where to read more: Distributed Erlang and some distributed + programming techniques are described in the Erlang book.
+For more information, see
++ Distributed Programming. Relevant manual pages are the following:
++
- +
erlang manual page in ERTS + (describes the BIFs)- +
global manual page in Kernel- +
net_adm manual page in Kernel- +
pg2 manual page in Kernel- +
rpc manual page in Kernel- +
pool manual page in STDLIB- +
slave manual page in STDLIBPorts and Linked-In Drivers -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.
-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.
-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.
-When to use: 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.
+
- - 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.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.
+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.
+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.
+When to use: 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.
+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.
- -An erroneous linked-in driver will cause the entire Erlang runtime system to leak memory, hang or crash.
+A faulty linked-in driver causes the entire Erlang runtime + system to leak memory, hang, or crash.
Where to read more: Ports are described in the "Miscellaneous Items" chapter of the Erlang book. Linked-in drivers are described in Appendix E.
-
- - The BIFopen_port/2 is documented in the man page forerlang . For linked-in drivers, the programmer needs to read the information in the man page forerl_ddll .Examples:
+Port example .Where to read more: Ports are described in section + "Miscellaneous Items" of the Erlang book. Linked-in drivers + are described in Appendix E.
+The BIF
+open_port/2 is documented in the +erlang manual page in + ERTS.For linked-in drivers, the programmer needs to read the +
+erl_ddll manual + page in Kernel.Examples: Port example in
+ Ports .- Erl_Interface -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:
+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:
-
-- -
erl_marshal ,erl_eterm ,erl_format ,erl_malloc Handling of the Erlang external term format.- -
erl_connect Communication with distributed Erlang, seeC nodes below.- -
erl_error Error print routines.- -
erl_global Access globally registered names.- +
Registry Store and backup of key-value pairs.- +
+erl_marshal ,erl_eterm ,erl_format , and +erl_malloc : Handling of the Erlang external term format- +
+erl_connect : + Communication with distributed Erlang, seeC nodes below- +
+erl_error : + Error print routines- +
+erl_global : + Access globally registered names- +
Registry : + Store and backup of key-value pairsThe 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.
+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:
Binary = term_to_binary(Term) Term = binary_to_term(Binary)-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.
+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.
When to use: In C code, in conjunction with Erlang binaries.
-Where to read more: 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.
-Examples:
+erl_interface example .Where to read more: 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.
Examples: Erl_Interface example in +
Erl_Interface .C Nodes -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 C node, or a hidden node. 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.
-When to use: 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.
-Where to read more: In the
-erl_connect part of the Erl_Interface documentation, see above. The programmer also needs to be familiar with TCP/IP sockets, seebelow , and distributed Erlang, seeabove .Examples:
+C node example .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 C node, or a hidden + node. 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.
+When to use: 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.
+Where to read more: See the
+erl_connect part + of the Erl_Interface documentation. The programmer also needs + to be familiar with TCP/IP sockets, see Sockets inStandard + Protocols and Distributed Erlang inBuilt-In Mechanisms .Example: C node example in
+ C Nodes .Jinterface -In Erlang/OTP R6B, a library similar to Erl_Interface for Java was added called jinterface.
+In Erlang/OTP R6B, a library similar to Erl_Interface for + Java was added called jinterface. It provides a tool + for Java programs to communicate with Erlang nodes.
Sometimes communication between an Erlang program and another program using a standard protocol is desirable. Erlang/OTP currently supports TCP/IP and UDP sockets, 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.
+Sometimes communication between an Erlang program and another + program using a standard protocol is desirable. Erlang/OTP + currently supports TCP/IP and UDP sockets: as + follows:
+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.
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 UNIX Network Programming, Volume 1: Networking APIs - Sockets and XTI by W. Richard Stevens, ISBN: 013490012X.
-In Erlang/OTP, access to TCP/IP and UDP sockets is provided by the
- Kernel modules
When to use: For programs running on the same or on another machine than the Erlang program.
-Where to read more: The man pages for
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.
+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, refer to a + suitable book about network programming. A suggestion is + UNIX Network Programming, Volume 1: Networking APIs - + Sockets and XTI by W. Richard Stevens, ISBN: + 013490012X.
+In Erlang/OTP, access to TCP/IP and UDP sockets is provided
+ by the modules
When to use: For programs running on the same or on + another machine than the Erlang program.
+Where to read more: See the
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.
+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.
+For details, see the
There are two old applications of interest when talking about interoperability: IG which was removed in Erlang/OTP R6B and Jive which was removed in Erlang/OTP R7B. Both applications have been replaced by IC and are mentioned here for reference only.
-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.
+Two old applications are of interest regarding + interoperability. Both have been replaced by IC and are + mentioned here for reference only:
+IG - Removed from Erlang/OTP R6B.
+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 - Removed from Erlang/OTP R7B.
+Jive provided a simple interface between an Erlang program + and a Java program.
+