[fortran] Make recursion_check work for multiple threads

Message ID 20181123195815.13679-1-blomqvist.janne@gmail.com
State New
Headers show
Series
  • [fortran] Make recursion_check work for multiple threads
Related show

Commit Message

Janne Blomqvist Nov. 23, 2018, 7:58 p.m.
With multiple threads, using an unprotected static variable to check
whether recursion has occured isn't valid, as one thread might have
modified the variable, thus causing another thread to incorrectly
conclude that recursion has occured.  This patch avoids this problem
by using a thread-specific variable for the recursion check.

Regtested on x86_64-pc-linux-gnu, Ok for trunk?

libgfortran/ChangeLog:

2018-11-23  Janne Blomqvist  <jb@gcc.gnu.org>

	* runtime/error.c (MAGIC): Remove.
	(recursion_key): New variable.
	(recursion_check): Use thread-specific variable for recursion
	check if threads are active.
	(constructor_recursion_check): New function.
	(destructor_recursion_check): New funcion.
---
 libgfortran/runtime/error.c | 43 +++++++++++++++++++++++++++++++------
 1 file changed, 36 insertions(+), 7 deletions(-)

-- 
2.17.1

Comments

Janne Blomqvist Nov. 23, 2018, 8:43 p.m. | #1
On Fri, Nov 23, 2018 at 10:24 PM Jerry DeLisle <jvdelisle@charter.net>
wrote:

> On 11/23/18 11:58 AM, Janne Blomqvist wrote:

> > With multiple threads, using an unprotected static variable to check

> > whether recursion has occured isn't valid, as one thread might have

> > modified the variable, thus causing another thread to incorrectly

> > conclude that recursion has occured.  This patch avoids this problem

> > by using a thread-specific variable for the recursion check.

> >

> > Regtested on x86_64-pc-linux-gnu, Ok for trunk?

> >

>

> OK and thanks Janne.

>


Thanks for the quick review, committed as r266419.


-- 
Janne Blomqvist

Patch

diff --git a/libgfortran/runtime/error.c b/libgfortran/runtime/error.c
index b07a4c0b12a..7c52733c19c 100644
--- a/libgfortran/runtime/error.c
+++ b/libgfortran/runtime/error.c
@@ -332,21 +332,50 @@  show_locus (st_parameter_common *cmp)
 
 /* recursion_check()-- It's possible for additional errors to occur
  * during fatal error processing.  We detect this condition here and
- * exit with code 4 immediately. */
+ * abort immediately. */
 
-#define MAGIC 0x20DE8101
+static __gthread_key_t recursion_key;
 
 static void
 recursion_check (void)
 {
-  static int magic = 0;
+  if (__gthread_active_p ())
+    {
+      bool* p = __gthread_getspecific (recursion_key);
+      if (!p)
+        {
+          p = xcalloc (1, sizeof (bool));
+          __gthread_setspecific (recursion_key, p);
+        }
+      if (*p)
+	sys_abort ();
+      *p = true;
+    }
+  else
+    {
+      static bool recur;
+      if (recur)
+	sys_abort ();
+      recur = true;
+    }
+}
 
-  /* Don't even try to print something at this point */
-  if (magic == MAGIC)
-    sys_abort ();
+#ifdef __GTHREADS
+static void __attribute__((constructor))
+constructor_recursion_check (void)
+{
+  if (__gthread_active_p ())
+    __gthread_key_create (&recursion_key, &free);
+}
 
-  magic = MAGIC;
+static void __attribute__((destructor))
+destructor_recursion_check (void)
+{
+  if (__gthread_active_p ())
+    __gthread_key_delete (recursion_key);
 }
+#endif
+
 
 
 #define STRERR_MAXSZ 256