2010-12-03 05:34:57 +01:00
|
|
|
// Copyright 2010 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2011-03-09 07:31:37 +01:00
|
|
|
#include <errno.h>
|
2010-12-03 05:34:57 +01:00
|
|
|
#include "runtime.h"
|
2011-02-01 21:15:13 +01:00
|
|
|
#include "go-assert.h"
|
2010-12-03 05:34:57 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
runtime_initlock(Lock *l)
|
|
|
|
{
|
2010-12-17 07:42:06 +01:00
|
|
|
l->key = 0;
|
|
|
|
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)
|
|
|
|
{
|
2011-03-09 07:31:37 +01:00
|
|
|
for(;;){
|
|
|
|
if(sem_wait(&l->sem) == 0)
|
|
|
|
return;
|
|
|
|
if(errno != EINTR)
|
|
|
|
runtime_throw("sem_wait failed");
|
|
|
|
}
|
2010-12-03 05:34:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
runtime_lock(Lock *l)
|
|
|
|
{
|
2011-01-22 03:59:24 +01:00
|
|
|
if(m != nil) {
|
|
|
|
if(m->locks < 0)
|
|
|
|
runtime_throw("lock count");
|
|
|
|
m->locks++;
|
|
|
|
}
|
2010-12-17 07:42:06 +01:00
|
|
|
|
|
|
|
if(runtime_xadd(&l->key, 1) > 1) // someone else has it; wait
|
|
|
|
runtime_lock_full(l);
|
2010-12-03 05:34:57 +01:00
|
|
|
}
|
|
|
|
|
2010-12-17 07:42:06 +01:00
|
|
|
static void runtime_unlock_full(Lock *l) __attribute__ ((noinline));
|
|
|
|
|
|
|
|
static void
|
|
|
|
runtime_unlock_full(Lock *l)
|
2010-12-03 05:34:57 +01:00
|
|
|
{
|
2010-12-17 07:42:06 +01:00
|
|
|
if(sem_post(&l->sem) != 0)
|
|
|
|
runtime_throw("sem_post failed");
|
2010-12-03 05:34:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-12-17 07:42:06 +01:00
|
|
|
runtime_unlock(Lock *l)
|
2010-12-03 05:34:57 +01:00
|
|
|
{
|
2011-01-22 03:59:24 +01:00
|
|
|
if(m != nil) {
|
|
|
|
m->locks--;
|
|
|
|
if(m->locks < 0)
|
|
|
|
runtime_throw("lock count");
|
|
|
|
}
|
2010-12-17 07:42:06 +01:00
|
|
|
|
|
|
|
if(runtime_xadd(&l->key, -1) > 0) // someone else is waiting
|
|
|
|
runtime_unlock_full(l);
|
2010-12-03 05:34:57 +01:00
|
|
|
}
|
|
|
|
|
2010-12-17 07:42:06 +01:00
|
|
|
void
|
|
|
|
runtime_destroylock(Lock *l)
|
2010-12-03 05:34:57 +01:00
|
|
|
{
|
2010-12-17 07:42:06 +01:00
|
|
|
sem_destroy(&l->sem);
|
2010-12-03 05:34:57 +01:00
|
|
|
}
|
2011-02-01 21:15:13 +01:00
|
|
|
|
2011-02-01 22:23:07 +01:00
|
|
|
#ifndef HAVE_SYNC_BOOL_COMPARE_AND_SWAP_4
|
2011-02-01 21:15:13 +01:00
|
|
|
|
|
|
|
// For targets which don't have the required sync support. Really
|
|
|
|
// this should be provided by gcc itself. FIXME.
|
|
|
|
|
|
|
|
static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
|
|
|
|
_Bool
|
|
|
|
__sync_bool_compare_and_swap_4(uint32*, uint32, uint32)
|
|
|
|
__attribute__((visibility("hidden")));
|
|
|
|
|
|
|
|
_Bool
|
|
|
|
__sync_bool_compare_and_swap_4(uint32* ptr, uint32 old, uint32 new)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
_Bool ret;
|
|
|
|
|
|
|
|
i = pthread_mutex_lock(&sync_lock);
|
|
|
|
__go_assert(i == 0);
|
|
|
|
|
|
|
|
if(*ptr != old) {
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
*ptr = new;
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = pthread_mutex_unlock(&sync_lock);
|
|
|
|
__go_assert(i == 0);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|