[comp.os.mach] Combining UNIX-style and MACH-style messaging

ken@gvax.cs.cornell.edu (Ken Birman) (03/27/90)

Joe Boykin at Encore answered my questions as follows:
  1) I can't get "select" to run on a Mach port; have to fork off a thread
     for each port-set on which I want to do a read (or perhaps for each
     port) and structure my code to interrupt the select if a message comes
     in this way.
  2) I need to use the environment manager to pass the receive rights,
     or build some equivalent mechanism into ISIS to map from ISIS addresses
     to mach ports.
My guess is that (1) translates to a lot of code for me, (2) seems pretty
straightforward.

Probably, I will do this, but as an aside to the Mach group let me make
the following points.  For a project like mine, there is no major advantage
to Mach except speed: it is a more elegant operating system, granted, but
my code already was working just fine, and portability is very important to
me.  So, to the extent that I specialize I am going to have to combine UNIX
and Mach features, and will do it mostly for some overwhelming performance
advantage.

The scheme Joe outlined actually implies a fairly substantial amount of 
code in ISIS: I would estimate 1-2 weeks full time for someone without
much Mach experience.

On the other hand, if Mach offered me an AF_MACH socket type from UNIX,
I could benefit from Mach performance without adding a zillion ifdef's
to use the various special Mach facilities that I seem unable to avoid.

As I see it, there seems to be some inconsistency between Rick (who 
recently explained that he views Mach as a core system, with interfaces
like UNIX, VMS, and even OS/2 layered around it for those who want them)
and Joe, who seems to be more of a purist (if you want the speed, do it
our way).  Personally, I want do minimize the amount of work I do and
maximize portability for my UNIX code, while also benefiting from Mach
performance...  And, the bottom line is that this will only benefit
ISIS users who run ISIS over Mach: a small minority of our community.

So how about it, Rick?  Why not give me an AF_MACH socket type and
a make_unix_fdes(port-no) system call, so that I can do select and
just hack my recvfrom/sendto code... I bet that there are more people
like me than you realize.  Sure, I like your system, but I'm just too
busy to do everything differently to make use of it.  And, unless a lot
of people do redo things, it looks to me as if the major Mach advantages
are very hard to "experience" without a big investment.   That is, if
you are doing UNIX over Mach, why not do it right?

Ken

avie@wb1.cs.cmu.edu (Avadis Tevanian) (03/27/90)

In article <39068@cornell.UUCP> ken@cs.cornell.edu (Ken Birman) writes:
>So how about it, Rick?  Why not give me an AF_MACH socket type and
>a make_unix_fdes(port-no) system call, so that I can do select and
>just hack my recvfrom/sendto code...

Well, if you were to do this you'd end up throwing away most of the performance
gains you are after.  One advantages of the Mach interface is that you
can effectively combine the UNIX select/recv into just one call, msg_receive.

Besides, the code is actually not that difficult.  The way we do this in
NextStep is to assume that the majority of communication occurs using
Mach IPC (it does).  All of the main pathways are IPC based, if someone also
wants to wait on a fd, a separate thread does the select and sends a message
to the main thread with data is available.  The common case is super fast,
the less common case is not a lot slower than it was before (the additional
context switch is negligible when compared to the costs of the write/select/
read).
-- 
Avadis Tevanian, Jr.    (Avie)
Manager, System Software
NeXT, Inc.
avie@NeXT.COM

Richard.Draves@CS.CMU.EDU (03/29/90)

> Excerpts from netnews.comp.os.mach: 26-Mar-90 Re: Combining UNIX-style
> an.. Avadis Tevanian@wb1.cs.c (1094)

> In article <39068@cornell.UUCP> ken@cs.cornell.edu (Ken Birman) writes:
> >So how about it, Rick?  Why not give me an AF_MACH socket type and
> >a make_unix_fdes(port-no) system call, so that I can do select and
> >just hack my recvfrom/sendto code...

> Well, if you were to do this you'd end up throwing away most of the
> performance
> gains you are after.  One advantages of the Mach interface is that you
> can effectively combine the UNIX select/recv into just one call,
> msg_receive.

Avie makes a good point here.  select() is a hefty performance hit, and
combining select/receive into a single msg_receive is a big win. 
Another optimization you should try for is combining send/receive into a
single msg_rpc.  This avoids another system call and lets the kernel use
a more efficient path through the scheduling code.

> Besides, the code is actually not that difficult.  The way we do this in
> NextStep is to assume that the majority of communication occurs using
> Mach IPC (it does).  All of the main pathways are IPC based, if someone
> also
> wants to wait on a fd, a separate thread does the select and sends a
> message
> to the main thread with data is available.  The common case is super
> fast,
> the less common case is not a lot slower than it was before (the
> additional
> context switch is negligible when compared to the costs of the
> write/select/
> read).

It is a little more complicated, but it is possible to avoid the
performance hit for the socket operations.  I'm assuming your server
code isn't written to be multi-threaded, so the easiest approach (having
multiple server threads processing requests from different sources in
parallel) isn't possible.

The basic idea is to have a giant lock around most of the server code,
with a queue to hold requests that can't be processed because the lock
is taken.  Your server has two threads, one blocking in msg_receive and
the other blocking in select.  The two threads communicate with each
other through a shared data structure that holds pending requests and
records which thread, if any, is off in the non-parallel server code
processing a request.  When a thread unblocks with a new request, it
checks the shared data structure.  If the other thread is busy
processing, it drops the new request in the queue and blocks again.  If
the other thread isn't processing, then it go ahead and process the
request directly, recording this in the shared data structure.  When a
thread finishes processing a request, it checks the shared data
structure.  If there are queued requests, then it picks them up and
continues processing.  Otherwise it records that no thread is processing
and blocks for more requests.

Rich