runtime: don't use runtime_lock in __go_get_backtrace_state

If getSiginfo does not know how to determine the PC, it will call
    runtime_callers. That can happen in a thread that was started by
    non-Go code, in which case the TLS variable g will not be set, in
    which case runtime_lock will crash.
    
    Avoid the problem by using atomic operations for the lock. This is OK
    since creating a backtrace state is fast and never blocks.
    
    The test case is TestCgoExternalThreadSIGPROF in the runtime package
    on a system that getSiginfo doesn't handle specially.
    
    Updates golang/go#20931
    
    Reviewed-on: https://go-review.googlesource.com/50650

From-SVN: r250439
This commit is contained in:
Ian Lance Taylor 2017-07-21 18:27:35 +00:00
parent 2401ffc3fe
commit df206c6e77
2 changed files with 12 additions and 4 deletions

View File

@ -1,4 +1,4 @@
a9f1aeced86691de891fbf2a8c97e848faf1962e b712bacd939466e66972337744983e180849c535
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.

View File

@ -74,7 +74,7 @@ static void *back_state;
/* A lock to control creating back_state. */ /* A lock to control creating back_state. */
static Lock back_state_lock; static uint32 back_state_lock;
/* The program arguments. */ /* The program arguments. */
@ -85,7 +85,15 @@ extern Slice runtime_get_args(void);
struct backtrace_state * struct backtrace_state *
__go_get_backtrace_state () __go_get_backtrace_state ()
{ {
runtime_lock (&back_state_lock); uint32 set;
/* We may not have a g here, so we can't use runtime_lock. */
set = 0;
while (!__atomic_compare_exchange_n (&back_state_lock, &set, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
{
runtime_osyield ();
set = 0;
}
if (back_state == NULL) if (back_state == NULL)
{ {
Slice args; Slice args;
@ -113,7 +121,7 @@ __go_get_backtrace_state ()
back_state = backtrace_create_state (filename, 1, error_callback, NULL); back_state = backtrace_create_state (filename, 1, error_callback, NULL);
} }
runtime_unlock (&back_state_lock); __atomic_store_n (&back_state_lock, 0, __ATOMIC_RELEASE);
return back_state; return back_state;
} }