Skip to content

Commit 95198c1

Browse files
committed
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.
1 parent fad30ac commit 95198c1

File tree

10 files changed

+135
-5
lines changed

10 files changed

+135
-5
lines changed

dist/threads/lib/threads.pm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use 5.008;
55
use strict;
66
use warnings;
77

8-
our $VERSION = '2.29'; # remember to update version in POD!
8+
our $VERSION = '2.31'; # remember to update version in POD!
99
my $XS_VERSION = $VERSION;
1010
$VERSION = eval $VERSION;
1111

@@ -134,7 +134,7 @@ threads - Perl interpreter-based threads
134134
135135
=head1 VERSION
136136
137-
This document describes threads version 2.29
137+
This document describes threads version 2.31
138138
139139
=head1 WARNING
140140

dist/threads/threads.xs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,20 @@ S_ithread_clear(pTHX_ ithread *thread)
241241
S_block_most_signals(&origmask);
242242
#endif
243243

244+
int save_veto = PL_veto_switch_non_tTHX_context;
245+
244246
interp = thread->interp;
245247
if (interp) {
246248
dTHXa(interp);
247249

250+
/* We will pretend to be a thread that we are not by switching tTHX,
251+
* which doesn't work with things that don't rely on tTHX during
252+
* tear-down, as they will tend to rely on a mapping from the tTHX
253+
* structure, and that structure is being destroyed. */
254+
PL_veto_switch_non_tTHX_context = true;
255+
248256
PERL_SET_CONTEXT(interp);
257+
249258
S_ithread_set(aTHX_ thread);
250259

251260
SvREFCNT_dec(thread->params);
@@ -262,6 +271,8 @@ S_ithread_clear(pTHX_ ithread *thread)
262271
}
263272

264273
PERL_SET_CONTEXT(aTHX);
274+
PL_veto_switch_non_tTHX_context = save_veto;
275+
265276
#ifdef THREAD_SIGNAL_BLOCKING
266277
S_set_sigmask(&origmask);
267278
#endif

embed.fnc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,9 @@ Apd |void |switch_to_global_locale
16651665
Apd |bool |sync_locale
16661666
Apx |void |thread_locale_init
16671667
Apx |void |thread_locale_term
1668+
#ifdef USE_PERL_SWITCH_LOCALE_CONTEXT
1669+
CopT |void |switch_locale_context
1670+
#endif
16681671
ApdO |void |require_pv |NN const char* pv
16691672
Apd |void |packlist |NN SV *cat|NN const char *pat|NN const char *patend|NN SV **beglist|NN SV **endlist
16701673
#if defined(PERL_USES_PL_PIDSTATUS) && defined(PERL_IN_UTIL_C)

locale.c

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2593,7 +2593,6 @@ S_win32_setlocale(pTHX_ int category, const char* locale)
25932593
* use the particular category's variable if set; otherwise to use the LANG
25942594
* variable. */
25952595

2596-
25972596
if (locale == NULL) {
25982597
return wrap_wsetlocale(category, NULL);
25992598
}
@@ -2607,6 +2606,20 @@ S_win32_setlocale(pTHX_ int category, const char* locale)
26072606
const char * result = wrap_wsetlocale(category, locale);
26082607
DEBUG_L(PerlIO_printf(Perl_debug_log, "%s\n",
26092608
setlocale_debug_string_r(category, locale, result)));
2609+
2610+
# ifdef USE_PL_CUR_LC_ALL
2611+
2612+
/* If we need to keep track of LC_ALL, update it to the new value. */
2613+
Safefree(PL_cur_LC_ALL);
2614+
if (category == LC_ALL) {
2615+
PL_cur_LC_ALL = savepv(result);
2616+
}
2617+
else {
2618+
PL_cur_LC_ALL = savepv(setlocale(LC_ALL, NULL));
2619+
}
2620+
2621+
# endif
2622+
26102623
return result;
26112624
}
26122625

@@ -6719,6 +6732,46 @@ S_my_setlocale_debug_string_i(pTHX_
67196732
retval_quote, retval, retval_quote);
67206733
}
67216734

6735+
#endif
6736+
#ifdef USE_PERL_SWITCH_LOCALE_CONTEXT
6737+
6738+
void
6739+
Perl_switch_locale_context()
6740+
{
6741+
/* libc keeps per-thread locale status information in some configurations.
6742+
* So, we can't just switch out aTHX to switch to a new thread. libc has
6743+
* to follow along. This routine does that based on per-interpreter
6744+
* variables we keep just for this purpose */
6745+
6746+
/* Can't use pTHX, because we may be called from a place where that
6747+
* isn't available */
6748+
dTHX;
6749+
6750+
if (UNLIKELY( aTHX == NULL
6751+
|| PL_veto_switch_non_tTHX_context
6752+
|| PL_phase == PERL_PHASE_CONSTRUCT))
6753+
{
6754+
return;
6755+
}
6756+
6757+
# ifdef USE_POSIX_2008_LOCALE
6758+
6759+
if (! uselocale(PL_cur_locale_obj)) {
6760+
locale_panic_(Perl_form(aTHX_
6761+
"Can't uselocale(%p), LC_ALL supposed to be '%s",
6762+
PL_cur_locale_obj, get_LC_ALL_display()));
6763+
}
6764+
6765+
# elif defined(WIN32)
6766+
6767+
if (! bool_setlocale_c(LC_ALL, PL_cur_LC_ALL)) {
6768+
locale_panic_(Perl_form(aTHX_ "Can't setlocale(%s)", PL_cur_LC_ALL));
6769+
}
6770+
6771+
# endif
6772+
6773+
}
6774+
67226775
#endif
67236776

67246777
void

makedef.pl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,20 @@ BEGIN
177177

178178
if ($ARGS{PLATFORM} eq 'win32' && $define{USE_THREAD_SAFE_LOCALE})
179179
{
180+
$define{USE_PL_CUR_LC_ALL} = 1;
181+
180182
if ($cctype < 140) {
181183
$define{TS_W32_BROKEN_LOCALECONV} = 1;
182184
}
183185
}
184186

187+
if ($define{MULTIPLICITY} && ( $define{USE_POSIX_2008_LOCALE}
188+
|| ( $define{WIN32}
189+
&& $define{USE_THREAD_SAFE_LOCALE})))
190+
{
191+
$define{USE_PERL_SWITCH_LOCALE_CONTEXT}
192+
}
193+
185194
# perl.h logic duplication ends
186195
#==========================================================================
187196

@@ -400,6 +409,7 @@ sub readvar {
400409
PL_stashpad
401410
PL_stashpadix
402411
PL_stashpadmax
412+
PL_veto_switch_non_tTHX_context
403413
Perl_alloccopstash
404414
Perl_allocfilegv
405415
Perl_clone_params_del
@@ -450,6 +460,13 @@ sub readvar {
450460
);
451461
}
452462

463+
unless ($define{USE_PERL_SWITCH_LOCALE_CONTEXT})
464+
{
465+
++$skip{$_} foreach qw(
466+
Perl_switch_locale_context
467+
);
468+
}
469+
453470
unless ($define{'MULTIPLICITY'}) {
454471
++$skip{$_} foreach qw(
455472
PL_my_cxt_index

perl.h

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,11 @@ violations are fatal.
12721272

12731273
# if defined(WIN32) && defined(USE_THREAD_SAFE_LOCALE)
12741274

1275+
/* We need to be able to map the current value of what the tTHX context
1276+
* thinks LC_ALL is so as to inform the Windows libc when switching
1277+
* contexts. */
1278+
# define USE_PL_CUR_LC_ALL
1279+
12751280
/* Microsoft documentation reads in the change log for VS 2015: "The
12761281
* localeconv function declared in locale.h now works correctly when
12771282
* per-thread locale is enabled. In previous versions of the library, this
@@ -1280,6 +1285,15 @@ violations are fatal.
12801285
# if _MSC_VER < 1900
12811286
# define TS_W32_BROKEN_LOCALECONV
12821287
# endif
1288+
# endif
1289+
1290+
/* POSIX 2008 and Windows with thread-safe locales keep locale information
1291+
* in libc data. Therefore we must inform their libc's when the context
1292+
* switches */
1293+
# if defined(MULTIPLICITY) && ( defined(USE_POSIX_2008_LOCALE) \
1294+
|| ( defined(WIN32) \
1295+
&& defined(USE_THREAD_SAFE_LOCALE)))
1296+
# define USE_PERL_SWITCH_LOCALE_CONTEXT
12831297
# endif
12841298
#endif
12851299

@@ -4046,7 +4060,10 @@ out there, Solaris being the most prominent.
40464060

40474061
/* the traditional thread-unsafe notion of "current interpreter". */
40484062
#ifndef PERL_SET_INTERP
4049-
# define PERL_SET_INTERP(i) (PL_curinterp = (PerlInterpreter*)(i))
4063+
# define PERL_SET_INTERP(i) \
4064+
STMT_START { PL_curinterp = (PerlInterpreter*)(i); \
4065+
PERL_SET_NON_tTHX_CONTEXT(i); \
4066+
} STMT_END
40504067
#endif
40514068

40524069
#ifndef PERL_GET_INTERP
@@ -6273,6 +6290,24 @@ EXTCONST U8 PL_deBruijn_bitpos_tab64[];
62736290
# define PERL_SET_CONTEXT(i) PERL_SET_INTERP(i)
62746291
#endif
62756292

6293+
#ifdef USE_PERL_SWITCH_LOCALE_CONTEXT
6294+
# define PERL_SET_LOCALE_CONTEXT(i) \
6295+
STMT_START { \
6296+
if (UNLIKELY(PL_veto_switch_non_tTHX_context)) \
6297+
Perl_switch_locale_context(); \
6298+
} STMT_END
6299+
#else
6300+
# define PERL_SET_LOCALE_CONTEXT(i) NOOP
6301+
#endif
6302+
6303+
/* In some Configurations there may be per-thread information that is carried
6304+
* in a library instead of perl's tTHX structure. This macro is to be used to
6305+
* handle those when tTHX is changed. Only locale handling is currently known
6306+
* to be affected. */
6307+
#define PERL_SET_NON_tTHX_CONTEXT(i) \
6308+
STMT_START { PERL_SET_LOCALE_CONTEXT(i); } STMT_END
6309+
6310+
62766311
#ifndef PERL_GET_CONTEXT
62776312
# define PERL_GET_CONTEXT PERL_GET_INTERP
62786313
#endif
@@ -7883,7 +7918,9 @@ C<strtoul>.
78837918
* "DynaLoader::_guts" XS_VERSION
78847919
* XXX in the current implementation, this string is ignored.
78857920
* 2. Declare a typedef named my_cxt_t that is a structure that contains
7886-
* all the data that needs to be interpreter-local.
7921+
* all the data that needs to be interpreter-local that perl controls. This
7922+
* doesn't include things that libc controls, such as the uselocale object
7923+
* in Configurations that use it.
78877924
* 3. Use the START_MY_CXT macro after the declaration of my_cxt_t.
78887925
* 4. Use the MY_CXT_INIT macro such that it is called exactly once
78897926
* (typically put in the BOOT: section).

perlvars.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ PERLVAR(G, check_mutex, perl_mutex) /* Mutex for PL_check */
169169
#ifdef MULTIPLICITY
170170
# ifdef USE_ITHREADS
171171
PERLVAR(G, my_ctx_mutex, perl_mutex)
172+
PERLVARI(G, veto_switch_non_tTHX_context, int, FALSE)
172173
# endif
173174
PERLVARI(G, my_cxt_index, int, 0)
174175
#endif

proto.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7661,6 +7661,10 @@ PERL_CALLCONV SSize_t Perl_PerlIO_write(pTHX_ PerlIO *f, const void *vbuf, Size_
76617661
#define PERL_ARGS_ASSERT_PERLIO_WRITE \
76627662
assert(vbuf)
76637663
#endif
7664+
#if defined(USE_PERL_SWITCH_LOCALE_CONTEXT)
7665+
PERL_CALLCONV void Perl_switch_locale_context(void);
7666+
#define PERL_ARGS_ASSERT_SWITCH_LOCALE_CONTEXT
7667+
#endif
76647668
#if defined(USE_QUADMATH)
76657669
PERL_CALLCONV bool Perl_quadmath_format_needed(const char* format)
76667670
__attribute__visibility__("hidden");

thread.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ extern PERL_THREAD_LOCAL void *PL_current_context;
404404
PL_current_context = (void *)(t)))) \
405405
Perl_croak_nocontext("panic: pthread_setspecific (%d) [%s:%d]", \
406406
_eC_, __FILE__, __LINE__); \
407+
PERL_SET_NON_tTHX_CONTEXT(t); \
407408
} STMT_END
408409

409410
#else

util.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3740,6 +3740,9 @@ Perl_set_context(void *t)
37403740
Perl_croak_nocontext("panic: pthread_setspecific, error=%d", error);
37413741
}
37423742
# endif
3743+
3744+
PERL_SET_NON_tTHX_CONTEXT(t);
3745+
37433746
#else
37443747
PERL_UNUSED_ARG(t);
37453748
#endif

0 commit comments

Comments
 (0)