Responding to messages

I’ve just started trying to figure out Neutrino, and I’d like a bit of
guidance in inter-process communication.

I’ll be running Neutrino on two embedded computers in one medical
device. One computer will drive a Photon user interface. The other
controls hardware, and the two communicate via ethernet.

I want the UI computer to respond to messages sent by the second
computer, but I haven’t found a good way to do that. I don’t want to
lock the machine up while it waits for messages (ie. using
MessageReceive()). I’d poll for messages if I knew where to put polling
code, but I don’t. I could have a timer-driven thread that checks for
messages, but then I don’t know how to tell the main user-interface
thread to respond to a message if one gets received by the other thread.

In summary, I don’t know how to do what I want. What’s the general
mechanism for detecting and responding to messages? Where should I be
looking in the documentation?

Thanks for your help,

Bruce Knoth

Bruce Knoth <bknoth@erg.sri.com> wrote:

I’ve just started trying to figure out Neutrino, and I’d like a bit of
guidance in inter-process communication.

I’ll be running Neutrino on two embedded computers in one medical
device. One computer will drive a Photon user interface. The other
controls hardware, and the two communicate via ethernet.

I want the UI computer to respond to messages sent by the second
computer, but I haven’t found a good way to do that.

Have a look for the stuff on Input functions in the Photon
programmer’s guide – it’s designed to solve exactly this
problem.


Norbert Black
QSSL Training Services

Thanks,

That looks like the information I was looking for. Now I need help
implementing it. One question I have is “How does a process send a message
to itself?” As detailed below, I’m trying to send a test message to the
process, but it hangs…

I’m using (trying to use) the PtAppAddInput() call to insert a handler for
messages.

I call it with:

pMsgHandler = PtAppAddInput(NULL, getpid(), input_proc, NULL)

which I expect adds input_proc as a message handler to the current process.

Then I try sending a message to myself for test purposes using:

int kk = 33;
int coid;
char buff[33];
coid = ConnectAttach(0, getpid(), 1, 0, 0); // Don’t know how to get the
connection ID for my process, so guess it’s 1
MsgSend(coid, (void *)&kk, sizeof(int), buff, 33);
ConnectDetach(coid);


The program hangs when I send the message, and I have no evidence that my
message-handling function (input_proc()) is getting the message. I don’t
think I am
getting a reply from the message, even though input_proc does send a
MsgReply() as follows (I don’t think input_proc() gets called at all):

char buff[20];
MsgReply(rcvid, 0, buff, 20);

Thanks again,

Bruce




Norbert Black wrote:

Bruce Knoth <> bknoth@erg.sri.com> > wrote:
I’ve just started trying to figure out Neutrino, and I’d like a bit of
guidance in inter-process communication.

I’ll be running Neutrino on two embedded computers in one medical
device. One computer will drive a Photon user interface. The other
controls hardware, and the two communicate via ethernet.

I want the UI computer to respond to messages sent by the second
computer, but I haven’t found a good way to do that.

Have a look for the stuff on Input functions in the Photon
programmer’s guide – it’s designed to solve exactly this
problem.

Norbert Black
QSSL Training Services

Bruce Knoth <bknoth@erg.sri.com> wrote:

Thanks,

That looks like the information I was looking for. Now I need help
implementing it. One question I have is “How does a process send a message
to itself?” As detailed below, I’m trying to send a test message to the
process, but it hangs…

I’m using (trying to use) the PtAppAddInput() call to insert a handler for
messages.

I call it with:

pMsgHandler = PtAppAddInput(NULL, getpid(), input_proc, NULL)

which I expect adds input_proc as a message handler to the current process.

Then I try sending a message to myself for test purposes using:

int kk = 33;
int coid;
char buff[33];
coid = ConnectAttach(0, getpid(), 1, 0, 0); // Don’t know how to get the
connection ID for my process, so guess it’s 1
MsgSend(coid, (void *)&kk, sizeof(int), buff, 33);
ConnectDetach(coid);

This would be a lucky guess (refering to the //Don’t know how to get the
connection id for my process so guess it’s 1), but you shouldn’t count
on it.

The arguments for ConnectAttach() are (from the docs):
-nd (0 is this host)
-pid (0 is this pid)
-chid (This is the ChannelID generated by ChannelCreate() and is
different from the connection id which is the result of
ConnectAttach())
-index (where to start iterating to generate the coid)
-flags

There should be a photon call to get a connection id for the photon
server so that you can do message sends to it to have them dispatched
to your application (so you wouldn’t even call ConnectAttach() your
self in your code). Unfortunately the Photon API is not my area
of expertise so I’ll have to let someone else comment.

Thomas

Norbert Black wrote:

Bruce Knoth <> bknoth@erg.sri.com> > wrote:
I’ve just started trying to figure out Neutrino, and I’d like a bit of
guidance in inter-process communication.

I’ll be running Neutrino on two embedded computers in one medical
device. One computer will drive a Photon user interface. The other
controls hardware, and the two communicate via ethernet.

I want the UI computer to respond to messages sent by the second
computer, but I haven’t found a good way to do that.

Have a look for the stuff on Input functions in the Photon
programmer’s guide – it’s designed to solve exactly this
problem.

Norbert Black
QSSL Training Services

Bruce Knoth <bknoth@erg.sri.com> wrote:

One question I have is “How does a process send a message
to itself?” As detailed below, I’m trying to send a test message to the
process, but it hangs…

I’m just the GUI guy, so I’m a bit insulated from some of this
level of stuff (and I still tend to think in QNX4…), but it
strikes me that this is to be expected, at least so long as the
program is single threaded. MsgSend() is a blocking call, and if
your program is blocked, it can’t get to the MsgRead() that
exists in the photon library that would unblock itself.

If what you’re trying to do is test to see if you’ve got your
input handler set up correctly, you’d be better off writing a
tiny test app that MsgSend()'s to your GUI.

Norbert Black
QSSL Training Services

If what you’re trying to do is test to see if you’ve got your
input handler set up correctly, you’d be better off writing a
tiny test app that MsgSend()'s to your GUI.

Thanks, that sounds like what I want to do. Now how do I get the channel ID
for the Photon app? I’m using getpid() to get the process ID. Once I get the
ChannelID, I’ll write both to an ASCII file and read them into my other app,
then test message send. I can’t figure out how to get the channel ID for my
Photon app, though.

Thanks for your help -

Bruce

Bruce Knoth <bknoth@erg.sri.com> wrote:

If what you’re trying to do is test to see if you’ve got your
input handler set up correctly, you’d be better off writing a
tiny test app that MsgSend()'s to your GUI.

Thanks, that sounds like what I want to do. Now how do I get the channel ID
for the Photon app?

For one process to find another, it needs a connection id (coid)
This is usually obtained via ConnectAttach(), which requires both
process id (pid) and channel id (chid).

There are three ways to find another process:

  1. a parent-child relationship: parent passes chid in
    command line arguments when spawning child, and receives
    pid as a return value

  2. have a “starter” process which creates a channel and
    spawns everybody, passing them its chid in command line
    arguments

  • receivers send their chids to starter
  • senders request chids from starter
  1. have the GUI register a name via name_attach() and have
    the sender look up the name using name_open(), which
    returns a connection id

The server does:
name_attach_t *attach;
attach = name_attach( NULL, “myname”, 0 );
PhChannelAttach( attach->chid, -1, NULL );
// handle IPC until you want to go offline

The client does:
coid = name_open( “myname”, 0 );

MsgSend( coid, &msg, sizeof(msg), NULL, 0 );

Does that help?


Norbert Black
QSSL Training Services

I’m trying the name_attach method. What does your comment “// handle IPC until
you want to go offline” mean? Is it like this example from the QNX docs?

/* Create a local name (/dev/name/local/…) */
if ((attach = name_attach(NULL, ATTACH_POINT, 0)) == NULL) {
return EXIT_FAILURE;
}

/* Do your MsgReceive’s here now with the chid */
while (1) {
rcvid = MsgReceive(attach->chid, &msg, sizeof(msg), NULL);

if (rcvid == -1) {/* Error condition, exit */
break;
}

if (rcvid == 0) {/* Pulse received */
switch (msg.hdr.code) {
case _PULSE_CODE_DISCONNECT:



If so, how do I keep the rest of my photon app running without hanging on the
MsgReceive() call? Is there a way to take advantage of a message handler added
through PtAppAddInput()?


Thanks,

Bruce



  1. have the GUI register a name via name_attach() and have
    the sender look up the name using name_open(), which
    returns a connection id

The server does:
name_attach_t *attach;
attach = name_attach( NULL, “myname”, 0 );
PhChannelAttach( attach->chid, -1, NULL );
// handle IPC until you want to go offline

The client does:
coid = name_open( “myname”, 0 );

MsgSend( coid, &msg, sizeof(msg), NULL, 0 );

Does that help?

Norbert Black
QSSL Training Services

Bruce Knoth <bknoth@erg.sri.com> wrote:

I’m trying the name_attach method. What does your comment “// handle IPC until
you want to go offline” mean? Is it like this example from the QNX docs?

Oh, sorry – guilty of being too terse there (I snatched that bit
of sample from one of the course slides, which assume you already
know about the mechanics of input function.

Here’s the entire contents of “callbacks.c” from the receiver
half of a sender/receiver pair. Hopefully this will get you over
that hump. The key thing to remember (I think the docs
mention this) is that Photon processes don’t do a MsgReceive()
in user-written code – the receiving end of the send/receive
link is in the photon library, done for you by the PtMainLoop()
code.

******************** begins ****************************
/* callbacks.c /
/
/
/
This application demonstrates how to receive messages /
/
from other processes. The “sender_nameattach” /
/
application is meant to be used as the message /
/
sender. /
/
/
/
This module contains: /
/
/
/
base_windowclosingCB /
/
Function type: Pt_CB_WINDOW_CLOSING /
/
Widget: base /
/
/
/
Operation: /
/
This function detaches the name we attached at /
/
startup /
/
/
/
-------------------------------------------------------/
/
/
/
init() /
/
Function type: Application Initialization Function /
/
Widget: base /
/
/
/
Operation: /
/
This attaches a name that other processes /
/
(in particular, sender_nameattach) can use to /
/
find us. Note that this requires us to include /
/
the header <sys/dispatch.h> /
/
/
/
We also set up an input function to handle /
/
incoming messages /
/
/
/
-------------------------------------------------------/
/
/
/
inputFunction() /
/
Function type: Input Function /
/
Widget: N/A /
/
/
/
This function demonstrates a simple input function. /
/
/
/
Operation: /
/
This function simply displays whatever text it /
/
receives using a PtLabel widget. /
/
*/

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/neutrino.h>

/* header required to use name_attach */
#include <sys/dispatch.h>

/* Toolkit headers */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>

/* Local headers */
#include “abimport.h”
#include “proto.h”

/* Application Options string /
const char ApOptions[] =
AB_OPTIONS “”; /
Add your options in the “” */


char progname = “inputfunc_nameattach”; / the name others will use
to find us */
name_attach_t attach; / structure describing our attached name /


/
----------------------------------------------------------------------
*

  • base_windowclosingCB

--------------------------------------------------------------------/
int
base_windowclosingCB( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo )
{
name_detach( attach, 0 );

/* eliminate ‘unreferenced’ warnings */
widget = widget, apinfo = apinfo, cbinfo = cbinfo;

return( Pt_CONTINUE );
}


/*----------------------------------------------------------------------
*

  • init - Application initialization function.

---------------------------------------------------------------------/
int
init( int argc, char argv[] )
{
/

  • attach a name so that other processes can find us
    /
    if( (attach = name_attach( NULL, progname, 0 ))
    == NULL )
    {
    ApError( ABW_base, 0, progname,
    “failed name_attach()”, NULL );
    exit( EXIT_FAILURE );
    }


    /
  • let the Photon library know that it’s supposed to watch
  • the channel associated with the name we’ve attached
    /
    PhChannelAttach( attach->chid, -1, NULL );


    /
  • set up the input function so that it will be called whenever
  • a message is received that is not for Photon; note the “0”
  • as second parameter – we want to be called in response to
  • messages from any process at all
    /
    PtAppAddInput( NULL, 0, inputFunction, NULL );


    /
    eliminate ‘unreferenced’ warnings */
    argc = argc, argv = argv;

return( Pt_CONTINUE );
}

/*----------------------------------------------------------------------
*

  • inputFunction

--------------------------------------------------------------------/
int inputFunction( void *data, pid_t rcvid, void message, size_t size )
{
PtArg_t arg[1];
static int count = 1;
/

  • treat the message as if it were a simply NULL terminated string.
  • Display this string using a PtLabel widget.
    */
    PtSetArg( &arg[0], Pt_ARG_TEXT_STRING, (char *)message, 0 );
    PtSetResources( ABW_base_lbl_displaymessage, 1, arg );

printf( “input function called %d times\n”, count++ );

/*

  • reply to the sender
    */
    MsgReply( rcvid, 0, NULL, 0 );

/* eliminate ‘unreferenced’ warnings */
data = data, size = size;

return( Pt_CONTINUE );
}

********************* ends *****************************


Clearer?


Norbert Black
QSSL Training Services

Thanks, that helped immensely! I now have my test app working. I push the button on one
app and the second app responds to the message.

I haven’t done the research yet, but any quick pointers on how to do the same thing with
the apps on separate machines on the network?

Thanks again - I was tearing my hair out over this message stuff.

Bruce

Norbert Black <nblack@qnx.com> wrote:

Bruce Knoth <> bknoth@erg.sri.com> > wrote:
If what you’re trying to do is test to see if you’ve got your
input handler set up correctly, you’d be better off writing a
tiny test app that MsgSend()'s to your GUI.

Thanks, that sounds like what I want to do. Now how do I get the channel ID
for the Photon app?

For one process to find another, it needs a connection id (coid)
This is usually obtained via ConnectAttach(), which requires both
process id (pid) and channel id (chid).

There are three ways to find another process:

  1. a parent-child relationship: parent passes chid in
    command line arguments when spawning child, and receives
    pid as a return value

You also need the channel ID – a Photon app can know its
channel ID from PtChannelCreate(). (The reason it’s called
PtChannelCreate() rather than something like PtGetChannelId() is
because it will create a channel if you don’t have one already;
but if you have called PtAppAddInput(), you do.)

  1. have a “starter” process which creates a channel and
    spawns everybody, passing them its chid in command line
    arguments
  • receivers send their chids to starter
  • senders request chids from starter
  1. have the GUI register a name via name_attach() and have
    the sender look up the name using name_open(), which
    returns a connection id

The server does:
name_attach_t *attach;
attach = name_attach( NULL, “myname”, 0 );
PhChannelAttach( attach->chid, -1, NULL );
// handle IPC until you want to go offline

A bit of a warning here: I consider this a little bit of a hack. It
appears to work, but I have never made sure that the channel that
name_attach() or the dispatch functions create has all the setting
required to support all the functionality of the Photon library.

  1. If both your processes are Photon applications, you might want to
    consider using the Photon connection API (look up
    PtConnectorCreate() in the docs and follow the link to
    “Connections”). This API registers the names with the Photon server
    rather than the process manager, and thus lets you have an instance
    of the name per Photon session rather than per machine. This can be
    significant when you’re running multiple Photon sessions in a single
    machine (i.e. a “Phindows server”) or have (when Photon eventually
    supports it) applications running on different machines attached to
    the same Photon session.



    Wojtek Lerch (wojtek@qnx.com) QNX Software Systems Ltd.

Wojtek Lerch <wojtek@qnx.com> wrote:

attach = name_attach( NULL, “myname”, 0 );
PhChannelAttach( attach->chid, -1, NULL );

… but I have never made sure that the channel that
name_attach() or the dispatch functions create has all the setting
required to support all the functionality of the Photon library.

I guess what I really meant is that I doubt anybody has ever made sure
that name_attach() creates its channel with 100% Photon-compatible
settings. While it seems to work, some more exotic features have never
been tested. My main suspicion is that the channel flags are not quite
right, the PtConnection API might fail to report certain errors. But
you probably won’t be mixing name_attach() with PtConnection anyway…


Wojtek Lerch (wojtek@qnx.com) QNX Software Systems Ltd.

Wojtek:
I have been using the technique suggested by Norbert using the name_attach
and then the PhChannelAttach() without any problems. However, since you had
pointed out that this was really a hack and not guaranteed, I looked for
another way to accomplish something similar - i.e. easily publish the main
channel of a Photon app via the “name_xxxx” capability. Unfortunately, I ran
into a problem that perhaps you can explain.

The basic idea is to
(a) - In the initialization function, determine the channel id - using
PtChannelCreate() and record it in a global
(b) - Start off a separate thread that creates its own channel/published
name combination through name_attach()
(c) - Any client can then MsgSend to the subordinate thread requesting the
“main” channel id and can then communicate directly using this main channel
id.

Unfortunately - doing the following:

pid_t gMainChannel;

int Init( int argc, char *argv[] ) // PhAB Initialization function
{
name_attach_t *pInfo;

/* eliminate ‘unreferenced’ warnings */
argc = argc, argv = argv;

gMainChannel = PtChannelCreate();

pInfo = name_attach(NULL,MYNAME,0);
if ( pInfo == NULL )
{
printf ( “Name attach failed on %s - errno: %d\n”, MYNAME, errno);
PtExit(-1);
}

causes the name_attach to fail with an errno 16, (EBUSY) - whether I call it
here or in a separate thread


Strangely enough, if I do the following:

int Init( int argc, char *argv[] )
{
name_attach_t *pInfo;

/* eliminate ‘unreferenced’ warnings */
argc = argc, argv = argv;

// Create my own channel from a name and use it as the main photon thread
pInfo = name_attach(NULL,MYNAME_MAIN,0);
if ( pInfo == NULL )
{
printf ( “Name attach failed on %s - errno: %d\n”, MYNAME_MAIN, errno);
PtExit(-1);
}
gMainChannel = pInfo->chid;
PhChannelAttach(gMainChannel, -1, NULL);

gpInputApp = PtAppAddInput(NULL,0,InputFunc,NULL);


pInfo = name_attach(NULL,MYNAME_OTHER,0);
if ( pInfo == NULL )
{
printf ( “Name attach failed on %s - errno: %d\n”, MYNAME_OTHER, errno);
PtExit(-1);
}

So, If I allow the Photon library to do its thing and get its channel
through PtChannelCreate(), I am prevented from successfully calling
name_attach(). However if I use name_attach(), get a channel and tell the
Photon library to make use of that channel, I’m able to continue using
name_attach to create other channels.

Also, if I try the name_attach() first and then call PtChannelCreate(), the
latter returns a (-1).

What am I missing here

Thanks
Lionel


“Wojtek Lerch” <wojtek@qnx.com> wrote in message
news:93pr29$jf8$1@nntp.qnx.com

Wojtek Lerch <> wojtek@qnx.com> > wrote:
attach = name_attach( NULL, “myname”, 0 );
PhChannelAttach( attach->chid, -1, NULL );

… but I have never made sure that the channel that
name_attach() or the dispatch functions create has all the setting
required to support all the functionality of the Photon library.

I guess what I really meant is that I doubt anybody has ever made sure
that name_attach() creates its channel with 100% Photon-compatible
settings. While it seems to work, some more exotic features have never
been tested. My main suspicion is that the channel flags are not quite
right, the PtConnection API might fail to report certain errors. But
you probably won’t be mixing name_attach() with PtConnection anyway…


Wojtek Lerch (> wojtek@qnx.com> ) QNX Software Systems Ltd.

Lionel Johnson ljohnson**nospam**@sterling1.com wrote:

Unfortunately - doing the following:

gMainChannel = PtChannelCreate();

pInfo = name_attach(NULL,MYNAME,0);

causes the name_attach to fail with an errno 16, (EBUSY) - whether I call it
here or in a separate thread

So, If I allow the Photon library to do its thing and get its channel
through PtChannelCreate(), I am prevented from successfully calling
name_attach(). However if I use name_attach(), get a channel and tell the
Photon library to make use of that channel, I’m able to continue using
name_attach to create other channels.

Also, if I try the name_attach() first and then call PtChannelCreate(), the
latter returns a (-1).

What am I missing here

The problem is that both PtChannelCreate() and name_attach() want to
create their channels with the _NTO_CHF_COID_DISCONNECT and
_NTO_CHF_DISCONNECT flags, and the kernel only lets one channel per
process to have those flags.

If you do want your app to have two channels, one for Photon stuff and
the other for the name_attach() stuff, you will have to create your own
channel without the DISCONNECT flags and give that channel to
PhChannelAttach(). This will allow name_attach() to create its channel.
But as I said before, this may break some rarely used Photon mechanisms
that rely on the pulses that those flags enable.

\

Wojtek Lerch (wojtek@qnx.com) QNX Software Systems Ltd.

Wojtek:

“Wojtek Lerch” <wojtek@qnx.com> wrote in message
news:96edql$t7u$1@nntp.qnx.com

Lionel Johnson ljohnson**nospam**@sterling1.com wrote:

Unfortunately - doing the following:

gMainChannel = PtChannelCreate();

pInfo = name_attach(NULL,MYNAME,0);

causes the name_attach to fail with an errno 16, (EBUSY) - whether I
call it
here or in a separate thread

So, If I allow the Photon library to do its thing and get its channel
through PtChannelCreate(), I am prevented from successfully calling
name_attach(). However if I use name_attach(), get a channel and tell
the
Photon library to make use of that channel, I’m able to continue using
name_attach to create other channels.

Also, if I try the name_attach() first and then call PtChannelCreate(),
the
latter returns a (-1).

What am I missing here

The problem is that both PtChannelCreate() and name_attach() want to
create their channels with the _NTO_CHF_COID_DISCONNECT and
_NTO_CHF_DISCONNECT flags, and the kernel only lets one channel per
process to have those flags.

Wouldn’t your statement also imply that one would be unable to do more than
one name_attach() within the same process as each call to name_attach()
would produce a separate channel each with the *_DISCONNECT flags set? But,
yet, I am quite able to do this. In fact, in the examples given previously,
if I do a name_attach() and then use PhChannelAttach(), I can still go ahead
and make subsequent successful calls to name_attach().
Lionel


If you do want your app to have two channels, one for Photon stuff and
the other for the name_attach() stuff, you will have to create your own
channel without the DISCONNECT flags and give that channel to
PhChannelAttach(). This will allow name_attach() to create its channel.
But as I said before, this may break some rarely used Photon mechanisms
that rely on the pulses that those flags enable.

\

Wojtek Lerch (> wojtek@qnx.com> ) QNX Software Systems Ltd.

Lionel Johnson ljohnson**nospam**@sterling1.com wrote:

“Wojtek Lerch” <> wojtek@qnx.com> > wrote in message
The problem is that both PtChannelCreate() and name_attach() want to
create their channels with the _NTO_CHF_COID_DISCONNECT and
_NTO_CHF_DISCONNECT flags, and the kernel only lets one channel per
process to have those flags.

Wouldn’t your statement also imply that one would be unable to do more than
one name_attach() within the same process as each call to name_attach()
would produce a separate channel each with the *_DISCONNECT flags set? But,
yet, I am quite able to do this. In fact, in the examples given previously,
if I do a name_attach() and then use PhChannelAttach(), I can still go ahead
and make subsequent successful calls to name_attach().

From a quick look at the library code, it seems that the dispatch stuff
knows that a there is dispatch_t structure whose channel has the
DISCONNECT flags, and therefore the subsequent calls to name_attch()
don’t attempt to set the flags. But, unfortunately, the dispatch
library neither knows nor cares about Photon…

\

Wojtek Lerch (wojtek@qnx.com) QNX Software Systems Ltd.