Erlang

Erlang - a great tool. But, unfortunately, remain challenges that it is either impossible to implement, in principle, a possible but not effectively enough. Also, there are plenty already written in other languages code.

What to do in this case?

We use the native code from Erlang. Fortunately, for this is as much the whole two ways:
Running native code in third-party process
Using shared library

I prefer the first method. If the native code, if you please break down (lyrics SIGSEGV or SIGFPE), almost no effect on the performance of core applications: the current operation is, of course returns an error, but we will re-launch-party process and will continue to work. But in the case of shared library - drop the whole node entirely.

Task

We have some functions written in C:
/ * Very simple primerchik, take two bytes, return one * /
byte sum (byte addee1, byte addee2) (
return addee1 + addee2;
)
/ * This function “according to legend was written long ago, one very nelyudivym borodotym Dyad’kov,
* With which young officers are afraid to communicate. It was so long ago that nobody remembers how it works … = (
* We only know that it takes an array of bytes, and <s> invert </ s> and something weird with him.
* (Ask people who have devoted their lives cryptography, not to throw tomatoes) * /
void simple_crypt (byte * in_out_chunk, int chunk_size) (
int i;
for (i = 0; i <chunk_size; i + +) (
in_out_chunk [i] ^ = 0xFF;
)
)

I want to be able to do so:
piece_of_code () ->
Encrypted = simple_crypt (Orig),

Solution Overview

From the perspective of the operating system we will be running two processes: Erlang and Native. They will communicate via stdin and stdout of the latter.

For the programmer it will look as follows:
module in Erlang exporting simple_crypt / 1 and the sum / 2
Part C programs directly from the functions of interest to us
Part C program, dedicated I / Os
Part C programs dealing marshalling (the dirty and unpleasant work)

Boring technical details about the marshalling

Since communicating with Erlang C in our case through the streams of bytes, will somehow dodge and serialize our data types, so that they are in these flows went to bed.
Components will communicate “proposals”, in which the first two bytes will be official, and will denote the size of the remaining part (carrying semantic meaning).
Size will be written in Little-endian format: [0xAD, 0x0A] - will be denoted 0xAD * 161 + 0×0A.
When prompted, the first byte in the “body” of the request would be caused by an index function. The rest - the arguments for the function.
The answer - just the length, and data return value.
Since in our case the function does not accept / do not return any data types other than bytes - the task much easier: the arguments can be simply read and write, and do not pack and unpack.

The sun was still high … work …

Where do we start?
component number 2 in the review of the decision

/ * Header * /
# define IDX_SUM 1
# define IDX_SIMPLE_CRYPT 3

int sum (byte addee1, byte addee2);
void simple_crypt (byte * in_out_chunk, int chunk_size);
/ * Source * /
int sum (byte addee1, byte addee2) (
return addee1 + addee2;
)
void simple_crypt (byte * in_out_chunk, int chunk_size) (
int i;
for (i = 0; i <chunk_size; i + +) (
in_out_chunk [i] ^ = 0xFF;
)
)

It’s simple. We give a soulless index function names and write functions, which, in the conditions of the problem can not be implemented in Erlang.

Input output

Who cares - read carefully.
Who is not really - just use it, not really thinking: this part will not change in 99.9% of cases.
# include <unistd.h>
# include <stdio.h>
# include <errno.h>
/ *
* Read the command of Erlang
* /
int read_cmd (byte * buff) (
int len;
/ * Try to extort the length of the data from stdin * /
if ((len = read_exact (buff, 2)) = 2) (
return -1;
)
/ * Consider it * /
len = (buff [0] <<8) | buff [1];
/ * Finished reading data from stdin * /
return read_exact (buff, len);
)
/ *
* This is a lower level than the previous one.
* HERE, we read a specified number of bytes.
* /
int read_exact (byte * buff, int len) (
int i, got = 0;
do (
i = read (0 / * STDIN * /, buff + got, len - got);
if (i <= 0) (
return i;
)
got + = i;
) While (got <len);
return len;
)
/ *
* The answer Erlang
* /
int write_cmd (byte * buff, int len) (
/ * Erlang also expects us to answer length * /
byte li;
li = (len>> 8) & 0xff;
write_exact (& li, 1);
li = len & 0xff;
write_exact (& li, 1);
/ * The answer * /
return write_exact (buff, len);
)
/ *
* Write bytes
* /
int write_exact (byte * buff, int len) (
int i; int wrote = 0;
do (
if ((i = write (1 / * STDOUT * /, buff + wrote, len - wrote)) <= 0) (
return i;
)
wrote + = i;
) While (wrote <len);
return len;
)

Marshalling calls

In principle, a little bit and not difficult. But when you add another function, it will be necessary to climb here and add another branch test the index function … Nepriyatnenko.
On the other hand can duplicate pieces “shod” in the macros and enjoy life. =)
int main (int argc, char ** argv) (
int body_size;
int fn_idx;
byte buff [BUFF_SIZE];

while ((body_size = read_cmd (buff))> 0) (
fn_idx = buff [0] / * All as described above: the first byte of the body - index / Haydee called function * /

if (fn_idx == IDX_SUM) (/ * int sum (int, int) * /
int arg1, arg2, result;
arg1 = buff [1];
arg2 = buff [2];
result = sum (arg1, arg2);
buff [0] = result;
write_cmd (buff, 1);
)
else if (fn_idx == IDX_SIMPLE_CRYPT) (/ * void simple_crypt (byte *, int) * /
simple_crypt (
buff + 1, / * one long argument … * /
body_size - 1 / * … that’s such a long * /
)
/ *
* By the way, if you too lazy to deal with GDB: debazhitsya be like this:
fprintf (
stderr / * Erlang it does not take into account, but simply transfers to your console * /
“simple_crypt, chunk_size =% i \ r \ n”, body_size - 1
)
* /
write_cmd (buff + 1, body_size - 1);
)
)
return 0;
)

And for dessert …

Now we write Erlang module, which will provide a convenient interface for a call okoyannyh Legacy Functions
%% Before using the functions - it is necessary to run our c_server
start () ->
spawn_link (fun () ->
register (c_server, self ()),
process_flag (trap_exit, true),
Port = open_port ((spawn, “. / C_server”), [(packet, 2)]),% I turned “. / C_server”, as you compile - you decide
loop (Port)
end).
%% Does the reverse of the previous function =)
stop () ->
c_server! stop.

%% Like this, we will ask c_server call sishnuyu function …
call_c_server (Msg) ->
c_server! (call, self (), Msg),
receive
(c_server, Result) ->
(ok, Result)
after
5000 -> (fail, timeout)
end.

%% … No, better like this.
sum (Addee1, Addee2) ->
call_c_server ((sum, Addee1, Addee2)).
simple_crypt (Chunk) ->
call_c_server ((simple_crypt, Chunk)).

%% Serialization =)
pack_buff ((sum, Addee1, Addee2)) -> [1, Addee1, Addee2];% pack two byte-ints for function # 1
pack_buff ((simple_crypt, Chunk)) -> [3 | Chunk]. % Pack byte array for function # 3
%% Deserialization
unpack_buff ([Result]) -> Result;% int return value
unpack_buff (AnyThing) -> AnyThing. % Byte array return value
%% Yeah … easier than in C … =)

%% Directly, dispatcher
loop (Port) ->
receive
( ‘EXIT’, Port, Reason) ->% in case of “Oh!”
exit ((port_terminated, Reason));
stop ->%% stop
Port! (self (), close),
receive
(Port, closed) ->
exit (normal)
end;
(call, From, Msg) ->% that, for what is being written
Port! (self (), (command, pack_buff (Msg))),% kommanduem …
receive
(Port, (data, Data)) ->% rejoice result
From! (c_server, unpack_buff (Data)),
loop (Port);
AnyThing ->% indignant
io: format ( “received invalid message: ~ p ~ n”, AnyThing),
loop (Port)
end
end.

Let’s go! ©

Check what we got.
Run erl-shell.
Eshell V5.6.5 (abort with ^ G)
1> c_server: sum (1, 5).
** Exception error: bad argument
in function c_server: call_c_server / 1
2> c_server: start ().
<0.35.0>
3> c_server: sum (1, 5).
6
4> c_server: simple_crypt ( “Its bean - a heart dace knight”).
[182,139,140,223,157,154,158,145,223,210,223,158,223,151,
154,158,141,139,223,155,158,156,154,223,148,145,150,152,151 |...]
5> c_server: simple_crypt ([182,139,140,223,157,154,158,145,223,210,223,158,223,151,154,158,141,139,223,155,158,156,154,223,148,145,150,152,151,139]).
“Its bean - a heart dace knight”
6> io: format ( “Hooray!”)

Summarize

We were able to bind together the Native code and Erlang.
One question remains: And Haha?
But, Haha - native code could be:
old and ugly, but very necessary
new and highly-optimized code
general, no, we did it for Lulzim

You see, if you start to learn Erlang, you already have as many as three reasons to learn the material in this article. =)

Appendix A. Really very short troubleshooting guide

For those who did not get to run, tell, with what problem I encountered.
We are looking for a piece of code here:
(Port, (data, Data)) ->% rejoice result
From! (c_server, unpack_buff (Data)),
loop (Port);

Harvesting from the loop (Port), and for understandable reasons, we obtain single-shot-library, which needs the start before each call.
At first I was looking for a problem in Cu. I tried to change the properties through fcntl stdin (it seemed to me that he somehow becomes a non-blocking).
A casket was opened just …

Appendix B. Reference

Programming Erlang. Software for a concurrent world.
Joe Armstrong. ISBN-10: 1-9343560-0-X


Check out the analysis of podnapisi.net, segundamano.es, pussy.org, wanadoo.es, xtshare.com, geovisite.com, 000webhost.com, daum.net, 171l.cn, gougou.com - and much more

Related Posts

Posted under Uncategorized by admin on Saturday 3 October 2009 at 3:42 pm

1 Comment »

  1. Trackback by RAYMOND — July 1, 2010 @ 9:49 pm


    Pillspot.org. Canadian Health&Care.Best quality drugs.Special Internet Prices.No prescription online pharmacy. High quality drugs. Order pills online

    Buy:Accutane.Actos.Retin-A.Nexium.Mega Hoodia.Petcam (Metacam) Oral Suspension.Lumigan.100% Pure Okinawan Coral Calcium.Human Growth Hormone.Valtrex.Synthroid.Zyban.Zovirax.Prednisolone.Arimidex.Prevacid….

RSS feed for comments on this post. TrackBack URI

Leave a comment

Fresh information about high speed internet and news from internet service providers