From 37398f7c95b0435a583adc6ee2d35ccdf06411e4 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 25 Sep 2011 22:02:18 +0200 Subject: [PATCH] msvc-inval: Make handler multithread-safe. * lib/msvc-inval.h (struct gl_msvc_inval_per_thread): New type. (gl_msvc_inval_restart, gl_msvc_inval_restart_valid): Remove declarations. (gl_msvc_inval_current): New declaration. (TRY_MSVC_INVAL, CATCH_MSVC_INVAL, DONE_MSVC_INVAL) [!_MSC_VER]: Operate on the structure returned by gl_msvc_inval_current(). * lib/msvc-inval.c (gl_msvc_inval_restart, gl_msvc_inval_restart_valid): Remove varaiables. (tls_index, tls_initialized): New variables. (not_per_thread): New variable. (gl_msvc_inval_current): New function. (gl_msvc_invalid_parameter_handler) [!_MSC_VER]: Use the structure returned by gl_msvc_inval_current(). --- ChangeLog | 17 +++++++++++++++++ lib/msvc-inval.c | 43 +++++++++++++++++++++++++++++++++++++++---- lib/msvc-inval.h | 28 ++++++++++++++++++---------- 3 files changed, 74 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 73ad1b0e8..4b51d086f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,22 @@ 2011-09-25 Bruno Haible + msvc-inval: Make handler multithread-safe. + * lib/msvc-inval.h (struct gl_msvc_inval_per_thread): New type. + (gl_msvc_inval_restart, gl_msvc_inval_restart_valid): Remove + declarations. + (gl_msvc_inval_current): New declaration. + (TRY_MSVC_INVAL, CATCH_MSVC_INVAL, DONE_MSVC_INVAL) [!_MSC_VER]: + Operate on the structure returned by gl_msvc_inval_current(). + * lib/msvc-inval.c (gl_msvc_inval_restart, gl_msvc_inval_restart_valid): + Remove varaiables. + (tls_index, tls_initialized): New variables. + (not_per_thread): New variable. + (gl_msvc_inval_current): New function. + (gl_msvc_invalid_parameter_handler) [!_MSC_VER]: Use the structure + returned by gl_msvc_inval_current(). + +2011-09-25 Bruno Haible + msvc-inval: Install handler globally. * lib/msvc-inval.h (STATUS_GNULIB_INVALID_PARAMETER): Define also for !_MSC_VER. diff --git a/lib/msvc-inval.c b/lib/msvc-inval.c index 4618455fa..ba3c799fd 100644 --- a/lib/msvc-inval.c +++ b/lib/msvc-inval.c @@ -40,8 +40,42 @@ gl_msvc_invalid_parameter_handler (const wchar_t *expression, # else -jmp_buf gl_msvc_inval_restart; -int gl_msvc_inval_restart_valid; +/* An index to thread-local storage. */ +static DWORD tls_index; +static int tls_initialized /* = 0 */; + +/* Used as a fallback only. */ +static struct gl_msvc_inval_per_thread not_per_thread; + +struct gl_msvc_inval_per_thread * +gl_msvc_inval_current (void) +{ + if (!tls_initialized) + { + tls_index = TlsAlloc (); + tls_initialized = 1; + } + if (tls_index == TLS_OUT_OF_INDEXES) + /* TlsAlloc had failed. */ + return ¬_per_thread; + else + { + struct gl_msvc_inval_per_thread *pointer = + (struct gl_msvc_inval_per_thread *) TlsGetValue (tls_index); + if (pointer == NULL) + { + /* First call. Allocate a new 'struct gl_msvc_inval_per_thread'. */ + pointer = + (struct gl_msvc_inval_per_thread *) + malloc (sizeof (struct gl_msvc_inval_per_thread)); + if (pointer == NULL) + /* Could not allocate memory. Use the global storage. */ + pointer = ¬_per_thread; + TlsSetValue (tls_index, pointer); + } + return pointer; + } +} static void cdecl gl_msvc_invalid_parameter_handler (const wchar_t *expression, @@ -50,8 +84,9 @@ gl_msvc_invalid_parameter_handler (const wchar_t *expression, unsigned int line, uintptr_t dummy) { - if (gl_msvc_inval_restart_valid) - longjmp (gl_msvc_inval_restart, 1); + struct gl_msvc_inval_per_thread *current = gl_msvc_inval_current (); + if (current->restart_valid) + longjmp (current->restart, 1); else /* An invalid parameter notification from outside the gnulib code. Give the caller a chance to intervene. */ diff --git a/lib/msvc-inval.h b/lib/msvc-inval.h index 952e72ae9..5f2e4462b 100644 --- a/lib/msvc-inval.h +++ b/lib/msvc-inval.h @@ -102,13 +102,16 @@ extern void gl_msvc_inval_ensure_handler (void); extern "C" { # endif -/* The restart that will resume execution at the code between - CATCH_MSVC_INVAL and DONE_MSVC_INVAL. It is enabled only between - TRY_MSVC_INVAL and CATCH_MSVC_INVAL. */ -extern jmp_buf gl_msvc_inval_restart; +struct gl_msvc_inval_per_thread +{ + /* The restart that will resume execution at the code between + CATCH_MSVC_INVAL and DONE_MSVC_INVAL. It is enabled only between + TRY_MSVC_INVAL and CATCH_MSVC_INVAL. */ + jmp_buf restart; -/* Tells whether the contents of gl_msvc_inval_restart is valid. */ -extern int gl_msvc_inval_restart_valid; + /* Tells whether the contents of restart is valid. */ + int restart_valid; +}; /* Ensure that the invalid parameter handler in installed that passes control to the gl_msvc_inval_restart if it is valid, or raises a @@ -117,6 +120,9 @@ extern int gl_msvc_inval_restart_valid; invalid parameter handler, this solution is multithread-safe. */ extern void gl_msvc_inval_ensure_handler (void); +/* Return a pointer to the per-thread data for the current thread. */ +extern struct gl_msvc_inval_per_thread *gl_msvc_inval_current (void); + # ifdef __cplusplus } # endif @@ -124,22 +130,24 @@ extern void gl_msvc_inval_ensure_handler (void); # define TRY_MSVC_INVAL \ do \ { \ + struct gl_msvc_inval_per_thread *msvc_inval_current; \ gl_msvc_inval_ensure_handler (); \ + msvc_inval_current = gl_msvc_inval_current (); \ /* First, initialize gl_msvc_inval_restart. */ \ - if (setjmp (gl_msvc_inval_restart) == 0) \ + if (setjmp (msvc_inval_current->restart) == 0) \ { \ /* Then, mark it as valid. */ \ - gl_msvc_inval_restart_valid = 1; + msvc_inval_current->restart_valid = 1; # define CATCH_MSVC_INVAL \ /* Execution completed. \ Mark gl_msvc_inval_restart as invalid. */ \ - gl_msvc_inval_restart_valid = 0; \ + msvc_inval_current->restart_valid = 0; \ } \ else \ { \ /* Execution triggered an invalid parameter notification. \ Mark gl_msvc_inval_restart as invalid. */ \ - gl_msvc_inval_restart_valid = 0; + msvc_inval_current->restart_valid = 0; # define DONE_MSVC_INVAL \ } \ } \ -- 2.11.0