This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH 1/2] gold: extend Output_file to support read/write access to existing files.
- From: Mikolaj Zalewski <mikolajz at google dot com>
- To: binutils at sourceware dot org
- Date: Tue, 1 Sep 2009 18:10:52 +0200
- Subject: [PATCH 1/2] gold: extend Output_file to support read/write access to existing files.
Added options to open file without removing its contents and made
map_anonymous behave similarly to other *map* methods, e.g. to modify
this->base_ on success.
2009-09-01 Mikolaj Zalewski <mikolajz@google.com>
* output.cc (Output_file::Output_file): Initialize
map_include_original_content_ .
(Output_file::open_for_modification): New method.
(Output_file::try_map_anonymous): Renamed from
Output_file::map_anonymous, changed behavior to similar to other
*map*.
(Output_file::map): Don't try anonymous mapping it
this->map_include_original_content_.
(Output_file::try_map_no_anonymous): New method (most code from
Output_file::map).
* output.h (Output_file::open_for_modification): New method.
(Output_file::open): Update comment.
(Output_file::resize): Update comment.
(Output_file::close): Update comment.
(Output_file::map): Update comment.
(Output_file::try_map_anonymous): Renamed from Output_file::map_anonymous.
(Output_file::try_map_no_anonymous): New method.
(Output_file::map_include_original_content_): New field.
From 1f7b4c9a802f851e6d3a1f78b2e2333648ae2da4 Mon Sep 17 00:00:00 2001
From: Mikolaj Zalewski <mikolajz@google.com>
Date: Tue, 1 Sep 2009 17:16:25 +0200
Subject: [PATCH] gold: extend Output_file to support read/write access to existing files.
---
gold/output.cc | 91 +++++++++++++++++++++++++++++++++++++++++++++----------
gold/output.h | 24 ++++++++++++---
2 files changed, 93 insertions(+), 22 deletions(-)
diff --git a/gold/output.cc b/gold/output.cc
index 64fcb37..4d1b144 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -3392,11 +3392,47 @@ Output_file::Output_file(const char* name)
o_(-1),
file_size_(0),
base_(NULL),
+ map_include_original_content_(false),
map_is_anonymous_(false),
is_temporary_(false)
{
}
+// Try to open an existing file. Returns false if the file doesn't exist,
+// has a size of 0 or can't be mmaped.
+
+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 mode = parameters->options().relocatable() ? 0666 : 0777;
+ int o = open_descriptor(-1, this->name_, O_RDWR | O_CREAT, mode);
+ 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->try_map_no_anonymous()) {
+ this->o_ = -1;
+ this->file_size_ = 0;
+ return false;
+ }
+ this->map_include_original_content_ = true;
+ return true;
+}
+
// Open the output file.
void
@@ -3468,12 +3504,17 @@ 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.
-void*
-Output_file::map_anonymous()
+bool
+Output_file::try_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 (this->base_ != MAP_FAILED) {
+ this->map_is_anonymous_ = true;
+ this->base_ = static_cast<unsigned char*>(base);
+ return true;
+ }
+ return false;
}
// Map the file into memory.
@@ -3481,6 +3522,28 @@ Output_file::map_anonymous()
void
Output_file::map()
{
+ if (try_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_include_original_content_ && this->try_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));
+}
+
+// Map the file into memory. Unlike map(), we don't fallback into creating
+// an anonymous mapping if the file can't be mmapped.
+
+bool
+Output_file::try_map_no_anonymous()
+{
const int o = this->o_;
// If the output file is not a regular file, don't try to mmap it;
@@ -3492,7 +3555,7 @@ Output_file::map()
|| ::fstat(o, &statbuf) != 0
|| !S_ISREG(statbuf.st_mode)
|| this->is_temporary_)
- base = this->map_anonymous();
+ return false;
else
{
// Ensure that we have disk space available for the file. If we
@@ -3510,20 +3573,14 @@ Output_file::map()
this->map_is_anonymous_ = false;
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. 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();
}
+ // 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->base_ = static_cast<unsigned char*>(base);
+ return true;
}
// Unmap the file from memory.
diff --git a/gold/output.h b/gold/output.h
index f9cbfa6..d104952 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -3093,16 +3093,23 @@ 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,13 +3160,17 @@ class Output_file
{ }
private:
- // Map the file into memory.
+ // Map the file into memory or, if this fails, allocate anonymous memory.
void
map();
// Allocate anonymous memory for the file.
- void*
- map_anonymous();
+ bool
+ try_map_anonymous();
+
+ // Map the file into memory. Don't fall back info allocating anonymous memory.
+ bool
+ try_map_no_anonymous();
// Unmap the file from memory (and flush to disk buffers).
void
@@ -3173,6 +3184,9 @@ class Output_file
off_t file_size_;
// Base of file mapped into memory.
unsigned char* base_;
+ // Whether the mmapped memory should include original content (needed only
+ // during incremental links).
+ bool map_include_original_content_;
// True iff base_ points to a memory buffer rather than an output file.
bool map_is_anonymous_;
// True if this is a temporary file which should not be output.
--
1.5.4.3