[comp.lang.misc] UNIX semantics do permit full support for asynchronous I/O

steve@nuchat.UUCP (Steve Nuchia) (08/29/90)

On the subject of asynchronous I/O in Unix:  I've come up with
what I consider a rather slick way of making it fit neatly
into Unix's way of doing things:

Have read(2) and write(2) calls map the pages containing the buffers
out of the user address space and return immediately.  Once the
data have been copied (DMAed?) to/from the buffers, map the pages back in.

A user program that is not aware of the subterfuge will then run
along for some (probably short) time and trap on an attempt to
refill or inspect the buffer.  It will then be blocked until
the request completes.  A savvy program will do something else
for as long as it can, then take a peek at the buffer when it
has run out of busy work.  One would probably also provide
(grudgingly, in my case) an explicit call for discovering the status.

(Note that such a call might be useful to a program that
wished to control its paging behaviour if it were written with
sufficient generality.)

The scheme will only provide asynchronicity in cases where the
return value for the read or write call is known early.  This
will be the case primarily for files, but other cases can be
made to take advantage of it.

The performance characteristics would be similar to using mmap
but would apply to programs written in normal unix style and
to dusty decks.  One must of course take some care in implementing
the scheme, and there are no doubt the usual raft of gotchas that
come up when doing anything involving memory management.  The
case of write(1,buf,read(0,buf,sizeof(buf))) is entertaining to
contemplate for instance.

Good performance with V7 file system call semantics.  Programs
work whether the feature is in the kernel or not and whether they
are written to take advantage of it or not.  I sure wish I
had thought of it a long time ago (like while the standards
were still soft).

I would appreciate any comments that wizards with more kernel
internals experience might have.  If I've rediscovered something
well-known again I think I shall slit my wrists.

(For completeness I will note that to use this scheme intelligently
you must be able to discover the relevant properties of the memory
management implementation.  This is nothing new for high performance
programs in a paged environment, but unless its been added recently
there isn't a standard way to do it.  Whether this is properly a
language or a system interface issue is best left to another debate.)
-- 
Steve Nuchia	      South Coast Computing Services      (713) 964-2462
"To learn which questions are unanswerable, and _not_to_answer_them;
this skill is most needful in times of stress and darkness."
		Ursula LeGuin, _The_Left_Hand_of_Darkness_

lewine@dg-rtp.dg.com (Donald Lewine) (08/29/90)

In article <27619@nuchat.UUCP>, steve@nuchat.UUCP (Steve Nuchia) writes:
|> (For completeness I will note that to use this scheme intelligently
|> you must be able to discover the relevant properties of the memory
|> management implementation.  This is nothing new for high performance
|> programs in a paged environment, but unless its been added recently
|> there isn't a standard way to do it.  Whether this is properly a
|> language or a system interface issue is best left to another debate.)
|> -- 

That last remark defeats your entire suggestion.  If I have to
"discover the relevant properties of the memory management 
implementation", all dusty decks will fail.  

If you blindly map the page(s) containing "buf" out of the users
address space you will map out other variables that the user may
want.  It is not possible for the compiler to know that buf must
be on a page by itself.  How could you implement your scheme?

Also the read() and write() functions return the number of characters
read or written.  How do you know this before the read() or write()
completes?  Do you assume that all disks are error free and never
fail?  That is a poor assumption!

I don't think that your idea works at all.  For a scheme that does
almost exactly this, but with the cooperation of the user program,
look at PMAP under DEC's TOPS-20 operating system or ?SPAGE under
DG's AOS/VS.

--------------------------------------------------------------------
Donald A. Lewine                (508) 870-9008
Data General Corporation        (508) 366-0750 FAX
4400 Computer Drive. MS D112A
Westboro, MA 01580  U.S.A.

uucp: uunet!dg!lewine   Internet: lewine@cheshirecat.webo.dg.com

rsc@merit.edu (Richard Conto) (08/30/90)

In article <27619@nuchat.UUCP> steve@nuchat.UUCP (Steve Nuchia) writes:
>On the subject of asynchronous I/O in Unix:  I've come up with
>what I consider a rather slick way of making it fit neatly
>into Unix's way of doing things:
>
>Have read(2) and write(2) calls map the pages containing the buffers
>out of the user address space and return immediately.  Once the
>data have been copied (DMAed?) to/from the buffers, map the pages back in.
>
>A user program that is not aware of the subterfuge will then run
>along for some (probably short) time and trap on an attempt to
>refill or inspect the buffer.  It will then be blocked until
>the request completes.  A savvy program will do something else
>for as long as it can, then take a peek at the buffer when it
>has run out of busy work.  One would probably also provide
>(grudgingly, in my case) an explicit call for discovering the status.
 
A buffer is not necessarily aligned on a page boundary. And a page
may contain more than one variable.  The savvy program would have to
design it's data structures (including local variable arrangement, if
a buffer happens to be there) to be aware of whatever peculiar way
the complier lays out variables and whatever peculiar granularity the
OS has for pages.

Make it simpler. Have a routine that requests an I/O operation. Another
routine that can check it's status. A way of specifying a routine to be
called when the I/O operation completes might be yet another option.
I'm afraid that your idea adds unnecessary complexity (and system dependancies).
And using constructs like 'write(fdout,buf,read(fdin,sizeof(buf), buf))' is
asking for trouble when 'read()' returns an error condition.

--- Richard

jlg@lanl.gov (Jim Giles) (08/30/90)

From article <27619@nuchat.UUCP>, by steve@nuchat.UUCP (Steve Nuchia):
> On the subject of asynchronous I/O in Unix:  I've come up with
> what I consider a rather slick way of making it fit neatly
> into Unix's way of doing things:
> 
> Have read(2) and write(2) calls map the pages containing the buffers
> out of the user address space and return immediately.  Once the
> data have been copied (DMAed?) to/from the buffers, map the pages back in.
> [...]

Yes, this will work.  I believe that MACH already does this.
Unfortunately, this idea has two problems: 1) not all machines are
paged/segmented; 2) not all I/O requests are a multiple of the
pagesize.  The first problem is more severe - hardware designers avoid
pages/segments when designing for speed.  The extra hardware overhead
is 10% speed or about that for extra hardware cost.  So they are
avoided (Crays don't have pages or segments).  The pagesize problem
just means that you'd have to map out more memory than is actually
involved in the I/O request.  This means that the user might get
blocked on memory that is really perfectly safe to access - a minor
source of slowdown.

J. Giles

merriman@ccavax.camb.com (08/30/90)

In article <1990Aug29.170931.10853@terminator.cc.umich.edu>, 
	rsc@merit.edu (Richard Conto) writes:

> 
> Make it simpler. Have a routine that requests an I/O operation. Another
> routine that can check it's status. A way of specifying a routine to be
> called when the I/O operation completes might be yet another option.

Sure sounds like VMS QIO calls.

bdsz@cbnewsl.att.com (bruce.d.szablak) (08/30/90)

In article <1990Aug29.170931.10853@terminator.cc.umich.edu>, rsc@merit.edu (Richard Conto) writes:
> In article <27619@nuchat.UUCP> steve@nuchat.UUCP (Steve Nuchia) writes:
> >Have read(2) and write(2) calls map the pages containing the buffers
> >out of the user address space and return immediately.
>  
> A buffer is not necessarily aligned on a page boundary. And a page
> may contain more than one variable.

Actually, the OS only has to mark the pages as copy on write. This sort
of thing is often done when a process forks to avoid making a copy of the data
space for the child. Whether its worth it is another matter.

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (08/31/90)

In article <861@dg.dg.com> uunet!dg!lewine writes:
> In article <27619@nuchat.UUCP>, steve@nuchat.UUCP (Steve Nuchia) writes:
> > (For completeness I will note that to use this scheme intelligently
> > you must be able to discover the relevant properties of the memory
> > management implementation.
> That last remark defeats your entire suggestion.  If I have to
> "discover the relevant properties of the memory management 
> implementation", all dusty decks will fail.  

No. Steve's point was that on paged architectures, he can get a low-cost
speedup out of some programs without any change in semantics. This is a
worthwhile change.

Discovering memory managemment can be as simple as having a system call
getpage() that returns a char buffer taking up exactly one page. Any
code that understands this can take full advantage of asynchronous I/O.

> If you blindly map the page(s) containing "buf" out of the users
> address space you will map out other variables that the user may
> want.  It is not possible for the compiler to know that buf must
> be on a page by itself.  How could you implement your scheme?

So what if there are other variables on the page? The worst that happens
is that the page gets mapped out and then back in; on paged hardware,
this cost is negligible. The best that happens is that the program uses
getpage() and guarantees that it will wait for the I/O to finish on that
page.

> Also the read() and write() functions return the number of characters
> read or written.  How do you know this before the read() or write()
> completes?  Do you assume that all disks are error free and never
> fail?  That is a poor assumption!

So what? read() and write() already return before data gets written out
to disk; assuming that you see all I/O errors before a sync is the poor
assumption! This is irrelevant to the issue at hand.

---Dan

stripes@eng.umd.edu (Joshua Osborne) (08/31/90)

In article <61535@lanl.gov> jlg@lanl.gov (Jim Giles) writes:
>From article <27619@nuchat.UUCP>, by steve@nuchat.UUCP (Steve Nuchia):
[...]
>> Have read(2) and write(2) calls map the pages containing the buffers
>> out of the user address space and return immediately.  Once the
>> data have been copied (DMAed?) to/from the buffers, map the pages back in.
>> [...]
>
>Yes, this will work.  I believe that MACH already does this.
>Unfortunately, this idea has two problems: 1) [omited]
>2) not all I/O requests are a multiple of the pagesize.
>The pagesize problem
>just means that you'd have to map out more memory than is actually
>involved in the I/O request.  This means that the user might get
>blocked on memory that is really perfectly safe to access - a minor
>source of slowdown.

It shouldn't be a source of slowdown in the read case; normally the program
would not get control untill after the read was done, the new worst case is
exactly the same.  However for reads the old best case is far better then
the new worst case, and it could happen relitavly offen.

The old best case: do a large write, the kernel copys the data lets you run
and writes it some time, you re-use the buffer.

If you do that under the new system:  You do the large write the kernal maps
out the pages,  gives you control you re-use the buffer, the kernel makes you
sleep untill it can do the write.  You lose out.  Alot of programs do this.
Currently stdio does this.  Of corse stdio would need a bit of tweeking anyway.
(allign page sized buffers on page boundrys)  While we are in there we could
make writes use 2 page buffers, and flush alterniate ones...  and do huge
writes directly out of the users space.

(just things to think about, I do like the idea...)
-- 
           stripes@eng.umd.edu          "Security for Unix is like
      Josh_Osborne@Real_World,The          Mutitasking for MS-DOS"
      "The dyslexic porgramer"                  - Kevin Lockwood
"Isn't that a shell script?"                                    - D. MacKenzie
"Yeah, kinda sticks out like a sore thumb in the middle of a kernel" - K. Lidl

peter@ficc.ferranti.com (Peter da Silva) (08/31/90)

In article <861@dg.dg.com> uunet!dg!lewine writes:
> That last remark defeats your entire suggestion.  If I have to
> "discover the relevant properties of the memory management 
> implementation", all dusty decks will fail.  

You only have to do this if you want to get some additional
performance. It should still work regardless.

> Also the read() and write() functions return the number of characters
> read or written.  How do you know this before the read() or write()
> completes?  Do you assume that all disks are error free and never
> fail?  That is a poor assumption!

Well, it's an assumption made for write() anyway. For read() you can just
treat it like any disk error on any other faulted-in page and blow off the
process. Disk errors are a very rare occurrence, and almost always require
human intervention anyway. Any other return value for read is known
ahead of time.
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
peter@ferranti.com

lfd@cbnewsm.att.com (leland.f.derbenwick) (08/31/90)

In article <27619@nuchat.UUCP>, steve@nuchat.UUCP (Steve Nuchia) writes:
> On the subject of asynchronous I/O in Unix:  I've come up with
> what I consider a rather slick way of making it fit neatly
> into Unix's way of doing things:
> 
> Have read(2) and write(2) calls map the pages containing the buffers
> out of the user address space and return immediately.  Once the
> data have been copied (DMAed?) to/from the buffers, map the pages back in.
> 
> A user program that is not aware of the subterfuge will then run
> along for some (probably short) time and trap on an attempt to
> refill or inspect the buffer.  It will then be blocked until
> the request completes.  A savvy program will do something else
> for as long as it can, then take a peek at the buffer when it
> has run out of busy work.  One would probably also provide
> (grudgingly, in my case) an explicit call for discovering the status.

Apart from the implementation problems that others have mentioned,
_this suggestion breaks existing code_.

In essentially any serious database application, a completed
write() to a raw disk is treated as a guarantee that the data
block has been _physically written to the device_.  (This is
needed to ensure reliable transaction behavior in the presence
of potential system crashes.)  Since your suggestion would void
that guarantee, it is not benign.

On the other hand, I like your idea of implementing asynchronous
behavior using the ordinary read() and write() calls.  So how
difficult would it be to add a couple ioctl's to the existing
raw disk driver to support that?

One ioctl would select sync/async reads/writes (the default would
be the present behavior: sync read, sync write).  The other ioctl
would do the status inquiry.  With these, asynchronous behavior
is available on demand, and the OS doesn't need to jump through
any hoops to make it transparent: it's up to the user to use the
facility properly.

This is a lot cleaner than implementing asynchronous I/O in user
mode with shared memory and a background process...

 -- Speaking strictly for myself,
 --   Lee Derbenwick, AT&T Bell Laboratories, Warren, NJ
 --   lfd@cbnewsm.ATT.COM  or  <wherever>!att!cbnewsm!lfd

brians@hpcljms.HP.COM (Brian Sullivan) (08/31/90)

> Have read(2) and write(2) calls map the pages containing the buffers
> out of the user address space and return immediately.  Once the
> data have been copied (DMAed?) to/from the buffers, map the pages back in.

  Well,  I suspect that this solution will not work with most C programs.
Why, because most of the time read(2) and write(2) are called with a
buffer that is an auto-variable or stack allocated.  Telling the MMU to
unmap a page in the users stack will have very dire consequences.  Maybe
a better idea would be a new memory allocation, combined with new read(2)
and write(2) calls.  Using this method the need to copy the users data
would be solved.

   kalloc :  allocate pages in kernal memory
   kwrite :  perform write without copying memory into kernal data area
   kread  :  perform read without copying memory into kernal data area


  You might want to investigate the POSIX working group P1003.4 which
deals with real-time issues.  They are creating the next generation
UNIX standard that will support threads, async_io, real-time scheduling
and other real-time issues.

utoddl@uncecs.edu (Todd M. Lewis) (08/31/90)

In article <31445.26dc0466@ccavax.camb.com> merriman@ccavax.camb.com writes:
>In article <1990Aug29.170931.10853@terminator.cc.umich.edu>, 
>	rsc@merit.edu (Richard Conto) writes:
>
>> 
>> Make it simpler. Have a routine that requests an I/O operation. Another
>> routine that can check it's status. A way of specifying a routine to be
>> called when the I/O operation completes might be yet another option.
>
>Sure sounds like VMS QIO calls.

Sounds like the Amiga's OS to me.  And UNIX doesn't do this?
I'm trying to be a UNIX nut in training, but I keep hearing about
these new tricks that seem to be rather hard to teach the
old dog.  I'd hate to wake up in 5 years and realize that UNIX
had become to workstations what MS-DOS is to PCs now.  Somebody
pinch me.

meissner@osf.org (Michael Meissner) (08/31/90)

In article <960022@hpcljms.HP.COM> brians@hpcljms.HP.COM (Brian
Sullivan) writes:

| > Have read(2) and write(2) calls map the pages containing the buffers
| > out of the user address space and return immediately.  Once the
| > data have been copied (DMAed?) to/from the buffers, map the pages back in.
| 
|   Well,  I suspect that this solution will not work with most C programs.
| Why, because most of the time read(2) and write(2) are called with a
| buffer that is an auto-variable or stack allocated.  Telling the MMU to
| unmap a page in the users stack will have very dire consequences.  Maybe
| a better idea would be a new memory allocation, combined with new read(2)
| and write(2) calls.  Using this method the need to copy the users data
| would be solved.

What are you talking about?  How is unmapping a page because of an I/O
request (with an intent to map it back in when the I/O completes and
having page faults wait for the I/O completion) any different from any
normal time the OS unmaps a page to reuse the memory for something
else.  That is not a dire consequence, that is how virtual memory
works.
--
Michael Meissner	email: meissner@osf.org		phone: 617-621-8861
Open Software Foundation, 11 Cambridge Center, Cambridge, MA, 02142

Do apple growers tell their kids money doesn't grow on bushes?

pplacewa@bbn.com (Paul W Placeway) (09/01/90)

peter@ficc.ferranti.com (Peter da Silva) writes:

< ... Disk errors are a very rare occurrence, and almost always require
< human intervention anyway. Any other return value for read is known
< ahead of time.

Unless your "disk" is RFS and the remote machine crashes, or soft
mounted NFS and any one of about a zillion things happens...


		-- Paul Placeway

eliot@dg-rtp.dg.com (Topher Eliot) (09/01/90)

In article <12023:Aug3017:24:1590@kramden.acf.nyu.edu>,
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
|> 
|> > Also the read() and write() functions return the number of
characters
|> > read or written.  How do you know this before the read() or
write()
|> > completes?  Do you assume that all disks are error free and never
|> > fail?  That is a poor assumption!
|> 
|> So what? read() and write() already return before data gets written
out
|> to disk; assuming that you see all I/O errors before a sync is the
poor
|> assumption! This is irrelevant to the issue at hand.

I think this point very well covers the case of writing:  if you want
to be sure it really got to disk, you need to do an fsync(), and even
then I'm not sure you can be sure (doesn't the fsync just *mark* the
buffers for writing out?).  We could certainly arrange for fsync to
block until everything is really on disk.

But consider the reading case.  Here, we could tell the process how
many bytes it had "gotten" (was going to get), even if it was less
than the process had requested (presumably the kernel knows how big
the file is, without having to read all those bytes off disk).  The
application then might do something *other than examining the bytes
it just "read"* based on this knowledge of a "successful read".  If
the disk then fails (or the net fails, or whatever), the application
would have acted incorrectly.  Moreover, instead of the application
learning about the failure by getting -1 back from a read call, it
will learn about it by receiving a signal or some such.

So, can anyone think of an application that behaves in this manner
(i.e.  acts upon the return value from a read by doing something
important, that does not involve examining the read buffer)?  I can't.
Perhaps more significant is the issue of the application not getting a
-1 back from the read call.

--
Topher Eliot
Data General Corporation                eliot@dg-rtp.dg.com
62 T. W. Alexander Drive               
{backbone}!mcnc!rti!dg-rtp!eliot
Research Triangle Park, NC 27709        (919) 248-6371
Obviously, I speak for myself, not for DG.

hunt@dg-rtp.dg.com (Greg Hunt) (09/01/90)

In article <1990Aug31.190751.12522@dg-rtp.dg.com>, eliot@dg-rtp.dg.com
(Topher Eliot) writes:
>
> But consider the reading case.  Here, we could tell the process how
> many bytes it had "gotten" (was going to get), even if it was less
> than the process had requested (presumably the kernel knows how big
> the file is, without having to read all those bytes off disk).  The
> application then might do something *other than examining the bytes
> it just "read"* based on this knowledge of a "successful read".  If
> the disk then fails (or the net fails, or whatever), the application
> would have acted incorrectly.  Moreover, instead of the application
> learning about the failure by getting -1 back from a read call, it
> will learn about it by receiving a signal or some such.
> 
> So, can anyone think of an application that behaves in this manner
> (i.e.  acts upon the return value from a read by doing something
> important, that does not involve examining the read buffer)?  I
can't.
> Perhaps more significant is the issue of the application not getting
a
> -1 back from the read call.
> 
> Topher Eliot
>

Yes, I can.  Under Data General's AOS/VS OS, I wrote a program that
read blocks from tape drives and checked the sizes of the blocks read.
The program was for verifying that labeled backup tapes were
physically readable.

The header label on the tape contained buffersize information which
the program used to read the data blocks.  As each block was read,
the size of the read returned by the OS was checked against the
buffersize to ensure that full buffer reads were done.  It also
counted the number of blocks read.  It discarded the contents of the
read buffer without looking at them.

The trailer label on the tape contained block count information that
was written by the OS.  The OS's block count was compared against the
block count seen by the program.

All of these checks were only to ensure that the tape could be
physically read.  Using it eliminated ALL bad backup tapes that I was
encountering.  Sometimes I found that I could write a tape, but not
read it again.  Tapes that could not be verified by this program were
discarded.  The program did nothing to ensure that the tape could
be logically read by the load program used to restore files, so it
did nothing to guard against bugs in the dump/load programs
themselves.

I have yet to port the program to DG/UX to verify UNIX backup tapes in
a similar manner.  I believe the program could be made to serve a
similar purpose, but I'd probably have to change the header/trailer
handling since AOS/VS uses ANSI standard tape labels and I don't think
that UNIX does.

Does this example meet the behavior that you were wondering about?  It
may be a specialized use of the results of a read and not be
representative of what applications-level software does.

--
Greg Hunt                        Internet: hunt@dg-rtp.dg.com
DG/UX Kernel Development         UUCP:     {world}!mcnc!rti!dg-rtp!hunt
Data General Corporation
Research Triangle Park, NC       These opinions are mine, not DG's.

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (09/01/90)

In article <1990Aug31.190751.12522@dg-rtp.dg.com> eliot@dg-rtp.dg.com writes:
> I think this point very well covers the case of writing:  if you want
> to be sure it really got to disk, you need to do an fsync(), and even
> then I'm not sure you can be sure (doesn't the fsync just *mark* the
> buffers for writing out?).  We could certainly arrange for fsync to
> block until everything is really on disk.

fsync() will certainly do that, independently of this mechanism. (It's
sync() that just marks buffers for writing. BSD's fsync() truly writes
the data to disk, giving the transaction control you need for reliable
databases. I have no idea what you poor System V folks do.)

> But consider the reading case.
  [ what happens upon failure? ]

As Peter pointed out, this case is fatal. How many disk errors have you
had over the last year? How many did the programs involved recover from?
Yeah, thought so.

I guess you're right in principle: Steve's proposal is only completely
transparent for writing (which is the more important case anyway).

---Dan

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (09/02/90)

In article <960022@hpcljms.HP.COM>, brians@hpcljms.HP.COM (Brian Sullivan) writes:
>   Well,  I suspect that this solution will not work with most C programs.
> Why, because most of the time read(2) and write(2) are called with a
> buffer that is an auto-variable or stack allocated.

Surely, most of the time read(2) and write(2) are called by the <stdio>
implementation, and _that_ uses heap-allocated buffers.  You _can_ make
a stdio stream use a stack-allocated buffer, but it requires an explicit
call to setbuf() or one of its relatives.
-- 
You can lie with statistics ... but not to a statistician.

dag@gorgon.uucp (Daniel A. Glasser) (09/04/90)

[was x-posted in comp.unix.wizards and comp.lang.misc]

In article <1990Aug31.142906.26633@uncecs.edu> utoddl@uncecs.edu (Todd M. Lewis) writes:
>In article <31445.26dc0466@ccavax.camb.com> merriman@ccavax.camb.com writes:
>>Sure sounds like VMS QIO calls.
>Sounds like the Amiga's OS to me.  And UNIX doesn't do this?

Well, standard Unix doesn't do this.  VMS always has, so has RSX-11, and
to some degree, even RT-11.  The Amiga OS is a rather recent invention, and
appears to use this old tried and true technique.

For those not familiar with the QIO concept, a read or write QIO is issued
with a special call that allows the application to proceed and be notified
by either a signal (AST in VMS technology) or an event flag.  When the
application needs to use the buffer it either checks the flag or waits until
the signal routine is executed.  Another QIO can be used to determine the
number of bytes read/written, the error status, etc.

This extends beyond doing solicited buffered I/O to unsolicited I/O.
In Unix, when a program wants to do processing in the background while
waiting for keyboard input, it either forks a child to do one or the
other, or polls the tty for input.  Under RSX or VMS, the program attatches
to the keyboard, specifies an unsolicited input Asynch. System Trap (AST)
service routine and goes about its business.  When the user types a key,
the main thread of execution is suspended and the AST service routine is called
to handle the keyboard input.  When done, the AST service routine returns
and the interrupted background processing continues as if nothing has happened.
When you get the hang of it, this is a very simple way to write programs.
I miss this capability in Unix, but have simulated it many times with
fork and signal.

As an extension to Unix, I would suggest the following:

  int writea(int fileno, void *buffer, size_t buflen, void (*complete_rtn)());
  int reada(int fileno, void *buffer, size_t buflen, void (*complete_rtn)());
	where fileno is the file number, buffer is a pointer to the
	bytes to be written/read, buflen is the number of bytes to
	be written/read from/to the buffer, and complete_rtn points
	to a function to be called when the read/write is complete.
	Maybe there should be an additional parameter or two -- flags
	modifying the actions, and a parameter to be passed to the
	completion routines.  The completion routines should take as
	a parameter the result of the write/read.  These routines return
	a status which indicates whether the async. read/write request
	is valid or not.  Care should be taken not to read/write
	the buffer area until the completion routine is called.

Since these are not changes to the existing read/write system calls,
dusty decks would not be broken.  They could also not take advantage
of the new functionality.  (The above proposal is close to the RT-11
completion routine scheme.)

If this debate goes on much longer, I'd suggest that it get removed
from comp.lang.misc, since this is not a language depenent issue.
-- 
Daniel A. Glasser                       One of those things that goes
dag%gorgon@persoft.com                  "BUMP! (ouch!)" in the night.

peter@ficc.ferranti.com (Peter da Silva) (09/05/90)

In article <59247@bbn.BBN.COM> pplacewa@bbn.com (Paul W Placeway) writes:
> peter@ficc.ferranti.com (Peter da Silva) writes:
> < ... Disk errors are a very rare occurrence, and almost always require
> < human intervention anyway. Any other return value for read is known
> < ahead of time.

> Unless your "disk" is RFS and the remote machine crashes, or soft
> mounted NFS and any one of about a zillion things happens...

This is an optimisation. You don't have to enable it for network
file systems, or raw disk devices, or whatever else. Most programs
can't recover from a disk fault, or a network fault, so blowing the
program away when you fault to the bogus page is perfectly legitimate.
Programs that *can* recover can either be run in a lower performance
mode or be rewritten to handle this error.
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
peter@ferranti.com

peter@ficc.ferranti.com (Peter da Silva) (09/05/90)

In article <1990Aug31.190751.12522@dg-rtp.dg.com> eliot@dg-rtp.dg.com writes:
> So, can anyone think of an application that behaves in this manner
> (i.e.  acts upon the return value from a read by doing something
> important, that does not involve examining the read buffer)?  I can't.

Any program that reads a whole file at a time, like GNU Emacs or TCL.
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
peter@ferranti.com