about summary refs log tree commit diff
path: root/intl/dcigettext.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2008-03-30 23:40:18 +0000
committerUlrich Drepper <drepper@redhat.com>2008-03-30 23:40:18 +0000
commit2ecc7d93b88b5b9e8ef5833c541d2db1c4608799 (patch)
treef404523e0a8d3fc70746d2a38cb31574fd1f30aa /intl/dcigettext.c
parentfaa091c673792ef8d148e1d2117c853da8a961a8 (diff)
downloadglibc-2ecc7d93b88b5b9e8ef5833c541d2db1c4608799.tar.gz
glibc-2ecc7d93b88b5b9e8ef5833c541d2db1c4608799.tar.xz
glibc-2ecc7d93b88b5b9e8ef5833c541d2db1c4608799.zip
* intl/dcigettext.c (_nl_find_msg): Reread nconversions after
	acquiring wrlock.  Do conv_tab allocation while holding lock.
	* intl/Makefile: Add rules to build and run tst-gettext6.
	* intl/tst-gettext6.c: New test.
	* intl/tst-gettext6.sh: New file.
Diffstat (limited to 'intl/dcigettext.c')
-rw-r--r--intl/dcigettext.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/intl/dcigettext.c b/intl/dcigettext.c
index 7004cd49cf..f8a0311f68 100644
--- a/intl/dcigettext.c
+++ b/intl/dcigettext.c
@@ -879,6 +879,7 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
 	{
 	  /* We have to allocate a new conversions table.  */
 	  __libc_rwlock_wrlock (domain->conversions_lock);
+	  nconversions = domain->nconversions;
 
 	  /* Maybe in the meantime somebody added the translation.
 	     Recheck.  */
@@ -1033,6 +1034,7 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
 # endif
 	  )
 	{
+	  __libc_lock_define_initialized (static, lock)
 	  /* We are supposed to do a conversion.  First allocate an
 	     appropriate table with the same structure as the table
 	     of translations in the file, where we can put the pointers
@@ -1042,13 +1044,21 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
 	     handle this case by converting RESULTLEN bytes, including
 	     NULs.  */
 
-	  if (convd->conv_tab == NULL
-	      && ((convd->conv_tab =
-		    (char **) calloc (nstrings + domain->n_sysdep_strings,
-				      sizeof (char *)))
-		  == NULL))
-	    /* Mark that we didn't succeed allocating a table.  */
-	    convd->conv_tab = (char **) -1;
+	  if (__builtin_expect (convd->conv_tab == NULL, 0))
+	    {
+	      __libc_lock_lock (lock);
+	      if (convd->conv_tab == NULL)
+		{
+		  convd->conv_tab
+		    = calloc (nstrings + domain->n_sysdep_strings,
+			      sizeof (char *));
+		  if (convd->conv_tab != NULL)
+		    goto not_translated_yet;
+		  /* Mark that we didn't succeed allocating a table.  */
+		  convd->conv_tab = (char **) -1;
+		}
+	      __libc_lock_unlock (lock);
+	    }
 
 	  if (__builtin_expect (convd->conv_tab == (char **) -1, 0))
 	    /* Nothing we can do, no more memory.  We cannot use the
@@ -1057,12 +1067,14 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
 
 	  if (convd->conv_tab[act] == NULL)
 	    {
+	      __libc_lock_lock (lock);
+	    not_translated_yet:;
+
 	      /* We haven't used this string so far, so it is not
 		 translated yet.  Do this now.  */
 	      /* We use a bit more efficient memory handling.
 		 We allocate always larger blocks which get used over
 		 time.  This is faster than many small allocations.   */
-	      __libc_lock_define_initialized (static, lock)
 # define INITIAL_BLOCK_SIZE	4080
 	      static unsigned char *freemem;
 	      static size_t freemem_size;
@@ -1074,8 +1086,6 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
 	      transmem_block_t *transmem_list = NULL;
 # endif
 
-	      __libc_lock_lock (lock);
-
 	      inbuf = (const unsigned char *) result;
 	      outbuf = freemem + sizeof (size_t);