> 1) Install the handler once, globally. > 2) Allocate the jmp_buf per thread.
Here comes part 2. 2011-09-25 Bruno Haible <br...@clisp.org> 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(). --- lib/msvc-inval.h.orig Sun Sep 25 21:55:14 2011 +++ lib/msvc-inval.h Sun Sep 25 21:27:53 2011 @@ -102,13 +102,16 @@ 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 @@ 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 @@ # 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 \ } \ } \ --- lib/msvc-inval.c.orig Sun Sep 25 21:55:14 2011 +++ lib/msvc-inval.c Sun Sep 25 21:27:53 2011 @@ -40,8 +40,42 @@ # 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 @@ 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. */ -- In memoriam Safia Ahmed-jan <http://en.wikipedia.org/wiki/Safia_Ahmed-jan>