]>
Commit | Line | Data |
---|---|---|
6724ff46 RP |
1 | /* BFD library -- caching of file descriptors. |
2 | Copyright (C) 1990-1991 Free Software Foundation, Inc. | |
3 | Hacked by Steve Chamberlain of Cygnus Support ([email protected]). | |
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 RP |
18 | along with this program; if not, write to the Free Software |
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | ||
21 | /*doc* | |
22 | @section File Caching | |
23 | The file caching mechanism is embedded within BFD and allows the application to open as many | |
24 | BFDs as it wants without regard to the underlying operating system's | |
25 | file descriptor limit (often as low as 20 open files). | |
26 | ||
27 | The module in @code{cache.c} maintains a least recently used list of | |
28 | @code{BFD_CACHE_MAX_OPEN} files, and exports the name | |
29 | @code{bfd_cache_lookup} which runs around and makes sure that the | |
30 | required BFD is open. If not, then it chooses a file to close, closes | |
31 | it and opens the one wanted, returning its file handle. | |
32 | ||
33 | */ | |
34 | ||
35 | ||
4a81b561 DHW |
36 | |
37 | /* $Id$ */ | |
6724ff46 | 38 | #include <sysdep.h> |
4a81b561 DHW |
39 | #include "bfd.h" |
40 | #include "libbfd.h" | |
41 | ||
6724ff46 RP |
42 | |
43 | /*proto-internal* BFD_CACHE_MAX_OPEN | |
44 | The maxiumum number of files which the cache will keep open at one | |
45 | time. | |
46 | *+ | |
4a81b561 | 47 | #define BFD_CACHE_MAX_OPEN 10 |
6724ff46 RP |
48 | *- |
49 | ||
50 | */ | |
51 | ||
4a81b561 | 52 | |
4a81b561 DHW |
53 | static int open_files; |
54 | ||
6724ff46 | 55 | static bfd *cache_sentinel; /* Chain of BFDs with active fds we've |
4a81b561 | 56 | opened */ |
4a81b561 | 57 | |
6724ff46 RP |
58 | /*proto-internal* bfd_last_cache |
59 | Zero, or a pointer to the topmost BFD on the chain. This is used by | |
60 | the @code{bfd_cache_lookup} macro in @file{libbfd.h} to determine when | |
61 | it can avoid a function call. | |
62 | *+ | |
63 | extern bfd *bfd_last_cache; | |
64 | *- | |
65 | ||
66 | */ | |
67 | ||
68 | bfd *bfd_last_cache; | |
69 | ||
70 | /*proto-internal* bfd_cache_lookup | |
71 | Checks to see if the required BFD is the same as the last one looked | |
72 | up. If so then it can use the iostream in the BFD with impunity, since | |
73 | it can't have changed since the last lookup, otherwise it has to | |
74 | perform the complicated lookup function | |
75 | *+ | |
76 | #define bfd_cache_lookup(x) \ | |
77 | ((x)==bfd_last_cache? \ | |
78 | (FILE*)(bfd_last_cache->iostream): \ | |
79 | bfd_cache_lookup_worker(x)) | |
80 | ||
81 | *- | |
82 | ||
83 | */ | |
fc723380 JG |
84 | |
85 | static void bfd_cache_delete(); | |
6724ff46 | 86 | |
4a81b561 DHW |
87 | |
88 | static void | |
9872a49c | 89 | DEFUN_VOID(close_one) |
4a81b561 DHW |
90 | { |
91 | bfd *kill = cache_sentinel; | |
92 | if (kill == 0) /* Nothing in the cache */ | |
93 | return ; | |
94 | ||
95 | /* We can only close files that want to play this game. */ | |
96 | while (!kill->cacheable) { | |
97 | kill = kill->lru_prev; | |
98 | if (kill == cache_sentinel) /* Nobody wants to play */ | |
99 | return ; | |
100 | } | |
101 | ||
102 | kill->where = ftell((FILE *)(kill->iostream)); | |
103 | bfd_cache_delete(kill); | |
4a81b561 | 104 | } |
fc723380 | 105 | |
6724ff46 | 106 | /* Cuts the BFD abfd out of the chain in the cache */ |
4a81b561 | 107 | static void |
9872a49c SC |
108 | DEFUN(snip,(abfd), |
109 | bfd *abfd) | |
4a81b561 DHW |
110 | { |
111 | abfd->lru_prev->lru_next = abfd->lru_next; | |
112 | abfd->lru_next->lru_prev = abfd->lru_prev; | |
113 | if (cache_sentinel == abfd) cache_sentinel = (bfd *)NULL; | |
114 | } | |
115 | ||
116 | static void | |
9872a49c SC |
117 | DEFUN(bfd_cache_delete,(abfd), |
118 | bfd *abfd) | |
4a81b561 DHW |
119 | { |
120 | fclose ((FILE *)(abfd->iostream)); | |
121 | snip (abfd); | |
122 | abfd->iostream = NULL; | |
123 | open_files--; | |
9872a49c | 124 | bfd_last_cache = 0; |
4a81b561 DHW |
125 | } |
126 | ||
127 | static bfd * | |
9872a49c SC |
128 | DEFUN(insert,(x,y), |
129 | bfd *x AND | |
130 | bfd *y) | |
4a81b561 DHW |
131 | { |
132 | if (y) { | |
133 | x->lru_next = y; | |
134 | x->lru_prev = y->lru_prev; | |
135 | y->lru_prev->lru_next = x; | |
136 | y->lru_prev = x; | |
137 | ||
138 | } | |
139 | else { | |
140 | x->lru_prev = x; | |
141 | x->lru_next = x; | |
142 | } | |
143 | return x; | |
144 | } | |
145 | \f | |
146 | ||
6724ff46 RP |
147 | /*proto-internal* |
148 | *i bfd_cache_init | |
149 | Initialize a BFD by putting it on the cache LRU. | |
150 | *; PROTO(void, bfd_cache_init, (bfd *)); | |
151 | *-*/ | |
152 | ||
4a81b561 | 153 | void |
9872a49c SC |
154 | DEFUN(bfd_cache_init,(abfd), |
155 | bfd *abfd) | |
4a81b561 DHW |
156 | { |
157 | cache_sentinel = insert(abfd, cache_sentinel); | |
158 | } | |
159 | ||
6724ff46 RP |
160 | |
161 | /*proto-internal* | |
162 | *i bfd_cache_close | |
163 | Remove the BFD from the cache. If the attatched file is open, then close it too. | |
164 | *; PROTO(void, bfd_cache_close, (bfd *)); | |
165 | *-*/ | |
4a81b561 | 166 | void |
9872a49c SC |
167 | DEFUN(bfd_cache_close,(abfd), |
168 | bfd *abfd) | |
4a81b561 DHW |
169 | { |
170 | /* If this file is open then remove from the chain */ | |
171 | if (abfd->iostream) | |
172 | { | |
173 | bfd_cache_delete(abfd); | |
174 | } | |
175 | } | |
4a81b561 | 176 | |
6724ff46 RP |
177 | /*proto-internal* |
178 | *i bfd_open_file | |
179 | Call the OS to open a file for this BFD. Returns the FILE * | |
180 | (possibly null) that results from this operation. Sets up the | |
181 | BFD so that future accesses know the file is open. If the FILE * | |
182 | returned is null, then there is won't have been put in the cache, so | |
183 | it won't have to be removed from it. | |
184 | *; PROTO(FILE *, bfd_open_file, (bfd *)); | |
185 | *-*/ | |
4a81b561 | 186 | FILE * |
9872a49c SC |
187 | DEFUN(bfd_open_file, (abfd), |
188 | bfd *abfd) | |
4a81b561 | 189 | { |
6724ff46 RP |
190 | abfd->cacheable = true; /* Allow it to be closed later. */ |
191 | if(open_files >= BFD_CACHE_MAX_OPEN) { | |
192 | close_one(); | |
193 | } | |
194 | switch (abfd->direction) { | |
195 | case read_direction: | |
196 | case no_direction: | |
197 | abfd->iostream = (char *) fopen(abfd->filename, "r"); | |
198 | break; | |
199 | case both_direction: | |
200 | case write_direction: | |
201 | if (abfd->opened_once == true) { | |
202 | abfd->iostream = (char *) fopen(abfd->filename, "r+"); | |
203 | if (!abfd->iostream) { | |
204 | abfd->iostream = (char *) fopen(abfd->filename, "w+"); | |
205 | } | |
206 | } else { | |
207 | /*open for creat */ | |
208 | abfd->iostream = (char *) fopen(abfd->filename, "w"); | |
209 | abfd->opened_once = true; | |
4a81b561 | 210 | } |
6724ff46 RP |
211 | break; |
212 | } | |
213 | if (abfd->iostream) { | |
214 | open_files++; | |
215 | bfd_cache_init (abfd); | |
216 | } | |
4a81b561 | 217 | |
6724ff46 | 218 | return (FILE *)(abfd->iostream); |
4a81b561 DHW |
219 | } |
220 | ||
6724ff46 RP |
221 | /*proto-internal* |
222 | *i bfd_cache_lookup_worker | |
223 | Called when the macro @code{bfd_cache_lookup} fails to find a quick | |
224 | answer. Finds a file descriptor for this BFD. If necessary, it open it. | |
225 | If there are already more than BFD_CACHE_MAX_OPEN files open, it trys to close | |
226 | one first, to avoid running out of file descriptors. | |
227 | *; PROTO(FILE *, bfd_cache_lookup_worker, (bfd *)); | |
228 | ||
229 | *-*/ | |
4a81b561 DHW |
230 | |
231 | FILE * | |
9872a49c SC |
232 | DEFUN(bfd_cache_lookup_worker,(abfd), |
233 | bfd *abfd) | |
4a81b561 DHW |
234 | { |
235 | if (abfd->my_archive) | |
9872a49c SC |
236 | { |
237 | abfd = abfd->my_archive; | |
238 | } | |
4a81b561 DHW |
239 | /* Is this file already open .. if so then quick exit */ |
240 | if (abfd->iostream) | |
9872a49c SC |
241 | { |
242 | if (abfd != cache_sentinel) { | |
243 | /* Place onto head of lru chain */ | |
244 | snip (abfd); | |
245 | cache_sentinel = insert(abfd, cache_sentinel); | |
246 | } | |
4a81b561 | 247 | } |
6724ff46 | 248 | /* This is a BFD without a stream - |
4a81b561 DHW |
249 | so it must have been closed or never opened. |
250 | find an empty cache entry and use it. */ | |
251 | else | |
9872a49c | 252 | { |
4a81b561 | 253 | |
9872a49c SC |
254 | if (open_files >= BFD_CACHE_MAX_OPEN) |
255 | { | |
256 | close_one(); | |
257 | } | |
4a81b561 | 258 | |
9872a49c SC |
259 | BFD_ASSERT(bfd_open_file (abfd) != (FILE *)NULL) ; |
260 | fseek((FILE *)(abfd->iostream), abfd->where, false); | |
261 | } | |
262 | bfd_last_cache = abfd; | |
4a81b561 DHW |
263 | return (FILE *)(abfd->iostream); |
264 | } |