* 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 <bruno@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().
+
2011-09-25 Bruno Haible <bruno@clisp.org>
msvc-inval: Install handler globally.
# 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,
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. */
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
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
# 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 \
} \
} \