X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Fcache.c;h=4e5ef2e3b4036b831352953fcd477a0757be4941;hb=2c73f9d86113b392342ec5a8cff8a42be78bd429;hp=fbd46bf9b2f5903d8f3ae55c9f409547aeb8b1bc;hpb=700b2ee3ef5cc4e03f905681cf549f43938ddf50;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/cache.c b/bfd/cache.c index fbd46bf9b2..4e5ef2e3b4 100644 --- a/bfd/cache.c +++ b/bfd/cache.c @@ -1,5 +1,6 @@ /* BFD library -- caching of file descriptors. - Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Copyright 1990, 1991, 1992, 1993, 1994, 1996, 2000, 2001 + Free Software Foundation, Inc. Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com). This file is part of BFD, the Binary File Descriptor library. @@ -16,11 +17,11 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* SECTION - File Caching + File caching The file caching mechanism is embedded within BFD and allows the application to open as many BFDs as it wants without @@ -28,10 +29,10 @@ SECTION limit (often as low as 20 open files). The module in <> maintains a least recently used list of <> files, and exports the name - <> which runs around and makes sure that + <>, which runs around and makes sure that the required BFD is open. If not, then it chooses a file to close, closes it and opens the one wanted, returning its file - handle. + handle. */ @@ -39,6 +40,11 @@ SECTION #include "sysdep.h" #include "libbfd.h" +static void insert PARAMS ((bfd *)); +static void snip PARAMS ((bfd *)); +static boolean close_one PARAMS ((void)); +static boolean bfd_cache_delete PARAMS ((bfd *)); + /* INTERNAL_FUNCTION BFD_CACHE_MAX_OPEN macro @@ -51,12 +57,10 @@ DESCRIPTION */ +/* The number of BFD files we have open. */ static int open_files; -static bfd *cache_sentinel; /* Chain of BFDs with active fds we've - opened */ - /* INTERNAL_FUNCTION bfd_last_cache @@ -73,240 +77,298 @@ DESCRIPTION bfd *bfd_last_cache; /* - * INTERNAL_FUNCTION - * bfd_cache_lookup - * - * DESCRIPTION - * Checks to see if the required BFD is the same as the last one - * looked up. If so then it can use the iostream in the BFD with - * impunity, since it can't have changed since the last lookup, - * otherwise it has to perform the complicated lookup function - * - * .#define bfd_cache_lookup(x) \ - * . ((x)==bfd_last_cache? \ - * . (FILE*)(bfd_last_cache->iostream): \ - * . bfd_cache_lookup_worker(x)) - * - * - */ + INTERNAL_FUNCTION + bfd_cache_lookup -static boolean EXFUN(bfd_cache_delete,(bfd *)); + DESCRIPTION + Check to see if the required BFD is the same as the last one + looked up. If so, then it can use the stream in the BFD with + impunity, since it can't have changed since the last lookup; + otherwise, it has to perform the complicated lookup function. + + .#define bfd_cache_lookup(x) \ + . ((x)==bfd_last_cache? \ + . (FILE*) (bfd_last_cache->iostream): \ + . bfd_cache_lookup_worker(x)) + + */ +/* Insert a BFD into the cache. */ -static void -DEFUN_VOID(close_one) +static INLINE void +insert (abfd) + bfd *abfd; { - bfd *kill = cache_sentinel; - if (kill == 0) /* Nothing in the cache */ - return ; - - /* We can only close files that want to play this game. */ - while (!kill->cacheable) { - kill = kill->lru_prev; - if (kill == cache_sentinel) /* Nobody wants to play */ - return ; + if (bfd_last_cache == NULL) + { + abfd->lru_next = abfd; + abfd->lru_prev = abfd; } - - kill->where = ftell((FILE *)(kill->iostream)); - (void) bfd_cache_delete(kill); + else + { + abfd->lru_next = bfd_last_cache; + abfd->lru_prev = bfd_last_cache->lru_prev; + abfd->lru_prev->lru_next = abfd; + abfd->lru_next->lru_prev = abfd; + } + bfd_last_cache = abfd; } -/* Cuts the BFD abfd out of the chain in the cache */ -static void -DEFUN(snip,(abfd), - bfd *abfd) +/* Remove a BFD from the cache. */ + +static INLINE void +snip (abfd) + bfd *abfd; { abfd->lru_prev->lru_next = abfd->lru_next; - abfd->lru_next->lru_prev = abfd->lru_prev; - if (cache_sentinel == abfd) cache_sentinel = (bfd *)NULL; + abfd->lru_next->lru_prev = abfd->lru_prev; + if (abfd == bfd_last_cache) + { + bfd_last_cache = abfd->lru_next; + if (abfd == bfd_last_cache) + bfd_last_cache = NULL; + } } +/* We need to open a new file, and the cache is full. Find the least + recently used cacheable BFD and close it. */ + static boolean -DEFUN(bfd_cache_delete,(abfd), - bfd *abfd) +close_one () { - boolean ret; + register bfd *kill; - if (fclose ((FILE *)(abfd->iostream)) == EOF) - ret = false; + if (bfd_last_cache == NULL) + kill = NULL; else + { + for (kill = bfd_last_cache->lru_prev; + ! kill->cacheable; + kill = kill->lru_prev) + { + if (kill == bfd_last_cache) + { + kill = NULL; + break; + } + } + } + + if (kill == NULL) + { + /* There are no open cacheable BFD's. */ + return true; + } + + kill->where = ftell ((FILE *) kill->iostream); + + return bfd_cache_delete (kill); +} + +/* Close a BFD and remove it from the cache. */ + +static boolean +bfd_cache_delete (abfd) + bfd *abfd; +{ + boolean ret; + + if (fclose ((FILE *) abfd->iostream) == 0) ret = true; + else + { + ret = false; + bfd_set_error (bfd_error_system_call); + } + snip (abfd); + abfd->iostream = NULL; - open_files--; - bfd_last_cache = 0; + --open_files; + return ret; } - -static bfd * -DEFUN(insert,(x,y), - bfd *x AND - bfd *y) -{ - if (y) { - x->lru_next = y; - x->lru_prev = y->lru_prev; - y->lru_prev->lru_next = x; - y->lru_prev = x; - - } - else { - x->lru_prev = x; - x->lru_next = x; - } - return x; -} - /* INTERNAL_FUNCTION bfd_cache_init SYNOPSIS - void bfd_cache_init (bfd *); + boolean bfd_cache_init (bfd *abfd); DESCRIPTION - Initialize a BFD by putting it on the cache LRU. + Add a newly opened BFD to the cache. */ -void -DEFUN(bfd_cache_init,(abfd), - bfd *abfd) +boolean +bfd_cache_init (abfd) + bfd *abfd; { - cache_sentinel = insert(abfd, cache_sentinel); + BFD_ASSERT (abfd->iostream != NULL); + if (open_files >= BFD_CACHE_MAX_OPEN) + { + if (! close_one ()) + return false; + } + insert (abfd); + ++open_files; + return true; } - /* INTERNAL_FUNCTION bfd_cache_close +SYNOPSIS + boolean bfd_cache_close (bfd *abfd); + DESCRIPTION - Remove the BFD from the cache. If the attached file is open, + Remove the BFD @var{abfd} from the cache. If the attached file is open, then close it too. -SYNOPSIS - boolean bfd_cache_close (bfd *); - RETURNS <> is returned if closing the file fails, <> is returned if all is well. */ + boolean -DEFUN(bfd_cache_close,(abfd), - bfd *abfd) +bfd_cache_close (abfd) + bfd *abfd; { - /* If this file is open then remove from the chain */ - if (abfd->iostream) - { - return bfd_cache_delete(abfd); - } - else - { - return true; - } + if (abfd->iostream == NULL + || (abfd->flags & BFD_IN_MEMORY) != 0) + return true; + + return bfd_cache_delete (abfd); } /* INTERNAL_FUNCTION bfd_open_file +SYNOPSIS + FILE* bfd_open_file(bfd *abfd); + DESCRIPTION - Call the OS to open a file for this BFD. Returns the FILE * - (possibly null) that results from this operation. Sets up the - BFD so that future accesses know the file is open. If the FILE - * returned is null, then there is won't have been put in the + Call the OS to open a file for @var{abfd}. Return the <> + (possibly <>) that results from this operation. Set up the + BFD so that future accesses know the file is open. If the <> + returned is <>, then it won't have been put in the cache, so it won't have to be removed from it. - -SYNOPSIS - FILE* bfd_open_file(bfd *); */ FILE * -DEFUN(bfd_open_file, (abfd), - bfd *abfd) +bfd_open_file (abfd) + bfd *abfd; { - abfd->cacheable = true; /* Allow it to be closed later. */ - - if(open_files >= BFD_CACHE_MAX_OPEN) { - close_one(); - } - - switch (abfd->direction) { - case read_direction: - case no_direction: - abfd->iostream = (char *) fopen(abfd->filename, FOPEN_RB); - break; - case both_direction: - case write_direction: - if (abfd->opened_once == true) { - abfd->iostream = (char *) fopen(abfd->filename, FOPEN_RUB); - if (!abfd->iostream) { - abfd->iostream = (char *) fopen(abfd->filename, FOPEN_WUB); - } - } else { - /*open for creat */ - abfd->iostream = (char *) fopen(abfd->filename, FOPEN_WB); - abfd->opened_once = true; + abfd->cacheable = true; /* Allow it to be closed later. */ + + if (open_files >= BFD_CACHE_MAX_OPEN) + { + if (! close_one ()) + return NULL; } - break; - } - if (abfd->iostream) { - open_files++; - bfd_cache_init (abfd); - } + switch (abfd->direction) + { + case read_direction: + case no_direction: + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_RB); + break; + case both_direction: + case write_direction: + if (abfd->opened_once == true) + { + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_RUB); + if (abfd->iostream == NULL) + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_WUB); + } + else + { + /* Create the file. + + Some operating systems won't let us overwrite a running + binary. For them, we want to unlink the file first. + + However, gcc 2.95 will create temporary files using + O_EXCL and tight permissions to prevent other users from + substituting other .o files during the compilation. gcc + will then tell the assembler to use the newly created + file as an output file. If we unlink the file here, we + open a brief window when another user could still + substitute a file. + + So we unlink the output file if and only if it has + non-zero size. */ +#ifndef __MSDOS__ + /* Don't do this for MSDOS: it doesn't care about overwriting + a running binary, but if this file is already open by + another BFD, we will be in deep trouble if we delete an + open file. In fact, objdump does just that if invoked with + the --info option. */ + struct stat s; + + if (stat (abfd->filename, &s) == 0 && s.st_size != 0) + unlink (abfd->filename); +#endif + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_WUB); + abfd->opened_once = true; + } + break; + } + + if (abfd->iostream != NULL) + { + if (! bfd_cache_init (abfd)) + return NULL; + } - return (FILE *)(abfd->iostream); + return (FILE *) abfd->iostream; } /* INTERNAL_FUNCTION bfd_cache_lookup_worker -DESCRIPTION - Called when the macro <> fails to find a - quick answer. Finds a file descriptor for this BFD. If - necessary, it open it. If there are already more than - BFD_CACHE_MAX_OPEN files open, it trys to close one first, to - avoid running out of file descriptors. - SYNOPSIS - FILE *bfd_cache_lookup_worker(bfd *); + FILE *bfd_cache_lookup_worker(bfd *abfd); +DESCRIPTION + Called when the macro <> fails to find a + quick answer. Find a file descriptor for @var{abfd}. If + necessary, it open it. If there are already more than + <> files open, it tries to close one first, to + avoid running out of file descriptors. */ FILE * -DEFUN(bfd_cache_lookup_worker,(abfd), - bfd *abfd) +bfd_cache_lookup_worker (abfd) + bfd *abfd; { - if (abfd->my_archive) - { - abfd = abfd->my_archive; - } - /* Is this file already open .. if so then quick exit */ - if (abfd->iostream) - { - if (abfd != cache_sentinel) { - /* Place onto head of lru chain */ + if ((abfd->flags & BFD_IN_MEMORY) != 0) + abort (); + + if (abfd->my_archive) + abfd = abfd->my_archive; + + if (abfd->iostream != NULL) + { + /* Move the file to the start of the cache. */ + if (abfd != bfd_last_cache) + { snip (abfd); - cache_sentinel = insert(abfd, cache_sentinel); + insert (abfd); } - } - /* This is a BFD without a stream - - so it must have been closed or never opened. - find an empty cache entry and use it. */ - else - { - - if (open_files >= BFD_CACHE_MAX_OPEN) - { - close_one(); - } + } + else + { + if (bfd_open_file (abfd) == NULL) + return NULL; + if (abfd->where != (unsigned long) abfd->where) + return NULL; + if (fseek ((FILE *) abfd->iostream, (long) abfd->where, SEEK_SET) != 0) + return NULL; + } - BFD_ASSERT(bfd_open_file (abfd) != (FILE *)NULL) ; - fseek((FILE *)(abfd->iostream), abfd->where, false); - } - bfd_last_cache = abfd; - return (FILE *)(abfd->iostream); + return (FILE *) abfd->iostream; }