summaryrefslogtreecommitdiff
path: root/libgo/runtime/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/runtime/thread.c')
-rw-r--r--libgo/runtime/thread.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/libgo/runtime/thread.c b/libgo/runtime/thread.c
new file mode 100644
index 000000000..bac3f7dfd
--- /dev/null
+++ b/libgo/runtime/thread.c
@@ -0,0 +1,118 @@
+// 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