localetable_head is used in libc/locale/setrunelocale.c for caching
previously loaded ctype locale (we keep a copy of every loaded
runelocale).
- it is a static variable that hold a list.
- _findrunelocale() is used for search in this list.
- _newrunelocale() will add a new item in the list (add in front of
list), if it isn't already in the list.
In order to prevent race that would result adding multiple times the
same runelocale in the list (by multiple threads) I use a mutex in
_newrunelocale() to protect all the adding code path.
--
Sebastien Marie
Index: b/lib/libc/locale/setrunelocale.c
===================================================================
--- a/lib/libc/locale/setrunelocale.c 2015-07-09 08:12:38.659210133 +0200
+++ b/lib/libc/locale/setrunelocale.c 2015-07-09 09:48:35.757157373 +0200
@@ -102,6 +102,7 @@
#include "citrus_ctype.h"
#include "rune.h"
#include "rune_local.h"
+#include "thread_private.h"
#include "xlocale_private.h"
struct localetable {
@@ -110,6 +111,7 @@
struct localetable *next;
};
static struct localetable *localetable_head;
+_THREAD_PRIVATE_MUTEX(localetable_head);
_RuneLocale *
_findrunelocale(const char *path)
@@ -130,22 +132,27 @@
struct localetable *lt;
FILE *fp;
_RuneLocale *rl;
+ int ret = 0;
if (strlen(path) + 1 > sizeof(lt->path))
return EINVAL;
+ _THREAD_PRIVATE_MUTEX_LOCK(localetable_head);
rl = _findrunelocale(path);
if (rl)
- return 0;
+ goto out; /* ret = 0 */
- if ((fp = fopen(path, "re")) == NULL)
- return ENOENT;
+ if ((fp = fopen(path, "re")) == NULL) {
+ ret = ENOENT;
+ goto out;
+ }
if ((rl = _Read_RuneMagi(fp)) != NULL)
goto found;
fclose(fp);
- return EFTYPE;
+ ret = EFTYPE;
+ goto out;
found:
fclose(fp);
@@ -154,21 +161,25 @@
if (_citrus_ctype_open(&rl->rl_citrus_ctype, rl->rl_encoding)) {
_NukeRune(rl);
- return EINVAL;
+ ret = EINVAL;
+ goto out;
}
/* register it */
lt = malloc(sizeof(struct localetable));
if (lt == NULL) {
_NukeRune(rl);
- return ENOMEM;
+ ret = ENOMEM;
+ goto out;
}
strlcpy(lt->path, path, sizeof(lt->path));
lt->runelocale = rl;
lt->next = localetable_head;
localetable_head = lt;
- return 0;
+out:
+ _THREAD_PRIVATE_MUTEX_UNLOCK(localetable_head);
+ return ret;
}
int