+2005-05-05 Bruno Haible <bruno@clisp.org>
+
+ * dcigettext.c (__libc_rwlock_wrlock): Define fallback.
+ * finddomain.c (__libc_rwlock_define_initialized,
+ __libc_rwlock_rdlock, __libc_rwlock_wrlock, __libc_rwlock_unlock):
+ Define fallbacks.
+ * loadmsgcat.c (__libc_lock_define_initialized_recursive,
+ __libc_lock_lock_recursive, __libc_lock_unlock_recursive): Define
+ fallbacks.
+ (_nl_load_domain): Fix portability problems in last patch.
+
+2004-09-25 Ulrich Drepper <drepper@redhat.com>
+
+ * dcigettext.c (DCIGETTEXT): Protect tfind/tsearch calls.
+ * dcigettext.c (_nl_find_msg): Call _nl_load_domain also if
+ decided < 0.
+ * finddomain.c (_nl_find_domain): Likewise.
+ * loadmsgcat.c (_nl_load_domain): Set decided to 1 only once we
+ are done. First set to -1 to signal initialization is ongoing.
+ Protect against concurrent callers with recursive lock.
+ * finddomain.c (_nl_find_domain): Protect calls to
+ _nl_make_l10nflist. [BZ #322]
+
2004-08-06 Jakub Jelinek <jakub@redhat.com>
* finddomain.c (free_mem): Rename to...
# define __libc_lock_unlock(NAME)
# define __libc_rwlock_define_initialized(CLASS, NAME)
# define __libc_rwlock_rdlock(NAME)
+# define __libc_rwlock_wrlock(NAME)
# define __libc_rwlock_unlock(NAME)
#endif
search->localename = localename;
# endif
+ /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
+ tsearch calls can be fatal. */
+ __libc_rwlock_define_initialized (static, tree_lock);
+ __libc_rwlock_rdlock (tree_lock);
+
foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
+
+ __libc_rwlock_unlock (tree_lock);
+
freea (search);
if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
{
newp->translation = retval;
newp->translation_length = retlen;
+ __libc_rwlock_wrlock (tree_lock);
+
/* Insert the entry in the search tree. */
foundp = (struct known_translation_t **)
tsearch (newp, &root, transcmp);
+
+ __libc_rwlock_unlock (tree_lock);
+
if (foundp == NULL
|| __builtin_expect (*foundp != newp, 0))
/* The insert failed. */
char *result;
size_t resultlen;
- if (domain_file->decided == 0)
+ if (domain_file->decided <= 0)
_nl_load_domain (domain_file, domainbinding);
if (domain_file->data == NULL)
/* Handle list of needed message catalogs
- Copyright (C) 1995-1999, 2000-2001, 2003-2004 Free Software Foundation, Inc.
+ Copyright (C) 1995-1999, 2000-2001, 2003-2005 Free Software Foundation, Inc.
Written by Ulrich Drepper <drepper@gnu.org>, 1995.
This program is free software; you can redistribute it and/or modify it
# include "libgnuintl.h"
#endif
+#ifdef _LIBC
+# include <bits/libc-lock.h>
+#else
+# define __libc_rwlock_define_initialized(CLASS, NAME)
+# define __libc_rwlock_rdlock(NAME)
+# define __libc_rwlock_wrlock(NAME)
+# define __libc_rwlock_unlock(NAME)
+#endif
+
/* @@ end of prolog @@ */
/* List of already loaded domains. */
static struct loaded_l10nfile *_nl_loaded_domains;
(7) audience/modifier
*/
+ /* We need to protect modifying the _NL_LOADED_DOMAINS data. */
+ __libc_rwlock_define_initialized (static, lock);
+ __libc_rwlock_rdlock (lock);
+
/* If we have already tested for this locale entry there has to
be one data set in the list of loaded domains. */
retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
strlen (dirname) + 1, 0, locale, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, domainname, 0);
+
+ __libc_rwlock_unlock (lock);
+
if (retval != NULL)
{
/* We know something about this locale. */
int cnt;
- if (retval->decided == 0)
+ if (retval->decided <= 0)
_nl_load_domain (retval, domainbinding);
if (retval->data != NULL)
for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
{
- if (retval->successor[cnt]->decided == 0)
+ if (retval->successor[cnt]->decided <= 0)
_nl_load_domain (retval->successor[cnt], domainbinding);
if (retval->successor[cnt]->data != NULL)
break;
}
+
return cnt >= 0 ? retval : NULL;
/* NOTREACHED */
}
&codeset, &normalized_codeset, &special,
&sponsor, &revision);
+ /* We need to protect modifying the _NL_LOADED_DOMAINS data. */
+ __libc_rwlock_wrlock (lock);
+
/* Create all possible locale entries which might be interested in
generalization. */
retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
strlen (dirname) + 1, mask, language, territory,
codeset, normalized_codeset, modifier, special,
sponsor, revision, domainname, 1);
+
+ __libc_rwlock_unlock (lock);
+
if (retval == NULL)
/* This means we are out of core. */
return NULL;
- if (retval->decided == 0)
+ if (retval->decided <= 0)
_nl_load_domain (retval, domainbinding);
if (retval->data == NULL)
{
int cnt;
for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
{
- if (retval->successor[cnt]->decided == 0)
+ if (retval->successor[cnt]->decided <= 0)
_nl_load_domain (retval->successor[cnt], domainbinding);
if (retval->successor[cnt]->data != NULL)
break;
#ifdef _LIBC
# include "../locale/localeinfo.h"
# include <not-cancel.h>
+# include <bits/libc-lock.h>
+#else
+# define __libc_lock_define_initialized_recursive(CLASS, NAME)
+# define __libc_lock_lock_recursive(NAME)
+# define __libc_lock_unlock_recursive(NAME)
#endif
/* Provide fallback values for macros that ought to be defined in <inttypes.h>.
_nl_load_domain (struct loaded_l10nfile *domain_file,
struct binding *domainbinding)
{
- int fd;
+ __libc_lock_define_initialized_recursive (static, lock);
+ int fd = -1;
size_t size;
#ifdef _LIBC
struct stat64 st;
const char *nullentry;
size_t nullentrylen;
- domain_file->decided = 1;
+ __libc_lock_lock_recursive (lock);
+ if (domain_file->decided != 0)
+ {
+ /* There are two possibilities:
+
+ + this is the same thread calling again during this initialization
+ via _nl_find_msg. We have initialized everything this call needs.
+
+ + this is another thread which tried to initialize this object.
+ Not necessary anymore since if the lock is available this
+ is finished.
+ */
+ goto done;
+ }
+
+ domain_file->decided = -1;
domain_file->data = NULL;
/* Note that it would be useless to store domainbinding in domain_file
specification the locale file name is different for XPG and CEN
syntax. */
if (domain_file->filename == NULL)
- return;
+ goto out;
/* Try to open the addressed file. */
fd = open (domain_file->filename, O_RDONLY | O_BINARY);
if (fd == -1)
- return;
+ goto out;
/* We must know about the size of the file. */
if (
#endif
|| __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
|| __builtin_expect (size < sizeof (struct mo_file_header), 0))
- {
- /* Something went wrong. */
- close (fd);
- return;
- }
+ /* Something went wrong. */
+ goto out;
#ifdef HAVE_MMAP
/* Now we are ready to load the file. If mmap() is available we try
{
/* mmap() call was successful. */
close (fd);
+ fd = -1;
use_mmap = 1;
}
#endif
data = (struct mo_file_header *) malloc (size);
if (data == NULL)
- return;
+ goto out;
to_read = size;
read_ptr = (char *) data;
if (nb == -1 && errno == EINTR)
continue;
#endif
- close (fd);
- return;
+ goto out;
}
read_ptr += nb;
to_read -= nb;
while (to_read > 0);
close (fd);
+ fd = -1;
}
/* Using the magic number we can test whether it really is a message
else
#endif
free (data);
- return;
+ goto out;
}
domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
if (domain == NULL)
- return;
+ goto out;
domain_file->data = domain;
domain->data = (char *) data;
free (data);
free (domain);
domain_file->data = NULL;
- return;
+ goto out;
}
/* No caches of converted translations so far. */
/* Get the header entry and look for a plural specification. */
nullentry = _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
+
+ out:
+ if (fd != -1)
+ close (fd);
+
+ domain_file->decided = 1;
+
+ done:
+ __libc_lock_unlock_recursive (lock);
}