[comp.os.minix] User Process Message-Passing in Minix

wheeler@IDA.ORG (David Wheeler) (05/23/91)

The original version of Minix did not allow _User Processes_
to pass messages to OTHER user processes.


Two questions for the net:

1. Does the current version (or some modified version everyone uses)
allow this? (From all I can tell it doesn't).

2. If not, would someone who has the current version of Minix mind
trying out the following modification to allow it?  Please?
Or tell me a better way to do it?

------------------------------------------

Background:  all of Minix's implementation is based on send, receive,
and send_receive.  UNFORTUNATELY user processes are ONLY allowed to do
send_receive, and to only two OS processes, not to other user processes.
Lots of other OS's _DO_ provide this feature (Mach, System V, QNX, etc),
it's VERY useful.

Last year Mark Boyd posted the following:

mark@ccvr1.ncsu.edu (Mark Boyd):
> I'm trying to use messages for process syncronization.  I can
> find no way to use messages between user processes. Has anyone
> done this? I'm working on 68000 based systems ( ST and PT68k ),
> but I don't see where the problem would be any different on
> PCs. 
>                       Mark Boyd
>                       mark@ccvr1.ncsu.edu
 
I then replied a possible solution.  Has anyone tried this?  Does the
current version already include this?  Would anyone mind trying this
and telling me if things blow up?  I've incorporated a modified
(improved) version of my reply to him below:

-------------------------------------------------------------------

I looked into this problem once.. I think it can be done but haven't
tried it myself.  I'm not aware of this capability being in the latest
version of MINIX, so you'd have to modify the OS.  I don't have the
latest version of MINIX, so my info is based on the original code in
the book. See the MINIX code as published in "Operating Systems:
Design & Implementation", page 473.  Lines 1987-1988 and 1950-1953 mean
that user processes may only execute a sendreceive, and that user
processes may only send to FS or MM.

A quick & dirty solution would be to remove these two sections, then
recompile MINIX.  There may be other sections which make this
assumption, but those two sections are certainly a minimum.  This would
mean, unfortunately, that user programs could send to anybody,
including internal OS processes.

A much better approach would be to make it so that user programs can
only call other user programs OR FS OR MM.  For this, change
kernel/proc.c lines 1950-1953 and 1987-1988 (as numbered in the
original MINIX book) to what follows.  These lines are checks which
currently prohibit user-to-user calls; I replace them with checks that
allow users to either call FS & MM (only send_receive to these) *OR*
call other user processes any way they wish.

Since user processes MUST do a send_receive when they message to FS & MM,
FS & MM don't need to change (since they expect send_receive), and
other user processes can't spoof as FS & MM (since a process sending to
FS & MM will only listen to who it sent to).

Any process sending to another process is automatically trusting the sendee-
if the sendee never receives from ANY, the process stays blocked!
That's normal for this kind of IPC.  You can kill the sender, and Minix
will automatically clean up this queued request, so no harm done.

More interesting is killing a user process to which others are sending
(i.e. a user-level server).  I don't see any code in Minix to handle
this case (ie by restarting those processes waiting to send or receive
from this process), though I may have missed it.  You shouldn't be
killing server-type processes this way anyway; it's much safer to give
server processes a ``kill'' command so they can shut down gracefully.

FS & MM expect to be BOTH sent & received by users, so calling to
FS & MM by users MUST obey that restriction.
(Note: I forgot this check in my last post).
Lines 1950-1953 need to be changed to the following:
----------------------------------------
if (function != BOTH && caller>=LOW_USER &&
           ( src_dest == FS_PROC_NR || src_dest == MM_PROC_NR ) )
    {
     rp->p_reg[RET_REG] = E_NO_PERM; /* Users only do BOTH to MM & FS */
     return;
    }
----------------------------------------


The mini_send routine currently only allows users to send to MM & FS.
You want users to be able to send to MM, FS, or other users.
Calling a process greater than the # of possible processes was checked earlier.
Change lines 1987-1988 to the following:

----------------------------------------

/* Allow users to send to each other as well as MM and FS */
if (caller >= LOW_USER &&
    (dest != FS_PROC_NR && dest != MM_PROC_NR && dest < LOW_USER))
    return(E_BAD_DEST);

/* It is illegal to send to ``any'' - complain if it's attempted! */
/* NOTE: This check is new; my last post didn't check for this error. */
if (dest == ANY) return(E_BAD_DEST);

----------------------------------------


One problem is how to get the process id for the process to send to, since
unlike MM & FS there's no fixed process id for other processes.

In the short run, here's a simple technique:
Have your server (user program) store its process id when it starts up
in a file with an agreed-on filename.  Other programs can read the file
to get its name.  If there's a possibility that programs could try to
read the file while it's being written, have the server create a second
file that indicates ``I'm done writing'', and have all the clients
look for that file first.

A much better solution would be a name server process at a set
process id (as FS and MM are now).  Serving programs could ``register''
themselves with a short name, and clients could request a program by name
and receive its process id.

A better approach would be replacing those sections with something
more sophisticated, so that certain user processes can talk with
certain other processes given certain secure conditions.
Other OS's do allow user processes to send & receive messages and
have some security checks (perhaps the process sets certain permissions
to allow certain other user tasks to send to it, etc, etc).
 
--- David A. Wheeler
    wheeler@ida.org

philip@cs.vu.nl (Philip Homburg) (05/23/91)

In article <1991May22.235824.6939@IDA.ORG> wheeler@IDA.ORG (David Wheeler) writes:
%
%The original version of Minix did not allow _User Processes_
%to pass messages to OTHER user processes.
%
%
%Two questions for the net:
%
%1. Does the current version (or some modified version everyone uses)
%allow this? (From all I can tell it doesn't).
%
%2. If not, would someone who has the current version of Minix mind
%trying out the following modification to allow it?  Please?
%Or tell me a better way to do it?


Please DON'T DO THIS. May be this is too loud and I should whisper "please,
don't do this" but you are looking for trouble.

I have a kernel which allows user processes to send to and receive from
anyone and it is part of minix 1.6.15 but it is for debugging purposes only.

There are a few problems:
- What to do with signals. You didn't get a message but you got a signal.
- What if somebody is sending to you and you die. The kernel doesn't check.
- How does a server find out his process number.
- How do you send messages larger than about 32 bytes.
- How do you know who sent the request, no userids can be checked.

And, last but not least, you can do it with fifos.

Of course the best way to find out about your idea is to implement it, but 
I think that for IPC you need a dedicated server like FS or in the kernel
that has access to userids, etc.




					Philip

wheeler@IDA.ORG (David Wheeler) (05/25/91)

I wrote:

%The original version of Minix did not allow _User Processes_
%to pass messages to OTHER user processes.

philip@cs.vu.nl (Philip Homburg) replied:

% Please DON'T DO THIS. May be this is too loud and I should whisper "please,
% don't do this" but you are looking for trouble.

I agree with some of the problems you list, but I'd like to try to fix
them.. and thanks for listing some.  I think what's needed to make it
work is a fair amount of thinking time & relatively little new code.
It's essentially like thinking up & verifying communication protocols!

There are LOTS of operating systems and languages which already support
user-to-user message-passing to some degree, so I disagree that it's
_automatically_ a bad idea.  They include Mach, QNX, System V, Berkeley, Ada.
Many others, too.  Communicating sequential processes goes back to Hoare's
work & is a very useful capability!

This is a fundamental new capability, though, so I completely
agree with you that it has to be thought out carefully.

What's definitely NOT a good idea is:

% And, last but not least, you can do it with fifos.

You mean pipes, unnamed or named, right?

I want to support user-level servers to other user-level programs.
These servers can be started up later, and (rarely) taken down
(for example, to replace them with a new & improved version).

Unnamed pipes just don't work in this case; there isn't a shared
parent who can create a pipe between the client & server.

Named pipes are a uniformly AWFUL way to do client/server
communication.  The server DEFINITELY doesn't know who sent the
message, the size of the sent message isn't known, and
the server has to do all sorts of work to do named pipe
management.  All of which is pointless, since the OS itself ``knows''
about all the tasks & is already based on a message-passing system.


= There are a few problems:
= What to do with signals. You didn't get a message but you got a signal.

That's already in the CURRENT SYSTEM.  After all, you can send_receive
to MM or FS.  You can either be sending, server hasn't gotten to you yet,
or receiving, your message was received but you haven't been replied to yet.
I do need to examine this more carefully, though -- is what the current
system does now appropriate?

= What if somebody is sending to you and you die. The kernel doesn't check.

Actually, the kernel DOES check.  Page 473, line 1991.

= How does a server find out his process number.
 getpid().

= How do you send messages larger than about 32 bytes.

 Some applications won't need more.  For those that do:

  1. Send multiple messages. or,
  2. Modify MM and operations for memory-to-memory moves possible.
     Clearly this would have to be "agreed to" by both processes,
     but other OS's do exactly this (I believe Thoth does; anyone know
     for certain?).

= How do you know who sent the request, no userids can be checked.

  The kernel gets the pid's from the process table (MM's main.c
  does this).  Perhaps calls need to be added to get
  the process id of the one who sent to you, and/or a uid given a pid.
  Those would be trivial to add!

--- David A. Wheeler
    wheeler@ida.org

dh4@crosfield.co.uk (damian hamill) (05/28/91)

In article <1991May22.235824.6939@IDA.ORG> wheeler@IDA.ORG (David Wheeler) writes:
>
>The original version of Minix did not allow _User Processes_
>to pass messages to OTHER user processes.
>
>
>Two questions for the net:
>
>1. Does the current version (or some modified version everyone uses)
>allow this? (From all I can tell it doesn't).
>
>2. If not, would someone who has the current version of Minix mind
>trying out the following modification to allow it?  Please?
>Or tell me a better way to do it?
>
	[nasty stuff deleted about modifying kernel]
>

	[more nasty stuff deleted about files and things]

>  Serving programs could ``register''
>themselves with a short name, and clients could request a program by name
			 ^^^^

Now you are on the right track, and what do you know that nice Mr Tannenbaum
has already implemented it for you in the network communication tasks (taken
from the Amoeba system and referred to as AMOEBA tasks) that came with minix 
1.3.

Processes simply send and recieve messages to/from a port (which is identified
by a character string).  There is one distinct advantage with this method, ie
you remove location dependancy from your communicating processes.  

However, one or two subtle issues arise:

The network "AMOEBA" tasks (in 1.3 at least) are allocated to processes and
thus are associated with one particular instance of IPC, hence the number of
processes that can communicate using this method at any one time is limited.

The AMOEBA tasks are only BLOCKING processes, this (strictly) supports the 
client-server model.  My final year project was something to do with 
distributing minix and at times some non blocking primitives would have been
appreciated.

It's easy peasy lemon squeezy to include the AMOEBA task in your kernel, just
read the network documentation that comes with the 1.3 upgrade.

I hope this is of interest to you.

Damian.

-- 
/***************************************************************************
 Damian Hamill Crosfield Electronics ltd, Hemel Hempstead, Herts. UK.
 dh4@crosfield.co.uk	    TUNA?? ......NO THANK YOU
***************************************************************************/