>From de62ab01a4b868acadc33ea6edec95d279664aa7 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Mon, 22 Oct 2018 02:38:39 +0200 Subject: [PATCH 2/2] localename: Fine-tune support for per-thread locales on Solaris 11.4. * lib/localename-table.h: New file, extracted from lib/localename.c. * lib/localename-table.c: Likewise. * lib/localename.c: Include localename-table.h. (get_locale_t_name, newlocale, duplocale, freelocale): Invoke locale_hash_function instead of pointer_hash. * modules/localename (Files): Add lib/localename-table.h, lib/localename-table.c. (lib_SOURCES): Add localename-table.c. * m4/intlsolaris.m4 (gt_INTL_SOLARIS): Require AC_CANONICAL_HOST. Test for Solaris 11.4 locale system only on Solaris. Test for it independently whether getlocalename_l exists. * m4/intl.m4 (gt_INTL_SUBDIR_CORE): Don't test for 'uselocale' and 'getlocalename_l'. Instead, invoke gt_INTL_SOLARIS. Set HAVE_NAMELESS_LOCALES. * modules/gettext (Files): Add m4/intlsolaris.m4. diff --git a/ChangeLog b/ChangeLog index 3548a53..d1fd026 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,24 @@ 2018-10-21 Bruno Haible + localename: Fine-tune support for per-thread locales on Solaris 11.4. + * lib/localename-table.h: New file, extracted from lib/localename.c. + * lib/localename-table.c: Likewise. + * lib/localename.c: Include localename-table.h. + (get_locale_t_name, newlocale, duplocale, freelocale): Invoke + locale_hash_function instead of pointer_hash. + * modules/localename (Files): Add lib/localename-table.h, + lib/localename-table.c. + (lib_SOURCES): Add localename-table.c. + * m4/intlsolaris.m4 (gt_INTL_SOLARIS): Require AC_CANONICAL_HOST. Test + for Solaris 11.4 locale system only on Solaris. Test for it + independently whether getlocalename_l exists. + * m4/intl.m4 (gt_INTL_SUBDIR_CORE): Don't test for 'uselocale' and + 'getlocalename_l'. Instead, invoke gt_INTL_SOLARIS. Set + HAVE_NAMELESS_LOCALES. + * modules/gettext (Files): Add m4/intlsolaris.m4. + +2018-10-21 Bruno Haible + Small update from gettext. * m4/intl.m4: Update from gettext: - 2018-01-02: Fix 'ar' invocation when cross-compiling and in 64-bit diff --git a/lib/localename-table.c b/lib/localename-table.c new file mode 100644 index 0000000..54fd67d --- /dev/null +++ b/lib/localename-table.c @@ -0,0 +1,48 @@ +/* Table that maps a locale object to the names of the locale categories. + Copyright (C) 2018 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program. If not, see . */ + +/* Written by Bruno Haible , 2018. */ + +#include + +#if HAVE_USELOCALE && HAVE_NAMELESS_LOCALES /* Solaris >= 11.4 */ + +/* Specification. */ +#include "localename-table.h" + +#include + +/* A hash function for pointers. */ +size_t _GL_ATTRIBUTE_CONST +locale_hash_function (locale_t x) +{ + uintptr_t p = (uintptr_t) x; + size_t h = ((p % 4177) << 12) + ((p % 79) << 6) + (p % 61); + return h; +} + +struct locale_hash_node * locale_hash_table[LOCALE_HASH_TABLE_SIZE] + /* = { NULL, ..., NULL } */; + +gl_rwlock_define_initialized(, locale_lock) + +#else + +/* This declaration is solely to ensure that after preprocessing + this file is never empty. */ +typedef int dummy; + +#endif diff --git a/lib/localename-table.h b/lib/localename-table.h new file mode 100644 index 0000000..0d204d6 --- /dev/null +++ b/lib/localename-table.h @@ -0,0 +1,73 @@ +/* Table that maps a locale object to the names of the locale categories. + Copyright (C) 2018 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program. If not, see . */ + +/* Written by Bruno Haible , 2018. */ + +#if HAVE_USELOCALE && HAVE_NAMELESS_LOCALES /* Solaris >= 11.4 */ + +# include +# include + +# ifdef IN_LIBINTL +# include "lock.h" +# else +# include "glthread/lock.h" +# endif + +struct locale_categories_names + { + /* Locale category -> name (allocated with indefinite extent). */ + const char *category_name[6]; + }; + +/* A hash table of fixed size. Multiple threads can access it read-only + simultaneously, but only one thread can insert into it or remove from it + at the same time. + This hash table has global scope, so that when an application uses both + GNU libintl and gnulib, the application sees only one hash table. (When + linking statically with libintl, the fact that localename-table.c is a + separate compilation unit resolves the duplicate symbol conflict. When + linking with libintl as a shared library, we rely on ELF and the symbol + conflict resolution implemented in the ELF dynamic loader here.) + Both the libintl overrides and the gnulib overrides of the functions + newlocale, duplocale, freelocale see the same hash table (and the same lock). + For this reason, the internal layout of the hash table and the hash function + MUST NEVER CHANGE. If you need to change the internal layout or the hash + function, introduce versioning by appending a version suffix to the symbols + at the linker level. */ +# define locale_hash_function libintl_locale_hash_function +# define locale_hash_table libintl_locale_hash_table +# define locale_lock libintl_locale_lock + +extern size_t _GL_ATTRIBUTE_CONST locale_hash_function (locale_t x); + +/* A node in a hash bucket collision list. */ +struct locale_hash_node + { + struct locale_hash_node *next; + locale_t locale; + struct locale_categories_names names; + }; + +# define LOCALE_HASH_TABLE_SIZE 101 +extern struct locale_hash_node * locale_hash_table[LOCALE_HASH_TABLE_SIZE]; + +/* This lock protects the locale_hash_table against multiple simultaneous + accesses (except that multiple simultaneous read accesses are allowed). */ + +gl_rwlock_define(extern, locale_lock) + +#endif diff --git a/lib/localename.c b/lib/localename.c index 93fee9b..04e6d42 100644 --- a/lib/localename.c +++ b/lib/localename.c @@ -52,7 +52,7 @@ extern char * getlocalename_l(int, locale_t); # endif # if HAVE_NAMELESS_LOCALES # include -# include +# include "localename-table.h" # endif #endif @@ -2707,43 +2707,8 @@ struniq (const char *string) #if HAVE_USELOCALE && HAVE_NAMELESS_LOCALES /* Solaris >= 11.4 */ /* The 'locale_t' object does not contain the names of the locale categories. - We have to associate them with the object through a hash table. */ - -struct locale_categories_names - { - /* Locale category -> name (allocated with indefinite extent). */ - const char *category_name[6]; - }; - -/* A hash function for pointers. */ -static size_t _GL_ATTRIBUTE_CONST -pointer_hash (const void *x) -{ - uintptr_t p = (uintptr_t) x; - size_t h = ((p % 4177) << 12) + ((p % 79) << 6) + (p % 61); - return h; -} - -/* A hash table of fixed size. Multiple threads can access it read-only - simultaneously, but only one thread can insert into it or remove from it - at the same time. */ - -/* A node in a hash bucket collision list. */ -struct locale_hash_node - { - struct locale_hash_node *next; - locale_t locale; - struct locale_categories_names names; - }; - -# define LOCALE_HASH_TABLE_SIZE 101 -static struct locale_hash_node * locale_hash_table[LOCALE_HASH_TABLE_SIZE] - /* = { NULL, ..., NULL } */; - -/* This lock protects the locale_hash_table against multiple simultaneous - accesses (except that multiple simultaneous read accesses are allowed). */ - -gl_rwlock_define_initialized(static, locale_lock) + We have to associate them with the object through a hash table. + The hash table is defined in localename-table.[hc]. */ /* Returns the name of a given locale category in a given locale_t object, allocated as a string with indefinite extent. */ @@ -2763,7 +2728,7 @@ get_locale_t_name (int category, locale_t locale) else { /* Look up the names in the hash table. */ - size_t hashcode = pointer_hash (locale); + size_t hashcode = locale_hash_function (locale); size_t slot = hashcode % LOCALE_HASH_TABLE_SIZE; /* If the locale was not found in the table, return "". This can happen if the application uses the original newlocale()/duplocale() @@ -2898,7 +2863,7 @@ newlocale (int category_mask, const char *name, locale_t base) /* Lock while looking up the hash node. */ gl_rwlock_rdlock (locale_lock); - for (p = locale_hash_table[pointer_hash (base) % LOCALE_HASH_TABLE_SIZE]; + for (p = locale_hash_table[locale_hash_function (base) % LOCALE_HASH_TABLE_SIZE]; p != NULL; p = p->next) if (p->locale == base) @@ -2961,7 +2926,7 @@ newlocale (int category_mask, const char *name, locale_t base) /* Insert it in the hash table. */ { - size_t hashcode = pointer_hash (result); + size_t hashcode = locale_hash_function (result); size_t slot = hashcode % LOCALE_HASH_TABLE_SIZE; struct locale_hash_node *p; @@ -3036,7 +3001,7 @@ duplocale (locale_t locale) /* Lock once, for the lookup and the insertion. */ gl_rwlock_wrlock (locale_lock); - for (p = locale_hash_table[pointer_hash (locale) % LOCALE_HASH_TABLE_SIZE]; + for (p = locale_hash_table[locale_hash_function (locale) % LOCALE_HASH_TABLE_SIZE]; p != NULL; p = p->next) if (p->locale == locale) @@ -3057,7 +3022,7 @@ duplocale (locale_t locale) /* Insert it in the hash table. */ { - size_t hashcode = pointer_hash (result); + size_t hashcode = locale_hash_function (result); size_t slot = hashcode % LOCALE_HASH_TABLE_SIZE; struct locale_hash_node *p; @@ -3094,7 +3059,7 @@ freelocale (locale_t locale) abort (); { - size_t hashcode = pointer_hash (locale); + size_t hashcode = locale_hash_function (locale); size_t slot = hashcode % LOCALE_HASH_TABLE_SIZE; struct locale_hash_node *found; struct locale_hash_node **p; diff --git a/m4/intl.m4 b/m4/intl.m4 index 42fac95..7efc7e8 100644 --- a/m4/intl.m4 +++ b/m4/intl.m4 @@ -1,5 +1,5 @@ -# intl.m4 serial 32 (gettext-0.19.9) -dnl Copyright (C) 1995-2014, 2016-2018 Free Software Foundation, Inc. +# intl.m4 serial 33 (gettext-0.19.9) +dnl Copyright (C) 1995-2014, 2016-2018 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. @@ -229,14 +232,17 @@ AC_DEFUN([gt_INTL_SUBDIR_CORE], AC_CHECK_HEADERS([argz.h inttypes.h limits.h unistd.h sys/param.h]) AC_CHECK_FUNCS([getcwd getegid geteuid getgid getuid mempcpy munmap \ - stpcpy strcasecmp strdup strtoul tsearch uselocale argz_count \ - argz_stringify argz_next __fsetlocking]) + stpcpy strcasecmp strdup strtoul tsearch argz_count argz_stringify \ + argz_next __fsetlocking]) - dnl Solaris 12 provides getlocalename_l, while Illumos doesn't have - dnl it nor the equivalent. - if test $ac_cv_func_uselocale = yes; then - AC_CHECK_FUNCS([getlocalename_l]) + dnl For Solaris 11.4 and 12. + gt_INTL_SOLARIS + if test $gt_nameless_locales = yes; then + HAVE_NAMELESS_LOCALES=1 + else + HAVE_NAMELESS_LOCALES=0 fi + AC_SUBST([HAVE_NAMELESS_LOCALES]) dnl Use the *_unlocked functions only if they are declared. dnl (because some of them were defined without being declared in Solaris diff --git a/m4/intlsolaris.m4 b/m4/intlsolaris.m4 index 2e3db7f..6d3ade4 100644 --- a/m4/intlsolaris.m4 +++ b/m4/intlsolaris.m4 @@ -1,4 +1,4 @@ -# intlsolaris.m4 serial 1 +# intlsolaris.m4 serial 2 dnl Copyright (C) 2015-2018 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -17,37 +17,49 @@ dnl Checks for special localename support needed on Solaris. dnl Sets gt_nameless_locales. AC_DEFUN([gt_INTL_SOLARIS], [ + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + dnl Persuade Solaris to define 'locale_t'. AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) AC_CHECK_FUNCS_ONCE([uselocale]) gt_nameless_locales=no - dnl Solaris 12 provides getlocalename_l, while Illumos doesn't have - dnl it nor the equivalent. + if test $ac_cv_func_uselocale = yes; then + AC_CACHE_CHECK([for Solaris 11.4 locale system], + [gt_cv_locale_solaris114], + [case "$host_os" in + solaris*) + dnl Test whether defines locale_t as a typedef of + dnl 'struct _LC_locale_t **' (whereas Illumos defines it as a + dnl typedef of 'struct _locale *'). + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ + #include + struct _LC_locale_t *x; + locale_t y; + ]], + [[*y = x;]])], + [gt_cv_locale_solaris114=yes], + [gt_cv_locale_solaris114=no]) + ;; + *) gt_cv_locale_solaris114=no ;; + esac + ]) + fi + if test $gt_cv_locale_solaris114 = yes; then + gt_nameless_locales=yes + AC_DEFINE([HAVE_NAMELESS_LOCALES], [1], + [Define if the locale_t type does not contain the name of each locale category.]) + fi + + dnl Solaris 12 will maybe provide getlocalename_l. If it does, it will + dnl simplify the implementation of gl_locale_name_thread(). But the overrides + dnl of newlocale, duplocale, freelocale will still be necessary, in order to + dnl keep the libintl_locale_hash_table up-to-date, which may be used by + dnl libintl or gnulib code that was compiled on Solaris 11.4, before + dnl getlocalename_l was introduced. if test $ac_cv_func_uselocale = yes; then AC_CHECK_FUNCS([getlocalename_l]) - if test $ac_cv_func_getlocalename_l != yes; then - AC_CACHE_CHECK([for Solaris 11.4 locale system], - [gt_cv_locale_solaris114], - [dnl Test whether defines locale_t as a typedef of - dnl 'struct _LC_locale_t **' (whereas Illumos defines it as a - dnl typedef of 'struct _locale *'). - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([[ - #include - struct _LC_locale_t *x; - locale_t y; - ]], - [[*y = x;]])], - [gt_cv_locale_solaris114=yes], - [gt_cv_locale_solaris114=no]) - ]) - if test $gt_cv_locale_solaris114 = yes; then - gt_nameless_locales=yes - AC_DEFINE([HAVE_NAMELESS_LOCALES], [1], - [Define if the locale_t type does not contain the name of each locale category.]) - fi - fi fi ]) diff --git a/modules/gettext b/modules/gettext index 8c94e2d..15cf53b 100644 --- a/modules/gettext +++ b/modules/gettext @@ -20,6 +20,7 @@ m4/intdiv0.m4 m4/intl.m4 m4/intldir.m4 m4/intlmacosx.m4 +m4/intlsolaris.m4 m4/intmax.m4 m4/inttypes_h.m4 m4/inttypes-pri.m4 diff --git a/modules/localename b/modules/localename index 29c4321..cb848b5 100644 --- a/modules/localename +++ b/modules/localename @@ -4,6 +4,8 @@ Return current locale's name, according to glibc naming conventions. Files: lib/localename.h lib/localename.c +lib/localename-table.h +lib/localename-table.c m4/localename.m4 m4/intlmacosx.m4 m4/intlsolaris.m4 @@ -22,7 +24,7 @@ gl_LOCALENAME gl_LOCALE_MODULE_INDICATOR([localename]) Makefile.am: -lib_SOURCES += localename.c +lib_SOURCES += localename.c localename-table.c Include: "localename.h" -- 2.7.4