aboutsummaryrefslogtreecommitdiff
path: root/libgo/runtime
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2016-09-30 13:45:08 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2016-09-30 13:45:08 +0000
commitc0401cf78c555ef38d2d2fba94ebffeaef7c6bc9 (patch)
treed1646c0c4bb59624dfdc04420f835270129cc18e /libgo/runtime
parent9e28a77462f81a9a2ab9064d768bd7c9484047e1 (diff)
downloadgcc-c0401cf78c555ef38d2d2fba94ebffeaef7c6bc9.zip
gcc-c0401cf78c555ef38d2d2fba94ebffeaef7c6bc9.tar.gz
gcc-c0401cf78c555ef38d2d2fba94ebffeaef7c6bc9.tar.bz2
runtime: copy internal locking code from Go 1.7 runtime
Remove the old locking code written in C. Add a shell script mkrsysinfo.sh to generate the runtime_sysinfo.go file, so that we can get Go copies of the system time structures and other types. Tweak the compiler so that when compiling the runtime package the address operator does not cause local variables to escape. When the gc compiler compiles the runtime, an escaping local variable is treated as an error. We should implement that, instead of this change, when escape analysis is turned on. Tweak the compiler so that the generated C header does not include names that start with an underscore followed by a non-upper-case letter, except for the special cases of _defer and _panic. Otherwise we translate C types to Go in runtime_sysinfo.go and then generate those Go types back as C types in runtime.inc, which is useless and painful for the C code. Change entersyscall and friends to take a dummy argument, as the gc versions do, to simplify calls from the shared code. Reviewed-on: https://go-review.googlesource.com/30079 From-SVN: r240657
Diffstat (limited to 'libgo/runtime')
-rw-r--r--libgo/runtime/go-cgo.c14
-rw-r--r--libgo/runtime/lock_futex.c204
-rw-r--r--libgo/runtime/lock_sema.c281
-rw-r--r--libgo/runtime/malloc.goc6
-rw-r--r--libgo/runtime/proc.c57
-rw-r--r--libgo/runtime/runtime.c10
-rw-r--r--libgo/runtime/runtime.h48
-rw-r--r--libgo/runtime/thread-linux.c58
-rw-r--r--libgo/runtime/thread-sema.c125
9 files changed, 74 insertions, 729 deletions
diff --git a/libgo/runtime/go-cgo.c b/libgo/runtime/go-cgo.c
index 598c261..7d0494c 100644
--- a/libgo/runtime/go-cgo.c
+++ b/libgo/runtime/go-cgo.c
@@ -45,7 +45,7 @@ syscall_cgocall ()
m = runtime_m ();
++m->ncgocall;
++m->ncgo;
- runtime_entersyscall ();
+ runtime_entersyscall (0);
}
/* Prepare to return to Go code from C/C++ code. */
@@ -69,7 +69,7 @@ syscall_cgocalldone ()
/* If we are invoked because the C function called _cgo_panic, then
_cgo_panic will already have exited syscall mode. */
if (g->atomicstatus == _Gsyscall)
- runtime_exitsyscall ();
+ runtime_exitsyscall (0);
runtime_unlockOSThread();
}
@@ -89,7 +89,7 @@ syscall_cgocallback ()
mp->dropextram = true;
}
- runtime_exitsyscall ();
+ runtime_exitsyscall (0);
if (runtime_m ()->ncgo == 0)
{
@@ -115,7 +115,7 @@ syscall_cgocallbackdone ()
{
M *mp;
- runtime_entersyscall ();
+ runtime_entersyscall (0);
mp = runtime_m ();
if (mp->dropextram && mp->ncgo == 0)
{
@@ -154,9 +154,9 @@ _cgo_allocate (size_t n)
{
void *ret;
- runtime_exitsyscall ();
+ runtime_exitsyscall (0);
ret = alloc_saved (n);
- runtime_entersyscall ();
+ runtime_entersyscall (0);
return ret;
}
@@ -171,7 +171,7 @@ _cgo_panic (const char *p)
String *ps;
struct __go_empty_interface e;
- runtime_exitsyscall ();
+ runtime_exitsyscall (0);
len = __builtin_strlen (p);
data = alloc_saved (len);
__builtin_memcpy (data, p, len);
diff --git a/libgo/runtime/lock_futex.c b/libgo/runtime/lock_futex.c
deleted file mode 100644
index 33ef073..0000000
--- a/libgo/runtime/lock_futex.c
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright 2011 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.
-
-// +build dragonfly freebsd linux
-
-#include "runtime.h"
-
-// This implementation depends on OS-specific implementations of
-//
-// runtime_futexsleep(uint32 *addr, uint32 val, int64 ns)
-// Atomically,
-// if(*addr == val) sleep
-// Might be woken up spuriously; that's allowed.
-// Don't sleep longer than ns; ns < 0 means forever.
-//
-// runtime_futexwakeup(uint32 *addr, uint32 cnt)
-// If any procs are sleeping on addr, wake up at most cnt.
-
-enum
-{
- MUTEX_UNLOCKED = 0,
- MUTEX_LOCKED = 1,
- MUTEX_SLEEPING = 2,
-
- ACTIVE_SPIN = 4,
- ACTIVE_SPIN_CNT = 30,
- PASSIVE_SPIN = 1,
-};
-
-// Possible lock states are MUTEX_UNLOCKED, MUTEX_LOCKED and MUTEX_SLEEPING.
-// MUTEX_SLEEPING means that there is presumably at least one sleeping thread.
-// Note that there can be spinning threads during all states - they do not
-// affect mutex's state.
-void
-runtime_lock(Lock *l)
-{
- uint32 i, v, wait, spin;
-
- if(runtime_m()->locks++ < 0)
- runtime_throw("runtime_lock: lock count");
-
- // Speculative grab for lock.
- v = runtime_xchg((uint32*)&l->key, MUTEX_LOCKED);
- if(v == MUTEX_UNLOCKED)
- return;
-
- // wait is either MUTEX_LOCKED or MUTEX_SLEEPING
- // depending on whether there is a thread sleeping
- // on this mutex. If we ever change l->key from
- // MUTEX_SLEEPING to some other value, we must be
- // careful to change it back to MUTEX_SLEEPING before
- // returning, to ensure that the sleeping thread gets
- // its wakeup call.
- wait = v;
-
- // On uniprocessor's, no point spinning.
- // On multiprocessors, spin for ACTIVE_SPIN attempts.
- spin = 0;
- if(runtime_ncpu > 1)
- spin = ACTIVE_SPIN;
-
- for(;;) {
- // Try for lock, spinning.
- for(i = 0; i < spin; i++) {
- while(l->key == MUTEX_UNLOCKED)
- if(runtime_cas((uint32*)&l->key, MUTEX_UNLOCKED, wait))
- return;
- runtime_procyield(ACTIVE_SPIN_CNT);
- }
-
- // Try for lock, rescheduling.
- for(i=0; i < PASSIVE_SPIN; i++) {
- while(l->key == MUTEX_UNLOCKED)
- if(runtime_cas((uint32*)&l->key, MUTEX_UNLOCKED, wait))
- return;
- runtime_osyield();
- }
-
- // Sleep.
- v = runtime_xchg((uint32*)&l->key, MUTEX_SLEEPING);
- if(v == MUTEX_UNLOCKED)
- return;
- wait = MUTEX_SLEEPING;
- runtime_futexsleep((uint32*)&l->key, MUTEX_SLEEPING, -1);
- }
-}
-
-void
-runtime_unlock(Lock *l)
-{
- uint32 v;
-
- v = runtime_xchg((uint32*)&l->key, MUTEX_UNLOCKED);
- if(v == MUTEX_UNLOCKED)
- runtime_throw("unlock of unlocked lock");
- if(v == MUTEX_SLEEPING)
- runtime_futexwakeup((uint32*)&l->key, 1);
-
- if(--runtime_m()->locks < 0)
- runtime_throw("runtime_unlock: lock count");
-}
-
-// One-time notifications.
-void
-runtime_noteclear(Note *n)
-{
- n->key = 0;
-}
-
-void
-runtime_notewakeup(Note *n)
-{
- uint32 old;
-
- old = runtime_xchg((uint32*)&n->key, 1);
- if(old != 0) {
- runtime_printf("notewakeup - double wakeup (%d)\n", old);
- runtime_throw("notewakeup - double wakeup");
- }
- runtime_futexwakeup((uint32*)&n->key, 1);
-}
-
-void
-runtime_notesleep(Note *n)
-{
- M *m = runtime_m();
-
- /* For gccgo it's OK to sleep in non-g0, and it happens in
- stoptheworld because we have not implemented preemption.
-
- if(runtime_g() != runtime_m()->g0)
- runtime_throw("notesleep not on g0");
- */
- while(runtime_atomicload((uint32*)&n->key) == 0) {
- m->blocked = true;
- runtime_futexsleep((uint32*)&n->key, 0, -1);
- m->blocked = false;
- }
-}
-
-static bool
-notetsleep(Note *n, int64 ns, int64 deadline, int64 now)
-{
- M *m = runtime_m();
-
- // Conceptually, deadline and now are local variables.
- // They are passed as arguments so that the space for them
- // does not count against our nosplit stack sequence.
-
- if(ns < 0) {
- while(runtime_atomicload((uint32*)&n->key) == 0) {
- m->blocked = true;
- runtime_futexsleep((uint32*)&n->key, 0, -1);
- m->blocked = false;
- }
- return true;
- }
-
- if(runtime_atomicload((uint32*)&n->key) != 0)
- return true;
-
- deadline = runtime_nanotime() + ns;
- for(;;) {
- m->blocked = true;
- runtime_futexsleep((uint32*)&n->key, 0, ns);
- m->blocked = false;
- if(runtime_atomicload((uint32*)&n->key) != 0)
- break;
- now = runtime_nanotime();
- if(now >= deadline)
- break;
- ns = deadline - now;
- }
- return runtime_atomicload((uint32*)&n->key) != 0;
-}
-
-bool
-runtime_notetsleep(Note *n, int64 ns)
-{
- bool res;
-
- if(runtime_g() != runtime_m()->g0 && !runtime_m()->gcing)
- runtime_throw("notetsleep not on g0");
-
- res = notetsleep(n, ns, 0, 0);
- return res;
-}
-
-// same as runtime_notetsleep, but called on user g (not g0)
-// calls only nosplit functions between entersyscallblock/exitsyscall
-bool
-runtime_notetsleepg(Note *n, int64 ns)
-{
- bool res;
-
- if(runtime_g() == runtime_m()->g0)
- runtime_throw("notetsleepg on g0");
-
- runtime_entersyscallblock();
- res = notetsleep(n, ns, 0, 0);
- runtime_exitsyscall();
- return res;
-}
diff --git a/libgo/runtime/lock_sema.c b/libgo/runtime/lock_sema.c
deleted file mode 100644
index 06ac6e7..0000000
--- a/libgo/runtime/lock_sema.c
+++ /dev/null
@@ -1,281 +0,0 @@
-// Copyright 2011 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.
-
-// +build darwin nacl netbsd openbsd plan9 solaris windows
-
-#include "runtime.h"
-
-// This implementation depends on OS-specific implementations of
-//
-// uintptr runtime_semacreate(void)
-// Create a semaphore, which will be assigned to m->waitsema.
-// The zero value is treated as absence of any semaphore,
-// so be sure to return a non-zero value.
-//
-// int32 runtime_semasleep(int64 ns)
-// If ns < 0, acquire m->waitsema and return 0.
-// If ns >= 0, try to acquire m->waitsema for at most ns nanoseconds.
-// Return 0 if the semaphore was acquired, -1 if interrupted or timed out.
-//
-// int32 runtime_semawakeup(M *mp)
-// Wake up mp, which is or will soon be sleeping on mp->waitsema.
-//
-
-enum
-{
- LOCKED = 1,
-
- ACTIVE_SPIN = 4,
- ACTIVE_SPIN_CNT = 30,
- PASSIVE_SPIN = 1,
-};
-
-void
-runtime_lock(Lock *l)
-{
- M *m;
- uintptr v;
- uint32 i, spin;
-
- m = runtime_m();
- if(m->locks++ < 0)
- runtime_throw("runtime_lock: lock count");
-
- // Speculative grab for lock.
- if(runtime_casp((void**)&l->key, nil, (void*)LOCKED))
- return;
-
- if(m->waitsema == 0)
- m->waitsema = runtime_semacreate();
-
- // On uniprocessor's, no point spinning.
- // On multiprocessors, spin for ACTIVE_SPIN attempts.
- spin = 0;
- if(runtime_ncpu > 1)
- spin = ACTIVE_SPIN;
-
- for(i=0;; i++) {
- v = (uintptr)runtime_atomicloadp((void**)&l->key);
- if((v&LOCKED) == 0) {
-unlocked:
- if(runtime_casp((void**)&l->key, (void*)v, (void*)(v|LOCKED)))
- return;
- i = 0;
- }
- if(i<spin)
- runtime_procyield(ACTIVE_SPIN_CNT);
- else if(i<spin+PASSIVE_SPIN)
- runtime_osyield();
- else {
- // Someone else has it.
- // l->waitm points to a linked list of M's waiting
- // for this lock, chained through m->nextwaitm.
- // Queue this M.
- for(;;) {
- m->nextwaitm = v&~LOCKED;
- if(runtime_casp((void**)&l->key, (void*)v, (void*)((uintptr)m|LOCKED)))
- break;
- v = (uintptr)runtime_atomicloadp((void**)&l->key);
- if((v&LOCKED) == 0)
- goto unlocked;
- }
- if(v&LOCKED) {
- // Queued. Wait.
- runtime_semasleep(-1);
- i = 0;
- }
- }
- }
-}
-
-void
-runtime_unlock(Lock *l)
-{
- uintptr v;
- M *mp;
-
- for(;;) {
- v = (uintptr)runtime_atomicloadp((void**)&l->key);
- if(v == LOCKED) {
- if(runtime_casp((void**)&l->key, (void*)LOCKED, nil))
- break;
- } else {
- // Other M's are waiting for the lock.
- // Dequeue an M.
- mp = (void*)(v&~LOCKED);
- if(runtime_cas(&l->key, v, mp->nextwaitm)) {
- // Dequeued an M. Wake it.
- runtime_semawakeup(mp);
- break;
- }
- }
- }
-
- if(--runtime_m()->locks < 0)
- runtime_throw("runtime_unlock: lock count");
-}
-
-// One-time notifications.
-void
-runtime_noteclear(Note *n)
-{
- n->key = 0;
-}
-
-void
-runtime_notewakeup(Note *n)
-{
- M *mp;
-
- do
- mp = runtime_atomicloadp((void**)&n->key);
- while(!runtime_casp((void**)&n->key, mp, (void*)LOCKED));
-
- // Successfully set waitm to LOCKED.
- // What was it before?
- if(mp == nil) {
- // Nothing was waiting. Done.
- } else if(mp == (M*)LOCKED) {
- // Two notewakeups! Not allowed.
- runtime_throw("notewakeup - double wakeup");
- } else {
- // Must be the waiting m. Wake it up.
- runtime_semawakeup(mp);
- }
-}
-
-void
-runtime_notesleep(Note *n)
-{
- M *m;
-
- m = runtime_m();
-
- /* For gccgo it's OK to sleep in non-g0, and it happens in
- stoptheworld because we have not implemented preemption.
-
- if(runtime_g() != m->g0)
- runtime_throw("notesleep not on g0");
- */
-
- if(m->waitsema == 0)
- m->waitsema = runtime_semacreate();
- if(!runtime_casp((void**)&n->key, nil, m)) { // must be LOCKED (got wakeup)
- if(n->key != LOCKED)
- runtime_throw("notesleep - waitm out of sync");
- return;
- }
- // Queued. Sleep.
- m->blocked = true;
- runtime_semasleep(-1);
- m->blocked = false;
-}
-
-static bool
-notetsleep(Note *n, int64 ns, int64 deadline, M *mp)
-{
- M *m;
-
- m = runtime_m();
-
- // Conceptually, deadline and mp are local variables.
- // They are passed as arguments so that the space for them
- // does not count against our nosplit stack sequence.
-
- // Register for wakeup on n->waitm.
- if(!runtime_casp((void**)&n->key, nil, m)) { // must be LOCKED (got wakeup already)
- if(n->key != LOCKED)
- runtime_throw("notetsleep - waitm out of sync");
- return true;
- }
-
- if(ns < 0) {
- // Queued. Sleep.
- m->blocked = true;
- runtime_semasleep(-1);
- m->blocked = false;
- return true;
- }
-
- deadline = runtime_nanotime() + ns;
- for(;;) {
- // Registered. Sleep.
- m->blocked = true;
- if(runtime_semasleep(ns) >= 0) {
- m->blocked = false;
- // Acquired semaphore, semawakeup unregistered us.
- // Done.
- return true;
- }
- m->blocked = false;
-
- // Interrupted or timed out. Still registered. Semaphore not acquired.
- ns = deadline - runtime_nanotime();
- if(ns <= 0)
- break;
- // Deadline hasn't arrived. Keep sleeping.
- }
-
- // Deadline arrived. Still registered. Semaphore not acquired.
- // Want to give up and return, but have to unregister first,
- // so that any notewakeup racing with the return does not
- // try to grant us the semaphore when we don't expect it.
- for(;;) {
- mp = runtime_atomicloadp((void**)&n->key);
- if(mp == m) {
- // No wakeup yet; unregister if possible.
- if(runtime_casp((void**)&n->key, mp, nil))
- return false;
- } else if(mp == (M*)LOCKED) {
- // Wakeup happened so semaphore is available.
- // Grab it to avoid getting out of sync.
- m->blocked = true;
- if(runtime_semasleep(-1) < 0)
- runtime_throw("runtime: unable to acquire - semaphore out of sync");
- m->blocked = false;
- return true;
- } else
- runtime_throw("runtime: unexpected waitm - semaphore out of sync");
- }
-}
-
-bool
-runtime_notetsleep(Note *n, int64 ns)
-{
- M *m;
- bool res;
-
- m = runtime_m();
-
- if(runtime_g() != m->g0 && !m->gcing)
- runtime_throw("notetsleep not on g0");
-
- if(m->waitsema == 0)
- m->waitsema = runtime_semacreate();
-
- res = notetsleep(n, ns, 0, nil);
- return res;
-}
-
-// same as runtime_notetsleep, but called on user g (not g0)
-// calls only nosplit functions between entersyscallblock/exitsyscall
-bool
-runtime_notetsleepg(Note *n, int64 ns)
-{
- M *m;
- bool res;
-
- m = runtime_m();
-
- if(runtime_g() == m->g0)
- runtime_throw("notetsleepg on g0");
-
- if(m->waitsema == 0)
- m->waitsema = runtime_semacreate();
-
- runtime_entersyscallblock();
- res = notetsleep(n, ns, 0, nil);
- runtime_exitsyscall();
- return res;
-}
diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc
index 591d06a..a924b8a 100644
--- a/libgo/runtime/malloc.goc
+++ b/libgo/runtime/malloc.goc
@@ -99,7 +99,7 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
// returns a non-pointer, so memory allocation occurs
// after syscall.Cgocall but before syscall.CgocallDone.
// We treat it as a callback.
- runtime_exitsyscall();
+ runtime_exitsyscall(0);
m = runtime_m();
incallback = true;
flag |= FlagNoInvokeGC;
@@ -171,7 +171,7 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
m->mallocing = 0;
m->locks--;
if(incallback)
- runtime_entersyscall();
+ runtime_entersyscall(0);
return v;
}
}
@@ -256,7 +256,7 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
runtime_gc(0);
if(incallback)
- runtime_entersyscall();
+ runtime_entersyscall(0);
return v;
}
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index 32d0fb2..dac32eb 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -2021,11 +2021,11 @@ goexit0(G *gp)
// make g->sched refer to the caller's stack segment, because
// entersyscall is going to return immediately after.
-void runtime_entersyscall(void) __attribute__ ((no_split_stack));
+void runtime_entersyscall(int32) __attribute__ ((no_split_stack));
static void doentersyscall(void) __attribute__ ((no_split_stack, noinline));
void
-runtime_entersyscall()
+runtime_entersyscall(int32 dummy __attribute__ ((unused)))
{
// Save the registers in the g structure so that any pointers
// held in registers will be seen by the garbage collector.
@@ -2095,7 +2095,7 @@ doentersyscall()
// The same as runtime_entersyscall(), but with a hint that the syscall is blocking.
void
-runtime_entersyscallblock(void)
+runtime_entersyscallblock(int32 dummy __attribute__ ((unused)))
{
P *p;
@@ -2133,7 +2133,7 @@ runtime_entersyscallblock(void)
// This is called only from the go syscall library, not
// from the low-level system calls used by the runtime.
void
-runtime_exitsyscall(void)
+runtime_exitsyscall(int32 dummy __attribute__ ((unused)))
{
G *gp;
@@ -2254,6 +2254,28 @@ exitsyscall0(G *gp)
schedule(); // Never returns.
}
+void syscall_entersyscall(void)
+ __asm__(GOSYM_PREFIX "syscall.Entersyscall");
+
+void syscall_entersyscall(void) __attribute__ ((no_split_stack));
+
+void
+syscall_entersyscall()
+{
+ runtime_entersyscall(0);
+}
+
+void syscall_exitsyscall(void)
+ __asm__(GOSYM_PREFIX "syscall.Exitsyscall");
+
+void syscall_exitsyscall(void) __attribute__ ((no_split_stack));
+
+void
+syscall_exitsyscall()
+{
+ runtime_exitsyscall(0);
+}
+
// Called from syscall package before fork.
void syscall_runtime_BeforeFork(void)
__asm__(GOSYM_PREFIX "syscall.runtime_BeforeFork");
@@ -2323,33 +2345,6 @@ runtime_malg(int32 stacksize, byte** ret_stack, uintptr* ret_stacksize)
return newg;
}
-/* For runtime package testing. */
-
-
-// Create a new g running fn with siz bytes of arguments.
-// Put it on the queue of g's waiting to run.
-// The compiler turns a go statement into a call to this.
-// Cannot split the stack because it assumes that the arguments
-// are available sequentially after &fn; they would not be
-// copied if a stack split occurred. It's OK for this to call
-// functions that split the stack.
-void runtime_testing_entersyscall(int32)
- __asm__ (GOSYM_PREFIX "runtime.entersyscall");
-void
-runtime_testing_entersyscall(int32 dummy __attribute__ ((unused)))
-{
- runtime_entersyscall();
-}
-
-void runtime_testing_exitsyscall(int32)
- __asm__ (GOSYM_PREFIX "runtime.exitsyscall");
-
-void
-runtime_testing_exitsyscall(int32 dummy __attribute__ ((unused)))
-{
- runtime_exitsyscall();
-}
-
G*
__go_go(void (*fn)(void*), void* arg)
{
diff --git a/libgo/runtime/runtime.c b/libgo/runtime/runtime.c
index e5e88ed..8e6f1f5 100644
--- a/libgo/runtime/runtime.c
+++ b/libgo/runtime/runtime.c
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <errno.h>
#include <signal.h>
#include <unistd.h>
@@ -210,3 +211,12 @@ go_closefd(int32 fd)
{
return runtime_close(fd);
}
+
+intgo go_errno(void)
+ __asm__ (GOSYM_PREFIX "runtime.errno");
+
+intgo
+go_errno()
+{
+ return (intgo)errno;
+}
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index d223ec0..d1aad1e 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -108,8 +108,16 @@ struct FuncVal
#include "array.h"
#include "interface.h"
+// Rename Go types generated by mkrsysinfo.sh from C types, to avoid
+// the name conflict.
+#define timeval go_timeval
+#define timespec go_timespec
+
#include "runtime.inc"
+#undef timeval
+#undef timespec
+
/*
* Per-CPU declaration.
*/
@@ -392,9 +400,12 @@ void runtime_parkunlock(Lock*, const char*);
void runtime_tsleep(int64, const char*);
M* runtime_newm(void);
void runtime_goexit(void);
-void runtime_entersyscall(void) __asm__ (GOSYM_PREFIX "syscall.Entersyscall");
-void runtime_entersyscallblock(void);
-void runtime_exitsyscall(void) __asm__ (GOSYM_PREFIX "syscall.Exitsyscall");
+void runtime_entersyscall(int32)
+ __asm__ (GOSYM_PREFIX "runtime.entersyscall");
+void runtime_entersyscallblock(int32)
+ __asm__ (GOSYM_PREFIX "runtime.entersyscallblock");
+void runtime_exitsyscall(int32)
+ __asm__ (GOSYM_PREFIX "runtime.exitsyscall");
G* __go_go(void (*pfn)(void*), void*);
void siginit(void);
bool __go_sigsend(int32 sig);
@@ -476,21 +487,16 @@ void runtime_unlock(Lock*)
* notesleep/notetsleep are generally called on g0,
* notetsleepg is similar to notetsleep but is called on user g.
*/
-void runtime_noteclear(Note*);
-void runtime_notesleep(Note*);
-void runtime_notewakeup(Note*);
-bool runtime_notetsleep(Note*, int64); // false - timeout
-bool runtime_notetsleepg(Note*, int64); // false - timeout
-
-/*
- * low-level synchronization for implementing the above
- */
-uintptr runtime_semacreate(void);
-int32 runtime_semasleep(int64);
-void runtime_semawakeup(M*);
-// or
-void runtime_futexsleep(uint32*, uint32, int64);
-void runtime_futexwakeup(uint32*, uint32);
+void runtime_noteclear(Note*)
+ __asm__ (GOSYM_PREFIX "runtime.noteclear");
+void runtime_notesleep(Note*)
+ __asm__ (GOSYM_PREFIX "runtime.notesleep");
+void runtime_notewakeup(Note*)
+ __asm__ (GOSYM_PREFIX "runtime.notewakeup");
+bool runtime_notetsleep(Note*, int64) // false - timeout
+ __asm__ (GOSYM_PREFIX "runtime.notetsleep");
+bool runtime_notetsleepg(Note*, int64) // false - timeout
+ __asm__ (GOSYM_PREFIX "runtime.notetsleepg");
/*
* Lock-free stack.
@@ -578,8 +584,10 @@ void runtime_newErrorCString(const char*, Eface*)
void runtime_semacquire(uint32 volatile *, bool);
void runtime_semrelease(uint32 volatile *);
int32 runtime_gomaxprocsfunc(int32 n);
-void runtime_procyield(uint32);
-void runtime_osyield(void);
+void runtime_procyield(uint32)
+ __asm__(GOSYM_PREFIX "runtime.procyield");
+void runtime_osyield(void)
+ __asm__(GOSYM_PREFIX "runtime.osyield");
void runtime_lockOSThread(void);
void runtime_unlockOSThread(void);
bool runtime_lockedOSThread(void);
diff --git a/libgo/runtime/thread-linux.c b/libgo/runtime/thread-linux.c
index ae56261..63a2b75 100644
--- a/libgo/runtime/thread-linux.c
+++ b/libgo/runtime/thread-linux.c
@@ -7,69 +7,11 @@
#include "signal_unix.h"
// Linux futex.
-//
-// futexsleep(uint32 *addr, uint32 val)
-// futexwakeup(uint32 *addr)
-//
-// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
-// Futexwakeup wakes up threads sleeping on addr.
-// Futexsleep is allowed to wake up spuriously.
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <unistd.h>
#include <syscall.h>
#include <linux/futex.h>
-typedef struct timespec Timespec;
-
-// Atomically,
-// if(*addr == val) sleep
-// Might be woken up spuriously; that's allowed.
-// Don't sleep longer than ns; ns < 0 means forever.
-void
-runtime_futexsleep(uint32 *addr, uint32 val, int64 ns)
-{
- Timespec ts;
- int32 nsec;
-
- // Some Linux kernels have a bug where futex of
- // FUTEX_WAIT returns an internal error code
- // as an errno. Libpthread ignores the return value
- // here, and so can we: as it says a few lines up,
- // spurious wakeups are allowed.
-
- if(ns < 0) {
- syscall(__NR_futex, addr, FUTEX_WAIT, val, nil, nil, 0);
- return;
- }
- ts.tv_sec = runtime_timediv(ns, 1000000000LL, &nsec);
- ts.tv_nsec = nsec;
- syscall(__NR_futex, addr, FUTEX_WAIT, val, &ts, nil, 0);
-}
-
-// If any procs are sleeping on addr, wake up at most cnt.
-void
-runtime_futexwakeup(uint32 *addr, uint32 cnt)
-{
- int64 ret;
-
- ret = syscall(__NR_futex, addr, FUTEX_WAKE, cnt, nil, nil, 0);
-
- if(ret >= 0)
- return;
-
- // I don't know that futex wakeup can return
- // EAGAIN or EINTR, but if it does, it would be
- // safe to loop and call futex again.
- runtime_printf("futexwakeup addr=%p returned %D\n", addr, ret);
- *(int32*)0x1006 = 0x1006;
-}
-
void
runtime_osinit(void)
{
diff --git a/libgo/runtime/thread-sema.c b/libgo/runtime/thread-sema.c
index 18827b0..b74b1da 100644
--- a/libgo/runtime/thread-sema.c
+++ b/libgo/runtime/thread-sema.c
@@ -10,131 +10,6 @@
#include <time.h>
#include <semaphore.h>
-/* If we don't have sem_timedwait, use pthread_cond_timedwait instead.
- We don't always use condition variables because on some systems
- pthread_mutex_lock and pthread_mutex_unlock must be called by the
- same thread. That is never true of semaphores. */
-
-struct go_sem
-{
- sem_t sem;
-
-#ifndef HAVE_SEM_TIMEDWAIT
- int timedwait;
- pthread_mutex_t mutex;
- pthread_cond_t cond;
-#endif
-};
-
-/* Create a semaphore. */
-
-uintptr
-runtime_semacreate(void)
-{
- struct go_sem *p;
-
- /* Call malloc rather than runtime_malloc. This will allocate space
- on the C heap. We can't call runtime_malloc here because it
- could cause a deadlock. */
- p = malloc (sizeof (struct go_sem));
- if (sem_init (&p->sem, 0, 0) != 0)
- runtime_throw ("sem_init");
-
-#ifndef HAVE_SEM_TIMEDWAIT
- if (pthread_mutex_init (&p->mutex, NULL) != 0)
- runtime_throw ("pthread_mutex_init");
- if (pthread_cond_init (&p->cond, NULL) != 0)
- runtime_throw ("pthread_cond_init");
-#endif
-
- return (uintptr) p;
-}
-
-/* Acquire m->waitsema. */
-
-int32
-runtime_semasleep (int64 ns)
-{
- M *m;
- struct go_sem *sem;
- int r;
-
- m = runtime_m ();
- sem = (struct go_sem *) m->waitsema;
- if (ns >= 0)
- {
- int64 abs;
- struct timespec ts;
- int err;
-
- abs = ns + runtime_nanotime ();
- ts.tv_sec = abs / 1000000000LL;
- ts.tv_nsec = abs % 1000000000LL;
-
- err = 0;
-
-#ifdef HAVE_SEM_TIMEDWAIT
- r = sem_timedwait (&sem->sem, &ts);
- if (r != 0)
- err = errno;
-#else
- if (pthread_mutex_lock (&sem->mutex) != 0)
- runtime_throw ("pthread_mutex_lock");
-
- while ((r = sem_trywait (&sem->sem)) != 0)
- {
- r = pthread_cond_timedwait (&sem->cond, &sem->mutex, &ts);
- if (r != 0)
- {
- err = r;
- break;
- }
- }
-
- if (pthread_mutex_unlock (&sem->mutex) != 0)
- runtime_throw ("pthread_mutex_unlock");
-#endif
-
- if (err != 0)
- {
- if (err == ETIMEDOUT || err == EAGAIN || err == EINTR)
- return -1;
- runtime_throw ("sema_timedwait");
- }
- return 0;
- }
-
- while (sem_wait (&sem->sem) != 0)
- {
- if (errno == EINTR)
- continue;
- runtime_throw ("sem_wait");
- }
-
- return 0;
-}
-
-/* Wake up mp->waitsema. */
-
-void
-runtime_semawakeup (M *mp)
-{
- struct go_sem *sem;
-
- sem = (struct go_sem *) mp->waitsema;
- if (sem_post (&sem->sem) != 0)
- runtime_throw ("sem_post");
-
-#ifndef HAVE_SEM_TIMEDWAIT
- if (pthread_mutex_lock (&sem->mutex) != 0)
- runtime_throw ("pthread_mutex_lock");
- if (pthread_cond_broadcast (&sem->cond) != 0)
- runtime_throw ("pthread_cond_broadcast");
- if (pthread_mutex_unlock (&sem->mutex) != 0)
- runtime_throw ("pthread_mutex_unlock");
-#endif
-}
-
void
runtime_osinit (void)
{