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.
This commit is contained in:
Augustin Cavalier
2026-01-15 18:48:10 -05:00
parent 2d20dfef26
commit 9be2b373d3
18 changed files with 144 additions and 164 deletions
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
@@ -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;
+4 -4
View File
@@ -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
;
}
}
@@ -5,13 +5,12 @@
#include "LocaleBackend.h"
#include "LocaleInternal.h"
#include <dlfcn.h>
#include <pthread.h>
#include <string.h>
#include <ThreadLocale.h>
namespace BPrivate {
namespace Libroot {
@@ -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;
@@ -5,20 +5,17 @@
#include "LocaleBackend.h"
#include "LocaleInternal.h"
#include <ctype.h>
#include <langinfo.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <LocaleData.h>
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
@@ -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 <ctype.h>
#include <locale.h>
#include <stdlib.h>
#include <strings.h>
#include <tls.h>
#include <OS.h>
#include <Debug.h>
#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
@@ -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
@@ -1,67 +0,0 @@
/*
* Copyright 2022, Trung Nguyen, trungnt282910@gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <ctype.h>
#include <tls.h>
#include <kernel/OS.h>
#include <ThreadLocale.h>
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
-10
View File
@@ -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)
{
@@ -6,28 +6,38 @@
#include <ctype.h>
#include <LocaleData.h>
// 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;
}
@@ -0,0 +1,40 @@
/*
* Copyright 2022, Trung Nguyen, trungnt282910@gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <ctype.h>
#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;
}
+1 -1
View File
@@ -49,7 +49,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
<src!system!libroot!posix!$(architecture)>fcntl.o
<src!system!libroot!posix!locale!$(architecture)>ctype.o
<src!system!libroot!posix!locale!$(architecture)>ctype_loc.o
<src!system!libroot!posix!locale!$(architecture)>ctype_loc_global.o
<src!system!libroot!posix!locale!$(architecture)>LocaleData.o
<src!system!libroot!posix!musl!string!$(architecture)>memchr.o