diff options
-rw-r--r-- | ChangeLog | 25 | ||||
-rw-r--r-- | libio/fileops.c | 63 | ||||
-rw-r--r-- | libio/iofdopen.c | 4 | ||||
-rw-r--r-- | libio/iofopen.c | 85 | ||||
-rw-r--r-- | libio/iofopen64.c | 28 | ||||
-rw-r--r-- | libio/iolibio.h | 2 | ||||
-rw-r--r-- | libio/libioP.h | 3 | ||||
-rw-r--r-- | libio/wfileops.c | 92 | ||||
-rw-r--r-- | stdio-common/Makefile | 2 | ||||
-rw-r--r-- | sysdeps/gnu/_G_config.h | 1 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/cris/_G_config.h | 1 |
11 files changed, 271 insertions, 35 deletions
diff --git a/ChangeLog b/ChangeLog index 6e4be046e9..2ab8d3064e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2002-01-07 Ulrich Drepper <drepper@redhat.com> + + * libio/fileops.c (_IO_file_underflow_mmap): New function. + (_IO_file_close_mmap): New function. + (_IO_file_jumps_mmap): New variable. + * libio/wfileops.c (_IO_wfile_underflow): Reset read pointer before + trying to convert rest of byte buffer. + (_IO_wfile_underflow_mmap): New function. + (_IO_wfile_jumps_mmap): New variable. + * libio/iofopen.c (__fopen_maybe_mmap): New function. + (__fopen_internal): New function. Split out from _IO_new_fopen. + (_IO_new_fopen): Call __fopen_internal. + * libio/iofopen64.c: Just call __fopen_internal. + * libio/iofdopen.c: Call __fopen_maybe_mmap before returning + successfully. + * libio/iolibio.h: Declare __fopen_internal and __fopen_maybe_mmap. + * libio/libioP.h: Declare _IO_file_jumps_mmap, _IO_wfile_jumps_mmap, + _IO_file_close_mmap. + + * sysdeps/gnu/_G_config.h: Define _G_MMAP64. + * sysdeps/unix/sysv/linux/cris/_G_config.h: Likewise. + + * stdio-common/Makefile (tests): Add tst-rndseek. + * stdio-common/tst-rndseek.c: New file. + 2002-01-05 Roland McGrath <roland@frob.com> * config.h.in (HAVE_MIG_RETCODE): New #undef. diff --git a/libio/fileops.c b/libio/fileops.c index f67eeefe6e..32fa524507 100644 --- a/libio/fileops.c +++ b/libio/fileops.c @@ -556,6 +556,34 @@ _IO_new_file_underflow (fp) return *(unsigned char *) fp->_IO_read_ptr; } +/* Special callback replacing the underflow callbacks if we mmap the + file. */ +static int +_IO_file_underflow_mmap (_IO_FILE *fp) +{ + if (fp->_IO_read_end < fp->_IO_buf_end) + { + if ( +# ifdef _G_LSEEK64 + _G_LSEEK64 (fp->_fileno, fp->_IO_buf_end - fp->_IO_buf_base, + SEEK_SET) +# else + __lseek (fp->_fileno, fp->_IO_buf_end - fp->_IO_buf_base, SEEK_SET) +# endif + != fp->_IO_buf_end - fp->_IO_buf_base) + { + fp->_flags |= _IO_ERR_SEEN; + return EOF; + } + + fp->_IO_read_end = fp->_IO_buf_end; + return *fp->_IO_read_ptr; + } + + fp->_flags |= _IO_EOF_SEEN; + return EOF; +} + int _IO_new_file_overflow (f, ch) _IO_FILE *f; @@ -864,6 +892,17 @@ _IO_file_stat (fp, st) } int +_IO_file_close_mmap (fp) + _IO_FILE *fp; +{ + /* In addition to closing the file descriptor we have to unmap the + file. */ + (void) munmap (fp->_IO_buf_base, fp->_IO_buf_end - fp->_IO_buf_base); + fp->_IO_buf_base = fp->_IO_buf_end = NULL; + return close (fp->_fileno); +} + +int _IO_file_close (fp) _IO_FILE *fp; { @@ -1107,6 +1146,30 @@ struct _IO_jump_t _IO_file_jumps = JUMP_INIT(imbue, _IO_default_imbue) }; +struct _IO_jump_t _IO_file_jumps_mmap = +{ + JUMP_INIT_DUMMY, + JUMP_INIT(finish, _IO_new_file_finish), + JUMP_INIT(overflow, _IO_new_file_overflow), + JUMP_INIT(underflow, _IO_file_underflow_mmap), + JUMP_INIT(uflow, _IO_default_uflow), + JUMP_INIT(pbackfail, _IO_default_pbackfail), + JUMP_INIT(xsputn, _IO_new_file_xsputn), + JUMP_INIT(xsgetn, _IO_file_xsgetn), + JUMP_INIT(seekoff, _IO_new_file_seekoff), + JUMP_INIT(seekpos, _IO_default_seekpos), + JUMP_INIT(setbuf, _IO_new_file_setbuf), + JUMP_INIT(sync, _IO_new_file_sync), + JUMP_INIT(doallocate, _IO_file_doallocate), + JUMP_INIT(read, _IO_file_read), + JUMP_INIT(write, _IO_new_file_write), + JUMP_INIT(seek, _IO_file_seek), + JUMP_INIT(close, _IO_file_close_mmap), + JUMP_INIT(stat, _IO_file_stat), + JUMP_INIT(showmanyc, _IO_default_showmanyc), + JUMP_INIT(imbue, _IO_default_imbue) +}; + #ifdef _LIBC versioned_symbol (libc, _IO_new_do_write, _IO_do_write, GLIBC_2_1); versioned_symbol (libc, _IO_new_file_attach, _IO_file_attach, GLIBC_2_1); diff --git a/libio/iofdopen.c b/libio/iofdopen.c index 91e68fa56b..2c73bdabab 100644 --- a/libio/iofdopen.c +++ b/libio/iofdopen.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1993, 1994, 1997-1999, 2000 Free Software Foundation, Inc. +/* Copyright (C) 1993,1994,1997-1999,2000,2002 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -142,7 +142,7 @@ _IO_new_fdopen (fd, mode) _IO_mask_flags (&new_f->fp.file, read_write, _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); - return (_IO_FILE *) &new_f->fp; + return __fopen_maybe_mmap (&new_f->fp.file); } strong_alias (_IO_new_fdopen, __new_fdopen) diff --git a/libio/iofopen.c b/libio/iofopen.c index 8fd334543d..e4821cbf0e 100644 --- a/libio/iofopen.c +++ b/libio/iofopen.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1993, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. +/* Copyright (C) 1993,1997,1998,1999,2000,2002 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -28,6 +28,7 @@ #include "libioP.h" #ifdef __STDC__ #include <stdlib.h> +#include <stddef.h> #endif #ifdef _LIBC # include <shlib-compat.h> @@ -36,9 +37,76 @@ #endif _IO_FILE * -_IO_new_fopen (filename, mode) +__fopen_maybe_mmap (fp) + _IO_FILE *fp; +{ +#ifdef _G_HAVE_MMAP + if (fp->_flags & _IO_NO_WRITES) + { + /* We use the file in read-only mode. This could mean we can + mmap the file and use it without any copying. But not all + file descriptors are for mmap-able objects and on 32-bit + machines we don't want to map files which are too large since + this would require too much virtual memory. */ + struct _G_stat64 st; + + if (_IO_SYSSTAT (fp, &st) == 0 + && S_ISREG (st.st_mode) && st.st_size != 0 + /* Limit the file size to 1MB for 32-bit machines. */ + && (sizeof (ptrdiff_t) > 4 || st.st_size < 1*1024*1024)) + { + /* Try to map the file. */ + void *p; + +# ifdef _G_MMAP64 + p = _G_MMAP64 (NULL, st.st_size, PROT_READ, MAP_PRIVATE, + fp->_fileno, 0); +# else + p = __mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, + fp->_fileno, 0); +# endif + if (p != MAP_FAILED) + { + if ( +# ifdef _G_LSEEK64 + _G_LSEEK64 (fp->_fileno, st.st_size, SEEK_SET) +# else + __lseek (fp->_fileno, st.st_size, SEEK_SET) +# endif + != st.st_size) + { + /* We cannot search the file. Don't mmap then. */ + __munmap (p, st.st_size); + return fp; + } + + /* OK, we managed to map the file. Set the buffer up + and use a special jump table with simplified + underflow functions which never tries to read + anything from the file. */ + _IO_setb (fp, p, (char *) p + st.st_size, 0); + _IO_setg (fp, p, p, (char *) p + st.st_size); + + if (fp->_mode <= 0) + _IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_file_jumps_mmap; + else + _IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_wfile_jumps_mmap; + fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap; + + fp->_offset = st.st_size; + } + } + } +#endif + return fp; +} + + +_IO_FILE * +__fopen_internal (filename, mode, is32) const char *filename; const char *mode; + int is32; { struct locked_FILE { @@ -64,13 +132,22 @@ _IO_new_fopen (filename, mode) #if !_IO_UNIFIED_JUMPTABLES new_f->fp.vtable = NULL; #endif - if (_IO_file_fopen ((_IO_FILE *) new_f, filename, mode, 1) != NULL) - return (_IO_FILE *) &new_f->fp; + if (_IO_file_fopen ((_IO_FILE *) new_f, filename, mode, is32) != NULL) + return __fopen_maybe_mmap (&new_f->fp.file); + _IO_un_link (&new_f->fp); free (new_f); return NULL; } +_IO_FILE * +_IO_new_fopen (filename, mode) + const char *filename; + const char *mode; +{ + return __fopen_internal (filename, mode, 1); +} + #ifdef _LIBC strong_alias (_IO_new_fopen, __new_fopen) versioned_symbol (libc, _IO_new_fopen, _IO_fopen, GLIBC_2_1); diff --git a/libio/iofopen64.c b/libio/iofopen64.c index d7f97478f6..69e62b8cda 100644 --- a/libio/iofopen64.c +++ b/libio/iofopen64.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1993, 1997, 1999, 2000 Free Software Foundation, Inc. +/* Copyright (C) 1993, 1997, 1999, 2000, 2002 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -36,31 +36,7 @@ _IO_fopen64 (filename, mode) const char *mode; { #ifdef _G_OPEN64 - struct locked_FILE - { - struct _IO_FILE_plus fp; -#ifdef _IO_MTSAFE_IO - _IO_lock_t lock; -#endif - struct _IO_wide_data wd; - } *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE)); - - if (new_f == NULL) - return NULL; -#ifdef _IO_MTSAFE_IO - new_f->fp.file._lock = &new_f->lock; -#endif - _IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd, &_IO_wfile_jumps); - _IO_JUMPS (&new_f->fp) = &_IO_file_jumps; - _IO_file_init (&new_f->fp); -#if !_IO_UNIFIED_JUMPTABLES - new_f->fp.vtable = NULL; -#endif - if (_IO_file_fopen ((_IO_FILE *) new_f, filename, mode, 0) != NULL) - return (_IO_FILE *) &new_f->fp; - _IO_un_link (&new_f->fp); - free (new_f); - return NULL; + return __fopen_internal (filename, mode, 0); #else __set_errno (ENOSYS); return NULL; diff --git a/libio/iolibio.h b/libio/iolibio.h index 5417de0603..709760670b 100644 --- a/libio/iolibio.h +++ b/libio/iolibio.h @@ -21,6 +21,8 @@ extern _IO_FILE *_IO_fopen __P((const char*, const char*)); extern _IO_FILE *_IO_old_fopen __P((const char*, const char*)); extern _IO_FILE *_IO_new_fopen __P((const char*, const char*)); extern _IO_FILE *_IO_fopen64 __P((const char*, const char*)); +extern _IO_FILE *__fopen_internal __P((const char*, const char*, int)); +extern _IO_FILE *__fopen_maybe_mmap __P((_IO_FILE *)); extern int _IO_fprintf __P((_IO_FILE*, const char*, ...)); extern int _IO_fputs __P((const char*, _IO_FILE*)); extern int _IO_fsetpos __P((_IO_FILE*, const _IO_fpos_t *)); diff --git a/libio/libioP.h b/libio/libioP.h index 3a32caa8b6..f9f44cc0d3 100644 --- a/libio/libioP.h +++ b/libio/libioP.h @@ -414,7 +414,9 @@ extern int _IO_default_showmanyc __P ((_IO_FILE *)); extern void _IO_default_imbue __P ((_IO_FILE *, void *)); extern struct _IO_jump_t _IO_file_jumps; +extern struct _IO_jump_t _IO_file_jumps_mmap; extern struct _IO_jump_t _IO_wfile_jumps; +extern struct _IO_jump_t _IO_wfile_jumps_mmap; extern struct _IO_jump_t _IO_old_file_jumps; extern struct _IO_jump_t _IO_streambuf_jumps; extern struct _IO_jump_t _IO_proc_jumps; @@ -488,6 +490,7 @@ extern _IO_size_t _IO_file_xsputn __P ((_IO_FILE *, const void *, _IO_size_t)); extern _IO_size_t _IO_file_xsgetn __P ((_IO_FILE *, void *, _IO_size_t)); extern int _IO_file_stat __P ((_IO_FILE *, void *)); extern int _IO_file_close __P ((_IO_FILE *)); +extern int _IO_file_close_mmap __P ((_IO_FILE *)); extern int _IO_file_underflow __P ((_IO_FILE *)); extern int _IO_file_overflow __P ((_IO_FILE *, int)); #define _IO_file_is_open(__fp) ((__fp)->_fileno != -1) diff --git a/libio/wfileops.c b/libio/wfileops.c index 92d1a08190..35d201b939 100644 --- a/libio/wfileops.c +++ b/libio/wfileops.c @@ -143,7 +143,7 @@ _IO_wfile_underflow (fp) int tries; const char *read_ptr_copy; - if (fp->_flags & _IO_NO_READS) + if (__builtin_expect (fp->_flags & _IO_NO_READS, 0)) { fp->_flags |= _IO_ERR_SEEN; __set_errno (EBADF); @@ -161,10 +161,12 @@ _IO_wfile_underflow (fp) const char *read_stop = (const char *) fp->_IO_read_ptr; fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; + fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr = + fp->_wide_data->_IO_buf_base; status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, fp->_IO_read_ptr, fp->_IO_read_end, &read_stop, - fp->_wide_data->_IO_read_end, + fp->_wide_data->_IO_read_ptr, fp->_wide_data->_IO_buf_end, &fp->_wide_data->_IO_read_end); @@ -306,6 +308,67 @@ _IO_wfile_underflow (fp) } +static wint_t +_IO_wfile_underflow_mmap (_IO_FILE *fp) +{ + struct _IO_codecvt *cd; + enum __codecvt_result status; + + if (__builtin_expect (fp->_flags & _IO_NO_READS, 0)) + { + fp->_flags |= _IO_ERR_SEEN; + __set_errno (EBADF); + return WEOF; + } + if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end) + return *fp->_wide_data->_IO_read_ptr; + + cd = fp->_codecvt; + + /* Maybe there is something left in the external buffer. */ + if (fp->_IO_read_ptr < fp->_IO_read_end) + { + /* There is more in the external. Convert it. */ + const char *read_stop = (const char *) fp->_IO_read_ptr; + + if (fp->_wide_data->_IO_buf_base == NULL) + { + /* Maybe we already have a push back pointer. */ + if (fp->_wide_data->_IO_save_base != NULL) + { + free (fp->_wide_data->_IO_save_base); + fp->_flags &= ~_IO_IN_BACKUP; + } + _IO_wdoallocbuf (fp); + } + + fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; + fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr = + fp->_wide_data->_IO_buf_base; + status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, + fp->_IO_read_ptr, fp->_IO_read_end, + &read_stop, + fp->_wide_data->_IO_read_ptr, + fp->_wide_data->_IO_buf_end, + &fp->_wide_data->_IO_read_end); + + fp->_IO_read_ptr = (char *) read_stop; + + /* If we managed to generate some text return the next character. */ + if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end) + return *fp->_wide_data->_IO_read_ptr; + + /* There is some garbage at the end of the file. */ + __set_errno (EILSEQ); + fp->_flags |= _IO_ERR_SEEN; + return WEOF; + } + + fp->_flags |= _IO_EOF_SEEN; + return WEOF; +} + + wint_t _IO_wfile_overflow (f, wch) _IO_FILE *f; @@ -789,3 +852,28 @@ struct _IO_jump_t _IO_wfile_jumps = JUMP_INIT(showmanyc, _IO_default_showmanyc), JUMP_INIT(imbue, _IO_default_imbue) }; + + +struct _IO_jump_t _IO_wfile_jumps_mmap = +{ + JUMP_INIT_DUMMY, + JUMP_INIT(finish, _IO_new_file_finish), + JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow), + JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap), + JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow), + JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail), + JUMP_INIT(xsputn, _IO_wfile_xsputn), + JUMP_INIT(xsgetn, _IO_file_xsgetn), + JUMP_INIT(seekoff, _IO_wfile_seekoff), + JUMP_INIT(seekpos, _IO_default_seekpos), + JUMP_INIT(setbuf, _IO_new_file_setbuf), + JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync), + JUMP_INIT(doallocate, _IO_wfile_doallocate), + JUMP_INIT(read, _IO_file_read), + JUMP_INIT(write, _IO_new_file_write), + JUMP_INIT(seek, _IO_file_seek), + JUMP_INIT(close, _IO_file_close_mmap), + JUMP_INIT(stat, _IO_file_stat), + JUMP_INIT(showmanyc, _IO_default_showmanyc), + JUMP_INIT(imbue, _IO_default_imbue) +}; diff --git a/stdio-common/Makefile b/stdio-common/Makefile index fd7a8c415a..b72e71efa2 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -56,7 +56,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \ scanf1 scanf2 scanf3 scanf4 scanf5 scanf7 scanf8 scanf9 scanf10 \ scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf tst-sscanf \ tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \ - tst-perror tst-sprintf + tst-perror tst-sprintf tst-rndseek test-srcs = tst-unbputc tst-printf diff --git a/sysdeps/gnu/_G_config.h b/sysdeps/gnu/_G_config.h index edd29ea3f6..b643059234 100644 --- a/sysdeps/gnu/_G_config.h +++ b/sysdeps/gnu/_G_config.h @@ -77,6 +77,7 @@ typedef unsigned int _G_uint32_t __attribute__ ((__mode__ (__SI__))); #define _G_OPEN64 __open64 #define _G_LSEEK64 __lseek64 +#define _G_MMAP64 __mmap64 #define _G_FSTAT64(fd,buf) __fxstat64 (_STAT_VER, fd, buf) /* This is defined by <bits/stat.h> if `st_blksize' exists. */ diff --git a/sysdeps/unix/sysv/linux/cris/_G_config.h b/sysdeps/unix/sysv/linux/cris/_G_config.h index 42fef4d288..083a00abfb 100644 --- a/sysdeps/unix/sysv/linux/cris/_G_config.h +++ b/sysdeps/unix/sysv/linux/cris/_G_config.h @@ -81,6 +81,7 @@ typedef unsigned int _G_uint32_t __attribute__ ((__mode__ (__SI__))); #define _G_OPEN64 __open64 #define _G_LSEEK64 __lseek64 +#define _G_MMAP64 __mmap64 #define _G_FSTAT64(fd,buf) __fxstat64 (_STAT_VER, fd, buf) /* This is defined by <bits/stat.h> if `st_blksize' exists. */ |