From 9154401f58c3fecf24758b1026d10590eabdb0fe Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 28 Sep 2015 12:56:02 -0400 Subject: [PATCH] Update the locale thread-safely. setlocale() affects the entire process, potentially changing the locale while another thread is executing. In POSIX.1-2008, a thread-safe uselocale() function was added that affects only the current thread. Use this function instead when it's available. --- svm.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/svm.cpp b/svm.cpp index f31a5a0e..698dcf85 100644 --- a/svm.cpp +++ b/svm.cpp @@ -7,7 +7,13 @@ #include #include #include + +#if __unix__ +# include // For _POSIX_VERSION +#endif + #include "svm.h" + int libsvm_version = LIBSVM_VERSION; typedef float Qfloat; typedef signed char schar; @@ -2638,16 +2644,55 @@ static const char *kernel_type_table[]= "linear","polynomial","rbf","sigmoid","precomputed",NULL }; -int svm_save_model(const char *model_file_name, const svm_model *model) +#if _POSIX_VERSION >= 200809L + +// If possible, use the thread-safe uselocale() function +typedef locale_t locale_handle; + +static locale_handle set_c_locale() { - FILE *fp = fopen(model_file_name,"w"); - if(fp==NULL) return -1; + locale_handle c_locale = newlocale(LC_ALL_MASK, "C", 0); + locale_handle old_locale = uselocale(c_locale); + return old_locale; +} + +static void restore_locale(locale_handle locale) +{ + locale_handle c_locale = uselocale(locale); + if (c_locale && c_locale != LC_GLOBAL_LOCALE) { + freelocale(c_locale); + } +} + +#else + +// But fall back to setlocale() if uselocale() is not available +typedef char *locale_handle; - char *old_locale = setlocale(LC_ALL, NULL); +static locale_handle set_c_locale() +{ + locale_handle old_locale = setlocale(LC_ALL, NULL); if (old_locale) { old_locale = strdup(old_locale); } setlocale(LC_ALL, "C"); + return old_locale; +} + +static void restore_locale(locale_handle locale) +{ + setlocale(LC_ALL, locale); + free(locale); +} + +#endif + +int svm_save_model(const char *model_file_name, const svm_model *model) +{ + FILE *fp = fopen(model_file_name,"w"); + if(fp==NULL) return -1; + + locale_handle old_locale = set_c_locale(); const svm_parameter& param = model->param; @@ -2728,8 +2773,7 @@ int svm_save_model(const char *model_file_name, const svm_model *model) fprintf(fp, "\n"); } - setlocale(LC_ALL, old_locale); - free(old_locale); + restore_locale(old_locale); if (ferror(fp) != 0 || fclose(fp) != 0) return -1; else return 0; @@ -2878,11 +2922,7 @@ svm_model *svm_load_model(const char *model_file_name) FILE *fp = fopen(model_file_name,"rb"); if(fp==NULL) return NULL; - char *old_locale = setlocale(LC_ALL, NULL); - if (old_locale) { - old_locale = strdup(old_locale); - } - setlocale(LC_ALL, "C"); + locale_handle old_locale = set_c_locale(); // read parameters @@ -2898,8 +2938,7 @@ svm_model *svm_load_model(const char *model_file_name) if (!read_model_header(fp, model)) { fprintf(stderr, "ERROR: fscanf failed to read model\n"); - setlocale(LC_ALL, old_locale); - free(old_locale); + restore_locale(old_locale); free(model->rho); free(model->label); free(model->nSV); @@ -2971,8 +3010,7 @@ svm_model *svm_load_model(const char *model_file_name) } free(line); - setlocale(LC_ALL, old_locale); - free(old_locale); + restore_locale(old_locale); if (ferror(fp) != 0 || fclose(fp) != 0) return NULL;