diff options
author | Andrew Hsieh <andrewhsieh@google.com> | 2014-06-13 12:38:00 -0700 |
---|---|---|
committer | Andrew Hsieh <andrewhsieh@google.com> | 2014-06-13 12:38:00 -0700 |
commit | 54f1b3cf509cd889905287cb8ce6c5ae33911a21 (patch) | |
tree | e39b1a7fa04db86a8215b7f9d4656d74e394aec0 /binutils-2.25/gold/dirsearch.cc | |
parent | 2a6558a8ecfb81d75215b4ec7dc61113e12cfd5f (diff) | |
download | toolchain_binutils-54f1b3cf509cd889905287cb8ce6c5ae33911a21.tar.gz toolchain_binutils-54f1b3cf509cd889905287cb8ce6c5ae33911a21.tar.bz2 toolchain_binutils-54f1b3cf509cd889905287cb8ce6c5ae33911a21.zip |
Add upstream binutils-2.25 snapshot 4/4 2014
For MIPS -mmsa support
Change-Id: I08c4f002fa7b33dec85ed75956e6ab551bb03c96
Diffstat (limited to 'binutils-2.25/gold/dirsearch.cc')
-rw-r--r-- | binutils-2.25/gold/dirsearch.cc | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/binutils-2.25/gold/dirsearch.cc b/binutils-2.25/gold/dirsearch.cc new file mode 100644 index 00000000..a6114a44 --- /dev/null +++ b/binutils-2.25/gold/dirsearch.cc @@ -0,0 +1,305 @@ +// dirsearch.cc -- directory searching for gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 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 <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> + +#include "debug.h" +#include "gold-threads.h" +#include "options.h" +#include "workqueue.h" +#include "dirsearch.h" + +namespace +{ + +// Read all the files in a directory. + +class Dir_cache +{ + public: + Dir_cache(const char* dirname) + : dirname_(dirname), files_() + { } + + // Read the files in the directory. + void read_files(); + + // Return whether a file (a base name) is present in the directory. + bool find(const std::string&) const; + + private: + // We can not copy this class. + Dir_cache(const Dir_cache&); + Dir_cache& operator=(const Dir_cache&); + + const char* dirname_; + Unordered_set<std::string> files_; +}; + +void +Dir_cache::read_files() +{ + DIR* d = opendir(this->dirname_); + if (d == NULL) + { + // We ignore directories which do not exist or are actually file + // names. + if (errno != ENOENT && errno != ENOTDIR) + gold::gold_error(_("%s: can not read directory: %s"), + this->dirname_, strerror(errno)); + return; + } + + dirent* de; + while ((de = readdir(d)) != NULL) + this->files_.insert(std::string(de->d_name)); + + if (closedir(d) != 0) + gold::gold_warning("%s: closedir failed: %s", this->dirname_, + strerror(errno)); +} + +bool +Dir_cache::find(const std::string& basename) const +{ + return this->files_.find(basename) != this->files_.end(); +} + +// A mapping from directory names to caches. A lock permits +// concurrent update. There is no lock for read operations--some +// other mechanism must be used to prevent reads from conflicting with +// writes. + +class Dir_caches +{ + public: + Dir_caches() + : lock_(), caches_() + { } + + ~Dir_caches(); + + // Add a cache for a directory. + void add(const char*); + + // Look up a directory in the cache. This much be locked against + // calls to Add. + Dir_cache* lookup(const char*) const; + + private: + // We can not copy this class. + Dir_caches(const Dir_caches&); + Dir_caches& operator=(const Dir_caches&); + + typedef Unordered_map<const char*, Dir_cache*> Cache_hash; + + gold::Lock lock_; + Cache_hash caches_; +}; + +Dir_caches::~Dir_caches() +{ + for (Cache_hash::iterator p = this->caches_.begin(); + p != this->caches_.end(); + ++p) + delete p->second; +} + +void +Dir_caches::add(const char* dirname) +{ + { + gold::Hold_lock hl(this->lock_); + if (this->lookup(dirname) != NULL) + return; + } + + Dir_cache* cache = new Dir_cache(dirname); + + cache->read_files(); + + { + gold::Hold_lock hl(this->lock_); + + std::pair<const char*, Dir_cache*> v(dirname, cache); + std::pair<Cache_hash::iterator, bool> p = this->caches_.insert(v); + gold_assert(p.second); + } +} + +Dir_cache* +Dir_caches::lookup(const char* dirname) const +{ + Cache_hash::const_iterator p = this->caches_.find(dirname); + if (p == this->caches_.end()) + return NULL; + return p->second; +} + +// The caches. + +Dir_caches* caches; + +// A Task to read the directory. + +class Dir_cache_task : public gold::Task +{ + public: + Dir_cache_task(const char* dir, gold::Task_token& token) + : dir_(dir), token_(token) + { } + + gold::Task_token* + is_runnable(); + + void + locks(gold::Task_locker*); + + void + run(gold::Workqueue*); + + std::string + get_name() const + { return std::string("Dir_cache_task ") + this->dir_; } + + private: + const char* dir_; + gold::Task_token& token_; +}; + +// We can always run the task to read the directory. + +gold::Task_token* +Dir_cache_task::is_runnable() +{ + return NULL; +} + +// Return the locks to hold. We use a blocker lock to prevent file +// lookups from starting until the directory contents have been read. + +void +Dir_cache_task::locks(gold::Task_locker* tl) +{ + tl->add(this, &this->token_); +} + +// Run the task--read the directory contents. + +void +Dir_cache_task::run(gold::Workqueue*) +{ + caches->add(this->dir_); +} + +} + +namespace gold +{ + +// Initialize. + +void +Dirsearch::initialize(Workqueue* workqueue, + const General_options::Dir_list* directories) +{ + gold_assert(caches == NULL); + caches = new Dir_caches; + this->directories_ = directories; + this->token_.add_blockers(directories->size()); + for (General_options::Dir_list::const_iterator p = directories->begin(); + p != directories->end(); + ++p) + workqueue->queue(new Dir_cache_task(p->name().c_str(), this->token_)); +} + +// Search for a file. NOTE: we only log failed file-lookup attempts +// here. Successfully lookups will eventually get logged in +// File_read::open. + +std::string +Dirsearch::find(const std::vector<std::string>& names, + bool* is_in_sysroot, int* pindex, + std::string *found_name) const +{ + gold_assert(!this->token_.is_blocked()); + gold_assert(*pindex >= 0); + + for (unsigned int i = static_cast<unsigned int>(*pindex); + i < this->directories_->size(); + ++i) + { + const Search_directory* p = &this->directories_->at(i); + Dir_cache* pdc = caches->lookup(p->name().c_str()); + gold_assert(pdc != NULL); + for (std::vector<std::string>::const_iterator n = names.begin(); + n != names.end(); + ++n) + { + if (pdc->find(*n)) + { + *is_in_sysroot = p->is_in_sysroot(); + *pindex = i; + *found_name = *n; + return p->name() + '/' + *n; + } + else + gold_debug(DEBUG_FILES, "Attempt to open %s/%s failed", + p->name().c_str(), (*n).c_str()); + } + } + + *pindex = -2; + return std::string(); +} + +// Search for a file in a directory list. This is a low-level function and +// therefore can be used before options and parameters are set. + +std::string +Dirsearch::find_file_in_dir_list(const std::string& name, + const General_options::Dir_list& directories, + const std::string& extra_search_dir) +{ + struct stat buf; + std::string extra_name = extra_search_dir + '/' + name; + + if (stat(extra_name.c_str(), &buf) == 0) + return extra_name; + for (General_options::Dir_list::const_iterator dir = directories.begin(); + dir != directories.end(); + ++dir) + { + std::string full_name = dir->name() + '/' + name; + if (stat(full_name.c_str(), &buf) == 0) + return full_name; + } + return name; +} + +} // End namespace gold. |