aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2000-05-07 21:23:56 +0000
committerUlrich Drepper <drepper@redhat.com>2000-05-07 21:23:56 +0000
commit45eca4d141c047950db48c69c8941163d0a61fcd (patch)
tree66035482a9beed5f14699227294ac902b32a5106
parentd89d0afad4551a808b15510795f965aed147a834 (diff)
downloadglibc-45eca4d141c047950db48c69c8941163d0a61fcd.tar
glibc-45eca4d141c047950db48c69c8941163d0a61fcd.tar.gz
glibc-45eca4d141c047950db48c69c8941163d0a61fcd.tar.bz2
glibc-45eca4d141c047950db48c69c8941163d0a61fcd.zip
Update.
2000-05-06 Bruno Haible <haible@clisp.cons.org> * iconv/gconv_open.c (__gconv_open): If __gconv_find_transform returned != __GCONV_OK, there is nothing to clean up. 2000-05-06 Bruno Haible <haible@clisp.cons.org> * intl/tst-gettext.c (main): Disable possibly existing LC_CTYPE and OUTPUT_CHARSET environment variables. 2000-05-06 Andreas Jaeger <aj@suse.de> * 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 <haible@clisp.cons.org> * 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 <haible@clisp.cons.org> * intl/dcigettext.c (dcigettext): Fix interpretation of tsearch return value.
-rw-r--r--ChangeLog65
-rw-r--r--elf/cache.c277
-rw-r--r--elf/ldconfig.c150
-rw-r--r--elf/ldconfig.h11
-rw-r--r--iconv/gconv_open.c28
-rw-r--r--intl/dcigettext.c36
-rw-r--r--intl/tst-gettext.c2
-rw-r--r--linuxthreads/Examples/ex7.c40
-rw-r--r--linuxthreads/Makefile3
-rw-r--r--linuxthreads/internals.h2
-rw-r--r--linuxthreads/join.c8
-rw-r--r--linuxthreads/manager.c34
-rw-r--r--sysdeps/generic/dl-cache.c275
-rw-r--r--sysdeps/generic/dl-cache.h100
14 files changed, 721 insertions, 310 deletions
diff --git a/ChangeLog b/ChangeLog
index 9332cba808..04787bb705 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,68 @@
+2000-05-06 Bruno Haible <haible@clisp.cons.org>
+
+ * iconv/gconv_open.c (__gconv_open): If __gconv_find_transform
+ returned != __GCONV_OK, there is nothing to clean up.
+
+2000-05-06 Bruno Haible <haible@clisp.cons.org>
+
+ * intl/tst-gettext.c (main): Disable possibly existing LC_CTYPE and
+ OUTPUT_CHARSET environment variables.
+
+2000-05-06 Andreas Jaeger <aj@suse.de>
+
+ * 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 <haible@clisp.cons.org>
+
+ * 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 <haible@clisp.cons.org>
+
+ * intl/dcigettext.c (dcigettext): Fix interpretation of tsearch
+ return value.
+
2000-05-06 Ulrich Drepper <drepper@redhat.com>
* 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 <assert.h>
#include <errno.h>
#include <error.h>
#include <dirent.h>
@@ -34,32 +31,18 @@
#include <sys/types.h>
#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 <aj@suse.de>, 1999.
@@ -32,10 +32,12 @@
#include <sys/types.h>
#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 <aj@suse.de>, 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 <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#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 <sys/mman.h>
#include <dl-cache.h>
+
/* 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;
+}