Sophie

Sophie

distrib > Mageia > 7 > aarch64 > by-pkgid > ca236e080672a3aa5beda2fe21b8473d > files > 154

erlang-doc-21.2.5-1.mga7.noarch.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns:erl="http://erlang.org" xmlns:fn="http://www.w3.org/2005/02/xpath-functions">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="../otp_doc.css" type="text/css">
<title>Erlang -- Erl_Interface</title>
</head>
<body>
<div id="container">
<script id="js" type="text/javascript" language="JavaScript" src="../js/flipmenu/flipmenu.js"></script><script id="js2" type="text/javascript" src="../js/erlresolvelinks.js"></script><script language="JavaScript" type="text/javascript">
            <!--
              function getWinHeight() {
                var myHeight = 0;
                if( typeof( window.innerHeight ) == 'number' ) {
                  //Non-IE
                  myHeight = window.innerHeight;
                } else if( document.documentElement && ( document.documentElement.clientWidth ||
                                                         document.documentElement.clientHeight ) ) {
                  //IE 6+ in 'standards compliant mode'
                  myHeight = document.documentElement.clientHeight;
                } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
                  //IE 4 compatible
                  myHeight = document.body.clientHeight;
                }
                return myHeight;
              }

              function setscrollpos() {
                var objf=document.getElementById('loadscrollpos');
                 document.getElementById("leftnav").scrollTop = objf.offsetTop - getWinHeight()/2;
              }

              function addEvent(obj, evType, fn){
                if (obj.addEventListener){
                obj.addEventListener(evType, fn, true);
                return true;
              } else if (obj.attachEvent){
                var r = obj.attachEvent("on"+evType, fn);
                return r;
              } else {
                return false;
              }
             }

             addEvent(window, 'load', setscrollpos);

             //--></script><div id="leftnav"><div class="innertube">
<div class="erlang-logo-wrapper"><a href="../index.html"><img alt="Erlang Logo" src="../erlang-logo.png" class="erlang-logo"></a></div>
<p class="section-title">Interoperability Tutorial</p>
<p class="section-subtitle">User's Guide</p>
<p class="section-version">Version 10.2.3</p>
<ul class="panel-sections">
<li><a href="users_guide.html">User's Guide</a></li>
<li><a href="../pdf/otp-system-documentation-10.2.3.pdf">PDF</a></li>
<li><a href="../index.html">Top</a></li>
</ul>
<ul class="expand-collapse-items">
<li><a href="javascript:openAllFlips()">Expand All</a></li>
<li><a href="javascript:closeAllFlips()">Contract All</a></li>
</ul>
<h3>Chapters</h3>
<ul class="flipMenu" imagepath="../js/flipmenu">
<li id="no" title="Introduction" expanded="false">Introduction<ul>
<li><a href="introduction.html">
              Top of chapter
            </a></li>
<li title="Purpose"><a href="introduction.html#purpose">Purpose</a></li>
<li title="Prerequisites"><a href="introduction.html#prerequisites">Prerequisites</a></li>
</ul>
</li>
<li id="no" title="Overview" expanded="false">Overview<ul>
<li><a href="overview.html">
              Top of chapter
            </a></li>
<li title="Built-In Mechanisms"><a href="overview.html#built-in-mechanisms">Built-In Mechanisms</a></li>
<li title="C and Java Libraries"><a href="overview.html#c-and-java-libraries">C and Java Libraries</a></li>
<li title="Standard Protocols"><a href="overview.html#standard-protocols">Standard Protocols</a></li>
<li title="IC"><a href="overview.html#ic">IC</a></li>
<li title="Old Applications"><a href="overview.html#old-applications">Old Applications</a></li>
</ul>
</li>
<li id="no" title="Problem Example" expanded="false">Problem Example<ul>
<li><a href="example.html">
              Top of chapter
            </a></li>
<li title="Description"><a href="example.html#description">Description</a></li>
</ul>
</li>
<li id="no" title="Ports" expanded="false">Ports<ul>
<li><a href="c_port.html">
              Top of chapter
            </a></li>
<li title="Erlang Program"><a href="c_port.html#erlang-program">Erlang Program</a></li>
<li title="C Program"><a href="c_port.html#c-program">C Program</a></li>
<li title="Running the Example"><a href="c_port.html#running-the-example">Running the Example</a></li>
</ul>
</li>
<li id="loadscrollpos" title="Erl_Interface" expanded="true">Erl_Interface<ul>
<li><a href="erl_interface.html">
              Top of chapter
            </a></li>
<li title="Erlang Program"><a href="erl_interface.html#erlang-program">Erlang Program</a></li>
<li title="C Program"><a href="erl_interface.html#c-program">C Program</a></li>
<li title="Running the Example"><a href="erl_interface.html#running-the-example">Running the Example</a></li>
</ul>
</li>
<li id="no" title="Port Drivers" expanded="false">Port Drivers<ul>
<li><a href="c_portdriver.html">
              Top of chapter
            </a></li>
<li title="Erlang Program"><a href="c_portdriver.html#erlang-program">Erlang Program</a></li>
<li title="C Driver"><a href="c_portdriver.html#c-driver">C Driver</a></li>
<li title="Running the Example"><a href="c_portdriver.html#running-the-example">Running the Example</a></li>
</ul>
</li>
<li id="no" title="C Nodes" expanded="false">C Nodes<ul>
<li><a href="cnode.html">
              Top of chapter
            </a></li>
<li title="Erlang Program"><a href="cnode.html#erlang-program">Erlang Program</a></li>
<li title="C Program"><a href="cnode.html#c-program">C Program</a></li>
<li title="Running the Example"><a href="cnode.html#running-the-example">Running the Example</a></li>
</ul>
</li>
<li id="no" title="NIFs" expanded="false">NIFs<ul>
<li><a href="nif.html">
              Top of chapter
            </a></li>
<li title="Erlang Program"><a href="nif.html#erlang-program">Erlang Program</a></li>
<li title="NIF Library Code"><a href="nif.html#nif-library-code">NIF Library Code</a></li>
<li title="Running the Example"><a href="nif.html#running-the-example">Running the Example</a></li>
</ul>
</li>
</ul>
</div></div>
<div id="content">
<div class="innertube">
<h1>5 Erl_Interface</h1>
  

  <p>This section outlines an example of how to solve the example
    problem in <span class="bold_code bc-19"><a href="example.html">Problem Example</a></span> by
    using a port and Erl_Interface. It is necessary to read the port
    example in <span class="bold_code bc-19"><a href="c_port.html">Ports</a></span> before reading
    this section.</p>

  <h3><span onMouseOver="document.getElementById('ghlink-erlang-program-idm281472710422040').style.visibility = 'visible';" onMouseOut="document.getElementById('ghlink-erlang-program-idm281472710422040').style.visibility = 'hidden';"><span id="ghlink-erlang-program-idm281472710422040" class="ghlink"><a href="https://github.com/erlang/otp/edit/maint/system/doc/tutorial/erl_interface.xmlsrc#L39" title="Found an issue with the documentation? Fix it by clicking here!"><span class="pencil"></span></a></span><a class="title_link" name="erlang-program" href="#erlang-program">5.1 
          Erlang Program</a></span></h3>
    
    <p>The following example shows an Erlang program communicating
      with a C program over a plain port with home made encoding:</p>
<div class="example"><pre>-module(complex1).
-export([start/1, stop/0, init/1]).
-export([foo/1, bar/1]).

start(ExtPrg) -&gt;
    spawn(?MODULE, init, [ExtPrg]).
stop() -&gt;
    complex ! stop.

foo(X) -&gt;
    call_port({foo, X}).
bar(Y) -&gt;
    call_port({bar, Y}).

call_port(Msg) -&gt;
    complex ! {call, self(), Msg},
    receive
	{complex, Result} -&gt;
	    Result
    end.

init(ExtPrg) -&gt;
    register(complex, self()),
    process_flag(trap_exit, true),
    Port = open_port({spawn, ExtPrg}, [{packet, 2}]),
    loop(Port).

loop(Port) -&gt;
    receive
	{call, Caller, Msg} -&gt;
	    Port ! {self(), {command, encode(Msg)}},
	    receive
		{Port, {data, Data}} -&gt;
		    Caller ! {complex, decode(Data)}
	    end,
	    loop(Port);
	stop -&gt;
	    Port ! {self(), close},
	    receive
		{Port, closed} -&gt;
		    exit(normal)
	    end;
	{'EXIT', Port, Reason} -&gt;
	    exit(port_terminated)
    end.

encode({foo, X}) -&gt; [1, X];
encode({bar, Y}) -&gt; [2, Y].

decode([Int]) -&gt; Int.</pre></div>    <p>There are two differences when using Erl_Interface on the C
      side compared to the example in <span class="bold_code bc-19"><a href="c_port.html">Ports</a></span>, using only the plain port:</p>
    <ul>
       <li>As Erl_Interface operates on the Erlang external term format,
       the port must be set to use binaries.</li>
       <li>Instead of inventing an encoding/decoding scheme, the
       <span class="code">term_to_binary/1</span> and <span class="code">binary_to_term/1</span> BIFs are to
       be used.</li>
     </ul>
    <p>That is:</p>
    <div class="example"><pre>
open_port({spawn, ExtPrg}, [{packet, 2}])</pre></div>
    <p>is replaced with:</p>
    <div class="example"><pre>
open_port({spawn, ExtPrg}, [{packet, 2}, binary])</pre></div>
    <p>And:</p>
    <div class="example"><pre>
Port ! {self(), {command, encode(Msg)}},
receive
  {Port, {data, Data}} -&gt;
    Caller ! {complex, decode(Data)}
end</pre></div>
    <p>is replaced with:</p>
    <div class="example"><pre>
Port ! {self(), {command, term_to_binary(Msg)}},
receive
  {Port, {data, Data}} -&gt;
    Caller ! {complex, binary_to_term(Data)}
end</pre></div>
    <p>The resulting Erlang program is as follows:</p>
<div class="example"><pre>-module(complex2).
-export([start/1, stop/0, init/1]).
-export([foo/1, bar/1]).

start(ExtPrg) -&gt;
    spawn(?MODULE, init, [ExtPrg]).
stop() -&gt;
    complex ! stop.

foo(X) -&gt;
    call_port({foo, X}).
bar(Y) -&gt;
    call_port({bar, Y}).

call_port(Msg) -&gt;
    complex ! {call, self(), Msg},
    receive
	{complex, Result} -&gt;
	    Result
    end.

init(ExtPrg) -&gt;
    register(complex, self()),
    process_flag(trap_exit, true),
    Port = open_port({spawn, ExtPrg}, [{packet, 2}, binary]),
    loop(Port).

loop(Port) -&gt;
    receive
	{call, Caller, Msg} -&gt;
	    Port ! {self(), {command, term_to_binary(Msg)}},
	    receive
		{Port, {data, Data}} -&gt;
		    Caller ! {complex, binary_to_term(Data)}
	    end,
	    loop(Port);
	stop -&gt;
	    Port ! {self(), close},
	    receive
		{Port, closed} -&gt;
		    exit(normal)
	    end;
	{'EXIT', Port, Reason} -&gt;
	    exit(port_terminated)
    end.</pre></div>    <p>Notice that calling <span class="code">complex2:foo/1</span> and
      <span class="code">complex2:bar/1</span> results in the tuple <span class="code">{foo,X}</span> or
      <span class="code">{bar,Y}</span> being sent to the <span class="code">complex</span> 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>
  

  <h3><span onMouseOver="document.getElementById('ghlink-c-program-idm281472710406472').style.visibility = 'visible';" onMouseOut="document.getElementById('ghlink-c-program-idm281472710406472').style.visibility = 'hidden';"><span id="ghlink-c-program-idm281472710406472" class="ghlink"><a href="https://github.com/erlang/otp/edit/maint/system/doc/tutorial/erl_interface.xmlsrc#L83" title="Found an issue with the documentation? Fix it by clicking here!"><span class="pencil"></span></a></span><a class="title_link" name="c-program" href="#c-program">5.2 
          C Program</a></span></h3>
    
    <p>The following example shows a C program communicating with an
      Erlang program over a plain port with home made encoding:</p>
<div class="example"><pre>/* port.c */

typedef unsigned char byte;

int main() {
  int fn, arg, res;
  byte buf[100];

  while (read_cmd(buf) &gt; 0) {
    fn = buf[0];
    arg = buf[1];
    
    if (fn == 1) {
      res = foo(arg);
    } else if (fn == 2) {
      res = bar(arg);
    }

    buf[0] = res;
    write_cmd(buf, 1);
  }
}</pre></div>    <p>Compared to the C program in <span class="bold_code bc-19"><a href="c_port.html">Ports</a></span>, using only the plain port, the
      <span class="code">while</span>-loop must be rewritten. Messages coming from the
      port is on the Erlang external term format. They must be
      converted into an <span class="code">ETERM</span> struct, which is a C struct
      similar to an Erlang term. The result of calling <span class="code">foo()</span> or
      <span class="code">bar()</span> 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>
    <div class="example"><pre>
erl_init(NULL, 0);</pre></div>
    <p>The following functions, <span class="code">read_cmd()</span> and
      <span class="code">write_cmd()</span>, from the <span class="code">erl_comm.c</span> example in
      <span class="bold_code bc-19"><a href="c_port.html">Ports</a></span> can still be
      used for reading from and writing to the port:
    </p>
<div class="example"><pre>/* erl_comm.c */

typedef unsigned char byte;

read_cmd(byte *buf)
{
  int len;

  if (read_exact(buf, 2) != 2)
    return(-1);
  len = (buf[0] &lt;&lt; 8) | buf[1];
  return read_exact(buf, len);
}

write_cmd(byte *buf, int len)
{
  byte li;

  li = (len &gt;&gt; 8) &amp; 0xff;
  write_exact(&amp;li, 1);
  
  li = len &amp; 0xff;
  write_exact(&amp;li, 1);

  return write_exact(buf, len);
}

read_exact(byte *buf, int len)
{
  int i, got=0;

  do {
    if ((i = read(0, buf+got, len-got)) &lt;= 0)
      return(i);
    got += i;
  } while (got&lt;len);

  return(len);
}

write_exact(byte *buf, int len)
{
  int i, wrote = 0;

  do {
    if ((i = write(1, buf+wrote, len-wrote)) &lt;= 0)
      return (i);
    wrote += i;
  } while (wrote&lt;len);

  return (len);
}</pre></div>    <p>The function <span class="code">erl_decode()</span> from <span class="code">erl_marshal</span>
      converts the binary into an <span class="code">ETERM</span> struct:</p>
    <div class="example"><pre>
int main() {
  ETERM *tuplep;

  while (read_cmd(buf) &gt; 0) {
    tuplep = erl_decode(buf);</pre></div>
    <p>Here, <span class="code">tuplep</span> points to an <span class="code">ETERM</span> struct
      representing a tuple with two elements; the function name (atom)
      and the argument (integer). Using the function
      <span class="code">erl_element()</span> from <span class="code">erl_eterm</span>, these elements can
      be extracted, but they must also be declared as pointers to an
      <span class="code">ETERM</span> struct:</p>
    <div class="example"><pre>
    fnp = erl_element(1, tuplep);
    argp = erl_element(2, tuplep);</pre></div>
    <p>The macros <span class="code">ERL_ATOM_PTR</span> and <span class="code">ERL_INT_VALUE</span> from
      <span class="code">erl_eterm</span> 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>
    <div class="example"><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></div>
    <p>Now an <span class="code">ETERM</span> struct that represents the integer result
      can be constructed using the function <span class="code">erl_mk_int()</span> from
      <span class="code">erl_eterm</span>. The function
      <span class="code">erl_format()</span> from the module <span class="code">erl_format</span> can also
      be used:</p>
    <div class="example"><pre>
    intp = erl_mk_int(res);</pre></div>
    <p>The resulting <span class="code">ETERM</span> struct is converted into the Erlang
      external term format using the function <span class="code">erl_encode()</span> from
      <span class="code">erl_marshal</span> and sent to Erlang using
      <span class="code">write_cmd()</span>:</p>
    <div class="example"><pre>
    erl_encode(intp, buf);
    write_cmd(buf, erl_eterm_len(intp));</pre></div>
    <p>Finally, the memory allocated by the <span class="code">ETERM</span> creating
      functions must be freed:</p>
    <div class="example"><pre>
    erl_free_compound(tuplep);
    erl_free_term(fnp);
    erl_free_term(argp);
    erl_free_term(intp);</pre></div>
    <p>The resulting C program is as follows:</p>
<div class="example"><pre>/* ei.c */

#include "erl_interface.h"
#include "ei.h"

typedef unsigned char byte;

int main() {
  ETERM *tuplep, *intp;
  ETERM *fnp, *argp;
  int res;
  byte buf[100];
  long allocated, freed;

  erl_init(NULL, 0);

  while (read_cmd(buf) &gt; 0) {
    tuplep = erl_decode(buf);
    fnp = erl_element(1, tuplep);
    argp = erl_element(2, tuplep);
    
    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));
    }

    intp = erl_mk_int(res);
    erl_encode(intp, buf);
    write_cmd(buf, erl_term_len(intp));

    erl_free_compound(tuplep);
    erl_free_term(fnp);
    erl_free_term(argp);
    erl_free_term(intp);
  }
}</pre></div>  

  <h3><span onMouseOver="document.getElementById('ghlink-running-the-example-idm281472710270936').style.visibility = 'visible';" onMouseOut="document.getElementById('ghlink-running-the-example-idm281472710270936').style.visibility = 'hidden';"><span id="ghlink-running-the-example-idm281472710270936" class="ghlink"><a href="https://github.com/erlang/otp/edit/maint/system/doc/tutorial/erl_interface.xmlsrc#L159" title="Found an issue with the documentation? Fix it by clicking here!"><span class="pencil"></span></a></span><a class="title_link" name="running-the-example" href="#running-the-example">5.3 
          Running the Example</a></span></h3>
    
    <p><strong>Step 1.</strong> Compile the C code. This provides the paths to
      the include files <span class="code">erl_interface.h</span> and <span class="code">ei.h</span>, and
      also to the libraries <span class="code">erl_interface</span> and <span class="code">ei</span>:</p>
    <div class="example"><pre>
unix&gt; <span class="bold_code bc-12">gcc -o extprg -I/usr/local/otp/lib/erl_interface-3.9.2/include \\ </span>
<span class="bold_code bc-12">      -L/usr/local/otp/lib/erl_interface-3.9.2/lib \\ </span>
<span class="bold_code bc-12">      complex.c erl_comm.c ei.c -lerl_interface -lei -lpthread</span></pre></div>
    <p>In Erlang/OTP R5B and later versions of OTP, the <span class="code">include</span>
      and <span class="code">lib</span> directories are situated under
      <span class="code">OTPROOT/lib/erl_interface-VSN</span>, where <span class="code">OTPROOT</span> is
      the root directory of the OTP installation
      (<span class="code">/usr/local/otp</span> in the recent example) and <span class="code">VSN</span> is
      the version of the Erl_interface application (3.2.1 in the
      recent example).</p>
    <p>In R4B and earlier versions of OTP, <span class="code">include</span> and <span class="code">lib</span>
      are situated under <span class="code">OTPROOT/usr</span>.</p>
    <p><strong>Step 2.</strong> Start Erlang and compile the Erlang code:</p>
    <div class="example"><pre>
unix&gt; <span class="bold_code bc-12">erl</span>
Erlang (BEAM) emulator version 4.9.1.2

Eshell V4.9.1.2 (abort with ^G)
1&gt; <span class="bold_code bc-12">c(complex2).</span>
{ok,complex2}</pre></div>
    <p><strong>Step 3.</strong> Run the example:</p>
    <div class="example"><pre>
2&gt; <span class="bold_code bc-12">complex2:start("./extprg").</span>
&lt;0.34.0&gt;
3&gt; <span class="bold_code bc-12">complex2:foo(3).</span>
4
4&gt; <span class="bold_code bc-12">complex2:bar(5).</span>
10
5&gt; <span class="bold_code bc-12">complex2:bar(352).</span>
704
6&gt; <span class="bold_code bc-12">complex2:stop().</span>
stop</pre></div>
  
</div>
<div class="footer">
<hr>
<p>Copyright © 2000-2019 Ericsson AB. All Rights Reserved.</p>
</div>
</div>
</div>
<script type="text/javascript">window.__otpTopDocDir = '../js/';</script><script type="text/javascript" src="../js/highlight.js"></script>
</body>
</html>