Commit a4ad1c7a by Ian Lance Taylor

Rework locking code to split stack much less.

From-SVN: r167973
parent 785e11cc
...@@ -270,6 +270,9 @@ runtime_allocmcache(void) ...@@ -270,6 +270,9 @@ runtime_allocmcache(void)
void void
runtime_mallocinit(void) runtime_mallocinit(void)
{ {
runtime_initfintab();
runtime_Mprof_Init();
runtime_SysMemInit(); runtime_SysMemInit();
runtime_InitSizes(); runtime_InitSizes();
runtime_MHeap_Init(&runtime_mheap, runtime_SysAlloc); runtime_MHeap_Init(&runtime_mheap, runtime_SysAlloc);
......
...@@ -375,6 +375,7 @@ enum ...@@ -375,6 +375,7 @@ enum
RefFlags = 0xFFFF0000U, RefFlags = 0xFFFF0000U,
}; };
void runtime_Mprof_Init(void);
void runtime_MProf_Malloc(void*, uintptr); void runtime_MProf_Malloc(void*, uintptr);
void runtime_MProf_Free(void*, uintptr); void runtime_MProf_Free(void*, uintptr);
void runtime_MProf_Mark(void (*scan)(byte *, int64)); void runtime_MProf_Mark(void (*scan)(byte *, int64));
......
...@@ -5,7 +5,13 @@ ...@@ -5,7 +5,13 @@
#include "runtime.h" #include "runtime.h"
#include "malloc.h" #include "malloc.h"
static Lock finlock = LOCK_INITIALIZER; static Lock finlock;
void
runtime_initfintab()
{
runtime_initlock(&finlock);
}
// Finalizer hash table. Direct hash, linear scan, at most 3/4 full. // Finalizer hash table. Direct hash, linear scan, at most 3/4 full.
// Table size is power of 3 so that hash can be key % max. // Table size is power of 3 so that hash can be key % max.
......
...@@ -27,7 +27,7 @@ struct BlockList ...@@ -27,7 +27,7 @@ struct BlockList
}; };
static bool finstarted; static bool finstarted;
static Lock finqlock = LOCK_INITIALIZER; static pthread_mutex_t finqlock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t finqcond = PTHREAD_COND_INITIALIZER; static pthread_cond_t finqcond = PTHREAD_COND_INITIALIZER;
static Finalizer *finq; static Finalizer *finq;
static int32 fingwait; static int32 fingwait;
...@@ -284,7 +284,7 @@ sweep(void) ...@@ -284,7 +284,7 @@ sweep(void)
sweepspan(s); sweepspan(s);
} }
static Lock gcsema = LOCK_INITIALIZER; static pthread_mutex_t gcsema = PTHREAD_MUTEX_INITIALIZER;
// Initialized from $GOGC. GOGC=off means no gc. // Initialized from $GOGC. GOGC=off means no gc.
// //
...@@ -327,8 +327,8 @@ runtime_gc(int32 force __attribute__ ((unused))) ...@@ -327,8 +327,8 @@ runtime_gc(int32 force __attribute__ ((unused)))
if(gcpercent < 0) if(gcpercent < 0)
return; return;
runtime_lock(&finqlock); pthread_mutex_lock(&finqlock);
runtime_lock(&gcsema); pthread_mutex_lock(&gcsema);
m->locks++; // disable gc during the mallocs in newproc m->locks++; // disable gc during the mallocs in newproc
t0 = runtime_nanotime(); t0 = runtime_nanotime();
runtime_stoptheworld(); runtime_stoptheworld();
...@@ -345,7 +345,7 @@ runtime_gc(int32 force __attribute__ ((unused))) ...@@ -345,7 +345,7 @@ runtime_gc(int32 force __attribute__ ((unused)))
mstats.pause_ns += t1 - t0; mstats.pause_ns += t1 - t0;
if(mstats.debuggc) if(mstats.debuggc)
runtime_printf("pause %llu\n", (unsigned long long)t1-t0); runtime_printf("pause %llu\n", (unsigned long long)t1-t0);
runtime_unlock(&gcsema); pthread_mutex_unlock(&gcsema);
runtime_starttheworld(); runtime_starttheworld();
// finqlock is still held. // finqlock is still held.
...@@ -362,7 +362,7 @@ runtime_gc(int32 force __attribute__ ((unused))) ...@@ -362,7 +362,7 @@ runtime_gc(int32 force __attribute__ ((unused)))
} }
} }
m->locks--; m->locks--;
runtime_unlock(&finqlock); pthread_mutex_unlock(&finqlock);
} }
static void static void
...@@ -373,16 +373,16 @@ runfinq(void* dummy) ...@@ -373,16 +373,16 @@ runfinq(void* dummy)
USED(dummy); USED(dummy);
for(;;) { for(;;) {
runtime_lock(&finqlock); pthread_mutex_lock(&finqlock);
f = finq; f = finq;
finq = nil; finq = nil;
if(f == nil) { if(f == nil) {
fingwait = 1; fingwait = 1;
pthread_cond_wait(&finqcond, &finqlock.mutex); pthread_cond_wait(&finqcond, &finqlock);
runtime_unlock(&finqlock); pthread_mutex_unlock(&finqlock);
continue; continue;
} }
runtime_unlock(&finqlock); pthread_mutex_unlock(&finqlock);
for(; f; f=next) { for(; f; f=next) {
void *params[1]; void *params[1];
......
...@@ -14,7 +14,7 @@ package runtime ...@@ -14,7 +14,7 @@ package runtime
typedef struct __go_open_array Slice; typedef struct __go_open_array Slice;
// NOTE(rsc): Everything here could use cas if contention became an issue. // NOTE(rsc): Everything here could use cas if contention became an issue.
static Lock proflock = LOCK_INITIALIZER; static Lock proflock;
// Per-call-stack allocation information. // Per-call-stack allocation information.
// Lookup by hashing call stack into a linked-list hash table. // Lookup by hashing call stack into a linked-list hash table.
...@@ -185,6 +185,12 @@ found: ...@@ -185,6 +185,12 @@ found:
return nil; return nil;
} }
void
runtime_Mprof_Init()
{
runtime_initlock(&proflock);
}
// Called by malloc to record a profiled block. // Called by malloc to record a profiled block.
void void
runtime_MProf_Malloc(void *p, uintptr size) runtime_MProf_Malloc(void *p, uintptr size)
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <pthread.h> #include <pthread.h>
#include <semaphore.h>
#ifdef HAVE_SYS_MMAN_H #ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h> #include <sys/mman.h>
...@@ -53,7 +54,8 @@ typedef struct Lock Lock; ...@@ -53,7 +54,8 @@ typedef struct Lock Lock;
struct Lock struct Lock
{ {
pthread_mutex_t mutex; uint32 key;
sem_t sem;
}; };
/* A Note. */ /* A Note. */
...@@ -119,6 +121,7 @@ struct M ...@@ -119,6 +121,7 @@ struct M
void* runtime_mal(uintptr); void* runtime_mal(uintptr);
void runtime_mallocinit(void); void runtime_mallocinit(void);
void runtime_initfintab(void);
void siginit(void); void siginit(void);
bool __go_sigsend(int32 sig); bool __go_sigsend(int32 sig);
int64 runtime_nanotime(void); int64 runtime_nanotime(void);
...@@ -138,12 +141,10 @@ void __go_cachestats(void); ...@@ -138,12 +141,10 @@ void __go_cachestats(void);
* as fast as spin locks (just a few user-level instructions), * as fast as spin locks (just a few user-level instructions),
* but on the contention path they sleep in the kernel. * but on the contention path they sleep in the kernel.
*/ */
#define LOCK_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
void runtime_initlock(Lock*); void runtime_initlock(Lock*);
void runtime_lock(Lock*); void runtime_lock(Lock*);
void runtime_unlock(Lock*); void runtime_unlock(Lock*);
void runtime_destroylock(Lock*); void runtime_destroylock(Lock*);
bool runtime_trylock(Lock*);
void semacquire (uint32 *) asm ("libgo_runtime.runtime.Semacquire"); void semacquire (uint32 *) asm ("libgo_runtime.runtime.Semacquire");
void semrelease (uint32 *) asm ("libgo_runtime.runtime.Semrelease"); void semrelease (uint32 *) asm ("libgo_runtime.runtime.Semrelease");
...@@ -178,7 +179,7 @@ void runtime_addfinalizer(void*, void(*fn)(void*), const struct __go_func_type * ...@@ -178,7 +179,7 @@ void runtime_addfinalizer(void*, void(*fn)(void*), const struct __go_func_type *
void runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64)); void runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64));
#define runtime_mmap mmap #define runtime_mmap mmap
#define runtime_munmap(p, s) munmap((p), (s)) #define runtime_munmap(p, s) munmap((p), (s))
#define cas(pval, old, new) __sync_bool_compare_and_swap (pval, old, new) #define runtime_cas(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
struct __go_func_type; struct __go_func_type;
void reflect_call(const struct __go_func_type *, const void *, _Bool, void **, void reflect_call(const struct __go_func_type *, const void *, _Bool, void **,
......
...@@ -67,7 +67,7 @@ __go_sigsend(int32 s) ...@@ -67,7 +67,7 @@ __go_sigsend(int32 s)
mask = sig.mask; mask = sig.mask;
if(mask & bit) if(mask & bit)
break; // signal already in queue break; // signal already in queue
if(cas(&sig.mask, mask, mask|bit)) { if(runtime_cas(&sig.mask, mask, mask|bit)) {
// Added to queue. // Added to queue.
// Only send a wakeup for the first signal in each round. // Only send a wakeup for the first signal in each round.
if(mask == 0) if(mask == 0)
...@@ -86,7 +86,7 @@ func Sigrecv() (m uint32) { ...@@ -86,7 +86,7 @@ func Sigrecv() (m uint32) {
noteclear(&sig); noteclear(&sig);
for(;;) { for(;;) {
m = sig.mask; m = sig.mask;
if(cas(&sig.mask, m, 0)) if(runtime_cas(&sig.mask, m, 0))
break; break;
} }
} }
......
...@@ -7,32 +7,67 @@ ...@@ -7,32 +7,67 @@
void void
runtime_initlock(Lock *l) runtime_initlock(Lock *l)
{ {
if(pthread_mutex_init(&l->mutex, NULL) != 0) l->key = 0;
runtime_throw("pthread_mutex_init failed"); if(sem_init(&l->sem, 0, 0) != 0)
runtime_throw("sem_init failed");
}
static uint32
runtime_xadd(uint32 volatile *val, int32 delta)
{
uint32 oval, nval;
for(;;){
oval = *val;
nval = oval + delta;
if(runtime_cas(val, oval, nval))
return nval;
}
}
// noinline so that runtime_lock doesn't have to split the stack.
static void runtime_lock_full(Lock *l) __attribute__ ((noinline));
static void
runtime_lock_full(Lock *l)
{
if(sem_wait(&l->sem) != 0)
runtime_throw("sem_wait failed");
} }
void void
runtime_lock(Lock *l) runtime_lock(Lock *l)
{ {
if(pthread_mutex_lock(&l->mutex) != 0) if(m->locks < 0)
runtime_throw("lock failed"); runtime_throw("lock count");
m->locks++;
if(runtime_xadd(&l->key, 1) > 1) // someone else has it; wait
runtime_lock_full(l);
} }
void static void runtime_unlock_full(Lock *l) __attribute__ ((noinline));
runtime_unlock(Lock *l)
static void
runtime_unlock_full(Lock *l)
{ {
if(pthread_mutex_unlock(&l->mutex) != 0) if(sem_post(&l->sem) != 0)
runtime_throw("unlock failed"); runtime_throw("sem_post failed");
} }
void void
runtime_destroylock(Lock *l) runtime_unlock(Lock *l)
{ {
pthread_mutex_destroy(&l->mutex); m->locks--;
if(m->locks < 0)
runtime_throw("lock count");
if(runtime_xadd(&l->key, -1) > 0) // someone else is waiting
runtime_unlock_full(l);
} }
bool void
runtime_trylock(Lock *l) runtime_destroylock(Lock *l)
{ {
return pthread_mutex_trylock(&l->mutex) == 0; sem_destroy(&l->sem);
} }
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