From: "David L. Hawley" 
Subject: Re: AmigaOS and QNX... Hmmm...  Tell me more...
Date: 25 Nov 1998 19:17:59 GMT

Mitchell Schoenbrun  wrote:
: Thomas Weeks  wrote:
: > I assume you guys have a FAQ?

: You can browse around at www.qnx.com.  I maintain a faq that you
: can find at www.schoenbrun.com/mba.

Look at http://www.qnx.com/literature/nto_sysarch/nto_sysarch.html
for a good intro to Neutrino (Nto).

The key aspects of all versions of QNX are that there is a small kernel
which implements a handful of calls for creating a process, sending a
message, handling timers and so on. Everything else is a process (thread
or groups of threads in Nto). Message passing is the most interesting
aspect.

A file system (media or pseudo media) consists of a process which "talks"
to the hardware and implements calls such as open(), close(), read(),
write()... as well as defines a portion of "namespace" such as /dev/fd0 -
the first floppy drive. In QNX4, if we insert a floppy with a QNX file
system on it, we'd start Fsys.floppy (which creates /dev/fd0) and then
do something like:

  mount /dev/fd0 /a

which will create a prefix "/a" where we now see the floppy files. On the
otherhand, if the floppy has a fat16 or fat32 file system, we'd need to
run Fsys.dos which will use Fsys.floppy in block mode and present us with
a directory /dos/a.  The reason I used pseudo above is that I can also
write a process called something like ISAMfsys which might manage a set of
disk blocks (or files) as an ISAM file system. Two classic QNX4 examples
of pseudo file systems are:

1. Knews - which maps a subset of the standard file system for use with
news readers. The basic concept is to group all articles received in a
particular news feed into 1 "real" file per day, but present a files
system to the news reader which looks like 1 file per article. On a busy
news group this could reduce the number of files by an order of magnitude
or more. This is in /usr/free on ftp.qnx.com

2. Disk Shadow - maps 2 file systems into 1 (a poor man's RAID) opens,
writes, ... of the Disk Shadow file space map into 2 opens, ...
see: http://www.rtts.com.au/diskshad.html.

In QNX, the device driver is a standard process. It can be debugged using
printf(), trace(), or a debugger. A driver for an audio card may present
several interfaces: /dev/dsp, /dev/mix, /dev/midi. A program wanting to
use the device just opens it and does reads, writes, seeks, ioctls as
needed. A shell (cli) might do something like:

        cat /home/dlh/blab.wav > /dev/dsp

to play the blab file on the sound card. I suppose one could do something
like cat < //2/dev/dsp > //1/dev/dsp to listen in on what's happening on
node 2.

OK - where does this QNX message passing come in? Look at (and I admit
that my model is mostly QNX4 based) an open( "/dev/dsp", O_WRONLY ). You
find that after a bit of preliminary magic (calls into Proc to find the
owner of /def/dsp), the write() does a Send() to the Audio process with
some info to tell Audio that a write mode open is requested. Audio will
Reply() with a new file descriptor (or an error). writes() have less
overhead since we know the Audio process id, and map to a Sendfd() call.
Send() and Sendfd() are kernel calls which cause our process to block, and
if Audio is in a Receive() state, the kernel schedules it to run and it's
Receive() call returns with the data from our write call copied into it's
buffers. Audio does it's stuff with the data and Reply()'s to us. The
Reply() returns to a ready state. If Audio was not is a Receive() state,
then we are blocked until it is. Our message is queued with any other
Sends() into Audio. Audio can set itself to run at the priority of the
highest priority process waiting on it to prevent priority inversion.

Note that I said that the write data is copied into audio's buffers. QNX
Send(), Receive(), Reply() calls pass copies of the buffers passed, not
just pointers. This has several important implications:

- a small bit of extra overhead (but if you hate this, pass a pointer to
shared memory).

- Neither process can access buffers in the other, so it's hard to trash
the other process.

- QNX Networking pretty much falls out. The Net process (and drivers for
the specific hardware) can intercept the data and pass it to a process on
an other node. In QNX4 a virtual circuit is set up to pass the Send(),
Receive(), Reply() data between the processes - they don't really know
that the IPC is going across the net. Note: your pointer to memory mapped
data is useless in this case unless you write a memory map process which
does network copies (a reasonable Nto thing to do).

In QNX2 and QNX4, a lot of us the low level Send(), Receive(), Reply()
calls. In Nto it's a lot easier to use the open(), read(), write() calls.
It's also easier to write device drivers.

If you look at the Nto kernel calls, you will see that they are a more or
less orthogonal superset of the QNX4 equivalents.  I think that the
original idea was that Nto would slide in under the QNX4 kernel and
replace it.  For better or worse, a lot of the low level messages
structures were "optimized", so this is going to be difficult.

Both QNX4 and Nto are POSIX os's. POSIX is essentially standardized UNIX.
several POSIX standards are defined including utilities, calls, and
threads. The thread standard was not approved when QNX4 was written. POSIX
compliance means that POSIX code, shell scripts and so on are more or less
portable.

--
David L. Hawley       D.L. Hawley and Associates    1(503)274-2242
Software Engineer                            dlhawley@teleport.com