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
+3 -11
View File
@@ -61,15 +61,9 @@ enum {
_ISgraph = 0x8000 /* graphical */ _ISgraph = 0x8000 /* graphical */
}; };
/* Characteristics */ extern const unsigned short int *const *const __ctype_b_loc();
extern const unsigned short int *__ctype_b; extern const int *const *const __ctype_tolower_loc();
/* Case conversions */ extern const int *const *const __ctype_toupper_loc();
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();
#define __isctype(c, type) \ #define __isctype(c, type) \
((*__ctype_b_loc())[(int)(c)] & (unsigned short int)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 isupper(c) __isctype((c), _ISupper)
#define isxdigit(c) __isctype((c), _ISxdigit) #define isxdigit(c) __isctype((c), _ISxdigit)
extern unsigned short int __ctype_mb_cur_max;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@@ -25,11 +25,13 @@ private:
const unsigned short* localClassInfoTable; const unsigned short* localClassInfoTable;
const int* localToLowerTable; const int* localToLowerTable;
const int* localToUpperTable; const int* localToUpperTable;
unsigned short localMbCurMax;
public: public:
const unsigned short** addrOfClassInfoTable; const unsigned short** addrOfClassInfoTable;
const int** addrOfToLowerTable; const int** addrOfToLowerTable;
const int** addrOfToUpperTable; const int** addrOfToUpperTable;
unsigned short* addrOfMbCurMax;
const unsigned short* const posixClassInfo; const unsigned short* const posixClassInfo;
const int* const posixToLowerMap; const int* const posixToLowerMap;
@@ -39,7 +41,6 @@ public:
LocaleCtypeDataBridge(bool isGlobal); LocaleCtypeDataBridge(bool isGlobal);
void setMbCurMax(unsigned short mbCurMax);
void ApplyToCurrentThread(); void ApplyToCurrentThread();
}; };
@@ -61,7 +62,6 @@ struct LocaleMonetaryDataBridge {
struct LocaleNumericDataBridge { struct LocaleNumericDataBridge {
public: public:
const struct lconv* const posixLocaleConv; const struct lconv* const posixLocaleConv;
bool isGlobal;
LocaleNumericDataBridge(bool isGlobal); LocaleNumericDataBridge(bool isGlobal);
~LocaleNumericDataBridge(); ~LocaleNumericDataBridge();
@@ -89,7 +89,6 @@ public:
int* addrOfDaylight; int* addrOfDaylight;
long* addrOfTimezone; long* addrOfTimezone;
char** addrOfTZName; char** addrOfTZName;
bool isGlobal;
TimeConversionDataBridge(bool isGlobal); TimeConversionDataBridge(bool isGlobal);
}; };
@@ -103,7 +102,6 @@ struct LocaleDataBridge {
LocaleTimeDataBridge timeDataBridge; LocaleTimeDataBridge timeDataBridge;
TimeConversionDataBridge timeConversionDataBridge; TimeConversionDataBridge timeConversionDataBridge;
const char** const posixLanginfo; const char** const posixLanginfo;
bool isGlobal;
LocaleDataBridge(bool isGlobal); LocaleDataBridge(bool isGlobal);
@@ -182,6 +180,7 @@ LocaleBackend* GetCurrentLocaleBackend();
extern LocaleBackend* gGlobalLocaleBackend; extern LocaleBackend* gGlobalLocaleBackend;
extern LocaleDataBridge gGlobalLocaleDataBridge; extern LocaleDataBridge gGlobalLocaleDataBridge;
} // namespace Libroot } // namespace Libroot
} // namespace BPrivate } // namespace BPrivate
@@ -9,6 +9,15 @@
#include <locale.h> #include <locale.h>
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 BPrivate {
namespace Libroot { namespace Libroot {
@@ -1,34 +0,0 @@
/*
* Copyright 2022, Trung Nguyen, [email protected]
* 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
+1 -1
View File
@@ -308,7 +308,7 @@ for platform in [ MultiBootSubDirSetup ] {
BootMergeObject boot_libroot_$(platform:G=).o : BootMergeObject boot_libroot_$(platform:G=).o :
abs.c abs.c
ctype_loc.cpp ctype_loc_global.cpp
ctype_l.cpp ctype_l.cpp
ctype.cpp ctype.cpp
generic_memcpy.c generic_memcpy.c
+1 -1
View File
@@ -74,7 +74,7 @@ KernelMergeObject kernel_lib_posix.o :
utime.c utime.c
# locale # locale
ctype_loc.cpp ctype_loc_global.cpp
ctype_l.cpp ctype_l.cpp
ctype.cpp ctype.cpp
localeconv.cpp localeconv.cpp
@@ -74,7 +74,7 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName)
ucnv_reset(converter); ucnv_reset(converter);
fDataBridge->setMbCurMax(ucnv_getMaxCharSize(converter)); *fDataBridge->addrOfMbCurMax = ucnv_getMaxCharSize(converter);
char buffer[] = { 0, 0 }; char buffer[] = { 0, 0 };
for (int i = 0; i < 256; ++i) { for (int i = 0; i < 256; ++i) {
@@ -150,8 +150,7 @@ ICUCtypeData::SetToPosix()
memcpy(fClassInfo, fDataBridge->posixClassInfo, sizeof(fClassInfo)); memcpy(fClassInfo, fDataBridge->posixClassInfo, sizeof(fClassInfo));
memcpy(fToLowerMap, fDataBridge->posixToLowerMap, sizeof(fToLowerMap)); memcpy(fToLowerMap, fDataBridge->posixToLowerMap, sizeof(fToLowerMap));
memcpy(fToUpperMap, fDataBridge->posixToUpperMap, sizeof(fToUpperMap)); memcpy(fToUpperMap, fDataBridge->posixToUpperMap, sizeof(fToUpperMap));
*fDataBridge->addrOfMbCurMax = 1;
fDataBridge->setMbCurMax(1);
} }
return result; return result;
+4 -4
View File
@@ -13,8 +13,9 @@ for architectureObject in [ MultiArchSubDirSetup ] {
local architecture = $(TARGET_PACKAGING_ARCH) ; local architecture = $(TARGET_PACKAGING_ARCH) ;
MergeObject <$(architecture)>posix_locale.o : MergeObject <$(architecture)>posix_locale.o :
ctype_l.cpp
ctype.cpp ctype.cpp
ctype_l.cpp
ctype_loc_thread.cpp
LocaleBackend.cpp LocaleBackend.cpp
LocaleData.cpp LocaleData.cpp
LocaleDataBridge.cpp LocaleDataBridge.cpp
@@ -23,13 +24,12 @@ for architectureObject in [ MultiArchSubDirSetup ] {
localeconv.cpp localeconv.cpp
nl_langinfo.cpp nl_langinfo.cpp
setlocale.cpp setlocale.cpp
ThreadLocale.cpp
wctype_l.cpp wctype_l.cpp
wctype.cpp wctype.cpp
; ;
MergeObject <$(architecture)>ctype_loc.o : MergeObject <$(architecture)>ctype_loc_global.o :
ctype_loc.cpp ctype_loc_global.cpp
; ;
} }
} }
@@ -5,13 +5,12 @@
#include "LocaleBackend.h" #include "LocaleBackend.h"
#include "LocaleInternal.h"
#include <dlfcn.h> #include <dlfcn.h>
#include <pthread.h> #include <pthread.h>
#include <string.h> #include <string.h>
#include <ThreadLocale.h>
namespace BPrivate { namespace BPrivate {
namespace Libroot { namespace Libroot {
@@ -329,3 +329,4 @@ const char* gPosixLanginfo[_NL_LANGINFO_LAST] = {
const unsigned short* __ctype_b = &BPrivate::Libroot::gPosixClassInfo[128]; const unsigned short* __ctype_b = &BPrivate::Libroot::gPosixClassInfo[128];
const int* __ctype_tolower = &BPrivate::Libroot::gPosixToLowerMap[128]; const int* __ctype_tolower = &BPrivate::Libroot::gPosixToLowerMap[128];
const int* __ctype_toupper = &BPrivate::Libroot::gPosixToUpperMap[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 "LocaleBackend.h"
#include "LocaleInternal.h"
#include <ctype.h> #include <ctype.h>
#include <langinfo.h> #include <langinfo.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <LocaleData.h> #include <LocaleData.h>
extern const unsigned short* __ctype_b;
extern const int* __ctype_tolower;
extern const int* __ctype_toupper;
namespace BPrivate { namespace BPrivate {
namespace Libroot { namespace Libroot {
@@ -37,26 +34,27 @@ LocaleCtypeDataBridge::LocaleCtypeDataBridge(bool isGlobal)
addrOfClassInfoTable = &__ctype_b; addrOfClassInfoTable = &__ctype_b;
addrOfToLowerTable = &__ctype_tolower; addrOfToLowerTable = &__ctype_tolower;
addrOfToUpperTable = &__ctype_toupper; addrOfToUpperTable = &__ctype_toupper;
addrOfMbCurMax = &__ctype_mb_cur_max;
} else { } else {
addrOfClassInfoTable = &localClassInfoTable; addrOfClassInfoTable = &localClassInfoTable;
addrOfToLowerTable = &localToLowerTable; addrOfToLowerTable = &localToLowerTable;
addrOfToUpperTable = &localToUpperTable; addrOfToUpperTable = &localToUpperTable;
addrOfMbCurMax = &localMbCurMax;
} }
} }
void LocaleCtypeDataBridge::setMbCurMax(unsigned short mbCurMax)
{
__ctype_mb_cur_max = mbCurMax;
}
void void
LocaleCtypeDataBridge::ApplyToCurrentThread() LocaleCtypeDataBridge::ApplyToCurrentThread()
{ {
*__ctype_b_loc() = *addrOfClassInfoTable; if (isGlobal)
*__ctype_tolower_loc() = *addrOfToLowerTable; abort();
*__ctype_toupper_loc() = *addrOfToUpperTable;
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) LocaleNumericDataBridge::LocaleNumericDataBridge(bool isGlobal)
: :
posixLocaleConv(&gPosixLocaleConv), posixLocaleConv(&gPosixLocaleConv)
isGlobal(isGlobal)
{ {
} }
@@ -97,8 +94,7 @@ LocaleTimeDataBridge::LocaleTimeDataBridge()
TimeConversionDataBridge::TimeConversionDataBridge(bool isGlobal) TimeConversionDataBridge::TimeConversionDataBridge(bool isGlobal)
: :
localDaylight(daylight), localDaylight(daylight),
localTimezone(timezone), localTimezone(timezone)
isGlobal(isGlobal)
{ {
if (isGlobal) { if (isGlobal) {
addrOfDaylight = &daylight; addrOfDaylight = &daylight;
@@ -121,8 +117,7 @@ LocaleDataBridge::LocaleDataBridge(bool isGlobal)
ctypeDataBridge(isGlobal), ctypeDataBridge(isGlobal),
numericDataBridge(isGlobal), numericDataBridge(isGlobal),
timeConversionDataBridge(isGlobal), timeConversionDataBridge(isGlobal),
posixLanginfo(gPosixLanginfo), posixLanginfo(gPosixLanginfo)
isGlobal(isGlobal)
{ {
} }
@@ -131,7 +126,7 @@ void
LocaleDataBridge::ApplyToCurrentThread() LocaleDataBridge::ApplyToCurrentThread()
{ {
ctypeDataBridge.ApplyToCurrentThread(); ctypeDataBridge.ApplyToCurrentThread();
// While timeConverstionDataBridge stores read-write variables, // While timeConversionDataBridge stores read-write variables,
// these variables are global (by POSIX definition). Furthermore, // these variables are global (by POSIX definition). Furthermore,
// none of the backends seem to access these variables // none of the backends seem to access these variables
// directly. The values are set in the bridge mostly for // directly. The values are set in the bridge mostly for
@@ -1,18 +1,24 @@
/* /*
* Copyright 2004-2007, Axel Dörfler, [email protected] * Copyright 2004-2007, Axel Dörfler, [email protected]
* Copyright 2010, Oliver Tappe, [email protected] * Copyright 2010, Oliver Tappe, [email protected]
* Copyright 2022, Trung Nguyen, [email protected]
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#include "LocaleInternal.h" #include "LocaleInternal.h"
#include <ctype.h>
#include <locale.h> #include <locale.h>
#include <stdlib.h> #include <stdlib.h>
#include <strings.h> #include <strings.h>
#include <tls.h>
#include <OS.h>
#include <Debug.h> #include <Debug.h>
#include "LocaleData.h"
namespace BPrivate { namespace BPrivate {
namespace Libroot { namespace Libroot {
@@ -21,9 +27,8 @@ namespace Libroot {
status_t status_t
GetLocalesFromEnvironment(int category, const char** locales) GetLocalesFromEnvironment(int category, const char** locales)
{ {
if (category > LC_LAST) { if (category > LC_LAST)
return B_BAD_VALUE; return B_BAD_VALUE;
}
const char* locale = getenv("LC_ALL"); const char* locale = getenv("LC_ALL");
if (locale != NULL && *locale != '\0') if (locale != NULL && *locale != '\0')
@@ -72,5 +77,33 @@ GetLocalesFromEnvironment(int category, const char** locales)
return B_OK; 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 Libroot
} // namespace BPrivate } // namespace BPrivate
@@ -17,5 +17,19 @@ namespace Libroot {
status_t GetLocalesFromEnvironment(int category, const char** locales); 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 Libroot
} // namespace BPrivate } // namespace BPrivate
@@ -1,67 +0,0 @@
/*
* Copyright 2022, Trung Nguyen, [email protected]
* 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 int
isalnum(int c) isalnum(int c)
{ {
@@ -6,28 +6,38 @@
#include <ctype.h> #include <ctype.h>
#include <LocaleData.h>
// These functions are intended for scenarios where we cannot // These functions are intended for scenarios where we cannot
// link to the whole libroot and access pthread functions; // link to the whole libroot and access pthread functions;
// for example, when we're in the bootloader, kernel or the // for example, when we're in the bootloader, kernel or the
// runtime_loader. // runtime_loader.
extern "C" const unsigned short**
extern "C" const unsigned short *const *const
__ctype_b_loc() __ctype_b_loc()
{ {
return &__ctype_b; return &__ctype_b;
} }
extern "C" const int** extern "C" const int *const *const
__ctype_tolower_loc() __ctype_tolower_loc()
{ {
return &__ctype_tolower; return &__ctype_tolower;
} }
extern "C" const int** extern "C" const int *const *const
__ctype_toupper_loc() __ctype_toupper_loc()
{ {
return &__ctype_toupper; 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, [email protected]
* 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!$(architecture)>fcntl.o
<src!system!libroot!posix!locale!$(architecture)>ctype.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!locale!$(architecture)>LocaleData.o
<src!system!libroot!posix!musl!string!$(architecture)>memchr.o <src!system!libroot!posix!musl!string!$(architecture)>memchr.o