The Erl_Interface library contains functions. which help you integrate programs written in C and Erlang. The functions in Erl_Interface support the following:
In the following sections, these topics are described:
The support for VxWorks is deprecated as of OTP 22, and will be removed in OTP 23.
The old legacy
In order to use any of the Erl_Interface functions, include the following lines in your code:
Determine where the top directory of your OTP installation is. You can find this out by starting Erlang and entering the following command at the Eshell prompt:
code:root_dir().
/usr/local/otp ]]>
To compile your code, make sure that your C compiler knows where
to find
When linking, you will need to specify the path to
Also, on some systems it may be necessary to link with some
additional libraries (e.g.
If you are using Erl_Interface functions in a threaded
application based on POSIX threads or Solaris threads, then
Erl_Interface needs access to some of the synchronization
facilities in your threads package, and you will need to specify
additional compiler flags in order to indicate which of the packages
you are using. Define
Note that both single threaded and default versions of the Erl_interface
and Ei libraries are provided. (The single threaded versions are named
Before calling any of the other Erl_Interface functions, you
must call
Data sent between distributed Erlang nodes is encoded in the Erlang external format. Consequently, you have to encode and decode Erlang terms into byte streams if you want to use the distribution protocol to communicate between a C program and Erlang.
The Erl_Interface library supports this activity. It has a
number of C functions which create and manipulate Erlang data
structures. The library also contains an encode and a decode function.
The example below shows how to create and encode an Erlang tuple
Alternatively, you can use
Refer to the Reference Manual for a complete description of the following modules:
The previous example can be simplified by using
Refer to the Reference Manual, the
As in previous examples, it is your responsibility to free the
memory allocated for Erlang terms. In this example,
The following example shows a slightly different solution:
In this case, you free the two terms independently. The order in
which you free the terms
If you are not sure whether you have freed the terms properly, you can use the following function to see the status of the fixed term allocator:
Refer to the Reference Manual, the
An Erlang pattern is a term that may contain unbound variables or
Refer to the Reference Manual, the
In order to connect to a distributed Erlang node you need to first
initialize the connection routine with
Refer to the Reference Manual, the
After initialization, you set up the connection to the Erlang node.
Use
When you use
C nodes can also register themselves with
Before registering with
Be aware that on some systems (such as VxWorks), a failed node will
not be detected by this mechanism since the operating system does not
automatically close descriptors that were left open when the node
failed. If a node has failed in this way,
This will cause
Use one of the following two functions to send messages:
As in Erlang, it is possible to send messages to a Pid or to a registered name. It is easier to send a message to a registered name because it avoids the problem of finding a suitable Pid.
Use one of the following two functions to receive messages:
In the following example,
The first element of the tuple that is sent is your own
Pid. This enables
In this example
In order to provide robustness, a distributed Erlang node
occasionally polls all its connected neighbours in an attempt to
detect failed nodes or communication links. A node which receives such
a message is expected to respond immediately with an
When a message has been received, it is the caller's responsibility
to free the received message
Refer to the Reference Manual for additional information about the following modules:
An Erlang node acting as a client to another Erlang node typically sends a request and waits for a reply. Such a request is included in a function call at a remote node and is called a remote procedure call. The following example shows how the Erl_Interface library supports remote procedure calls:
when compiling file: %s.erl !\
", modname);
erl_free_term(ep);
ep = erl_format("{ok,_}");
if (!erl_match(ep, reply))
erl_err_msg(" compiler errors !\
");
erl_free_term(ep);
erl_free_term(reply); ]]>
Refer to the Reference Manual, the
A C node has access to names registered through the Erlang Global module. Names can be looked up, allowing the C node to send messages to named Erlang services. C nodes can also register global names, allowing them to provide named services to Erlang processes or other C nodes.
Erl_Interface does not provide a native implementation of the global service. Instead it uses the global services provided by a "nearby" Erlang node. In order to use the services described in this section, it is necessary to first open a connection to an Erlang node.
To see what names there are:
It is the caller's responsibility to free the array.
To look up one of the names:
If
Before registering a name, you should already have registered your
port number with
Create a pid that Erlang processes can use to communicate with your service:
After registering the name, you should use
Do not forget to free
To unregister a name:
This section describes the use of the registry, a simple mechanism for storing key-value pairs in a C-node, as well as backing them up or restoring them from a Mnesia table on an Erlang node. More detailed information about the individual API functions can be found in the Reference Manual.
Keys are strings, i.e.
To start, you need to open a registry:
The number 45 in the example indicates the approximate number of objects that you expect to store in the registry. Internally the registry uses hash tables with collision chaining, so there is no absolute upper limit on the number of objects that the registry can contain, but if performance or memory usage are important, then you should choose a number accordingly. The registry can be resized later.
You can open as many registries as you like (if memory permits).
Objects are stored and retrieved through set and get functions. In the following examples you see how to store integers, floats, strings and arbitrary binary objects:
l = 42;
b->m = 12;
ei_reg_setpval(reg,"jox",b,sizeof(*b)); ]]>
If you attempt to store an object in the registry and there is an existing object with the same key, the new value will replace the old one. This is done regardless of whether the new object and the old one have the same type, so you can, for example, replace a string with an integer. If the existing value is a string or binary, it will be freed before the new value is assigned.
Stored values are retrieved from the registry as follows:
In all of the above examples, the object must exist and it must be of the right type for the specified operation. If you do not know the type of a given object, you can ask:
Buf will be initialized to contain object attributes.
Objects can be removed from the registry:
When you are finished with a registry, close it to remove all the objects and free the memory back to the system:
The contents of a registry can be backed up to Mnesia on a "nearby"
Erlang node. You need to provide an open connection to the Erlang node
(see
The example above will backup the contents of the registry to the
specified Mnesia table
In the same manner, a registry can be restored from a Mnesia table:
This will read the entire contents of
Note that if you restore to a non-empty registry, objects in the table will overwrite objects in the registry with the same keys. Also, the entire contents of the registry is marked as unmodified after the restore, including any modified objects that were not overwritten by the restore operation. This may not be your intention.
When string or binary objects are stored in the registry it is important that a number of simple guidelines are followed.
Most importantly, the object must have been created with a single call
to
You should also be aware that if you store binary objects that are context-dependent (e.g. containing pointers or open file descriptors), they will lose their meaning if they are backed up to a Mnesia table and subsequently restored in a different context.
When you retrieve a stored string or binary value from the registry, the registry maintains a pointer to the object and you are passed a copy of that pointer. You should never free an object retrieved in this manner because when the registry later attempts to free it, a runtime error will occur that will likely cause the C-node to crash.
You are free to modify the contents of an object retrieved this way.
However when you do so, the registry will not be aware of the changes
you make, possibly causing it to be missed the next time you make a
Mnesia backup of the registry contents. This can be avoided if you
mark the object as dirty after any such changes with