#include <cerrno>
#include <fcntl.h>
#include <unistd.h>
+#include <sys/mman.h>
#include "options.h"
#include "dirsearch.h"
File_read::View::~View()
{
gold_assert(!this->is_locked());
- delete[] this->data_;
+ if (!this->mapped_)
+ delete[] this->data_;
+ else
+ {
+ if (::munmap(const_cast<unsigned char*>(this->data_), this->size_) != 0)
+ fprintf(stderr, _("%s: munmap failed: %s\n"),
+ program_name, strerror(errno));
+ }
}
void
{
gold_assert(this->lock_count_ > 0);
--this->lock_count_;
+ if (this->lock_count_ == 0)
+ this->clear_views(false);
}
bool
}
// Read SIZE bytes from the file starting at offset START. Read into
-// the buffer at P. Return the number of bytes read, which should
-// always be at least SIZE except at the end of the file.
+// the buffer at P.
-off_t
+void
File_read::do_read(off_t start, off_t size, void* p)
{
gold_assert(this->lock_count_ > 0);
+ off_t bytes;
if (this->contents_ != NULL)
{
- off_t bytes = this->size_ - start;
- if (bytes < 0)
- bytes = 0;
- else if (bytes > size)
- bytes = size;
- memcpy(p, this->contents_ + start, bytes);
- return bytes;
+ bytes = this->size_ - start;
+ if (bytes >= size)
+ {
+ memcpy(p, this->contents_ + start, size);
+ return;
+ }
}
-
- off_t bytes = ::pread(this->descriptor_, p, size, start);
- if (bytes < 0)
+ else
{
- fprintf(stderr, _("%s: %s: pread failed: %s\n"),
- program_name, this->filename().c_str(), strerror(errno));
- gold_exit(false);
- }
-
- return bytes;
-}
-
-// Read exactly SIZE bytes from the file starting at offset START.
-// Read into the buffer at P.
+ bytes = ::pread(this->descriptor_, p, size, start);
+ if (bytes == size)
+ return;
-void
-File_read::do_read_exact(off_t start, off_t size, void* p)
-{
- off_t bytes = this->do_read(start, size, p);
- if (bytes != size)
- {
- 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),
- static_cast<long long>(size),
- static_cast<long long>(start));
- gold_exit(false);
+ if (bytes < 0)
+ {
+ fprintf(stderr, _("%s: %s: pread failed: %s\n"),
+ program_name, this->filename().c_str(), strerror(errno));
+ gold_exit(false);
+ }
}
+
+ 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),
+ static_cast<long long>(size),
+ static_cast<long long>(start));
+ gold_exit(false);
}
// Read data from the file.
return;
}
- this->do_read_exact(start, size, p);
+ this->do_read(start, size, p);
}
// Find an existing view or make a new one.
File_read::View*
-File_read::find_or_make_view(off_t start, off_t size)
+File_read::find_or_make_view(off_t start, off_t size, bool cache)
{
gold_assert(this->lock_count_ > 0);
// There was an existing view at this offset.
File_read::View* v = ins.first->second;
if (v->size() - (start - v->start()) >= size)
- return v;
+ {
+ if (cache)
+ v->set_cache();
+ return v;
+ }
// This view is not large enough.
this->saved_views_.push_back(v);
gold_assert(psize >= size);
}
- unsigned char* p = new unsigned char[psize];
+ File_read::View* v;
- this->do_read_exact(poff, psize, p);
+ if (this->contents_ != NULL)
+ {
+ unsigned char* p = new unsigned char[psize];
+ this->do_read(poff, psize, p);
+ v = new File_read::View(poff, psize, p, cache, false);
+ }
+ else
+ {
+ void* p = ::mmap(NULL, psize, PROT_READ, MAP_SHARED,
+ this->descriptor_, poff);
+ if (p == MAP_FAILED)
+ {
+ fprintf(stderr, _("%s: %s: mmap offset %lld size %lld failed: %s\n"),
+ program_name, this->filename().c_str(),
+ static_cast<long long>(poff),
+ static_cast<long long>(psize),
+ strerror(errno));
+ gold_exit(false);
+ }
+
+ const unsigned char* pbytes = static_cast<const unsigned char*>(p);
+ v = new File_read::View(poff, psize, pbytes, cache, true);
+ }
- File_read::View* v = new File_read::View(poff, psize, p);
ins.first->second = v;
return v;
}
// mmap.
const unsigned char*
-File_read::get_view(off_t start, off_t size)
+File_read::get_view(off_t start, off_t size, bool cache)
{
gold_assert(this->lock_count_ > 0);
- File_read::View* pv = this->find_or_make_view(start, size);
+ File_read::View* pv = this->find_or_make_view(start, size, cache);
return pv->data() + (start - pv->start());
}
File_view*
-File_read::get_lasting_view(off_t start, off_t size)
+File_read::get_lasting_view(off_t start, off_t size, bool cache)
{
gold_assert(this->lock_count_ > 0);
- File_read::View* pv = this->find_or_make_view(start, size);
+ File_read::View* pv = this->find_or_make_view(start, size, cache);
pv->lock();
return new File_view(*this, pv, pv->data() + (start - pv->start()));
}
p != this->views_.end();
++p)
{
- if (!p->second->is_locked())
+ if (!p->second->is_locked()
+ && (destroying || !p->second->should_cache()))
delete p->second;
else
{
Saved_views::iterator p = this->saved_views_.begin();
while (p != this->saved_views_.end())
{
- if (!(*p)->is_locked())
+ if (!(*p)->is_locked()
+ && (destroying || !(*p)->should_cache()))
{
delete *p;
p = this->saved_views_.erase(p);