[net.micro.6809] Make your own OS9 pipes -- it works

strick@gatech.UUCP (08/13/84)

As I typed in my note yesterday I realized what all I did wrong
last time I tried this.

I have sucessfully created my own pipes for process-to-
process communication.  The following example shows how to
do this.  The secret is to be able to use the OS9 I$DUP system
call to make the other half of the pipe.  A short assembly
language subroutine allows you to do this from basic09;
this will be the last listing in this article.

My example is a basic09 program that opens a path to a pipe
and then starts a "dir &" process (running asynchronously in
the background) with its standard output going to the pipe.
The basic09 program can read the directory listing from the
pipe.  I will give the basic09 listing now:

    PROCEDURE PIPEDIR
 1      DIM f,g : INTEGER
 2      OPEN #f, "/pipe" : UPDATE
 3      PRINT "f is "; f
 4      CLOSE #1
 5      g := f
 6      RUN dup(g)
 7      SHELL "dir &"
 8      PRINT #2, "g is "; g
 9      CLOSE #g
10      g := 2
11      RUN dup(g)
12      PRINT "g is "; g
13      READ #f, a$
14      PRINT a$
15      CLOSE #f


(I hope I haven't make any typos.)  ( Line numbers in [brackets] below. )
line [1]:  f and g will hold path numbers. g must be INTEGER (not BYTE)
    because dup in lines 6 and 11 (my a/l program) requires it.
line [2]:  you must use update mode because the path will be read by  
    this program and its "dup" clone will be written by "dir".
line [3]:  f will probably be assigned either path 3 or 4.
line [6] and [11]:  RUN dup(g):  g inputs the path number to duplicate
    and outputs the new synonymous path number.

This program starts running with paths 0 (stdin), 1(stdout), and
2 (stderr) going to "/term".  I want to spawn a process with path 1
(stdout) going to "/pipe".  To do this I will close my own stdout [4],
and ask [6] for a dup of my path f (the "/pipe"[2]).  The OS will make this
path 1 since I just closed path 1.  Then I fork off the "dir" process[7],
and let it run asynchronously (using the &) (actually it will be
synchronized some by the piped output -- the pipe buffer holds
about 64 characters).  The "dir" process inherits dups of the
stdin, stdout, and stderr paths of the parent (basic09) as they
are at the time it is forked.  Note that SHELL "dir >/pipe &"
would not work because this would be an entirely different pipe
(not a dup of the same one as basic09 will be reading from).

After the "dir" is forked, I close stdout again [9] to restore it to
"/term".  I do this by getting a duplicate of the stderr path [11].
To be totally proper, I should not have assumed stdout and stderr
were going to the same place; I should have duped a stdout path
to keep before I closed stdout[4], and duped stdout back from this spare
later [11].

To read the output of the "dir" command, I read from path f [13].
In my example I only read one line of the directory listing,
but I could have kept reading until eof.  I think using 
the function EOF(#f) will not work for detecting eof from a
pipe;  you would have to use ON ERROR GOTO and actually get
an error after reading too far.  Messy.


Finally, here is the dup program:


********
*  dup -- open duplicate path to existing path
*  henry strickland  11aug84
*  run as a basic09 procedure
*     run dup(n)       n must be INTEGER
*  input  n => path number to duplicate
*  output n <= new synonymous path number
*
    use defsfile
edit    set 1
type    set sbrtn+objct
revs    set reent+1
        mod finis,nom,type,revs,entrez,0
nom     fcs /dup/
        fcb edit        edition number

entrez
        ldd 2,s         entry point: get # of params
        cmpd #1         must be exactly one
        bne bad

        ldd 6,s         get size of parameter
        cmpd #2         must be INTEGER sized
        bne bad

        ldx 4,s         get addr of parameter
        ldd ,x          get param
        tsta            absurd if >256
        bne bad

*
*  about to use the I$DUP system call
*  input A => path to dup
*  output A <= new path number
*         CS, B <= if error

        tfr b,a         old path number
        OS9 I$DUP
        bcs exit        jump out if error

        tfr a,b         new path number
        clra            hi byte zero
        std ,x          return value
        clrb
exit    rts             return to basic09

*****
* parameter errors go here

bad     ldb #56         parameter error
        coma            set C bit
        rts             return to basic09

        emod
finis
        end


In summary, the two secrets are (1) to use dup to open the second
half of the pipe (:UPDATE) and (2) to get the pipe to the other process(es) by
changing paths 0, 1, and/or 2 for a short time while you are forking.

When the shell forks two processes connected by a pipe, it must (1)
close stdout (2) open a pipe for stdout (3) fork the first (producer)
process (4) close stdin (5) dup stdout for stdin (6) change stdout
to whatever you need to and (7) fork the second (consumer) process
(8) close stdout and (9) reopen the origional stdout.  Plus more
redirection if needed.

James, hope this helps -- let me hear if anyone does anything
exciting with all of this -- I might have a smarter shell with a
basic09 front end soon --

confusion to our enemies

strick
-- 
Henry Strickland
The Clouds Project, School of ICS, Georgia Tech, Atlanta GA 30332
CSNet:	Strick @ GATech		ARPA:	Strick.GATech @ CSNet-Relay
uucp:	...!{akgua,allegra,rlgvax,sb1,unmvax,ulysses,ut-sally}!gatech!strick