bug-gnulib
[Top][All Lists]
Advanced

[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 &not_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 = &not_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>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]