aboutsummaryrefslogtreecommitdiff
path: root/gold/fileread.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/fileread.cc')
-rw-r--r--gold/fileread.cc104
1 files changed, 80 insertions, 24 deletions
diff --git a/gold/fileread.cc b/gold/fileread.cc
index 987408e..00971a7 100644
--- a/gold/fileread.cc
+++ b/gold/fileread.cc
@@ -102,18 +102,16 @@ File_read::is_locked()
// See if we have a view which covers the file starting at START for
// SIZE bytes. Return a pointer to the View if found, NULL if not.
-File_read::View*
+inline File_read::View*
File_read::find_view(off_t start, off_t size)
{
- for (std::list<File_read::View*>::iterator p = this->view_list_.begin();
- p != this->view_list_.end();
- ++p)
- {
- if ((*p)->start() <= start
- && (*p)->start() + (*p)->size() >= start + size)
- return *p;
- }
- return NULL;
+ off_t page = File_read::page_offset(start);
+ Views::iterator p = this->views_.find(page);
+ if (p == this->views_.end())
+ return NULL;
+ if (p->second->size() - (start - page) < size)
+ return NULL;
+ return p->second;
}
// Read data from the file. Return the number of bytes read. If
@@ -184,15 +182,59 @@ File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes)
{
assert(this->lock_count_ > 0);
- File_read::View* pv = this->find_view(start, size);
- if (pv != NULL)
- return pv;
+ off_t poff = File_read::page_offset(start);
+
+ File_read::View* const vnull = NULL;
+ std::pair<Views::iterator, bool> ins =
+ this->views_.insert(std::make_pair(poff, vnull));
+
+ if (!ins.second)
+ {
+ // There was an existing view at this offset.
+ File_read::View* v = ins.first->second;
+ if (v->size() - (start - v->start()) >= size)
+ {
+ if (pbytes != NULL)
+ *pbytes = size;
+ return v;
+ }
+
+ // This view is not large enough.
+ this->saved_views_.push_back(v);
+ }
+
+ // We need to read data from the file.
+
+ off_t psize = File_read::pages(size + (start - poff));
+ unsigned char* p = new unsigned char[psize];
- unsigned char* p = new unsigned char[size];
- off_t bytes = this->do_read(start, size, p, pbytes);
- pv = new File_read::View(start, bytes, p);
- this->view_list_.push_back(pv);
- return pv;
+ off_t got_bytes;
+ off_t bytes = this->do_read(poff, psize, p, &got_bytes);
+
+ File_read::View* v = new File_read::View(poff, bytes, p);
+
+ ins.first->second = v;
+
+ if (bytes - (start - poff) >= size)
+ {
+ if (pbytes != NULL)
+ *pbytes = size;
+ return v;
+ }
+
+ if (pbytes != NULL)
+ {
+ *pbytes = bytes - (start - poff);
+ return v;
+ }
+
+ fprintf(stderr,
+ _("%s: %s: file too short: read only %lld of %lld bytes at %lld\n"),
+ program_name, this->filename().c_str(),
+ static_cast<long long>(bytes - (start - poff)),
+ static_cast<long long>(size),
+ static_cast<long long>(start));
+ gold_exit(false);
}
// This implementation of get_view just reads into a memory buffer,
@@ -221,18 +263,32 @@ File_read::get_lasting_view(off_t start, off_t size, off_t* pbytes)
void
File_read::clear_views(bool destroying)
{
- std::list<File_read::View*>::iterator p = this->view_list_.begin();
- while (p != this->view_list_.end())
+ for (Views::iterator p = this->views_.begin();
+ p != this->views_.end();
+ ++p)
{
- if ((*p)->is_locked())
+ if (!p->second->is_locked())
+ delete p->second;
+ else
{
assert(!destroying);
- ++p;
+ this->saved_views_.push_back(p->second);
}
- else
+ }
+ this->views_.clear();
+
+ Saved_views::iterator p = this->saved_views_.begin();
+ while (p != this->saved_views_.end())
+ {
+ if (!(*p)->is_locked())
{
delete *p;
- p = this->view_list_.erase(p);
+ p = this->saved_views_.erase(p);
+ }
+ else
+ {
+ assert(!destroying);
+ ++p;
}
}
}