* configure.ac: Check for chsize and posix_fallocate. Replace
authorIan Lance Taylor <ian@airs.com>
Tue, 17 Mar 2009 22:25:30 +0000 (22:25 +0000)
committerIan Lance Taylor <ian@airs.com>
Tue, 17 Mar 2009 22:25:30 +0000 (22:25 +0000)
ftruncate.
* ftruncate.c: New file, from gnulib.
* output.cc (posix_fallocate): Define dummy version if not
HAVE_POSIX_FALLOCATE.
(Output_file::map): Call posix_fallocate rather than lseek and
write.
* gold.h (ftruncate): Declare if not HAVE_FTRUNCATE.
* configure, Makefile.in, config.in: Rebuild.

gold/ChangeLog
gold/Makefile.in
gold/config.in
gold/configure
gold/configure.ac
gold/ftruncate.c [new file with mode: 0644]
gold/gold.h
gold/output.cc

index 501aabe..50aaaf6 100644 (file)
@@ -1,3 +1,15 @@
+2009-03-17  Ian Lance Taylor  <iant@google.com>
+
+       * configure.ac: Check for chsize and posix_fallocate.  Replace
+       ftruncate.
+       * ftruncate.c: New file, from gnulib.
+       * output.cc (posix_fallocate): Define dummy version if not
+       HAVE_POSIX_FALLOCATE.
+       (Output_file::map): Call posix_fallocate rather than lseek and
+       write.
+       * gold.h (ftruncate): Declare if not HAVE_FTRUNCATE.
+       * configure, Makefile.in, config.in: Rebuild.
+
 2009-03-17  Paul Pluzhnikov  <ppluzhnikov@google.com>
        
        * layout.h (Layout::create_note): Add section_name parameter.
index 20ad5b4..cb49fef 100644 (file)
@@ -50,7 +50,7 @@ DIST_COMMON = README $(am__configure_deps) $(srcdir)/../config.guess \
        $(srcdir)/../mkinstalldirs $(srcdir)/Makefile.am \
        $(srcdir)/Makefile.in $(srcdir)/config.in \
        $(top_srcdir)/configure $(top_srcdir)/po/Make-in ChangeLog \
-       NEWS TODO pread.c yyscript.c yyscript.h
+       NEWS TODO ftruncate.c pread.c yyscript.c yyscript.h
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
@@ -532,6 +532,7 @@ mostlyclean-compile:
 distclean-compile:
        -rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ftruncate.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pread.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binary.Po@am__quote@
index 01aac90..c9e994b 100644 (file)
 /* Define to 1 if you have the <byteswap.h> header file. */
 #undef HAVE_BYTESWAP_H
 
+/* Define to 1 if you have the `chsize' function. */
+#undef HAVE_CHSIZE
+
 /* Define to 1 if you have the <ext/hash_map> header file. */
 #undef HAVE_EXT_HASH_MAP
 
 /* Define to 1 if you have the <ext/hash_set> header file. */
 #undef HAVE_EXT_HASH_SET
 
+/* Define to 1 if you have the `ftruncate' function. */
+#undef HAVE_FTRUNCATE
+
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
 
@@ -40,6 +46,9 @@
 /* Define if compiler supports #pragma omp threadprivate */
 #undef HAVE_OMP_SUPPORT
 
+/* Define to 1 if you have the `posix_fallocate' function. */
+#undef HAVE_POSIX_FALLOCATE
+
 /* Define to 1 if you have the `pread' function. */
 #undef HAVE_PREAD
 
index 50ebad4..5f2782a 100755 (executable)
@@ -5057,7 +5057,110 @@ LFS_CFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
 
 
 
-for ac_func in pread
+for ac_func in chsize
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+for ac_func in pread ftruncate
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
 echo "$as_me:$LINENO: checking for $ac_func" >&5
@@ -6640,7 +6743,8 @@ fi
 done
 
 
-for ac_func in mallinfo
+
+for ac_func in mallinfo posix_fallocate
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
 echo "$as_me:$LINENO: checking for $ac_func" >&5
index c26c05d..134efe6 100644 (file)
@@ -307,7 +307,8 @@ dnl host dependent.  If build == host, we can check getconf LFS_CFLAGS.
 LFS_CFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
 AC_SUBST(LFS_CFLAGS)
 
-AC_REPLACE_FUNCS(pread)
+AC_CHECK_FUNCS(chsize)
+AC_REPLACE_FUNCS(pread ftruncate)
 
 # Link in zlib if we can.  This allows us to write compressed sections.
 AC_SEARCH_LIBS(zlibVersion, z, [AC_CHECK_HEADERS(zlib.h)])
@@ -318,7 +319,7 @@ AC_LANG_PUSH(C++)
 AC_CHECK_HEADERS(tr1/unordered_set tr1/unordered_map)
 AC_CHECK_HEADERS(ext/hash_map ext/hash_set)
 AC_CHECK_HEADERS(byteswap.h)
-AC_CHECK_FUNCS(mallinfo)
+AC_CHECK_FUNCS(mallinfo posix_fallocate)
 
 # gcc 4.3.0 doesn't recognize the printf attribute on a template
 # function.  Check for that.  This is gcc bug 35546.  This test can
diff --git a/gold/ftruncate.c b/gold/ftruncate.c
new file mode 100644 (file)
index 0000000..ff7d11b
--- /dev/null
@@ -0,0 +1,90 @@
+/* ftruncate emulations that work on some System V's.
+   This file is in the public domain.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef F_CHSIZE
+
+int
+ftruncate (int fd, off_t length)
+{
+  return fcntl (fd, F_CHSIZE, length);
+}
+
+#else /* not F_CHSIZE */
+# ifdef F_FREESP
+
+/* By William Kucharski <kucharsk@netcom.com>.  */
+
+#  include <sys/stat.h>
+#  include <errno.h>
+
+int
+ftruncate (int fd, off_t length)
+{
+  struct flock fl;
+  struct stat filebuf;
+
+  if (fstat (fd, &filebuf) < 0)
+    return -1;
+
+  if (filebuf.st_size < length)
+    {
+      /* Extend file length. */
+      if (lseek (fd, (length - 1), SEEK_SET) < 0)
+       return -1;
+
+      /* Write a "0" byte. */
+      if (write (fd, "", 1) != 1)
+       return -1;
+    }
+  else
+    {
+
+      /* Truncate length. */
+
+      fl.l_whence = 0;
+      fl.l_len = 0;
+      fl.l_start = length;
+      fl.l_type = F_WRLCK;     /* write lock on file space */
+
+      /* This relies on the *undocumented* F_FREESP argument to fcntl,
+        which truncates the file so that it ends at the position
+        indicated by fl.l_start.  Will minor miracles never cease?  */
+
+      if (fcntl (fd, F_FREESP, &fl) < 0)
+       return -1;
+    }
+
+  return 0;
+}
+
+# else /* not F_CHSIZE nor F_FREESP */
+#  if HAVE_CHSIZE                      /* native Windows, e.g. mingw */
+
+int
+ftruncate (int fd, off_t length)
+{
+  return chsize (fd, length);
+}
+
+#  else /* not F_CHSIZE nor F_FREESP nor HAVE_CHSIZE */
+
+#   include <errno.h>
+
+int
+ftruncate (int fd, off_t length)
+{
+  errno = EIO;
+  return -1;
+}
+
+#  endif /* not HAVE_CHSIZE */
+# endif /* not F_FREESP */
+#endif /* not F_CHSIZE */
index a0cc62d..780561d 100644 (file)
@@ -121,6 +121,10 @@ struct hash<T*>
 extern "C" ssize_t pread(int, void*, size_t, off_t);
 #endif
 
+#ifndef HAVE_FTRUNCATE
+extern "C" int ftruncate(int, off_t);
+#endif
+
 namespace gold
 {
 
index f2ec6ee..2f9db62 100644 (file)
 # define MAP_ANONYMOUS  MAP_ANON
 #endif
 
+#ifndef HAVE_POSIX_FALLOCATE
+// A dummy, non general, version of posix_fallocate.  Here we just set
+// the file size and hope that there is enough disk space.  FIXME: We
+// could allocate disk space by walking block by block and writing a
+// zero byte into each block.
+static int
+posix_fallocate(int o, off_t offset, off_t len)
+{
+  return ftruncate(o, offset + len);
+}
+#endif // !defined(HAVE_POSIX_FALLOCATE)
+
 namespace gold
 {
 
@@ -3388,12 +3400,16 @@ Output_file::map()
     }
   else
     {
-      // Write out one byte to make the file the right size.
-      if (::lseek(o, this->file_size_ - 1, SEEK_SET) < 0)
-        gold_fatal(_("%s: lseek: %s"), this->name_, strerror(errno));
-      char b = 0;
-      if (::write(o, &b, 1) != 1)
-        gold_fatal(_("%s: write: %s"), this->name_, strerror(errno));
+      // Ensure that we have disk space available for the file.  If we
+      // don't do this, it is possible that we will call munmap,
+      // close, and exit with dirty buffers still in the cache with no
+      // assigned disk blocks.  If the disk is out of space at that
+      // point, the output file will wind up incomplete, but we will
+      // have already exited.  The alternative to fallocate would be
+      // to use fdatasync, but that would be a more significant
+      // performance hit.
+      if (::posix_fallocate(o, 0, this->file_size_) < 0)
+       gold_fatal(_("%s: %s"), this->name_, strerror(errno));
 
       // Map the file into memory.
       this->map_is_anonymous_ = false;