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