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

Reply via email to