Article View: comp.sys.amiga.tech
Article #2574Using PIP:
From: Michael Richardson
Date: Thu, 07 Dec 1989 13:07
Date: Thu, 07 Dec 1989 13:07
268 lines
8449 bytes
8449 bytes
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 <stdio.h>
#include <fcntl.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#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
Technical Details
Message-ID:
<1610.AA1610@julie>Path:
arc1-ca.pugleaf.net!utzoo!dciem!nrcaer!fts1!julie!mcrShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!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