]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/locale/DESIGN.xlocale
zfs: merge openzfs/zfs@f795e90a1
[FreeBSD/FreeBSD.git] / lib / libc / locale / DESIGN.xlocale
1
2 Design of xlocale
3 =================
4
5 The xlocale APIs come from Darwin, although a subset is now part of POSIX 2008.
6 They fall into two broad categories:
7
8 - Manipulation of per-thread locales (POSIX)
9 - Locale-aware functions taking an explicit locale argument (Darwin)
10
11 This document describes the implementation of these APIs for FreeBSD.
12
13 Goals
14 -----
15
16 The overall goal of this implementation is to be compatible with the Darwin
17 version.  Additionally, it should include minimal changes to the existing
18 locale code.  A lot of the existing locale code originates with 4BSD or earlier
19 and has had over a decade of testing.  Replacing this code, unless absolutely
20 necessary, gives us the potential for more bugs without much benefit.
21
22 With this in mind, various libc-private functions have been modified to take a
23 locale_t parameter.  This causes a compiler error if they are accidentally
24 called without a locale.  This approach was taken, rather than adding _l
25 variants of these functions, to make it harder for accidental uses of the
26 global-locale versions to slip in.
27
28 Locale Objects
29 --------------
30
31 A locale is encapsulated in a `locale_t`, which is an opaque type: a pointer to
32 a `struct _xlocale`.  The name `_xlocale` is unfortunate, as it does not fit
33 well with existing conventions, but is used because this is the name the Darwin
34 implementation gives to this structure and so may be used by existing (bad) code.
35
36 This structure should include all of the information corresponding to a locale.
37 A locale_t is almost immutable after creation.  There are no functions that modify it,
38 and it can therefore be used without locking.  It is the responsibility of the
39 caller to ensure that a locale is not deallocated during a call that uses it.
40
41 Each locale contains a number of components, one for each of the categories
42 supported by `setlocale()`.  These are likewise immutable after creation.  This
43 differs from the Darwin implementation, which includes a deprecated
44 `setinvalidrune()` function that can modify the rune locale.
45
46 The exception to these mutability rules is a set of `mbstate_t` flags stored
47 with each locale.  These are used by various functions that previously had a
48 static local `mbstate_t` variable.  
49
50 The components are reference counted, and so can be aliased between locale
51 objects.  This makes copying locales very cheap.
52
53 The Global Locale
54 -----------------
55
56 All locales and locale components are reference counted.  The global locale,
57 however, is special.  It, and all of its components, are static and so no
58 malloc() memory is required when using a single locale.
59
60 This means that threads using the global locale are subject to the same
61 constraints as with the pre-xlocale libc.  Calls to any locale-aware functions
62 in threads using the global locale, while modifying the global locale, have
63 undefined behaviour.
64
65 Because of this, we have to ensure that we always copy the components of the
66 global locale, rather than alias them.  
67
68 It would be cleaner to simply remove the special treatment of the global locale
69 and have a locale_t lazily allocated for the global context.  This would cost a
70 little more `malloc()` memory, so is not done in the initial version.
71
72 Caching
73 -------
74
75 The existing locale implementation included several ad-hoc caching layers.
76 None of these were thread safe.  Caching is only really of use for supporting
77 the pattern where the locale is briefly changed to something and then changed
78 back.
79
80 The current xlocale implementation removes the caching entirely.  This pattern
81 is not one that should be encouraged.  If you need to make some calls with a
82 modified locale, then you should use the _l suffix versions of the calls,
83 rather than switch the global locale.  If you do need to temporarily switch the
84 locale and then switch it back, `uselocale()` provides a way of doing this very
85 easily: It returns the old locale, which can then be passed to a subsequent
86 call to `uselocale()` to restore it, without the need to load any locale data
87 from the disk.
88
89 If, in the future, it is determined that caching is beneficial, it can be added
90 quite easily in xlocale.c.  Given, however, that any locale-aware call is going
91 to be a preparation for presenting data to the user, and so is invariably going
92 to be part of an I/O operation, this seems like a case of premature
93 optimisation.
94
95 localeconv
96 ----------
97
98 The `localeconv()` function is an exception to the immutable-after-creation
99 rule.  In the classic implementation, this function returns a pointer to some
100 global storage, which is initialised with the data from the current locale.
101 This is not possible in a multithreaded environment, with multiple locales.  
102
103 Instead, each locale contains a `struct lconv` that is lazily initialised on
104 calls to `localeconv()`.  This is not protected by any locking, however this is
105 still safe on any machine where word-sized stores are atomic: two concurrent
106 calls will write the same data into the structure.
107
108 Explicit Locale Calls
109 ---------------------
110
111 A large number of functions have been modified to take an explicit `locale_t`
112 parameter.  The old APIs are then reimplemented with a call to `__get_locale()`
113 to supply the `locale_t` parameter.  This is in line with the Darwin public
114 APIs, but also simplifies the modifications to these functions.  The
115 `__get_locale()` function is now the only way to access the current locale
116 within libc.  All of the old globals have gone, so there is now a linker error
117 if any functions attempt to use them.  
118
119 The ctype.h functions are a little different.  These are not implemented in
120 terms of their locale-aware versions, for performance reasons.  Each of these
121 is implemented as a short inline function.
122
123 Differences to Darwin APIs
124 --------------------------
125
126 `strtoq_l()` and `strtouq_l() `are not provided.  These are extensions to
127 deprecated functions - we should not be encouraging people to use deprecated
128 interfaces.
129
130 Locale Placeholders
131 -------------------
132
133 The pointer values 0 and -1 have special meanings as `locale_t` values.  Any
134 public function that accepts a `locale_t` parameter must use the `FIX_LOCALE()`
135 macro on it before using it.  For efficiency, this can be emitted in functions
136 which *only* use their locale parameter as an argument to another public
137 function, as the callee will do the `FIX_LOCALE()` itself.
138
139 Potential Improvements
140 ----------------------
141
142 Currently, the current rune set is accessed via a function call.  This makes it
143 fairly expensive to use any of the ctype.h functions.  We could improve this
144 quite a lot by storing the rune locale data in a __thread-qualified variable.
145
146 Several of the existing FreeBSD locale-aware functions appear to be wrong.  For
147 example, most of the `strto*()` family should probably use `digittoint_l()`,
148 but instead they assume ASCII.  These will break if using a character encoding
149 that does not put numbers and the letters A-F in the same location as ASCII.
150 Some functions, like `strcoll()` only work on single-byte encodings.  No
151 attempt has been made to fix existing limitations in the libc functions other
152 than to add support for xlocale.
153
154 Intuitively, setting a thread-local locale should ensure that all locale-aware
155 functions can be used safely from that thread.  In fact, this is not the case
156 in either this implementation or the Darwin one.  You must call `duplocale()`
157 or `newlocale()` before calling `uselocale()`.  This is a bit ugly, and it
158 would be better if libc ensure that every thread had its own locale object.