PR 5990
authorIan Lance Taylor <ian@airs.com>
Fri, 25 Jul 2008 04:25:49 +0000 (04:25 +0000)
committerIan Lance Taylor <ian@airs.com>
Fri, 25 Jul 2008 04:25:49 +0000 (04:25 +0000)
* descriptors.cc: New file.
* descriptors.h: New file.
* gold-threads.h (class Hold_optional_lock): New class.
* fileread.cc: Include "descriptors.h".
(File_read::~File_read): Release descriptor rather than closing
it.
(File_read::open) [file]: Call open_descriptor rather than open.
Set is_descriptor_opened_.
(File_read::open) [memory]: Assert that descriptor is not open.
(File_read::reopen_descriptor): New function.
(File_read::release): Release descriptor.
(File_read::do_read): Make non-const.  Reopen descriptor.
(File_read::read): Make non-const.
(File_read::make_view): Reopen descriptor.
(File_read::do_readv): Likewise.
* fileread.h (class File_read): Add is_descriptor_opened_ field.
Update declarations.
* layout.cc: Include "descriptors.h".
(Layout::create_build_id): Use open_descriptor rather than open.
* output.cc: Include "descriptors.h".
(Output_file::open): Use open_descriptor rather than open.
* archive.cc (Archive::const_iterator): Change Archive to be
non-const.
(Archive::begin, Archive::end): Make non-const.
(Archive::count_members): Likewise.
* archive.h (class Archive): Update declarations.
* object.h (Object::read): Make non-const.
* Makefile.am (CCFILES): Add descriptors.cc.
(HFILES): Add descriptors.h.
* Makefile.in: Rebuild.

13 files changed:
gold/ChangeLog
gold/Makefile.am
gold/Makefile.in
gold/archive.cc
gold/archive.h
gold/descriptors.cc [new file with mode: 0644]
gold/descriptors.h [new file with mode: 0644]
gold/fileread.cc
gold/fileread.h
gold/gold-threads.h
gold/layout.cc
gold/object.h
gold/output.cc

index 657f644d56497e4e90cfb5eae328fbfdeee229e7..853984950e84acbb8bf99bfcc2b6bd2fb43f7199 100644 (file)
@@ -1,5 +1,37 @@
 2008-07-24  Ian Lance Taylor  <iant@google.com>
 
+       PR 5990
+       * descriptors.cc: New file.
+       * descriptors.h: New file.
+       * gold-threads.h (class Hold_optional_lock): New class.
+       * fileread.cc: Include "descriptors.h".
+       (File_read::~File_read): Release descriptor rather than closing
+       it.
+       (File_read::open) [file]: Call open_descriptor rather than open.
+       Set is_descriptor_opened_.
+       (File_read::open) [memory]: Assert that descriptor is not open.
+       (File_read::reopen_descriptor): New function.
+       (File_read::release): Release descriptor.
+       (File_read::do_read): Make non-const.  Reopen descriptor.
+       (File_read::read): Make non-const.
+       (File_read::make_view): Reopen descriptor.
+       (File_read::do_readv): Likewise.
+       * fileread.h (class File_read): Add is_descriptor_opened_ field.
+       Update declarations.
+       * layout.cc: Include "descriptors.h".
+       (Layout::create_build_id): Use open_descriptor rather than open.
+       * output.cc: Include "descriptors.h".
+       (Output_file::open): Use open_descriptor rather than open.
+       * archive.cc (Archive::const_iterator): Change Archive to be
+       non-const.
+       (Archive::begin, Archive::end): Make non-const.
+       (Archive::count_members): Likewise.
+       * archive.h (class Archive): Update declarations.
+       * object.h (Object::read): Make non-const.
+       * Makefile.am (CCFILES): Add descriptors.cc.
+       (HFILES): Add descriptors.h.
+       * Makefile.in: Rebuild.
+
        PR 6716
        * gold.h: Always include <clocale>.  Add Solaris workarounds
        following code in binutils/sysdep.h.
index fd5870aefe92e874f8a9fe9f9c507b50023fffff..b5a5e54a3551af579f58af07971556ff082f00cf 100644 (file)
@@ -36,6 +36,7 @@ CCFILES = \
        copy-relocs.cc \
        cref.cc \
        defstd.cc \
+       descriptors.cc \
        dirsearch.cc \
        dynobj.cc \
        dwarf_reader.cc \
@@ -74,6 +75,7 @@ HFILES = \
        cref.h \
        defstd.h \
        dirsearch.h \
+       descriptors.h \
        dynobj.h \
        dwarf_reader.h \
        ehframe.h \
index 242924b2880832afb43d564f55edda0166d242f9..007730871d01c3ec2e261cf0d885d14ab12fb448 100644 (file)
@@ -76,16 +76,17 @@ libgold_a_AR = $(AR) $(ARFLAGS)
 libgold_a_LIBADD =
 am__objects_1 = archive.$(OBJEXT) binary.$(OBJEXT) common.$(OBJEXT) \
        compressed_output.$(OBJEXT) copy-relocs.$(OBJEXT) \
-       cref.$(OBJEXT) defstd.$(OBJEXT) dirsearch.$(OBJEXT) \
-       dynobj.$(OBJEXT) dwarf_reader.$(OBJEXT) ehframe.$(OBJEXT) \
-       errors.$(OBJEXT) expression.$(OBJEXT) fileread.$(OBJEXT) \
-       gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(OBJEXT) \
-       mapfile.$(OBJEXT) merge.$(OBJEXT) object.$(OBJEXT) \
-       options.$(OBJEXT) output.$(OBJEXT) parameters.$(OBJEXT) \
-       readsyms.$(OBJEXT) reduced_debug_output.$(OBJEXT) \
-       reloc.$(OBJEXT) resolve.$(OBJEXT) script-sections.$(OBJEXT) \
-       script.$(OBJEXT) stringpool.$(OBJEXT) symtab.$(OBJEXT) \
-       target-select.$(OBJEXT) version.$(OBJEXT) workqueue.$(OBJEXT) \
+       cref.$(OBJEXT) defstd.$(OBJEXT) descriptors.$(OBJEXT) \
+       dirsearch.$(OBJEXT) dynobj.$(OBJEXT) dwarf_reader.$(OBJEXT) \
+       ehframe.$(OBJEXT) errors.$(OBJEXT) expression.$(OBJEXT) \
+       fileread.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
+       layout.$(OBJEXT) mapfile.$(OBJEXT) merge.$(OBJEXT) \
+       object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \
+       parameters.$(OBJEXT) readsyms.$(OBJEXT) \
+       reduced_debug_output.$(OBJEXT) reloc.$(OBJEXT) \
+       resolve.$(OBJEXT) script-sections.$(OBJEXT) script.$(OBJEXT) \
+       stringpool.$(OBJEXT) symtab.$(OBJEXT) target-select.$(OBJEXT) \
+       version.$(OBJEXT) workqueue.$(OBJEXT) \
        workqueue-threads.$(OBJEXT)
 am__objects_2 =
 am__objects_3 = yyscript.$(OBJEXT)
@@ -318,6 +319,7 @@ CCFILES = \
        copy-relocs.cc \
        cref.cc \
        defstd.cc \
+       descriptors.cc \
        dirsearch.cc \
        dynobj.cc \
        dwarf_reader.cc \
@@ -356,6 +358,7 @@ HFILES = \
        cref.h \
        defstd.h \
        dirsearch.h \
+       descriptors.h \
        dynobj.h \
        dwarf_reader.h \
        ehframe.h \
@@ -528,6 +531,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copy-relocs.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cref.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defstd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/descriptors.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirsearch.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_reader.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynobj.Po@am__quote@
index 8d11797defa726e9de4f3d41bfed6e93e9e62cf2..27f4380fbeb36cf7687a8825607e0e842dada199 100644 (file)
@@ -384,7 +384,7 @@ class Archive::const_iterator
     off_t size;
   };
 
-  const_iterator(const Archive* archive, off_t off)
+  const_iterator(Archive* archive, off_t off)
     : archive_(archive), off_(off)
   { this->read_next_header(); }
 
@@ -431,7 +431,7 @@ class Archive::const_iterator
   read_next_header();
 
   // The underlying archive.
-  const Archive* archive_;
+  Archive* archive_;
   // The current offset in the file.
   off_t off_;
   // The current archive header.
@@ -481,7 +481,7 @@ Archive::const_iterator::read_next_header()
 // Initial iterator.
 
 Archive::const_iterator
-Archive::begin() const
+Archive::begin()
 {
   return Archive::const_iterator(this, sarmag);
 }
@@ -489,7 +489,7 @@ Archive::begin() const
 // Final iterator.
 
 Archive::const_iterator
-Archive::end() const
+Archive::end()
 {
   return Archive::const_iterator(this, this->input_file_->file().filesize());
 }
@@ -515,7 +515,7 @@ Archive::include_all_members(Symbol_table* symtab, Layout* layout,
 // reports.
 
 size_t
-Archive::count_members() const
+Archive::count_members()
 {
   size_t ret = 0;
   for (Archive::const_iterator p = this->begin();
index 53b8452d81d757297ddf462d063f776731cde8ac..cca74b6d2cd3d84f7eec23d82cd2304b6e58674c 100644 (file)
@@ -133,7 +133,7 @@ class Archive
 
   // Return the number of members in the archive.
   size_t
-  count_members() const;
+  count_members();
 
  private:
   Archive(const Archive&);
@@ -175,10 +175,10 @@ class Archive
   class const_iterator;
 
   const_iterator
-  begin() const;
+  begin();
 
   const_iterator
-  end() const;
+  end();
 
   friend class const_iterator;
 
diff --git a/gold/descriptors.cc b/gold/descriptors.cc
new file mode 100644 (file)
index 0000000..75a7a86
--- /dev/null
@@ -0,0 +1,211 @@
+// descriptors.cc -- manage file descriptors for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "gold.h"
+
+#include <cerrno>
+#include <cstring>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "parameters.h"
+#include "gold-threads.h"
+#include "descriptors.h"
+
+namespace gold
+{
+
+// Class Descriptors.
+
+// The default for limit_ is meant to simply be large.  It gets
+// adjusted downward if we run out of file descriptors.
+
+Descriptors::Descriptors()
+  : lock_(NULL), open_descriptors_(), stack_top_(-1), current_(0),
+    limit_(8192 - 16)
+{
+  this->open_descriptors_.reserve(128);
+}
+
+// Open a file.
+
+int
+Descriptors::open(int descriptor, const char* name, int flags, int mode)
+{
+  // We don't initialize this until we are called, because we can't
+  // initialize a Lock until we have parsed the options to find out
+  // whether we are running with threads.  We can be called before
+  // options are valid when reading a linker script.
+  if (this->lock_ == NULL)
+    {
+      if (parameters->options_valid())
+       this->lock_ = new Lock();
+      else
+       gold_assert(descriptor < 0);
+    }
+
+  if (descriptor >= 0)
+    {
+      Hold_lock hl(*this->lock_);
+
+      gold_assert(static_cast<size_t>(descriptor)
+                 < this->open_descriptors_.size());
+      Open_descriptor* pod = &this->open_descriptors_[descriptor];
+      if (pod->name == name
+         || (pod->name != NULL && strcmp(pod->name, name) == 0))
+       {
+         gold_assert(!pod->inuse);
+         pod->inuse = true;
+         return descriptor;
+       }
+    }
+
+  while (true)
+    {
+      int new_descriptor = ::open(name, flags, mode);
+      if (new_descriptor < 0
+         && errno != ENFILE
+         && errno != EMFILE)
+       {
+         if (descriptor >= 0 && errno == ENOENT)
+           {
+             {
+               Hold_lock hl(*this->lock_);
+
+               gold_error(_("file %s was removed during the link"),
+                          this->open_descriptors_[descriptor].name);
+             }
+
+             errno = ENOENT;
+           }
+
+         return new_descriptor;
+       }
+
+      if (new_descriptor >= 0)
+       {
+         Hold_optional_lock hl(this->lock_);
+
+         if (static_cast<size_t>(new_descriptor)
+             >= this->open_descriptors_.size())
+           this->open_descriptors_.resize(new_descriptor + 64);
+
+         Open_descriptor* pod = &this->open_descriptors_[new_descriptor];
+         pod->name = name;
+         pod->stack_next = -1;
+         pod->inuse = true;
+         pod->is_write = (flags & O_ACCMODE) != O_RDONLY;
+
+         ++this->current_;
+         if (this->current_ >= this->limit_)
+           this->close_some_descriptor();
+
+         return new_descriptor;
+       }
+
+      // We ran out of file descriptors.
+      {
+       Hold_optional_lock hl(this->lock_);
+
+       this->limit_ = this->current_ - 16;
+       if (this->limit_ < 8)
+         this->limit_ = 8;
+       if (!this->close_some_descriptor())
+         gold_fatal(_("out of file descriptors and couldn't close any"));
+      }
+    }
+}
+
+// Release a descriptor.
+
+void
+Descriptors::release(int descriptor, bool permanent)
+{
+  Hold_optional_lock hl(this->lock_);
+
+  gold_assert(descriptor >= 0
+             && (static_cast<size_t>(descriptor)
+                 < this->open_descriptors_.size()));
+  Open_descriptor* pod = &this->open_descriptors_[descriptor];
+
+  if (permanent
+      || (this->current_ > this->limit_ && !pod->is_write))
+    {
+      if (::close(descriptor) < 0)
+       gold_warning(_("while closing %s: %s"), pod->name, strerror(errno));
+      pod->name = NULL;
+      --this->current_;
+    }
+  else
+    {
+      pod->inuse = false;
+      if (!pod->is_write)
+       {
+         pod->stack_next = this->stack_top_;
+         this->stack_top_ = descriptor;
+       }
+    }
+}
+
+// Close some descriptor.  The lock is held when this is called.  We
+// close the descriptor on the top of the free stack.  Note that this
+// is the opposite of an LRU algorithm--we close the most recently
+// used descriptor.  That is because the linker tends to cycle through
+// all the files; after we release a file, we are unlikely to need it
+// again until we have looked at all the other files.  Return true if
+// we closed a descriptor.
+
+bool
+Descriptors::close_some_descriptor()
+{
+  int last = -1;
+  int i = this->stack_top_;
+  while (i >= 0)
+    {
+      gold_assert(static_cast<size_t>(i) < this->open_descriptors_.size());
+      Open_descriptor* pod = &this->open_descriptors_[i];
+      if (!pod->inuse && !pod->is_write)
+       {
+         if (::close(i) < 0)
+           gold_warning(_("while closing %s: %s"), pod->name, strerror(errno));
+         --this->current_;
+         pod->name = NULL;
+         if (last < 0)
+           this->stack_top_ = pod->stack_next;
+         else
+           this->open_descriptors_[last].stack_next = pod->stack_next;
+         return true;
+       }
+      last = i;
+      i = pod->stack_next;
+    }
+
+  // We couldn't find any descriptors to close.  This is weird but not
+  // necessarily an error.
+  return false;
+}
+
+// The single global variable which manages descriptors.
+
+Descriptors descriptors;
+
+} // End namespace gold.
diff --git a/gold/descriptors.h b/gold/descriptors.h
new file mode 100644 (file)
index 0000000..6a6ab61
--- /dev/null
@@ -0,0 +1,105 @@
+// descriptors.h -- manage file descriptors for gold   -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#ifndef GOLD_DESCRIPTORS_H
+#define GOLD_DESCRIPTORS_H
+
+#include <vector>
+
+namespace gold
+{
+
+class Lock;
+
+// This class manages file descriptors for gold.
+
+class Descriptors
+{
+ public:
+  Descriptors();
+
+  // Get a file descriptor for a file.  The DESCRIPTOR parameter is
+  // the descriptor the last time the file was used; this will be -1
+  // if this is the first time the file is being opened.  The NAME,
+  // FLAGS, and MODE parameters are as for ::open.  NAME must be in
+  // permanent storage.  This returns the descriptor to use, which may
+  // or may not be the same as DESCRIPTOR.  If there is an error
+  // opening the file, this will return -1 with errno set
+  // appropriately.
+  int
+  open(int descriptor, const char* name, int flags, int mode = 0);
+
+  // Release the file descriptor DESCRIPTOR.  If PERMANENT is true, it
+  // will be closed, and the caller may not reopen it.  If PERMANENT
+  // is false this doesn't necessarily close the descriptor, but it
+  // makes it available to be closed; the descriptor must not be used
+  // again except as an argument to Descriptor::open.
+  void
+  release(int descriptor, bool permanent);
+
+ private:
+  // Information kept for a descriptor.
+  struct Open_descriptor
+  {
+    // File name currently associated with descriptor.  This is empty
+    // if none.
+    const char* name;
+    // Index of next descriptor on stack of released descriptors.
+    int stack_next;
+    // Whether the descriptor is currently in use.
+    bool inuse;
+    // Whether this is a write descriptor.
+    bool is_write;
+  };
+
+  bool
+  close_some_descriptor();
+
+  // We need to lock before accessing any fields.
+  Lock* lock_;
+  // Information for descriptors.
+  std::vector<Open_descriptor> open_descriptors_;
+  // Top of stack.
+  int stack_top_;
+  // The current number of file descriptors open.
+  int current_;
+  // The maximum number of file descriptors we open.
+  int limit_;
+};
+
+// File descriptors are a centralized data structure, and we use a
+// global variable rather than passing the data structure into every
+// routine that does file I/O.
+
+extern Descriptors descriptors;
+
+inline int
+open_descriptor(int descriptor, const char* name, int flags, int mode = 0)
+{ return descriptors.open(descriptor, name, flags, mode); }
+
+inline void
+release_descriptor(int descriptor, bool permanent)
+{ descriptors.release(descriptor, permanent); }
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_DESCRIPTORS_H)
index cfe0ee6debbeb72293afe9a576e69087868ff502..e476194f0499a9bdd396d98bc116cb5f85ffacb5 100644 (file)
@@ -36,6 +36,7 @@
 #include "dirsearch.h"
 #include "target.h"
 #include "binary.h"
+#include "descriptors.h"
 #include "fileread.h"
 
 namespace gold
@@ -83,18 +84,14 @@ unsigned long long File_read::total_mapped_bytes;
 unsigned long long File_read::current_mapped_bytes;
 unsigned long long File_read::maximum_mapped_bytes;
 
-// The File_read class is designed to support file descriptor caching,
-// but this is not currently implemented.
-
 File_read::~File_read()
 {
   gold_assert(this->token_.is_writable());
-  if (this->descriptor_ >= 0)
+  if (this->is_descriptor_opened_)
     {
-      if (close(this->descriptor_) < 0)
-       gold_warning(_("close of %s failed: %s"),
-                    this->name_.c_str(), strerror(errno));
+      release_descriptor(this->descriptor_, true);
       this->descriptor_ = -1;
+      this->is_descriptor_opened_ = false;
     }
   this->name_.clear();
   this->clear_views(true);
@@ -107,13 +104,16 @@ File_read::open(const Task* task, const std::string& name)
 {
   gold_assert(this->token_.is_writable()
              && this->descriptor_ < 0
+             && !this->is_descriptor_opened_
              && this->name_.empty());
   this->name_ = name;
 
-  this->descriptor_ = ::open(this->name_.c_str(), O_RDONLY);
+  this->descriptor_ = open_descriptor(-1, this->name_.c_str(),
+                                     O_RDONLY);
 
   if (this->descriptor_ >= 0)
     {
+      this->is_descriptor_opened_ = true;
       struct stat s;
       if (::fstat(this->descriptor_, &s) < 0)
        gold_error(_("%s: fstat failed: %s"),
@@ -136,6 +136,7 @@ File_read::open(const Task* task, const std::string& name,
 {
   gold_assert(this->token_.is_writable()
              && this->descriptor_ < 0
+             && !this->is_descriptor_opened_
              && this->name_.empty());
   this->name_ = name;
   this->contents_ = contents;
@@ -144,6 +145,22 @@ File_read::open(const Task* task, const std::string& name,
   return true;
 }
 
+// Reopen a descriptor if necessary.
+
+void
+File_read::reopen_descriptor()
+{
+  if (!this->is_descriptor_opened_)
+    {
+      this->descriptor_ = open_descriptor(this->descriptor_,
+                                         this->name_.c_str(),
+                                         O_RDONLY);
+      if (this->descriptor_ < 0)
+       gold_fatal(_("could not reopen file %s"), this->name_.c_str());
+      this->is_descriptor_opened_ = true;
+    }
+}
+
 // Release the file.  This is called when we are done with the file in
 // a Task.
 
@@ -159,9 +176,17 @@ File_read::release()
     File_read::maximum_mapped_bytes = File_read::current_mapped_bytes;
 
   // Only clear views if there is only one attached object.  Otherwise
-  // we waste time trying to clear cached archive views.
+  // we waste time trying to clear cached archive views.  Similarly
+  // for releasing the descriptor.
   if (this->object_count_ <= 1)
-    this->clear_views(false);
+    {
+      this->clear_views(false);
+      if (this->is_descriptor_opened_)
+       {
+         release_descriptor(this->descriptor_, false);
+         this->is_descriptor_opened_ = false;
+       }
+    }
 
   this->released_ = true;
 }
@@ -243,7 +268,7 @@ File_read::find_view(off_t start, section_size_type size,
 // the buffer at P.
 
 void
-File_read::do_read(off_t start, section_size_type size, void* p) const
+File_read::do_read(off_t start, section_size_type size, void* p)
 {
   ssize_t bytes;
   if (this->contents_ != NULL)
@@ -257,6 +282,7 @@ File_read::do_read(off_t start, section_size_type size, void* p) const
     }
   else
     {
+      this->reopen_descriptor();
       bytes = ::pread(this->descriptor_, p, size, start);
       if (static_cast<section_size_type>(bytes) == size)
        return;
@@ -279,7 +305,7 @@ File_read::do_read(off_t start, section_size_type size, void* p) const
 // Read data from the file.
 
 void
-File_read::read(off_t start, section_size_type size, void* p) const
+File_read::read(off_t start, section_size_type size, void* p)
 {
   const File_read::View* pv = this->find_view(start, size, -1U, NULL);
   if (pv != NULL)
@@ -349,6 +375,7 @@ File_read::make_view(off_t start, section_size_type size,
     }
   else
     {
+      this->reopen_descriptor();
       void* p = ::mmap(NULL, psize, PROT_READ, MAP_PRIVATE,
                        this->descriptor_, poff);
       if (p == MAP_FAILED)
@@ -493,6 +520,8 @@ File_read::do_readv(off_t base, const Read_multiple& rm, size_t start,
       last_offset = i_entry.file_offset + i_entry.size;
     }
 
+  this->reopen_descriptor();
+
   gold_assert(iov_index < sizeof iov / sizeof iov[0]);
 
   if (::lseek(this->descriptor_, base + first_offset, SEEK_SET) < 0)
index 3e25f8b39b0c8189af3049106e03234c8ce3d2a4..4236ce0ccef66edae4275d05a02a8ff512205973 100644 (file)
@@ -40,17 +40,16 @@ class Input_file_argument;
 class Dirsearch;
 class File_view;
 
-// File_read manages a file descriptor for a file we are reading.  We
-// close file descriptors if we run out of them, so this class reopens
-// the file as needed.
+// File_read manages a file descriptor and mappings for a file we are
+// reading.
 
 class File_read
 {
  public:
   File_read()
-    : name_(), descriptor_(-1), object_count_(0), size_(0), token_(false),
-      views_(), saved_views_(), contents_(NULL), mapped_bytes_(0),
-      released_(true)
+    : name_(), descriptor_(-1), is_descriptor_opened_(false), object_count_(0),
+      size_(0), token_(false), views_(), saved_views_(), contents_(NULL),
+      mapped_bytes_(0), released_(true)
   { }
 
   ~File_read();
@@ -82,12 +81,12 @@ class File_read
   { --this->object_count_; }
 
   // Lock the file for exclusive access within a particular Task::run
-  // execution.  This means that the descriptor can not be closed.
-  // This routine may only be called when the workqueue lock is held.
+  // execution.  This routine may only be called when the workqueue
+  // lock is held.
   void
   lock(const Task* t);
 
-  // Unlock the descriptor, permitting it to be closed if necessary.
+  // Unlock the file.
   void
   unlock(const Task* t);
 
@@ -133,7 +132,7 @@ class File_read
   // Read data from the file into the buffer P starting at file offset
   // START for SIZE bytes.
   void
-  read(off_t start, section_size_type size, void* p) const;
+  read(off_t start, section_size_type size, void* p);
 
   // Return a lasting view into the file starting at file offset START
   // for SIZE bytes.  This is allocated with new, and the caller is
@@ -296,6 +295,10 @@ class File_read
   // A simple list of Views.
   typedef std::list<View*> Saved_views;
 
+  // Open the descriptor if necessary.
+  void
+  reopen_descriptor();
+
   // Find a view into the file.
   View*
   find_view(off_t start, section_size_type size, unsigned int byteshift,
@@ -303,7 +306,7 @@ class File_read
 
   // Read data from the file into a buffer.
   void
-  do_read(off_t start, section_size_type size, void* p) const;
+  do_read(off_t start, section_size_type size, void* p);
 
   // Add a view.
   void
@@ -347,6 +350,8 @@ class File_read
   std::string name_;
   // File descriptor.
   int descriptor_;
+  // Whether we have regained the descriptor after releasing the file.
+  bool is_descriptor_opened_;
   // The number of objects associated with this file.  This will be
   // more than 1 in the case of an archive.
   int object_count_;
index bc4595a84df99a54d0b7fdafdf9d6ef7b9eab2e9..c901e42e50e3ff1e5f07b02e650350e9ec92b8ea 100644 (file)
@@ -107,6 +107,29 @@ class Hold_lock
   Lock& lock_;
 };
 
+class Hold_optional_lock
+{
+ public:
+  Hold_optional_lock(Lock* lock)
+    : lock_(lock)
+  {
+    if (this->lock_ != NULL)
+      this->lock_->acquire();
+  }
+
+  ~Hold_optional_lock()
+  {
+    if (this->lock_ != NULL)
+      this->lock_->release();
+  }
+
+ private:
+  Hold_optional_lock(const Hold_optional_lock&);
+  Hold_optional_lock& operator=(const Hold_optional_lock&);
+
+  Lock* lock_;
+};
+
 // The interface for the implementation of a condition variable.
 
 class Condvar_impl
index 37edbb6c8366645b9d886082bfbf279ba79ed27f..a08ec72193799af5645909454f774c00f6bfeb2a 100644 (file)
@@ -45,6 +45,7 @@
 #include "compressed_output.h"
 #include "reduced_debug_output.h"
 #include "reloc.h"
+#include "descriptors.h"
 #include "layout.h"
 
 namespace gold
@@ -1507,14 +1508,14 @@ Layout::create_build_id()
       char buffer[uuidsz];
       memset(buffer, 0, uuidsz);
 
-      int descriptor = ::open("/dev/urandom", O_RDONLY);
+      int descriptor = open_descriptor(-1, "/dev/urandom", O_RDONLY);
       if (descriptor < 0)
        gold_error(_("--build-id=uuid failed: could not open /dev/urandom: %s"),
                   strerror(errno));
       else
        {
          ssize_t got = ::read(descriptor, buffer, uuidsz);
-         ::close(descriptor);
+         release_descriptor(descriptor, true);
          if (got < 0)
            gold_error(_("/dev/urandom: read failed: %s"), strerror(errno));
          else if (static_cast<size_t>(got) != uuidsz)
index 8ddd68970a3d548cb853e2d43fa9cad488dc1545..188f1f208fe23845b37d3b7f77dde7b8efcc6a8f 100644 (file)
@@ -410,7 +410,7 @@ class Object
 
   // Read data from the underlying file.
   void
-  read(off_t start, section_size_type size, void* p) const
+  read(off_t start, section_size_type size, void* p)
   { this->input_file()->file().read(start + this->offset_, size, p); }
 
   // Read multiple data from the underlying file.
index a24ee5fff951a2c895b14444be5edb7d083fbd46..145fca159df5f00e0fb4bc7c3e6af3c592b9d5ac 100644 (file)
@@ -37,6 +37,7 @@
 #include "symtab.h"
 #include "reloc.h"
 #include "merge.h"
+#include "descriptors.h"
 #include "output.h"
 
 // Some BSD systems still use MAP_ANON instead of MAP_ANONYMOUS
@@ -3321,7 +3322,8 @@ Output_file::open(off_t file_size)
            unlink_if_ordinary(this->name_);
 
          int mode = parameters->options().relocatable() ? 0666 : 0777;
-         int o = ::open(this->name_, O_RDWR | O_CREAT | O_TRUNC, mode);
+         int o = open_descriptor(-1, this->name_, O_RDWR | O_CREAT | O_TRUNC,
+                                 mode);
          if (o < 0)
            gold_fatal(_("%s: open: %s"), this->name_, strerror(errno));
          this->o_ = o;