about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog25
-rw-r--r--libio/fileops.c63
-rw-r--r--libio/iofdopen.c4
-rw-r--r--libio/iofopen.c85
-rw-r--r--libio/iofopen64.c28
-rw-r--r--libio/iolibio.h2
-rw-r--r--libio/libioP.h3
-rw-r--r--libio/wfileops.c92
-rw-r--r--stdio-common/Makefile2
-rw-r--r--sysdeps/gnu/_G_config.h1
-rw-r--r--sysdeps/unix/sysv/linux/cris/_G_config.h1
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.  */