summaryrefslogtreecommitdiff
path: root/gold/dirsearch.cc
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2006-08-04 23:10:59 +0000
committerIan Lance Taylor <iant@google.com>2006-08-04 23:10:59 +0000
commitbae7f79e03d6405f5ceec0e3e24671e6b30f29ed (patch)
tree4b9df8c6433411b45963dd75e3a6dcad9a22518e /gold/dirsearch.cc
parentc17d87de17351aed016a9d0b0712cdee4cca5f9e (diff)
Initial CVS checkin of gold
Diffstat (limited to 'gold/dirsearch.cc')
-rw-r--r--gold/dirsearch.cc236
1 files changed, 236 insertions, 0 deletions
diff --git a/gold/dirsearch.cc b/gold/dirsearch.cc
new file mode 100644
index 0000000000..41a2660a88
--- /dev/null
+++ b/gold/dirsearch.cc
@@ -0,0 +1,236 @@
+// dirsearch.cc -- directory searching for gold
+
+#include "gold.h"
+
+#include <cerrno>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "gold-threads.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.
+ if (errno == ENOENT)
+ return;
+
+ char *s = NULL;
+ if (asprintf(&s, _("can not read directory %s"), this->dirname_) < 0)
+ gold::gold_nomem();
+ gold::gold_fatal(s, true);
+ }
+
+ dirent* de;
+ while ((de = readdir(d)) != NULL)
+ this->files_.insert(std::string(de->d_name));
+
+ if (closedir(d) != 0)
+ gold::gold_fatal("closedir failed", true);
+}
+
+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);
+ 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)
+ { }
+
+ Is_runnable_type is_runnable(gold::Workqueue*);
+
+ gold::Task_locker* locks(gold::Workqueue*);
+
+ void run(gold::Workqueue*);
+
+ private:
+ const char* dir_;
+ gold::Task_token& token_;
+};
+
+// We can always run the task to read the directory.
+
+gold::Task::Is_runnable_type
+Dir_cache_task::is_runnable(gold::Workqueue*)
+{
+ return IS_RUNNABLE;
+}
+
+// Return the locks to hold. We use a blocker lock to prevent file
+// lookups from starting until the directory contents have been read.
+
+gold::Task_locker*
+Dir_cache_task::locks(gold::Workqueue* workqueue)
+{
+ return new gold::Task_locker_block(this->token_, workqueue);
+}
+
+// Run the task--read the directory contents.
+
+void
+Dir_cache_task::run(gold::Workqueue*)
+{
+ caches.add(this->dir_);
+}
+
+}
+
+namespace gold
+{
+
+Dirsearch::Dirsearch()
+ : directories_(), token_()
+{
+}
+
+void
+Dirsearch::add(Workqueue* workqueue, const char* d)
+{
+ this->directories_.push_back(d);
+ this->token_.add_blocker();
+ workqueue->queue(new Dir_cache_task(d, this->token_));
+}
+
+void
+Dirsearch::add(Workqueue* workqueue, const General_options::Dir_list& list)
+{
+ for (General_options::Dir_list::const_iterator p = list.begin();
+ p != list.end();
+ ++p)
+ this->add(workqueue, *p);
+}
+
+std::string
+Dirsearch::find(const std::string& n1, const std::string& n2) const
+{
+ assert(!this->token_.is_blocked());
+
+ for (std::list<const char*>::const_iterator p = this->directories_.begin();
+ p != this->directories_.end();
+ ++p)
+ {
+ Dir_cache* pdc = caches.lookup(*p);
+ assert(pdc != NULL);
+ if (pdc->find(n1))
+ return std::string(*p) + '/' + n1;
+ if (!n2.empty() && pdc->find(n2))
+ return std::string(*p) + '/' + n2;
+ }
+
+ return std::string();
+}
+
+} // End namespace gold.