From 45eca4d141c047950db48c69c8941163d0a61fcd Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sun, 7 May 2000 21:23:56 +0000 Subject: Update. 2000-05-06 Bruno Haible * iconv/gconv_open.c (__gconv_open): If __gconv_find_transform returned != __GCONV_OK, there is nothing to clean up. 2000-05-06 Bruno Haible * intl/tst-gettext.c (main): Disable possibly existing LC_CTYPE and OUTPUT_CHARSET environment variables. 2000-05-06 Andreas Jaeger * sysdeps/generic/dl-cache.h (struct file_entry_new): New. (struct cache_file_new): New. (struct file_entry): New (moved from cache.c). (struct cache_file): New (moved from cache.c). * sysdeps/generic/dl-cache.c (SEARCH_CACHE): New macro, broken out from _dl_load_cache_lookup. (_dl_load_cache_lookup): Move search to SEARCH_CACHE macro, handle the different cache formats. New variable cache_new for new format. * elf/ldconfig.h: Change according to changes in cache.c and ldconfig.c; remove cache_libcmp; add opt_format. * elf/ldconfig.c: Include "dl-cache.h" and "dl-procinfo.h"; remove stuff that's defined in those headers. Add hwcap to struct lib_entry. (opt_format): New variable to select cache format. (options): Add format parameter. (is_hwcap): New function. (path_hwcap): New function. (parse_opt): Handle new format parameter. (search_dir): Handle hwcap, search also subdirectories with hwcap. * elf/cache.c (_GNU_SOURCE): Removed. Not needed anymore since ldconfig is part of glibc. Include dl-cache.h and remove stuff that's defined there. (struct cache_entry): Add new member hwcap. (print_entry): Print hwcap, cleanup a bit. (print_cache): Print new and old formats. (compare): Use _dl_cache_libcmp from dl-cache.h; handle hwcap. (save_cache): Save new and old formats. (add_to_cache): Handle hwcap. * sysdeps/generic/dl-cache.c (_dl_cache_libcmp): Moved from here... * sysdeps/generic/dl-cache.h (_dl_cache_libcmp): ...to here. * sysdeps/generic/dl-cache.c (LD_SO_CACHE): Moved from here... * sysdeps/generic/dl-cache.h (LD_SO_CACHE): ...to here. * sysdeps/generic/dl-cache.c (CACHEMAGIC): Moved from here... * sysdeps/generic/dl-cache.h (CACHEMAGIC): ...to here. 2000-05-05 Bruno Haible * intl/dcigettext.c (alignof): New macro. (_nl_find_msg): Use it instead of __alignof__. Pass correct output buffer length to __gconv/iconv. If malloc (freemem_size) fails, set freemem_size to 0. 2000-05-05 Bruno Haible * intl/dcigettext.c (dcigettext): Fix interpretation of tsearch return value. --- ChangeLog | 65 +++++++++++ elf/cache.c | 277 ++++++++++++++++++++++++++++---------------- elf/ldconfig.c | 150 ++++++++++++++++++------ elf/ldconfig.h | 11 +- iconv/gconv_open.c | 28 ++--- intl/dcigettext.c | 36 ++++-- intl/tst-gettext.c | 2 + linuxthreads/Examples/ex7.c | 40 +++++++ linuxthreads/Makefile | 3 +- linuxthreads/internals.h | 2 +- linuxthreads/join.c | 8 +- linuxthreads/manager.c | 34 +++++- sysdeps/generic/dl-cache.c | 275 +++++++++++++++++++++---------------------- sysdeps/generic/dl-cache.h | 100 +++++++++++++++- 14 files changed, 721 insertions(+), 310 deletions(-) create mode 100644 linuxthreads/Examples/ex7.c diff --git a/ChangeLog b/ChangeLog index 9332cba808..04787bb705 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,68 @@ +2000-05-06 Bruno Haible + + * iconv/gconv_open.c (__gconv_open): If __gconv_find_transform + returned != __GCONV_OK, there is nothing to clean up. + +2000-05-06 Bruno Haible + + * intl/tst-gettext.c (main): Disable possibly existing LC_CTYPE and + OUTPUT_CHARSET environment variables. + +2000-05-06 Andreas Jaeger + + * sysdeps/generic/dl-cache.h (struct file_entry_new): New. + (struct cache_file_new): New. + (struct file_entry): New (moved from cache.c). + (struct cache_file): New (moved from cache.c). + + * sysdeps/generic/dl-cache.c (SEARCH_CACHE): New macro, broken out + from _dl_load_cache_lookup. + (_dl_load_cache_lookup): Move search to SEARCH_CACHE macro, handle + the different cache formats. + New variable cache_new for new format. + + * elf/ldconfig.h: Change according to changes in cache.c and + ldconfig.c; remove cache_libcmp; add opt_format. + + * elf/ldconfig.c: Include "dl-cache.h" and "dl-procinfo.h"; remove + stuff that's defined in those headers. + Add hwcap to struct lib_entry. + (opt_format): New variable to select cache format. + (options): Add format parameter. + (is_hwcap): New function. + (path_hwcap): New function. + (parse_opt): Handle new format parameter. + (search_dir): Handle hwcap, search also subdirectories with hwcap. + + * elf/cache.c (_GNU_SOURCE): Removed. Not needed anymore since + ldconfig is part of glibc. + Include dl-cache.h and remove stuff that's defined there. + (struct cache_entry): Add new member hwcap. + (print_entry): Print hwcap, cleanup a bit. + (print_cache): Print new and old formats. + (compare): Use _dl_cache_libcmp from dl-cache.h; handle hwcap. + (save_cache): Save new and old formats. + (add_to_cache): Handle hwcap. + + * sysdeps/generic/dl-cache.c (_dl_cache_libcmp): Moved from here... + * sysdeps/generic/dl-cache.h (_dl_cache_libcmp): ...to here. + * sysdeps/generic/dl-cache.c (LD_SO_CACHE): Moved from here... + * sysdeps/generic/dl-cache.h (LD_SO_CACHE): ...to here. + * sysdeps/generic/dl-cache.c (CACHEMAGIC): Moved from here... + * sysdeps/generic/dl-cache.h (CACHEMAGIC): ...to here. + +2000-05-05 Bruno Haible + + * intl/dcigettext.c (alignof): New macro. + (_nl_find_msg): Use it instead of __alignof__. Pass correct output + buffer length to __gconv/iconv. If malloc (freemem_size) fails, set + freemem_size to 0. + +2000-05-05 Bruno Haible + + * intl/dcigettext.c (dcigettext): Fix interpretation of tsearch + return value. + 2000-05-06 Ulrich Drepper * intl/dcigettext.c (DCIGETTEXT): Always define local variable `index'. diff --git a/elf/cache.c b/elf/cache.c index cc75704f54..fbbc426268 100644 --- a/elf/cache.c +++ b/elf/cache.c @@ -17,9 +17,6 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#define _GNU_SOURCE 1 - -#include #include #include #include @@ -34,32 +31,18 @@ #include #include "ldconfig.h" - -#define CACHEMAGIC "ld.so-1.7.0" +#include "dl-cache.h" struct cache_entry { - char *lib; - char *path; - int flags; - struct cache_entry *next; + char *lib; /* Library name. */ + char *path; /* Path to find library. */ + int flags; /* Flags to indicate kind of library. */ + unsigned long int hwcap; /* Important hardware capabilities. */ + int bits_hwcap; /* Number of bits set in hwcap. */ + struct cache_entry *next; /* Next entry in list. */ }; -struct file_entry -{ - int flags; /* This is 1 for an ELF library. */ - unsigned int key, value; /* String table indices. */ -}; - - -struct cache_file -{ - char magic[sizeof CACHEMAGIC - 1]; - unsigned int nlibs; - struct file_entry libs[0]; -}; - - /* List of all cache entries. */ static struct cache_entry *entries; @@ -69,7 +52,7 @@ static const char *flag_descr[] = /* Print a single entry. */ static void -print_entry (const char *lib, int flag, const char *key) +print_entry (const char *lib, int flag, unsigned long int hwcap, const char *key) { printf ("\t%s (", lib); switch (flag & FLAG_TYPE_MASK) @@ -93,14 +76,17 @@ print_entry (const char *lib, int flag, const char *key) case 0: break; default: - fprintf (stdout, ",%d", flag & FLAG_REQUIRED_MASK); + printf (",%d", flag & FLAG_REQUIRED_MASK); break; } + if (hwcap != 0) + printf (", hwcap: 0x%lx", hwcap); printf (") => %s\n", key); } -/* Print the whole cache file. */ +/* Print the whole cache file, if a file contains the new cache format + hidden in the old one, print the contents of the new format. */ void print_cache (const char *cache_name) { @@ -109,7 +95,9 @@ print_cache (const char *cache_name) int fd; unsigned int i; struct cache_file *cache; + struct cache_file_new *cache_new = NULL; const char *cache_data; + int format = 0; fd = open (cache_name, O_RDONLY); if (fd < 0) @@ -128,20 +116,63 @@ print_cache (const char *cache_name) error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n")); cache_size = st.st_size; - if (cache_size < sizeof (struct cache_file) - || memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1)) - return; - /* This is where the strings start. */ - cache_data = (const char *) &cache->libs[cache->nlibs]; + if (cache_size < sizeof (struct cache_file)) + error (EXIT_FAILURE, 0, _("File is not a cache file.\n")); + + if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1)) + { + /* This can only be the new format without the old one. */ + cache_new = (struct cache_file_new *) cache; + + if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1) + || memcmp (cache_new->version, CACHE_VERSION, + sizeof CACHE_VERSION - 1)) + error (EXIT_FAILURE, 0, _("File is not a cache file.\n")); + format = 1; + /* This is where the strings start. */ + cache_data = (const char *) cache; + } + else + { + /* This is where the strings start. */ + cache_data = (const char *) &cache->libs[cache->nlibs]; + + /* Check for a new cache embedded in the old format. */ + if (cache_size > + (sizeof (struct cache_file) + + cache->nlibs * sizeof (struct file_entry) + + sizeof (struct cache_file_new))) + { + cache_new = (struct cache_file_new *) cache_data; - printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name); + if (!memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1) + && !memcmp (cache_new->version, CACHE_VERSION, + sizeof CACHE_VERSION - 1)) + format = 1; + } + } - /* Print everything. */ - for (i = 0; i < cache->nlibs; i++) - print_entry (cache_data + cache->libs[i].key, - cache->libs[i].flags, - cache_data + cache->libs[i].value); + if (format == 0) + { + printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name); + /* Print everything. */ + for (i = 0; i < cache->nlibs; i++) + print_entry (cache_data + cache->libs[i].key, + cache->libs[i].flags, 0, + cache_data + cache->libs[i].value); + } + else if (format == 1) + { + printf (_("%d libs found in cache `%s'\n"), cache_new->nlibs, cache_name); + + /* Print everything. */ + for (i = 0; i < cache_new->nlibs; i++) + print_entry (cache_data + cache_new->libs[i].key, + cache_new->libs[i].flags, + cache_new->libs[i].hwcap, + cache_data + cache_new->libs[i].value); + } /* Cleanup. */ munmap (cache, cache_size); close (fd); @@ -155,45 +186,6 @@ init_cache (void) } -/* Helper function which must match the one in the dynamic linker, so that - we rely on the same sort order. */ -int -cache_libcmp (const char *p1, const char *p2) -{ - while (*p1 != '\0') - { - if (*p1 >= '0' && *p1 <= '9') - { - if (*p2 >= '0' && *p2 <= '9') - { - /* Must compare this numerically. */ - int val1; - int val2; - - val1 = *p1++ - '0'; - val2 = *p2++ - '0'; - while (*p1 >= '0' && *p1 <= '9') - val1 = val1 * 10 + *p1++ - '0'; - while (*p2 >= '0' && *p2 <= '9') - val2 = val2 * 10 + *p2++ - '0'; - if (val1 != val2) - return val1 - val2; - } - else - return 1; - } - else if (*p2 >= '0' && *p2 <= '9') - return -1; - else if (*p1 != *p2) - return *p1 - *p2; - else - { - ++p1; - ++p2; - } - } - return *p1 - *p2; -} static int compare (const struct cache_entry *e1, const struct cache_entry *e2) @@ -201,80 +193,142 @@ int compare (const struct cache_entry *e1, const struct cache_entry *e2) int res; /* We need to swap entries here to get the correct sort order. */ - res = cache_libcmp (e2->lib, e1->lib); + res = _dl_cache_libcmp (e2->lib, e1->lib); if (res == 0) { if (e1->flags < e2->flags) return 1; else if (e1->flags > e2->flags) return -1; + /* Sort by most specific hwcap. */ + else if (e2->bits_hwcap > e1->bits_hwcap) + return 1; + else if (e2->bits_hwcap < e1->bits_hwcap) + return -1; + else if (e2->hwcap > e1->hwcap) + return 1; + else if (e2->hwcap < e1->hwcap) + return -1; } return res; } - /* Save the contents of the cache. */ void save_cache (const char *cache_name) { struct cache_entry *entry; - int i, fd; + int fd, idx_old, idx_new; size_t total_strlen, len; char *strings, *str, *temp_name; - struct cache_file *file_entries; - size_t file_entries_size; + struct cache_file *file_entries = NULL; + struct cache_file_new *file_entries_new = NULL; + size_t file_entries_size = 0; + size_t file_entries_new_size = 0; unsigned int str_offset; /* Number of cache entries. */ int cache_entry_count = 0; + /* Number of normal cache entries. */ + int cache_entry_old_count = 0; /* The cache entries are sorted already, save them in this order. */ /* Count the length of all strings. */ + /* The old format doesn't contain hwcap entries and doesn't contain + libraries in subdirectories with hwcaps entries. Count therefore + also all entries with hwcap == 0. */ total_strlen = 0; for (entry = entries; entry != NULL; entry = entry->next) { /* Account the final NULs. */ total_strlen += strlen (entry->lib) + strlen (entry->path) + 2; ++cache_entry_count; + if (entry->hwcap == 0) + ++cache_entry_old_count; } /* Create the on disk cache structure. */ /* First an array for all strings. */ - strings = (char *)xmalloc (total_strlen + 1); + strings = (char *)xmalloc (total_strlen); - /* And the list of all entries. */ - file_entries_size = sizeof (struct cache_file) - + cache_entry_count * sizeof (struct file_entry); - file_entries = (struct cache_file *) xmalloc (file_entries_size); + if (opt_format != 2) + { + /* And the list of all entries in the old format. */ + file_entries_size = sizeof (struct cache_file) + + cache_entry_old_count * sizeof (struct file_entry); + file_entries = (struct cache_file *) xmalloc (file_entries_size); + + /* Fill in the header. */ + memset (file_entries, 0, sizeof (struct cache_file)); + memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1); - /* Fill in the header. */ - memset (file_entries, 0, sizeof (struct cache_file)); - memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1); + file_entries->nlibs = cache_entry_old_count; + } - file_entries->nlibs = cache_entry_count; + if (opt_format != 0) + { + /* And the list of all entries in the new format. */ + file_entries_new_size = sizeof (struct cache_file_new) + + cache_entry_count * sizeof (struct file_entry_new); + file_entries_new = (struct cache_file_new *) xmalloc (file_entries_new_size); + + /* Fill in the header. */ + memset (file_entries_new, 0, sizeof (struct cache_file_new)); + memcpy (file_entries_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1); + memcpy (file_entries_new->version, CACHE_VERSION, sizeof CACHE_VERSION - 1); + + file_entries_new->nlibs = cache_entry_count; + file_entries_new->len_strings = total_strlen; + } + + /* If we have both formats, we hide the new format in the strings + table, we have to adjust all string indices for this so that + old libc5/glibc 2 dynamic linkers just ignore them. */ + if (opt_format == 1) + str_offset = file_entries_new_size; + else + str_offset = 0; - str_offset = 0; str = strings; - for (i = 0, entry = entries; entry != NULL; entry = entry->next, ++i) + for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL; + entry = entry->next, ++idx_new) { - file_entries->libs[i].flags = entry->flags; /* First the library. */ - /* XXX: Actually we can optimize here and remove duplicates. */ - file_entries->libs[i].key = str_offset; + if (opt_format != 2) + { + file_entries->libs[idx_old].flags = entry->flags; + /* XXX: Actually we can optimize here and remove duplicates. */ + file_entries->libs[idx_old].key = str_offset; + } + if (opt_format != 0) + { + /* We could subtract file_entries_new_size from str_offset - + not doing so makes the code easier, the string table + always begins at the beginning of the the new cache + struct. */ + file_entries_new->libs[idx_new].flags = entry->flags; + file_entries_new->libs[idx_new].hwcap = entry->hwcap; + file_entries_new->libs[idx_new].key = str_offset; + } len = strlen (entry->lib); str = stpcpy (str, entry->lib); /* Account the final NUL. */ ++str; str_offset += len + 1; /* Then the path. */ - file_entries->libs[i].value = str_offset; + if (opt_format != 2) + file_entries->libs[idx_old].value = str_offset; + if (opt_format != 0) + file_entries_new->libs[idx_new].value = str_offset; len = strlen (entry->path); str = stpcpy (str, entry->path); /* Account the final NUL. */ ++str; str_offset += len + 1; + /* Ignore entries with hwcap for old format. */ + if (entry->hwcap == 0) + ++idx_old; } - assert (str_offset == total_strlen); /* Write out the cache. */ @@ -293,8 +347,17 @@ save_cache (const char *cache_name) temp_name); /* Write contents. */ - if (write (fd, file_entries, file_entries_size) != (ssize_t)file_entries_size) - error (EXIT_FAILURE, errno, _("Writing of cache data failed")); + if (opt_format != 2) + { + if (write (fd, file_entries, file_entries_size) != (ssize_t)file_entries_size) + error (EXIT_FAILURE, errno, _("Writing of cache data failed")); + } + if (opt_format != 0) + { + if (write (fd, file_entries_new, file_entries_new_size) + != (ssize_t)file_entries_new_size) + error (EXIT_FAILURE, errno, _("Writing of cache data failed")); + } if (write (fd, strings, total_strlen) != (ssize_t)total_strlen) error (EXIT_FAILURE, errno, _("Writing of cache data failed.")); @@ -325,13 +388,15 @@ save_cache (const char *cache_name) } } + /* Add one library to the cache. */ void -add_to_cache (const char *path, const char *lib, int flags) +add_to_cache (const char *path, const char *lib, int flags, + unsigned long int hwcap) { struct cache_entry *new_entry, *ptr, *prev; char *full_path; - int len; + int len, i; new_entry = (struct cache_entry *) xmalloc (sizeof (struct cache_entry)); @@ -343,6 +408,14 @@ add_to_cache (const char *path, const char *lib, int flags) new_entry->lib = xstrdup (lib); new_entry->path = full_path; new_entry->flags = flags; + new_entry->hwcap = hwcap; + new_entry->bits_hwcap = 0; + + /* Count the number of bits set in the masked value. */ + for (i = 0; (~((1UL << i) - 1) & hwcap) != 0; ++i) + if ((hwcap & (1UL << i)) != 0) + ++new_entry->bits_hwcap; + /* Keep the list sorted - search for right place to insert. */ ptr = entries; diff --git a/elf/ldconfig.c b/elf/ldconfig.c index 98a4817202..ff96682c79 100644 --- a/elf/ldconfig.c +++ b/elf/ldconfig.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1999 Free Software Foundation, Inc. +/* Copyright (C) 1999, 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Andreas Jaeger , 1999. @@ -32,10 +32,12 @@ #include #include "ldconfig.h" +#include "dl-cache.h" -#ifndef LD_SO_CACHE -# define LD_SO_CACHE "/etc/ld.so.cache" -#endif +/* We don't need this here - silence the compiler. */ +#define _dl_sysdep_message(string, args...) do {} while (0); + +#include "dl-procinfo.h" #ifndef LD_SO_CONF # define LD_SO_CONF "/etc/ld.so.conf" @@ -49,6 +51,7 @@ struct lib_entry { int flags; + unsigned long int hwcap; char *lib; char *path; }; @@ -63,7 +66,7 @@ static const struct {"libc5", FLAG_ELF_LIBC5}, {"libc6", FLAG_ELF_LIBC6}, {"glibc2", FLAG_ELF_LIBC6} -}; +}; /* List of directories to handle. */ @@ -85,6 +88,10 @@ static int opt_print_cache = 0; /* Be verbose. */ int opt_verbose = 0; +/* Format to support. */ +/* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */ +int opt_format = 1; + /* Build cache. */ static int opt_build_cache = 1; @@ -123,6 +130,7 @@ static const struct argp_option options[] = { NULL, 'f', "CONF", 0, N_("Use CONF as configuration file"), 0}, { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0}, { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0}, + { "format", 'c', "FORMAT", 0, N_("Format to use: new, old or compat (default)"), 0}, { NULL, 0, NULL, 0, NULL, 0 } }; @@ -138,7 +146,53 @@ static struct argp argp = options, parse_opt, NULL, doc, NULL, NULL, NULL }; +/* Check if string corresponds to an important hardware capability. */ +static int +is_hwcap (const char *name) +{ + int hwcap_idx = _dl_string_hwcap (name); + + if (hwcap_idx != -1 && ((1 << hwcap_idx) & HWCAP_IMPORTANT)) + return 1; + return 0; +} + +/* Get hwcap encoding of path. */ +static unsigned long int +path_hwcap (const char *path) +{ + char *str = xstrdup (path); + char *ptr; + unsigned long int hwcap = 0; + unsigned long int h; + + size_t len; + + len = strlen (str); + if (str[len] == '/') + str[len] = '\0'; + + /* Search pathname from the end and check for hwcap strings. */ + for (;;) + { + ptr = strrchr (str, '/'); + + if (ptr == NULL) + break; + + h = _dl_string_hwcap (ptr+1); + + if (h == -1) + break; + hwcap += 1 << h; + /* Search the next part of the path. */ + *ptr = '\0'; + } + + free (str); + return hwcap; +} /* Handle program arguments. */ static error_t @@ -174,6 +228,14 @@ parse_opt (int key, char *arg, struct argp_state *state) case 'X': opt_link = 0; break; + case 'c': + if (strcmp (arg, "old") == 0) + opt_format = 0; + else if (strcmp (arg, "compat") == 0) + opt_format = 1; + else if (strcmp (arg, "new") == 0) + opt_format = 2; + break; default: return ARGP_ERR_UNKNOWN; } @@ -190,7 +252,7 @@ print_version (FILE *stream, struct argp_state *state) Copyright (C) %s Free Software Foundation, Inc.\n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ -"), "1999"); +"), "2000"); fprintf (stream, gettext ("Written by %s.\n"), "Andreas Jaeger"); } @@ -202,10 +264,10 @@ add_dir (const char *line) char *equal_sign; struct dir_entry *entry, *ptr, *prev; unsigned int i; - + entry = xmalloc (sizeof (struct dir_entry)); entry->next = NULL; - + /* Search for an '=' sign. */ entry->path = xstrdup (line); equal_sign = strchr (entry->path, '='); @@ -235,7 +297,7 @@ add_dir (const char *line) entry->path [i] = '\0'; --i; } - + ptr = dir_entries; prev = ptr; while (ptr != NULL) @@ -270,7 +332,7 @@ create_links (const char *path, const char *libname, const char *soname) int do_link = 1; int do_remove = 1; /* XXX: The logics in this function should be simplified. */ - + /* Get complete path. */ snprintf (full_libname, sizeof full_libname, "%s/%s", path, libname); snprintf (full_soname, sizeof full_soname, "%s/%s", path, soname); @@ -405,7 +467,7 @@ manual_link (char *library) - create symbolic links to the soname for each library This has to be done separatly for each directory. - + To keep track of which libraries to add to the cache and which links to create, we save a list of all libraries. @@ -416,7 +478,7 @@ manual_link (char *library) if new library is newer, replace entry otherwise ignore this library otherwise add library to list - + For example, if the two libraries libxy.so.1.1 and libxy.so.1.2 exist and both have the same soname, e.g. libxy.so, a symbolic link is created from libxy.so.1.2 (the newer one) to libxy.so. @@ -424,7 +486,7 @@ manual_link (char *library) libxy.so.1.1. */ /* Information for one library. */ -struct dlib_entry +struct dlib_entry { char *name; char *soname; @@ -446,12 +508,18 @@ search_dir (const struct dir_entry *entry) int nchars; struct stat stat_buf; int is_link; - + unsigned long int hwcap = path_hwcap (entry->path); + dlibs = NULL; if (opt_verbose) - printf ("%s:\n", entry->path); - + { + if (hwcap != 0) + printf ("%s: (hwcap: 0x%lx)\n", entry->path, hwcap); + else + printf ("%s:\n", entry->path); + } + dir = opendir (entry->path); if (dir == NULL) { @@ -459,7 +527,7 @@ search_dir (const struct dir_entry *entry) error (0, errno, _("Can't open directory %s"), entry->path); return; } - + while ((direntry = readdir (dir)) != NULL) { @@ -468,15 +536,17 @@ search_dir (const struct dir_entry *entry) /* We only look at links and regular files. */ if (direntry->d_type != DT_UNKNOWN && direntry->d_type != DT_LNK - && direntry->d_type != DT_REG) + && direntry->d_type != DT_REG + && direntry->d_type != DT_DIR) continue; #endif /* _DIRENT_HAVE_D_TYPE */ - - /* Does this file look like a shared library? The dynamic - linker is also considered as shared library. */ - if ((strncmp (direntry->d_name, "lib", 3) != 0 - && strncmp (direntry->d_name, "ld-", 3) != 0) - || strstr (direntry->d_name, ".so") == NULL) + /* Does this file look like a shared library or is it a hwcap + subdirectory? The dynamic linker is also considered as + shared library. */ + if (((strncmp (direntry->d_name, "lib", 3) != 0 + && strncmp (direntry->d_name, "ld-", 3) != 0) + || strstr (direntry->d_name, ".so") == NULL) + && !is_hwcap (direntry->d_name)) continue; nchars = snprintf (buf, sizeof (buf), "%s/%s", entry->path, direntry->d_name); @@ -492,6 +562,16 @@ search_dir (const struct dir_entry *entry) error (0, errno, _("Can't lstat %s"), buf); continue; } + else if (S_ISDIR (stat_buf.st_mode) && is_hwcap (direntry->d_name)) + { + /* Handle subdirectory also, make a recursive call. */ + struct dir_entry new_entry; + new_entry.path = buf; + new_entry.flag = entry->flag; + new_entry.next = NULL; + search_dir (&new_entry); + continue; + } else if (!S_ISREG (stat_buf.st_mode) && !S_ISLNK (stat_buf.st_mode)) continue; @@ -506,7 +586,7 @@ search_dir (const struct dir_entry *entry) free (soname); soname = xstrdup (direntry->d_name); } - + if (flag == FLAG_ELF && (entry->flag == FLAG_ELF_LIBC5 || entry->flag == FLAG_ELF_LIBC6)) @@ -524,7 +604,7 @@ search_dir (const struct dir_entry *entry) && entry->flag != FLAG_ANY) error (0, 0, _("libc4 library %s in wrong directory"), buf); } - + /* Add library to list. */ for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next) { @@ -535,7 +615,7 @@ search_dir (const struct dir_entry *entry) is newer. */ if ((!is_link && dlib_ptr->is_link) || (is_link == dlib_ptr->is_link - && cache_libcmp (dlib_ptr->name, direntry->d_name) < 0)) + && _dl_cache_libcmp (dlib_ptr->name, direntry->d_name) < 0)) { /* It's newer - add it. */ /* Flag should be the same - sanity check. */ @@ -586,11 +666,11 @@ search_dir (const struct dir_entry *entry) if (dlib_ptr->is_link == 0) create_links (entry->path, dlib_ptr->name, dlib_ptr->soname); if (opt_build_cache) - add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag); + add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag, hwcap); } /* Free all resources. */ - while (dlibs) + while (dlibs) { dlib_ptr = dlibs; free (dlib_ptr->soname); @@ -627,7 +707,7 @@ parse_conf (const char *filename) FILE *file; char *line = NULL; size_t len = 0; - + file = fopen (filename, "r"); if (file == NULL) @@ -667,7 +747,7 @@ int main (int argc, char **argv) { int remaining; - + /* Parse and process arguments. */ argp_parse (&argp, argc, argv, 0, &remaining, NULL); @@ -685,7 +765,7 @@ main (int argc, char **argv) if (config_file == NULL) config_file = LD_SO_CONF; - + /* Chroot first. */ if (opt_chroot) { @@ -713,8 +793,8 @@ main (int argc, char **argv) exit (0); } - - + + if (opt_build_cache) init_cache (); @@ -726,7 +806,7 @@ main (int argc, char **argv) parse_conf (config_file); } - + search_dirs (); if (opt_build_cache) diff --git a/elf/ldconfig.h b/elf/ldconfig.h index 9e40714c05..ecdbb14883 100644 --- a/elf/ldconfig.h +++ b/elf/ldconfig.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1999 Free Software Foundation, Inc. +/* Copyright (C) 1999, 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Andreas Jaeger , 1999. @@ -37,10 +37,8 @@ extern void init_cache (void); extern void save_cache (const char *cache_name); -extern void add_to_cache (const char *path, const char *lib, int flags); - -extern int cache_libcmp (const char *p1, const char *p2); - +extern void add_to_cache (const char *path, const char *lib, int flags, + unsigned long int hwcap); /* Declared in readlib.c. */ extern int process_file (const char *file_name, const char *lib, int *flag, @@ -54,6 +52,8 @@ extern int process_elf_file (const char *file_name, const char *lib, int *flag, /* Declared in ldconfig.c. */ extern int opt_verbose; +extern int opt_format; + /* Prototypes for a few program-wide used functions. */ extern void *xmalloc (size_t __n); extern void *xcalloc (size_t __n, size_t __size); @@ -61,4 +61,3 @@ extern void *xrealloc (void *__p, size_t __n); extern char *xstrdup (const char *__str); #endif /* ! _LDCONFIG_H */ - diff --git a/iconv/gconv_open.c b/iconv/gconv_open.c index 35ea4782ac..147f5b0e06 100644 --- a/iconv/gconv_open.c +++ b/iconv/gconv_open.c @@ -93,25 +93,25 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle, result->__data[cnt].__internal_use = 0; result->__data[cnt].__statep = &result->__data[cnt].__state; } - } - - if (res != __GCONV_OK) - { - /* Something went wrong. Free all the resources. */ - int serrno = errno; - if (result != NULL) + if (res != __GCONV_OK) { - while (cnt-- > 0) - free (result->__data[cnt].__outbuf); + /* Something went wrong. Free all the resources. */ + int serrno = errno; - free (result); - result = NULL; - } + if (result != NULL) + { + while (cnt-- > 0) + free (result->__data[cnt].__outbuf); + + free (result); + result = NULL; + } - __gconv_close_transform (steps, nsteps); + __gconv_close_transform (steps, nsteps); - __set_errno (serrno); + __set_errno (serrno); + } } *handle = result; diff --git a/intl/dcigettext.c b/intl/dcigettext.c index 3c86b83f28..b52fbd58c4 100644 --- a/intl/dcigettext.c +++ b/intl/dcigettext.c @@ -110,6 +110,14 @@ void free (); # define __libc_rwlock_unlock(NAME) #endif +/* Alignment of types. */ +#if defined __GNUC__ && __GNUC__ >= 2 +# define alignof(TYPE) __alignof__ (TYPE) +#else +# define alignof(TYPE) \ + ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2) +#endif + /* @@ end of prolog @@ */ #ifdef _LIBC @@ -785,20 +793,24 @@ _nl_find_msg (domain_file, msgid, index) resultlen = p - result; } - inbuf = result; - outbuf = freemem + 4; - __libc_lock_lock (lock); + inbuf = result; + outbuf = freemem + sizeof (nls_uint32); + while (1) { # ifdef _LIBC size_t non_reversible; int res; + if (freemem_size < 4) + goto resize_freemem; + res = __gconv (domain->conv, &inbuf, inbuf + resultlen, - &outbuf, outbuf + freemem_size, + &outbuf, + outbuf + freemem_size - sizeof (nls_uint32), &non_reversible); if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT) @@ -816,8 +828,12 @@ _nl_find_msg (domain_file, msgid, index) const char *inptr = (const char *) inbuf; size_t inleft = resultlen; char *outptr = (char *) outbuf; - size_t outleft = freemem_size; + size_t outleft; + + if (freemem_size < 4) + goto resize_freemem; + outleft = freemem_size - 4; if (iconv (domain->conv, &inptr, &inleft, &outptr, &outleft) != (size_t) (-1)) { @@ -832,6 +848,7 @@ _nl_find_msg (domain_file, msgid, index) # endif # endif + resize_freemem: /* We must resize the buffer. */ freemem_size = 2 * freemem_size; if (freemem_size < 4064) @@ -839,11 +856,12 @@ _nl_find_msg (domain_file, msgid, index) freemem = (char *) malloc (freemem_size); if (__builtin_expect (freemem == NULL, 0)) { + freemem_size = 0; __libc_lock_unlock (lock); goto converted; } - outbuf = freemem + 4; + outbuf = freemem + sizeof (nls_uint32); } /* We have now in our buffer a converted string. Put this @@ -853,15 +871,15 @@ _nl_find_msg (domain_file, msgid, index) /* Shrink freemem, but keep it aligned. */ freemem_size -= outbuf - freemem; freemem = outbuf; - freemem += freemem_size & (__alignof__ (nls_uint32) - 1); - freemem_size = freemem_size & ~ (__alignof__ (nls_uint32) - 1); + freemem += freemem_size & (alignof (nls_uint32) - 1); + freemem_size = freemem_size & ~ (alignof (nls_uint32) - 1); __libc_lock_unlock (lock); } /* Now domain->conv_tab[act] contains the translation of at least the variants 0 .. INDEX. */ - result = domain->conv_tab[act] + 4; + result = domain->conv_tab[act] + sizeof (nls_uint32); } converted: diff --git a/intl/tst-gettext.c b/intl/tst-gettext.c index 9ce11903aa..b897d71582 100644 --- a/intl/tst-gettext.c +++ b/intl/tst-gettext.c @@ -68,7 +68,9 @@ main (int argc, char *argv[]) setenv ("LANGUAGE", "existing-locale", 1); setenv ("LC_ALL", "non-existing-locale", 1); setenv ("LC_MESSAGES", "non-existing-locale", 1); + setenv ("LC_CTYPE", "non-existing-locale", 1); setenv ("LANG", "non-existing-locale", 1); + unsetenv ("OUTPUT_CHARSET"); /* This is the name of the existing domain with a catalog for the LC_MESSAGES category. */ textdomain ("existing-domain"); diff --git a/linuxthreads/Examples/ex7.c b/linuxthreads/Examples/ex7.c new file mode 100644 index 0000000000..94b708b56b --- /dev/null +++ b/linuxthreads/Examples/ex7.c @@ -0,0 +1,40 @@ +/* This is a test of the special shutdown that occurs + when all threads, including the main one, call + pthread_exit(). It demonstrates that atexit + handlers are properly called, and that the + output is properly flushed even when stdout is + redirected to a file, and therefore fully buffered. */ + +#include +#include +#include + +#define NTHREADS 20 /* number of threads */ + +static void *thread(void *arg) +{ + printf("thread terminating\n"); + return 0; +} + +void cleanup(void) +{ + printf("atexit handler called\n"); +} + +int main(void) +{ + int i; + + atexit(cleanup); + + for (i = 0; i < NTHREADS; i++) { + pthread_t id; + if (pthread_create(&id, 0, thread, 0) != 0) { + fprintf(stderr, "pthread_create failed\n"); + abort(); + } + } + + pthread_exit(0); +} diff --git a/linuxthreads/Makefile b/linuxthreads/Makefile index b51ea84f33..6e443631c3 100644 --- a/linuxthreads/Makefile +++ b/linuxthreads/Makefile @@ -38,7 +38,7 @@ libpthread-routines := attr cancel condvar join manager mutex ptfork \ oldsemaphore events getcpuclockid vpath %.c Examples -tests = ex1 ex2 ex3 ex4 ex5 ex6 +tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7 include ../Rules @@ -66,3 +66,4 @@ $(objpfx)ex3: $(libpthread) $(objpfx)ex4: $(libpthread) $(objpfx)ex5: $(libpthread) $(objpfx)ex6: $(libpthread) +$(objpfx)ex7: $(libpthread) diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h index b257be0279..e4cda4b66c 100644 --- a/linuxthreads/internals.h +++ b/linuxthreads/internals.h @@ -199,7 +199,7 @@ struct pthread_request { pthread_descr req_thread; /* Thread doing the request */ enum { /* Request kind */ REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT, - REQ_POST, REQ_DEBUG + REQ_POST, REQ_DEBUG, REQ_KICK } req_kind; union { /* Arguments for request */ struct { /* For REQ_CREATE: */ diff --git a/linuxthreads/join.c b/linuxthreads/join.c index 2716d799c1..7c9b6c5fd3 100644 --- a/linuxthreads/join.c +++ b/linuxthreads/join.c @@ -73,9 +73,13 @@ void pthread_exit(void * retval) request.req_kind = REQ_MAIN_THREAD_EXIT; __libc_write(__pthread_manager_request, (char *)&request, sizeof(request)); suspend(self); + /* Main thread flushes stdio streams and runs atexit functions. + It also calls a handler within LinuxThreads which sends a process exit + request to the thread manager. */ + exit(0); } - /* Exit the process (but don't flush stdio streams, and don't run - atexit functions). */ + /* Threads other than the main one terminate without flushing stdio streams + or running atexit functions. */ _exit(0); } diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c index 0c781dea6e..2d3e227f23 100644 --- a/linuxthreads/manager.c +++ b/linuxthreads/manager.c @@ -162,13 +162,22 @@ int __pthread_manager(void *arg) case REQ_PROCESS_EXIT: pthread_handle_exit(request.req_thread, request.req_args.exit.code); + /* NOTREACHED */ break; case REQ_MAIN_THREAD_EXIT: main_thread_exiting = 1; + /* Reap children in case all other threads died and the signal handler + went off before we set main_thread_exiting to 1, and therefore did + not do REQ_KICK. */ + pthread_reap_children(); + if (__pthread_main_thread->p_nextlive == __pthread_main_thread) { restart(__pthread_main_thread); - return 0; - } + /* The main thread will now call exit() which will trigger an + __on_exit handler, which in turn will send REQ_PROCESS_EXIT + to the thread manager. In case you are wondering how the + manager terminates from its loop here. */ + } break; case REQ_POST: __new_sem_post(request.req_args.post); @@ -179,6 +188,10 @@ int __pthread_manager(void *arg) if (__pthread_threads_debug && __pthread_sig_debug > 0) raise(__pthread_sig_debug); break; + case REQ_KICK: + /* This is just a prod to get the manager to reap some + threads right away, avoiding a potential delay at shutdown. */ + break; } } } @@ -591,7 +604,7 @@ static void pthread_exited(pid_t pid) if (main_thread_exiting && __pthread_main_thread->p_nextlive == __pthread_main_thread) { restart(__pthread_main_thread); - _exit(0); + /* Same logic as REQ_MAIN_THREAD_EXIT. */ } } @@ -685,7 +698,22 @@ static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode) void __pthread_manager_sighandler(int sig) { + int kick_manager = terminated_children == 0 && main_thread_exiting; terminated_children = 1; + + /* If the main thread is terminating, kick the thread manager loop + each time some threads terminate. This eliminates a two second + shutdown delay caused by the thread manager sleeping in the + call to __poll(). Instead, the thread manager is kicked into + action, reaps the outstanding threads and resumes the main thread + so that it can complete the shutdown. */ + + if (kick_manager) { + struct pthread_request request; + request.req_thread = 0; + request.req_kind = REQ_KICK; + __libc_write(__pthread_manager_request, (char *) &request, sizeof(request)); + } } /* Adjust priority of thread manager so that it always run at a priority diff --git a/sysdeps/generic/dl-cache.c b/sysdeps/generic/dl-cache.c index 2ab13d8d3f..28fab0b19e 100644 --- a/sysdeps/generic/dl-cache.c +++ b/sysdeps/generic/dl-cache.c @@ -22,31 +22,16 @@ #include #include + /* System-dependent function to read a file's whole contents in the most convenient manner available. */ extern void *_dl_sysdep_read_whole_file (const char *filename, size_t *filesize_ptr, int mmap_prot); -#ifndef LD_SO_CACHE -# define LD_SO_CACHE "/etc/ld.so.cache" -#endif - -#define CACHEMAGIC "ld.so-1.7.0" - -struct cache_file - { - char magic[sizeof CACHEMAGIC - 1]; - unsigned int nlibs; - struct - { - int flags; /* This is 1 for an ELF library. */ - unsigned int key, value; /* String table indices. */ - } libs[0]; - }; - /* This is the starting address and the size of the mmap()ed file. */ static struct cache_file *cache; +static struct cache_file_new *cache_new; static size_t cachesize; /* 1 if cache_data + PTR points into the cache. */ @@ -56,45 +41,100 @@ static size_t cachesize; binaries. */ int _dl_correct_cache_id = _DL_CACHE_DEFAULT_ID; -/* Helper function which must match the one in ldconfig, so that - we rely on the same sort order. */ -static int -_dl_cache_libcmp (const char *p1, const char *p2) -{ - while (*p1 != '\0') - { - if (*p1 >= '0' && *p1 <= '9') - { - if (*p2 >= '0' && *p2 <= '9') - { - /* Must compare this numerically. */ - int val1; - int val2; - - val1 = *p1++ - '0'; - val2 = *p2++ - '0'; - while (*p1 >= '0' && *p1 <= '9') - val1 = val1 * 10 + *p1++ - '0'; - while (*p2 >= '0' && *p2 <= '9') - val2 = val2 * 10 + *p2++ - '0'; - if (val1 != val2) - return val1 - val2; - } - else - return 1; - } - else if (*p2 >= '0' && *p2 <= '9') - return -1; - else if (*p1 != *p2) - return *p1 - *p2; - else - { - ++p1; - ++p2; - } - } - return *p1 - *p2; -} +#define SEARCH_CACHE(cache) \ +/* We use binary search since the table is sorted in the cache file. \ + The first matching entry in the table is returned. \ + It is important to use the same algorithm as used while generating \ + the cache file. */ \ +do \ + { \ + left = 0; \ + right = cache->nlibs - 1; \ + middle = (left + right) / 2; \ + cmpres = 1; \ + \ + while (left <= right) \ + { \ + /* Make sure string table indices are not bogus before using \ + them. */ \ + if (! _dl_cache_verify_ptr (cache->libs[middle].key)) \ + { \ + cmpres = 1; \ + break; \ + } \ + \ + /* Actually compare the entry with the key. */ \ + cmpres = _dl_cache_libcmp (name, \ + cache_data + cache->libs[middle].key); \ + if (cmpres == 0) \ + /* Found it. */ \ + break; \ + \ + if (cmpres < 0) \ + left = middle + 1; \ + else \ + right = middle - 1; \ + \ + middle = (left + right) / 2; \ + } \ + \ + if (cmpres == 0) \ + { \ + /* LEFT now marks the last entry for which we know the name is \ + correct. */ \ + left = middle; \ + \ + /* There might be entries with this name before the one we \ + found. So we have to find the beginning. */ \ + while (middle > 0 \ + /* Make sure string table indices are not bogus before \ + using them. */ \ + && _dl_cache_verify_ptr (cache->libs[middle - 1].key) \ + /* Actually compare the entry. */ \ + && (_dl_cache_libcmp (name, \ + cache_data \ + + cache->libs[middle - 1].key) \ + == 0)) \ + --middle; \ + \ + do \ + { \ + int flags; \ + \ + /* Only perform the name test if necessary. */ \ + if (middle > left \ + /* We haven't seen this string so far. Test whether the \ + index is ok and whether the name matches. Otherwise \ + we are done. */ \ + && (! _dl_cache_verify_ptr (cache->libs[middle].key) \ + || (_dl_cache_libcmp (name, \ + cache_data \ + + cache->libs[middle].key) \ + != 0))) \ + break; \ + \ + flags = cache->libs[middle].flags; \ + if (_dl_cache_check_flags (flags) \ + && _dl_cache_verify_ptr (cache->libs[middle].value)) \ + { \ + if (best == NULL || flags == _dl_correct_cache_id) \ + { \ + HWCAP_CHECK; \ + best = cache_data + cache->libs[middle].value; \ + \ + if (flags == _dl_correct_cache_id) \ + /* We've found an exact match for the shared \ + object and no general `ELF' release. Stop \ + searching. */ \ + break; \ + } \ + } \ + } \ + while (++middle <= right); \ + } \ + } \ +while (0) + /* Look up NAME in ld.so.cache and return the file name stored there, @@ -117,10 +157,38 @@ _dl_load_cache_lookup (const char *name) /* Read the contents of the file. */ void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize, PROT_READ); + + /* We can handle three different cache file formats here: + - the old libc5/glibc2.0/2.1 format + - the old format with the new format in it + - only the new format + The following checks if the cache contains any of these formats. */ if (file && cachesize > sizeof *cache && !memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1)) - /* Looks ok. */ - cache = file; + { + /* Looks ok. */ + cache = file; + + /* Check for new version. */ + cache_new = (struct cache_file_new *) &cache->libs[cache->nlibs]; + if (cachesize < + (sizeof (struct cache_file) + cache->nlibs * sizeof (struct file_entry) + + sizeof (struct cache_file_new)) + || memcmp (cache_new->magic, CACHEMAGIC_NEW, + sizeof CACHEMAGIC_NEW - 1) + || memcmp (cache_new->version, CACHE_VERSION, + sizeof CACHE_VERSION - 1)) + cache_new = (void *) -1; + } + else if (file && cachesize > sizeof *cache_new) + { + cache_new = (struct cache_file_new *) file; + if (memcmp (cache_new->magic, CACHEMAGIC_NEW, + sizeof CACHEMAGIC_NEW - 1) + || memcmp (cache_new->version, CACHE_VERSION, + sizeof CACHE_VERSION - 1)) + cache_new = (void *) -1; + } else { if (file) @@ -139,88 +207,23 @@ _dl_load_cache_lookup (const char *name) best = NULL; - /* We use binary search since the table is sorted in the cache file. - It is important to use the same algorithm as used while generating - the cache file. */ - left = 0; - right = cache->nlibs - 1; - middle = (left + right) / 2; - cmpres = 1; - - while (left <= right) + if (cache_new != (void *) -1) { - /* Make sure string table indices are not bogus before using them. */ - if (! _dl_cache_verify_ptr (cache->libs[middle].key)) - { - cmpres = 1; - break; - } + /* This file ends in static libraries where we don't have a hwcap. */ + unsigned long int *hwcap; + weak_extern (_dl_hwcap); - /* Actually compare the entry with the key. */ - cmpres = _dl_cache_libcmp (name, cache_data + cache->libs[middle].key); - if (cmpres == 0) - /* Found it. */ - break; + hwcap = &_dl_hwcap; - if (cmpres < 0) - left = middle + 1; - else - right = middle - 1; - - middle = (left + right) / 2; - } - - if (cmpres == 0) - { - /* LEFT now marks the last entry for which we know the name is - correct. */ - left = middle; - - /* There might be entries with this name before the one we - found. So we have to find the beginning. */ - while (middle > 0 - /* Make sure string table indices are not bogus before - using them. */ - && _dl_cache_verify_ptr (cache->libs[middle - 1].key) - /* Actually compare the entry. */ - && (_dl_cache_libcmp (name, - cache_data + cache->libs[middle - 1].key) - == 0)) - --middle; - - do - { - int flags; - - /* Only perform the name test if necessary. */ - if (middle > left - /* We haven't seen this string so far. Test whether the - index is ok and whether the name matches. Otherwise - we are done. */ - && (! _dl_cache_verify_ptr (cache->libs[middle].key) - || (_dl_cache_libcmp (name, - cache_data + cache->libs[middle].key) - != 0))) - break; - - flags = cache->libs[middle].flags; - if (_dl_cache_check_flags (flags) - && _dl_cache_verify_ptr (cache->libs[middle].value)) - { - if (best == NULL || flags == _dl_correct_cache_id) - { - best = cache_data + cache->libs[middle].value; - - if (flags == _dl_correct_cache_id) - /* We've found an exact match for the shared - object and no general `ELF' release. Stop - searching. */ - break; - } - } - } - while (++middle <= right); +#define HWCAP_CHECK \ + if (hwcap && (cache_new->libs[middle].hwcap & *hwcap) > _dl_hwcap) \ + continue + SEARCH_CACHE (cache_new); } + else +#undef HWCAP_CHECK +#define HWCAP_CHECK do {} while (0) + SEARCH_CACHE (cache); /* Print our result if wanted. */ if (_dl_debug_libs && best != NULL) diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h index 579c261af1..4eb64cf557 100644 --- a/sysdeps/generic/dl-cache.h +++ b/sysdeps/generic/dl-cache.h @@ -1,5 +1,5 @@ /* Support for reading /etc/ld.so.cache files written by Linux ldconfig. - Copyright (C) 1999 Free Software Foundation, Inc. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -21,3 +21,101 @@ #define _dl_cache_check_flags(flags) \ ((flags) == 1 || (flags) == _DL_CACHE_DEFAULT_ID) + + +#ifndef LD_SO_CACHE +# define LD_SO_CACHE "/etc/ld.so.cache" +#endif + +#define CACHEMAGIC "ld.so-1.7.0" + +/* libc5 and glibc 2.0/2.1 use the same format. For glibc 2.2 another + format has been added in a compatible way: + The beginning of the string table is used for the new table: + old_magic + nlibs + libs[0] + ... + libs[nlibs-1] + new magic + newnlibs + ... + newlibs[0] + ... + newlibs[newnlibs-1] + string 1 + string 2 + ... +*/ +struct file_entry +{ + int flags; /* This is 1 for an ELF library. */ + unsigned int key, value; /* String table indices. */ +}; + +struct cache_file +{ + char magic[sizeof CACHEMAGIC - 1]; + unsigned int nlibs; + struct file_entry libs[0]; +}; + +#define CACHEMAGIC_NEW "glibc-ld.so.cache" +#define CACHE_VERSION "1.0" + + +struct file_entry_new +{ + int flags; /* This is 1 for an ELF library. */ + unsigned int key, value; /* String table indices. */ + unsigned long hwcap; /* Hwcap entry. */ +}; + +struct cache_file_new +{ + char magic[sizeof CACHEMAGIC_NEW - 1]; + char version[sizeof CACHE_VERSION - 1]; + unsigned int nlibs; /* Number of entries. */ + unsigned int len_strings; /* Size of string table. */ + unsigned int unused[4]; /* Leave space for future extensions. */ + struct file_entry_new libs[0]; /* Entries describing libraries. */ + /* After this the string table of size len_strings is found. */ +}; + +static int +_dl_cache_libcmp (const char *p1, const char *p2) +{ + while (*p1 != '\0') + { + if (*p1 >= '0' && *p1 <= '9') + { + if (*p2 >= '0' && *p2 <= '9') + { + /* Must compare this numerically. */ + int val1; + int val2; + + val1 = *p1++ - '0'; + val2 = *p2++ - '0'; + while (*p1 >= '0' && *p1 <= '9') + val1 = val1 * 10 + *p1++ - '0'; + while (*p2 >= '0' && *p2 <= '9') + val2 = val2 * 10 + *p2++ - '0'; + if (val1 != val2) + return val1 - val2; + } + else + return 1; + } + else if (*p2 >= '0' && *p2 <= '9') + return -1; + else if (*p1 != *p2) + return *p1 - *p2; + else + { + ++p1; + ++p2; + } + } + return *p1 - *p2; +} -- cgit v1.2.3