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.
This commit is contained in:
parent
e2df110677
commit
2a00e4fb8e
13 changed files with 459 additions and 45 deletions
|
@ -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.
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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@
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
211
gold/descriptors.cc
Normal file
211
gold/descriptors.cc
Normal file
|
@ -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.
|
105
gold/descriptors.h
Normal file
105
gold/descriptors.h
Normal file
|
@ -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)
|
|
@ -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)
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue