1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

wrap iconv_open / iconv_close with a lock to help in thread/fork issues

* libguile/bytevectors.c (STRING_TO_UTF, scm_string_to_utf8)
  (UTF_TO_STRING):
* libguile/ports.c (open_iconv_descriptors, close_iconv_descriptors):
* libguile/strings.c (scm_from_stringn, scm_to_stringn): Wrap operations
  that acquire and destroy iconv contexts with a mutex.  While iconv is
  threadsafe, internally it uses a lock, and we need to make sure when
  we fork() that no one has that lock -- so we surround it with another
  one.  Gross.
This commit is contained in:
Andy Wingo 2012-02-14 14:30:48 +01:00
parent 6a97b1f93a
commit 8dfb7bbfd9
4 changed files with 45 additions and 1 deletions

View file

@ -1934,10 +1934,12 @@ utf_encoding_name (char *name, size_t utf_width, SCM endianness)
c_strlen = scm_i_string_length (str); \ c_strlen = scm_i_string_length (str); \
if (scm_i_is_narrow_string (str)) \ if (scm_i_is_narrow_string (str)) \
{ \ { \
scm_i_lock_iconv (); \
err = mem_iconveh (scm_i_string_chars (str), c_strlen, \ err = mem_iconveh (scm_i_string_chars (str), c_strlen, \
"ISO-8859-1", c_utf_name, \ "ISO-8859-1", c_utf_name, \
iconveh_question_mark, NULL, \ iconveh_question_mark, NULL, \
&c_utf, &c_utf_len); \ &c_utf, &c_utf_len); \
scm_i_unlock_iconv (); \
if (SCM_UNLIKELY (err)) \ if (SCM_UNLIKELY (err)) \
scm_syserror_msg (FUNC_NAME, "failed to convert string: ~A", \ scm_syserror_msg (FUNC_NAME, "failed to convert string: ~A", \
scm_list_1 (str), err); \ scm_list_1 (str), err); \
@ -1945,10 +1947,12 @@ utf_encoding_name (char *name, size_t utf_width, SCM endianness)
else \ else \
{ \ { \
const scm_t_wchar *wbuf = scm_i_string_wide_chars (str); \ const scm_t_wchar *wbuf = scm_i_string_wide_chars (str); \
scm_i_lock_iconv (); \
c_utf = u32_conv_to_encoding (c_utf_name, \ c_utf = u32_conv_to_encoding (c_utf_name, \
iconveh_question_mark, \ iconveh_question_mark, \
(scm_t_uint32 *) wbuf, \ (scm_t_uint32 *) wbuf, \
c_strlen, NULL, NULL, &c_utf_len); \ c_strlen, NULL, NULL, &c_utf_len); \
scm_i_unlock_iconv (); \
if (SCM_UNLIKELY (c_utf == NULL)) \ if (SCM_UNLIKELY (c_utf == NULL)) \
scm_syserror_msg (FUNC_NAME, "failed to convert string: ~A", \ scm_syserror_msg (FUNC_NAME, "failed to convert string: ~A", \
scm_list_1 (str), errno); \ scm_list_1 (str), errno); \
@ -2050,10 +2054,12 @@ SCM_DEFINE (scm_string_to_utf32, "string->utf32",
c_utf = (char *) SCM_BYTEVECTOR_CONTENTS (utf); \ c_utf = (char *) SCM_BYTEVECTOR_CONTENTS (utf); \
utf_encoding_name (c_utf_name, (_utf_width), endianness); \ utf_encoding_name (c_utf_name, (_utf_width), endianness); \
\ \
scm_i_lock_iconv (); \
err = mem_iconveh (c_utf, c_utf_len, \ err = mem_iconveh (c_utf, c_utf_len, \
c_utf_name, "UTF-8", \ c_utf_name, "UTF-8", \
iconveh_question_mark, NULL, \ iconveh_question_mark, NULL, \
&c_str, &c_strlen); \ &c_str, &c_strlen); \
scm_i_unlock_iconv (); \
if (SCM_UNLIKELY (err)) \ if (SCM_UNLIKELY (err)) \
scm_syserror_msg (FUNC_NAME, "failed to convert to string: ~A", \ scm_syserror_msg (FUNC_NAME, "failed to convert to string: ~A", \
scm_list_1 (utf), err); \ scm_list_1 (utf), err); \

View file

@ -882,7 +882,9 @@ open_iconv_descriptors (const char *encoding, int reading, int writing)
allocation. */ allocation. */
scm_gc_register_allocation (16 * 1024); scm_gc_register_allocation (16 * 1024);
scm_i_lock_iconv ();
input_cd = iconv_open ("UTF-8", encoding); input_cd = iconv_open ("UTF-8", encoding);
scm_i_unlock_iconv ();
if (input_cd == (iconv_t) -1) if (input_cd == (iconv_t) -1)
goto invalid_encoding; goto invalid_encoding;
} }
@ -893,11 +895,15 @@ open_iconv_descriptors (const char *encoding, int reading, int writing)
allocation. */ allocation. */
scm_gc_register_allocation (16 * 1024); scm_gc_register_allocation (16 * 1024);
scm_i_lock_iconv ();
output_cd = iconv_open (encoding, "UTF-8"); output_cd = iconv_open (encoding, "UTF-8");
scm_i_unlock_iconv ();
if (output_cd == (iconv_t) -1) if (output_cd == (iconv_t) -1)
{ {
scm_i_lock_iconv ();
if (input_cd != (iconv_t) -1) if (input_cd != (iconv_t) -1)
iconv_close (input_cd); iconv_close (input_cd);
scm_i_unlock_iconv ();
goto invalid_encoding; goto invalid_encoding;
} }
} }
@ -930,10 +936,12 @@ open_iconv_descriptors (const char *encoding, int reading, int writing)
static void static void
close_iconv_descriptors (scm_t_iconv_descriptors *id) close_iconv_descriptors (scm_t_iconv_descriptors *id)
{ {
scm_i_lock_iconv ();
if (id->input_cd != (iconv_t) -1) if (id->input_cd != (iconv_t) -1)
iconv_close (id->input_cd); iconv_close (id->input_cd);
if (id->output_cd != (iconv_t) -1) if (id->output_cd != (iconv_t) -1)
iconv_close (id->output_cd); iconv_close (id->output_cd);
scm_i_unlock_iconv ();
id->input_cd = (void *) -1; id->input_cd = (void *) -1;
id->output_cd = (void *) -1; id->output_cd = (void *) -1;
} }
@ -1937,10 +1945,12 @@ scm_ungetc_unlocked (scm_t_wchar c, SCM port)
encoding = "ISO-8859-1"; encoding = "ISO-8859-1";
len = sizeof (result_buf); len = sizeof (result_buf);
scm_i_lock_iconv ();
result = u32_conv_to_encoding (encoding, result = u32_conv_to_encoding (encoding,
(enum iconv_ilseq_handler) pt->ilseq_handler, (enum iconv_ilseq_handler) pt->ilseq_handler,
(uint32_t *) &c, 1, NULL, (uint32_t *) &c, 1, NULL,
result_buf, &len); result_buf, &len);
scm_i_unlock_iconv ();
if (SCM_UNLIKELY (result == NULL || len == 0)) if (SCM_UNLIKELY (result == NULL || len == 0))
scm_encoding_error (FUNC_NAME, errno, scm_encoding_error (FUNC_NAME, errno,

View file

@ -225,9 +225,25 @@ narrow_stringbuf (SCM buf)
return new_buf; return new_buf;
} }
scm_i_pthread_mutex_t stringbuf_write_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER; scm_i_pthread_mutex_t stringbuf_write_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
SCM_PTHREAD_ATFORK_LOCK_STATIC_MUTEX (stringbuf_write_mutex); SCM_PTHREAD_ATFORK_LOCK_STATIC_MUTEX (stringbuf_write_mutex);
static scm_i_pthread_mutex_t iconv_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
void
scm_i_lock_iconv (void)
{
scm_i_pthread_mutex_lock (&iconv_mutex);
}
void
scm_i_unlock_iconv (void)
{
scm_i_pthread_mutex_unlock (&iconv_mutex);
}
/* Copy-on-write strings. /* Copy-on-write strings.
*/ */
@ -1531,12 +1547,14 @@ scm_from_stringn (const char *str, size_t len, const char *encoding,
return scm_from_utf8_stringn (str, len); return scm_from_utf8_stringn (str, len);
u32len = 0; u32len = 0;
scm_i_lock_iconv ();
u32 = (scm_t_wchar *) u32_conv_from_encoding (encoding, u32 = (scm_t_wchar *) u32_conv_from_encoding (encoding,
(enum iconv_ilseq_handler) (enum iconv_ilseq_handler)
handler, handler,
str, len, str, len,
NULL, NULL,
NULL, &u32len); NULL, &u32len);
scm_i_unlock_iconv ();
if (SCM_UNLIKELY (u32 == NULL)) if (SCM_UNLIKELY (u32 == NULL))
decoding_error (__func__, errno, str, len); decoding_error (__func__, errno, str, len);
@ -2071,10 +2089,12 @@ scm_to_stringn (SCM str, size_t *lenp, const char *encoding,
enc = "ISO-8859-1"; enc = "ISO-8859-1";
if (scm_i_is_narrow_string (str)) if (scm_i_is_narrow_string (str))
{ {
scm_i_lock_iconv ();
ret = mem_iconveh (scm_i_string_chars (str), ilen, ret = mem_iconveh (scm_i_string_chars (str), ilen,
"ISO-8859-1", enc, "ISO-8859-1", enc,
(enum iconv_ilseq_handler) handler, NULL, (enum iconv_ilseq_handler) handler, NULL,
&buf, &len); &buf, &len);
scm_i_unlock_iconv ();
if (ret != 0) if (ret != 0)
scm_encoding_error (__func__, errno, scm_encoding_error (__func__, errno,
@ -2085,12 +2105,14 @@ scm_to_stringn (SCM str, size_t *lenp, const char *encoding,
} }
else else
{ {
scm_i_lock_iconv ();
buf = u32_conv_to_encoding (enc, buf = u32_conv_to_encoding (enc,
(enum iconv_ilseq_handler) handler, (enum iconv_ilseq_handler) handler,
(scm_t_uint32 *) scm_i_string_wide_chars (str), (scm_t_uint32 *) scm_i_string_wide_chars (str),
ilen, ilen,
NULL, NULL,
NULL, &len); NULL, &len);
scm_i_unlock_iconv ();
if (buf == NULL) if (buf == NULL)
scm_encoding_error (__func__, errno, scm_encoding_error (__func__, errno,
"cannot convert wide string to output locale", "cannot convert wide string to output locale",
@ -2334,6 +2356,9 @@ scm_init_strings ()
{ {
scm_nullstr = scm_i_make_string (0, NULL, 0); scm_nullstr = scm_i_make_string (0, NULL, 0);
scm_i_pthread_atfork (scm_i_lock_iconv, scm_i_unlock_iconv,
scm_i_unlock_iconv);
#include "libguile/strings.x" #include "libguile/strings.x"
} }

View file

@ -3,7 +3,7 @@
#ifndef SCM_STRINGS_H #ifndef SCM_STRINGS_H
#define SCM_STRINGS_H #define SCM_STRINGS_H
/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2004, 2005, 2006, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. /* Copyright (C) 1995,1996,1997,1998,2000,2001, 2004, 2005, 2006, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * modify it under the terms of the GNU Lesser General Public License
@ -220,6 +220,9 @@ SCM_INTERNAL void scm_decoding_error (const char *subr, int err,
/* internal utility functions. */ /* internal utility functions. */
SCM_INTERNAL void scm_i_lock_iconv (void);
SCM_INTERNAL void scm_i_unlock_iconv (void);
SCM_INTERNAL char **scm_i_allocate_string_pointers (SCM list); SCM_INTERNAL char **scm_i_allocate_string_pointers (SCM list);
SCM_INTERNAL void scm_i_get_substring_spec (size_t len, SCM_INTERNAL void scm_i_get_substring_spec (size_t len,
SCM start, size_t *cstart, SCM start, size_t *cstart,