summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>2008-07-25 04:25:49 +0000
committerIan Lance Taylor <ian@airs.com>2008-07-25 04:25:49 +0000
commit2a00e4fb8e170de97cb80a0140ba4d42a8ffd42f (patch)
treebd6483e0ea6e9704286a6ff02d732a79c29e91cf
parente2df110677592d7b096d7ea9a20d695b49555037 (diff)
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.
-rw-r--r--gold/ChangeLog32
-rw-r--r--gold/Makefile.am2
-rw-r--r--gold/Makefile.in24
-rw-r--r--gold/archive.cc10
-rw-r--r--gold/archive.h6
-rw-r--r--gold/descriptors.cc211
-rw-r--r--gold/descriptors.h105
-rw-r--r--gold/fileread.cc53
-rw-r--r--gold/fileread.h27
-rw-r--r--gold/gold-threads.h23
-rw-r--r--gold/layout.cc5
-rw-r--r--gold/object.h2
-rw-r--r--gold/output.cc4
13 files changed, 459 insertions, 45 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 657f644d56..853984950e 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -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.
diff --git a/gold/Makefile.am b/gold/Makefile.am
index fd5870aefe..b5a5e54a35 100644
--- a/gold/Makefile.am
+++ b/gold/Makefile.am
@@ -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 \
diff --git a/gold/Makefile.in b/gold/Makefile.in
index 242924b288..007730871d 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -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@
diff --git a/gold/archive.cc b/gold/archive.cc
index 8d11797def..27f4380fbe 100644
--- a/gold/archive.cc
+++ b/gold/archive.cc
@@ -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();
diff --git a/gold/archive.h b/gold/archive.h
index 53b8452d81..cca74b6d2c 100644
--- a/gold/archive.h
+++ b/gold/archive.h
@@ -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
index 0000000000..75a7a869c5
--- /dev/null
+++ b/gold/descriptors.cc
@@ -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
index 0000000000..6a6ab61be0
--- /dev/null
+++ b/gold/descriptors.h
@@ -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)
diff --git a/gold/fileread.cc b/gold/fileread.cc
index cfe0ee6deb..e476194f04 100644
--- a/gold/fileread.cc
+++ b/gold/fileread.cc
@@ -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)
diff --git a/gold/fileread.h b/gold/fileread.h
index 3e25f8b39b..4236ce0cce 100644
--- a/gold/fileread.h
+++ b/gold/fileread.h
@@ -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_;
diff --git a/gold/gold-threads.h b/gold/gold-threads.h
index bc4595a84d..c901e42e50 100644
--- a/gold/gold-threads.h
+++ b/gold/gold-threads.h
@@ -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
diff --git a/gold/layout.cc b/gold/layout.cc
index 37edbb6c83..a08ec72193 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -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)
diff --git a/gold/object.h b/gold/object.h
index 8ddd68970a..188f1f208f 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -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.
diff --git a/gold/output.cc b/gold/output.cc
index a24ee5fff9..145fca159d 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -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;