aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2012-05-08 17:50:04 -0700
committerH. Peter Anvin <hpa@zytor.com>2012-05-08 17:50:04 -0700
commitb80351139f1398bbd932165d84ac0d15571bfd70 (patch)
tree76257f6fb25a01c347b97587b80c8397dfbd5cfb
parent96819e548a603081a482bfb71ac0c71051a9021b (diff)
downloadklibc-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.c80
-rw-r--r--usr/klibc/stdio/fwrite.c58
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;
}