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