aboutsummaryrefslogtreecommitdiff
path: root/locale
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2002-08-28 10:39:23 +0000
committerRoland McGrath <roland@gnu.org>2002-08-28 10:39:23 +0000
commit1a0d874ed44e1fe59470497d65af8822a1b3abb8 (patch)
treee182578150b4cc6ad70d2e39fba0baeea4e1ad49 /locale
parentd10c64301e56bd9cb77f5f480ba62df683ddbc5f (diff)
downloadglibc-1a0d874ed44e1fe59470497d65af8822a1b3abb8.zip
glibc-1a0d874ed44e1fe59470497d65af8822a1b3abb8.tar.gz
glibc-1a0d874ed44e1fe59470497d65af8822a1b3abb8.tar.bz2
Make uselocale support static linking.
* locale/xlocale.c: Revert changes putting _nl_global_locale here. This file again just defines _nl_C_locobj. (_nl_C_locobj): Use a categories.def iterator in the initializer. * locale/global-locale.c: New file. Define _nl_global_locale here, using all weak references in the initializer. * locale/Makefile (aux): Add global-locale. * locale/localeinfo.h (_nl_global_locale, _NL_CURRENT_LOCALE): Make these unconditional, along with the tsd decl. [!SHARED && HAVE___THREAD && HAVE_WEAK_SYMBOLS] (NL_CURRENT_INDIRECT): Define it under these conditions. [NL_CURRENT_INDIRECT]: Test this instead of [! SHARED]. Don't declare _nl_current. Declare _nl_current_LC_FOO as `extern __thread struct locale_data *const *'. [NL_CURRENT_INDIRECT] (_NL_CURRENT_DATA, _NL_CURRENT, _NL_CURRENT_WSTR): Add indirection. [NL_CURRENT_INDIRECT] (_NL_CURRENT_DEFINE): Rewritten. Define the thread variable _nl_current_LC_FOO and also a special absolute symbol _nl_current_LC_FOO_used. * locale/uselocale.c (__uselocale) [NL_CURRENT_INDIRECT]: Set each _nl_current_LC_FOO symbol to point into the new locale, using weak references to test if _nl_current_LC_FOO_used was linked in. * locale/setlocale.c [! SHARED]: Replace this conditional ... [NL_CURRENT_INDIRECT]: ... with this one. (_nl_current, _nl_C): Variables removed. [NL_CURRENT_INDIRECT] (_nl_current_used): New variable, table of weak references to _nl_current_LC_FOO_used. [NL_CURRENT_INDIRECT] (CATEGORY_USED): Define using that table. (free_category): New function, broken out of ... (free_mem): ... here. Call that. (free_mem) [NL_CURRENT_INDIRECT]: Use a categories.def iterator instead of a loop. __USING_NAMESPACE_C99 depending on _GLIBCPP_USE_NAMESPACES.
Diffstat (limited to 'locale')
-rw-r--r--locale/Makefile2
-rw-r--r--locale/global-locale.c63
-rw-r--r--locale/localeinfo.h73
-rw-r--r--locale/setlocale.c139
-rw-r--r--locale/uselocale.c42
-rw-r--r--locale/xlocale.c51
6 files changed, 225 insertions, 145 deletions
diff --git a/locale/Makefile b/locale/Makefile
index 0a5cac0..523e03b 100644
--- a/locale/Makefile
+++ b/locale/Makefile
@@ -42,7 +42,7 @@ tests = tst-C-locale
categories = ctype messages monetary numeric time paper name \
address telephone measurement identification collate
aux = $(categories:%=lc-%) $(categories:%=C-%) SYS_libc C_name \
- xlocale localename
+ xlocale localename global-locale
others = localedef locale
#others-static = localedef locale
install-bin = localedef locale
diff --git a/locale/global-locale.c b/locale/global-locale.c
new file mode 100644
index 0000000..70f10ab
--- /dev/null
+++ b/locale/global-locale.c
@@ -0,0 +1,63 @@
+/* Locale object representing the global locale controlled by setlocale.
+ Copyright (C) 2002 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <locale.h>
+#include "localeinfo.h"
+
+#define DEFINE_CATEGORY(category, category_name, items, a) \
+extern struct locale_data _nl_C_##category; weak_extern (_nl_C_##category)
+#include "categories.def"
+#undef DEFINE_CATEGORY
+
+/* Defined in locale/C-ctype.c. */
+extern const char _nl_C_LC_CTYPE_class[] attribute_hidden;
+extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden;
+extern const char _nl_C_LC_CTYPE_tolower[] attribute_hidden;
+weak_extern (_nl_C_LC_CTYPE_class)
+weak_extern (_nl_C_LC_CTYPE_toupper)
+weak_extern (_nl_C_LC_CTYPE_tolower)
+
+/* Here we define the locale object maintained by setlocale.
+ The references in the initializer are weak, so the parts of
+ the structure that are never referred to will be zero. */
+
+struct __locale_struct _nl_global_locale attribute_hidden =
+ {
+ .__locales =
+ {
+#define DEFINE_CATEGORY(category, category_name, items, a) \
+ [category] = &_nl_C_##category,
+#include "categories.def"
+#undef DEFINE_CATEGORY
+ },
+ .__ctype_b = (const unsigned short int *) _nl_C_LC_CTYPE_class + 128,
+ .__ctype_tolower = (const int *) _nl_C_LC_CTYPE_tolower + 128,
+ .__ctype_toupper = (const int *) _nl_C_LC_CTYPE_toupper + 128
+ };
+
+#include <tls.h>
+#if USE_TLS && HAVE___THREAD
+/* The tsd macros don't permit an initializer. */
+__thread void *__libc_tsd_LOCALE = &_nl_global_locale;
+#else
+__libc_tsd_define (, LOCALE)
+/* This is a bad kludge presuming the variable name used by the macros.
+ Using typeof makes sure to barf if we do not match the macro definition. */
+__typeof (__libc_tsd_LOCALE_data) __libc_tsd_LOCALE_data = &_nl_global_locale;
+#endif
diff --git a/locale/localeinfo.h b/locale/localeinfo.h
index 44a10e1..4e8c86e 100644
--- a/locale/localeinfo.h
+++ b/locale/localeinfo.h
@@ -155,54 +155,81 @@ extern const char _nl_C_codeset[] attribute_hidden;
Each is malloc'd unless it is _nl_C_name. */
extern const char *_nl_current_names[] attribute_hidden;
+/* This is the internal locale_t object that holds the global locale
+ controlled by calls to setlocale. A thread's TSD locale pointer
+ points to this when `uselocale (LC_GLOBAL_LOCALE)' is in effect. */
+extern struct __locale_struct _nl_global_locale attribute_hidden;
+
+/* This fetches the thread-local locale_t pointer, either one set with
+ uselocale or &_nl_global_locale. */
+#define _NL_CURRENT_LOCALE ((__locale_t) __libc_tsd_get (LOCALE))
+#include <bits/libc-tsd.h>
+__libc_tsd_define (extern, LOCALE)
-#ifndef SHARED
-/* For each category declare the variable for the current locale data. */
-/* XXX _nl_current_LC_CTYPE and _nl_current_LC_COLLATE were exported
- but where are they used? */
+/* For static linking it is desireable to avoid always linking in the code
+ and data for every category when we can tell at link time that they are
+ unused. We can manage this playing some tricks with weak references.
+ But with thread-local locale settings, it becomes quite ungainly unless
+ we can use __thread variables. So only in that case do we attempt this. */
+#if !defined SHARED && defined HAVE___THREAD && defined HAVE_WEAK_SYMBOLS
+# include <tls.h>
+# if USE_TLS
+# define NL_CURRENT_INDIRECT 1
+# endif
+#endif
+
+#ifdef NL_CURRENT_INDIRECT
+
+/* For each category declare the thread-local variable for the current
+ locale data. This has an extra indirection so it points at the
+ __locales[CATEGORY] element in either _nl_global_locale or the current
+ locale object set by uselocale, which points at the actual data. The
+ reason for having these variables is so that references to particular
+ categories will link in the lc-CATEGORY.c module to define this symbol,
+ and we arrange that linking that module is what brings in all the code
+ associated with this category. */
#define DEFINE_CATEGORY(category, category_name, items, a) \
-extern struct locale_data *_nl_current_##category attribute_hidden;
+extern __thread struct locale_data *const *_nl_current_##category \
+ attribute_hidden;
#include "categories.def"
#undef DEFINE_CATEGORY
-extern struct locale_data * *const _nl_current[__LC_LAST] attribute_hidden;
/* Return a pointer to the current `struct locale_data' for CATEGORY. */
-#define _NL_CURRENT_DATA(category) _nl_current_##category
-/* Hackety hack, don't talk back. */
-#define _nl_current_category (*_nl_current[category])
+#define _NL_CURRENT_DATA(category) (*_nl_current_##category)
/* Extract the current CATEGORY locale's string for ITEM. */
#define _NL_CURRENT(category, item) \
- (_nl_current_##category->values[_NL_ITEM_INDEX (item)].string)
+ ((*_nl_current_##category)->values[_NL_ITEM_INDEX (item)].string)
/* Extract the current CATEGORY locale's string for ITEM. */
#define _NL_CURRENT_WSTR(category, item) \
- ((wchar_t *) _nl_current_##category->values[_NL_ITEM_INDEX (item)].wstr)
+ ((wchar_t *) (*_nl_current_##category)->values[_NL_ITEM_INDEX (item)].wstr)
/* Extract the current CATEGORY locale's word for ITEM. */
#define _NL_CURRENT_WORD(category, item) \
- (_nl_current_##category->values[_NL_ITEM_INDEX (item)].word)
+ ((*_nl_current_##category)->values[_NL_ITEM_INDEX (item)].word)
/* This is used in lc-CATEGORY.c to define _nl_current_CATEGORY. */
#define _NL_CURRENT_DEFINE(category) \
- extern struct locale_data _nl_C_##category attribute_hidden; \
- struct locale_data *_nl_current_##category = &_nl_C_##category
+ __thread struct locale_data *const *_nl_current_##category \
+ attribute_hidden = &_nl_global_locale.__locales[category]; \
+ asm (_NL_CURRENT_DEFINE_STRINGIFY (ASM_GLOBAL_DIRECTIVE) \
+ " " __SYMBOL_PREFIX "_nl_current_" #category "_used\n" \
+ _NL_CURRENT_DEFINE_ABS (_nl_current_##category##_used, 1));
+#define _NL_CURRENT_DEFINE_STRINGIFY(x) _NL_CURRENT_DEFINE_STRINGIFY_1 (x)
+#define _NL_CURRENT_DEFINE_STRINGIFY_1(x) #x
+#ifdef HAVE_ASM_SET_DIRECTIVE
+# define _NL_CURRENT_DEFINE_ABS(sym, val) ".set " #sym ", " #val
+#else
+# define _NL_CURRENT_DEFINE_ABS(sym, val) #sym " = " #val
+#endif
#else
/* All categories are always loaded in the shared library, so there is no
point in having lots of separate symbols for linking. */
-# include <bits/libc-tsd.h>
-
-__libc_tsd_define (extern, LOCALE)
-
-extern struct __locale_struct _nl_global_locale attribute_hidden;
-
-# define _NL_CURRENT_LOCALE \
- ((__locale_t) __libc_tsd_get (LOCALE))
-
/* Return a pointer to the current `struct locale_data' for CATEGORY. */
# define _NL_CURRENT_DATA(category) \
(_NL_CURRENT_LOCALE->__locales[category])
diff --git a/locale/setlocale.c b/locale/setlocale.c
index 3c80379..296903f 100644
--- a/locale/setlocale.c
+++ b/locale/setlocale.c
@@ -27,55 +27,39 @@
#include "localeinfo.h"
-#ifndef SHARED
-
-/* For each category declare two external variables (with weak references):
- extern const struct locale_data *_nl_current_CATEGORY;
- This points to the current locale's in-core data for CATEGORY.
- extern const struct locale_data _nl_C_CATEGORY;
- This contains the built-in "C"/"POSIX" locale's data for CATEGORY.
- Both are weak references; if &_nl_current_CATEGORY is zero,
- then nothing is using the locale data. */
-#define DEFINE_CATEGORY(category, category_name, items, a) \
-weak_extern (_nl_current_##category) \
-weak_extern (_nl_C_##category) \
-extern struct locale_data *_nl_current_##category; \
-extern struct locale_data _nl_C_##category;
-#include "categories.def"
-#undef DEFINE_CATEGORY
-
-/* Array indexed by category of pointers to _nl_current_CATEGORY slots.
- Elements are zero for categories whose data is never used. */
-struct locale_data * *const _nl_current[] =
- {
-#define DEFINE_CATEGORY(category, category_name, items, a) \
- [category] = &_nl_current_##category,
-#include "categories.def"
-#undef DEFINE_CATEGORY
- /* We need this additional element to simplify the code. It must
- simply be != NULL. */
- [LC_ALL] = (struct locale_data **) ~0ul
- };
-
-/* Array indexed by category of pointers to _nl_C_CATEGORY slots.
- Elements are zero for categories whose data is never used. */
-struct locale_data *const _nl_C[] attribute_hidden =
+#ifdef NL_CURRENT_INDIRECT
+
+/* For each category declare a special external symbol
+ _nl_current_CATEGORY_used with a weak reference.
+ This symbol will is defined in lc-CATEGORY.c and will be linked in
+ if anything uses _nl_current_CATEGORY (also defined in that module).
+ Also use a weak reference for the _nl_current_CATEGORY thread variable. */
+
+# define DEFINE_CATEGORY(category, category_name, items, a) \
+ extern char _nl_current_##category##_used; \
+ weak_extern (_nl_current_##category##_used) \
+ weak_extern (_nl_current_##category)
+# include "categories.def"
+# undef DEFINE_CATEGORY
+
+/* Now define a table of flags based on those special weak symbols' values.
+ _nl_current_used[CATEGORY] will be zero if _nl_current_CATEGORY is not
+ linked in. */
+static char *const _nl_current_used[] =
{
-#define DEFINE_CATEGORY(category, category_name, items, a) \
- [category] = &_nl_C_##category,
-#include "categories.def"
-#undef DEFINE_CATEGORY
+# define DEFINE_CATEGORY(category, category_name, items, a) \
+ [category] = &_nl_current_##category##_used,
+# include "categories.def"
+# undef DEFINE_CATEGORY
};
-# define CATEGORY_USED(category) (_nl_current[category] != NULL)
+# define CATEGORY_USED(category) (_nl_current_used[category] != 0)
#else
/* The shared library always loads all the categories,
and the current global settings are kept in _nl_global_locale. */
-# define _nl_C (_nl_C_locobj.__locales)
-
# define CATEGORY_USED(category) (1)
#endif
@@ -211,13 +195,7 @@ setdata (int category, struct locale_data *data)
{
if (CATEGORY_USED (category))
{
-#ifdef SHARED
_nl_global_locale.__locales[category] = data;
-#endif
-#ifndef SHARED
-# warning when uselocale exists it will need the line above too
- *_nl_current[category] = data;
-#endif
if (_nl_category_postload[category])
(*_nl_category_postload[category]) ();
}
@@ -444,38 +422,57 @@ setlocale (int category, const char *locale)
}
libc_hidden_def (setlocale)
+static void
+free_category (int category,
+ struct locale_data *here, struct locale_data *c_data)
+{
+ struct loaded_l10nfile *runp = _nl_locale_file_list[category];
+
+ /* If this category is already "C" don't do anything. */
+ if (here != c_data)
+ {
+ /* We have to be prepared that sometime later we still
+ might need the locale information. */
+ setdata (category, c_data);
+ setname (category, _nl_C_name);
+ }
+
+ while (runp != NULL)
+ {
+ struct loaded_l10nfile *curr = runp;
+ struct locale_data *data = (struct locale_data *) runp->data;
+
+ if (data != NULL && data != c_data)
+ _nl_unload_locale (data);
+ runp = runp->next;
+ free ((char *) curr->filename);
+ free (curr);
+ }
+}
+
static void __attribute__ ((unused))
free_mem (void)
{
+#ifdef NL_CURRENT_INDIRECT
+ /* We don't use the loop because we want to have individual weak
+ symbol references here. */
+# define DEFINE_CATEGORY(category, category_name, items, a) \
+ if (CATEGORY_USED (category)) \
+ { \
+ extern struct locale_data _nl_C_##category; \
+ weak_extern (_nl_C_##category) \
+ free_category (category, *_nl_current_##category, &_nl_C_##category); \
+ }
+# include "categories.def"
+# undef DEFINE_CATEGORY
+#else
int category;
for (category = 0; category < __LC_LAST; ++category)
if (category != LC_ALL)
- {
- struct locale_data *here = _NL_CURRENT_DATA (category);
- struct loaded_l10nfile *runp = _nl_locale_file_list[category];
-
- /* If this category is already "C" don't do anything. */
- if (here != _nl_C[category])
- {
- /* We have to be prepared that sometime later we still
- might need the locale information. */
- setdata (category, _nl_C[category]);
- setname (category, _nl_C_name);
- }
-
- while (runp != NULL)
- {
- struct loaded_l10nfile *curr = runp;
- struct locale_data *data = (struct locale_data *) runp->data;
-
- if (data != NULL && data != _nl_C[category])
- _nl_unload_locale (data);
- runp = runp->next;
- free ((char *) curr->filename);
- free (curr);
- }
- }
+ free_category (category, _NL_CURRENT_DATA (category),
+ _nl_C_locobj.__locales[category]);
+#endif
setname (LC_ALL, _nl_C_name);
diff --git a/locale/uselocale.c b/locale/uselocale.c
index 1e81938..d5e5311 100644
--- a/locale/uselocale.c
+++ b/locale/uselocale.c
@@ -20,8 +20,6 @@
#include <locale.h>
#include "localeinfo.h"
-#ifdef SHARED
-
/* Switch the current thread's locale to DATASET.
If DATASET is null, instead just return the current setting.
The special value LC_GLOBAL_LOCALE is the initial setting
@@ -35,18 +33,38 @@ __uselocale (locale_t newloc)
locale_t loc = __libc_tsd_get (LOCALE);
return loc == &_nl_global_locale ? LC_GLOBAL_LOCALE : loc;
}
- if (newloc == LC_GLOBAL_LOCALE)
+ else
{
- __libc_tsd_set (LOCALE, &_nl_global_locale);
- return LC_GLOBAL_LOCALE;
+ const locale_t locobj
+ = newloc == LC_GLOBAL_LOCALE ? &_nl_global_locale : newloc;
+ __libc_tsd_set (LOCALE, locobj);
+
+#ifdef NL_CURRENT_INDIRECT
+ /* Now we must update all the per-category thread-local variables to
+ point into the new current locale for this thread. The magic
+ symbols _nl_current_LC_FOO_used are defined to meaningless values
+ if _nl_current_LC_FOO was linked in. By using weak references to
+ both symbols and testing the address of _nl_current_LC_FOO_used,
+ we can avoid accessing the _nl_current_LC_FOO thread-local
+ variable at all when no code referring to it was linked in. We
+ need the special bogus symbol because while TLS symbols can be
+ weak, there is no reasonable way to test for the default-zero
+ value as with a heap symbol (taking the address would just use
+ some bogus offset from our thread pointer). */
+
+# define DEFINE_CATEGORY(category, category_name, items, a) \
+ { \
+ extern char _nl_current_##category##_used; \
+ weak_extern (_nl_current_##category##_used) \
+ weak_extern (_nl_current_##category) \
+ if (&_nl_current_##category##_used != 0) \
+ _nl_current_##category = &locobj->__locales[category]; \
+ }
+# include "categories.def"
+# undef DEFINE_CATEGORY
+#endif
}
- __libc_tsd_set (LOCALE, newloc);
+
return newloc;
}
weak_alias (__uselocale, uselocale)
-
-#else
-
-# warning uselocale not implemented for static linking yet
-
-#endif
diff --git a/locale/xlocale.c b/locale/xlocale.c
index 854584c..2f9e198 100644
--- a/locale/xlocale.c
+++ b/locale/xlocale.c
@@ -32,41 +32,16 @@ extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden;
extern const char _nl_C_LC_CTYPE_tolower[] attribute_hidden;
-#define NL_C_INITIALIZER \
- { \
- .__locales = \
- { \
- [LC_CTYPE] = &_nl_C_LC_CTYPE, \
- [LC_NUMERIC] = &_nl_C_LC_NUMERIC, \
- [LC_TIME] = &_nl_C_LC_TIME, \
- [LC_COLLATE] = &_nl_C_LC_COLLATE, \
- [LC_MONETARY] = &_nl_C_LC_MONETARY, \
- [LC_MESSAGES] = &_nl_C_LC_MESSAGES, \
- [LC_PAPER] = &_nl_C_LC_PAPER, \
- [LC_NAME] = &_nl_C_LC_NAME, \
- [LC_ADDRESS] = &_nl_C_LC_ADDRESS, \
- [LC_TELEPHONE] = &_nl_C_LC_TELEPHONE, \
- [LC_MEASUREMENT] = &_nl_C_LC_MEASUREMENT, \
- [LC_IDENTIFICATION] = &_nl_C_LC_IDENTIFICATION \
- }, \
- .__ctype_b = (const unsigned short int *) _nl_C_LC_CTYPE_class + 128, \
- .__ctype_tolower = (const int *) _nl_C_LC_CTYPE_tolower + 128, \
- .__ctype_toupper = (const int *) _nl_C_LC_CTYPE_toupper + 128 \
- }
-
-struct __locale_struct _nl_C_locobj attribute_hidden = NL_C_INITIALIZER;
-
-#ifdef SHARED
-struct __locale_struct _nl_global_locale attribute_hidden = NL_C_INITIALIZER;
-
-# if USE_TLS && HAVE___THREAD
-/* The tsd macros don't permit an initializer. */
-__thread void *__libc_tsd_LOCALE = &_nl_global_locale;
-# else
-__libc_tsd_define (, LOCALE)
-/* This is a bad kludge presuming the variable name used by the macros.
- Using typeof makes sure to barf if we do not match the macro definition. */
-__typeof (__libc_tsd_LOCALE_data) __libc_tsd_LOCALE_data = &_nl_global_locale;
-# endif
-
-#endif
+struct __locale_struct _nl_C_locobj attribute_hidden =
+ {
+ .__locales =
+ {
+#define DEFINE_CATEGORY(category, category_name, items, a) \
+ [category] = &_nl_C_##category,
+#include "categories.def"
+#undef DEFINE_CATEGORY
+ },
+ .__ctype_b = (const unsigned short int *) _nl_C_LC_CTYPE_class + 128,
+ .__ctype_tolower = (const int *) _nl_C_LC_CTYPE_tolower + 128,
+ .__ctype_toupper = (const int *) _nl_C_LC_CTYPE_toupper + 128
+ };