1 /* BFD library -- caching of file descriptors.
2 Copyright (C) 1990-1991 Free Software Foundation, Inc.
5 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
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
46 BFD_CACHE_MAX_OPEN macro
49 The maxiumum number of files which the cache will keep open at
52 .#define BFD_CACHE_MAX_OPEN 10
57 static int open_files;
59 static bfd *cache_sentinel; /* Chain of BFDs with active fds we've
67 extern bfd *bfd_last_cache;
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.
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
87 * .#define bfd_cache_lookup(x) \
88 * . ((x)==bfd_last_cache? \
89 * . (FILE*)(bfd_last_cache->iostream): \
90 * . bfd_cache_lookup_worker(x))
95 static void bfd_cache_delete();
101 bfd *kill = cache_sentinel;
102 if (kill == 0) /* Nothing in the cache */
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 */
112 kill->where = ftell((FILE *)(kill->iostream));
113 bfd_cache_delete(kill);
116 /* Cuts the BFD abfd out of the chain in the cache */
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;
127 DEFUN(bfd_cache_delete,(abfd),
130 fclose ((FILE *)(abfd->iostream));
132 abfd->iostream = NULL;
144 x->lru_prev = y->lru_prev;
145 y->lru_prev->lru_next = x;
162 void bfd_cache_init (bfd *);
165 Initialize a BFD by putting it on the cache LRU.
169 DEFUN(bfd_cache_init,(abfd),
172 cache_sentinel = insert(abfd, cache_sentinel);
181 Remove the BFD from the cache. If the attached file is open,
185 void bfd_cache_close (bfd *);
188 DEFUN(bfd_cache_close,(abfd),
191 /* If this file is open then remove from the chain */
194 bfd_cache_delete(abfd);
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.
210 FILE* bfd_open_file(bfd *);
214 DEFUN(bfd_open_file, (abfd),
217 abfd->cacheable = true; /* Allow it to be closed later. */
218 if(open_files >= BFD_CACHE_MAX_OPEN) {
221 switch (abfd->direction) {
224 abfd->iostream = (char *) fopen(abfd->filename, "rb");
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");
235 abfd->iostream = (char *) fopen(abfd->filename, "wb");
236 abfd->opened_once = true;
240 if (abfd->iostream) {
242 bfd_cache_init (abfd);
245 return (FILE *)(abfd->iostream);
250 bfd_cache_lookup_worker
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.
260 FILE *bfd_cache_lookup_worker(bfd *);
265 DEFUN(bfd_cache_lookup_worker,(abfd),
268 if (abfd->my_archive)
270 abfd = abfd->my_archive;
272 /* Is this file already open .. if so then quick exit */
275 if (abfd != cache_sentinel) {
276 /* Place onto head of lru chain */
278 cache_sentinel = insert(abfd, cache_sentinel);
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. */
287 if (open_files >= BFD_CACHE_MAX_OPEN)
292 BFD_ASSERT(bfd_open_file (abfd) != (FILE *)NULL) ;
293 fseek((FILE *)(abfd->iostream), abfd->where, false);
295 bfd_last_cache = abfd;
296 return (FILE *)(abfd->iostream);