contrib/oul/oufgl/asyncio.h
Go to the documentation of this file.
00001 // This is oul/oufgl/asyncio.h
00002 #ifndef OTAGO_Asyncio_IO__h_INCLUDED
00003 #define OTAGO_Asyncio_IO__h_INCLUDED
00004 //:
00005 // \file
00006 // \brief A simple wrapper around POSIX.1b asynchronous I/O
00007 //
00008 // Copyright (c) 2001 Simon Brady
00009 // University of Otago, Dunedin, New Zealand
00010 // Reproduction rights limited as described in the COPYRIGHT file.
00011 //----------------------------------------------------------------------
00012 //
00013 //: Asynchronous I/O wrapper
00014 // Simple wrapper around POSIX.1b asynchronous I/O (as documented in GNU Info
00015 // under Libc -> Low-Level I/O -> Asynchronous I/O). This should be portable
00016 // across most Unix-like systems. Win32 has its own async I/O facilities which
00017 // are similar to these (see Jeffrey Richter's "Advanced Windows" for details).
00018 //
00019 // An AsyncIO object represents I/O on a particular file descriptor. The read()
00020 // and write() methods attempt to initiate I/O, returning error status if
00021 // unsuccessful. If they succeed then I/O is underway and you can't touch the
00022 // buffer until completion. You can either poll by calling is_complete(), or
00023 // (better) do everything else you need to do then call wait_for_completion()
00024 // which will block in a multiprocessing-friendly way. Even if is_complete()
00025 // has returned true you must still call wait_for_completion() to determine
00026 // the completion status of the operation. 
00027 //
00028 // WARNING: Although you can instantiate multiple AsyncIO objects, only one
00029 // I/O op can be in progress at once within a process. This is because we get
00030 // notified of completion by a signal, whose handler has to be a non-member
00031 // function. The handler could be extended to inspect a list of (signal,
00032 // request) pairs to determine which object's request has completed, but I
00033 // haven't done this since protecting such a list from race conditions is
00034 // probably non-trivial and I don't need the capability. Note the use of
00035 // class AsyncIO_Shared_State to clarify the distinction between shared
00036 // and per-object state.
00037 //
00038 // \verbatim
00039 //  Modifications
00040 //   06-Nov-00  SJB  Initial version
00041 //   13-Dec-00  SJB  Use SIGIO as default completion signal
00042 //                   Fix up wait_for_completion, add suspend flag
00043 // \endverbatim
00044 // \author Simon Brady
00045 // \status Complete
00046 //----------------------------------------------------------------------
00047 
00048 #include <unistd.h>
00049 #ifndef _POSIX_ASYNCHRONOUS_IO
00050 #error Your system does not support POSIX asynchronous I/O
00051 #endif
00052 #include <aio.h>
00053 #include <vcl_csignal.h>
00054 #include <vcl_cstddef.h> // for size_t
00055 
00056 class AsyncIO_Shared_State
00057 {
00058  protected:
00059   static volatile vcl_sig_atomic_t complete;   // 0 - in progress, 1 - complete
00060 
00061   // Set complete flag when completion signal arrives. Currently ignores
00062   // the signal number (see the warning at the start of this header)
00063   static void signal_handler(int);
00064 };
00065 
00066 class AsyncIO : protected AsyncIO_Shared_State
00067 {
00068   struct aiocb cb;                         // Control block
00069 
00070  public:
00071 
00072   // Constructor - perform I/O on file descriptor fd, using sig as completion
00073   // signal. Note that SIGUSR1,2 may be used by the linuxthreads library.
00074   AsyncIO(int fd, int sig = SIGIO);
00075 
00076   // Destructor - disconnect signal handler
00077  ~AsyncIO();
00078 
00079   // NB: All methods returning int return zero on success, or an errno value
00080   // on failure
00081 
00082   // Begin reading n bytes into buf starting at current file position
00083   int read(volatile void *buf, vcl_size_t n);
00084 
00085   // Begin reading n bytes into buf starting at absolute file position pos
00086   int read(volatile void *buf, vcl_size_t n, off_t pos);
00087 
00088   // Begin writing n bytes from buf starting at current file position
00089   int write(volatile void *buf, vcl_size_t nbytes);
00090 
00091   // Begin writing n bytes from buf starting at absolute file position pos
00092   int write(volatile void *buf, vcl_size_t nbytes, off_t pos);
00093 
00094   // Wait for I/O to complete, then return status. If suspend is true, block
00095   // the calling process while waiting, otherwise continuously poll for
00096   // completion (not recommended, but may be more reliable).
00097   int wait_for_completion(bool suspend = true);
00098 
00099   // Test if operation complete. You still need to call wait_for_completion()
00100   // to tidy up and get final status
00101   bool is_complete() const { return complete; }
00102 };
00103 
00104 #endif // OTAGO_Asyncio_IO__h_INCLUDED
00105