mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-26 09:54:17 +08:00
* output.cc (Output_file::open_for_modification): New method.
(Output_file::map_anonymous): Changed return type to bool. Record map in base_ field. (Output_file::map_no_anonymous): New method, broken out of map. (Output_file::map): Use map_no_anonymous and map_anonymous. * output.h (class Output_file): Update declarations.
This commit is contained in:
parent
77495bbfbf
commit
404c2abb01
130
gold/output.cc
130
gold/output.cc
@ -3397,6 +3397,42 @@ Output_file::Output_file(const char* name)
|
||||
{
|
||||
}
|
||||
|
||||
// Try to open an existing file. Returns false if the file doesn't
|
||||
// exist, has a size of 0 or can't be mmapped.
|
||||
|
||||
bool
|
||||
Output_file::open_for_modification()
|
||||
{
|
||||
// The name "-" means "stdout".
|
||||
if (strcmp(this->name_, "-") == 0)
|
||||
return false;
|
||||
|
||||
// Don't bother opening files with a size of zero.
|
||||
struct stat s;
|
||||
if (::stat(this->name_, &s) != 0 || s.st_size == 0)
|
||||
return false;
|
||||
|
||||
int o = open_descriptor(-1, this->name_, O_RDWR, 0);
|
||||
if (o < 0)
|
||||
gold_fatal(_("%s: open: %s"), this->name_, strerror(errno));
|
||||
this->o_ = o;
|
||||
this->file_size_ = s.st_size;
|
||||
|
||||
// If the file can't be mmapped, copying the content to an anonymous
|
||||
// map will probably negate the performance benefits of incremental
|
||||
// linking. This could be helped by using views and loading only
|
||||
// the necessary parts, but this is not supported as of now.
|
||||
if (!this->map_no_anonymous())
|
||||
{
|
||||
release_descriptor(o, true);
|
||||
this->o_ = -1;
|
||||
this->file_size_ = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Open the output file.
|
||||
|
||||
void
|
||||
@ -3465,21 +3501,27 @@ Output_file::resize(off_t file_size)
|
||||
}
|
||||
}
|
||||
|
||||
// Map a block of memory which will later be written to the file.
|
||||
// Return a pointer to the memory.
|
||||
// Map an anonymous block of memory which will later be written to the
|
||||
// file. Return whether the map succeeded.
|
||||
|
||||
void*
|
||||
bool
|
||||
Output_file::map_anonymous()
|
||||
{
|
||||
this->map_is_anonymous_ = true;
|
||||
return ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
void* base = ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (base != MAP_FAILED)
|
||||
{
|
||||
this->map_is_anonymous_ = true;
|
||||
this->base_ = static_cast<unsigned char*>(base);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map the file into memory.
|
||||
// Map the file into memory. Return whether the mapping succeeded.
|
||||
|
||||
void
|
||||
Output_file::map()
|
||||
bool
|
||||
Output_file::map_no_anonymous()
|
||||
{
|
||||
const int o = this->o_;
|
||||
|
||||
@ -3492,38 +3534,52 @@ Output_file::map()
|
||||
|| ::fstat(o, &statbuf) != 0
|
||||
|| !S_ISREG(statbuf.st_mode)
|
||||
|| this->is_temporary_)
|
||||
base = this->map_anonymous();
|
||||
else
|
||||
{
|
||||
// Ensure that we have disk space available for the file. If we
|
||||
// don't do this, it is possible that we will call munmap,
|
||||
// close, and exit with dirty buffers still in the cache with no
|
||||
// assigned disk blocks. If the disk is out of space at that
|
||||
// point, the output file will wind up incomplete, but we will
|
||||
// have already exited. The alternative to fallocate would be
|
||||
// to use fdatasync, but that would be a more significant
|
||||
// performance hit.
|
||||
if (::posix_fallocate(o, 0, this->file_size_) < 0)
|
||||
gold_fatal(_("%s: %s"), this->name_, strerror(errno));
|
||||
return false;
|
||||
|
||||
// Map the file into memory.
|
||||
this->map_is_anonymous_ = false;
|
||||
base = ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, o, 0);
|
||||
// Ensure that we have disk space available for the file. If we
|
||||
// don't do this, it is possible that we will call munmap, close,
|
||||
// and exit with dirty buffers still in the cache with no assigned
|
||||
// disk blocks. If the disk is out of space at that point, the
|
||||
// output file will wind up incomplete, but we will have already
|
||||
// exited. The alternative to fallocate would be to use fdatasync,
|
||||
// but that would be a more significant performance hit.
|
||||
if (::posix_fallocate(o, 0, this->file_size_) < 0)
|
||||
gold_fatal(_("%s: %s"), this->name_, strerror(errno));
|
||||
|
||||
// The mmap call might fail because of file system issues: the
|
||||
// file system might not support mmap at all, or it might not
|
||||
// support mmap with PROT_WRITE. I'm not sure which errno
|
||||
// values we will see in all cases, so if the mmap fails for any
|
||||
// reason try for an anonymous map.
|
||||
if (base == MAP_FAILED)
|
||||
base = this->map_anonymous();
|
||||
}
|
||||
// Map the file into memory.
|
||||
base = ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, o, 0);
|
||||
|
||||
// The mmap call might fail because of file system issues: the file
|
||||
// system might not support mmap at all, or it might not support
|
||||
// mmap with PROT_WRITE.
|
||||
if (base == MAP_FAILED)
|
||||
gold_fatal(_("%s: mmap: failed to allocate %lu bytes for output file: %s"),
|
||||
this->name_, static_cast<unsigned long>(this->file_size_),
|
||||
strerror(errno));
|
||||
return false;
|
||||
|
||||
this->map_is_anonymous_ = false;
|
||||
this->base_ = static_cast<unsigned char*>(base);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Map the file into memory.
|
||||
|
||||
void
|
||||
Output_file::map()
|
||||
{
|
||||
if (this->map_no_anonymous())
|
||||
return;
|
||||
|
||||
// The mmap call might fail because of file system issues: the file
|
||||
// system might not support mmap at all, or it might not support
|
||||
// mmap with PROT_WRITE. I'm not sure which errno values we will
|
||||
// see in all cases, so if the mmap fails for any reason and we
|
||||
// don't care about file contents, try for an anonymous map.
|
||||
if (this->map_anonymous())
|
||||
return;
|
||||
|
||||
gold_fatal(_("%s: mmap: failed to allocate %lu bytes for output file: %s"),
|
||||
this->name_, static_cast<unsigned long>(this->file_size_),
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
// Unmap the file from memory.
|
||||
|
@ -3093,16 +3093,24 @@ class Output_file
|
||||
set_is_temporary()
|
||||
{ this->is_temporary_ = true; }
|
||||
|
||||
// Try to open an existing file. Returns false if the file doesn't
|
||||
// exist, has a size of 0 or can't be mmaped. This method is
|
||||
// thread-unsafe.
|
||||
bool
|
||||
open_for_modification();
|
||||
|
||||
// Open the output file. FILE_SIZE is the final size of the file.
|
||||
// If the file already exists, it is deleted/truncated. This method
|
||||
// is thread-unsafe.
|
||||
void
|
||||
open(off_t file_size);
|
||||
|
||||
// Resize the output file.
|
||||
// Resize the output file. This method is thread-unsafe.
|
||||
void
|
||||
resize(off_t file_size);
|
||||
|
||||
// Close the output file (flushing all buffered data) and make sure
|
||||
// there are no errors.
|
||||
// there are no errors. This method is thread-unsafe.
|
||||
void
|
||||
close();
|
||||
|
||||
@ -3153,14 +3161,19 @@ class Output_file
|
||||
{ }
|
||||
|
||||
private:
|
||||
// Map the file into memory.
|
||||
// Map the file into memory or, if that fails, allocate anonymous
|
||||
// memory.
|
||||
void
|
||||
map();
|
||||
|
||||
// Allocate anonymous memory for the file.
|
||||
void*
|
||||
bool
|
||||
map_anonymous();
|
||||
|
||||
// Map the file into memory.
|
||||
bool
|
||||
map_no_anonymous();
|
||||
|
||||
// Unmap the file from memory (and flush to disk buffers).
|
||||
void
|
||||
unmap();
|
||||
|
Loading…
Reference in New Issue
Block a user