Commit d6174543 authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

runtime: change Lock from union to struct

Unions can break precise GC.
Update #5193.

R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/8457043
parent 60682c4f
...@@ -41,7 +41,7 @@ runtime·lock(Lock *l) ...@@ -41,7 +41,7 @@ runtime·lock(Lock *l)
runtime·throw("runtime·lock: lock count"); runtime·throw("runtime·lock: lock count");
// Speculative grab for lock. // Speculative grab for lock.
v = runtime·xchg(&l->key, MUTEX_LOCKED); v = runtime·xchg((uint32*)&l->key, MUTEX_LOCKED);
if(v == MUTEX_UNLOCKED) if(v == MUTEX_UNLOCKED)
return; return;
...@@ -64,7 +64,7 @@ runtime·lock(Lock *l) ...@@ -64,7 +64,7 @@ runtime·lock(Lock *l)
// Try for lock, spinning. // Try for lock, spinning.
for(i = 0; i < spin; i++) { for(i = 0; i < spin; i++) {
while(l->key == MUTEX_UNLOCKED) while(l->key == MUTEX_UNLOCKED)
if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait)) if(runtime·cas((uint32*)&l->key, MUTEX_UNLOCKED, wait))
return; return;
runtime·procyield(ACTIVE_SPIN_CNT); runtime·procyield(ACTIVE_SPIN_CNT);
} }
...@@ -72,17 +72,17 @@ runtime·lock(Lock *l) ...@@ -72,17 +72,17 @@ runtime·lock(Lock *l)
// Try for lock, rescheduling. // Try for lock, rescheduling.
for(i=0; i < PASSIVE_SPIN; i++) { for(i=0; i < PASSIVE_SPIN; i++) {
while(l->key == MUTEX_UNLOCKED) while(l->key == MUTEX_UNLOCKED)
if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait)) if(runtime·cas((uint32*)&l->key, MUTEX_UNLOCKED, wait))
return; return;
runtime·osyield(); runtime·osyield();
} }
// Sleep. // Sleep.
v = runtime·xchg(&l->key, MUTEX_SLEEPING); v = runtime·xchg((uint32*)&l->key, MUTEX_SLEEPING);
if(v == MUTEX_UNLOCKED) if(v == MUTEX_UNLOCKED)
return; return;
wait = MUTEX_SLEEPING; wait = MUTEX_SLEEPING;
runtime·futexsleep(&l->key, MUTEX_SLEEPING, -1); runtime·futexsleep((uint32*)&l->key, MUTEX_SLEEPING, -1);
} }
} }
...@@ -94,11 +94,11 @@ runtime·unlock(Lock *l) ...@@ -94,11 +94,11 @@ runtime·unlock(Lock *l)
if(--m->locks < 0) if(--m->locks < 0)
runtime·throw("runtime·unlock: lock count"); runtime·throw("runtime·unlock: lock count");
v = runtime·xchg(&l->key, MUTEX_UNLOCKED); v = runtime·xchg((uint32*)&l->key, MUTEX_UNLOCKED);
if(v == MUTEX_UNLOCKED) if(v == MUTEX_UNLOCKED)
runtime·throw("unlock of unlocked lock"); runtime·throw("unlock of unlocked lock");
if(v == MUTEX_SLEEPING) if(v == MUTEX_SLEEPING)
runtime·futexwakeup(&l->key, 1); runtime·futexwakeup((uint32*)&l->key, 1);
} }
// One-time notifications. // One-time notifications.
......
...@@ -41,7 +41,7 @@ runtime·lock(Lock *l) ...@@ -41,7 +41,7 @@ runtime·lock(Lock *l)
runtime·throw("runtime·lock: lock count"); runtime·throw("runtime·lock: lock count");
// Speculative grab for lock. // Speculative grab for lock.
if(runtime·casp(&l->waitm, nil, (void*)LOCKED)) if(runtime·casp((void**)&l->key, nil, (void*)LOCKED))
return; return;
if(m->waitsema == 0) if(m->waitsema == 0)
...@@ -54,10 +54,10 @@ runtime·lock(Lock *l) ...@@ -54,10 +54,10 @@ runtime·lock(Lock *l)
spin = ACTIVE_SPIN; spin = ACTIVE_SPIN;
for(i=0;; i++) { for(i=0;; i++) {
v = (uintptr)runtime·atomicloadp(&l->waitm); v = (uintptr)runtime·atomicloadp((void**)&l->key);
if((v&LOCKED) == 0) { if((v&LOCKED) == 0) {
unlocked: unlocked:
if(runtime·casp(&l->waitm, (void*)v, (void*)(v|LOCKED))) if(runtime·casp((void**)&l->key, (void*)v, (void*)(v|LOCKED)))
return; return;
i = 0; i = 0;
} }
...@@ -72,9 +72,9 @@ unlocked: ...@@ -72,9 +72,9 @@ unlocked:
// Queue this M. // Queue this M.
for(;;) { for(;;) {
m->nextwaitm = (void*)(v&~LOCKED); m->nextwaitm = (void*)(v&~LOCKED);
if(runtime·casp(&l->waitm, (void*)v, (void*)((uintptr)m|LOCKED))) if(runtime·casp((void**)&l->key, (void*)v, (void*)((uintptr)m|LOCKED)))
break; break;
v = (uintptr)runtime·atomicloadp(&l->waitm); v = (uintptr)runtime·atomicloadp((void**)&l->key);
if((v&LOCKED) == 0) if((v&LOCKED) == 0)
goto unlocked; goto unlocked;
} }
...@@ -97,15 +97,15 @@ runtime·unlock(Lock *l) ...@@ -97,15 +97,15 @@ runtime·unlock(Lock *l)
runtime·throw("runtime·unlock: lock count"); runtime·throw("runtime·unlock: lock count");
for(;;) { for(;;) {
v = (uintptr)runtime·atomicloadp(&l->waitm); v = (uintptr)runtime·atomicloadp((void**)&l->key);
if(v == LOCKED) { if(v == LOCKED) {
if(runtime·casp(&l->waitm, (void*)LOCKED, nil)) if(runtime·casp((void**)&l->key, (void*)LOCKED, nil))
break; break;
} else { } else {
// Other M's are waiting for the lock. // Other M's are waiting for the lock.
// Dequeue an M. // Dequeue an M.
mp = (void*)(v&~LOCKED); mp = (void*)(v&~LOCKED);
if(runtime·casp(&l->waitm, (void*)v, mp->nextwaitm)) { if(runtime·casp((void**)&l->key, (void*)v, mp->nextwaitm)) {
// Dequeued an M. Wake it. // Dequeued an M. Wake it.
runtime·semawakeup(mp); runtime·semawakeup(mp);
break; break;
......
...@@ -50,7 +50,7 @@ typedef uint8 byte; ...@@ -50,7 +50,7 @@ typedef uint8 byte;
typedef struct Func Func; typedef struct Func Func;
typedef struct G G; typedef struct G G;
typedef struct Gobuf Gobuf; typedef struct Gobuf Gobuf;
typedef union Lock Lock; typedef struct Lock Lock;
typedef struct M M; typedef struct M M;
typedef struct P P; typedef struct P P;
typedef struct Mem Mem; typedef struct Mem Mem;
...@@ -156,10 +156,12 @@ enum ...@@ -156,10 +156,12 @@ enum
/* /*
* structures * structures
*/ */
union Lock struct Lock
{ {
uint32 key; // futex-based impl // Futex-based impl treats it as uint32 key,
M* waitm; // linked list of waiting M's (sema-based impl) // while sema-based impl as M* waitm.
// Used to be a union, but unions break precise GC.
uintptr key;
}; };
union Note union Note
{ {
......
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