******************************************************************************
General
******************************************************************************
There are two different interfaces, the old 'erl_interface' and 'ei'.
The old interface is to depend on the new one, not the other way arount.
Erl_interface should be "thread safe", i.e. you should be able to
handle connections, convert data etc from different threads.
Ei should be "reentrant" or "async safe", i.e. no locks should be set
so that if an ei function is called inside an signal handler there
could be a deadlock.
VxWorks call the operating processes "tasks". These are to be handled the
same way as Unix threads, i.e. there can only be one C node for all tasks
using the old interface.
Try to keep the documented functions, variables and symbols in sync
between
* Documentation
* ei.h and erl_interface.h
* prog/ei_fake_prog.c and prog/erl_fake_prog.c
From time to time do a
% (cd src; gmake check)
(FIXME this check should be rewritten to a test case)
******************************************************************************
Directories
******************************************************************************
* src/aux/
Support files for configure described in the next section
* src/legacy/
Old erl_interface stuff FIXME what about thread support etc....?
* src/connect/
Create nodes, connections, communication with the other node etc
* src/decode/
Simple decode functions
* src/encode/
Simple encode functions
* src/epmd/
Handle communication with epmd
* src/registry/
Key/value database with optional mnesia back up
* src/misc/
The rest of the library
* src/prog/
erl_call and some test programs for compiling and linking
* src/not_used/
Strange, some files are not used....
******************************************************************************
Configuration support files
******************************************************************************
The build uses GNU configure and libtool. The libtool and autoconf
package don't need to be installed to configure and build the
sources. But in "maintainer mode" you need them to update some files
in the source distribution.
* configure.in
Used in maintainer mode together with "aclocal.m4" to create
"configure". "configure.in" is hand written and only need to
be updated when you change the sources to use new header files
or C compiler features. You may get some hints about what to
update using a recent autoconf package and do
% cd erl_inteface
% autoscan src
The result to compare with the current "configure.in" will be
stored in "src/configure.scan".
* aclocal.m4
This file contains macros generated by ??? appended
with the content of "libtool.m4" in the installed libtool
package. (FIXME don't know when this is to be updated and
why it contains so much).
* src/aux/config.guess
* src/aux/config.sub
Used by "configure" to form the subdirectory name
"cpu-vendor-os".
* src/aux/install-sh*
Used if no other BSD compatible install script is found.
* src/aux/config.h.in
Used by "configure" as a template for the resulting
"src/config.h". The file "config.h.in" should be
updated when "configure.in" is updated because the
new macros used in your source and this is the file
where they are listed. You can find out what to update
using
% autoheader
* ltmain.sh
This is XXX (FIXME what?)
The base for the configure.in script was created with 'autoscan'.
The base for the config.h.in file was created with 'autoheader'.
******************************************************************************
Writing source
******************************************************************************
C files in "registry" are considered users of 'ei' and should not
include "eidef.h" or "config.h", only "ei.h".
C files in "prog" could include "config.h" directly.
Other C files should include "eidef.h" as the first line of
source. "eidef.h" contains some common constants and macros and
also includes config.h.
In general avoid including other header files from header files.
The exception is to make the protoypes complete to the user of
this library, i.e. to include <stdio.h> to defined FILE or
to include "ei_x_encode" to define the type ei_x_buff.
The function ei_decode_term() (FIXME encode_term?) work on ETERM,
i.e. it converts between the old erl_interface format and ei.
Because of this it is really part of the erl_interface library,
not the ei library.
Use uint8, uint16, uint32, int8, int16, and int32 for types
where size matters ;-) Use uint8 for buffers where we construct
messages.
NOTE!!!! Sending a "char" to macros like isupper(), isalpha() where
the character is > 127 will cause serios problems on some
machines/OS. The reason is that
'char' may be unsigned, i.e. the Swedish char '�' will
as a number be negativ.
The implementation of isupper() and others will on some
machines use an array that is indexed with the incoming
character code. The Swedish '�' will then create an access
on memory outside the array!
This may give a random value as a result or a segmentation
violation error.
******************************************************************************
Global variables
******************************************************************************
There are two reasons we avoid global variables:
- It is much easier to support threads without them
- On operating systems like VxWorks the global variable is global
to all operating system processes.
There are a few global variables that are ok
ei_x_extra This is set to 100 in "ei_x_encode.c" but can be
changed for debugging the memory allocation.
ei_trace_distribution Enable verbose tracing on stderr.
errno In the non threaded version of the lib this
is a global variable.
__erl_errno This is a global handled by "ei_pthreads.c"
You can check for globals using something like
% nm -g ei_fake_prog | fgrep OBJT
Global variables but with local scope
erl_if_ec Global state, is ok
******************************************************************************
The "long long" story
******************************************************************************
There are some functions in the 'ei' library that uses the GCC and
VC++ "long long" type. Unfortunately this can lead to some trouble.
When user code is linked with the "libei.a" the linker will extract
all objects files needed for resolving all symbol referenses
found. This means that you want to follow the rule that
* To reduce executable code size we use resonably small C source
files. One C file is one object file.
* We try to avoid unessesary dependency. For example currently almost all
ei_x_encode*() functions are in the same object file. Because they all
use the corresponding ei_encode*() function this means using one ei_x
function we will link in "ei_x_encode.o" object file but also all the
"ei_encode*.o" object files even if they are not used.
But the above is not the real trouble, memory and disk is cheap these
days. The real trouble is if we compile the 'ei' library using one
compiler, usually GNU cc, and link with another linker than GNU ld or
miss some runtime libraries that the GNU cc generated object files
assume is on the target. For example currently on Solaris some "long
long" operations will create a dependency to a "hidden" library
"libgcc.a". For example in a library not released got references to
"libgcc.a" '__ashldi3'
% nm -A libei.a | grep '__ashldi3'
libei.a[decode_longlong.o]: [6] | 0| 0|NOTY |GLOB |0 |UNDEF |__ashldi3
libei.a[decode_ulonglong.o]: [5] | 0| 0|NOTY |GLOB |0 |UNDEF |__ashldi3
We can accept that a dependecy is created for code linked with
"libei.a" that actually use 'ei' long long functions. But if we
arrange the 'ei' source badly using a non "long long" functions from
'ei' will still link in an object file that need "libgcc.a". One
example is that in plain R9C the ei_x_encode_longlong() function is
located in the file "ei_x_encode.c". So if any "long long" ei_x
function is used we have an unessesary dependency on
"ei_encode_longlong.o" and then need to link with GNU ld on with the
user code or explicitely link with "libgcc.a". The situation can be
visible in in plain R9C using
% nm -A erl_interface-3.4/lib/libei.a | \
grep 'longlong' | fgrep -v 'longlong.o'
As an possibly alternative to the current solution we may include the
object files inside the "libgcc.a" archive in the "libei.a" archive.
The "libgcc.a" that is assumed to be used when linking can be found
using
% gcc -print-libgcc-file-name
Some links about problems and solutions using "libgcc.a"
http://www.gnu.org/software/gcc/gcc-3.0/libgcc.html
http://www.gnu.org/software/libc/FAQ.html
The license for "libgcc.a" is a bit special and not located on the
official sites. You have to look in the source file for the "libgcc.a"
you use. The file is named "libgcc.c". If you don't know what gcc that
was used for the build of for example 'r9c' you can use
% otp_build_env -o r9c | perl -ne '/(gcc-[\d\.]+)/ and print "$1\n"'
Then to view the lincense do
% less `find /usr/local/share/src/gcc-REL/ -name "libgcc*.c"`
********************************* EOF ****************************************