Skip to content

Commit

Permalink
Update the locale thread-safely.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Tavian Barnes committed Jan 21, 2016
1 parent 2fdc614 commit 9154401
Showing 1 changed file with 53 additions and 15 deletions.
68 changes: 53 additions & 15 deletions svm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@
#include <stdarg.h>
#include <limits.h>
#include <locale.h>

#if __unix__
# include <unistd.h> // For _POSIX_VERSION
#endif

#include "svm.h"

int libsvm_version = LIBSVM_VERSION;
typedef float Qfloat;
typedef signed char schar;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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

Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 9154401

Please sign in to comment.