X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gold%2Fdescriptors.cc;h=d5cc9fc4c95966ce7b652ffd1f9e3f243506db10;hb=6d6c25c8eaaf42755a759beeb2996502322b960c;hp=73c03bf4a457552baafd7e13ba6e9a3b3c3e458c;hpb=89fc34211be8b1d74b83e4e2b18cfa4b4cf65ba9;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/descriptors.cc b/gold/descriptors.cc index 73c03bf4a4..d5cc9fc4c9 100644 --- a/gold/descriptors.cc +++ b/gold/descriptors.cc @@ -1,6 +1,6 @@ // descriptors.cc -- manage file descriptors for gold -// Copyright 2008 Free Software Foundation, Inc. +// Copyright (C) 2008-2019 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -23,13 +23,37 @@ #include "gold.h" #include +#include #include #include +#include #include +#include "debug.h" #include "parameters.h" +#include "options.h" #include "gold-threads.h" #include "descriptors.h" +#include "binary-io.h" + +// O_CLOEXEC is only available on newer systems. +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +// Very old systems may not define FD_CLOEXEC. +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +static inline void +set_close_on_exec(int fd ATTRIBUTE_UNUSED) +{ +// Mingw does not define F_SETFD. +#ifdef F_SETFD + fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif +} namespace gold { @@ -40,8 +64,8 @@ namespace gold // adjusted downward if we run out of file descriptors. Descriptors::Descriptors() - : lock_(NULL), open_descriptors_(), stack_top_(-1), current_(0), - limit_(8192 - 16) + : lock_(NULL), initialize_lock_(&this->lock_), open_descriptors_(), + stack_top_(-1), current_(0), limit_(8192 - 16) { this->open_descriptors_.reserve(128); } @@ -55,13 +79,12 @@ Descriptors::open(int descriptor, const char* name, int flags, int mode) // 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); - } + bool lock_initialized = this->initialize_lock_.initialize(); + + gold_assert(lock_initialized || descriptor < 0); + + if (is_debugging_enabled(DEBUG_FILES)) + this->limit_ = 8; if (descriptor >= 0) { @@ -75,12 +98,27 @@ Descriptors::open(int descriptor, const char* name, int flags, int mode) { gold_assert(!pod->inuse); pod->inuse = true; + if (descriptor == this->stack_top_) + { + this->stack_top_ = pod->stack_next; + pod->stack_next = -1; + pod->is_on_stack = false; + } + gold_debug(DEBUG_FILES, "Reused existing descriptor %d for \"%s\"", + descriptor, name); return descriptor; } } while (true) { + // We always want to set the close-on-exec flag; we don't + // require callers to pass it. + flags |= O_CLOEXEC; + + // Always open the file as a binary file. + flags |= O_BINARY; + int new_descriptor = ::open(name, flags, mode); if (new_descriptor < 0 && errno != ENFILE @@ -91,37 +129,52 @@ Descriptors::open(int descriptor, const char* name, int flags, int mode) { Hold_lock hl(*this->lock_); - gold_error(_("file %s was removed during the link"), - this->open_descriptors_[descriptor].name); + gold_error(_("file %s was removed during the link"), name); } errno = ENOENT; } + gold_debug(DEBUG_FILES, "Opened new descriptor %d for \"%s\"", + new_descriptor, name); 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; + // If we have any plugins, we really do need to set the + // close-on-exec flag, even if O_CLOEXEC is not defined. + // FIXME: In some cases O_CLOEXEC may be defined in the + // header file but not supported by the kernel. + // Unfortunately there doesn't seem to be any obvious way to + // detect that, as unknown flags passed to open are ignored. + if (O_CLOEXEC == 0 + && parameters->options_valid() + && parameters->options().has_plugins()) + set_close_on_exec(new_descriptor); + + { + 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; + pod->is_on_stack = false; - if (!pod->is_claimed) ++this->current_; - pod->is_claimed = false; - if (this->current_ >= this->limit_) - this->close_some_descriptor(); + if (this->current_ >= this->limit_) + this->close_some_descriptor(); - return new_descriptor; + gold_debug(DEBUG_FILES, "Opened new descriptor %d for \"%s\"", + new_descriptor, name); + return new_descriptor; + } } // We ran out of file descriptors. @@ -160,30 +213,16 @@ Descriptors::release(int descriptor, bool permanent) else { pod->inuse = false; - if (!pod->is_write) + if (!pod->is_write && !pod->is_on_stack) { pod->stack_next = this->stack_top_; this->stack_top_ = descriptor; + pod->is_on_stack = true; } } -} - -// Claim the file descriptor DESCRIPTOR for a plugin. This effectively -// removes the descriptor from the pool of linker-managed descriptors, -// as the plugin will assume responsibility for closing it. -// The IS_CLAIMED flag allows us to recognize when a file descriptor -// has been reused after being closed by the plugin. - -void -Descriptors::claim_for_plugin(int descriptor) -{ - Hold_lock hl(*this->lock_); - gold_assert(descriptor >= 0 - && (static_cast(descriptor) - < this->open_descriptors_.size())); - Open_descriptor* pod = &this->open_descriptors_[descriptor]; - pod->is_claimed = true; + gold_debug(DEBUG_FILES, "Released descriptor %d for \"%s\"", + descriptor, pod->name); } // Close some descriptor. The lock is held when this is called. We @@ -208,11 +247,15 @@ Descriptors::close_some_descriptor() if (::close(i) < 0) gold_warning(_("while closing %s: %s"), pod->name, strerror(errno)); --this->current_; + gold_debug(DEBUG_FILES, "Closed descriptor %d for \"%s\"", + i, pod->name); pod->name = NULL; if (last < 0) this->stack_top_ = pod->stack_next; else this->open_descriptors_[last].stack_next = pod->stack_next; + pod->stack_next = -1; + pod->is_on_stack = false; return true; } last = i; @@ -224,6 +267,30 @@ Descriptors::close_some_descriptor() return false; } +// Close all the descriptors open for reading. + +void +Descriptors::close_all() +{ + Hold_optional_lock hl(this->lock_); + + for (size_t i = 0; i < this->open_descriptors_.size(); i++) + { + Open_descriptor* pod = &this->open_descriptors_[i]; + if (pod->name != NULL && !pod->inuse && !pod->is_write) + { + if (::close(i) < 0) + gold_warning(_("while closing %s: %s"), pod->name, strerror(errno)); + gold_debug(DEBUG_FILES, "Closed descriptor %d for \"%s\" (close_all)", + static_cast(i), pod->name); + pod->name = NULL; + pod->stack_next = -1; + pod->is_on_stack = false; + } + } + this->stack_top_ = -1; +} + // The single global variable which manages descriptors. Descriptors descriptors;