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