This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]