From bb73362d239863f978617232017ad2dbcd22ab39 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Fri, 20 Nov 2015 00:07:29 +0100 Subject: [PATCH] Create stdio buffers at FILE creation time. This removes support for user-supplied buffers with setvbuf. --- libc/Makefile | 2 - libc/include/FILE.h | 11 ++-- libc/include/stdio.h | 16 +++--- libc/stdio/fgetc_unlocked.cpp | 11 ++-- libc/stdio/fnewfile.cpp | 7 ++- libc/stdio/fputc_unlocked.cpp | 7 ++- libc/stdio/fread_unlocked.cpp | 5 +- libc/stdio/fresetfile.cpp | 2 + libc/stdio/fsetdefaultbuf.cpp | 33 ------------ libc/stdio/fsetdefaultbuf_unlocked.cpp | 72 -------------------------- libc/stdio/fshutdown.cpp | 6 +-- libc/stdio/fwrite_unlocked.cpp | 5 +- libc/stdio/setvbuf_unlocked.cpp | 28 ++++++---- libc/stdio/stdio.cpp | 21 ++++---- libc/stdio/ungetc_unlocked.cpp | 7 ++- libc/stdio_ext/__fbufsize.cpp | 4 +- 16 files changed, 65 insertions(+), 172 deletions(-) delete mode 100644 libc/stdio/fsetdefaultbuf.cpp delete mode 100644 libc/stdio/fsetdefaultbuf_unlocked.cpp diff --git a/libc/Makefile b/libc/Makefile index 719f0ba9..9186bb29 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -126,8 +126,6 @@ stdio/fscanf_unlocked.o \ stdio/fseek.o \ stdio/fseeko.o \ stdio/fseeko_unlocked.o \ -stdio/fsetdefaultbuf.o \ -stdio/fsetdefaultbuf_unlocked.o \ stdio/fshutdown.o \ stdio/ftell.o \ stdio/ftello.o \ diff --git a/libc/include/FILE.h b/libc/include/FILE.h index c9654b97..905b2ec9 100644 --- a/libc/include/FILE.h +++ b/libc/include/FILE.h @@ -31,6 +31,10 @@ #include +#if !defined(BUFSIZ) +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -72,11 +76,6 @@ typedef struct __FILE FILE; changed if you make changes to this structure. */ struct __FILE { - /* This is non-standard, but useful. If you allocate your own FILE and - register it with fregister, feel free to use modify the following members - to customize how it works. Don't call the functions directly, though, as - the standard library does various kinds of buffering and conversion. */ - size_t buffersize; unsigned char* buffer; void* user; void* free_user; @@ -87,10 +86,8 @@ struct __FILE int (*fileno_func)(void* user); int (*close_func)(void* user); void (*free_func)(void* free_user, FILE* fp); - /* Application writers shouldn't use anything beyond this point. */ pthread_mutex_t file_lock; int (*fflush_indirect)(FILE*); - void (*buffer_free_indirect)(void*); FILE* prev; FILE* next; int flags; diff --git a/libc/include/stdio.h b/libc/include/stdio.h index b9fe3290..c4672831 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -40,10 +40,6 @@ #endif #include -#if defined(__is_sortix_libc) -#include -#endif - #ifdef __cplusplus extern "C" { #endif @@ -121,9 +117,9 @@ typedef __off_t fpos_t; #define FILE_MODE_CLOEXEC (1 << 7) #endif -extern FILE* stdin; -extern FILE* stdout; -extern FILE* stderr; +extern FILE* const stdin; +extern FILE* const stdout; +extern FILE* const stderr; #define stdin stdin #define stdout stdout @@ -300,8 +296,6 @@ void fregister(FILE* fp); void fresetfile(FILE* fp); void funregister(FILE* fp); FILE* fnewfile(void); -int fsetdefaultbuf(FILE* fp); -int fsetdefaultbuf_unlocked(FILE* fp); int fshutdown(FILE* fp); #endif @@ -323,4 +317,8 @@ int vscanf_callback(void* fp, } /* extern "C" */ #endif +#if defined(__is_sortix_libc) +#include +#endif + #endif diff --git a/libc/stdio/fgetc_unlocked.cpp b/libc/stdio/fgetc_unlocked.cpp index 1f858127..e132fee7 100644 --- a/libc/stdio/fgetc_unlocked.cpp +++ b/libc/stdio/fgetc_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015. This file is part of the Sortix C Library. @@ -38,8 +38,7 @@ extern "C" int fgetc_unlocked(FILE* fp) return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; if ( !(fp->flags & _FILE_BUFFER_MODE_SET) ) - if ( fsetdefaultbuf_unlocked(fp) != 0 ) - return EOF; + setvbuf_unlocked(fp, NULL, fp->buffer_mode, 0); if ( fp->buffer_mode == _IONBF ) { @@ -60,12 +59,12 @@ extern "C" int fgetc_unlocked(FILE* fp) if ( !(fp->offset_input_buffer < fp->amount_input_buffered) ) { - assert(fp->buffer && fp->buffersize); + assert(fp->buffer && BUFSIZ); size_t pushback = _FILE_MAX_PUSHBACK; - if ( fp->buffersize <= pushback ) + if ( BUFSIZ <= pushback ) pushback = 0; - size_t count = fp->buffersize - pushback; + size_t count = BUFSIZ - pushback; if ( (size_t) SSIZE_MAX < count ) count = SSIZE_MAX; ssize_t numread = fp->read_func(fp->user, fp->buffer + pushback, count); diff --git a/libc/stdio/fnewfile.cpp b/libc/stdio/fnewfile.cpp index 61cc4532..802c72e9 100644 --- a/libc/stdio/fnewfile.cpp +++ b/libc/stdio/fnewfile.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2015. This file is part of the Sortix C Library. @@ -25,6 +25,7 @@ #include #include #include +#include static void fnewfile_destroyer(void* /*user*/, FILE* fp) { @@ -33,9 +34,11 @@ static void fnewfile_destroyer(void* /*user*/, FILE* fp) extern "C" FILE* fnewfile(void) { - FILE* fp = (FILE*) calloc(sizeof(FILE), 1); + FILE* fp = (FILE*) malloc(sizeof(FILE) + BUFSIZ); if ( !fp ) return NULL; + memset(fp, 0, sizeof(FILE)); + fp->buffer = (unsigned char*) (fp + 1); fp->free_user = NULL; fp->free_func = fnewfile_destroyer; fresetfile(fp); diff --git a/libc/stdio/fputc_unlocked.cpp b/libc/stdio/fputc_unlocked.cpp index 2fd17096..964c3352 100644 --- a/libc/stdio/fputc_unlocked.cpp +++ b/libc/stdio/fputc_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015. This file is part of the Sortix C Library. @@ -31,8 +31,7 @@ extern "C" int fputc_unlocked(int c, FILE* fp) return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; if ( !(fp->flags & _FILE_BUFFER_MODE_SET) ) - if ( fsetdefaultbuf_unlocked(fp) != 0 ) - return EOF; + setvbuf_unlocked(fp, NULL, fp->buffer_mode, 0); if ( fp->buffer_mode == _IONBF ) { @@ -51,7 +50,7 @@ extern "C" int fputc_unlocked(int c, FILE* fp) fp->flags |= _FILE_LAST_WRITE; fp->flags &= ~_FILE_STATUS_EOF; - if ( fp->amount_output_buffered == fp->buffersize ) + if ( fp->amount_output_buffered == BUFSIZ ) { if ( fflush_unlocked(fp) == EOF ) return EOF; diff --git a/libc/stdio/fread_unlocked.cpp b/libc/stdio/fread_unlocked.cpp index a070ca66..10342e69 100644 --- a/libc/stdio/fread_unlocked.cpp +++ b/libc/stdio/fread_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015. This file is part of the Sortix C Library. @@ -46,8 +46,7 @@ size_t fread_unlocked(void* ptr, if ( fp->buffer_mode == _IONBF ) { if ( !(fp->flags & _FILE_BUFFER_MODE_SET) ) - if ( fsetdefaultbuf_unlocked(fp) != 0 ) - return EOF; + setvbuf_unlocked(fp, NULL, fp->buffer_mode, 0); if ( !fp->read_func ) return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, 0; if ( fp->flags & _FILE_LAST_WRITE ) diff --git a/libc/stdio/fresetfile.cpp b/libc/stdio/fresetfile.cpp index 9a339484..cd83e90b 100644 --- a/libc/stdio/fresetfile.cpp +++ b/libc/stdio/fresetfile.cpp @@ -33,10 +33,12 @@ extern "C" void fresetfile(FILE* fp) { FILE* prev = fp->prev; FILE* next = fp->next; + unsigned char* keep_buffer = fp->buffer; void* free_user = fp->free_user; void (*free_func)(void*, FILE*) = fp->free_func; int kept_flags = fp->flags & (_FILE_REGISTERED | 0); memset(fp, 0, sizeof(*fp)); + fp->buffer = keep_buffer; fp->file_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; fp->flags = kept_flags; fp->buffer_mode = -1; diff --git a/libc/stdio/fsetdefaultbuf.cpp b/libc/stdio/fsetdefaultbuf.cpp deleted file mode 100644 index c70a7943..00000000 --- a/libc/stdio/fsetdefaultbuf.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - - Copyright(C) Jonas 'Sortie' Termansen 2013. - - This file is part of the Sortix C Library. - - The Sortix C Library is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or (at your - option) any later version. - - The Sortix C Library 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 Lesser General Public - License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with the Sortix C Library. If not, see . - - stdio/fsetdefaultbuf.cpp - Sets up default buffering semantics for a FILE. - -*******************************************************************************/ - -#include - -extern "C" int fsetdefaultbuf(FILE* fp) -{ - flockfile(fp); - int ret = fsetdefaultbuf_unlocked(fp); - funlockfile(fp); - return ret; -} diff --git a/libc/stdio/fsetdefaultbuf_unlocked.cpp b/libc/stdio/fsetdefaultbuf_unlocked.cpp deleted file mode 100644 index bbc381d9..00000000 --- a/libc/stdio/fsetdefaultbuf_unlocked.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - - Copyright(C) Jonas 'Sortie' Termansen 2013, 2014. - - This file is part of the Sortix C Library. - - The Sortix C Library is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or (at your - option) any later version. - - The Sortix C Library 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 Lesser General Public - License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with the Sortix C Library. If not, see . - - stdio/fsetdefaultbuf_unlocked.cpp - Sets up default buffering semantics for a FILE. - -*******************************************************************************/ - -#include -#include -#include -#include - -extern "C" int fsetdefaultbuf_unlocked(FILE* fp) -{ - char* buf = (char*) malloc(sizeof(char) * BUFSIZ); - if ( !buf ) - { - // TODO: Determine whether this is truly what we would want and whether - // a buffer should be pre-allocated when the FILE is created such that - // this situation _cannot_ occur. - - // Alright, we're in a bit of a situation here. Normally, we'd go - // buffered but we are out of memory. We could either fail, but that - // would mean subsequent calls such as fgetc and fputc would also fail - - // however that we are out of memory doesn't mean that IO would also - // fail. Therefore we'll revert to unbuffered semantics and hope that's - // good enough. - - return setvbuf_unlocked(fp, NULL, _IONBF, 0); - } - - // Determine the buffering semantics depending on whether the destination is - // an interactive device or not. - int mode = fp->buffer_mode; - if ( mode == -1 ) - { -#if defined(__is_sortix_kernel) - mode = _IOLBF; -#else - mode = _IOFBF; - int saved_errno = errno; - if ( isatty(fileno_unlocked(fp)) ) - mode = _IOLBF; - errno = saved_errno; -#endif - } - if ( setvbuf_unlocked(fp, buf, mode, BUFSIZ) ) - return fp->flags |= _FILE_STATUS_ERROR, free(buf), -1; - - // The buffer now belongs to the FILE. - fp->flags |= _FILE_BUFFER_OWNED; - fp->buffer_free_indirect = free; - - return 0; -} diff --git a/libc/stdio/fshutdown.cpp b/libc/stdio/fshutdown.cpp index 86af0991..e874eb04 100644 --- a/libc/stdio/fshutdown.cpp +++ b/libc/stdio/fshutdown.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2013, 2014. + Copyright(C) Jonas 'Sortie' Termansen 2013, 2014, 2015. This file is part of the Sortix C Library. @@ -34,10 +34,8 @@ extern "C" int fshutdown(FILE* fp) exact error value, for instance, as with popen/pclose. */; } ret = fp->close_func ? fp->close_func(fp->user) : ret; - if ( fp->flags & _FILE_BUFFER_OWNED && fp->buffer_free_indirect ) - fp->buffer_free_indirect(fp->buffer); // Resetting the FILE here isn't needed in the case where fclose calls us, - // but it's nice to zero it out anyway (avoiding state) data, and it's a + // but it's nice to zero it out anyway (avoiding stale) data, and it's a // feature when called by freopen that wishes to reuse the FILE. It also // means that the file is always in a consistent state. fresetfile(fp); diff --git a/libc/stdio/fwrite_unlocked.cpp b/libc/stdio/fwrite_unlocked.cpp index 2e25222a..17d712e1 100644 --- a/libc/stdio/fwrite_unlocked.cpp +++ b/libc/stdio/fwrite_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015. This file is part of the Sortix C Library. @@ -46,8 +46,7 @@ size_t fwrite_unlocked(const void* ptr, if ( fp->buffer_mode == _IONBF ) { if ( !(fp->flags & _FILE_BUFFER_MODE_SET) ) - if ( fsetdefaultbuf_unlocked(fp) != 0 ) - return EOF; + setvbuf_unlocked(fp, NULL, fp->buffer_mode, 0); if ( !fp->write_func ) return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, 0; if ( fp->flags & _FILE_LAST_READ ) diff --git a/libc/stdio/setvbuf_unlocked.cpp b/libc/stdio/setvbuf_unlocked.cpp index 5dbed046..50b24be7 100644 --- a/libc/stdio/setvbuf_unlocked.cpp +++ b/libc/stdio/setvbuf_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2013, 2014. + Copyright(C) Jonas 'Sortie' Termansen 2013, 2014, 2015. This file is part of the Sortix C Library. @@ -24,18 +24,28 @@ #include #include +#include extern "C" int setvbuf_unlocked(FILE* fp, char* buf, int mode, size_t size) { - if ( fp->flags & _FILE_BUFFER_MODE_SET ) - return fp->flags |= _FILE_STATUS_ERROR, errno = EINVAL, -1; - fp->buffer_mode = mode; - if ( buf ) + (void) buf; + (void) size; + if ( mode == -1 ) { - fp->buffer = (unsigned char*) buf; - fp->buffersize = size; - fp->flags |= _FILE_BUFFER_MODE_SET; - fp->fflush_indirect = fflush; +#if defined(__is_sortix_kernel) + mode = _IOLBF; +#else + mode = _IOFBF; + int saved_errno = errno; + if ( isatty(fileno_unlocked(fp)) ) + mode = _IOLBF; + errno = saved_errno; +#endif } + if ( !fp->buffer ) + mode = _IONBF; + fp->buffer_mode = mode; + fp->flags |= _FILE_BUFFER_MODE_SET; + fp->fflush_indirect = fflush; return 0; } diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp index 1591c9d5..01692c56 100644 --- a/libc/stdio/stdio.cpp +++ b/libc/stdio/stdio.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2014. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2014, 2015. This file is part of the Sortix C Library. @@ -29,6 +29,9 @@ #include "fdio.h" +static unsigned char stdin_buffer[BUFSIZ]; +static unsigned char stdout_buffer[BUFSIZ]; + static struct fdio_state stdin_fdio = { NULL, 0 }; static struct fdio_state stdout_fdio = { NULL, 1 }; static struct fdio_state stderr_fdio = { NULL, 2 }; @@ -41,8 +44,7 @@ extern FILE __stderr_file; FILE __stdin_file = { - /* buffersize = */ 0, - /* buffer = */ NULL, + /* buffer = */ stdin_buffer, /* user = */ &stdin_fdio, /* free_user = */ NULL, /* reopen_func = */ fdio_reopen, @@ -54,7 +56,6 @@ FILE __stdin_file = /* free_func = */ NULL, /* file_lock = */ PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, /* fflush_indirect = */ NULL, - /* buffer_free_indirect = */ NULL, /* prev = */ NULL, /* next = */ &__stdout_file, /* flags = */ _FILE_REGISTERED | _FILE_READABLE, @@ -66,8 +67,7 @@ FILE __stdin_file = FILE __stdout_file { - /* buffersize = */ 0, - /* buffer = */ NULL, + /* buffer = */ stdout_buffer, /* user = */ &stdout_fdio, /* free_user = */ NULL, /* reopen_func = */ fdio_reopen, @@ -79,7 +79,6 @@ FILE __stdout_file /* free_func = */ NULL, /* file_lock = */ PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, /* fflush_indirect = */ NULL, - /* buffer_free_indirect = */ NULL, /* prev = */ &__stdin_file, /* next = */ &__stderr_file, /* flags = */ _FILE_REGISTERED | _FILE_WRITABLE, @@ -91,7 +90,6 @@ FILE __stdout_file FILE __stderr_file { - /* buffersize = */ 0, /* buffer = */ NULL, /* user = */ &stderr_fdio, /* free_user = */ NULL, @@ -104,7 +102,6 @@ FILE __stderr_file /* free_func = */ NULL, /* file_lock = */ PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, /* fflush_indirect = */ NULL, - /* buffer_free_indirect = */ NULL, /* prev = */ &__stdout_file, /* next = */ NULL, /* flags = */ _FILE_REGISTERED | _FILE_WRITABLE, @@ -114,8 +111,8 @@ FILE __stderr_file /* amount_output_buffered = */ 0, }; -FILE* stdin = &__stdin_file; -FILE* stdout = &__stdout_file; -FILE* stderr = &__stderr_file; +FILE* const stdin = &__stdin_file; +FILE* const stdout = &__stdout_file; +FILE* const stderr = &__stderr_file; } /* extern "C" */ diff --git a/libc/stdio/ungetc_unlocked.cpp b/libc/stdio/ungetc_unlocked.cpp index b377bfae..dd839085 100644 --- a/libc/stdio/ungetc_unlocked.cpp +++ b/libc/stdio/ungetc_unlocked.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015. This file is part of the Sortix C Library. @@ -36,8 +36,7 @@ extern "C" int ungetc_unlocked(int c, FILE* fp) return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; if ( !(fp->flags & _FILE_BUFFER_MODE_SET) ) - if ( fsetdefaultbuf_unlocked(fp) != 0 ) - return EOF; + setvbuf_unlocked(fp, NULL, fp->buffer_mode, 0); if ( fp->flags & _FILE_LAST_WRITE ) fflush_stop_writing_unlocked(fp); @@ -51,7 +50,7 @@ extern "C" int ungetc_unlocked(int c, FILE* fp) if ( fp->offset_input_buffer == 0 ) { size_t amount = fp->amount_input_buffered - fp->offset_input_buffer; - size_t offset = fp->buffersize - amount; + size_t offset = BUFSIZ - amount; if ( !offset ) return EOF; memmove(fp->buffer + offset, fp->buffer, sizeof(fp->buffer[0]) * amount); diff --git a/libc/stdio_ext/__fbufsize.cpp b/libc/stdio_ext/__fbufsize.cpp index c5fad42d..3f71b750 100644 --- a/libc/stdio_ext/__fbufsize.cpp +++ b/libc/stdio_ext/__fbufsize.cpp @@ -28,7 +28,7 @@ extern "C" size_t __fbufsize(FILE* fp) { flockfile(fp); - size_t result = fp->buffersize; + int mode = fp->buffer_mode; funlockfile(fp); - return result; + return mode == _IONBF ? 0 : BUFSIZ; }