1 /* BFD library -- caching of file descriptors.
2 Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
3 Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com).
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
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
*));
49 BFD_CACHE_MAX_OPEN macro
52 The maximum number of files which the cache will keep open at
55 .#define BFD_CACHE_MAX_OPEN 10
59 /* The number of BFD files we have open. */
61 static int open_files
;
68 extern bfd *bfd_last_cache;
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.
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.
88 .#define bfd_cache_lookup(x) \
89 . ((x)==bfd_last_cache? \
90 . (FILE*)(bfd_last_cache->iostream): \
91 . bfd_cache_lookup_worker(x))
96 /* Insert a BFD into the cache. */
102 if (bfd_last_cache
== NULL
)
104 abfd
->lru_next
= abfd
;
105 abfd
->lru_prev
= abfd
;
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
;
114 bfd_last_cache
= abfd
;
117 /* Remove a BFD from the cache. */
123 abfd
->lru_prev
->lru_next
= abfd
->lru_next
;
124 abfd
->lru_next
->lru_prev
= abfd
->lru_prev
;
125 if (abfd
== bfd_last_cache
)
127 bfd_last_cache
= abfd
->lru_next
;
128 if (abfd
== bfd_last_cache
)
129 bfd_last_cache
= NULL
;
133 /* We need to open a new file, and the cache is full. Find the least
134 recently used cacheable BFD and close it. */
141 if (bfd_last_cache
== NULL
)
145 for (kill
= bfd_last_cache
->lru_prev
;
147 kill
= kill
->lru_prev
)
149 if (kill
== bfd_last_cache
)
159 /* There are no open cacheable BFD's. */
163 kill
->where
= ftell ((FILE *) kill
->iostream
);
165 return bfd_cache_delete (kill
);
168 /* Close a BFD and remove it from the cache. */
171 bfd_cache_delete (abfd
)
176 if (fclose ((FILE *) abfd
->iostream
) == 0)
181 bfd_set_error (bfd_error_system_call
);
186 abfd
->iostream
= NULL
;
197 boolean bfd_cache_init (bfd *abfd);
200 Add a newly opened BFD to the cache.
204 bfd_cache_init (abfd
)
207 BFD_ASSERT (abfd
->iostream
!= NULL
);
208 if (open_files
>= BFD_CACHE_MAX_OPEN
)
223 boolean bfd_cache_close (bfd *abfd);
226 Remove the BFD @var{abfd} from the cache. If the attached file is open,
230 <<false>> is returned if closing the file fails, <<true>> is
231 returned if all is well.
235 bfd_cache_close (abfd
)
238 if (abfd
->iostream
== NULL
239 || (abfd
->flags
& BFD_IN_MEMORY
) != 0)
242 return bfd_cache_delete (abfd
);
250 FILE* bfd_open_file(bfd *abfd);
253 Call the OS to open a file for @var{abfd}. Return the <<FILE *>>
254 (possibly <<NULL>>) that results from this operation. Set up the
255 BFD so that future accesses know the file is open. If the <<FILE *>>
256 returned is <<NULL>>, then it won't have been put in the
257 cache, so it won't have to be removed from it.
264 abfd
->cacheable
= true; /* Allow it to be closed later. */
266 if (open_files
>= BFD_CACHE_MAX_OPEN
)
272 switch (abfd
->direction
)
276 abfd
->iostream
= (PTR
) fopen (abfd
->filename
, FOPEN_RB
);
279 case write_direction
:
280 if (abfd
->opened_once
== true)
282 abfd
->iostream
= (PTR
) fopen (abfd
->filename
, FOPEN_RUB
);
283 if (abfd
->iostream
== NULL
)
284 abfd
->iostream
= (PTR
) fopen (abfd
->filename
, FOPEN_WUB
);
288 /* Create the file. Unlink it first, for the convenience of
289 operating systems which worry about overwriting running
291 unlink (abfd
->filename
);
292 abfd
->iostream
= (PTR
) fopen (abfd
->filename
, FOPEN_WB
);
293 abfd
->opened_once
= true;
298 if (abfd
->iostream
!= NULL
)
300 if (! bfd_cache_init (abfd
))
304 return (FILE *) abfd
->iostream
;
309 bfd_cache_lookup_worker
312 FILE *bfd_cache_lookup_worker(bfd *abfd);
315 Called when the macro <<bfd_cache_lookup>> fails to find a
316 quick answer. Find a file descriptor for @var{abfd}. If
317 necessary, it open it. If there are already more than
318 <<BFD_CACHE_MAX_OPEN>> files open, it tries to close one first, to
319 avoid running out of file descriptors.
323 bfd_cache_lookup_worker (abfd
)
326 if ((abfd
->flags
& BFD_IN_MEMORY
) != 0)
329 if (abfd
->my_archive
)
330 abfd
= abfd
->my_archive
;
332 if (abfd
->iostream
!= NULL
)
334 /* Move the file to the start of the cache. */
335 if (abfd
!= bfd_last_cache
)
343 if (bfd_open_file (abfd
) == NULL
)
345 if (fseek ((FILE *) abfd
->iostream
, abfd
->where
, SEEK_SET
) != 0)
349 return (FILE *) abfd
->iostream
;