descriptors.cc revision 1.1.1.1
1// descriptors.cc -- manage file descriptors for gold 2 3// Copyright 2008 Free Software Foundation, Inc. 4// Written by Ian Lance Taylor <iant@google.com>. 5 6// This file is part of gold. 7 8// This program is free software; you can redistribute it and/or modify 9// it under the terms of the GNU General Public License as published by 10// the Free Software Foundation; either version 3 of the License, or 11// (at your option) any later version. 12 13// This program is distributed in the hope that it will be useful, 14// but WITHOUT ANY WARRANTY; without even the implied warranty of 15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16// GNU General Public License for more details. 17 18// You should have received a copy of the GNU General Public License 19// along with this program; if not, write to the Free Software 20// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 21// MA 02110-1301, USA. 22 23#include "gold.h" 24 25#include <cerrno> 26#include <cstring> 27#include <fcntl.h> 28#include <unistd.h> 29 30#include "parameters.h" 31#include "gold-threads.h" 32#include "descriptors.h" 33 34namespace gold 35{ 36 37// Class Descriptors. 38 39// The default for limit_ is meant to simply be large. It gets 40// adjusted downward if we run out of file descriptors. 41 42Descriptors::Descriptors() 43 : lock_(NULL), open_descriptors_(), stack_top_(-1), current_(0), 44 limit_(8192 - 16) 45{ 46 this->open_descriptors_.reserve(128); 47} 48 49// Open a file. 50 51int 52Descriptors::open(int descriptor, const char* name, int flags, int mode) 53{ 54 // We don't initialize this until we are called, because we can't 55 // initialize a Lock until we have parsed the options to find out 56 // whether we are running with threads. We can be called before 57 // options are valid when reading a linker script. 58 if (this->lock_ == NULL) 59 { 60 if (parameters->options_valid()) 61 this->lock_ = new Lock(); 62 else 63 gold_assert(descriptor < 0); 64 } 65 66 if (descriptor >= 0) 67 { 68 Hold_lock hl(*this->lock_); 69 70 gold_assert(static_cast<size_t>(descriptor) 71 < this->open_descriptors_.size()); 72 Open_descriptor* pod = &this->open_descriptors_[descriptor]; 73 if (pod->name == name 74 || (pod->name != NULL && strcmp(pod->name, name) == 0)) 75 { 76 gold_assert(!pod->inuse); 77 pod->inuse = true; 78 return descriptor; 79 } 80 } 81 82 while (true) 83 { 84 int new_descriptor = ::open(name, flags, mode); 85 if (new_descriptor < 0 86 && errno != ENFILE 87 && errno != EMFILE) 88 { 89 if (descriptor >= 0 && errno == ENOENT) 90 { 91 { 92 Hold_lock hl(*this->lock_); 93 94 gold_error(_("file %s was removed during the link"), 95 this->open_descriptors_[descriptor].name); 96 } 97 98 errno = ENOENT; 99 } 100 101 return new_descriptor; 102 } 103 104 if (new_descriptor >= 0) 105 { 106 Hold_optional_lock hl(this->lock_); 107 108 if (static_cast<size_t>(new_descriptor) 109 >= this->open_descriptors_.size()) 110 this->open_descriptors_.resize(new_descriptor + 64); 111 112 Open_descriptor* pod = &this->open_descriptors_[new_descriptor]; 113 pod->name = name; 114 pod->stack_next = -1; 115 pod->inuse = true; 116 pod->is_write = (flags & O_ACCMODE) != O_RDONLY; 117 118 ++this->current_; 119 if (this->current_ >= this->limit_) 120 this->close_some_descriptor(); 121 122 return new_descriptor; 123 } 124 125 // We ran out of file descriptors. 126 { 127 Hold_optional_lock hl(this->lock_); 128 129 this->limit_ = this->current_ - 16; 130 if (this->limit_ < 8) 131 this->limit_ = 8; 132 if (!this->close_some_descriptor()) 133 gold_fatal(_("out of file descriptors and couldn't close any")); 134 } 135 } 136} 137 138// Release a descriptor. 139 140void 141Descriptors::release(int descriptor, bool permanent) 142{ 143 Hold_optional_lock hl(this->lock_); 144 145 gold_assert(descriptor >= 0 146 && (static_cast<size_t>(descriptor) 147 < this->open_descriptors_.size())); 148 Open_descriptor* pod = &this->open_descriptors_[descriptor]; 149 150 if (permanent 151 || (this->current_ > this->limit_ && !pod->is_write)) 152 { 153 if (::close(descriptor) < 0) 154 gold_warning(_("while closing %s: %s"), pod->name, strerror(errno)); 155 pod->name = NULL; 156 --this->current_; 157 } 158 else 159 { 160 pod->inuse = false; 161 if (!pod->is_write) 162 { 163 pod->stack_next = this->stack_top_; 164 this->stack_top_ = descriptor; 165 } 166 } 167} 168 169// Close some descriptor. The lock is held when this is called. We 170// close the descriptor on the top of the free stack. Note that this 171// is the opposite of an LRU algorithm--we close the most recently 172// used descriptor. That is because the linker tends to cycle through 173// all the files; after we release a file, we are unlikely to need it 174// again until we have looked at all the other files. Return true if 175// we closed a descriptor. 176 177bool 178Descriptors::close_some_descriptor() 179{ 180 int last = -1; 181 int i = this->stack_top_; 182 while (i >= 0) 183 { 184 gold_assert(static_cast<size_t>(i) < this->open_descriptors_.size()); 185 Open_descriptor* pod = &this->open_descriptors_[i]; 186 if (!pod->inuse && !pod->is_write) 187 { 188 if (::close(i) < 0) 189 gold_warning(_("while closing %s: %s"), pod->name, strerror(errno)); 190 --this->current_; 191 pod->name = NULL; 192 if (last < 0) 193 this->stack_top_ = pod->stack_next; 194 else 195 this->open_descriptors_[last].stack_next = pod->stack_next; 196 return true; 197 } 198 last = i; 199 i = pod->stack_next; 200 } 201 202 // We couldn't find any descriptors to close. This is weird but not 203 // necessarily an error. 204 return false; 205} 206 207// The single global variable which manages descriptors. 208 209Descriptors descriptors; 210 211} // End namespace gold. 212