From 8406a53a2502e0896878bfc2fd5f5726be39604a Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Thu, 28 Apr 2005 18:21:03 +0000 Subject: * sysdeps/i386/i686/memcmp.S: Move misplaced END. 2005-03-27 Bruno Haible Make it possible for multiple threads to use gettext() in different locales. * intl/dcigettext.c (HAVE_PER_THREAD_LOCALE): New macro. (struct known_translation_t): If HAVE_PER_THREAD_LOCALE, add localename field. (transcmp): If HAVE_PER_THREAD_LOCALE, compare localename fields. (DCIGETTEXT): If HAVE_PER_THREAD_LOCALE, fill the localename field in search and newp. * intl/tst-gettext4.c: New file. * intl/tst-gettext4.sh: New file. * intl/tst-gettext4-de.po: New file. * intl/tst-gettext4-fr.po: New file. * intl/tst-gettext5.c: New file. * intl/tst-gettext5.sh: New file. * intl/Makefile (distribute): Add tst-gettext4.sh, tst-gettext4-de.po, tst-gettext4-fr.po, tst-gettext5.sh. (multithread-test-srcs): New variable. (test-srcs): Add its contents. (tests): Depend on tst-gettext4.out, tst-gettext5.out. (tst-gettext4.out, tst-gettext5.out): New rules. (CFLAGS-tst-gettext4.c, CFLAGS-tst-gettext5.c): New variables. Add rule for linking the multithread-test-srcs with the appropriate thread-library. 2005-04-28 Ulrich Drepper * po/rw.po: New file. From translation team. --- intl/Makefile | 34 ++++++++++- intl/dcigettext.c | 53 +++++++++++++--- intl/tst-gettext4-de.po | 8 +++ intl/tst-gettext4-fr.po | 8 +++ intl/tst-gettext4.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++ intl/tst-gettext4.sh | 48 +++++++++++++++ intl/tst-gettext5.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++ intl/tst-gettext5.sh | 46 ++++++++++++++ 8 files changed, 494 insertions(+), 10 deletions(-) create mode 100644 intl/tst-gettext4-de.po create mode 100644 intl/tst-gettext4-fr.po create mode 100644 intl/tst-gettext4.c create mode 100755 intl/tst-gettext4.sh create mode 100644 intl/tst-gettext5.c create mode 100755 intl/tst-gettext5.sh (limited to 'intl') diff --git a/intl/Makefile b/intl/Makefile index 81557a3457..19853974d7 100644 --- a/intl/Makefile +++ b/intl/Makefile @@ -30,9 +30,17 @@ distribute = gmo.h gettextP.h hash-string.h loadinfo.h locale.alias \ tst-translit.sh translit.po \ tst-gettext2.sh tstlang1.po tstlang2.po \ tst-codeset.sh tstcodeset.po \ - tst-gettext3.sh + tst-gettext3.sh \ + tst-gettext4.sh tst-gettext4-de.po tst-gettext4-fr.po \ + tst-gettext5.sh +include ../Makeconfig + +multithread-test-srcs := tst-gettext4 tst-gettext5 test-srcs := tst-gettext tst-translit tst-gettext2 tst-codeset tst-gettext3 +ifeq ($(have-thread-library),yes) +test-srcs += $(multithread-test-srcs) +endif tests = tst-ngettext before-compile = $(objpfx)msgs.h @@ -42,8 +50,6 @@ install-others = $(inst_msgcatdir)/locale.alias generated = msgs.h mtrace-tst-gettext tst-gettext.mtrace generated-dirs := domaindir localedir -include ../Makeconfig - ifneq (no,$(BISON)) plural.c: plural.y $(BISON) $(BISONFLAGS) $@ $^ @@ -60,6 +66,9 @@ ifeq (yes,$(build-shared)) ifneq ($(strip $(MSGFMT)),:) tests: $(objpfx)tst-translit.out $(objpfx)tst-gettext2.out \ $(objpfx)tst-codeset.out $(objpfx)tst-gettext3.out +ifeq ($(have-thread-library),yes) +tests: $(objpfx)tst-gettext4.out $(objpfx)tst-gettext5.out +endif ifneq (no,$(PERL)) tests: $(objpfx)mtrace-tst-gettext endif @@ -77,6 +86,10 @@ $(objpfx)tst-codeset.out: tst-codeset.sh $(objpfx)tst-codeset $(SHELL) -e $< $(common-objpfx) $(common-objpfx)intl/ $(objpfx)tst-gettext3.out: tst-gettext3.sh $(objpfx)tst-gettext3 $(SHELL) -e $< $(common-objpfx) $(common-objpfx)intl/ +$(objpfx)tst-gettext4.out: tst-gettext4.sh $(objpfx)tst-gettext4 + $(SHELL) -e $< $(common-objpfx) $(common-objpfx)intl/ +$(objpfx)tst-gettext5.out: tst-gettext5.sh $(objpfx)tst-gettext5 + $(SHELL) -e $< $(common-objpfx) $(common-objpfx)intl/ endif endif @@ -89,11 +102,26 @@ CFLAGS-tst-translit.c = -DOBJPFX=\"$(objpfx)\" CFLAGS-tst-gettext2.c = -DOBJPFX=\"$(objpfx)\" CFLAGS-tst-codeset.c = -DOBJPFX=\"$(objpfx)\" CFLAGS-tst-gettext3.c = -DOBJPFX=\"$(objpfx)\" +CFLAGS-tst-gettext4.c = -DOBJPFX=\"$(objpfx)\" +CFLAGS-tst-gettext5.c = -DOBJPFX=\"$(objpfx)\" + +ifeq ($(have-thread-library),yes) +ifeq (yes,$(build-shared)) +$(addprefix $(objpfx),$(multithread-test-srcs)): $(shared-thread-library) +else +$(addprefix $(objpfx),$(multithread-test-srcs)): $(static-thread-library) +endif +ifeq (yes,$(build-bounded)) +$(multithread-test-srcs:%=$(objpfx)%-bp): $(bounded-thread-library) +endif +endif $(objpfx)tst-translit.out: $(objpfx)tst-gettext.out $(objpfx)tst-gettext2.out: $(objpfx)tst-gettext.out $(objpfx)tst-codeset.out: $(objpfx)tst-gettext.out $(objpfx)tst-gettext3.out: $(objpfx)tst-gettext.out +$(objpfx)tst-gettext4.out: $(objpfx)tst-gettext.out +$(objpfx)tst-gettext5.out: $(objpfx)tst-gettext.out CPPFLAGS += -D'LOCALEDIR="$(msgcatdir)"' \ -D'LOCALE_ALIAS_PATH="$(msgcatdir)"' diff --git a/intl/dcigettext.c b/intl/dcigettext.c index c73c719d94..f294dedf2f 100644 --- a/intl/dcigettext.c +++ b/intl/dcigettext.c @@ -172,6 +172,11 @@ static void *mempcpy PARAMS ((void *dest, const void *src, size_t n)); # define PATH_MAX _POSIX_PATH_MAX #endif +/* Whether to support different locales in different threads. */ +#if defined _LIBC || HAVE_NL_LOCALE_NAME +# define HAVE_PER_THREAD_LOCALE +#endif + /* This is the type used for the search tree where known translations are stored. */ struct known_translation_t @@ -182,6 +187,11 @@ struct known_translation_t /* The category. */ int category; +#ifdef HAVE_PER_THREAD_LOCALE + /* Name of the relevant locale category, or "" for the global locale. */ + const char *localename; +#endif + /* State of the catalog counter at the point the string was found. */ int counter; @@ -226,10 +236,16 @@ transcmp (p1, p2) { result = strcmp (s1->domainname, s2->domainname); if (result == 0) - /* We compare the category last (though this is the cheapest - operation) since it is hopefully always the same (namely - LC_MESSAGES). */ - result = s1->category - s2->category; + { +#ifdef HAVE_PER_THREAD_LOCALE + result = strcmp (s1->localename, s2->localename); + if (result == 0) +#endif + /* We compare the category last (though this is the cheapest + operation) since it is hopefully always the same (namely + LC_MESSAGES). */ + result = s1->category - s2->category; + } } return result; @@ -408,6 +424,9 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category) struct known_translation_t *search; struct known_translation_t **foundp = NULL; size_t msgid_len; +# ifdef HAVE_PER_THREAD_LOCALE + const char *localename; +# endif #endif size_t domainname_len; @@ -442,6 +461,12 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category) memcpy (search->msgid, msgid1, msgid_len); search->domainname = domainname; search->category = category; +# ifdef HAVE_PER_THREAD_LOCALE +# ifdef _LIBC + localename = __current_locale_name (category); +# endif + search->localename = localename; +# endif /* Since tfind/tsearch manage a balanced tree, concurrent tfind and tsearch calls can be fatal. */ @@ -629,19 +654,33 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category) if (foundp == NULL) { /* Create a new entry and add it to the search tree. */ + size_t size; struct known_translation_t *newp; - newp = (struct known_translation_t *) - malloc (offsetof (struct known_translation_t, msgid) - + msgid_len + domainname_len + 1); + size = offsetof (struct known_translation_t, msgid) + + msgid_len + domainname_len + 1; +# ifdef HAVE_PER_THREAD_LOCALE + size += strlen (localename) + 1; +# endif + newp = (struct known_translation_t *) malloc (size); if (newp != NULL) { char *new_domainname; +# ifdef HAVE_PER_THREAD_LOCALE + char *new_localename; +# endif new_domainname = mempcpy (newp->msgid, msgid1, msgid_len); memcpy (new_domainname, domainname, domainname_len + 1); +# ifdef HAVE_PER_THREAD_LOCALE + new_localename = new_domainname + domainname_len + 1; + strcpy (new_localename, localename); +# endif newp->domainname = new_domainname; newp->category = category; +# ifdef HAVE_PER_THREAD_LOCALE + newp->localename = new_localename; +# endif newp->counter = _nl_msg_cat_cntr; newp->domain = domain; newp->translation = retval; diff --git a/intl/tst-gettext4-de.po b/intl/tst-gettext4-de.po new file mode 100644 index 0000000000..0a8d099398 --- /dev/null +++ b/intl/tst-gettext4-de.po @@ -0,0 +1,8 @@ +msgid "" +msgstr "" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8-bit\n" + +msgid "beauty" +msgstr "Schönheit" diff --git a/intl/tst-gettext4-fr.po b/intl/tst-gettext4-fr.po new file mode 100644 index 0000000000..8332c2d9f8 --- /dev/null +++ b/intl/tst-gettext4-fr.po @@ -0,0 +1,8 @@ +msgid "" +msgstr "" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8-bit\n" + +msgid "beauty" +msgstr "beauté" diff --git a/intl/tst-gettext4.c b/intl/tst-gettext4.c new file mode 100644 index 0000000000..a82446d14c --- /dev/null +++ b/intl/tst-gettext4.c @@ -0,0 +1,151 @@ +/* Test that gettext() in multithreaded applications works correctly if + different threads operate in different locales with the same encoding. + Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Bruno Haible , 2005. + + 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 +#include +#include +#include +#include +#include + +/* Set to 1 if the program is not behaving correctly. */ +int result; + +/* Denotes which thread should run next. */ +int flipflop; +/* Lock and wait queue used to switch between the threads. */ +pthread_mutex_t lock; +pthread_cond_t waitqueue; + +/* Waits until the flipflop has a given value. + Before the call, the lock is unlocked. After the call, it is locked. */ +static void +waitfor (int value) +{ + if (pthread_mutex_lock (&lock)) + exit (10); + while (flipflop != value) + if (pthread_cond_wait (&waitqueue, &lock)) + exit (11); +} + +/* Sets the flipflop to a given value. + Before the call, the lock is locked. After the call, it is unlocked. */ +static void +setto (int value) +{ + flipflop = value; + if (pthread_cond_signal (&waitqueue)) + exit (20); + if (pthread_mutex_unlock (&lock)) + exit (21); +} + +void * +thread1_execution (void *arg) +{ + char *s; + + waitfor (1); + uselocale (newlocale (LC_ALL_MASK, "de_DE.ISO-8859-1", NULL)); + setto (2); + + waitfor (1); + s = gettext ("beauty"); + puts (s); + if (strcmp (s, "Sch\366nheit")) + { + fprintf (stderr, "thread 1 call 1 returned: %s\n", s); + result = 1; + } + setto (2); + + waitfor (1); + s = gettext ("beauty"); + puts (s); + if (strcmp (s, "Sch\366nheit")) + { + fprintf (stderr, "thread 1 call 2 returned: %s\n", s); + result = 1; + } + setto (2); + + return NULL; +} + +void * +thread2_execution (void *arg) +{ + char *s; + + waitfor (2); + uselocale (newlocale (LC_ALL_MASK, "fr_FR.ISO-8859-1", NULL)); + setto (1); + + waitfor (2); + s = gettext ("beauty"); + puts (s); + if (strcmp (s, "beaut\351")) + { + fprintf (stderr, "thread 2 call 1 returned: %s\n", s); + result = 1; + } + setto (1); + + waitfor (2); + s = gettext ("beauty"); + puts (s); + if (strcmp (s, "beaut\351")) + { + fprintf (stderr, "thread 2 call 2 returned: %s\n", s); + result = 1; + } + setto (1); + + return NULL; +} + +int +main (void) +{ + pthread_t thread1; + pthread_t thread2; + + unsetenv ("LANGUAGE"); + unsetenv ("OUTPUT_CHARSET"); + textdomain ("multithread"); + bindtextdomain ("multithread", OBJPFX "domaindir"); + result = 0; + + flipflop = 1; + if (pthread_mutex_init (&lock, NULL)) + exit (2); + if (pthread_cond_init (&waitqueue, NULL)) + exit (2); + if (pthread_create (&thread1, NULL, &thread1_execution, NULL)) + exit (2); + if (pthread_create (&thread2, NULL, &thread2_execution, NULL)) + exit (2); + if (pthread_join (thread2, NULL)) + exit (3); + + return result; +} diff --git a/intl/tst-gettext4.sh b/intl/tst-gettext4.sh new file mode 100755 index 0000000000..8acdd37882 --- /dev/null +++ b/intl/tst-gettext4.sh @@ -0,0 +1,48 @@ +#! /bin/sh +# Test that gettext() in multithreaded applications works correctly if +# different threads operate in different locales with the same encoding. +# Copyright (C) 2001, 2002, 2005 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. + +common_objpfx=$1 +objpfx=$2 + +LC_ALL=C +export LC_ALL + +# Generate the test data. +test -d ${objpfx}domaindir || mkdir ${objpfx}domaindir +# Create the domain directories. +test -d ${objpfx}domaindir/de_DE || mkdir ${objpfx}domaindir/de_DE +test -d ${objpfx}domaindir/de_DE/LC_MESSAGES || mkdir ${objpfx}domaindir/de_DE/LC_MESSAGES +test -d ${objpfx}domaindir/fr_FR || mkdir ${objpfx}domaindir/fr_FR +test -d ${objpfx}domaindir/fr_FR/LC_MESSAGES || mkdir ${objpfx}domaindir/fr_FR/LC_MESSAGES +# Populate them. +msgfmt -o ${objpfx}domaindir/de_DE/LC_MESSAGES/multithread.mo tst-gettext4-de.po +msgfmt -o ${objpfx}domaindir/fr_FR/LC_MESSAGES/multithread.mo tst-gettext4-fr.po + +GCONV_PATH=${common_objpfx}iconvdata +export GCONV_PATH +LOCPATH=${common_objpfx}localedata +export LOCPATH + +${common_objpfx}elf/ld.so --library-path $common_objpfx \ +${objpfx}tst-gettext4 > ${objpfx}tst-gettext4.out + +exit $? diff --git a/intl/tst-gettext5.c b/intl/tst-gettext5.c new file mode 100644 index 0000000000..498ecab790 --- /dev/null +++ b/intl/tst-gettext5.c @@ -0,0 +1,156 @@ +/* Test that gettext() in multithreaded applications works correctly if + different threads operate in different locales referring to the same + catalog file but with different encodings. + Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Bruno Haible , 2005. + + 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 +#include +#include +#include +#include +#include + +/* Set to 1 if the program is not behaving correctly. */ +int result; + +/* Denotes which thread should run next. */ +int flipflop; +/* Lock and wait queue used to switch between the threads. */ +pthread_mutex_t lock; +pthread_cond_t waitqueue; + +/* Waits until the flipflop has a given value. + Before the call, the lock is unlocked. After the call, it is locked. */ +static void +waitfor (int value) +{ + if (pthread_mutex_lock (&lock)) + exit (10); + while (flipflop != value) + if (pthread_cond_wait (&waitqueue, &lock)) + exit (11); +} + +/* Sets the flipflop to a given value. + Before the call, the lock is locked. After the call, it is unlocked. */ +static void +setto (int value) +{ + flipflop = value; + if (pthread_cond_signal (&waitqueue)) + exit (20); + if (pthread_mutex_unlock (&lock)) + exit (21); +} + +void * +thread1_execution (void *arg) +{ + char *s; + + waitfor (1); + uselocale (newlocale (LC_ALL_MASK, "de_DE.ISO-8859-1", NULL)); + setto (2); + + /* Here we expect output in ISO-8859-1. */ + + waitfor (1); + s = gettext ("cheese"); + puts (s); + if (strcmp (s, "K\344se")) + { + fprintf (stderr, "thread 1 call 1 returned: %s\n", s); + result = 1; + } + setto (2); + + waitfor (1); + s = gettext ("cheese"); + puts (s); + if (strcmp (s, "K\344se")) + { + fprintf (stderr, "thread 1 call 2 returned: %s\n", s); + result = 1; + } + setto (2); + + return NULL; +} + +void * +thread2_execution (void *arg) +{ + char *s; + + waitfor (2); + uselocale (newlocale (LC_ALL_MASK, "de_DE.UTF-8", NULL)); + setto (1); + + /* Here we expect output in UTF-8. */ + + waitfor (2); + s = gettext ("cheese"); + puts (s); + if (strcmp (s, "K\303\244se")) + { + fprintf (stderr, "thread 2 call 1 returned: %s\n", s); + result = 1; + } + setto (1); + + waitfor (2); + s = gettext ("cheese"); + puts (s); + if (strcmp (s, "K\303\244se")) + { + fprintf (stderr, "thread 2 call 2 returned: %s\n", s); + result = 1; + } + setto (1); + + return NULL; +} + +int +main (void) +{ + pthread_t thread1; + pthread_t thread2; + + unsetenv ("LANGUAGE"); + unsetenv ("OUTPUT_CHARSET"); + textdomain ("codeset"); + bindtextdomain ("codeset", OBJPFX "domaindir"); + result = 0; + + flipflop = 1; + if (pthread_mutex_init (&lock, NULL)) + exit (2); + if (pthread_cond_init (&waitqueue, NULL)) + exit (2); + if (pthread_create (&thread1, NULL, &thread1_execution, NULL)) + exit (2); + if (pthread_create (&thread2, NULL, &thread2_execution, NULL)) + exit (2); + if (pthread_join (thread2, NULL)) + exit (3); + + return result; +} diff --git a/intl/tst-gettext5.sh b/intl/tst-gettext5.sh new file mode 100755 index 0000000000..bbc58e796f --- /dev/null +++ b/intl/tst-gettext5.sh @@ -0,0 +1,46 @@ +#! /bin/sh +# Test that gettext() in multithreaded applications works correctly if +# different threads operate in different locales referring to the same +# catalog file but with different encodings. +# Copyright (C) 2001, 2002, 2005 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. + +common_objpfx=$1 +objpfx=$2 + +LC_ALL=C +export LC_ALL + +# Generate the test data. +test -d ${objpfx}domaindir || mkdir ${objpfx}domaindir +# Create the domain directories. +test -d ${objpfx}domaindir/de_DE || mkdir ${objpfx}domaindir/de_DE +test -d ${objpfx}domaindir/de_DE/LC_MESSAGES || mkdir ${objpfx}domaindir/de_DE/LC_MESSAGES +# Populate them. +msgfmt -o ${objpfx}domaindir/de_DE/LC_MESSAGES/codeset.mo tstcodeset.po + +GCONV_PATH=${common_objpfx}iconvdata +export GCONV_PATH +LOCPATH=${common_objpfx}localedata +export LOCPATH + +${common_objpfx}elf/ld.so --library-path $common_objpfx \ +${objpfx}tst-gettext5 > ${objpfx}tst-gettext5.out + +exit $? -- cgit 1.4.1