diff options
author | Karl Williamson <khw@cpan.org> | 2018-02-05 22:11:51 -0700 |
---|---|---|
committer | Karl Williamson <khw@cpan.org> | 2018-02-18 15:44:23 -0700 |
commit | e9bc6d6b34afc0063cc5181b59f77eeb81b1182d (patch) | |
tree | 1028b01c95db9ebdc6d78340ca1f00aad07fe922 /vutil.c | |
parent | ddd5ebe0cadc81a0360ad8007674490fda89ee88 (diff) | |
download | perl-e9bc6d6b34afc0063cc5181b59f77eeb81b1182d.tar.gz |
Add thread-safe locale handling
This (large) commit allows locales to be used in threaded perls on
platforms that support it. This includes recent Windows and Posix 2008
ones.
Diffstat (limited to 'vutil.c')
-rw-r--r-- | vutil.c | 65 |
1 files changed, 64 insertions, 1 deletions
@@ -625,7 +625,11 @@ VER_NV: * locales without letting perl know, therefore we have to find it * from first principals. See [perl #121930]. */ - /* if it isn't C, set it to C. */ + /* In windows, or not threaded, or not thread-safe, if it isn't C, + * set it to C. */ + +# ifndef USE_POSIX_2008_LOCALE + const char * locale_name_on_entry; LC_NUMERIC_LOCK(0); /* Start critical section */ @@ -641,6 +645,48 @@ VER_NV: locale_name_on_entry = NULL; } +# else + + const locale_t locale_obj_on_entry = uselocale((locale_t) 0); + const char * locale_name_on_entry = NULL; + DECLARATION_FOR_LC_NUMERIC_MANIPULATION; + + if (locale_obj_on_entry == LC_GLOBAL_LOCALE) { + + /* in the global locale, we can call system setlocale and if it + * isn't C, set it to C. */ + LC_NUMERIC_LOCK(0); + + locale_name_on_entry = setlocale(LC_NUMERIC, NULL); + if ( strNE(locale_name_on_entry, "C") + && strNE(locale_name_on_entry, "POSIX")) + { + setlocale(LC_NUMERIC, "C"); + } + else { /* This value indicates to the restore code that we + didn't change the locale */ + locale_name_on_entry = NULL; + } + } + else if (locale_obj_on_entry == PL_underlying_numeric_obj) { + /* Here, the locale appears to have been changed to use the + * program's underlying locale. Just use our mechanisms to + * switch back to C. It might be possible for this pointer to + * actually refer to something else if it got released and + * reused somehow. But it doesn't matter, our mechanisms will + * work even so */ + STORE_LC_NUMERIC_SET_STANDARD(); + } + else if (locale_obj_on_entry != PL_C_locale_obj) { + /* The C object should be unchanged during a program's + * execution, so it should be safe to assume it means what it + * says, so if we are in it, no locale change is required. + * Otherwise, simply use the thread-safe operation. */ + uselocale(PL_C_locale_obj); + } + +# endif + /* Prevent recursed calls from trying to change back */ LOCK_LC_NUMERIC_STANDARD(); @@ -660,12 +706,29 @@ VER_NV: UNLOCK_LC_NUMERIC_STANDARD(); +# ifndef USE_POSIX_2008_LOCALE + if (locale_name_on_entry) { setlocale(LC_NUMERIC, locale_name_on_entry); } LC_NUMERIC_UNLOCK; /* End critical section */ +# else + + if (locale_name_on_entry) { + setlocale(LC_NUMERIC, locale_name_on_entry); + LC_NUMERIC_UNLOCK; + } + else if (locale_obj_on_entry == PL_underlying_numeric_obj) { + RESTORE_LC_NUMERIC(); + } + else if (locale_obj_on_entry != PL_C_locale_obj) { + uselocale(locale_obj_on_entry); + } + +# endif + } #endif /* USE_LOCALE_NUMERIC */ |