The package has be 'beautified' 2002-07-15, and it's easier to understand now. Also no c-code is required anymore, all is in Ada code now. (Did some studying on 'Pragma Import')
This package provides a way of sending telegrams to other processes. It is based on the System V message queue functionality. If you do 'man msgget' and related man pages you'll get the idea, or read Richard Stevens' Network Programming part II IPC.
In short, this is how it works. Your goal is to send or receive messages from a message queue. There are a number of ways to set up this, eg several processes can use the same queue, or each processes can have a queue of their own. This package will work in the latter way.
In order to create a message queue you need to call msgget, which takes 2 parameters.
int msgget(key_t key, int msgflg)
key_t ftok(char *pathname, int proj)(Yes proj is an int, not a char according to the headerfile)
This key_t number is passed to msgget and we get a queue identity. Depending on msgflg, we get different behaviour depending on the queue already exists or not. The package is set up to create the queue if it doesn't exist, with 'file-permissions' set to 664, and return the queue identity. If it already exists, and it is allowed to read from it, it will return the queue identity.
The identity is how we find were to receive from or send messages to.
Some rules apply to use the packages. Each process using it must have a unique process name. This is accomplished by using environment variables. In bash,
export PROCESS_NAME=the_nameNow, the process know what it is called. But ftok needs a file. There is a global constant in the sv_m body 'gcProcess_directory' that points out a directory. All processes using this package must have a file there (could be empty) that is called the same as 'the_name' exported above. Then ftok will be happy.
The nice thing with this package is that you send ordinary Ada records as messages. The packing and unpacking is provided in the package.
There is of course a 'send' and a 'receive' in the package. If the receive is supplied with a time out, then an exception is raised if no messages arrived in that time. Can be used for periodically actions. If no timeout is supplied, the process will sleep until a message arrives.
A tip is to have message definitions in a separate package, including message identities as constants. Then processes could be in a loop, receiving messages and unpack them with the correct datatype by looking at the message identity, perform some action based on the data in the message, and go back to sleep until the next message arrives. A good thing to have is a shutdown message too...
Both send and receive creates a message queue if there was no before the call. Receive creates a queue for the process calling receive, and send creates a queue for the process that will receive the message.
The send part is generic so instansiation must occure. Examples:
package tst is
type bnl is record
a : integer := 10;
b : String(1..3) := "Hej";
c : String(1..1017) := (others => '-');
end record;
end tst;
p1 (p1.ads)
with text_io;
with sv_m;
with tst;
procedure p1 is
package bnl_Package is new sv_m.Generic_io
(Identity => 3000,
Data_Type => tst.bnl);
rec : tst.bnl;
m: sv_m.message_type;
f : integer := 1016;
begin
begin
loop -- empty the queue if it already exists and contains messages.
sv_m.receive(m,0.1);
end loop;
exception
when sv_m.timeout => null;
end;
rec.a := 0;
rec.c(f..f+1) := "BL";
loop
rec.a := rec.a + 1;
bnl_Package.send(("p2 ",(others => ' ')),rec);
sv_m.receive(m,10.0);
rec := bnl_Package.unpack(m);
exit when rec.a >= 100_000;
end loop;
text_io.put_line ("done rec.a " & rec.a'img);
text_io.put_line("c(f..f+1): " & rec.c(f..f+1));
text_io.put_line("f= " & f'img);
text_io.put_line ("c: |" & rec.c & "|");
end p1;
p2 (p2.ads)
with text_io;
with sv_m;
with tst;
procedure p2 is
package bnl2_Package is new sv_m.Generic_io
(Identity => 3000,
Data_Type => tst.bnl);
rec : tst.bnl;
m: sv_m.message_type;
begin
loop
sv_m.receive(m,30.0);
rec := bnl2_Package.unpack(m);
-- text_io.put_line ("rec.a " & rec.a'img);
rec.a := rec.a + 1 ;
bnl2_Package.send(("p1 ",(others => ' ')),rec);
end loop;
exception
when sv_m.timeout =>
text_io.put_line ("done rec.a " & rec.a'img);
end p2;
In order to try this don't forget to change the gcProcess_directory, and add a p1 and p2 file there
(touch p1and p2 will do).
Also, the sv_m body relies on a c-file called sv_m_c.c that must be compiled as well.