13.2. QNX 4 Interprocess Communication (IPC)

QNX 4 interprocess communication is a popular mechanism for 'talking' between software modules, based on the QNX 4 operating system. QNX 4's microkernel architecture implements message passing in such a way that only data locations are transferred between processes, making its IPC for small amounts of data as, or more, efficient than shared memory schemes. Gamma encapsulates most of the common QNX 4 IPC 'C' function calls.

Functions such as qnx_receive and qnx_reply may be redundant in a program that is using one of Gamma's built-in event-loop mechanisms. To review the built-in functionality of Gamma's event loops refer to the section on event loops.

The qnx_name_attach function attaches a 'name' to the current process. Names, rather than PIDs, are convenient ways to look for tasks since they are static while the PID of a program will not be.

Names are ASCII strings up to 32 character in length and can be either local or global. Local names must be unique to the node. Any attempt to register an existing local name will fail. Global names allow duplication and start with a slash '/' character. Global names are stored within a name datahub in QNX 4 called nameloc. When one process wants to look up another process's name, the qnx_name_locate function is called and the name to PID mapping is completed.

Gamma> myname = qnx_name_attach(0,"my_app");
20
	

The first argument to the qnx_name_attach function is the node on which to register the name. If the node number is zero the local node is assumed. qnx_name_attach returns a name id which is used with the qnx_name_detach function.

The qnx_name_detach function removes a local or global name from the local name list or global datahub.

Gamma> qnx_name_detach(0,myname);
t
	  

As with the qnx_name_attach function, the first argument to the qnx_name_detach function is the node number. The second argument must be the name id returned when attaching the name.

Once a name is registered then the qnx_name_locate function is useful for locating the task by name. The return value of this function is a dotted list of the format: (pid . copies) The pid is the process ID of the located task and copies is the number of processes that matched the name. Local names must be unique but there can be multiple instances of global names (those starting with '/').

An example of using the qnx_name_locate function follows:

Gamma> queue = qnx_name_locate(0,"qserve",0);
(91 . 1)
	

The PID of the qserve task is 91 and there was a single instance of that registered name found.It is important to assign the return value of the qnx_name_locate function to a variable since it is the first number in the list (PID) that is used as an argument to Gamma functions such as qnx_send, qnx_receive, qnx_reply, qnx_vc_attach, and qnx_vc_detach.

The qnx_receive function allows for the Gamma engine to remain receive-blocked on a specific PID, waiting for a message.

IMPORTANT: If Gamma is being run using a built-in event loop or using the next_event or next_event_nb functions then using the qnx_receive function MAY BE REDUNDANT. Event loops in Gamma have a built-in receive/reply mechanism.

The qnx_send function uses the QNX 4 send C/C++ function to send information between tasks. The qnx_send function is a synchronous IPC function, and as such, the sending task waits for the receiving task's reply before continuing.

The qnx_send function can be used to send Gamma expressions between Gamma modules. Gamma ships with a number of example programs, of which example 12 demonstrates the use of qnx_send to transmit and execute a function on another module. (Examples can be found in /usr/cogent/examples/ directory)

The important excerpts from this example are:

task = car (qnx_name_locate (0, "gui", 1000));
qnx_send (task, stringc (#Arc.fill_color = PgRGB(0xff, 0xff, 0)));
function TitleClock()
{
    win.title = date();
}
// Transmit new function
qnx_send (task, stringc (TitleClock));
// Execute new function once.
qnx_send (task, stringc (#TitleClock()));
	

The communications channel is opened by locating the task using the qnx_name_locate function and then using qnx_send. The first qnx_send sends a command for the receiving task to evaluate, in this case to change the fill color of an object named 'Arc'. The stringc function is used to produce an expression that is parse-able.

Next, a new function is defined, passed, and executed on the other task using two separate qnx_send's.

If you are sending IPC messages to a non-Cogent IPC task the send_string and send_string_async functions should be used.