This section outlines an example of how to solve the example
problem in the
The scenario is illustrated in the following figure:
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:
-module(complex1). -export([start/1, init/1]). start(ExtPrg) -> spawn(?MODULE, init, [ExtPrg]). init(ExtPrg) -> register(complex, self()), process_flag(trap_exit, true), Port = open_port({spawn, ExtPrg}, [{packet, 2}]), loop(Port).
Now
foo(X) -> call_port({foo, X}). bar(Y) -> call_port({bar, Y}). call_port(Msg) -> complex ! {call, self(), Msg}, receive {complex, Result} -> Result end.
The
loop(Port) -> receive {call, Caller, Msg} -> Port ! {self(), {command, encode(Msg)}}, receive {Port, {data, Data}} -> Caller ! {complex, decode(Data)} end, loop(Port) end.
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,
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 as follows:
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,
Notice that
In the
Notice that the C program is in a
Step 1. Compile the C code:
unix> gcc -o extprg complex.c erl_comm.c port.c
Step 2. Start Erlang and compile the Erlang code:
unix> erl Erlang (BEAM) emulator version 4.9.1.2 Eshell V4.9.1.2 (abort with ^G) 1> c(complex1). {ok,complex1}
Step 3. Run the example:
2> complex1:start("extprg"). <0.34.0> 3> complex1:foo(3). 4 4> complex1:bar(5). 10 5> complex1:stop(). stop