diff options
author | H. Peter Anvin <hpa@zytor.com> | 2012-05-08 17:50:04 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2012-05-08 17:50:04 -0700 |
commit | b80351139f1398bbd932165d84ac0d15571bfd70 (patch) | |
tree | 76257f6fb25a01c347b97587b80c8397dfbd5cfb | |
parent | 96819e548a603081a482bfb71ac0c71051a9021b (diff) | |
download | klibc-b80351139f1398bbd932165d84ac0d15571bfd70.tar.gz |
[klibc] Bypass stdio buffering for large I/O
If the I/O size is too large to fit in the buffer, bypass the
buffering and go directly to the system call.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r-- | usr/klibc/stdio/fread.c | 80 | ||||
-rw-r--r-- | usr/klibc/stdio/fwrite.c | 58 |
2 files changed, 95 insertions, 43 deletions
diff --git a/usr/klibc/stdio/fread.c b/usr/klibc/stdio/fread.c index 6eecfc0da0b6f..dd27891cfe991 100644 --- a/usr/klibc/stdio/fread.c +++ b/usr/klibc/stdio/fread.c @@ -2,6 +2,7 @@ * fread.c */ +#include <stdbool.h> #include <string.h> #include "stdioint.h" @@ -10,44 +11,73 @@ size_t _fread(void *buf, size_t count, FILE *f) size_t bytes = 0; size_t nb; char *p = buf; + char *rdptr; ssize_t rv; + bool bypass; - /* Note: one could avoid double-buffering large reads. */ + if (!count) + return 0; - for (;;) { + if (f->flags & _IO_FILE_FLAG_WRITE) + fflush(f); + + while (count) { + while (f->bytes == 0) { + /* + * The buffer is empty, we have to read + */ + bypass = (count >= f->bufsiz); + if (bypass) { + /* Large read, bypass buffer */ + rdptr = p; + nb = count; + } else { + rdptr = f->buf + _IO_UNGET_SLOP; + nb = f->bufsiz; + } + + rv = read(f->fd, rdptr, nb); + if (rv == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + f->flags |= _IO_FILE_FLAG_ERR; + return bytes; + } else if (rv == 0) { + f->flags |= _IO_FILE_FLAG_EOF; + return bytes; + + + } + + if (bypass) { + p += rv; + bytes += rv; + count -= rv; + f->filepos += rv; + } else { + f->bytes = rv; + f->data = rdptr; + f->flags |= _IO_FILE_FLAG_READ; + } + + if (!count) + return bytes; + } + + /* If we get here, the buffer is non-empty */ nb = f->bytes; nb = (count < nb) ? count : nb; if (nb) { memcpy(p, f->data, nb); - f->data += nb; - f->bytes -= nb; p += nb; - count -= nb; bytes += nb; + count -= nb; + f->data += nb; + f->bytes -= nb; f->filepos += nb; if (!f->bytes) f->flags &= ~_IO_FILE_FLAG_READ; } - - if (!count) - break; /* Done... */ - - /* If we get here, f->ibuf must be empty */ - f->data = f->buf + _IO_UNGET_SLOP; - - rv = read(f->fd, f->data, BUFSIZ); - if (rv == -1) { - if (errno == EINTR || errno == EAGAIN) - continue; - f->flags |= _IO_FILE_FLAG_ERR; - return bytes; - } else if (rv == 0) { - f->flags |= _IO_FILE_FLAG_EOF; - return bytes; - } - - f->bytes = rv; - f->flags |= _IO_FILE_FLAG_READ; } return bytes; } diff --git a/usr/klibc/stdio/fwrite.c b/usr/klibc/stdio/fwrite.c index 7ad49d24162d7..96dbd09a52f09 100644 --- a/usr/klibc/stdio/fwrite.c +++ b/usr/klibc/stdio/fwrite.c @@ -10,28 +10,50 @@ static size_t fwrite_noflush(const void *buf, size_t count, FILE *f) size_t bytes = 0; size_t nb; const char *p = buf; + ssize_t rv; - /* Note: one could avoid double-buffering large writes. */ + while (count) { + if (f->bytes == 0 && count >= f->bufsiz) { + /* + * The buffer is empty and the write is large, + * so bypass the buffering entirely. + */ + rv = write(f->fd, p, count); + if (rv == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + f->flags |= _IO_FILE_FLAG_ERR; + break; + } else if (rv == 0) { + /* EOF on output? */ + f->flags |= _IO_FILE_FLAG_EOF; + break; + } - for (;;) { - nb = f->bufsiz - f->bytes; - nb = (count < nb) ? count : nb; - if (nb) { - memcpy(f->buf+f->bytes, p, nb); - p += nb; - f->bytes += nb; - count -= nb; - bytes += nb; - f->filepos += nb; - f->flags |= _IO_FILE_FLAG_WRITE; - } + p += rv; + bytes += rv; + count -= rv; + f->filepos += rv; + } else { + nb = f->bufsiz - f->bytes; + nb = (count < nb) ? count : nb; + if (nb) { + memcpy(f->buf+f->bytes, p, nb); + p += nb; + f->bytes += nb; + count -= nb; + bytes += nb; + f->filepos += nb; + f->flags |= _IO_FILE_FLAG_WRITE; + } - if (!count) - break; /* Done... */ + if (!count) + break; /* Done... */ - /* If we get here, the buffer must be full */ - if (fflush(f)) - break; + /* If we get here, the buffer must be full */ + if (fflush(f)) + break; + } } return bytes; } |