[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
msvc-inval multithread-safe [1/2]
From: |
Bruno Haible |
Subject: |
msvc-inval multithread-safe [1/2] |
Date: |
Sun, 25 Sep 2011 21:05:03 +0200 |
User-agent: |
KMail/1.13.6 (Linux/2.6.37.6-0.5-desktop; KDE/4.6.0; x86_64; ; ) |
There is one copy of the "invalid parameter handler" in the MSVC runtime
library; there is not one copy per thread. Therefore, setting this handler
or deinstalling it in a gnulib function is not multithread-safe. For MT-safety
the module needs two changes:
1) Install the handler once, globally.
2) Allocate the jmp_buf per thread.
Here comes part 1.
2011-09-25 Bruno Haible <address@hidden>
msvc-inval: Install handler globally.
* lib/msvc-inval.h (STATUS_GNULIB_INVALID_PARAMETER): Define also for
!_MSC_VER.
(gl_msvc_invalid_parameter_handler): Remove declaration.
(gl_msvc_inval_restart_valid, gl_msvc_inval_ensure_handler): New
declarations.
(TRY_MSVC_INVAL, CATCH_MSVC_INVAL, DONE_MSVC_INVAL) [!_MSC_VER]:
Install the handler globally, don't uninstall it.
* lib/msvc-inval.c (gl_msvc_inval_restart_valid): New variable.
(gl_msvc_invalid_parameter_handler): Make static. If the restart is not
currently valid, call RaiseException instead.
(gl_msvc_inval_initialized, gl_msvc_inval_ensure_handler): Define also
for !_MSC_VER.
--- lib/msvc-inval.h.orig Sun Sep 25 20:58:50 2011
+++ lib/msvc-inval.h Sun Sep 25 18:48:03 2011
@@ -47,14 +47,7 @@
/* Get _invalid_parameter_handler type and _set_invalid_parameter_handler
declaration. */
# include <stdlib.h>
-
-# if defined _MSC_VER
-/* A compiler that supports __try/__except, as described in the page
- "try-except statement" on microsoft.com
- <http://msdn.microsoft.com/en-us/library/s58ftw19.aspx>.
- With __try/__except, we can use the multithread-safe exception handling. */
-
-# include <excpt.h>
+# include <excpt.h>
/* Gnulib can define its own status codes, as described in the page
"Raising Software Exceptions" on microsoft.com
@@ -64,7 +57,13 @@
- 0x474E550, a API identifier ("GNU"),
- 0, 1, 2, ..., used to distinguish different status codes from the
same API. */
-# define STATUS_GNULIB_INVALID_PARAMETER (0xE0000000 + 0x474E550 + 0)
+# define STATUS_GNULIB_INVALID_PARAMETER (0xE0000000 + 0x474E550 + 0)
+
+# if defined _MSC_VER
+/* A compiler that supports __try/__except, as described in the page
+ "try-except statement" on microsoft.com
+ <http://msdn.microsoft.com/en-us/library/s58ftw19.aspx>.
+ With __try/__except, we can use the multithread-safe exception handling. */
# ifdef __cplusplus
extern "C" {
@@ -95,8 +94,7 @@
# else
/* Any compiler.
- We can only use setjmp/longjmp.
- Unfortunately, this is *not* multithread-safe. */
+ We can only use setjmp/longjmp. */
# include <setjmp.h>
@@ -109,14 +107,15 @@
TRY_MSVC_INVAL and CATCH_MSVC_INVAL. */
extern jmp_buf gl_msvc_inval_restart;
-/* The invalid parameter handler that unwinds the stack up to the
- gl_msvc_inval_restart. It is enabled only between TRY_MSVC_INVAL
- and CATCH_MSVC_INVAL. */
-extern void cdecl gl_msvc_invalid_parameter_handler (const wchar_t *expression,
- const wchar_t *function,
- const wchar_t *file,
- unsigned int line,
- uintptr_t dummy);
+/* Tells whether the contents of gl_msvc_inval_restart is valid. */
+extern int gl_msvc_inval_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
+ software exception with code STATUS_GNULIB_INVALID_PARAMETER otherwise.
+ Because we assume no other part of the program installs a different
+ invalid parameter handler, this solution is multithread-safe. */
+extern void gl_msvc_inval_ensure_handler (void);
# ifdef __cplusplus
}
@@ -125,23 +124,22 @@
# define TRY_MSVC_INVAL \
do
\
{
\
- _invalid_parameter_handler orig_handler;
\
+ gl_msvc_inval_ensure_handler ();
\
/* First, initialize gl_msvc_inval_restart. */
\
if (setjmp (gl_msvc_inval_restart) == 0)
\
{
\
- /* Then, enable gl_msvc_invalid_parameter_handler. */
\
- orig_handler =
\
- _set_invalid_parameter_handler
(gl_msvc_invalid_parameter_handler);
+ /* Then, mark it as valid. */
\
+ gl_msvc_inval_restart_valid = 1;
# define CATCH_MSVC_INVAL \
/* Execution completed.
\
- Disable gl_msvc_invalid_parameter_handler. */
\
- _set_invalid_parameter_handler (orig_handler);
\
+ Mark gl_msvc_inval_restart as invalid. */
\
+ gl_msvc_inval_restart_valid = 0;
\
}
\
else
\
{
\
/* Execution triggered an invalid parameter notification.
\
- Disable gl_msvc_invalid_parameter_handler. */
\
- _set_invalid_parameter_handler (orig_handler);
+ Mark gl_msvc_inval_restart as invalid. */
\
+ gl_msvc_inval_restart_valid = 0;
# define DONE_MSVC_INVAL \
}
\
}
\
--- lib/msvc-inval.c.orig Sun Sep 25 20:58:50 2011
+++ lib/msvc-inval.c Sun Sep 25 18:48:00 2011
@@ -22,11 +22,11 @@
#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
-# ifdef STATUS_GNULIB_INVALID_PARAMETER
-
/* Get declarations of the Win32 API functions. */
-# define WIN32_LEAN_AND_MEAN
-# include <windows.h>
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+
+# if defined _MSC_VER
static void cdecl
gl_msvc_invalid_parameter_handler (const wchar_t *expression,
@@ -38,32 +38,38 @@
RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
}
-static int gl_msvc_inval_initialized /* = 0 */;
-
-void
-gl_msvc_inval_ensure_handler (void)
-{
- if (gl_msvc_inval_initialized == 0)
- {
- _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
- gl_msvc_inval_initialized = 1;
- }
-}
-
# else
jmp_buf gl_msvc_inval_restart;
+int gl_msvc_inval_restart_valid;
-void cdecl
+static void cdecl
gl_msvc_invalid_parameter_handler (const wchar_t *expression,
const wchar_t *function,
const wchar_t *file,
unsigned int line,
uintptr_t dummy)
{
- longjmp (gl_msvc_inval_restart, 1);
+ if (gl_msvc_inval_restart_valid)
+ longjmp (gl_msvc_inval_restart, 1);
+ else
+ /* An invalid parameter notification from outside the gnulib code.
+ Give the caller a chance to intervene. */
+ RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
}
# endif
+static int gl_msvc_inval_initialized /* = 0 */;
+
+void
+gl_msvc_inval_ensure_handler (void)
+{
+ if (gl_msvc_inval_initialized == 0)
+ {
+ _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
+ gl_msvc_inval_initialized = 1;
+ }
+}
+
#endif
--
In memoriam Safia Ahmed-jan <http://en.wikipedia.org/wiki/Safia_Ahmed-jan>
- msvc-inval multithread-safe [1/2],
Bruno Haible <=