gcc/libgo/runtime/thread.c

119 lines
2.1 KiB
C
Raw Normal View History

// 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.
#include <errno.h>
#include "runtime.h"
#include "go-assert.h"
void
runtime_initlock(Lock *l)
{
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)
{
for(;;){
if(sem_wait(&l->sem) == 0)
return;
if(errno != EINTR)
runtime_throw("sem_wait failed");
}
}
void
runtime_lock(Lock *l)
{
if(m != nil) {
if(m->locks < 0)
runtime_throw("lock count");
m->locks++;
}
if(runtime_xadd(&l->key, 1) > 1) // someone else has it; wait
runtime_lock_full(l);
}
static void runtime_unlock_full(Lock *l) __attribute__ ((noinline));
static void
runtime_unlock_full(Lock *l)
{
if(sem_post(&l->sem) != 0)
runtime_throw("sem_post failed");
}
void
runtime_unlock(Lock *l)
{
if(m != nil) {
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);
}
void
runtime_destroylock(Lock *l)
{
sem_destroy(&l->sem);
}
#ifndef HAVE_SYNC_BOOL_COMPARE_AND_SWAP_4
// 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