From 9be2b373d3f7103a5ae5bbb17d9999b84282ab0c Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Thu, 15 Jan 2026 18:38:50 -0500 Subject: [PATCH] locale: Refactor ctype storage and consolidate some files. * Drop the global definitions from ctype.h, and move them to the internal LocaleData.h: the functions should be used always when building new applications (as they're thread-safe.) * Make __ctype_get_mb_cur_max thread-safe and move it to live alongside the other __ctype...() methods. * Put the __ctype...() methods in two files, clearly indicating versions: ctype_loc_global for the global (non-thread-safe) versions, used for the kernel, and ctype_loc_thread for the libroot versions. * Consolidate more internal functions into LocaleInternal.cpp. --- headers/posix/ctype.h | 14 +--- .../private/libroot/locale/LocaleBackend.h | 7 +- headers/private/libroot/locale/LocaleData.h | 9 +++ headers/private/libroot/locale/ThreadLocale.h | 34 ---------- src/system/boot/Jamfile | 2 +- src/system/kernel/lib/Jamfile | 2 +- .../libroot/add-ons/icu/ICUCtypeData.cpp | 5 +- src/system/libroot/posix/locale/Jamfile | 8 +-- .../libroot/posix/locale/LocaleBackend.cpp | 3 +- .../libroot/posix/locale/LocaleData.cpp | 1 + .../libroot/posix/locale/LocaleDataBridge.cpp | 37 +++++----- .../libroot/posix/locale/LocaleInternal.cpp | 37 +++++++++- .../libroot/posix/locale/LocaleInternal.h | 14 ++++ .../libroot/posix/locale/ThreadLocale.cpp | 67 ------------------- src/system/libroot/posix/locale/ctype.cpp | 10 --- .../{ctype_loc.cpp => ctype_loc_global.cpp} | 16 ++++- .../libroot/posix/locale/ctype_loc_thread.cpp | 40 +++++++++++ src/system/runtime_loader/Jamfile | 2 +- 18 files changed, 144 insertions(+), 164 deletions(-) delete mode 100644 headers/private/libroot/locale/ThreadLocale.h delete mode 100644 src/system/libroot/posix/locale/ThreadLocale.cpp rename src/system/libroot/posix/locale/{ctype_loc.cpp => ctype_loc_global.cpp} (69%) create mode 100644 src/system/libroot/posix/locale/ctype_loc_thread.cpp diff --git a/headers/posix/ctype.h b/headers/posix/ctype.h index 7693ae6e09..01d21d8678 100644 --- a/headers/posix/ctype.h +++ b/headers/posix/ctype.h @@ -61,15 +61,9 @@ enum { _ISgraph = 0x8000 /* graphical */ }; -/* Characteristics */ -extern const unsigned short int *__ctype_b; -/* Case conversions */ -extern const int *__ctype_tolower; -extern const int *__ctype_toupper; - -extern const unsigned short int **__ctype_b_loc(); -extern const int **__ctype_tolower_loc(); -extern const int **__ctype_toupper_loc(); +extern const unsigned short int *const *const __ctype_b_loc(); +extern const int *const *const __ctype_tolower_loc(); +extern const int *const *const __ctype_toupper_loc(); #define __isctype(c, type) \ ((*__ctype_b_loc())[(int)(c)] & (unsigned short int)type) @@ -96,8 +90,6 @@ extern const int **__ctype_toupper_loc(); #define isupper(c) __isctype((c), _ISupper) #define isxdigit(c) __isctype((c), _ISxdigit) -extern unsigned short int __ctype_mb_cur_max; - #ifdef __cplusplus } #endif diff --git a/headers/private/libroot/locale/LocaleBackend.h b/headers/private/libroot/locale/LocaleBackend.h index ce2d982f99..e980d6482a 100644 --- a/headers/private/libroot/locale/LocaleBackend.h +++ b/headers/private/libroot/locale/LocaleBackend.h @@ -25,11 +25,13 @@ private: const unsigned short* localClassInfoTable; const int* localToLowerTable; const int* localToUpperTable; + unsigned short localMbCurMax; public: const unsigned short** addrOfClassInfoTable; const int** addrOfToLowerTable; const int** addrOfToUpperTable; + unsigned short* addrOfMbCurMax; const unsigned short* const posixClassInfo; const int* const posixToLowerMap; @@ -39,7 +41,6 @@ public: LocaleCtypeDataBridge(bool isGlobal); - void setMbCurMax(unsigned short mbCurMax); void ApplyToCurrentThread(); }; @@ -61,7 +62,6 @@ struct LocaleMonetaryDataBridge { struct LocaleNumericDataBridge { public: const struct lconv* const posixLocaleConv; - bool isGlobal; LocaleNumericDataBridge(bool isGlobal); ~LocaleNumericDataBridge(); @@ -89,7 +89,6 @@ public: int* addrOfDaylight; long* addrOfTimezone; char** addrOfTZName; - bool isGlobal; TimeConversionDataBridge(bool isGlobal); }; @@ -103,7 +102,6 @@ struct LocaleDataBridge { LocaleTimeDataBridge timeDataBridge; TimeConversionDataBridge timeConversionDataBridge; const char** const posixLanginfo; - bool isGlobal; LocaleDataBridge(bool isGlobal); @@ -182,6 +180,7 @@ LocaleBackend* GetCurrentLocaleBackend(); extern LocaleBackend* gGlobalLocaleBackend; extern LocaleDataBridge gGlobalLocaleDataBridge; + } // namespace Libroot } // namespace BPrivate diff --git a/headers/private/libroot/locale/LocaleData.h b/headers/private/libroot/locale/LocaleData.h index ff20dcdcf2..5e2a85488d 100644 --- a/headers/private/libroot/locale/LocaleData.h +++ b/headers/private/libroot/locale/LocaleData.h @@ -9,6 +9,15 @@ #include +extern "C" { +// Global storage (exported for BeOS and older Haiku compatibility) +extern const unsigned short int *__ctype_b; +extern const int *__ctype_tolower; +extern const int *__ctype_toupper; +extern unsigned short int __ctype_mb_cur_max; +} + + namespace BPrivate { namespace Libroot { diff --git a/headers/private/libroot/locale/ThreadLocale.h b/headers/private/libroot/locale/ThreadLocale.h deleted file mode 100644 index 57b3cb51d5..0000000000 --- a/headers/private/libroot/locale/ThreadLocale.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2022, Trung Nguyen, trungnt282910@gmail.com - * All rights reserved. Distributed under the terms of the MIT License. - */ - -#ifndef _THREAD_LOCALE_H -#define _THREAD_LOCALE_H - - -#include "LocaleBackend.h" - - -namespace BPrivate { -namespace Libroot { - - -// The pointer in the TLS will point to this struct. -struct ThreadLocale { - LocaleBackendData* threadLocaleInfo; - - const unsigned short int* ctype_b; - const int* ctype_tolower; - const int* ctype_toupper; -}; - - -ThreadLocale* GetCurrentThreadLocale(); - - -} // namespace Libroot -} // namespace BPrivate - - -#endif // _THREAD_LOCALE_H diff --git a/src/system/boot/Jamfile b/src/system/boot/Jamfile index 8375eec313..fbd8aa29ba 100644 --- a/src/system/boot/Jamfile +++ b/src/system/boot/Jamfile @@ -308,7 +308,7 @@ for platform in [ MultiBootSubDirSetup ] { BootMergeObject boot_libroot_$(platform:G=).o : abs.c - ctype_loc.cpp + ctype_loc_global.cpp ctype_l.cpp ctype.cpp generic_memcpy.c diff --git a/src/system/kernel/lib/Jamfile b/src/system/kernel/lib/Jamfile index fac2767531..8419deb5bd 100644 --- a/src/system/kernel/lib/Jamfile +++ b/src/system/kernel/lib/Jamfile @@ -74,7 +74,7 @@ KernelMergeObject kernel_lib_posix.o : utime.c # locale - ctype_loc.cpp + ctype_loc_global.cpp ctype_l.cpp ctype.cpp localeconv.cpp diff --git a/src/system/libroot/add-ons/icu/ICUCtypeData.cpp b/src/system/libroot/add-ons/icu/ICUCtypeData.cpp index 74288cd32c..61d4f10cae 100644 --- a/src/system/libroot/add-ons/icu/ICUCtypeData.cpp +++ b/src/system/libroot/add-ons/icu/ICUCtypeData.cpp @@ -74,7 +74,7 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName) ucnv_reset(converter); - fDataBridge->setMbCurMax(ucnv_getMaxCharSize(converter)); + *fDataBridge->addrOfMbCurMax = ucnv_getMaxCharSize(converter); char buffer[] = { 0, 0 }; for (int i = 0; i < 256; ++i) { @@ -150,8 +150,7 @@ ICUCtypeData::SetToPosix() memcpy(fClassInfo, fDataBridge->posixClassInfo, sizeof(fClassInfo)); memcpy(fToLowerMap, fDataBridge->posixToLowerMap, sizeof(fToLowerMap)); memcpy(fToUpperMap, fDataBridge->posixToUpperMap, sizeof(fToUpperMap)); - - fDataBridge->setMbCurMax(1); + *fDataBridge->addrOfMbCurMax = 1; } return result; diff --git a/src/system/libroot/posix/locale/Jamfile b/src/system/libroot/posix/locale/Jamfile index eb420bac86..a3654f9bec 100644 --- a/src/system/libroot/posix/locale/Jamfile +++ b/src/system/libroot/posix/locale/Jamfile @@ -13,8 +13,9 @@ for architectureObject in [ MultiArchSubDirSetup ] { local architecture = $(TARGET_PACKAGING_ARCH) ; MergeObject <$(architecture)>posix_locale.o : - ctype_l.cpp ctype.cpp + ctype_l.cpp + ctype_loc_thread.cpp LocaleBackend.cpp LocaleData.cpp LocaleDataBridge.cpp @@ -23,13 +24,12 @@ for architectureObject in [ MultiArchSubDirSetup ] { localeconv.cpp nl_langinfo.cpp setlocale.cpp - ThreadLocale.cpp wctype_l.cpp wctype.cpp ; - MergeObject <$(architecture)>ctype_loc.o : - ctype_loc.cpp + MergeObject <$(architecture)>ctype_loc_global.o : + ctype_loc_global.cpp ; } } diff --git a/src/system/libroot/posix/locale/LocaleBackend.cpp b/src/system/libroot/posix/locale/LocaleBackend.cpp index ddace61c92..db337c5499 100644 --- a/src/system/libroot/posix/locale/LocaleBackend.cpp +++ b/src/system/libroot/posix/locale/LocaleBackend.cpp @@ -5,13 +5,12 @@ #include "LocaleBackend.h" +#include "LocaleInternal.h" #include #include #include -#include - namespace BPrivate { namespace Libroot { diff --git a/src/system/libroot/posix/locale/LocaleData.cpp b/src/system/libroot/posix/locale/LocaleData.cpp index 2c7156c5d4..622a017586 100644 --- a/src/system/libroot/posix/locale/LocaleData.cpp +++ b/src/system/libroot/posix/locale/LocaleData.cpp @@ -329,3 +329,4 @@ const char* gPosixLanginfo[_NL_LANGINFO_LAST] = { const unsigned short* __ctype_b = &BPrivate::Libroot::gPosixClassInfo[128]; const int* __ctype_tolower = &BPrivate::Libroot::gPosixToLowerMap[128]; const int* __ctype_toupper = &BPrivate::Libroot::gPosixToUpperMap[128]; +unsigned short int __ctype_mb_cur_max = 1; diff --git a/src/system/libroot/posix/locale/LocaleDataBridge.cpp b/src/system/libroot/posix/locale/LocaleDataBridge.cpp index 352a4ee884..b24be90a82 100644 --- a/src/system/libroot/posix/locale/LocaleDataBridge.cpp +++ b/src/system/libroot/posix/locale/LocaleDataBridge.cpp @@ -5,20 +5,17 @@ #include "LocaleBackend.h" +#include "LocaleInternal.h" #include #include +#include #include #include #include -extern const unsigned short* __ctype_b; -extern const int* __ctype_tolower; -extern const int* __ctype_toupper; - - namespace BPrivate { namespace Libroot { @@ -37,26 +34,27 @@ LocaleCtypeDataBridge::LocaleCtypeDataBridge(bool isGlobal) addrOfClassInfoTable = &__ctype_b; addrOfToLowerTable = &__ctype_tolower; addrOfToUpperTable = &__ctype_toupper; + addrOfMbCurMax = &__ctype_mb_cur_max; } else { addrOfClassInfoTable = &localClassInfoTable; addrOfToLowerTable = &localToLowerTable; addrOfToUpperTable = &localToUpperTable; + addrOfMbCurMax = &localMbCurMax; } } -void LocaleCtypeDataBridge::setMbCurMax(unsigned short mbCurMax) -{ - __ctype_mb_cur_max = mbCurMax; -} - - void LocaleCtypeDataBridge::ApplyToCurrentThread() { - *__ctype_b_loc() = *addrOfClassInfoTable; - *__ctype_tolower_loc() = *addrOfToLowerTable; - *__ctype_toupper_loc() = *addrOfToUpperTable; + if (isGlobal) + abort(); + + ThreadLocale* threadLocale = GetCurrentThreadLocale(); + threadLocale->ctype_b = *addrOfClassInfoTable; + threadLocale->ctype_tolower = *addrOfToLowerTable; + threadLocale->ctype_toupper = *addrOfToUpperTable; + threadLocale->mb_cur_max = addrOfMbCurMax; } @@ -76,8 +74,7 @@ LocaleMonetaryDataBridge::LocaleMonetaryDataBridge() LocaleNumericDataBridge::LocaleNumericDataBridge(bool isGlobal) : - posixLocaleConv(&gPosixLocaleConv), - isGlobal(isGlobal) + posixLocaleConv(&gPosixLocaleConv) { } @@ -97,8 +94,7 @@ LocaleTimeDataBridge::LocaleTimeDataBridge() TimeConversionDataBridge::TimeConversionDataBridge(bool isGlobal) : localDaylight(daylight), - localTimezone(timezone), - isGlobal(isGlobal) + localTimezone(timezone) { if (isGlobal) { addrOfDaylight = &daylight; @@ -121,8 +117,7 @@ LocaleDataBridge::LocaleDataBridge(bool isGlobal) ctypeDataBridge(isGlobal), numericDataBridge(isGlobal), timeConversionDataBridge(isGlobal), - posixLanginfo(gPosixLanginfo), - isGlobal(isGlobal) + posixLanginfo(gPosixLanginfo) { } @@ -131,7 +126,7 @@ void LocaleDataBridge::ApplyToCurrentThread() { ctypeDataBridge.ApplyToCurrentThread(); - // While timeConverstionDataBridge stores read-write variables, + // While timeConversionDataBridge stores read-write variables, // these variables are global (by POSIX definition). Furthermore, // none of the backends seem to access these variables // directly. The values are set in the bridge mostly for diff --git a/src/system/libroot/posix/locale/LocaleInternal.cpp b/src/system/libroot/posix/locale/LocaleInternal.cpp index 6557133819..8fcb861192 100644 --- a/src/system/libroot/posix/locale/LocaleInternal.cpp +++ b/src/system/libroot/posix/locale/LocaleInternal.cpp @@ -1,18 +1,24 @@ /* * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de + * Copyright 2022, Trung Nguyen, trungnt282910@gmail.com * All rights reserved. Distributed under the terms of the MIT License. */ #include "LocaleInternal.h" +#include #include #include #include +#include +#include #include +#include "LocaleData.h" + namespace BPrivate { namespace Libroot { @@ -21,9 +27,8 @@ namespace Libroot { status_t GetLocalesFromEnvironment(int category, const char** locales) { - if (category > LC_LAST) { + if (category > LC_LAST) return B_BAD_VALUE; - } const char* locale = getenv("LC_ALL"); if (locale != NULL && *locale != '\0') @@ -72,5 +77,33 @@ GetLocalesFromEnvironment(int category, const char** locales) return B_OK; } + +static void +DestroyThreadLocale(void* ptr) +{ + ThreadLocale* threadLocale = (ThreadLocale*)ptr; + delete threadLocale; +} + + +ThreadLocale* +GetCurrentThreadLocale() +{ + ThreadLocale* threadLocale = (ThreadLocale*)tls_get(TLS_LOCALE_SLOT); + if (threadLocale == NULL) { + threadLocale = new ThreadLocale(); + threadLocale->threadLocaleInfo = NULL; + threadLocale->ctype_b = __ctype_b; + threadLocale->ctype_tolower = __ctype_tolower; + threadLocale->ctype_toupper = __ctype_toupper; + threadLocale->mb_cur_max = &__ctype_mb_cur_max; + + on_exit_thread(DestroyThreadLocale, threadLocale); + tls_set(TLS_LOCALE_SLOT, threadLocale); + } + return threadLocale; +} + + } // namespace Libroot } // namespace BPrivate diff --git a/src/system/libroot/posix/locale/LocaleInternal.h b/src/system/libroot/posix/locale/LocaleInternal.h index 4f381af493..952531069d 100644 --- a/src/system/libroot/posix/locale/LocaleInternal.h +++ b/src/system/libroot/posix/locale/LocaleInternal.h @@ -17,5 +17,19 @@ namespace Libroot { status_t GetLocalesFromEnvironment(int category, const char** locales); + +// The pointer in the TLS will point to this struct. +struct ThreadLocale { + struct LocaleBackendData* threadLocaleInfo; + + const unsigned short int* ctype_b; + const int* ctype_tolower; + const int* ctype_toupper; + const unsigned short int* mb_cur_max; +}; + +ThreadLocale* GetCurrentThreadLocale(); + + } // namespace Libroot } // namespace BPrivate diff --git a/src/system/libroot/posix/locale/ThreadLocale.cpp b/src/system/libroot/posix/locale/ThreadLocale.cpp deleted file mode 100644 index 3ce6ad84ba..0000000000 --- a/src/system/libroot/posix/locale/ThreadLocale.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2022, Trung Nguyen, trungnt282910@gmail.com - * All rights reserved. Distributed under the terms of the MIT License. - */ - - -#include - -#include -#include -#include - - - -namespace BPrivate { -namespace Libroot { - - -static void -DestroyThreadLocale(void* ptr) -{ - ThreadLocale* threadLocale = (ThreadLocale*)ptr; - delete threadLocale; -} - - -ThreadLocale* -GetCurrentThreadLocale() -{ - ThreadLocale* threadLocale = (ThreadLocale*)tls_get(TLS_LOCALE_SLOT); - if (threadLocale == NULL) { - threadLocale = new ThreadLocale(); - threadLocale->threadLocaleInfo = NULL; - threadLocale->ctype_b = __ctype_b; - threadLocale->ctype_tolower = __ctype_tolower; - threadLocale->ctype_toupper = __ctype_toupper; - - on_exit_thread(DestroyThreadLocale, threadLocale); - tls_set(TLS_LOCALE_SLOT, threadLocale); - } - return threadLocale; -} - - -extern "C" const unsigned short** -__ctype_b_loc() -{ - return &GetCurrentThreadLocale()->ctype_b; -} - - -extern "C" const int** -__ctype_tolower_loc() -{ - return &GetCurrentThreadLocale()->ctype_tolower; -} - - -extern "C" const int** -__ctype_toupper_loc() -{ - return &GetCurrentThreadLocale()->ctype_toupper; -} - - -} // namespace Libroot -} // namespace BPrivate diff --git a/src/system/libroot/posix/locale/ctype.cpp b/src/system/libroot/posix/locale/ctype.cpp index 38578e3b39..4316edce47 100644 --- a/src/system/libroot/posix/locale/ctype.cpp +++ b/src/system/libroot/posix/locale/ctype.cpp @@ -30,16 +30,6 @@ extern "C" { -unsigned short int __ctype_mb_cur_max = 1; - - -unsigned short -__ctype_get_mb_cur_max() -{ - return __ctype_mb_cur_max; -} - - int isalnum(int c) { diff --git a/src/system/libroot/posix/locale/ctype_loc.cpp b/src/system/libroot/posix/locale/ctype_loc_global.cpp similarity index 69% rename from src/system/libroot/posix/locale/ctype_loc.cpp rename to src/system/libroot/posix/locale/ctype_loc_global.cpp index 4c3b127032..991563a692 100644 --- a/src/system/libroot/posix/locale/ctype_loc.cpp +++ b/src/system/libroot/posix/locale/ctype_loc_global.cpp @@ -6,28 +6,38 @@ #include +#include + // These functions are intended for scenarios where we cannot // link to the whole libroot and access pthread functions; // for example, when we're in the bootloader, kernel or the // runtime_loader. -extern "C" const unsigned short** + +extern "C" const unsigned short *const *const __ctype_b_loc() { return &__ctype_b; } -extern "C" const int** +extern "C" const int *const *const __ctype_tolower_loc() { return &__ctype_tolower; } -extern "C" const int** +extern "C" const int *const *const __ctype_toupper_loc() { return &__ctype_toupper; } + + +extern "C" unsigned short +__ctype_get_mb_cur_max() +{ + return __ctype_mb_cur_max; +} diff --git a/src/system/libroot/posix/locale/ctype_loc_thread.cpp b/src/system/libroot/posix/locale/ctype_loc_thread.cpp new file mode 100644 index 0000000000..79edd66139 --- /dev/null +++ b/src/system/libroot/posix/locale/ctype_loc_thread.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2022, Trung Nguyen, trungnt282910@gmail.com + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#include + +#include "LocaleInternal.h" + + +using BPrivate::Libroot::GetCurrentThreadLocale; + + +extern "C" const unsigned short int *const *const +__ctype_b_loc() +{ + return &GetCurrentThreadLocale()->ctype_b; +} + + +extern "C" const int *const *const +__ctype_tolower_loc() +{ + return &GetCurrentThreadLocale()->ctype_tolower; +} + + +extern "C" const int *const *const +__ctype_toupper_loc() +{ + return &GetCurrentThreadLocale()->ctype_toupper; +} + + +extern "C" unsigned short +__ctype_get_mb_cur_max() +{ + return *GetCurrentThreadLocale()->mb_cur_max; +} diff --git a/src/system/runtime_loader/Jamfile b/src/system/runtime_loader/Jamfile index 7134da4e7a..da697c754a 100644 --- a/src/system/runtime_loader/Jamfile +++ b/src/system/runtime_loader/Jamfile @@ -49,7 +49,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { fcntl.o ctype.o - ctype_loc.o + ctype_loc_global.o LocaleData.o memchr.o