Commit | Line | Data |
---|---|---|
6724ff46 | 1 | /* BFD library -- caching of file descriptors. |
64d5f5d0 | 2 | Copyright 1990, 1991, 1992, 1994 Free Software Foundation, Inc. |
6724ff46 | 3 | Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com). |
4a81b561 | 4 | |
6724ff46 | 5 | This file is part of BFD, the Binary File Descriptor library. |
4a81b561 | 6 | |
6724ff46 | 7 | This program is free software; you can redistribute it and/or modify |
4a81b561 | 8 | it under the terms of the GNU General Public License as published by |
6724ff46 RP |
9 | the Free Software Foundation; either version 2 of the License, or |
10 | (at your option) any later version. | |
4a81b561 | 11 | |
6724ff46 | 12 | This program is distributed in the hope that it will be useful, |
4a81b561 DHW |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
6724ff46 | 18 | along with this program; if not, write to the Free Software |
64d5f5d0 | 19 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
6724ff46 | 20 | |
b645b632 SC |
21 | /* |
22 | SECTION | |
c188b0be | 23 | File caching |
b645b632 SC |
24 | |
25 | The file caching mechanism is embedded within BFD and allows | |
26 | the application to open as many BFDs as it wants without | |
27 | regard to the underlying operating system's file descriptor | |
28 | limit (often as low as 20 open files). The module in | |
29 | <<cache.c>> maintains a least recently used list of | |
30 | <<BFD_CACHE_MAX_OPEN>> files, and exports the name | |
c188b0be | 31 | <<bfd_cache_lookup>>, which runs around and makes sure that |
b645b632 SC |
32 | the required BFD is open. If not, then it chooses a file to |
33 | close, closes it and opens the one wanted, returning its file | |
34 | handle. | |
6724ff46 RP |
35 | |
36 | */ | |
37 | ||
4a81b561 | 38 | #include "bfd.h" |
b645b632 | 39 | #include "sysdep.h" |
4a81b561 DHW |
40 | #include "libbfd.h" |
41 | ||
64d5f5d0 ILT |
42 | static void insert PARAMS ((bfd *)); |
43 | static void snip PARAMS ((bfd *)); | |
44 | static boolean close_one PARAMS ((void)); | |
45 | static boolean bfd_cache_delete PARAMS ((bfd *)); | |
46 | ||
b645b632 SC |
47 | /* |
48 | INTERNAL_FUNCTION | |
49 | BFD_CACHE_MAX_OPEN macro | |
6724ff46 | 50 | |
b645b632 | 51 | DESCRIPTION |
700b2ee3 | 52 | The maximum number of files which the cache will keep open at |
b645b632 SC |
53 | one time. |
54 | ||
55 | .#define BFD_CACHE_MAX_OPEN 10 | |
6724ff46 RP |
56 | |
57 | */ | |
58 | ||
64d5f5d0 | 59 | /* The number of BFD files we have open. */ |
c188b0be | 60 | |
4a81b561 DHW |
61 | static int open_files; |
62 | ||
b645b632 SC |
63 | /* |
64 | INTERNAL_FUNCTION | |
65 | bfd_last_cache | |
66 | ||
67 | SYNOPSIS | |
68 | extern bfd *bfd_last_cache; | |
6724ff46 | 69 | |
b645b632 SC |
70 | DESCRIPTION |
71 | Zero, or a pointer to the topmost BFD on the chain. This is | |
72 | used by the <<bfd_cache_lookup>> macro in @file{libbfd.h} to | |
73 | determine when it can avoid a function call. | |
6724ff46 RP |
74 | */ |
75 | ||
76 | bfd *bfd_last_cache; | |
77 | ||
b645b632 | 78 | /* |
c188b0be DM |
79 | INTERNAL_FUNCTION |
80 | bfd_cache_lookup | |
81 | ||
82 | DESCRIPTION | |
83 | Check to see if the required BFD is the same as the last one | |
84 | looked up. If so, then it can use the stream in the BFD with | |
85 | impunity, since it can't have changed since the last lookup; | |
86 | otherwise, it has to perform the complicated lookup function. | |
87 | ||
88 | .#define bfd_cache_lookup(x) \ | |
89 | . ((x)==bfd_last_cache? \ | |
90 | . (FILE*)(bfd_last_cache->iostream): \ | |
91 | . bfd_cache_lookup_worker(x)) | |
92 | ||
93 | ||
b645b632 | 94 | */ |
fc723380 | 95 | |
64d5f5d0 ILT |
96 | /* Insert a BFD into the cache. */ |
97 | ||
98 | static INLINE void | |
99 | insert (abfd) | |
100 | bfd *abfd; | |
4a81b561 | 101 | { |
64d5f5d0 ILT |
102 | if (bfd_last_cache == NULL) |
103 | { | |
104 | abfd->lru_next = abfd; | |
105 | abfd->lru_prev = abfd; | |
4a81b561 | 106 | } |
64d5f5d0 ILT |
107 | else |
108 | { | |
109 | abfd->lru_next = bfd_last_cache; | |
110 | abfd->lru_prev = bfd_last_cache->lru_prev; | |
111 | abfd->lru_prev->lru_next = abfd; | |
112 | abfd->lru_next->lru_prev = abfd; | |
113 | } | |
114 | bfd_last_cache = abfd; | |
4a81b561 | 115 | } |
fc723380 | 116 | |
64d5f5d0 ILT |
117 | /* Remove a BFD from the cache. */ |
118 | ||
119 | static INLINE void | |
120 | snip (abfd) | |
121 | bfd *abfd; | |
4a81b561 DHW |
122 | { |
123 | abfd->lru_prev->lru_next = abfd->lru_next; | |
64d5f5d0 ILT |
124 | abfd->lru_next->lru_prev = abfd->lru_prev; |
125 | if (abfd == bfd_last_cache) | |
126 | { | |
127 | bfd_last_cache = abfd->lru_next; | |
128 | if (abfd == bfd_last_cache) | |
129 | bfd_last_cache = NULL; | |
130 | } | |
4a81b561 DHW |
131 | } |
132 | ||
64d5f5d0 ILT |
133 | /* We need to open a new file, and the cache is full. Find the least |
134 | recently used cacheable BFD and close it. */ | |
135 | ||
700b2ee3 | 136 | static boolean |
64d5f5d0 ILT |
137 | close_one () |
138 | { | |
139 | register bfd *kill; | |
140 | ||
141 | if (bfd_last_cache == NULL) | |
142 | kill = NULL; | |
143 | else | |
144 | { | |
145 | for (kill = bfd_last_cache->lru_prev; | |
146 | ! kill->cacheable; | |
147 | kill = kill->lru_prev) | |
148 | { | |
149 | if (kill == bfd_last_cache) | |
150 | { | |
151 | kill = NULL; | |
152 | break; | |
153 | } | |
154 | } | |
155 | } | |
156 | ||
157 | if (kill == NULL) | |
158 | { | |
159 | /* There are no open cacheable BFD's. */ | |
160 | return true; | |
161 | } | |
162 | ||
163 | kill->where = ftell ((FILE *) kill->iostream); | |
164 | ||
165 | return bfd_cache_delete (kill); | |
166 | } | |
167 | ||
168 | /* Close a BFD and remove it from the cache. */ | |
169 | ||
170 | static boolean | |
171 | bfd_cache_delete (abfd) | |
172 | bfd *abfd; | |
4a81b561 | 173 | { |
700b2ee3 ILT |
174 | boolean ret; |
175 | ||
64d5f5d0 | 176 | if (fclose ((FILE *) abfd->iostream) == 0) |
700b2ee3 | 177 | ret = true; |
09141f8d ILT |
178 | else |
179 | { | |
180 | ret = false; | |
2f88343d | 181 | bfd_set_error (bfd_error_system_call); |
09141f8d | 182 | } |
64d5f5d0 | 183 | |
4a81b561 | 184 | snip (abfd); |
64d5f5d0 | 185 | |
4a81b561 | 186 | abfd->iostream = NULL; |
64d5f5d0 ILT |
187 | --open_files; |
188 | ||
700b2ee3 | 189 | return ret; |
4a81b561 | 190 | } |
4a81b561 | 191 | |
64d5f5d0 ILT |
192 | /* |
193 | INTERNAL_FUNCTION | |
194 | bfd_cache_init | |
195 | ||
196 | SYNOPSIS | |
197 | boolean bfd_cache_init (bfd *abfd); | |
198 | ||
199 | DESCRIPTION | |
200 | Add a newly opened BFD to the cache. | |
201 | */ | |
6724ff46 | 202 | |
64d5f5d0 ILT |
203 | boolean |
204 | bfd_cache_init (abfd) | |
205 | bfd *abfd; | |
4a81b561 | 206 | { |
64d5f5d0 | 207 | BFD_ASSERT (abfd->iostream != NULL); |
c188b0be | 208 | if (open_files >= BFD_CACHE_MAX_OPEN) |
64d5f5d0 ILT |
209 | { |
210 | if (! close_one ()) | |
211 | return false; | |
212 | } | |
213 | insert (abfd); | |
c188b0be | 214 | ++open_files; |
64d5f5d0 | 215 | return true; |
4a81b561 DHW |
216 | } |
217 | ||
b645b632 SC |
218 | /* |
219 | INTERNAL_FUNCTION | |
220 | bfd_cache_close | |
221 | ||
c188b0be DM |
222 | SYNOPSIS |
223 | boolean bfd_cache_close (bfd *abfd); | |
224 | ||
b645b632 | 225 | DESCRIPTION |
c188b0be | 226 | Remove the BFD @var{abfd} from the cache. If the attached file is open, |
b645b632 SC |
227 | then close it too. |
228 | ||
700b2ee3 ILT |
229 | RETURNS |
230 | <<false>> is returned if closing the file fails, <<true>> is | |
231 | returned if all is well. | |
b645b632 | 232 | */ |
64d5f5d0 | 233 | |
700b2ee3 | 234 | boolean |
64d5f5d0 ILT |
235 | bfd_cache_close (abfd) |
236 | bfd *abfd; | |
4a81b561 | 237 | { |
64d5f5d0 ILT |
238 | if (abfd->iostream == NULL |
239 | || (abfd->flags & BFD_IN_MEMORY) != 0) | |
240 | return true; | |
241 | ||
242 | return bfd_cache_delete (abfd); | |
4a81b561 | 243 | } |
4a81b561 | 244 | |
b645b632 SC |
245 | /* |
246 | INTERNAL_FUNCTION | |
247 | bfd_open_file | |
248 | ||
c188b0be DM |
249 | SYNOPSIS |
250 | FILE* bfd_open_file(bfd *abfd); | |
251 | ||
b645b632 | 252 | DESCRIPTION |
c188b0be | 253 | Call the OS to open a file for @var{abfd}. Return the <<FILE *>> |
2f88343d | 254 | (possibly <<NULL>>) that results from this operation. Set up the |
c188b0be | 255 | BFD so that future accesses know the file is open. If the <<FILE *>> |
2f88343d | 256 | returned is <<NULL>>, then it won't have been put in the |
b645b632 | 257 | cache, so it won't have to be removed from it. |
b645b632 SC |
258 | */ |
259 | ||
4a81b561 | 260 | FILE * |
64d5f5d0 ILT |
261 | bfd_open_file (abfd) |
262 | bfd *abfd; | |
4a81b561 | 263 | { |
6724ff46 | 264 | abfd->cacheable = true; /* Allow it to be closed later. */ |
8b046402 | 265 | |
64d5f5d0 ILT |
266 | if (open_files >= BFD_CACHE_MAX_OPEN) |
267 | { | |
268 | if (! close_one ()) | |
269 | return NULL; | |
270 | } | |
271 | ||
272 | switch (abfd->direction) | |
273 | { | |
274 | case read_direction: | |
275 | case no_direction: | |
276 | abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_RB); | |
277 | break; | |
278 | case both_direction: | |
279 | case write_direction: | |
280 | if (abfd->opened_once == true) | |
281 | { | |
282 | abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_RUB); | |
283 | if (abfd->iostream == NULL) | |
284 | abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_WUB); | |
285 | } | |
286 | else | |
287 | { | |
288 | /*open for creat */ | |
289 | abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_WB); | |
290 | abfd->opened_once = true; | |
291 | } | |
292 | break; | |
4a81b561 | 293 | } |
8b046402 | 294 | |
64d5f5d0 ILT |
295 | if (abfd->iostream != NULL) |
296 | { | |
297 | if (! bfd_cache_init (abfd)) | |
298 | return NULL; | |
299 | } | |
4a81b561 | 300 | |
64d5f5d0 | 301 | return (FILE *) abfd->iostream; |
4a81b561 DHW |
302 | } |
303 | ||
b645b632 SC |
304 | /* |
305 | INTERNAL_FUNCTION | |
306 | bfd_cache_lookup_worker | |
307 | ||
c188b0be DM |
308 | SYNOPSIS |
309 | FILE *bfd_cache_lookup_worker(bfd *abfd); | |
310 | ||
b645b632 SC |
311 | DESCRIPTION |
312 | Called when the macro <<bfd_cache_lookup>> fails to find a | |
c188b0be DM |
313 | quick answer. Find a file descriptor for @var{abfd}. If |
314 | necessary, it open it. If there are already more than | |
315 | <<BFD_CACHE_MAX_OPEN>> files open, it tries to close one first, to | |
b645b632 | 316 | avoid running out of file descriptors. |
b645b632 | 317 | */ |
4a81b561 DHW |
318 | |
319 | FILE * | |
64d5f5d0 ILT |
320 | bfd_cache_lookup_worker (abfd) |
321 | bfd *abfd; | |
4a81b561 | 322 | { |
64d5f5d0 ILT |
323 | if ((abfd->flags & BFD_IN_MEMORY) != 0) |
324 | abort (); | |
325 | ||
4a81b561 | 326 | if (abfd->my_archive) |
64d5f5d0 ILT |
327 | abfd = abfd->my_archive; |
328 | ||
329 | if (abfd->iostream != NULL) | |
330 | { | |
331 | /* Move the file to the start of the cache. */ | |
332 | if (abfd != bfd_last_cache) | |
333 | { | |
9872a49c | 334 | snip (abfd); |
64d5f5d0 | 335 | insert (abfd); |
9872a49c | 336 | } |
64d5f5d0 ILT |
337 | } |
338 | else | |
339 | { | |
340 | if (bfd_open_file (abfd) == NULL) | |
341 | return NULL; | |
342 | if (fseek ((FILE *) abfd->iostream, abfd->where, SEEK_SET) != 0) | |
343 | return NULL; | |
344 | } | |
4a81b561 | 345 | |
64d5f5d0 | 346 | return (FILE *) abfd->iostream; |
4a81b561 | 347 | } |