From b59413253fa0204d6897a05193c58c42ee0c029c Mon Sep 17 00:00:00 2001 From: Ivan Maidanski Date: Thu, 26 Apr 2018 10:54:52 +0300 Subject: [PATCH] Avoid multiple 'getcontext failed' warnings if getcontext is broken 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 | 18 ++++++++++++------ misc.c | 10 ++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/mach_dep.c b/mach_dep.c index b65e6dbe..95848971 100644 --- a/mach_dep.c +++ b/mach_dep.c @@ -237,6 +237,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 */ @@ -255,12 +256,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 2c4b6cee..10d26dfd 100644 --- a/misc.c +++ b/misc.c @@ -829,6 +829,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 */ @@ -1308,6 +1313,11 @@ GC_API void GC_CALL GC_init(void) # if defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED) UNLOCK(); # 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 -- 2.40.0