mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-24 12:23:31 +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:
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.
|
// Open the output file.
|
||||||
|
|
||||||
void
|
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.
|
// Map an anonymous block of memory which will later be written to the
|
||||||
// Return a pointer to the memory.
|
// file. Return whether the map succeeded.
|
||||||
|
|
||||||
void*
|
bool
|
||||||
Output_file::map_anonymous()
|
Output_file::map_anonymous()
|
||||||
{
|
{
|
||||||
this->map_is_anonymous_ = true;
|
void* base = ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
|
||||||
return ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
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
|
bool
|
||||||
Output_file::map()
|
Output_file::map_no_anonymous()
|
||||||
{
|
{
|
||||||
const int o = this->o_;
|
const int o = this->o_;
|
||||||
|
|
||||||
@ -3492,38 +3534,52 @@ Output_file::map()
|
|||||||
|| ::fstat(o, &statbuf) != 0
|
|| ::fstat(o, &statbuf) != 0
|
||||||
|| !S_ISREG(statbuf.st_mode)
|
|| !S_ISREG(statbuf.st_mode)
|
||||||
|| this->is_temporary_)
|
|| this->is_temporary_)
|
||||||
base = this->map_anonymous();
|
return false;
|
||||||
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));
|
|
||||||
|
|
||||||
// Map the file into memory.
|
// Ensure that we have disk space available for the file. If we
|
||||||
this->map_is_anonymous_ = false;
|
// don't do this, it is possible that we will call munmap, close,
|
||||||
base = ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
|
// and exit with dirty buffers still in the cache with no assigned
|
||||||
MAP_SHARED, o, 0);
|
// 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
|
// Map the file into memory.
|
||||||
// file system might not support mmap at all, or it might not
|
base = ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
|
||||||
// support mmap with PROT_WRITE. I'm not sure which errno
|
MAP_SHARED, o, 0);
|
||||||
// values we will see in all cases, so if the mmap fails for any
|
|
||||||
// reason try for an anonymous map.
|
// The mmap call might fail because of file system issues: the file
|
||||||
if (base == MAP_FAILED)
|
// system might not support mmap at all, or it might not support
|
||||||
base = this->map_anonymous();
|
// mmap with PROT_WRITE.
|
||||||
}
|
|
||||||
if (base == MAP_FAILED)
|
if (base == MAP_FAILED)
|
||||||
gold_fatal(_("%s: mmap: failed to allocate %lu bytes for output file: %s"),
|
return false;
|
||||||
this->name_, static_cast<unsigned long>(this->file_size_),
|
|
||||||
strerror(errno));
|
this->map_is_anonymous_ = false;
|
||||||
this->base_ = static_cast<unsigned char*>(base);
|
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.
|
// Unmap the file from memory.
|
||||||
|
@ -3093,16 +3093,24 @@ class Output_file
|
|||||||
set_is_temporary()
|
set_is_temporary()
|
||||||
{ this->is_temporary_ = true; }
|
{ 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.
|
// 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
|
void
|
||||||
open(off_t file_size);
|
open(off_t file_size);
|
||||||
|
|
||||||
// Resize the output file.
|
// Resize the output file. This method is thread-unsafe.
|
||||||
void
|
void
|
||||||
resize(off_t file_size);
|
resize(off_t file_size);
|
||||||
|
|
||||||
// Close the output file (flushing all buffered data) and make sure
|
// 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
|
void
|
||||||
close();
|
close();
|
||||||
|
|
||||||
@ -3153,14 +3161,19 @@ class Output_file
|
|||||||
{ }
|
{ }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Map the file into memory.
|
// Map the file into memory or, if that fails, allocate anonymous
|
||||||
|
// memory.
|
||||||
void
|
void
|
||||||
map();
|
map();
|
||||||
|
|
||||||
// Allocate anonymous memory for the file.
|
// Allocate anonymous memory for the file.
|
||||||
void*
|
bool
|
||||||
map_anonymous();
|
map_anonymous();
|
||||||
|
|
||||||
|
// Map the file into memory.
|
||||||
|
bool
|
||||||
|
map_no_anonymous();
|
||||||
|
|
||||||
// Unmap the file from memory (and flush to disk buffers).
|
// Unmap the file from memory (and flush to disk buffers).
|
||||||
void
|
void
|
||||||
unmap();
|
unmap();
|
||||||
|
Reference in New Issue
Block a user