diff options
author | Karl Williamson <khw@cpan.org> | 2022-09-29 12:51:21 -0600 |
---|---|---|
committer | Karl Williamson <khw@cpan.org> | 2022-10-18 06:22:16 -0600 |
commit | 644641ff58ccf88bd860ef5517a40d1fb27bf022 (patch) | |
tree | ef894cfcba475a235aa64d806d1e1052e9695d9b /locale.c | |
parent | 1094750e0904f86121732c4af342fbdaccf70df3 (diff) | |
download | perl-644641ff58ccf88bd860ef5517a40d1fb27bf022.tar.gz |
Switch libc per-interpreter data when tTHX changes
As noted in the previous commit, some library functions now keep
per-thread state. So far the only ones we care about are libc
locale-changing ones.
When perl changes threads by swapping out tTHX, those library functions
need to be informed about the new value so that they remain in sync with
what perl thinks the locale should be.
This commit creates a function to do this, and changes the
thread-changing macros to also call this as part of the change.
For POSIX 2008, the function just calls uselocale() using the
per-interpreter object introduced previously.
For Windows, this commit adds a per-interpreter string of the current
LC_ALL, and the function calls setlocale on that. We keep the same
string for POSIX 2008 implementations that lack querylocale(), so this
commit just enables that variable on Windows as well. The code is
already in place to free the memory the string occupies when done.
The commit also creates a mechanism to skip this during thread
destruction. A thread in its death throes doesn't need to have accurate
locale information, and the information needed to map from thread to
what libc needs to know gets destroyed as part of those throes, while
relics of the thread remain. I couldn't find a way to accurately know
if we are dealing with a relic or not, so the solution I adopted was to
just not switch during destruction.
This commit completes fixing #20155.
Diffstat (limited to 'locale.c')
-rw-r--r-- | locale.c | 55 |
1 files changed, 54 insertions, 1 deletions
@@ -2601,7 +2601,6 @@ S_win32_setlocale(pTHX_ int category, const char* locale) * use the particular category's variable if set; otherwise to use the LANG * variable. */ - if (locale == NULL) { return wrap_wsetlocale(category, NULL); } @@ -2615,6 +2614,20 @@ S_win32_setlocale(pTHX_ int category, const char* locale) const char * result = wrap_wsetlocale(category, locale); DEBUG_L(PerlIO_printf(Perl_debug_log, "%s\n", setlocale_debug_string_r(category, locale, result))); + +# ifdef USE_PL_CUR_LC_ALL + + /* If we need to keep track of LC_ALL, update it to the new value. */ + Safefree(PL_cur_LC_ALL); + if (category == LC_ALL) { + PL_cur_LC_ALL = savepv(result); + } + else { + PL_cur_LC_ALL = savepv(setlocale(LC_ALL, NULL)); + } + +# endif + return result; } @@ -6723,6 +6736,46 @@ S_my_setlocale_debug_string_i(pTHX_ } #endif +#ifdef USE_PERL_SWITCH_LOCALE_CONTEXT + +void +Perl_switch_locale_context() +{ + /* libc keeps per-thread locale status information in some configurations. + * So, we can't just switch out aTHX to switch to a new thread. libc has + * to follow along. This routine does that based on per-interpreter + * variables we keep just for this purpose */ + + /* Can't use pTHX, because we may be called from a place where that + * isn't available */ + dTHX; + + if (UNLIKELY( aTHX == NULL + || PL_veto_switch_non_tTHX_context + || PL_phase == PERL_PHASE_CONSTRUCT)) + { + return; + } + +# ifdef USE_POSIX_2008_LOCALE + + if (! uselocale(PL_cur_locale_obj)) { + locale_panic_(Perl_form(aTHX_ + "Can't uselocale(%p), LC_ALL supposed to be '%s", + PL_cur_locale_obj, get_LC_ALL_display())); + } + +# elif defined(WIN32) + + if (! bool_setlocale_c(LC_ALL, PL_cur_LC_ALL)) { + locale_panic_(Perl_form(aTHX_ "Can't setlocale(%s)", PL_cur_LC_ALL)); + } + +# endif + +} + +#endif void Perl_thread_locale_init(pTHX) |