Commit cf606aeb by Ian Lance Taylor

Avoid deadlock when finalizer lock is held during gc.

From-SVN: r169112
parent 723553bd
...@@ -315,6 +315,15 @@ gc_stop_handler (int sig __attribute__ ((unused))) ...@@ -315,6 +315,15 @@ gc_stop_handler (int sig __attribute__ ((unused)))
return; return;
} }
if (__sync_bool_compare_and_swap (&pm->holds_finlock, 1, 1))
{
/* Similarly, we can't interrupt the thread while it holds the
finalizer lock. Otherwise we can get into a deadlock when
mark calls runtime_walkfintab. */
__sync_bool_compare_and_swap (&pm->gcing_for_finlock, 0, 1);
return;
}
stop_for_gc (); stop_for_gc ();
} }
......
...@@ -106,9 +106,13 @@ runtime_addfinalizer(void *p, void (*f)(void*), const struct __go_func_type *ft) ...@@ -106,9 +106,13 @@ runtime_addfinalizer(void *p, void (*f)(void*), const struct __go_func_type *ft)
e->ft = ft; e->ft = ft;
} }
if(!__sync_bool_compare_and_swap(&m->holds_finlock, 0, 1))
runtime_throw("finalizer deadlock");
runtime_lock(&finlock); runtime_lock(&finlock);
if(!runtime_mlookup(p, &base, nil, nil, &ref) || p != base) { if(!runtime_mlookup(p, &base, nil, nil, &ref) || p != base) {
runtime_unlock(&finlock); runtime_unlock(&finlock);
__sync_bool_compare_and_swap(&m->holds_finlock, 1, 0);
runtime_throw("addfinalizer on invalid pointer"); runtime_throw("addfinalizer on invalid pointer");
} }
if(f == nil) { if(f == nil) {
...@@ -116,12 +120,12 @@ runtime_addfinalizer(void *p, void (*f)(void*), const struct __go_func_type *ft) ...@@ -116,12 +120,12 @@ runtime_addfinalizer(void *p, void (*f)(void*), const struct __go_func_type *ft)
lookfintab(&fintab, p, 1); lookfintab(&fintab, p, 1);
*ref &= ~RefHasFinalizer; *ref &= ~RefHasFinalizer;
} }
runtime_unlock(&finlock); goto unlock;
return;
} }
if(*ref & RefHasFinalizer) { if(*ref & RefHasFinalizer) {
runtime_unlock(&finlock); runtime_unlock(&finlock);
__sync_bool_compare_and_swap(&m->holds_finlock, 1, 0);
runtime_throw("double finalizer"); runtime_throw("double finalizer");
} }
*ref |= RefHasFinalizer; *ref |= RefHasFinalizer;
...@@ -156,7 +160,14 @@ runtime_addfinalizer(void *p, void (*f)(void*), const struct __go_func_type *ft) ...@@ -156,7 +160,14 @@ runtime_addfinalizer(void *p, void (*f)(void*), const struct __go_func_type *ft)
} }
addfintab(&fintab, p, e); addfintab(&fintab, p, e);
unlock:
runtime_unlock(&finlock); runtime_unlock(&finlock);
__sync_bool_compare_and_swap(&m->holds_finlock, 1, 0);
if(__sync_bool_compare_and_swap(&m->gcing_for_finlock, 1, 0)) {
__go_run_goroutine_gc(200);
}
} }
// get finalizer; if del, delete finalizer. // get finalizer; if del, delete finalizer.
...@@ -166,9 +177,18 @@ runtime_getfinalizer(void *p, bool del) ...@@ -166,9 +177,18 @@ runtime_getfinalizer(void *p, bool del)
{ {
Finalizer *f; Finalizer *f;
if(!__sync_bool_compare_and_swap(&m->holds_finlock, 0, 1))
runtime_throw("finalizer deadlock");
runtime_lock(&finlock); runtime_lock(&finlock);
f = lookfintab(&fintab, p, del); f = lookfintab(&fintab, p, del);
runtime_unlock(&finlock); runtime_unlock(&finlock);
__sync_bool_compare_and_swap(&m->holds_finlock, 1, 0);
if(__sync_bool_compare_and_swap(&m->gcing_for_finlock, 1, 0)) {
__go_run_goroutine_gc(201);
}
return f; return f;
} }
...@@ -178,6 +198,9 @@ runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64)) ...@@ -178,6 +198,9 @@ runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64))
void **key; void **key;
void **ekey; void **ekey;
if(!__sync_bool_compare_and_swap(&m->holds_finlock, 0, 1))
runtime_throw("finalizer deadlock");
scan((byte*)&fintab, sizeof fintab); scan((byte*)&fintab, sizeof fintab);
runtime_lock(&finlock); runtime_lock(&finlock);
key = fintab.key; key = fintab.key;
...@@ -186,4 +209,9 @@ runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64)) ...@@ -186,4 +209,9 @@ runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64))
if(*key != nil && *key != ((void*)-1)) if(*key != nil && *key != ((void*)-1))
fn(*key); fn(*key);
runtime_unlock(&finlock); runtime_unlock(&finlock);
__sync_bool_compare_and_swap(&m->holds_finlock, 1, 0);
if(__sync_bool_compare_and_swap(&m->gcing_for_finlock, 1, 0)) {
runtime_throw("walkfintab not called from gc");
}
} }
...@@ -97,6 +97,8 @@ struct M ...@@ -97,6 +97,8 @@ struct M
int32 locks; int32 locks;
int32 nomemprof; int32 nomemprof;
int32 gcing_for_prof; int32 gcing_for_prof;
int32 holds_finlock;
int32 gcing_for_finlock;
MCache *mcache; MCache *mcache;
/* For the list of all threads. */ /* For the list of all threads. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment