aboutsummaryrefslogtreecommitdiff
path: root/libgfortran/io/unit.c
diff options
context:
space:
mode:
authorJanne Blomqvist <jb@gcc.gnu.org>2014-11-10 02:17:16 +0200
committerJanne Blomqvist <jb@gcc.gnu.org>2014-11-10 02:17:16 +0200
commit9cbecd06be8bba398595990b0ecb4156d4a19aad (patch)
tree632705719333408c765e7eddf68dc9b1418b8854 /libgfortran/io/unit.c
parentf8df4b4e2b524b2f35fe93dd935c175c495a7fd0 (diff)
downloadgcc-9cbecd06be8bba398595990b0ecb4156d4a19aad.zip
gcc-9cbecd06be8bba398595990b0ecb4156d4a19aad.tar.gz
gcc-9cbecd06be8bba398595990b0ecb4156d4a19aad.tar.bz2
PR 47007 and 61847 Locale failures in libgfortran.
2014-11-10 Janne Blomqvist <jb@gcc.gnu.org> PR libfortran/47007 PR libfortran/61847 * config.h.in: Regenerated. * configure: Regenerated. * configure.ac (AC_CHECK_HEADERS_ONCE): Check for xlocale.h. (AC_CHECK_FUNCS_ONCE): Check for newlocale, freelocale, uselocale, strerror_l. * io/io.h (locale.h): Include. (xlocale.h): Include if present. (c_locale): New variable. (old_locale): New variable. (old_locale_ctr): New variable. (old_locale_lock): New variable. (st_parameter_dt): Add old_locale member. * io/transfer.c (data_transfer_init): Set locale to "C" if doing formatted transfer. (finalize_transfer): Reset locale to previous. * io/unit.c (c_locale): New variable. (old_locale): New variable. (old_locale_ctr): New variable. (old_locale_lock): New variable. (init_units): Init c_locale, init old_locale_lock. (close_units): Free c_locale. * runtime/error.c (locale.h): Include. (xlocale.h): Include if present. (gf_strerror): Use strerror_l if available. Reset locale to LC_GLOBAL_LOCALE for strerror_r branch. 2014-11-10 Janne Blomqvist <jb@gcc.gnu.org> PR libfortran/47007 PR libfortran/61847 * gfortran.texi: Add note about locale issues to thread-safety section. From-SVN: r217273
Diffstat (limited to 'libgfortran/io/unit.c')
-rw-r--r--libgfortran/io/unit.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/libgfortran/io/unit.c b/libgfortran/io/unit.c
index 2a31e55..277c7a1 100644
--- a/libgfortran/io/unit.c
+++ b/libgfortran/io/unit.c
@@ -90,6 +90,26 @@ static char stdin_name[] = "stdin";
static char stdout_name[] = "stdout";
static char stderr_name[] = "stderr";
+
+#ifdef HAVE_NEWLOCALE
+locale_t c_locale;
+#else
+/* If we don't have POSIX 2008 per-thread locales, we need to use the
+ traditional setlocale(). To prevent multiple concurrent threads
+ doing formatted I/O from messing up the locale, we need to store a
+ global old_locale, and a counter keeping track of how many threads
+ are currently doing formatted I/O. The first thread saves the old
+ locale, and the last one restores it. */
+char *old_locale;
+int old_locale_ctr;
+#ifdef __GTHREAD_MUTEX_INIT
+__gthread_mutex_t old_locale_lock = __GTHREAD_MUTEX_INIT;
+#else
+__gthread_mutex_t old_locale_lock;
+#endif
+#endif
+
+
/* This implementation is based on Stefan Nilsson's article in the
* July 1997 Doctor Dobb's Journal, "Treaps in Java". */
@@ -561,6 +581,14 @@ init_units (void)
gfc_unit *u;
unsigned int i;
+#ifdef HAVE_NEWLOCALE
+ c_locale = newlocale (0, "C", 0);
+#else
+#ifndef __GTHREAD_MUTEX_INIT
+ __GTHREAD_MUTEX_INIT_FUNCTION (&old_locale_lock);
+#endif
+#endif
+
#ifndef __GTHREAD_MUTEX_INIT
__GTHREAD_MUTEX_INIT_FUNCTION (&unit_lock);
#endif
@@ -736,6 +764,10 @@ close_units (void)
while (unit_root != NULL)
close_unit_1 (unit_root, 1);
__gthread_mutex_unlock (&unit_lock);
+
+#ifdef HAVE_FREELOCALE
+ freelocale (c_locale);
+#endif
}