Logo Search packages:      
Sourcecode: bar version File versions  Download package

io.c

#include "config.h"

#include "headers.h"
#include "error.h"
#include "fd.h"
#include "io.h"

/** I/O state data. */
IO io;

/** Initialize I/O state data.
 * \return 0 for success.  (This function does not fail.)
 */
int ioInit(void)
{
      /** Initlalize the input file path to null. */
      io.in_path = 0;
      /** Initialize the input file descriptor to standard input. */
      io.in = STDIN_FILENO;
      /** Initialize the output file descriptor to standard output. */
      io.out = STDOUT_FILENO;
      /** Set the initial end-of-file flags to false (or zero). */
      io.eof_in = 0;
      io.eof_out = 0;
      /** Initialize the ring buffer. */
      io.buffer_used = 0;
      io.buffer_head = 0;
      io.buffer_size = DEFAULT_BUFFER_SIZE;
      io.buffer = 0;
      /** Initialize the byte-counters. */
      io.last_read = 0;
      io.last_write = 0;
      io.total_size = 0;
      io.total_size_known = 0;
      io.total_read = 0;
      io.total_write = 0;
      io.continue_size = 0;
      /** Initialize the I/O timeout to 1 millisecond. */
      io.timeout = 1; /* 1/1000000 second */
      /** Initialize the current time and the throttle counts. */
      io.current_time = time(0);
      io.throttle_count = 1;
      io.throttle = MAX_UINT64;
      /** Initialize the default block size to 512 bytes. */
      io.block_size = 512; /* 0.5k default */
      return(0);
}

#ifdef HAVE_SIGNAL_H
/** A signal handler for control-C.
 *
 * \param signo The signal number.
 */
static void sig_int(int signo)
{
      /** Return I/O streams to a default state before exiting. */
      fdEnd(io.in);
      fdEnd(io.out);
      exit(1);
}
#endif

#ifdef HAVE_SYSCONF
#     if HAVE_DECL__SC_PAGE_SIZE == 1
#           define PAGESIZE _SC_PAGE_SIZE
#     else
#           if HAVE_DECL__SC_PAGESIZE == 1
#                 define PAGESIZE _SC_PAGESIZE
#           endif
#     endif
#     ifndef PAGESIZE
#           warning I dont know how to retrieve the size of a page using sysconf.
#           warning Assuming page size is DEFAULT_PAGE_SIZE bytes.
#           undef HAVE_SYSCONF
#     endif
#endif

/** Prepare I/O
 *
 * \return 0 for success, non-zero for failure.
 */
int ioBegin(void)
{
      /** If memalign() or posix_memalign() is available, then allocate memory on
       * a page boundary.  If sysconf() is available, find out what the page size
       * is for this machine, otherwise assume that a page is 8192 bytes.
       */
#if defined(USE_MEMALIGN) \
      && (defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_MEMALIGN))
      long page_size = 0;

#     ifdef HAVE_SYSCONF
      page_size = sysconf(PAGESIZE);
#     else
      page_size = DEFAULT_PAGE_SIZE;
#     endif
#endif

      /** Allocate memory for the ring buffer. */
#undef USED_MEMALIGN
#ifdef USE_MEMALIGN
#     if defined(HAVE_POSIX_MEMALIGN)
#           define USED_MEMALIGN
      if (
            /** Incorporating patch provided by Doncho N. Gunchev
             * Closes bug: [ 1158420 ] glibc detects invalid free on exit (Fedora Core 3)
             * */
            posix_memalign((void*)&io.buffer, page_size, sizeof(char) * io.buffer_size) != 0
            )
      {
            print_error(stderr, "Memory allocation failed");
            return(1);
      }
/*
#     elif defined(HAVE_MEMALIGN)
#           if defined(USE_MEMALIGN_BOUNDARY_SIZE)
#                 define USED_MEMALIGN
                  io.buffer = (char *)memalign(page_size, sizeof(char) * io.buffer_size);
#           elif defined(USE_MEMALIGN_SIZE_BOUNDARY)
#                 define USED_MEMALIGN
                  io.buffer = (char *)memalign(sizeof(char) * io.buffer_size, page_size);
#           endif
*/
#     endif
#endif
#ifndef USED_MEMALIGN
      io.buffer = (char *)malloc(sizeof(char) * io.buffer_size);
#endif
      if (io.buffer == 0) {
            print_error(stderr, "Memory allocation failed");
            return(1);
      }
      /** If we have signal(), then set up a signal handler to catch control-C's.
       */
#ifdef HAVE_SIGNAL_H
      if (signal(SIGINT, sig_int) == SIG_ERR) {
            print_error(stderr, "Could not install SIGINT signal handler");
            print_error(stderr, "Control-C events will not reset non-blocking I/O");
      }
#endif
      /** Prepare the I/O file descriptors. */
      fdBegin(io.in);
      fdBegin(io.out);
      return(0);
}

/** Shut down I/O
 *
 * \return 0 for success.  (This function does not fail.)
 */
int ioEnd(void)
{
      /** Free the I/O buffer. */
      free(io.buffer);
      io.buffer = 0;
      io.buffer_used = 0;
      /** Return the file descriptors to their previous state. */
      fdEnd(io.in);
      fdEnd(io.out);
      return(0);
}

/** Check to see if I/O is ready. */
void ioCheck(void)
{
      static fd_set rset, wset;
      static struct timeval to;
      
      to.tv_sec = 0;
      /** Wait for up to io.timeout milliseconds for a change in I/O state. */
      to.tv_usec = io.timeout;
      io.in_ready = 1;
      io.out_ready = 1;
      FD_ZERO(&rset);
      FD_ZERO(&wset);
      if (io.buffer_used != io.buffer_size) FD_SET(io.in, &rset);
      if (io.buffer_used) FD_SET(io.out, &wset);
      /** Check to see if I/O is ready. */
      if (select( ((io.in<io.out)?io.out:io.in)+1, 
            &rset, &wset, 0, &to) == -1) {
            if (errno != EINTR) {
                  print_error(stderr, "select() failed");
                  return;
            }
      }
      /** Set the I/O ready flags in I/O state data. */
      if (!FD_ISSET(io.in, &rset))
            io.in_ready = 0;
      if (!FD_ISSET(io.out, &wset))
            io.out_ready = 0;
}

/** Read input
 *
 * \return 0 for success, non-zero for failure.
 */
int ioRead(void)
{
      int num_read = 0;
      int end = 0;
      int avail = 0;
#ifdef USE_IOVEC
      int num = 0;
      struct iovec vec[2] = { { 0 } };
#endif

      /** If we've reached out throttle count for this second, return. */
      if ((io.current_time == time(0))
            && (io.throttle_count >= io.throttle)) {
            return(0);
      }
      if (io.current_time != time(0)) {
            io.throttle_count = 0;
            io.current_time = time(0);
      }
      /** If there is nothing to read yet, return. */
      if (!io.in_ready) return(0);
      io.last_read = 0;
      /** If we've reached the end of input, return. */
      if (io.eof_in) return(0);
      /** If the buffer is full, return. */
      if (io.buffer_used == io.buffer_size) return(0);
      /** Calculate the location and size of the free space in the buffer. */
      end = (io.buffer_used + io.buffer_head) % io.buffer_size;
      avail = io.buffer_size - io.buffer_used;
      /** If the free space in the buffer is greater than the number of bytes left
       * to be read in this second, throttle the input.
       */
      if ((io.throttle - io.throttle_count) < avail)
            avail = io.throttle - io.throttle_count;
#ifdef USE_IOVEC
      /** If using iovec I/O, set up vec[] with the proper information and then
       * read using iovec I/O.
       */
      vec[num  ].iov_base = io.buffer + end;
      if (end+avail <= io.buffer_size)
            vec[num++].iov_len  = avail;
      else {
            vec[num++].iov_len  = io.buffer_size - end;
            vec[num  ].iov_base = io.buffer;
            vec[num++].iov_len  = avail - (io.buffer_size - end);
      }
      num_read = readv(io.in, vec, num);
#else
      /** If not using iovec, then read input into the next available chunk of
       * linear buffer space.
       */
      if (end+avail <= io.buffer_size) {
            num_read = read(io.in,
                  io.buffer + end,
                  avail);
      }
      else {
            num_read = read(io.in,
                  io.buffer + end,
                  io.buffer_size - end);
      }
#endif
      /** Check for end of file. */
      if (num_read == 0) {
            io.eof_in = 1;
            return(0);
      }
      /** Check for an error. */
      if ((num_read < 0) && (errno == EAGAIN))
            num_read = 0;
      if (num_read < 0) return(num_read);
      /** Update I/O byte counters. */
      io.buffer_used += num_read;
      io.last_read = num_read;
      io.total_read += num_read;
      io.throttle_count += num_read;
      return(0);
}

/** Write data
 *
 * \return 0 for success, non-zero for failure.
 */
int ioWrite(void)
{
      int num_written = 0;
#ifdef USE_IOVEC
      int num = 0;
      struct iovec vec[2] = { { 0 } };
#endif

      /** If output is not ready, return. */
      if (!io.out_ready) return(0);
      io.last_write = 0;
#ifdef USE_IOVEC
      /** If using iovec I/O, set up vec[] with the correct information and then
       * write.
       */
      vec[num  ].iov_base = io.buffer + io.buffer_head;
      if (io.buffer_head + io.buffer_used <= io.buffer_size)
            vec[num++].iov_len  = io.buffer_used;
      else {
            vec[num++].iov_len  = io.buffer_size - io.buffer_head;
            vec[num  ].iov_base = io.buffer;
            vec[num++].iov_len  = io.buffer_used - (io.buffer_size - io.buffer_head);
      }
      num_written = writev(io.out, vec, num);
#else
      /** If not using iovec, then write the next chunk of linear data from the
       * buffer.
       */
      if (io.buffer_head + io.buffer_used <= io.buffer_size) {
            num_written = write(io.out,
                  io.buffer + io.buffer_head,
                  io.buffer_used);
      }
      else {
            num_written = write(io.out,
                  io.buffer + io.buffer_head,
                  io.buffer_size - io.buffer_head);
      }
#endif
      /** Check for end of file. */
      if (num_written == 0) {
            io.eof_out = 1;
            return(0);
      }
      /** Check for an error. */
      if ((num_written < 0) && (errno == EAGAIN))
            num_written = 0;
      if (num_written < 0) return(num_written);
      /** Update the I/O byte counters. */
      io.buffer_used -= num_written;
      io.buffer_head = (io.buffer_head + num_written) % io.buffer_size;
      io.last_write = num_written;
      io.total_write += num_written;
      return(0);
}

/** Check to see if we're done copying input to output
 *
 * \return 1 if done, 0 otherwise.
 */
int ioIsDone(void)
{
      if ((io.eof_in && (io.buffer_used == 0)) || io.eof_out) return(1);
      return(0);
}


Generated by  Doxygen 1.6.0   Back to index