Create stdio buffers at FILE creation time.

This removes support for user-supplied buffers with setvbuf.
This commit is contained in:
Jonas 'Sortie' Termansen 2015-11-20 00:07:29 +01:00
parent fe067c5150
commit bb73362d23
16 changed files with 65 additions and 172 deletions

View File

@ -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 \

View File

@ -31,6 +31,10 @@
#include <pthread.h>
#if !defined(BUFSIZ)
#include <stdio.h>
#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;

View File

@ -40,10 +40,6 @@
#endif
#include <stdarg.h>
#if defined(__is_sortix_libc)
#include <FILE.h>
#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 <FILE.h>
#endif
#endif

View File

@ -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);

View File

@ -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 <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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);

View File

@ -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;

View File

@ -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 )

View File

@ -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;

View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/fsetdefaultbuf.cpp
Sets up default buffering semantics for a FILE.
*******************************************************************************/
#include <stdio.h>
extern "C" int fsetdefaultbuf(FILE* fp)
{
flockfile(fp);
int ret = fsetdefaultbuf_unlocked(fp);
funlockfile(fp);
return ret;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/fsetdefaultbuf_unlocked.cpp
Sets up default buffering semantics for a FILE.
*******************************************************************************/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
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;
}

View File

@ -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);

View File

@ -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 )

View File

@ -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 <errno.h>
#include <stdio.h>
#include <unistd.h>
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;
}

View File

@ -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" */

View File

@ -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);

View File

@ -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;
}