This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Name individual locale locks
authorKarl Williamson <khw@cpan.org>
Mon, 30 Nov 2020 17:11:01 +0000 (10:11 -0700)
committerKarl Williamson <khw@cpan.org>
Tue, 8 Dec 2020 13:44:20 +0000 (06:44 -0700)
These locks for different functions all use the same underlying mutex;
but that may not always be the case.  By creating separate names
used only when we think they will be necessary, the compiler will
complain if the conditions in the code that actually use them are the
same.  Doing this showed a misspelling in an #ifdef, fixed in
9289d4dc7a3d24b20c6e25045e687321ee3e8faf

ext/POSIX/POSIX.xs
locale.c
perl.h

index 0f750c0..6bd30e8 100644 (file)
@@ -3376,9 +3376,9 @@ mblen(s, n = ~0)
             memzero(&PL_mbrlen_ps, sizeof(PL_mbrlen_ps));
             RETVAL = 0;
 #else
-            LOCALE_LOCK;
+            MBLEN_LOCK;
             RETVAL = mblen(NULL, 0);
-            LOCALE_UNLOCK;
+            MBLEN_UNLOCK;
 #endif
         }
         else {  /* Not resetting state */
@@ -3398,9 +3398,9 @@ mblen(s, n = ~0)
 #else
                 /* Locking prevents races, but locales can be switched out
                  * without locking, so this isn't a cure all */
-                LOCALE_LOCK;
+                MBLEN_LOCK;
                 RETVAL = mblen(string, len);
-                LOCALE_UNLOCK;
+                MBLEN_UNLOCK;
 #endif
             }
         }
@@ -3427,9 +3427,9 @@ mbtowc(pwc, s, n = ~0)
             memzero(&PL_mbrtowc_ps, sizeof(PL_mbrtowc_ps));
             RETVAL = 0;
 #else
-            LOCALE_LOCK;
+            MBTOWC_LOCK;
             RETVAL = mbtowc(NULL, NULL, 0);
-            LOCALE_UNLOCK;
+            MBTOWC_UNLOCK;
 #endif
         }
         else {  /* Not resetting state */
@@ -3448,9 +3448,9 @@ mbtowc(pwc, s, n = ~0)
 #else
                 /* Locking prevents races, but locales can be switched out
                  * without locking, so this isn't a cure all */
-                LOCALE_LOCK;
+                MBTOWC_LOCK;
                 RETVAL = mbtowc(&wc, string, len);
-                LOCALE_UNLOCK;
+                MBTOWC_UNLOCK;
 #endif
                 if (RETVAL >= 0) {
                     sv_setiv_mg(pwc, wc);
@@ -3482,9 +3482,9 @@ wctomb(s, wchar)
              * But probably memzero would too */
             RETVAL = wcrtomb(NULL, L'\0', &PL_wcrtomb_ps);
 #else
-            LOCALE_LOCK;
+            WCTOMB_LOCK;
             RETVAL = wctomb(NULL, L'\0');
-            LOCALE_UNLOCK;
+            WCTOMB_UNLOCK;
 #endif
         }
         else {  /* Not resetting state */
@@ -3494,9 +3494,9 @@ wctomb(s, wchar)
 #else
             /* Locking prevents races, but locales can be switched out without
              * locking, so this isn't a cure all */
-            LOCALE_LOCK;
+            WCTOMB_LOCK;
             RETVAL = wctomb(buffer, wchar);
-            LOCALE_UNLOCK;
+            WCTOMB_UNLOCK;
 #endif
             if (RETVAL >= 0) {
                 sv_setpvn_mg(s, buffer, RETVAL);
index 5dea47f..e43de9f 100644 (file)
--- a/locale.c
+++ b/locale.c
@@ -1227,10 +1227,10 @@ S_emulate_setlocale(const int category,
  * correct locale for that thread.  Any operation that was locale-sensitive
  * would have to be changed so that it would look like this:
  *
- *      LOCALE_LOCK;
+ *      SETLOCALE_LOCK;
  *      setlocale to the correct locale for this operation
  *      do operation
- *      LOCALE_UNLOCK
+ *      SETLOCALE_UNLOCK
  *
  * This leaves the global locale in the most recently used operation's, but it
  * was locked long enough to get the result.  If that result is static, it
@@ -1323,7 +1323,7 @@ S_locking_setlocale(pTHX_
 
     /* It might be that this is called from an already-locked section of code.
      * We would have to detect and skip the LOCK/UNLOCK if so */
-    LOCALE_LOCK;
+    SETLOCALE_LOCK;
 
     curlocales[index] = savepv(my_setlocale(category, new_locale));
 
@@ -1345,7 +1345,7 @@ S_locking_setlocale(pTHX_
 
 #endif
 
-    LOCALE_UNLOCK;
+    SETLOCALE_UNLOCK;
 
     return curlocales[index];
 }
@@ -2634,18 +2634,16 @@ S_my_nl_langinfo(const int item, bool toggle)
             STORE_LC_NUMERIC_FORCE_TO_UNDERLYING();
         }
 
-        LOCALE_LOCK;    /* Prevent interference from another thread executing
-                           this code section (the only call to nl_langinfo in
-                           the core) */
-
+        /* Prevent interference from another thread executing this code
+         * section. */
+        NL_LANGINFO_LOCK;
 
         /* Copy to a per-thread buffer, which is also one that won't be
          * destroyed by a subsequent setlocale(), such as the
          * RESTORE_LC_NUMERIC may do just below. */
         retval = save_to_buffer(nl_langinfo(item),
                                 &PL_langinfo_buf, &PL_langinfo_bufsize, 0);
-
-        LOCALE_UNLOCK;
+        NL_LANGINFO_UNLOCK;
 
         if (toggle) {
             RESTORE_LC_NUMERIC();
@@ -3041,7 +3039,7 @@ S_my_nl_langinfo(const int item, bool toggle)
             case MON_5: case MON_6: case MON_7: case MON_8:
             case MON_9: case MON_10: case MON_11: case MON_12:
 
-                LOCALE_LOCK;
+                LOCALE_LOCK_;
 
                 init_tm(&tm);   /* Precaution against core dumps */
                 tm.tm_sec = 30;
@@ -3052,7 +3050,7 @@ S_my_nl_langinfo(const int item, bool toggle)
                 tm.tm_mon = 0;
                 switch (item) {
                     default:
-                        LOCALE_UNLOCK;
+                        LOCALE_UNLOCK_;
                         Perl_croak(aTHX_
                                     "panic: %s: %d: switch case: %d problem",
                                        __FILE__, __LINE__, item);
@@ -3228,7 +3226,7 @@ S_my_nl_langinfo(const int item, bool toggle)
                  * wday was chosen because its range is all a single digit.
                  * Things like tm_sec have two digits as the minimum: '00' */
 
-                LOCALE_UNLOCK;
+                LOCALE_UNLOCK_;
 
                 retval = PL_langinfo_buf;
 
@@ -4844,12 +4842,12 @@ Perl__is_cur_LC_category_utf8(pTHX_ int category)
 
 #      else
 
-            LOCALE_LOCK;
+            MBTOWC_LOCK;
             PERL_UNUSED_RESULT(mbtowc(&wc, NULL, 0));/* Reset any shift state */
             SETERRNO(0, 0);
             len = mbtowc(&wc, STR_WITH_LEN(REPLACEMENT_CHARACTER_UTF8));
             SAVE_ERRNO;
-            LOCALE_UNLOCK;
+            MBTOWC_UNLOCK;
 
 #      endif
 
@@ -5357,7 +5355,7 @@ Perl_my_strerror(pTHX_ const int errnum)
      * same code at the same time.  (On thread-safe perls, the LOCK is a
      * no-op.)  Since this is the only place in core that changes LC_MESSAGES
      * (unless the user has called setlocale(), this works to prevent races. */
-    LOCALE_LOCK;
+    SETLOCALE_LOCK;
 
     DEBUG_Lv(PerlIO_printf(Perl_debug_log,
                             "my_strerror called with errnum %d\n", errnum));
@@ -5401,7 +5399,7 @@ Perl_my_strerror(pTHX_ const int errnum)
         }
     }
 
-    LOCALE_UNLOCK;
+    SETLOCALE_UNLOCK;
 
 #  endif /* End of doesn't have strerror_l */
 #  ifdef DEBUGGING
diff --git a/perl.h b/perl.h
index 959ddfe..1241983 100644 (file)
--- a/perl.h
+++ b/perl.h
@@ -6505,6 +6505,18 @@ the plain locale pragma without a parameter (S<C<use locale>>) is in effect.
 #  define LC_NUMERIC_UNLOCK         NOOP
 #  define LOCALECONV_LOCK           NOOP
 #  define LOCALECONV_UNLOCK         NOOP
+#  define LOCALE_READ_LOCK          NOOP
+#  define LOCALE_READ_UNLOCK        NOOP
+#  define MBLEN_LOCK                NOOP
+#  define MBLEN_UNLOCK              NOOP
+#  define MBTOWC_LOCK               NOOP
+#  define MBTOWC_UNLOCK             NOOP
+#  define NL_LANGINFO_LOCK          NOOP
+#  define NL_LANGINFO_UNLOCK        NOOP
+#  define SETLOCALE_LOCK            NOOP
+#  define SETLOCALE_UNLOCK          NOOP
+#  define WCTOMB_LOCK               NOOP
+#  define WCTOMB_UNLOCK             NOOP
 #else
 
    /* Here, we will need critical sections in locale handling, because one or
@@ -6535,21 +6547,45 @@ the plain locale pragma without a parameter (S<C<use locale>>) is in effect.
     * will be called frequently, and the locked interval should be short, and
     * modern platforms will have reentrant versions (which don't lock) for
     * almost all of them, so khw thinks a single mutex should suffice. */
-#  define LOCALE_LOCK                                                       \
+#  define LOCALE_LOCK_                                                      \
         STMT_START {                                                        \
             DEBUG_Lv(PerlIO_printf(Perl_debug_log,                          \
                     "%s: %d: locking locale\n", __FILE__, __LINE__));       \
             MUTEX_LOCK(&PL_locale_mutex);                                   \
         } STMT_END
-#  define LOCALE_UNLOCK                                                     \
+#  define LOCALE_UNLOCK_                                                    \
         STMT_START {                                                        \
             DEBUG_Lv(PerlIO_printf(Perl_debug_log,                          \
                    "%s: %d: unlocking locale\n", __FILE__, __LINE__));      \
             MUTEX_UNLOCK(&PL_locale_mutex);                                 \
         } STMT_END
 
-#    define LOCALECONV_LOCK   LOCALE_LOCK
-#    define LOCALECONV_UNLOCK LOCALE_UNLOCK
+   /* We do define a different macro for each case; then if we want to have
+    * separate mutexes for some of them, the only changes needed are here.
+    * Define just the necessary macros.  The compiler should then croak if the
+    * #ifdef's in the code are incorrect */
+#  if defined(HAS_LOCALECONV) && ( ! defined(HAS_LOCALECONV_L)              \
+                                  || defined(TS_W32_BROKEN_LOCALECONV))
+#    define LOCALECONV_LOCK   LOCALE_LOCK_
+#    define LOCALECONV_UNLOCK LOCALE_UNLOCK_
+#  endif
+#  if defined(HAS_NL_LANGINFO) && (   ! defined(HAS_THREAD_SAFE_NL_LANGINFO_L) \
+                                   || ! defined(HAS_POSIX_2008_LOCALE))
+#    define NL_LANGINFO_LOCK   LOCALE_LOCK_
+#    define NL_LANGINFO_UNLOCK LOCALE_UNLOCK_
+#  endif
+#  if defined(HAS_MBLEN) && ! defined(HAS_MBRLEN)
+#    define MBLEN_LOCK   LOCALE_LOCK_
+#    define MBLEN_UNLOCK LOCALE_UNLOCK_
+#  endif
+#  if defined(HAS_MBTOWC) && ! defined(HAS_MBRTOWC)
+#    define MBTOWC_LOCK   LOCALE_LOCK_
+#    define MBTOWC_UNLOCK LOCALE_UNLOCK_
+#  endif
+#  if defined(HAS_WCTOMB) && ! defined(HAS_WCRTOMB)
+#    define WCTOMB_LOCK   LOCALE_LOCK_
+#    define WCTOMB_UNLOCK LOCALE_UNLOCK_
+#  endif
 #  if defined(USE_THREAD_SAFE_LOCALE)
      /* On locale thread-safe systems, we don't need these workarounds */
 #    define LOCALE_TERM_LC_NUMERIC_   NOOP
@@ -6558,7 +6594,14 @@ the plain locale pragma without a parameter (S<C<use locale>>) is in effect.
 #    define LC_NUMERIC_UNLOCK       NOOP
 #    define LOCALE_INIT_LC_NUMERIC_ NOOP
 #    define LOCALE_TERM_LC_NUMERIC_ NOOP
+
+     /* There may be instance core where we this is invoked yet should do
+      * nothing.  Rather than have #ifdef's around them, define it here */
+#    define SETLOCALE_LOCK    NOOP
+#    define SETLOCALE_UNLOCK  NOOP
 #  else
+#    define SETLOCALE_LOCK   LOCALE_LOCK_
+#    define SETLOCALE_UNLOCK LOCALE_UNLOCK_
 
     /* On platforms without per-thread locales, when another thread can switch
      * our locale, we need another mutex to create critical sections where we
@@ -6582,7 +6625,7 @@ the plain locale pragma without a parameter (S<C<use locale>>) is in effect.
      * Clang improperly gives warnings for this, if not silenced:
      * https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#conditional-locks
      *
-     * If LC_NUMERIC_LOCK is combined with LOCALE_LOCK, calls to
+     * If LC_NUMERIC_LOCK is combined with one of the LOCKs above, calls to
      * that and its corresponding unlock should be contained entirely within
      * the locked portion of LC_NUMERIC.  Those mutexes should be used only in
      * very short sections of code, while LC_NUMERIC_LOCK may span more