From 2a00e4fb8e170de97cb80a0140ba4d42a8ffd42f Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 25 Jul 2008 04:25:49 +0000 Subject: [PATCH] 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. --- gold/ChangeLog | 32 +++++++ gold/Makefile.am | 2 + gold/Makefile.in | 24 ++--- gold/archive.cc | 10 +-- gold/archive.h | 6 +- gold/descriptors.cc | 211 ++++++++++++++++++++++++++++++++++++++++++++ gold/descriptors.h | 105 ++++++++++++++++++++++ gold/fileread.cc | 53 ++++++++--- gold/fileread.h | 27 +++--- gold/gold-threads.h | 23 +++++ gold/layout.cc | 5 +- gold/object.h | 2 +- gold/output.cc | 4 +- 13 files changed, 459 insertions(+), 45 deletions(-) create mode 100644 gold/descriptors.cc create mode 100644 gold/descriptors.h diff --git a/gold/ChangeLog b/gold/ChangeLog index 657f644d564..853984950e8 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,5 +1,37 @@ 2008-07-24 Ian Lance Taylor + 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 . Add Solaris workarounds following code in binutils/sysdep.h. diff --git a/gold/Makefile.am b/gold/Makefile.am index fd5870aefe9..b5a5e54a355 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 242924b2880..007730871d0 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 8d11797defa..27f4380fbeb 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 53b8452d81d..cca74b6d2cd 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 00000000000..75a7a869c59 --- /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 . + +// 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 +#include +#include +#include + +#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(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(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(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(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 00000000000..6a6ab61be0d --- /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 . + +// 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 + +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_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 cfe0ee6debb..e476194f049 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(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 3e25f8b39b0..4236ce0ccef 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 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 bc4595a84df..c901e42e50e 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 37edbb6c836..a08ec721937 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(got) != uuidsz) diff --git a/gold/object.h b/gold/object.h index 8ddd68970a3..188f1f208fe 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 a24ee5fff95..145fca159df 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; -- 2.30.2