Start of port of AsyncIO library.
[AROS-Contrib.git] / workbench / libs / asyncio / AsyncIO.guide
blobfd5415ce09f79f6a189f4239a69e3e771091bd50
1 @Database AsyncIO.guide
2 @$VER:    AsyncIO.guide 39.2 (2.9.97)
3 @Author   Magnus Holmgren
5 @Node Main AsyncIO.guide
7         @{FG highlight}@{U}@{B}AsyncIO library@{UB}@{UU}@{FG text}
9         Version 39.2
11         Original code by Martin Taillefer
12               updates by Magnus Holmgren
15 AsyncIO is a library providing double buffered asyncronous IO to files in a
16 DOS-like manner.
19         @{" Background      " Link Background}
21         @{" Contents        " Link Contents}
23         @{" Usage           " Link Usage}
25         @{" Technical notes " Link Notes}
27         @{" History         " Link History}
29         @{" Authors         " Link Authors}
31 @EndNode
36 @Node Background AsyncIO.guide/Background
38 @{U}@{B}Background@{UB}@{UU}
40 Reading and writing data is crucial to most applications and is in many
41 cases a major bottleneck. Using AmigaDOS' sophisticated file system
42 architecture can help reduce, and sometimes eliminate, the time spent
43 waiting for IO to complete. This package offers a few small routines that
44 can greatly improve an application's IO performance.
46 Normally, an application processes a file in a manner similar to the
47 following:
49         1 - Open the file
51         2 - Read some data
53         3 - Process data just read
55         4 - Repeat steps 2 and 3 until all data is processed
57         5 - Close file
59 Although the above sequence works fine, it doesn't make full use of the
60 Amiga's multitasking abilities. Step 2 in the above can become a serious
61 bottleneck. Whenever the application needs some data by using the DOS
62 Read() function, AmigaDOS has to put that task to sleep, and initiate a
63 request to the file system to have it fetch the data. The file system then
64 starts up the disk hardware and reads the data. Once the data is read, the
65 application is woken up and can start processing the data just read.
67 The point to note in the above paragraph is that when the file system is
68 reading data from disk, the application is asleep. Wouldn't it be nice if
69 the application could keep running while data is being fetched for it?
71 Most Amiga hard drives make use of DMA (Direct Memory Access). DMA enables
72 a hard drive to transfer data to memory @{B}at the same time@{UB} as the CPU does
73 some work. This parallelism is what makes the set of accompanying routines
74 so efficient. They exploit the fact that data can be transfered to memory
75 while the application is busy processing other data.
77 Using the asynchronous IO routines, an application's IO happens like this:
79         1 - Open the file, ask the file system to start reading ahead
81         2 - Read some data, ask the file system to read more data
83         3 - Process data
85         4 - Repeat steps 2 and 3 until all data is processed
87         5 - Close file
89 Immediately after opening the file, a request is sent to the file system to
90 get it reading data in the background. By the time the application gets
91 around to reading the first byte of data, it is likely already in memory.
92 That means the application doesn't need to wait and can start processing
93 the data. As soon as the application starts processing data from the file,
94 a second request is sent out to the file system to fill up a second buffer.
95 Once the application is done processing the first buffer, it starts
96 processing the second one. When this happens, the file system starts
97 filling up the first buffer again with new data. This process continues
98 until all data has been read.
100 The whole technique is known as "double-buffered asynchronous IO" since it
101 uses two buffers, and happens in the background (asynchronously).
103 The set of functions presented below offers high-performance IO using the
104 technique described above. The interface is very similar to standard
105 AmigaDOS files. These routines enable full asynchronous read/write of any
106 file.
108 @EndNode
113 @Node Contents AsyncIO.guide/Contents
115 @{U}@{B}Contents@{UB}@{UU}
117 The archive contains the following drawers:
119 @{B}dlib@{UB}                   Link libraries for DICE.
120 @{B}emodules@{UB}               "Include" files for E. These are currently not up to date.
121 @{B}include@{UB}                        Include files for C:
122         @{B}clib@{UB}           Function prototypes.
123         @{B}diceclib@{UB}       Special header for DICE 3.0 or higher, and is used
124                         when the "-mi" option is used. Similar to the
125                         proto file for SAS. Place them in DInclude:clib.
126         @{B}fd@{UB}             Function descriptor, e.g. used by various
127                         programming language tools (not really a C include
128                         file).
129         @{B}libraries@{UB}      General include file(s), for needed structures
130                         and constants.
131         @{B}pragmas@{UB}                Pragma file for DICE and SAS/C (and perhaps
132                         StormC).
133         @{B}proto@{UB}          Proto file for SAS/C.
134 @{B}lib@{UB}                    Link libraries for SAS/C.
135 @{B}libs@{UB}                   The shared library.
136 @{B}src@{UB}                    Source code for AsyncIO.
138 @EndNode
143 @Node Usage AsyncIO.guide/Usage
145 @{U}@{B}Usage@{UB}@{UU}
147 AsyncIO is available both as a C link library, and as a shared library.
148 Their usage should be fairly straight forward. There are a couple of
149 details though, since some of the include files are used for both the
150 shared and the link library. I'll only adress the use of AsyncIO from C
151 here, as this is more or less the only language I use (in addition to some
152 assembler).
154 @{U}@{B}Using the shared library@{UB}@{UU}
156 When using the shared library, make sure ASIO_SHARED_LIB is defined before
157 you include any header file for AsyncIO.
159 @{B}DICE@{UB}:  Include <clib/asyncio_protos.h>. Then link with
160         dlib/asynciolib#?.lib, if you want the autoinit code, or you didn't
161         use the "-mi" option. If "-mi" is used, remeber to copy the file
162         "include/diceclib/asyncio_protos.h" to "dinclude:clib".
164 @{B}SAS/C@{UB}: Include the file <proto/asyncio.h>, and link with lib/asyncio.lib
165         if you need the autoinit code. The proto file defines
166         ASIO_SHARED_LIB for you, so this should be all you need to do.
167         Currently there is no glue code available.
169 @{U}@{B}Using the link library@{UB}@{UU}
171 @{B}DICE@{UB}:  Simply define ASIO_REGARGS when you want the regards
172         version, and link with the proper library. If you use dcc for
173         linking, DICE should link with the right library. Otherwise you
174         will get linker errors.
176 @{B}SAS/C@{UB}: Do @{I}not @{UI}include <proto/asyncio.h>. Include <clib/asyncio_protos>
177         instead. It is very important that you link with the right library,
178         and define ASIO_REGARGS and link with "lib/asyncior.lib" when you
179         want the regargs version.
181         Warning: If you link with the wrong library, the program will link
182         properly, but will show strange errors when run! The reason for
183         this "problem" is that I wanted to be able to use the regargs
184         version from assembler, without assuming which register contained
185         which argument, and then SAS/C does it this way (i.e. no difference
186         in function names, as would normally happen for register argument
187         functions).
189 To use the "no externals" version of the link library, you first need to
190 compile it. ;) Then define ASIO_NOEXTERNALS, link with the new library, and
191 otherwise follow the instructions for the normal link libraries. ("No
192 externals" means that the code does not require any external data symbols,
193 like DOSBase or ExecBase, making the code purer. To do this, certain
194 function calls takes DOSBase and ExecBase as arguments.)
196 To create the link libraries:
198 @{B}DICE@{UB}:  Type e.g. "lbmake asyncio s r e" and have dtmp: set to some
199         temporary space. This creates a regargs, smalldata version.
201 @{B}SAS/C@{UB}: Type e.g. "dmake lib/asyncioer.lib" to get the regargs version.
203 @{U}@{B}Notes@{UB}@{UU}
205 Remember that all ASIO_#? symbols must be set before any AsyncIO header is
206 read. There is one exception: ASIO_SHARED_LIB does not need to be defined
207 before you include <proto/asyncio.h>.
209 I haven't personally tested all library versions in the makefile/lib.def.
211 SAS/C users still need DMake (from DICE) to compile things. I'm used to
212 DMake, and haven't really used SMake. ;)
214 The code was originally compiled with DICE. Current version is compiled
215 with SAS/C (as well).
217 Getting the code to compile with other compilers (GCC, StormC, ... ) should
218 be fairly easy, since I've tried to keep all compiler specific things
219 within #defines in a header file, and generally tried to only use normal
220 ANSI/C.
222 The DICE link libraries are created with the help of the LbMake utility in
223 the DICE package. The file Lib.Def contains the definitions for them.
225 @EndNode
230 @Node Notes "AsyncIO.guide/Technical notes"
232 @{U}@{B}Technical notes@{UB}@{UU}
234 The purpose of this chapter is to describe the inner workings of the code.
235 It is partly for my benefit, so that I don't need to remember all details,
236 and partly for your benefit, if you want to try to find bugs, or maybe use
237 asyncronous code in places were AsyncIO as is does not provide the needed
238 functionality.
240 The comments in the code do help, but here is the place to put everything
241 together, and place additional comments.
243 Please note that the information described herein may change, and can not
244 be used in normal applications that use AsyncIO! It is intended for persons
245 dealing with the AsyncIO code itself (or derivates thereof).
247         @{" The AsyncFile structure " Link AsyncFile}
248         (More to be added...)
250 @EndNode
255 @Node AsyncFile "AsyncIO.guide/Technical notes/The AsyncFile structure"
257 @{U}@{B}The AsyncFile structure@{UB}@{UU}
259 @{B}af_File@{UB} (BPTR)
260 The DOS file handle.
262 @{B}af_BlockSize@{UB} (ULONG)
263 Blocksize of the device the file resides on.
265 @{B}af_Handler@{UB} (struct MsgPort *)
266 Handler port of the file system responsible for the file.
268 @{B}af_BytesLeft@{UB} (LONG)
269 Number of bytes left in the buffer we are currently reading data from.
271 @{B}af_BufferSize@{UB} (ULONG)
272 The size of one of the two IO buffers.
274 @{B}af_Buffers[ 2 ]@{UB} (UBYTE *)
275 Pointers to the two IO buffers.
277 @{B}af_Packet@{UB} (struct StandardPacket)
278 Packet structure used when communicating with the file system.
280 @{B}af_PacketPort@{UB} (struct MsgPort)
281 Message port used to receive the packets sent to the file system. No
282 signal bit is allocated of this port; SIGB_SINGLE is used when needed.
284 @{B}af_CurrentBuf@{UB} (ULONG)
285 Number of the buffer that is @{I}currently being filled @{UI}(by the file system),
286 or, if AS_WaitPacket() just has been called, the newly arrived buffer. It
287 does @{I}not @{UI}refer to the buffer we are currently copying data from. Can be
288 used to index the af_Buffers[] array.
290 @{B}af_SeekOffset@{UB} (ULONG)
291 In order to keep the buffers block aligned while seeking in a read mode
292 file, this offset keeps track of the distance from the start of the buffer
293 to the position we should start reading the new data from.
295 @{B}af_SysBase@{UB} (struct ExecBase *)
296 Pointer to SysBase. Only available if ASIO_NOEXTERNALS is defined.
298 @{B}af_DOSBase@{UB} (struct DosLibrary *)
299 Pointer to DOSBase. Only available if ASIO_NOEXTERNALS is defined.
301 @{B}af_PacketPending@{UB} (UBYTE)
302 If true, then the file system is currently filling a packet for us, and it
303 will eventually be waiting for us on the message port.
305 @{B}af_ReadMode@{UB} (UBYTE)
306 If true, then the file is used for reading only. Otherwise the file is used
307 for writing only.
309 @{B}af_CloseFH@{UB} (UBYTE)
310 If true, then CloseAsync() will close the file in af_File. If
311 OpenAsyncFromFH() is used to open the file, then this field will be false.
313 @{B}af_SeekPastEOF@{UB} (UBYTE)
314 If true, then the last SeekAsync() tried to seek past EOF. SeekAsync() uses
315 this to allow the application to seek back to a valid position, and
316 continue reading from there.
318 @{b}af_LastRes1@{ub} (ULONG)
319 @{b}af_LastBytesLeft@{ub} (ULONG)
320 These two stores the last af_BytesLeft and af_Packet.sp_Pkt.dp_Res1. This
321 is needed in order to be able to resume seeking after a seek past EOF.
323 @EndNode
328 @Node History AsyncIO.guide/History
330 @{U}@{B}History@{UB}@{UU}
332 @{B}Release 1 - 23-Mar-94@{UB}
334       * When seeking within the current read buffer, the wrong packet would
335         be sent out to be filled asynchronously. Depending on the data read
336         from the buffer, and how fast it was read, you could end up getting
337         incorrect data on subsequent ReadAsync() calls.
339       * There was actually bufferSize*2 bytes allocated for IO buffers
340         instead of just bufferSize. This is fixed. So if you want the same
341         effective buffer size as before, you must double the value of the
342         bufferSize argument supplied to OpenAsync().
344       * MEMF_PUBLIC is now specified for the IO buffers. This is in support
345         of VM hacks such as GigaMem.
347       * A Seek() call had the mode and offset parameters reversed. The code
348         worked, because both values were luckily always 0, but it was not
349         very clean.
351       * Now uses a typedef for the AsyncFile structure, and enums for the
352         open modes and seek modes.
354 @{B}Release 2 - 16-Feb-94@{UB}
356       * SeekAsync() now consistently works. It was getting confused when
357         called multiple times in a row with no intervening IO.
359       * WriteAsync() would produce garbage in the destination file if it
360         had to bring up a "Disk is full" requester, and the user freed some
361         room on the disk and selected "Retry".
363 @{B}Release 3 - 12-Aug-95@{UB} - Changes from now on by Magnus Holmgren
365       * SeekAsync() is now not unecessarely slow when doing some "kinds" of
366         read-mode seeks (typically when seeking after some small amount of
367         initial read). The problem was that it usually only considered the
368         newly arrived buffer, not both buffers. This could make it discard
369         both buffers, and restart reading, although one of the buffers
370         already had the needed data.
372         Note that the kind of seeks that caused the above problem may still
373         seem to be somewhat slow, since the code must wait for both buffers
374         to be loaded. This cannot (easily) be avoided.
376       * SeekAsync() doesn't cause the read buffer to contain garbage after
377         certain seeks any more. The problem was that ReadAsync() would read
378         from the wrong buffer (the one currently being loaded). This made
379         the files seem to contain garbage. This happened when the seek
380         location was within the newly arrived buffer.
382       * The code package is now supplied as a link library, rather than a
383         single source module. The internal functions labeled "AS_#?" are
384         private and should not be called directly by the application.
386       * A few minor "cosmetic" changes were done, to either make the code
387         more readable, or to make it slightly smaller.
389       * Include file restructured a little (a public and a private part).
391       * OpenAsync() now offers some new "options" (all from the AIFF code
392         by Olaf Barthel):
394       * Opening a file from an already open filehandle is now possible.
396       * A "no externals" version may be compiled, that doesn't require any
397         external variables to be available.
399       * Each of the buffers will now be roughly bufferSize / 2 bytes large,
400         rather than bufferSize bytes (rel 6 note: Really from Taillefers
401         third release).
403       * If there isn't enough memory for the requested buffer size, the
404         code will try with smaller buffers (still properly "aligned")
405         before giving up.
407 @{B}Release 4 - 13-Sep-95@{UB}
409       * Oops. Forgot to include the include/asyncio.h file. Maybe as well,
410         since I anyway had forgot to mention a few things in it.. ;)
412       * Asyncio is now also available as a shared library (to be placed in
413         libs:). This means that a couple of new include files were added,
414         and a one include file was split up.
416         The main reason for doing this was to simplify the use of it in
417         other languages (only need to "port" a few includes). I have no
418         other include files than those for (DICE) C at the moment, but feel
419         free to send me headers for other languages as well.
421         Note: I have not yet verified that the SeekAsync function works,
422         but since read and write works just fine, I see no reason why
423         SeekAsync wouldn't work. ;)
425         Also, I haven't really used it in programs much either (only some
426         testing), so the different defines and similar to use different
427         versions may be a bit clumsy to use (see above for more
428         information). Feel free to send me comments on how to improve this.
430       * Changed so that a non-regargs version of the link library can be
431         created. To use the regargs version now, simply make sure that
432         ASIO_REGARGS is defined, and link with the proper link library.
434       * Changed the name of the NOEXTERNALS define to ASIO_NOEXTERNALS.
435         Define this before you include <clib/asyncio_protos.h> if you want
436         to use that feature. Note that you need to create a proper link
437         library yourself! (With DICE, all you need to do is "LbMake asyncio
438         s r e" in the Src drawer.)
440       * Modified OpenAsync() a little, to work around a problem when having
441         SnoopDos (with SendARexx active), MungWall and Enforcer running.
442         Not an asyncio bug as such, but.. ;)
444 @{B}Release 6 - 10-Nov-95@{UB}
446       * Bumped to version 6, since there was an "official" release 3 that I
447         was unaware of. However, most of the changes were in the AIFF
448         source. Thus, not much was "lost" due to this. (In fact, the
449         SeekAsync bugfix in the real release 3 was not correct. ;)
451       * Sigh. The SeekAsync fix (to the performance problem) was buggy. :/
452         I think I've got it right now.
454       * asyncio.library bumed to version 37.1.
456       * Cleaned up this documentation.
458       * Fixed some bugs in the include files.
460       * Made some fixes to the shared library.
462 @{B}Release 7 - 7-Jan-96@{UB}
464       * Files to use asyncio.library from E included.
466       * Fixed yet some SeekAsync() problems. It could (still) get confused
467         when called multiple times in a row with no intervening IO. I
468         wonder if there are any holes left. ;)
470       * Some more fixes to the shared library.
472       * asyncio.library bumped to version 37.2.
474       * Recompiled asyncio.library using SAS/C 6.56, and added general
475         SAS/C support.
477       * Cleaned up parts of this doc.
479 @{B}Release 8 - 28-Jan-97@{UB}
481       * Yet another hole in SeekAsync() (hopefully) plugged. ;) Seeking in
482         a double-buffered file is tricky business it seems. Thanks to David
483         Eaves for finding it, and sending me a good report about it
484         (including source to reproduce it).
486       * The problem was that when SeekAsync() really seeked past the end of
487         the file, it didn't notice, and would try to reload the "last"
488         buffer.
490       * Finally finished up the ReadLineAsync() function. Only difference
491         from dos.library/FGets() should be the return value. I hope it
492         works properly, since I haven't tested it that much. ;)
494       * Bumped the library version to 38, because of the new functions.
496 @{B}Release 9 - 27-Apr-97@{UB}
498       * Oops. The include/clib/asyncio_protos.h file wasn't quite correct,
499         causing problems when compiling with SAS/C and ASIO_REGARGS
500         defined. Also updated includes for StormC. Thanks to Alexander
501         Kazik who sent me the needed changes for StormC.
503       * Michael B. Smith pointed out that ReadLineAsync() wasn't quite
504         FGets()-compatible. So he sent me his version, which was. I've now
505         added his version (with some minor changes by me), and changed the
506         implementation for ReadLineAsync() to first call the new function
507         FGetsLenAsync(), and then skip up to the LF char, for backward
508         compatibility.
510       * Added PeekAsync(), to allow you to look ahead in the current buffer
511         without actually "reading" anything. Useful when reading from pipes
512         to e.g. find out the file type (needed in Visage ;).
514       * Bumped the library version to 39, because of the new functions.
516       * The autoopen code for SAS/C now uses __asiolibversion rather than
517         __oslibversion (in case of failure, __oslibversion is set to the
518         value of __asiolibversion, and the standard __autoopenfail is
519         called, in order to save code). The default value is 39, and any
520         external reference to __asiolibversion will cause the autoopen code
521         to be linked.
523       * Ouch. The DMakeFile/lib.def files contained some laws. As a result,
524         the DICE linker libraries (in dlib/) were not updated at all. Now
525         there should be fresh libraries for both DICE and SAS/C.
527       * Fixed a couple of typos in the autodocs, including the problem with
528         the enum arguments specified as (U)BYTE, when they need to be LONG
529         (some compilers assumes enums to be longs, unless told otherwise).
531 @{B}Version 39.1 - 27-Jul-97@{UB}
533       * Ouch. The "David Eaves" bug fix in SeekAsync() was wrong. Not only
534         did it not work as intended, the intention was all wrong. Should be
535         fixed now, I hope. ;)
537       * Cleaned up the messy asyncio.doc file, and moved all non-autodoc
538         stuff to this AmigaGuide file. Also added some technical notes (not
539         complete yet).
541       * Changed to "real" version numbers for the release archive.
543       * Referencing __asiolibversion alone isn't enough to drag in autoinit
544         code any more. Should also make it easier for user programs to set
545         their own version now. ;)
547       * Actually compiled a SAS/C version with ASIO_NOEXTERNALS defined.
548         PeekAsync() and FGetsLenAsync() needed a tweak because of this. The
549         generated link library seems to work as well.
551       * Tweaked the DMakeFile (and fixed a few quirks), to create the
552         object files in various sub-drawers.
554       * FGets(Len)Async() would never fill the entire read buffer, even when
555         it could (we're talking about one byte not used here! ;).
557       * Tried to make the usage instructions a bit clearer.
559 @{B}Version 39.2 - 2-Sep-97@{UB}
561       * ReadLineAsync() didn't detect end-of-file if the last line wasn't
562         terminated by a line feed.
564       * ReadLineAsync() could write one byte too much to the read buffer.
566       * Tried to make SeekAsync() allow seeks after a seek past EOF (in
567         order to be more DOS-compatible). I hope I didn't break anything. ;)
569       * Old bug: ReadCharAsync() and WriteCharAsync() could sometimes
570         manage to do their job successfully when they really should fail
571         (and return -1).
573 @EndNode
578 @Node Authors AsyncIO.guide/Authors
580 @{U}@{B}Authors@{UB}@{UU}
582 @{B}Martin Taillefer@{UB} wrote the original code.
584 @{B}Magnus Holmgren@{UB} (that's me ;) "took over" the development in 1995, since I
585 had found a couple of bugs in SeekAsync(). I contacted Martin Taillefer
586 about it, and asked if I could release new versions of AsyncIO, and he
587 didn't complain.
589 @{B}Olaf Barthel@{UB} provided inspiration for some of the changes in release 3
590 (one or two of them most likely came from Martin Taillefers third release,
591 which I was unaware of at the time).
593 @{B}Michael B. Smith@{UB} wrote the FGetsAsync() and FGetsLenAsync() functions,
594 which I added after some (really) minor changes.
596 Most of the changes I have done are marked in the sources with a comment
597 that starts with "MH:".
599 If you want to contact me about something, feel free to send a message to:
601         cmh@lls.se                              (internet)
602         "Magnus Holmgren", 2:203/512.10         (fidonet)
604 Please note that I don't poll the fidonet address that often. ;)
606 @EndNode