From patchwork Thu Aug 26 22:10:38 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [gccgo] Avoid GC deadlock Date: Thu, 26 Aug 2010 12:10:38 -0000 From: Ian Taylor X-Patchwork-Id: 62809 Message-Id: To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com I discovered a possible deadlock in the garbage collector due to memory profiling. When a thread is gathering data for memory profiling, it postpones GC until that is complete. The same happens during memory allocation. However, memory profiling can actually lead to memory allocation. Because the code used the same variable to postpone GC, that can cause the GC to start when the memory allocation is complete but memory profiling is still active. That can in turn cause a deadlock when the GC releases memory profiling data. This patch avoids the deadlock by using a different variable to postpone GC while doing memory profiling. Committed to gccgo branch. Ian diff -r b20eed5a1425 libgo/runtime/go-go.c --- a/libgo/runtime/go-go.c Wed Aug 25 16:59:52 2010 -0700 +++ b/libgo/runtime/go-go.c Thu Aug 26 15:06:20 2010 -0700 @@ -323,7 +323,7 @@ /* Similarly, we can't interrupt the thread while it is building profiling information. Otherwise we can get into a deadlock when sweepspan calls MProf_Free. */ - __sync_bool_compare_and_swap (&pm->gcing, 0, 1); + __sync_bool_compare_and_swap (&pm->gcing_for_prof, 0, 1); return; } diff -r b20eed5a1425 libgo/runtime/mprof.goc --- a/libgo/runtime/mprof.goc Wed Aug 25 16:59:52 2010 -0700 +++ b/libgo/runtime/mprof.goc Thu Aug 26 15:06:20 2010 -0700 @@ -208,7 +208,7 @@ unlock(&proflock); __sync_bool_compare_and_swap(&m->nomemprof, 1, 0); - if(__sync_bool_compare_and_swap(&m->gcing, 1, 0)) + if(__sync_bool_compare_and_swap(&m->gcing_for_prof, 1, 0)) __go_run_goroutine_gc(100); } @@ -230,7 +230,7 @@ unlock(&proflock); __sync_bool_compare_and_swap(&m->nomemprof, 1, 0); - if(__sync_bool_compare_and_swap(&m->gcing, 1, 0)) + if(__sync_bool_compare_and_swap(&m->gcing_for_prof, 1, 0)) __go_run_goroutine_gc(101); } @@ -285,7 +285,7 @@ __sync_bool_compare_and_swap(&m->nomemprof, 1, 0); - if(__sync_bool_compare_and_swap(&m->gcing, 1, 0)) + if(__sync_bool_compare_and_swap(&m->gcing_for_prof, 1, 0)) __go_run_goroutine_gc(102); } diff -r b20eed5a1425 libgo/runtime/runtime.h --- a/libgo/runtime/runtime.h Wed Aug 25 16:59:52 2010 -0700 +++ b/libgo/runtime/runtime.h Thu Aug 26 15:06:20 2010 -0700 @@ -94,6 +94,7 @@ int32 gcing; int32 locks; int32 nomemprof; + int32 gcing_for_prof; MCache *mcache; /* For the list of all threads. */