Path: utzoo!dciem!nrcaer!fts1!julie!mcr From: mcr@julie.UUCP (Michael Richardson) Newsgroups: comp.sys.amiga.tech Subject: Using PIP: Keywords: dupping closing pipes Message-ID: <1610.AA1610@julie> Date: 7 Dec 89 13:07:06 GMT Followup-To: comp.sys.amiga.tech Organization: Sandleman Software Works' Debugging Department, Ottawa, ON Lines: 268 When I finally got annoyed at the silliness of command line passing, program launching (with exit codes) and the pr_CLI structure in general [this was at least 6 months ago] I began to build an alternate launching scheme, much more similar to the way the workbench startup message works. I based it on Leo Shwab's wblaunch code. (I'm not sure if Peter, Leo or myself that had this thought first. I think we all came up with it independently...) In order deal with who closes file descriptors, etc.. I wound up passing a bitmap to the sub-process telling it which file handles it can close. [Actually, I can also pass the `ToolWindow' field, and although I haven't done it yet, I always put 0 in the place where the Workbench message's `number of arguments' is so I could in fact be launched from Workbench...] I'd like this field eventually to be $ffffffff. (I can pass any number of FileHandles though. They are installed in the Manx `_devtab' structure.) The point: I want a Popen call that works properly, and for which each end has it's own filehandle. PIP: seemed to be the thing, except that I can't seem to get it work. [My popen call takes an argv/argv rather than a string. My `RogueStart' (there is a book named Rogue Star by Frederik Pohl) shell is too simple at present to bother feeding it through that.] I tried a simple test program: #include #include #include #include #include #include "bcpl.h" extern void *AllocMem(); extern struct FileHandle *Open(); extern FILE *fdopen(); extern void *CreatePort(); extern void *GetMsg(); main() { struct FileHandle *pin,*pout,*ret,*temp; int i; char buf[100],buf2[100]; if((pin=AllocMem(sizeof(struct FileHandle),MEMF_PUBLIC|MEMF_CLEAR))==NULL) { return(NULL); } if((pout=Open("PIP:4096",2000L))==NULL) { FreeMem(pin,sizeof(struct FileHandle)); return(NULL); } temp=(struct FileHandle*)BTOC(pout); (*pin)=(*temp); pin=(struct FileHandle*)CTOB(pin); printf("Created two handles: %08x and %08x\n",pin,pout); printf("Please type a line: "); fgets(buf,100,stdin); printf("Got %s\n",buf); i=Write(pin,buf,strlen(buf)); printf("Wrote string (%d)\n",i); i=Read(pout,buf2,100); buf2[i]='\0'; printf("Read (%d) %s\n",i,buf2); Close(pin); i=Read(pout,buf2,100); buf2[i]='\0'; printf("Read (%d) %s\n",i,buf2); Close(pout); } While this seemed to work --- it didn't always work twice, it seemed that I could crash it by allocating pout, and opening pin rather than the reverse. I can understand this. It also seemed that the order in which I closed them was significant. I haven't run this program in awhile (I've been procrastinating this posting for at least a couple of months... But today I'm home sick, and don't feel like bashing any of my other projects...) so I'm sorry if I am a bit vague --- but there is no way that I can guarantee that the two ends of the pipe will be closed by the two processes in the right order. Processes are quite asynchronous in nature... I pretty sure that it is the order in which I close them that is causing the guru --- sometimes when I run a little test it crashes. Sometimes not. If I run two of them sequencially or concurrently, I get the same results... FILE * popenv(ac,av,mode,pp) int ac; char *av[]; char *mode; struct MsgPort **pp; { struct FileHandle *in,*out,*err; struct FileHandle *pin,*pout,*ret,*temp; struct MsgPort *p; struct RogueStartup *r; FILE *rf; int code; long mask; int i; in=RogueInput(); out=RogueOutput(); err=RogueError(); if(mode[0]!='r' && mode[0]!='w') return(NULL); if((pin=AllocMem(sizeof(struct FileHandle),MEMF_PUBLIC|MEMF_CLEAR))==NULL) { return(NULL); } if((pout=Open("PIP:4096",2000L))==NULL) { FreeMem(pin,sizeof(struct FileHandle)); return(NULL); } temp=(struct FileHandle*)BTOC(pout); (*pin)=(*temp); pin=(struct FileHandle*)CTOB(pin); if(mode[0]='r') { out=pin; ret=pout; mask=(1L << 1); } else { in=pout; ret=pin; mask=(1L << 0); } /* Now set up the _devtab structure. */ for(i=0; i<_numdev; i++) { if(_devtab[i].fd==NULL) { break; } } if(i==_numdev) { Close(pin); Close(pout); return(NULL); } _devtab[i].fd=(long)ret; _devtab[i].mode=(mode[0]=='r' ? O_RDONLY : O_WRONLY); if((rf=(FILE *)fdopen(i,mode))==NULL) { _devtab[i].fd=NULL; Close(pin); Close(pout); return(NULL); } if((p=(struct MsgPort *)CreatePort(NULL,NULL))==NULL) { if(ret==pin) Close(pout); else Close(pin); fclose(rf); return(NULL); } if((r=RogueLaunch(p,av[0],av,ac,NULL,0,NULL,10000,in,out,err,mask))==NULL) { /* RogueLaunch(rport, name, argv, argc, env, pri, win, stack, in, out, err) -- * launch a program. * * RogueLaunch builds a startup message, loads a program, and launches it. * * Arguments: * rport -- reply port to receive startup message back when the program * finishes. * name -- File name for the program to load. * argv -- list of filenames to pass to loaded program. * argc -- length of argument list. * env -- list of environment variables (local) * pri -- priority of the new process. * win -- ToolWindow for the new process, or NULL. * stack -- Stack size for the new process. * in -- Where to find Standard input \ Only taking * out -- Where to find Standard output > three is * err -- Where to find Standard error / arbitrary. * mask -- bitmap of file descriptors to close. * * argv[0] should be the same as the program. pri should normally be 0. * stack should normally be at least 4K. */ if(ret==pin) Close(pout); else Close(pin); fclose(rf); DeletePort(p); return(NULL); } *pp=p; return(rf); } int pclose(f,pp) FILE *f; struct MsgPort **pp; { struct MsgPort *p; struct RogueStart *rs; int code; if(f==NULL||pp==NULL) return(-1); p=*pp; if(p==NULL) return(-2); WaitPort(p); rs=GetMsg(p); if(rs) { code=RogueFreeStartup(rs); } fclose(f); /* Close our end of the pipe */ return(code); } I also somewhat suspect the fclose() call, but I believe I have tried converting everything to FileHandle level... BTW: Programs compiled with the Rogue Startup code can continue to run from CLI, and if I ever make the WorkBench modification from the workbench as well. Many parts of the uucp system that this is being posted with runs via RogueLaunch. Specifially I've rewritten uux/uuxqt/unbatchfc/rmail. Rmail has also be modified a large amount -- it adds Received:, collapses From_ [yuck], and adds a Message-Id: if there isn't one. I called it smail because I'll eventually add `smart-host' to it. It also calls uux with the `-a' option (however, I haven't figured out what uux should really do with it in terms of the X. file.). [Lots more to say -- but mail me. An AmigaNet (not to me confused with FidoNet despite that we run software that seems to be compatible :-)) /AmigaUUCP mailing list has existed for about year as amiga-mailer@doe.carleton.ca and amiga-mailer@fts1.UUCP (doe doesn't like .UUCP addresses that much...). The list is fairly dead right now, due in part because much of the activity has moved to an echo called AMIGASTAND.] The rewrite of the rest [and the posting to Bob Page] awaits pipes so that I can get rid of some of the temporary files. I don't like temporary files. -- :!mcr!: Michael Richardson Amiga v--------+ HOME: mcr@julie.UUCP | SCHOOL: mcr@doe.carleton.ca Fido: 1:163/109.10<--+ WORK: michael@fts1.UUCP