mwm@eris.BERKELEY.EDU (Mike (My watch has windows) Meyer) (06/06/87)
In article <279@louie.udel.EDU> rminnich@udel.EDU (Ron Minnich) writes:
<6. Do MCC pipes work as named pipes (a la sys V), or just the
< equivalent of the unix '|'?
Uh, MCC pipes (and also Matt's pipe device, which is PD) are more than
the "|". They put pipes in the file system name space, where you can
use the for magic. To wit:
run edit from ram:input to pipe:edit-tmp with s:edit-script
run edit from ram:control to pipe:control-tmp with s:edit-control
edit from pipe:edit-tmp to ram:output with pipe:edit-control
Pipe:file is a pipe. Such things run an order of magniude faster than
going through ram:.
I *think* that's what SysV pipes do, but the closest I can come to a
SysV box is Unicos, which was based on SysV before there was a relase
number, and has been severely hacked upon. Someone wanna tell me what
named pipes really do?
Thanx,
<mike
--
How many times do you have to fall Mike Meyer
While people stand there gawking? mwm@berkeley.edu
How many times do you have to fall ucbvax!mwm
Before you end up walking? mwm@ucbjade.BITNET
peter@sugar.UUCP (06/10/87)
You create a named pipe with a mknod call. As a special case anyone can do this. The pipe is therefore just another special file. You can open it and write to it just like a file. You can open it and read from it similarly. Unlike PIPE: pipes, a reader doesn't hang on opening... it hangs on a read. Similarly a writer doesn't hang: it can just write its bytes and get out of there without waiting for a reader to show up. You also don't hang on close waiting for your coconspiritor to finish. Otherwise it's pretty much the same. It would be nice if the MCC PIPE: would handle more packets. For example, Examine and ExNext.
dillon@CORY.BERKELEY.EDU (Matt Dillon) (06/12/87)
>You create a named pipe with a mknod call. As a special case anyone can do >this. The pipe is therefore just another special file. You can open it >and write to it just like a file. You can open it and read from it similarly. >Unlike PIPE: pipes, a reader doesn't hang on opening... it hangs on a read. >Similarly a writer doesn't hang: it can just write its bytes and get out of >there without waiting for a reader to show up. You also don't hang on close >waiting for your coconspiritor to finish. Otherwise it's pretty much the same. > >It would be nice if the MCC PIPE: would handle more packets. For example, >Examine and ExNext. You are, fortunetly, wrong. I wrote PIPE:, and it neither blocks on Open() nor blocks on Write(). In fact, I certainly hope MCC pipes have a provision for non-infinite buffer sizes, or they are useless to me. Perhaps you are refering to a very early version of my PIPE:? Specifically, you can specify the buffer size for PIPE: pipes easily enough: 'pipe:name/b#'. If you want an infinite buffer size (writer NEVER blocks), then 'pipe:name/n' suffices. Without any options, the pipe uses a 4K buffer. For non infinite buffer sizes, my PIPE: allows the writer to write until the buffer is full, then waits for it to drain down to half before allowing the writer to write again. If the reader can keep up with the writer, then the writer never blocks. The reason for this is obvious: reduce the number of task switches while still attaining 100% CPU utilization. Now you may ask, 'why not just make it use infinite buffer sizes as a default'?? That's an easy question to answer. By example I will describe how I construct my VD0: disk from floppy power up: given A 600K file on the floppy containing the COMPRESSED, ARCHIVED VD0: (As in backup, not arc), I setup two pipes between three programs which will run concurrently. (A) A Copy from the 600K file to the first PIPE: specifying a relatively large, but not infinite, buffer size (I use a 128K buffer) (B) A DECOMPRESS from the first PIPE: to a second PIPE: using an infinite buffer size. (C) A de-archive (restore) from the second PIPE:. restore takes the decompressed archive file and reconstructs the entire VD0:. Now, I don't want to use an infinite buffer size for the first PIPE: because the Copy is *much* faster than decompress, and would basically get most of the 600K file in RAM: before decompress got through the first 50K. 600K + memory that decompress uses + a partially restored VD0: is quite a bit more than the measily 2.5Meg I've got. I can use an infinite buffer size for the second PIPE: because Restore can read data much faster than the decompressor can decompress it. The net result is 100% CPU utilization. What you see is 128K bytes read from the floppy, about a 10 second wait while uncompress reduces the pipe buffer to around 64K, then a 64K byte read from the floppy, another 5 seconds, another 64K byte read, etc... until all 600K has gone through. Meanwhile, uncompress has enjoyed *never* having to block when reading the compressed file from the first PIPE: In fact, that first PIPE: rarely gets smaller than 64K until Copy is finished reading the disk file. -Matt
hatcher@INGRES.BERKELEY.EDU.UUCP (06/12/87)
Both Peter & Matt's comments about pipes were quite interesting. Unfortunately Matt neglected to answer Peter's comment about wanting pipes to support Examine and Exnext. This is a very important feature. The ideal, which tends to be discovered and rediscovered endlessly, is to have a consistent name space where everything is a first class citizen. The reason is simple...when things are very consistent, then software tends to work automatically with objects that the author didn't have in mind a priori. The Amiga currently has *almost* consistent universal name space, as illustrated by the fact that Matt can write a pipe: device in the first place, and any software can write to it as if it were a regular file. But unlike other devices which contain file names, the pipe: device cannot be listed (Examine/Exnext etc). If it supported those packet types then it would behave a lot more like our other devices. A practical example: I have sometimes used more than one pipe at once (good old multitasking Amiga!), and after scrolling several CLI's and swapping windows around, wanted to check what was going on with the pipes. The ideal way would be to do "dir pipe:". A second problem was that I had gotten a writer going to a pipe, then it took a while to set up the reader, but I couldn't remember the name I'd used for the pipe (and the command had scrolled off the top of the CLI window). Again, being able to do "dir pipe:" would fix that. These are just a few examples; consistency and universality of interfaces are well established principles by now. There are many discussions of these principles in histories of Unix and Smalltalk, to pick two easy examples. One ignores history at ones own peril (and to the inconvenience of clients of your software). Oh, a final note: it's nice to have a root in which to look at a name space. That's why devices on Unix live in the file system in /dev -- it's not a peculiarity, it's a very basic feature of a uniform name space. It would be very nice if we could do "dir ::" or something and discover a list of all devices. Doug Merritt ucbvax!unisoft!certes!doug
dillon@CORY.BERKELEY.EDU (Matt Dillon) (06/12/87)
>Both Peter & Matt's comments about pipes were quite interesting. >Unfortunately Matt neglected to answer Peter's comment about wanting >pipes to support Examine and Exnext. I'm convinced already.... shouldn't be too hard to implement. -Matt
peter@sugar.UUCP (Peter DaSilva) (06/16/87)
In article <8706120539.AA16159@cory.Berkeley.EDU>, dillon@CORY.BERKELEY.EDU (Matt Dillon) writes: > >You create a named pipe with a mknod call. As a special case anyone can do > >this. The pipe is therefore just another special file. You can open it > >and write to it just like a file. You can open it and read from it similarly. > >Unlike PIPE: pipes, a reader doesn't hang on opening... it hangs on a read. > >Similarly a writer doesn't hang: it can just write its bytes and get out of > >there without waiting for a reader to show up. You also don't hang on close > >waiting for your coconspiritor to finish. Otherwise it's pretty much the same. > > > >It would be nice if the MCC PIPE: would handle more packets. For example, > >Examine and ExNext. > > You are, fortunetly, wrong. I wrote PIPE:, and it neither blocks > on Open() nor blocks on Write(). In fact, I certainly hope MCC pipes have > a provision for non-infinite buffer sizes, or they are useless to me. Perhaps > you are refering to a very early version of my PIPE:? I don't know what version I'm talking about. Did you write the PIPE: device in the MCC toolkit, as well as the one whose source is floating around (that is, are they the same program)? It may well be a very early version that I'm using here. Let me check: The posted date is 6th Feb 1987. The buffer size is stated to be 4K. It does direct write-through when writing to a pending read (nice touch). The source contains the notation that if you open-write<4K bytes-close, the close will wait until a reader opens the pipe. That's what I mean by "waiting for your co-conspiritor to finish". > Specifically, you can specify the buffer size for PIPE: pipes easily > enough: 'pipe:name/b#'. If you want an infinite buffer size (writer NEVER > blocks), then 'pipe:name/n' suffices. Without any options, the pipe uses a > 4K buffer. There doesn't seem to be any provision for this. > Now you may ask, 'why not just make it use infinite buffer sizes > as a default'?? That's an easy question to answer. By example I will Nope, I didn't ask this one. It's pretty obvious that yanking all of memory in a multitasking system isn't always appropriate. I'm not sure I would use the infinite buffer size feature at all. > VD0: is quite a bit more than the measily 2.5Meg I've got. I can use > an infinite buffer size for the second PIPE: because Restore can > read data much faster than the decompressor can decompress it. But because of this, the pipe will always be almost empty, so you might as well give it a 4K buffer size as well. It might be noted here that the UNIX pipes have a 4K buffer size. Now, a question and a request: Does your new PIPE: support the packets Examine and ExNext use? If so, then you could just "dir pipe:" to get a list of active pipes, right? The request: I want to use your PIPE: device as the skeleton for an improved console device. May I? How would I use it with Aztec (compatibility mode for sure, right)? Can I call Intuition from a device (opening windows, etc) or do I have to handcraft windows from the lower level primitives? I assume the former, but I've visited the Guru enough to know how often my assumptions are unwarranted.
peter@sugar.UUCP (Peter DaSilva) (06/16/87)
> space. That's why devices on Unix live in the file system in /dev > -- it's not a peculiarity, it's a very basic feature of a uniform > name space. It would be very nice if we could do "dir ::" or something > and discover a list of all devices. You can do an assign with no args and get the list. From a program, however, it's a bit more complex. Maybe when I finish my console window device I can add a device device. In the meantime, use the code in my STDFILE package (to be posted soon). I have come to prefer the Amiga device naming convention to the UNIX one... if only it used the UNIX path naming conventions with them.
hatcher@INGRES.BERKELEY.EDU (Doug Merritt) (06/24/87)
In article <187@sugar.UUCP> peter@sugar.UUCP (Peter DaSilva) writes: Me: >> space. That's why devices on Unix live in the file system in /dev >> -- it's not a peculiarity, it's a very basic feature of a uniform >> name space. It would be very nice if we could do "dir ::" or something >> and discover a list of all devices. Peter: :Summary: List devices? Just say Assign! :You can do an assign with no args and get the list. From a program, however, :it's a bit more complex. Naturally we all know that Assign gives you a list of devices, but that is not the point (BTW I have a C function that searches the list for a device of a given name, email to "ucbvax!unisoft!certes!doug" if you want it). The point was about a single "uniform name space", not whether the two separate name spaces could be accessed. This is an important design principle, and not one that I am inventing off the top of my head. Before you start disagreeing with me too strongly on the issue, it wouldn't hurt to look up some of the papers published on the subject that explain the issues far better than I can. There is a clear, concise paper on the subject by the venerable Rob Pike and P.J. Weinberger called "The Hideous Name" on pg 563 of the Summer 1985 Usenix Proceedings (although their paper is oriented towards network names, the ideas are universal enough to be applicable). There've been lots of others published too, but I don't have references handy. But I'll plod ahead in my own fashion for those of you who may be interested. :Maybe when I finish my console window device I can :add a device device. In the meantime, use the code in my STDFILE package :(to be posted soon). I have come to prefer the Amiga device naming convention :to the UNIX one... if only it used the UNIX path naming conventions with :them. All of this sounds good. I don't have any argument with keeping the Amiga device naming convention. I didn't mean that AmigaDos should have a filesystem just exactly like Unix, I just meant that at least with Unix you can list out devices in directories just like any other file. And your "device device" could support that. Change the syntax of my original suggestion to "dir devices:" if you like that better than "dir ::". Another aspect of a universal name space is the /procs directory in Unix System 3, that contains a list of active processes (that again can be listed with the "ls" command). I think this is a good idea. Why have many interfaces for programs to deal with, when you could give just one uniform interface? Well, unfortunately, sometimes you need custom interfaces. But there's no conflict on the Amiga. You just support all the basic things like Lock, Open, Read, Examine, ExNext for any and all objects (files, directories, devices, tasks, processes, etc), and then add other message types as necessary to provide for the special functionality of that particular object. Just make sure that it always responds to the minimal message set. Regards, Doug Merritt ucbvax!ingres!hatcher (thru Jun 28 only!) or ucbvax!unisoft!certes!doug
dillon@CORY.BERKELEY.EDU (Matt Dillon) (06/24/87)
>I don't know what version I'm talking about. Did you write the PIPE: device >in the MCC toolkit, as well as the one whose source is floating around (that >is, are they the same program)? It may well be a very early version that I'm >using here. Let me check: Slight misunderstanding... you were talking about the MCC PIPE:, and I was talking about my PIPE: (I did not write the MCC pipe... I'm not connected with them in any way). >> VD0: is quite a bit more than the measily 2.5Meg I've got. I can use >> an infinite buffer size for the second PIPE: because Restore can >> read data much faster than the decompressor can decompress it. > >But because of this, the pipe will always be almost empty, so you might as well >give it a 4K buffer size as well. It might be noted here that the UNIX pipes >have a 4K buffer size. If the program writing to the pipe has a large buffer size (8K is not uncommon), then it will block every time it does a write until the reader is ready. Thus, to completely ensure the program does not block (assuming the reader can read it faster), the pipe would have to be a bit larger... say 16K. >Now, a question and a request: > >Does your new PIPE: support the packets Examine and ExNext use? If so, then you >could just "dir pipe:" to get a list of active pipes, right? I've been trying... and trying... and trying... I can't figure out why it is crashing.... Can somebody post a *working* device driver which uses Examine/ExNext???? >The request: I want to use your PIPE: device as the skeleton for an improved >console device. May I? How would I use it with Aztec (compatibility mode for >sure, right)? Can I call Intuition from a device (opening windows, etc) or do >I have to handcraft windows from the lower level primitives? I assume the >former, but I've visited the Guru enough to know how often my assumptions are >unwarranted. Anybody who wishes is certainly welcome to strip my source and use it as a skeleton. Since it is copyright, I have to give my permission: You have my permission (reasonable approximation of my signature: Matthew Dillon). Poof, done. Anybody who needs the source can also mail me directly and I'll send it to him/her. Devices are processes. Thus, you can call any library you wish. However, you have to be careful not to make a library call that will result in DOS trying to talk to your process. You can even open-up a CON: window and write to it... though that is *very* precarious. -Matt
qix@ihlpa.ATT.COM (Puckett) (06/25/87)
In article <8706240726.AA06112@cory.Berkeley.EDU>, dillon@CORY.BERKELEY.EDU (Matt Dillon) writes: > >Does your new PIPE: support the packets Examine and ExNext use? If so, then you > >could just "dir pipe:" to get a list of active pipes, right? > > I've been trying... and trying... and trying... I can't figure > out why it is crashing.... Can somebody post a *working* device driver > which uses Examine/ExNext???? P: supports these. Here is a fragment of the code. The complete sources have been posted to comp.sources.amiga and sent to Fred Fish. Hope this helps. -Ed Puckett. /*--------------------------------------------------------------------------- ** PipeExamine() responds to Examine requests. For locks on the handler, the ** address first item of the pipelist is stored in the DiskKey field for ** PipeExNext()'s reference. */ void PipeExamine (pkt) struct DosPacket *pkt; { struct FileInfoBlock *fib; struct FileLock *lock; PIPEDATA *pipe; void FillFIB(); pkt->dp_Res1= 1; /* no error, for now */ pkt->dp_Res2= 0; fib= (struct FileInfoBlock *) BPTRtoCptr (pkt->dp_Arg2); if ((lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg1)) == NULL) { pkt->dp_Res1= 0; pkt->dp_Res2= ERROR_OBJECT_NOT_FOUND; } else { if ((pipe= (PIPEDATA *) lock->fl_Key) == NULL) /* then this is a lock on the handler */ { FillFIB ( fib, FirstItem (&pipelist), HandlerName, (FIBF_EXECUTE | FIBF_DELETE), 1, 0, 0, &PipeDate ); } else { FillFIB ( fib, NULL, pipe->name, (FIBF_EXECUTE | FIBF_DELETE), -1, pipe->buf->len, 1, &pipe->accessdate ); } } ReplyPkt (pkt); } /*--------------------------------------------------------------------------- ** PipeExNext() responds to ExNext requests. The DiskKey field of the ** FileInfoBlock is assumed to be a pointer to the next pipe in the pipelist ** which is to be listed in the directory. We then scan pipelist for this ** pointer, and upon finding it, store its information in the FileInfoBlock ** and store the address of the next pipe in pipelist in the DiskKey field. ** If the pipe is not found in the list, or if DiskKey is NULL, then ** ERROR_NO_MORE_ENTRIES is returned. ** By rescanning the list each time, deletion of a pipe cannot hurt us ** by causing a dangling pointer in DiskKey -- we just end the directory ** listing there. This can cause incomplete directory information for the ** cleint, however, if the last listed pipe is deleted before the client's ** next ExNext() call. */ void PipeExNext (pkt) struct DosPacket *pkt; { struct FileLock *lock; struct FileInfoBlock *fib; PIPEDATA *listitem, *pipe; void FillFIB(); pkt->dp_Res1= 0; /* error, for now */ if ((lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg1)) == NULL) { pkt->dp_Res2= ERROR_INVALID_LOCK; goto EXNEXTREPLY; } if (lock->fl_Key != NULL) /* then an individual pipe */ { pkt->dp_Res2= ERROR_OBJECT_WRONG_TYPE; goto EXNEXTREPLY; } pkt->dp_Res2= ERROR_NO_MORE_ENTRIES; /* until found otherwise */ fib= (struct FileInfoBlock *) BPTRtoCptr (pkt->dp_Arg2); if ((listitem= (PIPEDATA *) fib->fib_DiskKey) == NULL) goto EXNEXTREPLY; for (pipe= (PIPEDATA *) FirstItem (&pipelist); pipe != NULL; pipe= (PIPEDATA *) NextItem (pipe)) if (listitem == pipe) break; if (listitem == pipe) /* then found next entry */ { FillFIB ( fib, NextItem (listitem), listitem->name, (FIBF_EXECUTE | FIBF_DELETE), -1, listitem->buf->len, 1, &listitem->accessdate ); pkt->dp_Res1= 1; pkt->dp_Res2= 0; } EXNEXTREPLY: ReplyPkt (pkt); } /*--------------------------------------------------------------------------- ** PipeParentDir() responds to ParentDir requests. */ void PipeParentDir (pkt) struct DosPacket *pkt; { struct FileLock *lock; void InitPipedirLock(); InitPipedirLock (); pkt->dp_Res2= 0; if ((lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg1)) == NULL) { pkt->dp_Res1= 0; pkt->dp_Res2= ERROR_INVALID_LOCK; } else { if (lock->fl_Key == NULL) /* then lock is on handler */ pkt->dp_Res1= 0; /* root of current filing system */ else pkt->dp_Res1= CptrtoBPTR (PipedirLock); } ReplyPkt (pkt); } * * * * * /*--------------------------------------------------------------------------- ** FillFIB() fills a FileInfoBlock with the specified information. Note ** that handlers must store BSTR's in the FileInfoBlock. */ static void FillFIB (fib, DiskKey, FileName, Protection, Type, Size, NumBlocks, Datep) struct FileInfoBlock *fib; LONG DiskKey; char *FileName; /* null-terminated */ LONG Protection; LONG Type; LONG Size; LONG NumBlocks; struct DateStamp *Datep; { fib->fib_DiskKey= DiskKey; fib->fib_DirEntryType= Type; CstrtoBSTR (FileName, fib->fib_FileName, sizeof (fib->fib_FileName)); fib->fib_Protection= Protection; fib->fib_EntryType= Type; /* ??? */ fib->fib_Size= Size; fib->fib_NumBlocks= NumBlocks; CopyMem (Datep, &fib->fib_Date, sizeof (struct DateStamp)); fib->fib_Comment[0]= '\0'; /* empty BSTR */ }