Resource Manager and message passing....

Hello all,

I have successfully created a resource manager that overloads the default functionality for io_read, io_write, and io_devctl.

The system that I am creating my resource managers for needs to be able to send some sort of message to a server (this could be an “empty” message or with some data). The receiver of this message (a resource manager/server) will do some sort of processing and then need to send an abitrarily long result string (char*) back to the process that sent the original message. I am able to use a devctl message to send the data to the server, but I haven’t been able to figure out how to send the result string back. I can do it by preallocating a large buffer that is sent in the original devctl message to be modified by the server, but I don’t like that as it is a kludge.

What I would like to do (assuming devctl’s won’t work in this situation) is have the client use MsgSend() to send a msg with or without data to the server. Then have the server respond with a MsgReply(). Given the prototypes for MsgSend() and MsgReply() they easily support the concept of replying with an arbitrarily sized amount of data to the sender. My dilema with this approach is that I would like to still use Resource managers for other reasons, but I can’t figure out, or find an examples of how to recieve my messages and reply to them in the resource manager code. I understand that internally the resource manager library uses a MsgReceive to deal with all incoming msgs, but I don’t know how to get my msgs to the code I have written so that I can respond in the manner I need to. I would like to do this without breaking any of the standard POSIX functionality resource managers give you ( read(), write(), open(), etc, etc).

Hopefully I have been clear enough. Any and all help would be appriciated.

Note I have read through the pertinent sections of the nto_prog.pdf and “Getting Started with Neotrino 2” but have come up empty in this regard.

Thanks,

Josh

Josh,

You are on the right track.  You can use the resource manager code to deal with standard messages in some manner, and add your own messages.   On the resource side, the trick is that since the resource manager code does all the receives, you have to register your messages.  You pick (an) unused message type(s), and tell the resource code what routine(s) to call when it/they comes in.   On the client side, the magic secret is that the fd that you get from open() is the destination parameter of MsgSend.  I don't have the manual in front of me, so I can't tell you the name of the registration routine, but if that isn't obvious, ask again.

Thanks maschoen for the reply…

Really all I needed was an example…from there I can modify.

At any rate just to help out anyone else who may find this topic useful go read the following page
qnx.com/developers/articles/ … 861_1.html
This article and the source code in it explains exactly what I was asking about.

Thanks again :smiley:

Ok, I hope this skeletal example helps.

Without the benefit of error checking.

// Resource Handler Code
main()
{

// create the dispatch structure
dpp = dispatch_create();
tpp = thread_pool_create(&pool_attr, POOL_FLAG_EXIT_SELF));

...
iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &connect_func,
	_RESMGR_IO_NFUNCS, &io_func);
...
iofunc_attr_init (&attr, 0555, 0, 0);

...

// establish a name in the pathname space
resmgr_attach (dpp, &resmgr_attr, attach_path,
	_FTYPE_ANY, 0, &connect_func, &io_func, &attr);

//******* ATTACH MY MESSAGES HERE! **************
message_attach(dpp, NULL,MSG_LOW, MSG_HIGH,
&message_handler, NULL);

// Should Never Return
thread_pool_start(tpp);

}

int message_handler(message_context_t *ctp, int code, unsigned flags,
void *handle )
{

switch(code)
{
case MY_MSG:
my_routine(ctp->rcvid);
break;

	default:
		MsgReply(ctp->rcvid,ENOSYS,NULL,0);
}
return(_RESMGR_NOREPLY);

}
void my_routine(int rcvid)
{

MsgReply(rcvid,EOK,NULL,0);

}

// CLIENT CODE
main()
{

fd = open(filename,O_RDWR);
...

MsgSend(fd, message, message_reply, sizeof(message), sizeof(message_reply));
...

}

Other method ( which is posix ) is having the client use read() to get the string. It’s not as efficient as getting the data in the reply, ( 2 messages instead of one) but it does allow for getting the string in section ( in case it’s really big). It could work from the shell.

This architecture is also very flexible because it becomes asynchronous. Hence if the string (or whatever return data) takes a long time to generate, the client doesn’t have to block and wait for the data. Splitting the read and write will also ease support for notification.

Thanks Mario for the suggestion. That is one of the approaches I was considering, however the fact that it is now two messages rather than one is something I wanted to avoid, not just for the efficiency sake, but because the data returned by read wouldn’t be the normal data returned by read… if that makes any sense. In either case I didn’t want to add the extra complexity to the system, as it may be maintained in the future by other people.

I like to provide various path entries for specific operation.

Example: I wrote a program to generate pulses on a parallel port ( for encoder simulation). The path space is setup as such:

/dev/encoder/frequency
/dev/encoder/direction
/dev/encoder/counter
/dev/encoder/on_off

That allows control from the shell with command such as:
echo 1000 > /dev/encoder/frequency #set pulse frequency to 1000zh
cat /dev/encoder/frequency #display current frequency

Yet the driver also support devctl command on /dev/encoder for convenience.