[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
msvc-inval multithread-safe [2/2]
From: |
Bruno Haible |
Subject: |
msvc-inval multithread-safe [2/2] |
Date: |
Sun, 25 Sep 2011 22:01:47 +0200 |
User-agent: |
KMail/1.13.6 (Linux/2.6.37.6-0.5-desktop; KDE/4.6.0; x86_64; ; ) |
> 1) Install the handler once, globally.
> 2) Allocate the jmp_buf per thread.
Here comes part 2.
2011-09-25 Bruno Haible <address@hidden>
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>