“Bill Caroselli (Q-TPS)” <QTPS@earthlink.net> wrote:
“Jim Douglas” <> jim@dramatec.co.uk> > wrote in message
news:aicea3$qf6$> 1@inn.qnx.com> …
… except that QNX 6 “prefers” resource managers
whereas in QNX 4 you rolled your own.
And above all cut the generalisation when it comes to resource managers -
let’s have some really useful examples from real life. Convince me that
they
will make my life easier and that they are not just some theoretical
construct dreamed up by Dan Dodge on a wet Sunday afternoon.
OK. I’m the 4 is better than 6 guy. But I will admit I love the ‘idea’ of a
resource manager. BTW, I loved it in QNX4 too.
I love the idea that instead of having to maintain a phonebook of pid
(nameloc in QNX4) you can just open() a file. That’s gives you a file
descriptor that you can use to communicate through. BUT, it seems to only
make sense to me for 1) establishing the connection, and 2) streamed I/O.
The technique really falls on it’s face in a transaction based client/server
application.
Why does it fall in it’s [sic] face?
What don’t you like about it?
To me it makes much more sense to fill in a struct that contains a request,
necessary data to perform the request and then just send the request. When
the send returns you have your reply. Using functions like ioctl() and
devctl() just seem like trying to shoehorn a fire engine into bottle cap.
devctl() is a very thin layer on top of MsgSend(); you still fill in a struct
that contains your request and the necessary data, and then when devctl()
returns you have your reply (he said, paraphrasing). What it buys you is
portability – I’ve ported 60k lines of Windoze drivers, which abstracted all
their IPC to the “driver” via DeviceIOControl(), and boy was it easy to make
that fit into devctl()! Yes, it would have been almost as easy to make it
fit into MsgSend(), but then I’d be shoehorning it into a QNX 6-ism…
The resource manager DOES have it’s place. It’s just not the end all to
IPC. I liked QNX4 because of it’s IPC. I think QNX6 is trying to make
everything look like a stream so that this open()/read()/write()/close()
will work from anywhere to anywhere. And I think it’s a mistake.
I’m going to have to disagree with you there, Bill. I think having two address
spaces (the QNX 4 PID space and the namespace) just makes things less, if you’ll
pardon the OO $10 word, “orthogonal”. An open() returns a fd, which is
your connection ID – do with it as you please. If you want to be POSIX
source code compatible, by all means use read()/write()/devctl() et al., but
if you want to be QNX 6 compatible, use MsgSend and _IO_MSG…
The main advantage, as I see it, of doing the whole read()/write() thing is that
you can now test, control, and exercise your resmgr from a shell script using
such tools as “cat” and “grep” – if you and QSSL will excuse a parody here,
but “QNX 6 is what QNX 2 was meant to be” [it’s a long story]
I look at it this way. There are low level function and high level
functions. The high level functions use the low level functions to
accomplish work for a client(caller). They provide an easier to use
interface then the many lower level functions at the cost of a little extra
overhead. But when the lower level functions are easier to use than the
higher level function, then that is the way to go.
Certainly. However, I’m sure you’d agree that for maximum portability, and
maintainability, testability, and other such desirables, you’d still want a small,
thin, layer on top of the low-level or (native) high-level calls.
Rarely, in a properly constructed (more than 1k line) program, would you depend
on the raw OS calls to achieve your functionality directly. You’d want to
provide a high-level API, which, if you’re using QNX 6, happens to map almost
directly onto MsgSend with _IO_MSG, or if you’re using Windoze maps almost
directly onto DeviceIOControl, or if you’re using UNIX maps almost directly
onto devctl(), etc… If your application is big, say > 10k lines, then the
high level calls would map to low level calls within the API, which would
then map to OS calls in an OS-abstraction layer.
Sure read()/write() are easy to use. But only if a streaming IO model fits
your applications.
Ahhh… that’s the problem, is it? I’m not advocating read()/write() as
the be-all and end-all to every problem. I’m advocating #1) abstraction,
abstraction, abstraction, and #2) applicable API calls. If you want to
transfer bulk data, then by all means write your own API calls to do this – you
may end up using shared memory, TCP/IP, RPC, or some other thing underneath
the calls, but that’s fine, you’re still achieving the same end result – you
have a shippable, testable product at the end.
And, to sum it up, whatever happened to the UNIX 1970’s concept of “everything
is a stream of bytes”? I personally think it’s a beautiful, clean concept.
But then I just returned from the QNX Users Group meeting
Cheers,
-RK
\
Robert Krten, PARSE Software Devices +1 613 599 8316.
Realtime Systems Architecture, Books, Video-based and Instructor-led
Training and Consulting at www.parse.com.
Email my initials at parse dot com.