From ef29ade04b883d407c9bdda8cf3895a8c51920a4 Mon Sep 17 00:00:00 2001 From: Jan Nieuwenhuizen Date: Sat, 27 Jul 2019 22:58:49 +0200 Subject: [PATCH] mescc: Mes C Library: Add buffered read. * lib/mes/__buffered_read.c: New file. * build-aux/configure-lib.sh (libc_SOURCES): Add it. Also add memmove.c. (libc_tcc_SOURCES): Remove memmove.c * lib/linux/close.c (close): Clear read buffer. * lib/linux/_open3.c (_open3): Likewise. * lib/linux/lseek.c (lseek): Correct for read buffer. * lib/stdio/fwrite.c (fwrite): Likewise. * lib/posix/read.c (read): Call __buffered_read. * lib/posix/write.c (write): Add FIXME note about buffered reads. * simple.sh: Update. --- build-aux/configure-lib.sh | 3 +- include/mes/lib.h | 5 ++- lib/linux/_open3.c | 5 ++- lib/linux/close.c | 4 +- lib/linux/lseek.c | 5 +++ lib/mes/__buffered_read.c | 79 ++++++++++++++++++++++++++++++++++++++ lib/mes/fdgetc.c | 8 ++-- lib/posix/read.c | 2 +- lib/posix/write.c | 11 +++++- lib/stdio/fread.c | 13 ++++--- lib/stdio/fseek.c | 7 ++-- lib/stdio/fwrite.c | 8 +++- mes/module/mes/repl.mes | 2 +- simple.sh | 5 ++- 14 files changed, 133 insertions(+), 24 deletions(-) create mode 100644 lib/mes/__buffered_read.c diff --git a/build-aux/configure-lib.sh b/build-aux/configure-lib.sh index 86d15b22..159aa11b 100644 --- a/build-aux/configure-lib.sh +++ b/build-aux/configure-lib.sh @@ -78,6 +78,7 @@ fi libc_SOURCES=" $libmes_SOURCES lib/mes/__assert_fail.c +lib/mes/__buffered_read.c lib/mes/__mes_debug.c lib/posix/execv.c lib/posix/getcwd.c @@ -101,6 +102,7 @@ lib/stdlib/realloc.c lib/string/memchr.c lib/string/memcmp.c lib/string/memcpy.c +lib/string/memmove.c lib/string/memset.c lib/string/strcmp.c lib/string/strcpy.c @@ -171,7 +173,6 @@ lib/stdlib/strtoll.c lib/stdlib/strtoul.c lib/stdlib/strtoull.c lib/string/memmem.c -lib/string/memmove.c lib/string/strcat.c lib/string/strchr.c lib/string/strlwr.c diff --git a/include/mes/lib.h b/include/mes/lib.h index 63d1eba9..1de015fa 100644 --- a/include/mes/lib.h +++ b/include/mes/lib.h @@ -54,11 +54,14 @@ ssize_t _read (int fd, void *buffer, size_t size); extern char *__brk; extern void (*__call_at_exit) (void); +#define __FILEDES_MAX 512 + #if !SYSTEM_LIBC void __assert_fail (char *s); +ssize_t __buffered_read (int filedes, void *buffer, size_t size); +size_t __buffered_read_clear (int filedes); void _exit (int code); long brk (void *addr); - #endif // !SYSTEM_LIBC #endif //__MES_LIB_H diff --git a/lib/linux/_open3.c b/lib/linux/_open3.c index e1bf1f7b..8f103e7b 100644 --- a/lib/linux/_open3.c +++ b/lib/linux/_open3.c @@ -29,6 +29,9 @@ _open3 (char const *file_name, int flags, int mask) int r = _sys_call3 (SYS_open, (long) file_name, (int) flags, (int) mask); __ungetc_init (); if (r > 2) - __ungetc_clear (r); + { + __ungetc_clear (r); + __buffered_read_clear (r); + } return r; } diff --git a/lib/linux/close.c b/lib/linux/close.c index 91a049c4..e25e8318 100644 --- a/lib/linux/close.c +++ b/lib/linux/close.c @@ -25,7 +25,7 @@ int close (int filedes) { - if (filedes > 2) - __ungetc_clear (filedes); + __ungetc_clear (filedes); + __buffered_read_clear (filedes); return _sys_call1 (SYS_close, (int) filedes); } diff --git a/lib/linux/lseek.c b/lib/linux/lseek.c index 9d21659b..94f2f9f7 100644 --- a/lib/linux/lseek.c +++ b/lib/linux/lseek.c @@ -18,12 +18,17 @@ * along with GNU Mes. If not, see . */ +#include #include #include +#include #include off_t lseek (int filedes, off_t offset, int whence) { + size_t skip = __buffered_read_clear (filedes); + if (whence == SEEK_CUR) + offset -= skip; return _sys_call3 (SYS_lseek, (int) filedes, (long) offset, (int) whence); } diff --git a/lib/mes/__buffered_read.c b/lib/mes/__buffered_read.c new file mode 100644 index 00000000..e47cca53 --- /dev/null +++ b/lib/mes/__buffered_read.c @@ -0,0 +1,79 @@ +/* -*-comment-start: "//";comment-end:""-*- + * GNU Mes --- Maxwell Equations of Software + * Copyright © 2019 Jan (janneke) Nieuwenhuizen + * + * This file is part of GNU Mes. + * + * GNU Mes is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * GNU Mes is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Mes. If not, see . + */ + +#include +#include +#include + +#define __READ_BUFFER_MAX 100 + +struct __read_buffer +{ + ssize_t size; + char string[__READ_BUFFER_MAX]; +}; + +struct __read_buffer *__read_cache = 0; + +void +__buffered_read_init (int filedes) +{ + if (!__read_cache) + __read_cache = (struct __read_buffer *) malloc (sizeof (struct __read_buffer) * __FILEDES_MAX); +} + +size_t +__buffered_read_clear (int filedes) +{ + __buffered_read_init (filedes); + size_t size = __read_cache[filedes].size; + __read_cache[filedes].size = 0; + return size; +} + +ssize_t +__buffered_read (int filedes, void *buffer, size_t size) +{ + size_t todo = size; + __buffered_read_init (filedes); + struct __read_buffer *cache = &__read_cache[filedes]; + char *p = buffer; + if (!cache->size && size > __READ_BUFFER_MAX) + return _read (filedes, buffer, size); + while (cache->size > 0 && todo) + { + todo--; + *p++ = cache->string[__READ_BUFFER_MAX - cache->size--]; + } + if (todo) + { + ssize_t bytes = _read (filedes, cache->string, __READ_BUFFER_MAX); + if (bytes < 0) + return -1; + if (bytes) + { + cache->size = bytes; + if (bytes < __READ_BUFFER_MAX) + memmove (cache->string + __READ_BUFFER_MAX - bytes, cache->string, bytes); + return size - todo + __buffered_read (filedes, p, todo); + } + } + return size - todo; +} diff --git a/lib/mes/fdgetc.c b/lib/mes/fdgetc.c index 8dfa256c..74a8eaff 100644 --- a/lib/mes/fdgetc.c +++ b/lib/mes/fdgetc.c @@ -24,9 +24,7 @@ #include #include -#define __UNGETC_MAX 1024 - -int __ungetc_buf[__UNGETC_MAX + 1] = { 0 }; +int __ungetc_buf[__FILEDES_MAX + 1] = { 0 }; int __ungetc_p (int filedes) @@ -37,8 +35,8 @@ __ungetc_p (int filedes) void __ungetc_init () { - if (__ungetc_buf[__UNGETC_MAX] == 0) - memset (__ungetc_buf, -1, (__UNGETC_MAX + 1) * sizeof (int)); + if (__ungetc_buf[__FILEDES_MAX] == 0) + memset (__ungetc_buf, -1, (__FILEDES_MAX + 1) * sizeof (int)); } void diff --git a/lib/posix/read.c b/lib/posix/read.c index 5fbda534..d47d5d15 100644 --- a/lib/posix/read.c +++ b/lib/posix/read.c @@ -24,7 +24,7 @@ ssize_t read (int filedes, void *buffer, size_t size) { - ssize_t bytes = _read (filedes, buffer, size); + ssize_t bytes = __buffered_read (filedes, buffer, size); if (__mes_debug () > 4) { if (bytes == 1) diff --git a/lib/posix/write.c b/lib/posix/write.c index 811bc0ab..6843cd55 100644 --- a/lib/posix/write.c +++ b/lib/posix/write.c @@ -18,12 +18,21 @@ * along with GNU Mes. If not, see . */ -#include #include +#include ssize_t write (int filedes, void const *buffer, size_t size) { +#if 0 // !MES_MINI + // FIXME: libc-mini has no __buffered_read_clear, lseek. + // and libc includes libc-mini...how to override? + // Let's hope everyone uses fwrite, or lseek for RDWR + // semantics... + size_t skip = __buffered_read_clear (filedes); + if (skip) + lseek (filedes, -skip, SEEK_CUR); +#endif int r = _write (filedes, buffer, size); if (r < 0) { diff --git a/lib/stdio/fread.c b/lib/stdio/fread.c index 77f3b864..505700ca 100644 --- a/lib/stdio/fread.c +++ b/lib/stdio/fread.c @@ -41,9 +41,10 @@ fread (void *data, size_t size, size_t count, FILE * stream) int bytes = 0; while (__fungetc_p (stream) && todo-- && ++bytes) *buf++ = fgetc (stream); + int filedes = (long) stream; if (todo) { - int r = read ((int) (long) stream, buf, todo); + int r = read (filedes, buf, todo); if (r < 0 && !bytes) bytes = r; else @@ -52,18 +53,18 @@ fread (void *data, size_t size, size_t count, FILE * stream) if (__mes_debug ()) { + static char debug_buf[4096]; eputs ("fread fd="); - eputs (itoa ((int) (long) stream)); + eputs (itoa (filedes)); eputs (" bytes="); eputs (itoa (bytes)); eputs ("\n"); - static char buf[4096]; - if (bytes > 0 && bytes < sizeof (buf)) + if (bytes > 0 && bytes < sizeof (debug_buf)) { - strncpy (buf, data, bytes); + strncpy (debug_buf, data, bytes); buf[bytes] = 0; eputs ("fread buf="); - eputs (buf); + eputs (debug_buf); eputs ("\n"); } } diff --git a/lib/stdio/fseek.c b/lib/stdio/fseek.c index 268f9792..ce468ab3 100644 --- a/lib/stdio/fseek.c +++ b/lib/stdio/fseek.c @@ -1,6 +1,6 @@ /* -*-comment-start: "//";comment-end:""-*- * GNU Mes --- Maxwell Equations of Software - * Copyright © 2017,2018 Jan (janneke) Nieuwenhuizen + * Copyright © 2017,2018,2019 Jan (janneke) Nieuwenhuizen * * This file is part of GNU Mes. * @@ -25,11 +25,12 @@ int fseek (FILE * stream, long offset, int whence) { - off_t pos = lseek ((int) (long) stream, offset, whence); + int filedes = (long) stream; + off_t pos = lseek (filedes, offset, whence); if (__mes_debug ()) { eputs ("fread fd="); - eputs (itoa ((int) (long) stream)); + eputs (itoa (filedes)); eputs (" =>"); eputs (itoa (pos)); eputs ("\n"); diff --git a/lib/stdio/fwrite.c b/lib/stdio/fwrite.c index 995450e9..6e048ee2 100644 --- a/lib/stdio/fwrite.c +++ b/lib/stdio/fwrite.c @@ -20,6 +20,7 @@ #include #include +#include size_t fwrite (void const *data, size_t size, size_t count, FILE * stream) @@ -35,7 +36,12 @@ fwrite (void const *data, size_t size, size_t count, FILE * stream) if (!size || !count) return 0; - int bytes = write ((int) (long) stream, data, size * count); + // FIXME: should be in write, but that's libc-mini. + int filedes = (long) stream; + size_t skip = __buffered_read_clear (filedes); + if (skip) + lseek (filedes, -skip, SEEK_CUR); + int bytes = write (filedes, data, size * count); if (__mes_debug () > 2) { diff --git a/mes/module/mes/repl.mes b/mes/module/mes/repl.mes index 4f4ab5a3..f3244203 100644 --- a/mes/module/mes/repl.mes +++ b/mes/module/mes/repl.mes @@ -29,7 +29,7 @@ (define welcome (string-append "GNU Mes " %version " -Copyright (C) 2016,2017,2018 Jan (janneke) Nieuwenhuizen +Copyright (C) 2016,2017,2018,2019 Jan (janneke) Nieuwenhuizen GNU Mes comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it diff --git a/simple.sh b/simple.sh index b0b02d7d..97e249e6 100755 --- a/simple.sh +++ b/simple.sh @@ -167,12 +167,14 @@ $CC -g -D HAVE_CONFIG_H=1 -I include -I include/$mes_kernel/$mes_cpu\ lib/ctype/isxdigit.c\ \ lib/mes/__assert_fail.c\ + lib/mes/__buffered_read.c\ lib/mes/__mes_debug.c\ lib/posix/execv.c\ lib/posix/getcwd.c\ lib/posix/getenv.c\ lib/posix/isatty.c\ lib/posix/open.c\ + lib/posix/read.c\ lib/posix/setenv.c\ lib/posix/wait.c\ lib/stdio/fgetc.c\ @@ -189,6 +191,7 @@ $CC -g -D HAVE_CONFIG_H=1 -I include -I include/$mes_kernel/$mes_cpu\ lib/string/memchr.c\ lib/string/memcmp.c\ lib/string/memcpy.c\ + lib/string/memmove.c\ lib/string/memset.c\ lib/string/strcmp.c\ lib/string/strcpy.c\ @@ -207,7 +210,7 @@ $CC -g -D HAVE_CONFIG_H=1 -I include -I include/$mes_kernel/$mes_cpu\ lib/linux/gettimeofday.c\ lib/linux/ioctl.c\ lib/linux/_open3.c\ - lib/linux/read.c\ + lib/linux/_read.c\ lib/linux/time.c\ lib/linux/unlink.c\ lib/linux/waitpid.c\