bruce@cs.su.oz (Bruce Janson) (02/06/91)
In article <13772@lanl.gov> jlg@lanl.gov (Jim Giles) writes: >.. The I/O call (below, RW >stands for _either_ the read or the write system call) should be >something like the following: > >RW(fd,nw,buf,da,aflag,handle) >.. >da - logical disk address (relative to beginning of file) for I/O > transfer. lseek() is redundant and in this model would disappear. > If da is -1, transfer is sequential from previous request. >.. >handle - this is a pointer to an I/O completion routine in the user's > process. This routine is called when the I/O requested has been > done. If this pointer is null, no user function is called. (This > routine is called even if synchronous I/O was requested.) >.. Jim, Above, you have outlined part of an async I/O interface. But there are some issues that I am still not clear about that perhaps you might like to clear up. When you say "transfer is sequential from previous request" do you mean the previously issued request or the previously completed request? More generally, in what context does the I/O get done? In what context does the I/O completion function run? Are the machine operations of either the I/O copy or the completion function interleaved with those of the rest of the program or is the "rest of the program" suspended while the I/O and its completion routine run. Is the contents of the area of memory pointed to by "buf" updated atomically with respect to the process? Is the I/O completion routine called with any arguments? Can the I/O completion routine call sleep()? Where does a longjmp() take me from within such an I/O completion routine? What does a setjmp() do when executed from within such an I/O completion routine? How about calls to the signal() family of routines and can the I/O completion routine be interrupted by an incoming signal? What exits when I call exit() from within an I/O completion routine? What happens when the main program calls exit() while there are still I/O requests outstanding? What happens if my process calls close() on an fd that is still associated with outstanding async I/O? How many concurrent outstanding I/O requests can my process have at the one time and can I prioritise and/or schedule them? Can a process enquire as to the status of a particular outstanding I/O request and if so, what naming scheme should it use to refer to the I/O request of interest. How do I terminate an outstanding I/O request prematurely? Can an I/O completion routine make further async I/O calls itself? It is possible to devise answers for all of these questions. And async I/O does exist in various operating systems so answers must have been devised. However, after considering these questions I might conclude that async I/O would need to bring with it some very significant advantages to offset what appears to be a more complex model. Cheers, bruce. Bruce Janson Basser Department of Computer Science University of Sydney Sydney, N.S.W., 2006 AUSTRALIA Internet: bruce@cs.su.oz.au Telephone: +61-2-692-3272 Fax: +61-2-692-3838
davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (02/07/91)
In article <13772@lanl.gov> jlg@lanl.gov (Jim Giles) writes: | The fact that UNIX is badly designed, doesn't rule out the possibility | of other bad systems. You should never be forced to do a wait system | call if what you want is synchronous I/O. The solutions are either a WAIT call, a separate SIO call for blocking i/o, or a flag to be supplied on each and every i/o system call. The systems I used all had the first, some had the second. Using a flag adds size to the calling program, CPU overhead to set and test the flag, and appears on first glance to have no advantages over the others. The separate blocking i/o system call is probably lowest overhead. -- bill davidsen (davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "I'll come home in one of two ways, the big parade or in a body bag. I prefer the former but I'll take the latter" -Sgt Marco Rodrigez
barmar@think.com (Barry Margolin) (02/07/91)
In article <3181@crdos1.crd.ge.COM> davidsen@crdos1.crd.ge.com (bill davidsen) writes: >In article <13772@lanl.gov> jlg@lanl.gov (Jim Giles) writes: >| The fact that UNIX is badly designed, doesn't rule out the possibility >| of other bad systems. You should never be forced to do a wait system >| call if what you want is synchronous I/O. >The solutions are either a WAIT call, a separate SIO call for blocking >i/o, or a flag to be supplied on each and every i/o system call. Another common solution is a settable mode. On the system I'm most familiar with (Multics), all I/O system calls are asynchronous (the only time a process ever blocks in the kernel is when it takes a page fault during a system call). However, the user-ring I/O library, which implements the device-independent equivalent to Unix's read() and write(), normally hides the asynchrony, by internally performing the wait. Applications can get an asynchronous interface by using an ioctl to set non-blocking mode (for devices where it makes sense -- there is no asynchronous interface to the file system, because it is implemented using files mapped into virtual memory, and page faults are implemented synchronously within a process). The blocking mechanism is based on general interprocess communications channels, and a process can either perform a wait call on a channel or request that a signal be generated when data is written to the channel (this is similar to Unix's select() and SIGIO, but more general because it can be used independently of I/O). -- Barry Margolin, Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar
Bruce.Hoult@bbs.actrix.gen.nz (02/07/91)
Jim Giles writes: >You should never be forced to do a wait system >call if what you want is synchronous I/O. The I/O call (below, RW >stands for _either_ the read or the write system call) should be >something like the following: > >RW(fd,nw,buf,da,aflag,handle) [rest of description deleted] Once again, that is almost *exactly* the way the Mac does it. The main difference is that the Mac splits out your "da" parameter into two parameters: an offset (+ve, -ve or zero), and a positioning mode which can be "from start of file", "from where the last transfer finished", or "from end of file". Also, your "aflag" parameter is split into two: an actual anync flag, and a result code that acts in almost exactly the way you indicate -- it is +ve during the i/o, zero on success, and has a -ve error number on failure. -- Bruce.Hoult@bbs.actrix.gen.nz Twisted pair: +64 4 772 116 BIX: brucehoult Last Resort: PO Box 4145 Wellington, NZ "And they shall beat their swords into plowshares, for if you hit a man with a plowshare, he's going to know he's been hit."
gsarff@meph.UUCP (Gary Sarff) (02/12/91)
In article <1995@cluster.cs.su.oz.au>, bruce@cs.su.oz (Bruce Janson) writes: >In article <13772@lanl.gov> jlg@lanl.gov (Jim Giles) writes: >>.. The I/O call (below, RW >>stands for _either_ the read or the write system call) should be >>something like the following: >> >>RW(fd,nw,buf,da,aflag,handle) >>.. >>da - logical disk address (relative to beginning of file) for I/O >> transfer. lseek() is redundant and in this model would disappear. >> If da is -1, transfer is sequential from previous request. >>.. > >Jim, > Above, you have outlined part of an async I/O interface. But there >are some issues that I am still not clear about that perhaps you might >like to clear up. I am now keeper of the sources of a multiuser/tasking OS at work that has async, I/O so, as the poster bruce says at the end of his posting, some of these questions have been answered in different ways at different places/times. Some of his questions, all of which are valid, I can not answer because we do not have callback functions when I/O is complete. I'll take a shot at the rest. > When you say "transfer is sequential from previous request" do you >mean the previously issued request or the previously completed request? Sequential from the last completed request. >More generally, in what context does the I/O get done? The I/O request is of course queued to the driver in the requesting process' context, (thread of execution through the driver). >In what context does the I/O completion function run? Are the machine >operations of either the I/O copy or the completion function interleaved with >those of the rest of the program or is the "rest of the program" >suspended while the I/O and its completion routine run. The rest of the program continues to execute or remains in an executable state while the I/O is happening, it is not suspended as I am understanding your question. >Is the contents of the area of memory pointed to by "buf" updated >atomically with respect to the process? Yes, in fact I will mention that we do place some restrictions on the I/O async I/O requests, that we do not place on synchronous I/O. To wit, the I/O request must begin on a sector boundary, and the destination buffer must be wholly contained within one 4K page of memory, i.e, cannot cross a page boundary. These requests are limited in this fashion mainly for simplicity of implementation, and next for efficiency sake. The buffer alignment condition can be easily satisfied because the OS has a system call that will allocate any number of 4K pages into a process' logical address space at whatever address the process requests, (as long of course as there is not some memory already allocated there.) All this is of course because we DMA the disk request. The physical address of the requesting process' buffer pages are resolved at the time the request is made from their logical address space, and those pages are marked as unswappable until the I/O completes, or the timeout expires. Unlike UNIX where a process makes an I/O request and then sets an alarm if needed, we incorporate a timeout value (in 100'ths of a second) into the I/O request itself. >Is the I/O completion routine called with any arguments? >Can the I/O completion routine call sleep()? Where does a longjmp() >take me from within such an I/O completion routine? What does a setjmp() >do when executed from within such an I/O completion routine? How about calls >to the signal() family of routines and can the I/O completion routine >be interrupted by an incoming signal? What exits when I call exit() >from within an I/O completion routine? What happens when the main >program calls exit() while there are still I/O requests outstanding? I cannot answer most of the above as I said because we don't do user I/O completion routines. The I/O completion itself happens in an interrupt routine, and it can of course be any arbitrary process on the system that was interrupted. What happens in this routine also answers the last question in the above paragraph. When a program dies, of its own free will or because another process or the OS kills it, all of its memory pages are deallocated and returned to the system free memory list. The pages that have Async I/O's pending were marked as such in the memory control structures (a bit was set), and those pages are not deallocated. They are placed on a pending deallocation list. The interrupt routine that handles the I/O completion clears this bit. Periodically the OS scans the list and pages that have their bit cleared can be returned to the OS free memory list. The list will also be scavenged by the OS before it comtemplates swapping of any process' address space because of memory shortage. >What happens if my process calls close() on an fd that is still >associated with outstanding async I/O? The same thing as the previous paragraph regarding processes dieing. >How many concurrent outstanding I/O requests can my process have at >the one time and can I prioritise and/or schedule them? No limit except that imposed by your memory and how much the control structures take up, which is only 20-30 bytes, by many megabytes of memory, that is a lot of I/O requests. >Can a process enquire as to the status of a particular >outstanding I/O request and if so, what naming scheme should it use >to refer to the I/O request of interest. Yes, you enquire by asking about the file handle (LUN, we call it ,Logical Unit Number,) and the offset into that file that was given in the original request. >How do I terminate an >outstanding I/O request prematurely? We currently do not implement this feature. >Can an I/O completion routine >make further async I/O calls itself? No completion routines, but it is possible that the interrupt routine that handles completed I/O could make additional requests, and often does, as this is one part of the way we implement read-aheads. > It is possible to devise answers for all of these questions. >And async I/O does exist in various operating systems so answers must >have been devised. However, after considering these questions I might >conclude that async I/O would need to bring with it some very >significant advantages to offset what appears to be a more complex model. Our more limited model does not seem to impose significant disadvantages, or unduly burden the system, in my view. But, I am the last source keeper, not the original designer, and though I have talked with him often, I do not know all the historical reasons he may have had, behind all the different features. I know we use it in some tasks, for instance, process activation from the image file on disk, is done using these async I/O (we call them fastreads), some utilities and other application programs use it. For instance a BACKUP program, upon entering a new sub directory, will read the directory in one sweep, generate open, and fast read requests for all the files that match its file specifications, and then start backing up the first file to tape. By the time it gets to subsequent files, it is hoped that some of them have already been read into memory buffers and can now also be backed up to tape. It helps keep the tape at streaming speed, at any rate.