[vte/vte-0-34] [stream] Add a stdio-based buffered implementation
- From: Behdad Esfahbod <behdad src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vte/vte-0-34] [stream] Add a stdio-based buffered implementation
- Date: Mon, 30 Sep 2013 01:41:46 +0000 (UTC)
commit b959b86bdb5759152328ff1b99ac956ba4189a77
Author: Behdad Esfahbod <behdad behdad org>
Date: Sun Sep 29 21:32:51 2013 -0400
[stream] Add a stdio-based buffered implementation
Should be fairly solid, though more testing will help.
The buffering in stdio makes most of the syscalls go away.
Most remaining are the lseek() syscalls caused by fseek()
calls for when moving backward in the buffer. I think
it's a bug in stdio to make those syscalls when the result
is cached anyway. Anyway, this is a huge improvement
already, specially when reading the buffer forward.
src/vtestream-file.h | 177 ++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 166 insertions(+), 11 deletions(-)
---
diff --git a/src/vtestream-file.h b/src/vtestream-file.h
index e8d95e3..8f705e2 100644
--- a/src/vtestream-file.h
+++ b/src/vtestream-file.h
@@ -25,7 +25,20 @@
#include "vteutils.h"
-#if 1
+/*
+ * We provide two file implementations: one based on raw
+ * syscalls, and one based on stdio. The syscall one has
+ * got more than enough testing in the past. The stdio
+ * is newer, but has a default cache, which greatly reduces
+ * number of syscalls.
+ *
+ * Change the following conditional to 0 for syscalls, and
+ * to 1 for stdio. Please test both branches before
+ * making changes to _file_t semantics or implementation.
+ */
+
+#if 0
+
/*
* File implementation using Unix syscalls.
@@ -38,9 +51,9 @@
static inline gsize
pread (int fd, char *data, gsize len, gsize offset)
{
- if (-1 == lseek (fd, offset, SEEK_SET))
- return -1;
- return read (fd, data, len);
+ if (-1 == lseek (fd, offset, SEEK_SET))
+ return -1;
+ return read (fd, data, len);
}
#endif
@@ -49,16 +62,16 @@ pread (int fd, char *data, gsize len, gsize offset)
static inline gsize
pwrite (int fd, char *data, gsize len, gsize offset)
{
- if (-1 == lseek (fd, offset, SEEK_SET))
- return -1;
- return write (fd, data, len);
+ if (-1 == lseek (fd, offset, SEEK_SET))
+ return -1;
+ return write (fd, data, len);
}
#endif
typedef struct
{
- int fd;
+ int fd;
} _file_t;
static inline void
@@ -89,19 +102,24 @@ _file_close (_file_t *f)
}
-static void
+static gboolean
_file_try_truncate (_file_t *f, gsize offset)
{
+ int ret;
+
if (G_UNLIKELY (!_file_isopen (f)))
return;
- do { } while (-1 == ftruncate (f->fd, offset) && errno == EINTR);
+ do {
+ ret = ftruncate (f->fd, offset);
+ } while (ret == -1 && errno == EINTR);
+
+ return !ret;
}
static void
_file_reset (_file_t *f)
{
- /* Our try_truncate() actually works. */
_file_try_truncate (f, 0);
}
@@ -166,6 +184,143 @@ _file_write (_file_t *f, const char *data, gsize len, gsize offset)
}
}
+
+#else
+
+
+/*
+ * File implementation using stdio.
+ */
+
+#include <stdio.h>
+
+/* TODO use unlocked versions. */
+
+typedef struct
+{
+ FILE *fp;
+ gsize pos;
+} _file_t;
+
+static inline void
+_file_init (_file_t *f)
+{
+ f->fp = NULL;
+ f->pos = -1;
+}
+
+static inline void
+_file_open (_file_t *f, int fd)
+{
+ f->fp = fdopen (fd, "w+");
+ f->pos = 0;
+}
+
+static inline gboolean
+_file_isopen (_file_t *f)
+{
+ return f->fp != NULL;
+}
+
+static inline void
+_file_close (_file_t *f)
+{
+ if (G_UNLIKELY (!_file_isopen (f)))
+ return;
+
+ fclose (f->fp);
+}
+
+
+static gboolean
+_file_try_truncate (_file_t *f, gsize offset)
+{
+ if (G_UNLIKELY (!_file_isopen (f)))
+ return TRUE;
+
+ /* We don't have to truncate. The bytestream works
+ * without a working truncate (hence the "try").
+ * Here's a fallback implementation. Things should
+ * work with or without this.
+ */
+ if (1)
+ {
+ int ret;
+
+ fflush (f->fp);
+
+ do {
+ ret = ftruncate (fileno (f->fp), offset);
+ } while (ret == -1 && errno == EINTR);
+
+ return !ret;
+ }
+
+ return FALSE;
+}
+
+static void
+_file_reset (_file_t *f)
+{
+ int fd;
+
+ if (_file_try_truncate (f, 0))
+ return;
+
+ if (G_UNLIKELY (!_file_isopen (f)))
+ return;
+
+ /* Reopen file to truncate it. */
+
+ fd = dup (fileno (f->fp));
+
+ _file_close (f);
+ _file_open (f, fd);
+}
+
+static gboolean
+_file_seek (_file_t *f, gsize offset)
+{
+ if (f->pos != offset)
+ {
+ if (-1 == fseek (f->fp, offset, SEEK_SET))
+ return FALSE;
+ f->pos = offset;
+ }
+ return TRUE;
+}
+
+static gsize
+_file_read (_file_t *f, char *data, gsize len, gsize offset)
+{
+ gsize ret;
+
+ if (G_UNLIKELY (!_file_isopen (f)))
+ return 0;
+
+ if (!_file_seek (f, offset))
+ return 0;
+
+ ret = fread (data, 1, len, f->fp);
+ f->pos += ret;
+ return ret;
+}
+
+static void
+_file_write (_file_t *f, const char *data, gsize len, gsize offset)
+{
+ gsize ret;
+
+ g_assert (_file_isopen (f) || !len);
+
+ if (!_file_seek (f, offset))
+ return;
+
+ ret = fwrite (data, 1, len, f->fp);
+ f->pos += ret;
+}
+
+
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]