Fri Oct 23 13:55:35 1992 Ian Lance Taylor (ian@cygnus.com)
[external/binutils.git] / bfd / cache.c
1 /* BFD library -- caching of file descriptors.
2    Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
3    Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com).
4
5 This file is part of BFD, the Binary File Descriptor library.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
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
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 /*
22 SECTION
23         File Caching
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
31         <<bfd_cache_lookup>> which runs around and makes sure that
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. 
35
36 */
37
38 #include "bfd.h"
39 #include "sysdep.h"
40 #include "libbfd.h"
41
42 /*
43 INTERNAL_FUNCTION
44         BFD_CACHE_MAX_OPEN macro
45
46 DESCRIPTION
47         The maximum number of files which the cache will keep open at
48         one time.
49
50 .#define BFD_CACHE_MAX_OPEN 10
51
52 */
53
54
55 static int open_files;
56
57 static bfd *cache_sentinel;     /* Chain of BFDs with active fds we've
58                                    opened */
59
60 /*
61 INTERNAL_FUNCTION
62         bfd_last_cache
63
64 SYNOPSIS
65         extern bfd *bfd_last_cache;
66
67 DESCRIPTION
68         Zero, or a pointer to the topmost BFD on the chain.  This is
69         used by the <<bfd_cache_lookup>> macro in @file{libbfd.h} to
70         determine when it can avoid a function call.
71 */
72
73 bfd *bfd_last_cache;
74
75 /*
76  * INTERNAL_FUNCTION
77  *      bfd_cache_lookup
78  *
79  * DESCRIPTION
80  *      Checks to see if the required BFD is the same as the last one
81  *      looked up. If so then it can use the iostream in the BFD with
82  *      impunity, since it can't have changed since the last lookup,
83  *      otherwise it has to perform the complicated lookup function 
84  *
85  * .#define bfd_cache_lookup(x) \
86  * .    ((x)==bfd_last_cache? \
87  * .      (FILE*)(bfd_last_cache->iostream): \
88  * .       bfd_cache_lookup_worker(x))
89  *
90  *
91  */
92
93 static boolean EXFUN(bfd_cache_delete,(bfd *));
94
95
96 static void
97 DEFUN_VOID(close_one)
98 {
99     bfd *kill = cache_sentinel;
100     if (kill == 0)              /* Nothing in the cache */
101         return ;
102
103     /* We can only close files that want to play this game.  */
104     while (!kill->cacheable) {
105         kill = kill->lru_prev;
106         if (kill == cache_sentinel) /* Nobody wants to play */
107            return ;
108     }
109
110     kill->where = ftell((FILE *)(kill->iostream));
111     (void) bfd_cache_delete(kill);
112 }
113
114 /* Cuts the BFD abfd out of the chain in the cache */
115 static void 
116 DEFUN(snip,(abfd),
117       bfd *abfd)
118 {
119   abfd->lru_prev->lru_next = abfd->lru_next;
120   abfd->lru_next->lru_prev = abfd->lru_prev; 
121   if (cache_sentinel == abfd) cache_sentinel = (bfd *)NULL;
122 }
123
124 static boolean
125 DEFUN(bfd_cache_delete,(abfd),
126       bfd *abfd)
127 {
128   boolean ret;
129
130   if (fclose ((FILE *)(abfd->iostream)) == EOF)
131     ret = false;
132   else
133     ret = true;
134   snip (abfd);
135   abfd->iostream = NULL;
136   open_files--;
137   bfd_last_cache = 0;
138   return ret;
139 }
140   
141 static bfd *
142 DEFUN(insert,(x,y),
143       bfd *x AND
144       bfd *y)
145 {
146   if (y) {
147     x->lru_next = y;
148     x->lru_prev = y->lru_prev;
149     y->lru_prev->lru_next = x;
150     y->lru_prev = x;
151
152   }
153   else {
154     x->lru_prev = x;
155     x->lru_next = x;
156   }
157   return x;
158 }
159 \f
160
161 /*
162 INTERNAL_FUNCTION
163         bfd_cache_init
164
165 SYNOPSIS
166         void  bfd_cache_init (bfd *);
167
168 DESCRIPTION
169         Initialize a BFD by putting it on the cache LRU.
170 */
171
172 void
173 DEFUN(bfd_cache_init,(abfd),
174       bfd *abfd)
175 {
176   cache_sentinel = insert(abfd, cache_sentinel);
177 }
178
179
180 /*
181 INTERNAL_FUNCTION
182         bfd_cache_close
183
184 DESCRIPTION
185         Remove the BFD from the cache. If the attached file is open,
186         then close it too.
187
188 SYNOPSIS
189         boolean bfd_cache_close (bfd *);
190
191 RETURNS
192         <<false>> is returned if closing the file fails, <<true>> is
193         returned if all is well.
194 */
195 boolean
196 DEFUN(bfd_cache_close,(abfd),
197       bfd *abfd)
198 {
199   /* If this file is open then remove from the chain */
200   if (abfd->iostream) 
201     {
202       return bfd_cache_delete(abfd);
203     }
204   else
205     {
206       return true;
207     }
208 }
209
210 /*
211 INTERNAL_FUNCTION
212         bfd_open_file
213
214 DESCRIPTION
215         Call the OS to open a file for this BFD.  Returns the FILE *
216         (possibly null) that results from this operation.  Sets up the
217         BFD so that future accesses know the file is open. If the FILE
218         * returned is null, then there is won't have been put in the
219         cache, so it won't have to be removed from it.
220
221 SYNOPSIS
222         FILE* bfd_open_file(bfd *);
223 */
224
225 FILE *
226 DEFUN(bfd_open_file, (abfd),
227       bfd *abfd)
228 {
229   abfd->cacheable = true;       /* Allow it to be closed later. */
230
231   if(open_files >= BFD_CACHE_MAX_OPEN) {
232     close_one();
233   }
234
235   switch (abfd->direction) {
236   case read_direction:
237   case no_direction:
238     abfd->iostream = (char *) fopen(abfd->filename, FOPEN_RB);
239     break;
240   case both_direction:
241   case write_direction:
242     if (abfd->opened_once == true) {
243       abfd->iostream = (char *) fopen(abfd->filename, FOPEN_RUB);
244       if (!abfd->iostream) {
245         abfd->iostream = (char *) fopen(abfd->filename, FOPEN_WUB);
246       }
247     } else {
248       /*open for creat */
249       abfd->iostream = (char *) fopen(abfd->filename, FOPEN_WB);
250       abfd->opened_once = true;
251     }
252     break;
253   }
254
255   if (abfd->iostream) {
256     open_files++;
257     bfd_cache_init (abfd);
258   }
259
260   return (FILE *)(abfd->iostream);
261 }
262
263 /*
264 INTERNAL_FUNCTION
265         bfd_cache_lookup_worker
266
267 DESCRIPTION
268         Called when the macro <<bfd_cache_lookup>> fails to find a
269         quick answer. Finds a file descriptor for this BFD.  If
270         necessary, it open it. If there are already more than
271         BFD_CACHE_MAX_OPEN files open, it trys to close one first, to
272         avoid running out of file descriptors.  
273
274 SYNOPSIS
275         FILE *bfd_cache_lookup_worker(bfd *);
276
277 */
278
279 FILE *
280 DEFUN(bfd_cache_lookup_worker,(abfd),
281       bfd *abfd)
282 {
283   if (abfd->my_archive) 
284       {
285         abfd = abfd->my_archive;
286       }
287   /* Is this file already open .. if so then quick exit */
288   if (abfd->iostream) 
289       {
290         if (abfd != cache_sentinel) {
291           /* Place onto head of lru chain */
292           snip (abfd);
293           cache_sentinel = insert(abfd, cache_sentinel);
294         }
295       }
296   /* This is a BFD without a stream -
297      so it must have been closed or never opened.
298      find an empty cache entry and use it.  */
299   else 
300       {
301
302         if (open_files >= BFD_CACHE_MAX_OPEN) 
303             {
304               close_one();
305             }
306
307         BFD_ASSERT(bfd_open_file (abfd) != (FILE *)NULL) ;
308         fseek((FILE *)(abfd->iostream), abfd->where, false);
309       }
310   bfd_last_cache = abfd;
311   return (FILE *)(abfd->iostream);
312 }