OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [gold/] [descriptors.cc] - Blame information for rev 318

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 khays
// descriptors.cc -- manage file descriptors for gold
2
 
3
// Copyright 2008, 2009, 2010, 2011 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 <cstdio>
27
#include <cstring>
28
#include <fcntl.h>
29
#include <unistd.h>
30
 
31
#include "parameters.h"
32
#include "options.h"
33
#include "gold-threads.h"
34
#include "descriptors.h"
35
#include "binary-io.h"
36
 
37
// O_CLOEXEC is only available on newer systems.
38
#ifndef O_CLOEXEC
39
#define O_CLOEXEC 0
40
#endif
41
 
42
// Very old systems may not define FD_CLOEXEC.
43
#ifndef FD_CLOEXEC
44
#define FD_CLOEXEC 1
45
#endif
46
 
47
static inline void
48
set_close_on_exec(int fd)
49
{
50
// Mingw does not define F_SETFD.
51
#ifdef F_SETFD
52
  fcntl(fd, F_SETFD, FD_CLOEXEC);
53
#endif
54
}
55
 
56
namespace gold
57
{
58
 
59
// Class Descriptors.
60
 
61
// The default for limit_ is meant to simply be large.  It gets
62
// adjusted downward if we run out of file descriptors.
63
 
64
Descriptors::Descriptors()
65
  : lock_(NULL), initialize_lock_(&this->lock_), open_descriptors_(),
66
    stack_top_(-1), current_(0), limit_(8192 - 16)
67
{
68
  this->open_descriptors_.reserve(128);
69
}
70
 
71
// Open a file.
72
 
73
int
74
Descriptors::open(int descriptor, const char* name, int flags, int mode)
75
{
76
  // We don't initialize this until we are called, because we can't
77
  // initialize a Lock until we have parsed the options to find out
78
  // whether we are running with threads.  We can be called before
79
  // options are valid when reading a linker script.
80
  bool lock_initialized = this->initialize_lock_.initialize();
81
 
82
  gold_assert(lock_initialized || descriptor < 0);
83
 
84
  if (descriptor >= 0)
85
    {
86
      Hold_lock hl(*this->lock_);
87
 
88
      gold_assert(static_cast<size_t>(descriptor)
89
                  < this->open_descriptors_.size());
90
      Open_descriptor* pod = &this->open_descriptors_[descriptor];
91
      if (pod->name == name
92
          || (pod->name != NULL && strcmp(pod->name, name) == 0))
93
        {
94
          gold_assert(!pod->inuse);
95
          pod->inuse = true;
96
          if (descriptor == this->stack_top_)
97
            {
98
              this->stack_top_ = pod->stack_next;
99
              pod->stack_next = -1;
100
              pod->is_on_stack = false;
101
            }
102
          return descriptor;
103
        }
104
    }
105
 
106
  while (true)
107
    {
108
      // We always want to set the close-on-exec flag; we don't
109
      // require callers to pass it.
110
      flags |= O_CLOEXEC;
111
 
112
      // Always open the file as a binary file.
113
      flags |= O_BINARY;
114
 
115
      int new_descriptor = ::open(name, flags, mode);
116
      if (new_descriptor < 0
117
          && errno != ENFILE
118
          && errno != EMFILE)
119
        {
120
          if (descriptor >= 0 && errno == ENOENT)
121
            {
122
              {
123
                Hold_lock hl(*this->lock_);
124
 
125
                gold_error(_("file %s was removed during the link"), name);
126
              }
127
 
128
              errno = ENOENT;
129
            }
130
 
131
          return new_descriptor;
132
        }
133
 
134
      if (new_descriptor >= 0)
135
        {
136
          // If we have any plugins, we really do need to set the
137
          // close-on-exec flag, even if O_CLOEXEC is not defined.
138
          // FIXME: In some cases O_CLOEXEC may be defined in the
139
          // header file but not supported by the kernel.
140
          // Unfortunately there doesn't seem to be any obvious way to
141
          // detect that, as unknown flags passed to open are ignored.
142
          if (O_CLOEXEC == 0
143
              && parameters->options_valid()
144
              && parameters->options().has_plugins())
145
            set_close_on_exec(new_descriptor);
146
 
147
          {
148
            Hold_optional_lock hl(this->lock_);
149
 
150
            if (static_cast<size_t>(new_descriptor)
151
                >= this->open_descriptors_.size())
152
              this->open_descriptors_.resize(new_descriptor + 64);
153
 
154
            Open_descriptor* pod = &this->open_descriptors_[new_descriptor];
155
            pod->name = name;
156
            pod->stack_next = -1;
157
            pod->inuse = true;
158
            pod->is_write = (flags & O_ACCMODE) != O_RDONLY;
159
            pod->is_on_stack = false;
160
 
161
            ++this->current_;
162
            if (this->current_ >= this->limit_)
163
              this->close_some_descriptor();
164
 
165
            return new_descriptor;
166
          }
167
        }
168
 
169
      // We ran out of file descriptors.
170
      {
171
        Hold_optional_lock hl(this->lock_);
172
 
173
        this->limit_ = this->current_ - 16;
174
        if (this->limit_ < 8)
175
          this->limit_ = 8;
176
        if (!this->close_some_descriptor())
177
          gold_fatal(_("out of file descriptors and couldn't close any"));
178
      }
179
    }
180
}
181
 
182
// Release a descriptor.
183
 
184
void
185
Descriptors::release(int descriptor, bool permanent)
186
{
187
  Hold_optional_lock hl(this->lock_);
188
 
189
  gold_assert(descriptor >= 0
190
              && (static_cast<size_t>(descriptor)
191
                  < this->open_descriptors_.size()));
192
  Open_descriptor* pod = &this->open_descriptors_[descriptor];
193
 
194
  if (permanent
195
      || (this->current_ > this->limit_ && !pod->is_write))
196
    {
197
      if (::close(descriptor) < 0)
198
        gold_warning(_("while closing %s: %s"), pod->name, strerror(errno));
199
      pod->name = NULL;
200
      --this->current_;
201
    }
202
  else
203
    {
204
      pod->inuse = false;
205
      if (!pod->is_write && !pod->is_on_stack)
206
        {
207
          pod->stack_next = this->stack_top_;
208
          this->stack_top_ = descriptor;
209
          pod->is_on_stack = true;
210
        }
211
    }
212
}
213
 
214
// Close some descriptor.  The lock is held when this is called.  We
215
// close the descriptor on the top of the free stack.  Note that this
216
// is the opposite of an LRU algorithm--we close the most recently
217
// used descriptor.  That is because the linker tends to cycle through
218
// all the files; after we release a file, we are unlikely to need it
219
// again until we have looked at all the other files.  Return true if
220
// we closed a descriptor.
221
 
222
bool
223
Descriptors::close_some_descriptor()
224
{
225
  int last = -1;
226
  int i = this->stack_top_;
227
  while (i >= 0)
228
    {
229
      gold_assert(static_cast<size_t>(i) < this->open_descriptors_.size());
230
      Open_descriptor* pod = &this->open_descriptors_[i];
231
      if (!pod->inuse && !pod->is_write)
232
        {
233
          if (::close(i) < 0)
234
            gold_warning(_("while closing %s: %s"), pod->name, strerror(errno));
235
          --this->current_;
236
          pod->name = NULL;
237
          if (last < 0)
238
            this->stack_top_ = pod->stack_next;
239
          else
240
            this->open_descriptors_[last].stack_next = pod->stack_next;
241
          pod->stack_next = -1;
242
          pod->is_on_stack = false;
243
          return true;
244
        }
245
      last = i;
246
      i = pod->stack_next;
247
    }
248
 
249
  // We couldn't find any descriptors to close.  This is weird but not
250
  // necessarily an error.
251
  return false;
252
}
253
 
254
// The single global variable which manages descriptors.
255
 
256
Descriptors descriptors;
257
 
258
} // End namespace gold.

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.