]> granicus.if.org Git - gc/commitdiff
Avoid multiple 'getcontext failed' warnings if getcontext is broken
authorIvan Maidanski <ivmai@mail.ru>
Thu, 26 Apr 2018 07:54:52 +0000 (10:54 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Thu, 26 Apr 2018 22:34:15 +0000 (01:34 +0300)
(back-port of commits b5941322bfaff7 from 'master')

Issue #133 (bdwgc).

* mach_dep.c [!HAVE_PUSH_REGS && UNIX_LIKE && !NO_GETCONTEXT]
(GC_with_callee_saves_pushed): Define getcontext_works static variable;
do not call getcontext() if getcontext_works < 0; add comment; set
getcontext_works to 1 or -1 (depending whether getcontext is working)
if getcontext_works is zero.
* misc.c [THREADS && UNIX_LIKE && !NO_GETCONTEXT]
(callee_saves_pushed_dummy_fn): New static function (empty).
* misc.c [THREADS && UNIX_LIKE && !NO_GETCONTEXT] (GC_init): Call
GC_with_callee_saves_pushed(callee_saves_pushed_dummy_fn) if GC_dont_gc
or GC_dont_precollect (otherwise it is called by GC_gcollect_inner);
add comment.

mach_dep.c
misc.c

index 5f64d4dc69a721a6574c767faefa061d942f41cc..14b4c9dbe6bc1cecbdbecb30f2c7d4a710c14b0b 100644 (file)
@@ -235,6 +235,7 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
       /* Older versions of Darwin seem to lack getcontext().    */
       /* ARM and MIPS Linux often doesn't support a real        */
       /* getcontext().                                          */
+      static signed char getcontext_works = 0; /* (-1) - broken, 1 - works */
       ucontext_t ctxt;
 #     ifdef GETCONTEXT_FPU_EXCMASK_BUG
         /* Workaround a bug (clearing the FPU exception mask) in        */
@@ -253,12 +254,17 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
 #       endif
 #     endif
 
-      if (getcontext(&ctxt) < 0) {
-        WARN("getcontext failed:"
-             " using another register retrieval method...\n", 0);
-        /* E.g., to workaround a bug in Docker ubuntu_32bit.    */
-      } else {
-        context = &ctxt;
+      if (getcontext_works >= 0) {
+        if (getcontext(&ctxt) < 0) {
+          WARN("getcontext failed:"
+               " using another register retrieval method...\n", 0);
+          /* getcontext() is broken, do not try again.          */
+          /* E.g., to workaround a bug in Docker ubuntu_32bit.  */
+        } else {
+          context = &ctxt;
+        }
+        if (EXPECT(0 == getcontext_works, FALSE))
+          getcontext_works = context != NULL ? 1 : -1;
       }
 #     ifdef GETCONTEXT_FPU_EXCMASK_BUG
 #       ifdef X86_64
diff --git a/misc.c b/misc.c
index 0ae5d3af2179fec654590aba3ba7d16cf46dcdb2..840e3d89feb3a249af008772c60d6dff02db652b 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -826,6 +826,11 @@ GC_API int GC_CALL GC_is_init_called(void)
   }
 #endif /* MSWIN32 */
 
+#if defined(THREADS) && defined(UNIX_LIKE) && !defined(NO_GETCONTEXT)
+  static void callee_saves_pushed_dummy_fn(ptr_t data GC_ATTR_UNUSED,
+                                           void * context GC_ATTR_UNUSED) {}
+#endif
+
 STATIC word GC_parse_mem_size_arg(const char *str)
 {
   word result = 0; /* bad value */
@@ -1292,6 +1297,11 @@ GC_API void GC_CALL GC_init(void)
           GC_gcollect_inner();
 #       endif
       }
+#   if defined(THREADS) && defined(UNIX_LIKE) && !defined(NO_GETCONTEXT)
+      /* Ensure getcontext_works is set to avoid potential data race.   */
+      if (GC_dont_gc || GC_dont_precollect)
+        GC_with_callee_saves_pushed(callee_saves_pushed_dummy_fn, NULL);
+#   endif
 #   ifdef STUBBORN_ALLOC
         GC_stubborn_init();
 #   endif