home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / biblioteki / c_library / asyncio / asyncio.doc next >
Text File  |  1977-12-31  |  23KB  |  592 lines

  1. TABLE OF CONTENTS
  2.  
  3. asyncio/--background--
  4. asyncio/--history--
  5. asyncio/--changes--
  6. asyncio/CloseAsync
  7. asyncio/OpenAsync
  8. asyncio/ReadAsync
  9. asyncio/ReadCharAsync
  10. asyncio/SeekAsync
  11. asyncio/WriteAsync
  12. asyncio/WriteCharAsync
  13. asyncio/--background--                                 asyncio/--background--
  14.  
  15. This documentation and source code was written by Martin Taillefer.
  16.  
  17. Reading and writing data is crucial to most applications and is in many cases
  18. a major bottleneck. Using AmigaDOS' sophisticated file system architecture
  19. can help reduce, and sometimes eliminate, the time spent waiting for IO to
  20. complete. This package offers a few small routines that can greatly improve
  21. an application's IO performance.
  22.  
  23. Normally, an application processes a file in a manner similar to the following:
  24.  
  25.   1 - Open the file
  26.  
  27.   2 - Read some data
  28.  
  29.   3 - Process data just read
  30.  
  31.   4 - Repeat steps 2 and 3 until all data is processed
  32.  
  33.   5 - Close file
  34.  
  35. Although the above sequence works fine, it doesn't make full use of the Amiga's
  36. multitasking abilities. Step 2 in the above can become a serious bottleneck.
  37. Whenever the application needs some data by using the DOS Read() function,
  38. AmigaDOS has to put that task to sleep, and initiate a request to the file
  39. system to have it fetch the data. The file system then starts up the disk
  40. hardware and reads the data. Once the data is read, the application is woken up
  41. and can start processing the data just read.
  42.  
  43. The point to note in the above paragraph is that when the file system is
  44. reading data from disk, the application is asleep. Wouldn't it be nice if the
  45. application could keep running while data is being fetched for it?
  46.  
  47. Most Amiga hard drives make use of DMA (Direct Memory Access). DMA enables a
  48. hard drive to transfer data to memory _at the same time_ as the CPU does some
  49. work. This parallelism is what makes the set of accompanying routines so
  50. efficient. They exploit the fact that data can be transfered to memory while
  51. the application is busy processing other data.
  52.  
  53. Using the asynchronous IO routines, an application's IO happens like this:
  54.  
  55.   1 - Open the file, ask the file system to start reading ahead
  56.  
  57.   2 - Read some data, ask the file system to read more data
  58.  
  59.   3 - Process data
  60.  
  61.   4 - Repeat steps 2 and 3 until all data is processed
  62.  
  63.   5 - Close file
  64.  
  65. Immediately after opening the file, a request is sent to the file system to get
  66. it reading data in the background. By the time the application gets around to
  67. reading the first byte of data, it is likely already in memory. That means the
  68. application doesn't need to wait and can start processing the data. As soon as
  69. the application starts processing data from the file, a second request is sent
  70. out to the file system to fill up a second buffer. Once the application is done
  71. processing the first buffer, it starts processing the second one. When this
  72. happens, the file system starts filling up the first buffer again with new
  73. data. This process continues until all data has been read.
  74.  
  75. The whole technique is known as "double-buffered asynchronous IO" since it uses
  76. two buffers, and happens in the background (asynchronously).
  77.  
  78. The set of functions presented below offers high-performance IO using the
  79. technique described above. The interface is very similar to standard AmigaDOS
  80. files. These routines enable full asynchronous read/write of any file.
  81.  
  82. asyncio/--history--                                       asyncio/--history--
  83.  
  84. 23-Mar-94
  85. ---------
  86.  
  87.   - When seeking within the current read buffer, the wrong packet would be
  88.     sent out to be filled asynchronously. Depending on the data read from
  89.     the buffer, and how fast it was read, you could end up getting incorrect
  90.     data on subsequent ReadAsync() calls.
  91.  
  92.   - There was actually bufferSize*2 bytes allocated for IO buffers instead
  93.     of just bufferSize. This is fixed. So if you want the same effective
  94.     buffer size as before, you must double the value of the bufferSize
  95.     argument supplied to OpenAsync().
  96.  
  97.   - MEMF_PUBLIC is now specified for the IO buffers. This is in support
  98.     of VM hacks such as GigaMem.
  99.  
  100.   - A Seek() call had the mode and offset parameters reversed. The code worked,
  101.     because both values were luckily always 0, but it was not very clean.
  102.  
  103.   - Now uses a typedef for the AsyncFile structure, and enums for the
  104.     open modes and seek modes.
  105.  
  106. 16-Feb-94
  107. ---------
  108.  
  109.   - SeekAsync() now consistently works. It was getting confused when called
  110.     multiple times in a row with no intervening IO.
  111.  
  112.   - WriteAsync() would produce garbage in the destination file if it had
  113.     to bring up a "Disk is full" requester, and the user freed some room on
  114.     the disk and selected "Retry".
  115.  
  116. asyncio/--changes--                                       asyncio/--changes--
  117.  
  118. All changes described in this section were made by Magnus Holmgren. If you
  119. want to contact me about something, feel free to send a message to
  120. cmh@lls.se (cmh@augs.se) or "Magnus Holmgren", 2:204/204.6@fidonet.
  121.  
  122. I've been in contact with Martin Taillefer, and he is aware of me releasing
  123. new versions of (t)his code. However, he is not informed about the actual
  124. details of the changes. Thus, any comments about the code (and especially
  125. the changes) should not be sent to him. Most of my changes are noted in the
  126. sources with a comment that starts with "MH:".
  127.  
  128. The code was compiled using SAS/C. Earlier version were compiled with DICE
  129. 3.0. GCC should be able to compile it as well, without any (large) changes
  130. (although I haven't tested this).
  131.  
  132. The DICE link libraries are created with the help of the LbMake utility in
  133. the DICE package. The file Lib.Def contains the definitions for them.
  134.  
  135. Notes about the different link libraries:
  136.  
  137.   · The 'DLib' drawer contains DICE versions of the link libraries, and
  138.     'Lib' contains the SAS/C versions ('Libs' contains the shared library).
  139.  
  140.   · The asyncio.lib libraries should be used when creating standalone
  141.     versions of the program. The ASIO_NO_EXTERNALS versions will have an
  142.     extra 'e' "flag" in the name.
  143.  
  144.   · New link libraries with the "base name" asynciolib.lib are needed if
  145.     you want to use asyncio.library, and don't use the DICE -mi option (or
  146.     perhaps you want to have the autoinit code). Note that there is no
  147.     corresponding SAS/C asynciolib.lib. Link with any of the asyncio*.lib
  148.     link libraries to get the autoinit code, if needed (there is no glue
  149.     available, as I don't want to write it by hand ;).
  150.  
  151.   · The include file "include/diceclib/asyncio_protos.h" is for DICE 3.0.
  152.     This include file should go to "dinclude:clib" (you only need this to
  153.     use the -mi option to use inline Amiga function calls), whereas the
  154.     other ones should be copied to the respective drawers in
  155.     "dinclude:amiga??/" (DICE) or "include:" (SAS/C).
  156.  
  157. Notes about how to use the different link libraries:
  158.  
  159.   · To use the shared library:
  160.   
  161.     DICE  - Define ASIO_SHARED_LIB and link with asynciolib#?.lib if you
  162.             didn't use the -mi option, or you need the autoinit code.
  163.             Remember that you must copy include/diceclib/asyncio_protos,h
  164.             to dinclude:clib/ if you use the -mi option.
  165.  
  166.     SAS/C - Include <proto/asyncio.h>, and link with asyncio.lib if you
  167.             need the autoinit code. Currently there is no glue code
  168.             available, so you must include the proto-file. This proto file
  169.             defines ASIO_SHARED_LIB for you.
  170.  
  171.   · To use the link library for standalone programs:
  172.  
  173.     Simply link with the appropriate link library, and make sure you only
  174.     define ASIO_REGARGS when you want the regargs version.
  175.     
  176.     Warning for SAS/C users: If you link with the wrong library, the
  177.     program will link properly, but will show strange errors when run.
  178.  
  179.   · To use the "no externals" version of the link library:
  180.   
  181.     You need to compile the library for startes. ;) Then define
  182.     ASIO_NO_EXTERNALS.
  183.  
  184.     DICE  - To compile the library simply type e.g. "lbmake asyncio s r e"
  185.             and have dtmp: set to some temporary space. This creates a
  186.             regargs, smalldata version.
  187.  
  188.     SAS/C - Type e.g. "dmake lib/asyncioer.lib" to get the regargs version.
  189.  
  190. Notes:
  191.  
  192.   · When defining any ASIO_#? symbol above, it must be done before any
  193.     asyncio include file is read.
  194.  
  195.   · I haven't personally tested all combinations above. The shared library
  196.     have had some quick tests, while the "no external" versions of the link
  197.     libraries haven't even been compiled. ;)
  198.  
  199.   · SAS/C users still need dmake (from DICE) to compile things. This since
  200.     SMake lacks one very useful feature in DMake.
  201.  
  202. In the future I plan to add two new functions (which explains the "function
  203. order" in the shared library ;): ReadLineAsync and WriteLineAsync. I have
  204. fairly well working prototypes of them, but ReadLineAsync is a bit messy. I
  205. also need to test it a bit more...
  206.  
  207.   Release 7 - 7-Jan-96
  208.   --------------------
  209.  
  210.   · Files to use asyncio.library from E included.
  211.  
  212.   · Fixed yet some SeekAsync() problems. It could (still) get confused when
  213.     called multiple times in a row with no intervening IO. I wonder if 
  214.     there are any holes left. ;)
  215.  
  216.   · Some more fixes to the shared library.
  217.  
  218.   · asyncio.library bumped to version 37.2.
  219.  
  220.   · Recompiled asyncio.library using SAS/C 6.56, and added general SAS/C
  221.     support.
  222.  
  223.   · Cleaned up parts of this doc.
  224.  
  225.   Release 6 - 10-Nov-95
  226.   ---------------------
  227.  
  228.   · Bumped to version 6, since there was an "official" release 3 that I was
  229.     unaware of. However, most of the changes were in the AIFF source (see
  230.     below). Thus, not much was "lost" due to this. (In fact, the SeekAsync
  231.     bugfix in the real release 3 was not correct. ;)
  232.  
  233.   · Sigh. The SeekAsync fix (to the performance problem) was buggy. :/ I
  234.     think I've got it right now.
  235.  
  236.   · asyncio.library bumed to version 37.1.
  237.     
  238.   · Cleaned up this documentation.
  239.  
  240.   · Fixed some bugs in the include files.
  241.  
  242.   · Made some fixes to the shared library.
  243.   
  244.   Release 4 - 13-Sep-95
  245.   ---------------------
  246.  
  247.   · Oops. Forgot to include the include/asyncio.h file. Maybe as well,
  248.     since I anyway had forgot to mention a few things in it.. ;)
  249.  
  250.   · Asyncio is now also available as a shared library (to be placed in
  251.     libs:). This means that a couple of new include files were added, and a
  252.     one include file was split up.
  253.  
  254.     The main reason for doing this was to simplify the use of it in other
  255.     languages (only need to "port" a few includes). I have no other include
  256.     files than those for (DICE) C at the moment, but feel free to send me
  257.     headers for other languages as well.
  258.  
  259.     Note: I have not yet verified that the SeekAsync function works, but
  260.     since read and write works just fine, I see no reason why SeekAsync
  261.     wouldn't work. ;)
  262.  
  263.     Also, I haven't really used it in programs much either (only some
  264.     testing), so the different defines and similar to use different
  265.     versions may be a bit clumsy to use (see above for more information).
  266.     Feel free to send me comments on how to improve this.
  267.  
  268.   · Changed so that a non-regargs version of the link library can be
  269.     created. To use the regargs version now, simply make sure that
  270.     ASIO_REGARGS is defined, and link with the proper link library.
  271.  
  272.   · Changed the name of the NOEXTERNALS define to ASIO_NOEXTERNALS. Define
  273.     this before you include <clib/asyncio_protos.h> if you want to use that
  274.     feature. Note that you need to create a proper link library yourself!
  275.     (With DICE, all you need to do is "LbMake asyncio s r e" in the Src
  276.     drawer.)
  277.  
  278.   · Modified OpenAsync() a little, to work around a problem when having
  279.     SnoopDos (with SendARexx active), MungWall and Enforcer running. Not an
  280.     asyncio bug as such, but.. ;)
  281.  
  282.   Release 3 - 12-Aug-95
  283.   ---------------------
  284.  
  285.   This version includes a couple of enhancements (most from asyncio code
  286.   found in the sources to the AIFF datatype, by Olaf `Olsen' Barthel) and a
  287.   couple of bugfixes to SeekAsync():
  288.  
  289.   · SeekAsync() is now not unecessarely slow when doing some "kinds" of
  290.     read-mode seeks (typically when seeking after some small amount of
  291.     initial read). The problem was that it usually only considered the
  292.     newly arrived buffer, not both buffers. This could make it discard both
  293.     buffers, and restart reading, although one of the buffers already had
  294.     the needed data. Note that the kind of seeks that caused the above
  295.     problem may still seem to be somewhat slow, since the code must wait
  296.     for both buffers to be loaded. This cannot (easily) be avoided.
  297.  
  298.   · SeekAsync() doesn't cause the read buffer to contain garbage after
  299.     certain seeks any more. The problem was that ReadAsync() would read
  300.     from the wrong buffer (the one currently being loaded). This made the
  301.     files seem to contain garbage. This happened when the seek location
  302.     was within the newly arrived buffer.
  303.  
  304.   · The code package is now supplied as a link library, rather than a
  305.     single source module. The internal functions labeled "AS_#?" are
  306.     private and should not be called directly by the application.
  307.  
  308.   · A few minor "cosmetic" changes were done, to either make the code more
  309.     readable, or to make it slightly smaller.
  310.  
  311.   · Include file restructured a little (a public and a private part).
  312.     
  313.   · OpenAsync() now offers some new "options" (all from the AIFF code by
  314.     Olaf Barthel):
  315.     - Opening a file from an already open filehandle is now possible.
  316.     - A "no externals" version may be compiled, that doesn't require any
  317.        external variables to be available.
  318.     - Each of the buffers will now be roughly bufferSize / 2 bytes large,
  319.        rather than bufferSize bytes (rel 6 note: Really from Taillefers
  320.        third release).
  321.     - If there isn't enough memory for the requested buffer size, the code
  322.        will try with smaller buffers (still properly "aligned") before
  323.        giving up.
  324.  
  325. asyncio/CloseAsync                                         asyncio/CloseAsync
  326.  
  327.    NAME
  328.     CloseAsync -- close an async file.
  329.  
  330.    SYNOPSIS
  331.     success = CloseAsync( file );
  332.       d0                   a0
  333.  
  334.     LONG CloseAsync( struct AsyncFile * );
  335.  
  336.    FUNCTION
  337.     Closes a file, flushing any pending writes. Once this call has been
  338.     made, the file can no longer be accessed.
  339.  
  340.    INPUTS
  341.     file - the file to close. May be NULL, in which case this function
  342.            returns -1 and sets the IoErr() code to ERROR_INVALID_LOCk.
  343.  
  344.    RESULT
  345.     result - < 0 for an error, >= 0 for success. Indicates whether closing
  346.          the file worked or not. If the file was opened in read-mode,
  347.              then this call will always work. In case of error,
  348.              dos.library/IoErr() can give more information.
  349.  
  350.    SEE ALSO
  351.     OpenAsync(), dos.library/Close()
  352.  
  353. asyncio/OpenAsync                                           asyncio/OpenAsync
  354.  
  355.    NAME
  356.     OpenAsync -- open a file for asynchronous IO.
  357.  
  358.    SYNOPSIS
  359.     file = OpenAsync( fileName, accessMode, bufferSize
  360.      d0                  a0         d0          d1
  361.                                            [, sysbase, dosbase ] );
  362.                                                 a1       a2
  363.  
  364.     struct AsyncFile OpenAsync( const STRPTR, UBYTE, LONG
  365.                        [, struct ExecBase *, struct DosLibrary * ] );
  366.  
  367.     file = OpenAsyncFromFH( handle, accessMode, bufferSize
  368.                               a0        d0          d1
  369.                                            [, sysbase, dosbase ] );
  370.                                                 a1       a2
  371.  
  372.     struct AsyncFile OpenAsyncFromFH( BPTR, UBYTE, LONG
  373.                        [, struct ExecBase *, struct DosLibrary * ] );
  374.  
  375.    FUNCTION
  376.     The named file is opened and an async file handle returned. If the
  377.     accessMode is MODE_READ, an existing file is opened for reading.
  378.     If accessMode is MODE_WRITE, a new file is created for writing. If
  379.     a file of the same name already exists, it is first deleted. If
  380.     accessMode is MODE_APPEND, an existing file is prepared for writing.
  381.     Data written is added to the end of the file. If the file does not
  382.     exists, it is created.
  383.  
  384.     'fileName' is a filename and CANNOT be a window specification such as
  385.     CON: or RAW:, or "*"
  386.  
  387.     'bufferSize' specifies the size of the IO buffer to use. There are
  388.     in fact two buffers allocated, each of roughly (bufferSize/2) bytes
  389.     in size. The actual buffer size use can vary slightly as the size
  390.     is rounded to speed up DMA.
  391.  
  392.     If the file cannot be opened for any reason, the value returned
  393.     will be NULL, and a secondary error code will be available by
  394.     calling the routine dos.library/IoErr().
  395.  
  396.     INPUTS
  397.     name - name of the file to open, cannot be a window specification
  398.     accessMode - one of MODE_READ, MODE_WRITE, or MODE_APPEND
  399.     bufferSize - size of IO buffer to use. 8192 is recommended as it
  400.              provides very good performance for relatively little
  401.              memory.
  402.     sysbase - Library base needed for the "no externals" version of the
  403.         library.
  404.     dosbase - Library base, as sysbase.
  405.  
  406.     RESULTS
  407.     file - an async file handle or NULL for failure. You should not access
  408.            the fields in the AsyncFile structure, these are private to the
  409.            async IO routines. In case of failure, dos.library/IoErr() can
  410.            give more information.
  411.  
  412.     NOTES (by MH)
  413.     Although stated that CON:, RAW:, or "*" cannot be used as the file
  414.     name, tests indicates that the 2.0+ "Console:" volume is safe to
  415.     use for writing (haven't tested reading). No guarantees though.
  416.  
  417.     SEE ALSO
  418.     CloseAsync(), dos.library/Open()
  419.  
  420. asyncio/ReadAsync                                           asyncio/ReadAsync
  421.  
  422.    NAME
  423.     ReadAsync -- read bytes from an async file.
  424.  
  425.    SYNOPSIS
  426.     actualLength = ReadAsync( file, buffer, numBytes );
  427.          d0                    a0     a1       d0
  428.  
  429.     LONG ReadAsync( struct AsyncFile *, APTR, LONG );
  430.  
  431.    FUNCTION
  432.     This function reads bytes of information from an opened async file
  433.         into the buffer given. 'numBytes' is the number of bytes to read from
  434.         the file.
  435.  
  436.     The value returned is the length of the information actually read.
  437.     So, when 'actualLength' is greater than zero, the value of
  438.     'actualLength' is the the number of characters read. Usually
  439.     ReadAsync() will try to fill up your buffer before returning. A value
  440.     of zero means that end-of-file has been reached. Errors are indicated
  441.     by a value of -1.
  442.  
  443.     INPUTS
  444.     file - opened file to read, as obtained from OpenAsync()
  445.     buffer - buffer where to put bytes read
  446.     numBytes - number of bytes to read into buffer
  447.  
  448.     RESULT
  449.     actualLength - actual number of bytes read, or -1 if an error. In
  450.                case of error, dos.library/IoErr() can give more
  451.                information.
  452.  
  453.     SEE ALSO
  454.     OpenAsync(), CloseAsync(), ReadCharAsync(), WriteAsync(),
  455.     dos.library/Read()
  456.  
  457. asyncio/ReadCharAsync                                   asyncio/ReadCharAsync
  458.  
  459.    NAME
  460.     ReadCharAsync -- read a single byte from an async file.
  461.  
  462.    SYNOPSIS
  463.     byte = ReadCharAsync( file );
  464.      d0                    a0
  465.  
  466.     LONG ReadCharAsync( struct AsyncFile * );
  467.  
  468.    FUNCTION
  469.     This function reads a single byte from an async file. The byte is
  470.     returned, or -1 if there was an error reading, or if the end-of-file
  471.     was reached.
  472.  
  473.    INPUTS
  474.     file - opened file to read from, as obtained from OpenAsync()
  475.  
  476.    RESULT
  477.     byte - the byte read, or -1 if no byte was read. In case of error,
  478.            dos.library/IoErr() can give more information. If IoErr()
  479.            returns 0, it means end-of-file was reached. Any other value
  480.            indicates an error.
  481.  
  482.    SEE ALSO
  483.     OpenAsync(), CloseAsync(), ReadAsync(), WriteCharAsync()
  484.     dos.library/Read()
  485.  
  486. asyncio/SeekAsync                                           asyncio/SeekAsync
  487.  
  488.    NAME
  489.     SeekAsync -- set the current position for reading or writing within
  490.              an async file.
  491.  
  492.    SYNOPSIS
  493.     oldPosition = SeekAsync( file, position, mode );
  494.          d0                   a0      d0      d1
  495.  
  496.     LONG SeekAsync( struct AsyncFile *, LONG, BYTE );
  497.  
  498.    FUNCTION
  499.     SeekAsync() sets the read/write cursor for the file 'file' to the
  500.     position 'position'. This position is used by the various read/write
  501.     functions as the place to start reading or writing. The result is the
  502.     current absolute position in the file, or -1 if an error occurs, in
  503.     which case dos.library/IoErr() can be used to find more information.
  504.     'mode' can be MODE_START, MODE_CURRENT or MODE_END. It is used to
  505.     specify the relative start position. For example, 20 from current
  506.     is a position 20 bytes forward from current, -20 is 20 bytes back
  507.     from current.
  508.  
  509.     To find out what the current position within a file is, simply seek
  510.     zero from current.
  511.  
  512.     INPUTS
  513.     file - an opened async file, as obtained from OpenAsync()
  514.     position - the place where to move the read/write cursor
  515.     mode - the mode for the position, one of MODE_START, MODE_CURRENT,
  516.            or MODE_END.
  517.  
  518.     RESULT
  519.     oldPosition - the previous position of the read/write cursor, or -1
  520.               if an error occurs. In case of error, dos.library/IoErr()
  521.               can give more information.
  522.  
  523.     NOTES (by MH)
  524.     If you seek after having read only a few bytes, the function must
  525.     wait for both buffers to be loaded, before the seek can be done.
  526.     This can cause small delays. Note that the above case isn't the
  527.     only one, but the typical one.
  528.  
  529.     SEE ALSO
  530.     OpenAsync(), CloseAsync(), ReadAsync(), WriteAsync(),
  531.     dos.library/Seek()
  532.  
  533. asyncio/WriteAsync                                         asyncio/WriteAsync
  534.  
  535.    NAME
  536.     WriteAsync -- write data to an async file.
  537.  
  538.    SYNOPSIS
  539.     actualLength = WriteAsync( file, buffer, numBytes );
  540.          d0                     a0     a1       d0
  541.  
  542.     LONG WriteAsync( struct AsyncFile *, APTR, LONG );
  543.  
  544.    FUNCTION
  545.     WriteAsync() writes bytes of data to an opened async file. 'numBytes'
  546.     indicates the number of bytes of data to be transferred. 'buffer'
  547.     points to the data to write. The value returned is the length of
  548.     information actually written. So, when 'numBytes' is greater than
  549.     zero, the value of 'numBytes' is the number of characters written.
  550.     Errors are indicated by a return value of -1.
  551.  
  552.     INPUTS
  553.     file - an opened file, as obtained from OpenAsync()
  554.     buffer - address of data to write
  555.     numBytes - number of bytes to write to the file
  556.  
  557.     RESULT
  558.     actualLength - number of bytes written, or -1 if error. In case
  559.                of error, dos.library/IoErr() can give more
  560.                information.
  561.  
  562.     SEE ALSO
  563.     OpenAsync(), CloseAsync(), ReadAsync(), WriteCharAsync(),
  564.     dos.library/Write()
  565.  
  566. asyncio/WriteCharAsync                                 asyncio/WriteCharAsync
  567.  
  568.    NAME
  569.     WriteCharAsync -- write a single byte to an async file.
  570.  
  571.    SYNOPSIS
  572.     result = WriteCharAsync( file, byte );
  573.       d0                      a0    d0
  574.  
  575.     LONG WriteCharAsync( struct AsyncFile *, UBYTE );
  576.  
  577.    FUNCTION
  578.     This function writes a single byte to an async file.
  579.  
  580.    INPUTS
  581.     file - an opened async file, as obtained from OpenAsync()
  582.     byte - byte of data to add to the file
  583.  
  584.    RESULT
  585.     result - 1 if the byte was written, -1 if there was an error. In
  586.          case of error, dos.library/IoErr() can give more information.
  587.  
  588.    SEE ALSO
  589.     OpenAsync(), CloseAsync(), ReadAsync(), WriteAsync(),
  590.     dos.library/Write()
  591.  
  592.