--- old/usr/src/head/iso/locale_iso.h	2013-06-16 17:44:30.705393710 +0000
+++ new/usr/src/head/iso/locale_iso.h	2013-06-16 17:44:30.714939435 +0000
@@ -115,6 +115,15 @@
 extern struct lconv	*localeconv();
 #endif
 
+/* XXX */
+typedef	struct _xlocale	*locale_t;
+
+locale_t	duplocale(locale_t);
+int		freelocale(locale_t);
+locale_t	newlocale(int, const char *, locale_t);
+const char	*querylocale(int, locale_t);
+locale_t	uselocale(locale_t);
+
 #if __cplusplus >= 199711L
 }
 #endif /* end of namespace std */
--- old/usr/src/lib/libc/amd64/Makefile	2013-06-16 17:44:31.167815372 +0000
+++ new/usr/src/lib/libc/amd64/Makefile	2013-06-16 17:44:31.179057767 +0000
@@ -774,7 +774,8 @@
 	wctrans.o		\
 	wctype.o		\
 	wcwidth.o		\
-	wscol.o
+	wscol.o			\
+	xlocale.o
 
 AIOOBJS=			\
 	aio.o			\
--- old/usr/src/lib/libc/i386/Makefile.com	2013-06-16 17:44:31.581771344 +0000
+++ new/usr/src/lib/libc/i386/Makefile.com	2013-06-16 17:44:31.594490501 +0000
@@ -816,7 +816,8 @@
 	wctrans.o		\
 	wctype.o		\
 	wcwidth.o		\
-	wscol.o
+	wscol.o			\
+	xlocale.o
 
 AIOOBJS=			\
 	aio.o			\
--- old/usr/src/lib/libc/port/locale/collate.c	2013-06-16 17:44:32.040220016 +0000
+++ new/usr/src/lib/libc/port/locale/collate.c	2013-06-16 17:44:32.057515409 +0000
@@ -65,6 +65,38 @@
 collate_info_t			*_collate_info;
 int _collate_load_error = 1;
 
+struct xlocale_collate __xlocale_global_collate = {
+	{{0}, "C"}, 1, 0
+};
+
+struct xlocale_collate __xlocale_C_collate = {
+	{{0}, "C"}, 1, 0
+};
+
+static void
+destruct_collate(void *t)
+{
+	struct xlocale_collate *table = t;
+
+	/* XXX */;
+}
+
+void *
+__collate_load(const char *encoding, locale_t unused)
+{
+	struct xlocale_collate *table;
+
+	if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
+		return &__xlocale_C_collate;
+	}
+
+	table = calloc(sizeof(struct xlocale_collate), 1);
+	if (table == NULL) {
+		/* XXX */
+	}
+
+	return (table);
+}
 
 int
 _collate_load_tables(const char *encoding)
--- old/usr/src/lib/libc/port/locale/collate.h	2013-06-16 17:44:32.480414996 +0000
+++ new/usr/src/lib/libc/port/locale/collate.h	2013-06-16 17:44:32.491779516 +0000
@@ -32,6 +32,8 @@
 #include <sys/types.h>
 #include <limits.h>
 
+#include "xlocale_private.h"
+
 #define	COLLATE_STR_LEN		24		/* should be 64-bit multiple */
 #define	COLLATE_VERSION		"IllumosCollate2\n"
 
@@ -92,6 +94,14 @@
 	int32_t pri[COLLATE_STR_LEN];
 } collate_subst_t;
 
+struct xlocale_collate {
+	struct xlocale_component header;
+	int __collate_load_error;
+	int __collate_substitute_nontrivial;
+
+	/* XXX */
+};
+
 int	_collate_load_tables(const char *);
 void	_collate_lookup(const wchar_t *, int *, int *, int, int **);
 size_t	_collate_wxfrm(const wchar_t *, wchar_t *, size_t);
--- old/usr/src/lib/libc/port/locale/lmessages.c	2013-06-16 17:44:32.912904415 +0000
+++ new/usr/src/lib/libc/port/locale/lmessages.c	2013-06-16 17:44:32.930614516 +0000
@@ -3,6 +3,11 @@
  * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -27,6 +32,7 @@
 
 #include "lint.h"
 #include <stddef.h>
+#include <stdlib.h>
 #include "ldpart.h"
 #include "lmessages.h"
 
@@ -34,6 +40,8 @@
 #define	LCMESSAGES_SIZE_MIN \
 	(offsetof(struct lc_messages_T, yesstr) / sizeof (char *))
 
+struct xlocale_messages __xlocale_global_messages;
+
 static char empty[] = "";
 
 static const struct lc_messages_T _C_messages_locale = {
@@ -43,31 +51,66 @@
 	"no"		/* nostr */
 };
 
-static struct lc_messages_T _messages_locale;
-static int	_messages_using_locale;
-static char	*_messages_locale_buf;
+static void
+destruct_messages(void *v)
+{
+	struct xlocale_messages *l = v;
 
-int
-__messages_load_locale(const char *name)
+	if (l->buffer != NULL)
+		free(l->buffer);
+
+	free(l);
+}
+
+static int
+messages_load_locale(struct xlocale_messages *loc, int *using_locale,
+    const char *name)
 {
 	int ret;
+	struct lc_messages_T *l = &loc->locale;
 
-	ret = __part_load_locale(name, &_messages_using_locale,
-	    &_messages_locale_buf, "LC_MESSAGES",
+	ret = __part_load_locale(name, using_locale,
+	    &loc->buffer, "LC_MESSAGES",
 	    LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
-	    (const char **)&_messages_locale);
+	    (const char **)l);
 	if (ret == _LDP_LOADED) {
-		if (_messages_locale.yesstr == NULL)
-			_messages_locale.yesstr = empty;
-		if (_messages_locale.nostr == NULL)
-			_messages_locale.nostr = empty;
+		if (l->yesstr == NULL)
+			l->yesstr = empty;
+		if (l->nostr == NULL)
+			l->nostr = empty;
 	}
+
 	return (ret);
 }
 
+int
+__messages_load_locale(const char *name)
+{
+	return (messages_load_locale(&__xlocale_global_messages,
+	    &__xlocale_global_locale.using_messages_locale, name));
+}
+
+void *
+__messages_load(const char *name, locale_t l)
+{
+	struct xlocale_messages *new;
+
+	new = calloc(sizeof(struct xlocale_messages), 1);
+	/* XXX */
+	new->header.header.destructor = destruct_messages;
+	if (messages_load_locale(new, &l->using_messages_locale, name) ==
+	    _LDP_ERROR) {
+		xlocale_release(new);
+		return (NULL);
+	}
+
+	return (new);
+}
+
 struct lc_messages_T *
-__get_current_messages_locale(void)
+__get_current_messages_locale(locale_t loc)
 {
-	return (_messages_using_locale ? &_messages_locale :
-	    (struct lc_messages_T *)&_C_messages_locale);
+	return (loc->using_messages_locale
+	    ? &((struct xlocale_messages *)loc->components[XLC_MESSAGES])->locale
+	    : (struct lc_messages_T *)&_C_messages_locale);
 }
--- old/usr/src/lib/libc/port/locale/lmessages.h	2013-06-16 17:44:33.295787139 +0000
+++ new/usr/src/lib/libc/port/locale/lmessages.h	2013-06-16 17:44:33.312216117 +0000
@@ -2,6 +2,11 @@
  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -27,6 +32,8 @@
 #ifndef _LMESSAGES_H_
 #define	_LMESSAGES_H_
 
+#include "xlocale_private.h"
+
 struct	lc_messages_T {
 	const char	*yesexpr;
 	const char	*noexpr;
@@ -34,7 +41,13 @@
 	const char	*nostr;
 };
 
-struct lc_messages_T *__get_current_messages_locale(void);
+struct xlocale_messages {
+	struct xlocale_component header;
+	char *buffer;
+	struct lc_messages_T locale;
+};
+
+struct lc_messages_T *__get_current_messages_locale(locale_t);
 int	__messages_load_locale(const char *);
 
 #endif /* !_LMESSAGES_H_ */
--- old/usr/src/lib/libc/port/locale/lmonetary.c	2013-06-16 17:44:33.689376408 +0000
+++ new/usr/src/lib/libc/port/locale/lmonetary.c	2013-06-16 17:44:33.706636769 +0000
@@ -3,6 +3,11 @@
  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -29,6 +34,7 @@
 #include <limits.h>
 #include <stddef.h>
 #include <stdlib.h>
+
 #include "ldpart.h"
 #include "lmonetary.h"
 
@@ -70,6 +76,8 @@
 static int	_monetary_using_locale;
 static char	*_monetary_locale_buf;
 
+struct xlocale_monetary __xlocale_global_monetary;
+
 static char
 cnv(const char *str)
 {
@@ -80,8 +88,20 @@
 	return ((char)i);
 }
 
-int
-__monetary_load_locale(const char *name)
+static void
+destruct_monetary(void *v)
+{
+	struct xlocale_monetary *l = v;
+
+	if (l->buffer != NULL)
+		free(l->buffer);
+
+	free(l);
+}
+
+static int
+monetary_load_locale_l(struct xlocale_monetary *loc, int *using_locale,
+    int *changed, const char *name)
 {
 	int ret;
 
@@ -130,9 +150,35 @@
 	return (ret);
 }
 
+int
+__monetary_load_locale(const char *name)
+{
+	return (monetary_load_locale_l(&__xlocale_global_monetary,
+	    &__xlocale_global_locale.using_monetary_locale,
+	    &__xlocale_global_locale.monetary_locale_changed, name));
+}
+
+void *
+__monetary_load(const char *name, locale_t loc)
+{
+	struct xlocale_monetary *new;
+
+	new = calloc(sizeof(struct xlocale_monetary), 1);
+	/* XXX */
+	new->header.header.destructor = destruct_monetary;
+	if (monetary_load_locale_l(new, &loc->using_monetary_locale,
+	    &loc->monetary_locale_changed, name) == _LDP_ERROR) {
+		xlocale_release(new);
+		return (NULL);
+	}
+
+	return (NULL);
+}
+
 struct lc_monetary_T *
-__get_current_monetary_locale(void)
+__get_current_monetary_locale(locale_t loc)
 {
-	return (_monetary_using_locale ? &_monetary_locale :
-	    (struct lc_monetary_T *)&_C_monetary_locale);
+	return (loc->using_monetary_locale
+	    ? &((struct xlocale_monetary*)loc->components[XLC_MONETARY])->locale
+	    : (struct lc_monetary_T *)&_C_monetary_locale);
 }
--- old/usr/src/lib/libc/port/locale/lmonetary.h	2013-06-16 17:44:34.118906394 +0000
+++ new/usr/src/lib/libc/port/locale/lmonetary.h	2013-06-16 17:44:34.130333392 +0000
@@ -2,6 +2,11 @@
  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -27,6 +32,8 @@
 #ifndef _LMONETARY_H_
 #define	_LMONETARY_H_
 
+#include "xlocale_private.h"
+
 struct lc_monetary_T {
 	const char	*int_curr_symbol;
 	const char	*currency_symbol;
@@ -51,7 +58,13 @@
 	const char	*int_n_sign_posn;
 };
 
-struct lc_monetary_T *__get_current_monetary_locale(void);
+struct xlocale_monetary {
+	struct xlocale_component header;
+	char *buffer;
+	struct lc_monetary_T locale;
+};
+
+struct lc_monetary_T *__get_current_monetary_locale(locale_t);
 int	__monetary_load_locale(const char *);
 
 #endif /* !_LMONETARY_H_ */
--- old/usr/src/lib/libc/port/locale/lnumeric.c	2013-06-16 17:44:34.555238386 +0000
+++ new/usr/src/lib/libc/port/locale/lnumeric.c	2013-06-16 17:44:34.570915232 +0000
@@ -36,6 +36,8 @@
 
 #define	LCNUMERIC_SIZE (sizeof (struct lc_numeric_T) / sizeof (char *))
 
+struct xlocale_numeric __xlocale_global_numeric;
+
 static char	numempty[] = { CHAR_MAX, '\0' };
 
 static const struct lc_numeric_T _C_numeric_locale = {
@@ -77,6 +79,18 @@
 	return (ret);
 }
 
+void *
+__numeric_load(const char *name, locale_t l)
+{
+	struct xlocale_numeric *new;
+
+	new = calloc(sizeof(struct xlocale_numeric), 1);
+
+	/* XXX */
+
+	return (new);
+}
+
 struct lc_numeric_T *
 __get_current_numeric_locale(void)
 {
--- old/usr/src/lib/libc/port/locale/lnumeric.h	2013-06-16 17:44:34.989424325 +0000
+++ new/usr/src/lib/libc/port/locale/lnumeric.h	2013-06-16 17:44:35.004615379 +0000
@@ -2,6 +2,11 @@
  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -27,12 +32,20 @@
 #ifndef _LNUMERIC_H_
 #define	_LNUMERIC_H_
 
+#include "xlocale_private.h"
+
 struct lc_numeric_T {
 	const char	*decimal_point;
 	const char	*thousands_sep;
 	const char	*grouping;
 };
 
+struct xlocale_numeric {
+	struct xlocale_component header;
+	char *buffer;
+	struct lc_numeric_T locale;
+};
+
 struct lc_numeric_T *__get_current_numeric_locale(void);
 int	__numeric_load_locale(const char *);
 
--- old/usr/src/lib/libc/port/locale/localeconv.c	2013-06-16 17:44:35.432376689 +0000
+++ new/usr/src/lib/libc/port/locale/localeconv.c	2013-06-16 17:44:35.455263769 +0000
@@ -4,6 +4,11 @@
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -54,18 +59,19 @@
  * Return the current locale conversion.
  */
 struct lconv *
-localeconv(void)
+localeconv_l(locale_t loc)
 {
-	static struct lconv ret;
+	FIX_LOCALE(loc);
+	struct lconv *ret = &loc->lconv;
 
-	if (__mlocale_changed) {
+	if (loc->monetary_locale_changed) {
 		/* LC_MONETARY part */
 		struct lc_monetary_T *mptr;
 
-#define	M_ASSIGN_STR(NAME) (ret.NAME = (char *)mptr->NAME)
-#define	M_ASSIGN_CHAR(NAME) (ret.NAME = mptr->NAME[0])
+#define	M_ASSIGN_STR(NAME) (ret->NAME = (char *)mptr->NAME)
+#define	M_ASSIGN_CHAR(NAME) (ret->NAME = mptr->NAME[0])
 
-		mptr = __get_current_monetary_locale();
+		mptr = __get_current_monetary_locale(loc);
 		M_ASSIGN_STR(int_curr_symbol);
 		M_ASSIGN_STR(currency_symbol);
 		M_ASSIGN_STR(mon_decimal_point);
@@ -90,11 +96,11 @@
 		__mlocale_changed = 0;
 	}
 
-	if (__nlocale_changed) {
+	if (loc->numeric_locale_changed) {
 		/* LC_NUMERIC part */
 		struct lc_numeric_T *nptr;
 
-#define	N_ASSIGN_STR(NAME) (ret.NAME = (char *)nptr->NAME)
+#define	N_ASSIGN_STR(NAME) (ret->NAME = (char *)nptr->NAME)
 
 		nptr = __get_current_numeric_locale();
 		N_ASSIGN_STR(decimal_point);
@@ -103,5 +109,11 @@
 		__nlocale_changed = 0;
 	}
 
-	return (&ret);
+	return (ret);
+}
+
+struct lconv *
+localeconv(void)
+{
+	return (localeconv_l(__get_locale()));
 }
--- old/usr/src/lib/libc/port/locale/mblocal.h	2013-06-16 17:44:35.815731479 +0000
+++ new/usr/src/lib/libc/port/locale/mblocal.h	2013-06-16 17:44:35.831155146 +0000
@@ -29,6 +29,26 @@
 #define	_MBLOCAL_H_
 
 #include "runetype.h"
+#include "xlocale_private.h"
+
+/*
+ * Conversion function pointers for current encoding.
+ */
+struct xlocale_ctype {
+	struct xlocale_component header;
+	_RuneLocale *runes;
+	size_t (*__mbrtowc)(wchar_t *_RESTRICT_KYWD, const char *_RESTRICT_KYWD,
+	    size_t, mbstate_t *_RESTRICT_KYWD);
+	int (*__mbsinit)(const mbstate_t *);
+	size_t (*__mbsnrtowcs)(wchar_t *_RESTRICT_KYWD, const char **_RESTRICT_KYWD,
+	    size_t, size_t, mbstate_t *_RESTRICT_KYWD);
+	size_t (*__wcrtomb)(char *_RESTRICT_KYWD, wchar_t, mbstate_t *_RESTRICT_KYWD);
+	size_t (*__wcsnrtombs)(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
+	    size_t, size_t, mbstate_t *_RESTRICT_KYWD);
+	int __mb_cur_max;
+	int __mb_sb_limit;
+};
+#define	XLOCALE_CTYPE(x)	((struct xlocale_ctype*)(x)->components[XLC_CTYPE])
 
 /*
  * Rune initialization function prototypes.
--- old/usr/src/lib/libc/port/locale/nl_langinfo.c	2013-06-16 17:44:36.272685358 +0000
+++ new/usr/src/lib/libc/port/locale/nl_langinfo.c	2013-06-16 17:44:36.282000402 +0000
@@ -3,6 +3,11 @@
  * Copyright (c) 2001, 2003 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -39,15 +44,15 @@
 
 #define	_REL(BASE) ((int)item-BASE)
 
-#define	MONETARY	(__get_current_monetary_locale())
+#define	MONETARY	(__get_current_monetary_locale(loc))
 #define	TIME		(__get_current_time_locale())
-#define	MESSAGES	(__get_current_messages_locale())
+#define	MESSAGES	(__get_current_messages_locale(loc))	/* XXX */
 #define	NUMERIC		(__get_current_numeric_locale())
 
 #pragma weak _nl_langinfo = nl_langinfo
 
 char *
-nl_langinfo(nl_item item)
+nl_langinfo_l(nl_item item, locale_t loc)
 {
 	char *ret, *s, *cs;
 	static char *csym = NULL;
@@ -194,3 +199,9 @@
 	}
 	return (ret);
 }
+
+char *
+nl_langinfo(nl_item item)
+{
+	return (nl_langinfo_l(item, __get_locale()));
+}
--- old/usr/src/lib/libc/port/locale/none.c	2013-06-16 17:44:36.664493150 +0000
+++ new/usr/src/lib/libc/port/locale/none.c	2013-06-16 17:44:36.681564409 +0000
@@ -7,6 +7,11 @@
  * This code is derived from software contributed to Berkeley by
  * Paul Borman at Krystal Technologies.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -197,3 +202,27 @@
 
 size_t (*__wcsnrtombs)(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
     size_t, size_t, mbstate_t *_RESTRICT_KYWD) = _none_wcsnrtombs;
+
+struct xlocale_ctype __xlocale_global_ctype = {
+	{{0}, "C"},
+	(_RuneLocale*)&_DefaultRuneLocale,
+	_none_mbrtowc,
+	_none_mbsinit,
+	_none_mbsnrtowcs,
+	_none_wcrtomb,
+	_none_wcsnrtombs,
+	1,	/* __mb_cur_max */
+	256	/* __mb_sb_limit */
+};
+
+const struct xlocale_ctype __xlocale_C_ctype = {
+	{{0}, "C"},
+	(_RuneLocale*)&_DefaultRuneLocale,
+	_none_mbrtowc,
+	_none_mbsinit,
+	_none_mbsnrtowcs,
+	_none_wcrtomb,
+	_none_wcsnrtombs,
+	1,	/* __mb_cur_max */
+	256	/* __mb_sb_limit */
+};
--- old/usr/src/lib/libc/port/locale/setlocale.c	2013-06-16 17:44:37.180236891 +0000
+++ new/usr/src/lib/libc/port/locale/setlocale.c	2013-06-16 17:44:37.190848528 +0000
@@ -94,7 +94,6 @@
 
 static char	*currentlocale(void);
 static char	*loadlocale(int);
-static const char *__get_locale_env(int);
 
 char *
 setlocale(int category, const char *locale)
@@ -305,7 +304,7 @@
 	return (NULL);
 }
 
-static const char *
+const char *
 __get_locale_env(int category)
 {
 	const char *env;
@@ -327,3 +326,14 @@
 
 	return (env);
 }
+
+/*
+ * Detect locale storage location and store its value to _PathLocale variable
+ */
+int
+__detect_path_locale(void)
+{
+	/* XXX */
+
+	return (0);
+}
--- old/usr/src/lib/libc/port/locale/setlocale.h	2013-06-16 17:44:37.640681622 +0000
+++ new/usr/src/lib/libc/port/locale/setlocale.h	2013-06-16 17:44:37.656328231 +0000
@@ -33,6 +33,7 @@
 
 extern char *_PathLocale;
 
+const char *__get_locale_env(int);
 int	__detect_path_locale(void);
 int	__wrap_setrunelocale(const char *);
 
--- old/usr/src/lib/libc/port/locale/setrunelocale.c	2013-06-16 17:44:38.073848409 +0000
+++ new/usr/src/lib/libc/port/locale/setrunelocale.c	2013-06-16 17:44:38.088368676 +0000
@@ -6,6 +6,11 @@
  * This code is derived from software contributed to Berkeley by
  * Paul Borman at Krystal Technologies.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -47,6 +52,11 @@
 #include "_ctype.h"
 #include "../i18n/_locale.h"
 
+/*
+ * A cached version of the runes for this thread.  Used by ctype.h
+ */
+__thread const _RuneLocale *_ThreadRuneLocale;
+
 extern _RuneLocale	*_Read_RuneMagi(FILE *);
 extern unsigned char	__ctype_C[];
 
@@ -250,3 +260,25 @@
 	}
 	return (_LDP_LOADED);
 }
+
+void
+__set_thread_rune_locale(locale_t loc)
+{
+
+	if (loc == NULL) {
+		_ThreadRuneLocale = &_DefaultRuneLocale;
+	} else {
+		_ThreadRuneLocale = XLOCALE_CTYPE(loc)->runes;
+	}
+}
+
+void *
+__ctype_load(const char *locale, locale_t unused)
+{
+	struct xlocale_ctype *l;
+
+	l = calloc(sizeof(struct xlocale_ctype), 1);
+	/* XXX */
+
+	return (l);
+}
--- old/usr/src/lib/libc/port/locale/timelocal.c	2013-06-16 17:44:38.503832607 +0000
+++ new/usr/src/lib/libc/port/locale/timelocal.c	2013-06-16 17:44:38.519808691 +0000
@@ -35,6 +35,8 @@
 static int _time_using_locale;
 static char *time_locale_buf;
 
+struct xlocale_time __xlocale_global_time;
+
 #define	LCTIME_SIZE (sizeof (struct lc_time_T) / sizeof (char *))
 
 static const struct lc_time_T	_C_time_locale = {
@@ -98,3 +100,14 @@
 	    &time_locale_buf, "LC_TIME", LCTIME_SIZE, LCTIME_SIZE,
 	    (const char **)&_time_locale));
 }
+
+void *
+__time_load(const char* name, locale_t loc)
+{
+	struct xlocale_time *new;
+
+	new = calloc(sizeof(struct xlocale_time), 1);
+	/* XXX */
+
+	return (new);
+}
--- old/usr/src/lib/libc/port/locale/timelocal.h	2013-06-16 17:44:38.962940787 +0000
+++ new/usr/src/lib/libc/port/locale/timelocal.h	2013-06-16 17:44:38.979128329 +0000
@@ -3,6 +3,10 @@
  * Copyright (c) 1997-2002 FreeBSD Project.
  * All rights reserved.
  *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -28,6 +32,8 @@
 #ifndef _TIMELOCAL_H_
 #define	_TIMELOCAL_H_
 
+#include "xlocale_private.h"
+
 /*
  * Private header file for the strftime and strptime localization
  * stuff.
@@ -46,6 +52,12 @@
 	const char	*ampm_fmt;
 };
 
+struct xlocale_time {
+	struct xlocale_component header;
+	char *buffer;
+	struct lc_time_T locale;
+};
+
 struct lc_time_T *__get_current_time_locale(void);
 int	__time_load_locale(const char *);
 
--- /dev/null	2013-06-16 17:44:39.000000000 +0000
+++ new/usr/src/lib/libc/port/locale/xlocale.c	2013-06-16 17:44:39.409791621 +0000
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "runetype.h"
+#include "xlocale_private.h"
+
+/*
+ * Each locale loader declares a global component.  This is used by setlocale()
+ * and also by xlocale with LC_GLOBAL_LOCALE..
+ */
+extern struct xlocale_component __xlocale_global_collate;
+extern struct xlocale_component __xlocale_global_ctype;
+extern struct xlocale_component __xlocale_global_monetary;
+extern struct xlocale_component __xlocale_global_numeric;
+extern struct xlocale_component __xlocale_global_time;
+extern struct xlocale_component __xlocale_global_messages;
+
+/*
+ * And another version for the statically-allocated C locale.  We only have
+ * components for the parts that are expected to be sensible.
+ */
+extern struct xlocale_component __xlocale_C_collate;
+extern struct xlocale_component __xlocale_C_ctype;
+
+/*
+ * The locale for this thread.
+ */
+__thread locale_t __thread_locale;
+
+/*
+ * Flag indicating that one or more per-thread locales exist.
+ */
+int __has_thread_locale;
+
+struct _xlocale __xlocale_global_locale = {
+	{0},
+	{
+		&__xlocale_global_collate,
+		&__xlocale_global_ctype,
+		&__xlocale_global_monetary,
+		&__xlocale_global_numeric,
+		&__xlocale_global_time,
+		&__xlocale_global_messages
+	},
+	1,
+	0,
+	1,
+	0
+};
+
+struct _xlocale __xlocale_C_locale = {
+	{0},
+	{
+		&__xlocale_C_collate,
+		&__xlocale_C_ctype,
+		0, 0, 0, 0
+	},
+	1,
+	0,
+	1,
+	0
+};
+
+static void*(*constructors[])(const char*, locale_t) =
+{
+	__collate_load,
+	__ctype_load,
+	__monetary_load,
+	__numeric_load,
+	__time_load,
+	__messages_load
+};
+
+static pthread_key_t locale_info_key;
+static int fake_tls;
+static locale_t thread_local_locale;
+
+static void
+init_key(void)
+{
+	pthread_key_create(&locale_info_key, xlocale_release);
+	pthread_setspecific(locale_info_key, (void*)42);
+	if (pthread_getspecific(locale_info_key) == (void*)42) {
+		pthread_setspecific(locale_info_key, 0);
+	} else {
+		fake_tls = 1;
+	}
+	/* At least one per-thread locale has now been set. */
+	__has_thread_locale = 1;
+	__detect_path_locale();
+}
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+
+static locale_t
+get_thread_locale(void)
+{
+
+	// XXX	_once(&once_control, init_key);
+	(void) pthread_once(&once_control, init_key);
+	
+	return (fake_tls ? thread_local_locale :
+	    pthread_getspecific(locale_info_key));
+}
+
+static void
+set_thread_locale(locale_t loc)
+{
+
+	// XXX _once(&once_control, init_key);
+	(void) pthread_once(&once_control, init_key);
+	
+	if (NULL != loc) {
+		xlocale_retain((struct xlocale_refcounted*)loc);
+	}
+	locale_t old = pthread_getspecific(locale_info_key);
+	if ((NULL != old) && (loc != old)) {
+		xlocale_release((struct xlocale_refcounted*)old);
+	}
+	if (fake_tls) {
+		thread_local_locale = loc;
+	} else {
+		pthread_setspecific(locale_info_key, loc);
+	}
+	__thread_locale = loc;
+	__set_thread_rune_locale(loc);
+}
+
+/*
+ * Clean up a locale, once its reference count reaches zero.  This function is
+ * called by xlocale_release(), it should not be called directly.
+ */
+static void
+destruct_locale(void *l)
+{
+	locale_t loc = l;
+
+	for (int type = 0; type < XLC_LAST; type++) {
+		if (loc->components[type]) {
+			xlocale_release(loc->components[type]);
+		}
+	}
+	if (loc->csym) {
+		free(loc->csym);
+	}
+	free(l);
+}
+
+/*
+ * Allocates a new, uninitialised, locale.
+ */
+static locale_t
+alloc_locale(void)
+{
+	locale_t new = calloc(sizeof(struct _xlocale), 1);
+
+	new->header.destructor = destruct_locale;
+	new->monetary_locale_changed = 1;
+	new->numeric_locale_changed = 1;
+	return (new);
+}
+
+static void
+copyflags(locale_t new, locale_t old)
+{
+	new->using_monetary_locale = old->using_monetary_locale;
+	new->using_numeric_locale = old->using_numeric_locale;
+	new->using_time_locale = old->using_time_locale;
+	new->using_messages_locale = old->using_messages_locale;
+}
+
+static int
+dupcomponent(int type, locale_t base, locale_t new) 
+{
+	/*
+	 * Always copy from the global locale, since it has mutable components.
+	 */
+	struct xlocale_component *src = base->components[type];
+
+	if (&__xlocale_global_locale == base) {
+		new->components[type] = constructors[type](src->locale, new);
+		if (new->components[type]) {
+			strncpy(new->components[type]->locale, src->locale,
+			    ENCODING_LEN);
+		}
+	} else if (base->components[type]) {
+		new->components[type] = xlocale_retain(base->components[type]);
+	} else {
+		/*
+		 * If the component was NULL, return success - if base is a
+		 * valid locale then the flag indicating that this isn't
+		 * present should be set.  If it isn't a valid locale, then
+		 * we're stuck anyway.
+		 */
+		return (1);
+	}
+	return (0 != new->components[type]);
+}
+
+/*
+ * Public interfaces.  These are the five public functions described by the
+ * xlocale interface.
+ */
+locale_t
+newlocale(int mask, const char *locale, locale_t base)
+{
+	int type;
+	const char *realLocale = locale;
+	int useenv = 0;
+	int success = 1;
+
+	// XXX _once(&once_control, init_key);
+	(void) pthread_once(&once_control, init_key);
+
+	locale_t new = alloc_locale();
+	if (NULL == new) {
+		return (NULL);
+	}
+
+	FIX_LOCALE(base);
+	copyflags(new, base);
+
+	if (NULL == locale) {
+		realLocale = "C";
+	} else if ('\0' == locale[0]) {
+		useenv = 1;
+	}
+
+	for (type = 0; type < XLC_LAST; type++) {
+		if (mask & 1) {
+			if (useenv) {
+				realLocale = __get_locale_env(type);
+			}
+			new->components[type] =
+			     constructors[type](realLocale, new);
+			if (new->components[type]) {
+				strncpy(new->components[type]->locale,
+				     realLocale, ENCODING_LEN);
+			} else {
+				success = 0;
+				break;
+			}
+		} else {
+			if (!dupcomponent(type, base, new)) {
+				success = 0;
+				break;
+			}
+		}
+		mask >>= 1;
+	}
+	if (0 == success) {
+		xlocale_release(new);
+		new = NULL;
+	}
+
+	return (new);
+}
+
+locale_t
+duplocale(locale_t base)
+{
+	locale_t new = alloc_locale();
+	int type;
+
+	// XXX _once(&once_control, init_key);
+	(void) pthread_once(&once_control, init_key);
+
+	if (NULL == new) {
+		return (NULL);
+	}
+	
+	FIX_LOCALE(base);
+	copyflags(new, base);
+
+	for (type=0 ; type<XLC_LAST ; type++) {
+		dupcomponent(type, base, new);
+	}
+
+	return (new);
+}
+
+/*
+ * Free a locale_t.  This is quite a poorly named function.  It actually
+ * disclaims a reference to a locale_t, rather than freeing it.  
+ */
+int
+freelocale(locale_t loc)
+{
+	/* Fail if we're passed something that isn't a locale. */
+	if ((NULL == loc) || (LC_GLOBAL_LOCALE == loc)) {
+		return (-1);
+	}
+	/*
+	 * If we're passed the global locale, pretend that we freed it but don't
+	 * actually do anything.
+	 */
+	if (&__xlocale_global_locale == loc) {
+		return (0);
+	}
+	xlocale_release(loc);
+	return (0);
+}
+
+/*
+ * Returns the name of the locale for a particular component of a locale_t.
+ */
+const char *
+querylocale(int mask, locale_t loc)
+{
+	int type = ffs(mask) - 1;
+	FIX_LOCALE(loc);
+	if (type >= XLC_LAST)
+		return (NULL);
+	if (loc->components[type])
+		return (loc->components[type]->locale);
+	return ("C");
+}
+
+/*
+ * Installs the specified locale_t as this thread's locale.
+ */
+locale_t
+uselocale(locale_t loc)
+{
+	locale_t old = get_thread_locale();
+	if (NULL != loc) {
+		if (LC_GLOBAL_LOCALE == loc) {
+			loc = NULL;
+		}
+		set_thread_locale(loc);
+	}
+	return (old ? old : LC_GLOBAL_LOCALE);
+}
--- /dev/null	2013-06-16 17:44:39.000000000 +0000
+++ new/usr/src/lib/libc/port/locale/xlocale_private.h	2013-06-16 17:44:39.646817264 +0000
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XLOCALE_PRIVATE__H_
+#define _XLOCALE_PRIVATE__H_
+
+//#include <xlocale.h> /* XXX */
+#include <locale.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include "setlocale.h"
+#include <wchar_impl.h>	/* XXX */
+
+enum {
+	XLC_COLLATE = 0,
+	XLC_CTYPE,
+	XLC_MONETARY,
+	XLC_NUMERIC,
+	XLC_TIME,
+	XLC_MESSAGES,
+	XLC_LAST
+};
+
+
+/*
+ * Header used for objects that are reference counted.  Objects may optionally
+ * have a destructor associated, which is responsible for destroying the
+ * structure.  Global / static versions of the structure should have no
+ * destructor set - they can then have their reference counts manipulated as
+ * normal, but will not do anything with them.
+ *
+ * The header stores a retain count - objects are assumed to have a reference
+ * count of 1 when they are created, but the retain count is 0.  When the
+ * retain count is less than 0, they are freed.
+ */
+struct xlocale_refcounted {
+	/* Number of references to this component. */
+	long retain_count;
+	/* Function used to destroy this component, if one is required */
+	void(*destructor)(void*);
+};
+
+/*
+ * Header for a locale component.  All locale components must begin with this
+ * header.
+ */
+struct xlocale_component {
+	struct xlocale_refcounted header;
+	/* Name of the locale used for this component. */
+	char locale[ENCODING_LEN+1];
+};
+
+/*
+ * xlocale structure, stores per-thread locale information.  
+ */
+struct _xlocale {
+	struct xlocale_refcounted header;
+	/* Components for the locale. */
+	struct xlocale_component *components[XLC_LAST];
+	/*
+	 * Flag indicating if components[XLC_MONETARY] has changed since the
+	 * last call to localeconv_l() with this locale.
+	 */
+	int monetary_locale_changed;
+	/** Flag indicating whether this locale is actually using a locale for
+	 * LC_MONETARY (1), or if it should use the C default instead (0). */
+	int using_monetary_locale;
+	/** Flag indicating if components[XLC_NUMERIC] has changed since the
+	 * last call to localeconv_l() with this locale. */
+	int numeric_locale_changed;
+	/** Flag indicating whether this locale is actually using a locale for
+	 * LC_NUMERIC (1), or if it should use the C default instead (0). */
+	int using_numeric_locale;
+	/** Flag indicating whether this locale is actually using a locale for
+	 * LC_TIME (1), or if it should use the C default instead (0). */
+	int using_time_locale;
+	/** Flag indicating whether this locale is actually using a locale for
+	 * LC_MESSAGES (1), or if it should use the C default instead (0). */
+	int using_messages_locale;
+	/** The structure to be returned from localeconv_l() for this locale. */
+	struct lconv lconv;
+	/** Persistent state used by mblen() calls. */
+	__mbstate_t mblen;
+	/** Persistent state used by mbrlen() calls. */
+	__mbstate_t mbrlen;
+	/** Persistent state used by mbrtoc16() calls. */
+	__mbstate_t mbrtoc16;
+	/** Persistent state used by mbrtoc32() calls. */
+	__mbstate_t mbrtoc32;
+	/** Persistent state used by mbrtowc() calls. */
+	__mbstate_t mbrtowc;
+	/** Persistent state used by mbsnrtowcs() calls. */
+	__mbstate_t mbsnrtowcs;
+	/** Persistent state used by mbsrtowcs() calls. */
+	__mbstate_t mbsrtowcs;
+	/** Persistent state used by mbtowc() calls. */
+	__mbstate_t mbtowc;
+	/** Persistent state used by c16rtomb() calls. */
+	__mbstate_t c16rtomb;
+	/** Persistent state used by c32rtomb() calls. */
+	__mbstate_t c32rtomb;
+	/** Persistent state used by wcrtomb() calls. */
+	__mbstate_t wcrtomb;
+	/** Persistent state used by wcsnrtombs() calls. */
+	__mbstate_t wcsnrtombs;
+	/** Persistent state used by wcsrtombs() calls. */
+	__mbstate_t wcsrtombs;
+	/** Persistent state used by wctomb() calls. */
+	__mbstate_t wctomb;
+	/** Buffer used by nl_langinfo_l() */
+	char *csym;
+};
+
+/*
+ * XXX freebsd-head/include/xlocale/_ctype.h
+ */
+// typedef struct _xlocale *locale_t;
+#define	LC_GLOBAL_LOCALE	((locale_t)-1)
+
+/*
+ * Increments the reference count of a reference-counted structure.
+ */
+__attribute__((unused)) static void*
+xlocale_retain(void *val)
+{
+	struct xlocale_refcounted *obj = val;
+	//atomic_add_long(&(obj->retain_count), 1); /* XXX */
+	return (val);
+}
+
+/**
+ * Decrements the reference count of a reference-counted structure, freeing it
+ * if this is the last reference, calling its destructor if it has one.
+ */
+__attribute__((unused)) static void
+xlocale_release(void *val)
+{
+	struct xlocale_refcounted *obj = val;
+	long count = 0; // atomic_fetchadd_long(&(obj->retain_count), -1) - 1; /* XXX */
+	if (count < 0) {
+		if (0 != obj->destructor) {
+			obj->destructor(obj);
+		}
+	}
+}
+
+/**
+ * Load functions.  Each takes the name of a locale and a pointer to the data
+ * to be initialised as arguments.  Two special values are allowed for the 
+ */
+extern void	*__collate_load(const char*, locale_t);
+extern void	*__ctype_load(const char*, locale_t);
+extern void	*__messages_load(const char*, locale_t);
+extern void	*__monetary_load(const char*, locale_t);
+extern void	*__numeric_load(const char*, locale_t);
+extern void	*__time_load(const char*, locale_t);
+
+extern struct _xlocale __xlocale_global_locale;
+extern struct _xlocale __xlocale_C_locale;
+
+/**
+ * Caches the rune table in TLS for fast access.
+ */
+void __set_thread_rune_locale(locale_t loc);
+/**
+ * Flag indicating whether a per-thread locale has been set.  If no per-thread
+ * locale has ever been set, then we always use the global locale.
+ */
+extern int __has_thread_locale;
+
+#ifndef __NO_TLS
+/*
+ * The per-thread locale.  Avoids the need to use pthread lookup functions when
+ * getting the per-thread locale.
+ */
+extern __thread locale_t __thread_locale;
+
+/**
+ * Returns the current locale for this thread, or the global locale if none is
+ * set.  The caller does not have to free the locale.  The return value from
+ * this call is not guaranteed to remain valid after the locale changes.  As
+ * such, this should only be called within libc functions.
+ */
+static inline locale_t __get_locale(void)
+{
+
+	if (!__has_thread_locale) {
+		return (&__xlocale_global_locale);
+	}
+	return (__thread_locale ? __thread_locale : &__xlocale_global_locale);
+}
+#else
+locale_t __get_locale(void);
+#endif
+
+/**
+ * Two magic values are allowed for locale_t objects.  NULL and -1.  This
+ * function maps those to the real locales that they represent.
+ */
+static inline locale_t get_real_locale(locale_t locale)
+{
+	switch ((intptr_t)locale) {
+		case 0: return (&__xlocale_C_locale);
+		case -1: return (&__xlocale_global_locale);
+		default: return (locale);
+	}
+}
+
+/**
+ * Replace a placeholder locale with the real global or thread-local locale_t.
+ */
+#define FIX_LOCALE(l) (l = get_real_locale(l))
+
+#endif
--- old/usr/src/lib/libc/port/mapfile-vers	2013-06-16 17:44:39.872997761 +0000
+++ new/usr/src/lib/libc/port/mapfile-vers	2013-06-16 17:44:39.887993752 +0000
@@ -90,6 +90,15 @@
 $add amd64
 $endif
 
+SYMBOL_VERSION ILLUMOS_0.5 {	# Illumos additions
+    protected:
+	duplocale;
+	freelocale;
+	newlocale;
+	querylocale;
+	uselocale;
+} ILLUMOS_0.4;
+
 SYMBOL_VERSION ILLUMOS_0.4 {	# Illumos additions
     protected:
         pipe2;
