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.
This commit is contained in:
Roland McGrath 2002-08-28 10:39:23 +00:00
parent d10c64301e
commit 1a0d874ed4
7 changed files with 257 additions and 144 deletions

View File

@ -1,5 +1,38 @@
2002-08-28 Roland McGrath <roland@redhat.com>
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.
* sysdeps/generic/libc-tls.c (__libc_setup_tls): Don't check for
PT_LOAD program headers and don't try to relocate PT_TLS's p_vaddr;
it is already absolute.
@ -64,7 +97,7 @@
* misc/sys/cdefs.h: Define __BEGIN_NAMESPACE_STD, __END_NAMESPACE_STD,
__USING_NAMESPACE_STD, __BEGIN_NAMESPACE_C99, __END_NAMESPACE_C99, and
__USING_NAMESPACE_C99 dependingon _GLIBCPP_USE_NAMESPACES.
__USING_NAMESPACE_C99 depending on _GLIBCPP_USE_NAMESPACES.
* ctype/ctype.h: Prepare headers for use in ISO C++ compliant
implementations.
* libio/stdio.h: Likewise.

View File

@ -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

63
locale/global-locale.c Normal file
View File

@ -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

View File

@ -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;
#ifndef SHARED
/* 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)
/* 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])

View File

@ -27,55 +27,39 @@
#include "localeinfo.h"
#ifndef SHARED
#ifdef NL_CURRENT_INDIRECT
/* 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
/* 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. */
/* 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) \
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_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
# define DEFINE_CATEGORY(category, category_name, items, a) \
[category] = &_nl_current_##category##_used,
# include "categories.def"
# undef DEFINE_CATEGORY
};
/* 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 =
{
#define DEFINE_CATEGORY(category, category_name, items, a) \
[category] = &_nl_C_##category,
#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);

View File

@ -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

View File

@ -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
};