Skip to content

Commit f39b100

Browse files
committed
POC for thread-safe and thread-local setlocale()
1 parent 9762c44 commit f39b100

3 files changed

Lines changed: 354 additions & 14 deletions

File tree

ext/standard/basic_functions.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,16 @@ PHP_RINIT_FUNCTION(basic) /* {{{ */
396396
BG(strtok_last) = NULL;
397397
BG(ctype_string) = NULL;
398398
BG(locale_changed) = 0;
399+
#if defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE) && defined(HAVE_FREELOCALE) && !defined(PHP_WIN32)
400+
BG(thread_locale) = (locale_t)0;
401+
BG(locale_cat_collate) = NULL;
402+
BG(locale_cat_monetary) = NULL;
403+
BG(locale_cat_numeric) = NULL;
404+
BG(locale_cat_time) = NULL;
405+
# ifdef LC_MESSAGES
406+
BG(locale_cat_messages) = NULL;
407+
# endif
408+
#endif
399409
BG(user_compare_fci) = empty_fcall_info;
400410
BG(user_compare_fci_cache) = empty_fcall_info_cache;
401411
BG(page_uid) = -1;
@@ -446,13 +456,36 @@ PHP_RSHUTDOWN_FUNCTION(basic) /* {{{ */
446456
/* Check if locale was changed and change it back
447457
* to the value in startup environment */
448458
if (BG(locale_changed)) {
459+
#if defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE) && defined(HAVE_FREELOCALE) && !defined(PHP_WIN32)
460+
/* Restore to use the global locale for this thread and free the per-thread locale */
461+
#ifdef LC_GLOBAL_LOCALE
462+
uselocale(LC_GLOBAL_LOCALE);
463+
#endif
464+
if (BG(thread_locale)) {
465+
freelocale(BG(thread_locale));
466+
BG(thread_locale) = (locale_t)0;
467+
}
468+
#else
449469
setlocale(LC_ALL, "C");
470+
#endif
471+
#if !(defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE) && defined(HAVE_FREELOCALE) && !defined(PHP_WIN32))
472+
/* Only reset process-wide LC_CTYPE when per-thread locales are not used */
450473
zend_reset_lc_ctype_locale();
474+
#endif
451475
zend_update_current_locale();
452476
if (BG(ctype_string)) {
453477
zend_string_release_ex(BG(ctype_string), 0);
454478
BG(ctype_string) = NULL;
455479
}
480+
#if defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE) && defined(HAVE_FREELOCALE) && !defined(PHP_WIN32)
481+
if (BG(locale_cat_collate)) { zend_string_release_ex(BG(locale_cat_collate), 0); BG(locale_cat_collate) = NULL; }
482+
if (BG(locale_cat_monetary)) { zend_string_release_ex(BG(locale_cat_monetary), 0); BG(locale_cat_monetary) = NULL; }
483+
if (BG(locale_cat_numeric)) { zend_string_release_ex(BG(locale_cat_numeric), 0); BG(locale_cat_numeric) = NULL; }
484+
if (BG(locale_cat_time)) { zend_string_release_ex(BG(locale_cat_time), 0); BG(locale_cat_time) = NULL; }
485+
# ifdef LC_MESSAGES
486+
if (BG(locale_cat_messages)) { zend_string_release_ex(BG(locale_cat_messages), 0); BG(locale_cat_messages) = NULL; }
487+
# endif
488+
#endif
456489
}
457490

458491
/* FG(stream_wrappers) and FG(stream_filters) are destroyed

ext/standard/basic_functions.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727

2828
#include "url_scanner_ex.h"
2929

30+
/* Locale headers for per-thread locale support */
31+
#include <locale.h>
32+
#ifdef HAVE_XLOCALE_H
33+
# include <xlocale.h>
34+
#endif
35+
3036
#if defined(_WIN32) && !defined(__clang__)
3137
#include <intrin.h>
3238
#endif
@@ -57,6 +63,16 @@ typedef struct _php_basic_globals {
5763
zend_string *strtok_string;
5864
zend_string *ctype_string; /* current LC_CTYPE locale (or NULL for 'C') */
5965
bool locale_changed; /* locale was changed and has to be restored */
66+
#if defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE) && defined(HAVE_FREELOCALE) && !defined(PHP_WIN32)
67+
locale_t thread_locale;
68+
zend_string *locale_cat_collate;
69+
zend_string *locale_cat_monetary;
70+
zend_string *locale_cat_numeric;
71+
zend_string *locale_cat_time;
72+
#ifdef LC_MESSAGES
73+
zend_string *locale_cat_messages;
74+
#endif
75+
#endif
6076
char *strtok_last;
6177
char strtok_table[256];
6278
size_t strtok_len;

0 commit comments

Comments
 (0)