/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005, 2008 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#define NMBSTATET 10
#define C_LOCALE_INITIALIZER { \
- 0, NULL, \
+ 0, XPERMANENT, \
{}, {}, {}, {}, {}, \
{}, {}, {}, {}, {}, \
+ OS_UNFAIR_LOCK_INIT, \
XMAGIC, \
1, 0, 0, 0, 0, 0, 1, 1, 0, \
NULL, \
}
static char C[] = "C";
-static const struct _xlocale __c_locale = C_LOCALE_INITIALIZER;
+static struct _xlocale __c_locale = C_LOCALE_INITIALIZER;
const locale_t _c_locale = (const locale_t)&__c_locale;
-__private_extern__ struct _xlocale __global_locale = C_LOCALE_INITIALIZER;
-__private_extern__ pthread_key_t __locale_key = (pthread_key_t)-1;
+struct _xlocale __global_locale = C_LOCALE_INITIALIZER;
+pthread_key_t __locale_key = (pthread_key_t)-1;
extern int __collate_load_tables(const char *, locale_t);
extern int __detect_path_locale(void);
}
/*
- * Make a copy of a locale_t, locking/unlocking the source as determined
- * by the lock flag. A NULL locale_t means to make a copy of the current
+ * Make a copy of a locale_t, locking/unlocking the source.
+ * A NULL locale_t means to make a copy of the current
* locale while LC_GLOBAL_LOCALE means to copy the global locale. If
* &__c_locale is passed (meaning a C locale is desired), just make
* a copy.
return NULL;
new->__refcount = 1;
new->__free_extra = (__free_extra_t)_releaselocale;
+ new->__lock = OS_UNFAIR_LOCK_INIT;
if (loc == NULL)
loc = __current_locale();
else if (loc == LC_GLOBAL_LOCALE)
loc = &__global_locale;
else if (loc == &__c_locale) {
*new = __c_locale;
+ new->__refcount = 1;
+ new->__free_extra = (__free_extra_t)_releaselocale;
+ new->__lock = OS_UNFAIR_LOCK_INIT;
return new;
}
+ XL_LOCK(loc);
_copylocale(new, loc);
+ XL_UNLOCK(loc);
/* __mbs_mblen is the first of NMBSTATET mbstate_t buffers */
bzero(&new->__mbs_mblen, offsetof(struct _xlocale, __magic)
- offsetof(struct _xlocale, __mbs_mblen));
XL_RETAIN(new->__lc_numeric_loc);
/* time */
XL_RETAIN(new->__lc_time);
- /* newale_t */
- XL_RETAIN(new->__lc_localeconv);
return new;
}
XL_RELEASE(loc->__lc_numeric_loc);
/* time */
XL_RELEASE(loc->__lc_time);
- /* locale_t */
- XL_RELEASE(loc->__lc_localeconv);
}
/*
loc->__numeric_fp_cvt = LC_NUMERIC_FP_SAME_LOCALE;
return loc;
} else {
- loc->__lc_numeric_loc = newlocale(LC_CTYPE_MASK, numeric, &__c_locale);
+ loc->__lc_numeric_loc = newlocale(LC_CTYPE_MASK, numeric, (locale_t)&__c_locale);
if (loc->__lc_numeric_loc) {
loc->__numeric_fp_cvt = LC_NUMERIC_FP_USE_LOCALE;
return loc->__lc_numeric_loc;
querylocale(int mask, locale_t loc)
{
int m;
+ const char *ret;
if (_checklocale(loc) < 0 || (mask & LC_ALL_MASK) == 0) {
errno = EINVAL;
return NULL;
}
- if (loc == NULL)
- loc = __current_locale();
- else if (loc == LC_GLOBAL_LOCALE)
- loc = &__global_locale;
- for(m = 1; m <= _LC_LAST_MASK; m <<= 1) {
- if (m & mask) {
- switch(m) {
- case LC_COLLATE_MASK:
- return (loc->__collate_load_error ? C : loc->__lc_collate->__encoding);
- case LC_CTYPE_MASK:
- return loc->__lc_ctype->__ctype_encoding;
- case LC_MESSAGES_MASK:
- return (loc->_messages_using_locale ? loc->__lc_messages->_messages_locale_buf : C);
- case LC_MONETARY_MASK:
- return (loc->_monetary_using_locale ? loc->__lc_monetary->_monetary_locale_buf : C);
- case LC_NUMERIC_MASK:
- return (loc->_numeric_using_locale ? loc->__lc_numeric->_numeric_locale_buf : C);
- case LC_TIME_MASK:
- return (loc->_time_using_locale ? loc->__lc_time->_time_locale_buf : C);
- }
- }
+ DEFAULT_CURRENT_LOCALE(loc);
+ m = ffs(mask);
+ if (m == 0 || m > _LC_NUM_MASK) {
+ errno = EINVAL;
+ return NULL;
}
- /* should never get here */
- errno = EINVAL;
- return NULL;
+ XL_LOCK(loc);
+ switch(1 << (m - 1)) {
+ case LC_COLLATE_MASK:
+ ret = (loc->__collate_load_error ? C : loc->__lc_collate->__encoding);
+ break;
+ case LC_CTYPE_MASK:
+ ret = loc->__lc_ctype->__ctype_encoding;
+ break;
+ case LC_MESSAGES_MASK:
+ ret = (loc->_messages_using_locale ? loc->__lc_messages->_messages_locale_buf : C);
+ break;
+ case LC_MONETARY_MASK:
+ ret = (loc->_monetary_using_locale ? loc->__lc_monetary->_monetary_locale_buf : C);
+ break;
+ case LC_NUMERIC_MASK:
+ ret = (loc->_numeric_using_locale ? loc->__lc_numeric->_numeric_locale_buf : C);
+ break;
+ case LC_TIME_MASK:
+ ret = (loc->_time_using_locale ? loc->__lc_time->_time_locale_buf : C);
+ break;
+ default:
+ /* should never get here */
+ XL_UNLOCK(loc);
+ errno = EINVAL;
+ return NULL;
+ }
+ XL_UNLOCK(loc);
+ return ret;
}
/*
errno = EINVAL;
return NULL;
}
- if (loc == &__global_locale) /* should never happen */
- loc = LC_GLOBAL_LOCALE;
+ if (loc == LC_GLOBAL_LOCALE ||
+ loc == &__global_locale) /* should never happen */
+ loc = NULL;
+ XL_RETAIN(loc);
orig = pthread_getspecific(__locale_key);
- pthread_setspecific(__locale_key, loc == LC_GLOBAL_LOCALE ? NULL : loc);
+ pthread_setspecific(__locale_key, loc);
+ XL_RELEASE(orig);
}
return (orig ? orig : LC_GLOBAL_LOCALE);
}
return __locale_ptr(loc)->__lc_ctype->__mb_cur_max;
}
+static void
+__xlocale_release(void *loc)
+{
+ locale_t l = loc;
+ XL_RELEASE(l);
+}
+
/*
* Called from the Libc initializer to setup the thread-specific key.
*/
-/*
- * Partition _pthread_keys in a lower part that dyld can use, and an upper
- * part for libSystem. The libSystem part starts at __pthread_tsd_first = 10.
- * dyld will set this value to 1.
- */
-extern int __pthread_tsd_first;
-
__private_extern__ void
__xlocale_init(void)
{
- if (__locale_key == (pthread_key_t)-1)
- __locale_key = __pthread_tsd_first;
+ if (__locale_key == (pthread_key_t)-1) {
+ __locale_key = __LIBC_PTHREAD_KEY_XLOCALE;
+ pthread_key_init_np(__locale_key, __xlocale_release);
+ }
}