diff mbox

libgo patch committed: Copy locking code from Go 1.7 master library

Message ID CAOyqgcX3xLiZ1NyBNkA4K8K-LeiZ3U_n98-OOe+XMW1nGkPDKQ@mail.gmail.com
State New
Headers show

Commit Message

Ian Lance Taylor Sept. 30, 2016, 1:45 p.m. UTC
This patch to libgo copies the locking code from the Go 1.7 master
library, replacing C code for locking with Go code.  The result is
more efficient on most systems, though it is essentially the same on
GNU/Linux.

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.

As part of this change, 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.  This is for
correctness: there are places in the runtime where we must not
allocate memory unintentionally.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu and
i386-sun-solaris.  Committed to mainline.

Ian
diff mbox

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 240609)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@ 
-e51657a576367c7a498c94baf985b79066fc082a
+f3fb9bf2d5a009a707962a416fcd1a8435756218
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 240453)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -3787,6 +3787,13 @@  Unary_expression::do_flatten(Gogo* gogo,
       if ((n->encoding() & ESCAPE_MASK) == int(Node::ESCAPE_NONE))
 	this->escapes_ = false;
 
+      // When compiling the runtime, the address operator does not
+      // cause local variables to escapes.  When escape analysis
+      // becomes the default, this should be changed to make it an
+      // error if we have an address operator that escapes.
+      if (gogo->compiling_runtime() && gogo->package_name() == "runtime")
+	this->escapes_ = false;
+
       Named_object* var = NULL;
       if (this->expr_->var_expression() != NULL)
 	var = this->expr_->var_expression()->named_object();
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc	(revision 240559)
+++ gcc/go/gofrontend/gogo.cc	(working copy)
@@ -4480,6 +4480,19 @@  Gogo::write_c_header()
        ++p)
     {
       Named_object* no = *p;
+
+      // Skip names that start with underscore followed by something
+      // other than an uppercase letter, as when compiling the runtime
+      // package they are mostly types defined by mkrsysinfo.sh based
+      // on the C system header files.  We don't need to translate
+      // types to C and back to Go.  But do accept the special cases
+      // _defer and _panic.
+      std::string name = Gogo::unpack_hidden_name(no->name());
+      if (name[0] == '_'
+	  && (name[1] < 'A' || name[1] > 'Z')
+	  && (name != "_defer" && name != "_panic"))
+	continue;
+
       if (no->is_type() && no->type_value()->struct_type() != NULL)
 	types.push_back(no);
       if (no->is_const() && no->const_value()->type()->integer_type() != NULL)
Index: libgo/Makefile.am
===================================================================
--- libgo/Makefile.am	(revision 240588)
+++ libgo/Makefile.am	(working copy)
@@ -396,9 +396,9 @@  rtems_task_variable_add_file =
 endif
 
 if LIBGO_IS_LINUX
-runtime_lock_files = runtime/lock_futex.c runtime/thread-linux.c
+runtime_thread_files = runtime/thread-linux.c
 else
-runtime_lock_files = runtime/lock_sema.c runtime/thread-sema.c
+runtime_thread_files = runtime/thread-sema.c
 endif
 
 if LIBGO_IS_LINUX
@@ -502,7 +502,6 @@  runtime_files = \
 	runtime/go-varargs.c \
 	runtime/env_posix.c \
 	runtime/heapdump.c \
-	$(runtime_lock_files) \
 	runtime/mcache.c \
 	runtime/mcentral.c \
 	$(runtime_mem_file) \
@@ -518,6 +517,7 @@  runtime_files = \
 	runtime/runtime.c \
 	runtime/signal_unix.c \
 	runtime/thread.c \
+	$(runtime_thread_files) \
 	runtime/yield.c \
 	$(rtems_task_variable_add_file) \
 	chan.c \
@@ -633,12 +633,8 @@  s-version: Makefile
 	$(STAMP) $@
 
 runtime_sysinfo.go: s-runtime_sysinfo; @true
-s-runtime_sysinfo: sysinfo.go
-	rm -f tmp-runtime_sysinfo.go
-	echo 'package runtime' > tmp-runtime_sysinfo.go
-	echo >> tmp-runtime_sysinfo.go
-	grep 'const _sizeof_ucontext_t ' sysinfo.go >> tmp-runtime_sysinfo.go
-	grep 'type _sigset_t ' sysinfo.go >> tmp-runtime_sysinfo.go
+s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go
+	$(SHELL) $(srcdir)/mkrsysinfo.sh
 	$(SHELL) $(srcdir)/mvifdiff.sh tmp-runtime_sysinfo.go runtime_sysinfo.go
 	$(STAMP) $@
 
Index: libgo/configure.ac
===================================================================
--- libgo/configure.ac	(revision 240146)
+++ libgo/configure.ac	(working copy)
@@ -570,7 +570,7 @@  AC_C_BIGENDIAN
 
 GCC_CHECK_UNWIND_GETIPINFO
 
-AC_CHECK_HEADERS(sched.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/icmp6.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h)
+AC_CHECK_HEADERS(sched.h semaphore.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/icmp6.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h)
 
 AC_CHECK_HEADERS([linux/filter.h linux/if_addr.h linux/if_ether.h linux/if_tun.h linux/netlink.h linux/rtnetlink.h], [], [],
 [#ifdef HAVE_SYS_SOCKET_H
Index: libgo/go/runtime/export_test.go
===================================================================
--- libgo/go/runtime/export_test.go	(revision 240609)
+++ libgo/go/runtime/export_test.go	(working copy)
@@ -17,8 +17,6 @@  package runtime
 //var F64toint = f64toint
 //var Sqrt = sqrt
 
-func entersyscall(int32)
-func exitsyscall(int32)
 func golockedOSThread() bool
 
 var Entersyscall = entersyscall
Index: libgo/go/runtime/lock_futex.go
===================================================================
--- libgo/go/runtime/lock_futex.go	(revision 0)
+++ libgo/go/runtime/lock_futex.go	(working copy)
@@ -0,0 +1,225 @@ 
+// 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
+
+package runtime
+
+import (
+	"runtime/internal/atomic"
+	"unsafe"
+)
+
+// For gccgo, while we still have C runtime code, use go:linkname to
+// rename some functions to themselves, so that the compiler will
+// export them.
+//
+//go:linkname lock runtime.lock
+//go:linkname unlock runtime.unlock
+//go:linkname noteclear runtime.noteclear
+//go:linkname notewakeup runtime.notewakeup
+//go:linkname notesleep runtime.notesleep
+//go:linkname notetsleep runtime.notetsleep
+//go:linkname notetsleepg runtime.notetsleepg
+
+// This implementation depends on OS-specific implementations of
+//
+//	futexsleep(addr *uint32, val uint32, ns int64)
+//		Atomically,
+//			if *addr == val { sleep }
+//		Might be woken up spuriously; that's allowed.
+//		Don't sleep longer than ns; ns < 0 means forever.
+//
+//	futexwakeup(addr *uint32, cnt uint32)
+//		If any procs are sleeping on addr, wake up at most cnt.
+
+const (
+	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.
+
+// We use the uintptr mutex.key and note.key as a uint32.
+func key32(p *uintptr) *uint32 {
+	return (*uint32)(unsafe.Pointer(p))
+}
+
+func lock(l *mutex) {
+	gp := getg()
+
+	if gp.m.locks < 0 {
+		throw("runtime·lock: lock count")
+	}
+	gp.m.locks++
+
+	// Speculative grab for lock.
+	v := atomic.Xchg(key32(&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 uniprocessors, no point spinning.
+	// On multiprocessors, spin for ACTIVE_SPIN attempts.
+	spin := 0
+	if ncpu > 1 {
+		spin = active_spin
+	}
+	for {
+		// Try for lock, spinning.
+		for i := 0; i < spin; i++ {
+			for l.key == mutex_unlocked {
+				if atomic.Cas(key32(&l.key), mutex_unlocked, wait) {
+					return
+				}
+			}
+			procyield(active_spin_cnt)
+		}
+
+		// Try for lock, rescheduling.
+		for i := 0; i < passive_spin; i++ {
+			for l.key == mutex_unlocked {
+				if atomic.Cas(key32(&l.key), mutex_unlocked, wait) {
+					return
+				}
+			}
+			osyield()
+		}
+
+		// Sleep.
+		v = atomic.Xchg(key32(&l.key), mutex_sleeping)
+		if v == mutex_unlocked {
+			return
+		}
+		wait = mutex_sleeping
+		futexsleep(key32(&l.key), mutex_sleeping, -1)
+	}
+}
+
+func unlock(l *mutex) {
+	v := atomic.Xchg(key32(&l.key), mutex_unlocked)
+	if v == mutex_unlocked {
+		throw("unlock of unlocked lock")
+	}
+	if v == mutex_sleeping {
+		futexwakeup(key32(&l.key), 1)
+	}
+
+	gp := getg()
+	gp.m.locks--
+	if gp.m.locks < 0 {
+		throw("runtime·unlock: lock count")
+	}
+	// if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack
+	//	gp.stackguard0 = stackPreempt
+	// }
+}
+
+// One-time notifications.
+func noteclear(n *note) {
+	n.key = 0
+}
+
+func notewakeup(n *note) {
+	old := atomic.Xchg(key32(&n.key), 1)
+	if old != 0 {
+		print("notewakeup - double wakeup (", old, ")\n")
+		throw("notewakeup - double wakeup")
+	}
+	futexwakeup(key32(&n.key), 1)
+}
+
+func notesleep(n *note) {
+	gp := getg()
+
+	// Currently OK to sleep in non-g0 for gccgo.  It happens in
+	// stoptheworld because we have not implemented preemption.
+	// if gp != gp.m.g0 {
+	// 	throw("notesleep not on g0")
+	// }
+
+	for atomic.Load(key32(&n.key)) == 0 {
+		gp.m.blocked = true
+		futexsleep(key32(&n.key), 0, -1)
+		gp.m.blocked = false
+	}
+}
+
+// May run with m.p==nil if called from notetsleep, so write barriers
+// are not allowed.
+//
+//go:nosplit
+//go:nowritebarrier
+func notetsleep_internal(n *note, ns int64) bool {
+	gp := getg()
+
+	if ns < 0 {
+		for atomic.Load(key32(&n.key)) == 0 {
+			gp.m.blocked = true
+			futexsleep(key32(&n.key), 0, -1)
+			gp.m.blocked = false
+		}
+		return true
+	}
+
+	if atomic.Load(key32(&n.key)) != 0 {
+		return true
+	}
+
+	deadline := nanotime() + ns
+	for {
+		gp.m.blocked = true
+		futexsleep(key32(&n.key), 0, ns)
+		gp.m.blocked = false
+		if atomic.Load(key32(&n.key)) != 0 {
+			break
+		}
+		now := nanotime()
+		if now >= deadline {
+			break
+		}
+		ns = deadline - now
+	}
+	return atomic.Load(key32(&n.key)) != 0
+}
+
+func notetsleep(n *note, ns int64) bool {
+	gp := getg()
+	if gp != gp.m.g0 && gp.m.preemptoff != "" {
+		throw("notetsleep not on g0")
+	}
+
+	return notetsleep_internal(n, ns)
+}
+
+// same as runtime·notetsleep, but called on user g (not g0)
+// calls only nosplit functions between entersyscallblock/exitsyscall
+func notetsleepg(n *note, ns int64) bool {
+	gp := getg()
+	if gp == gp.m.g0 {
+		throw("notetsleepg on g0")
+	}
+
+	entersyscallblock(0)
+	ok := notetsleep_internal(n, ns)
+	exitsyscall(0)
+	return ok
+}
Index: libgo/go/runtime/lock_sema.go
===================================================================
--- libgo/go/runtime/lock_sema.go	(revision 0)
+++ libgo/go/runtime/lock_sema.go	(working copy)
@@ -0,0 +1,281 @@ 
+// 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
+
+package runtime
+
+import (
+	"runtime/internal/atomic"
+	"unsafe"
+)
+
+// For gccgo, while we still have C runtime code, use go:linkname to
+// rename some functions to themselves, so that the compiler will
+// export them.
+//
+//go:linkname lock runtime.lock
+//go:linkname unlock runtime.unlock
+//go:linkname noteclear runtime.noteclear
+//go:linkname notewakeup runtime.notewakeup
+//go:linkname notesleep runtime.notesleep
+//go:linkname notetsleep runtime.notetsleep
+//go:linkname notetsleepg runtime.notetsleepg
+
+// This implementation depends on OS-specific implementations of
+//
+//	func semacreate(mp *m)
+//		Create a semaphore for mp, if it does not already have one.
+//
+//	func semasleep(ns int64) int32
+//		If ns < 0, acquire m's semaphore and return 0.
+//		If ns >= 0, try to acquire m's semaphore for at most ns nanoseconds.
+//		Return 0 if the semaphore was acquired, -1 if interrupted or timed out.
+//
+//	func semawakeup(mp *m)
+//		Wake up mp, which is or will soon be sleeping on its semaphore.
+//
+const (
+	mutex_locked uintptr = 1
+
+	active_spin     = 4
+	active_spin_cnt = 30
+	passive_spin    = 1
+)
+
+func lock(l *mutex) {
+	gp := getg()
+	if gp.m.locks < 0 {
+		throw("runtime·lock: lock count")
+	}
+	gp.m.locks++
+
+	// Speculative grab for lock.
+	if atomic.Casuintptr(&l.key, 0, mutex_locked) {
+		return
+	}
+	semacreate(gp.m)
+
+	// On uniprocessor's, no point spinning.
+	// On multiprocessors, spin for ACTIVE_SPIN attempts.
+	spin := 0
+	if ncpu > 1 {
+		spin = active_spin
+	}
+Loop:
+	for i := 0; ; i++ {
+		v := atomic.Loaduintptr(&l.key)
+		if v&mutex_locked == 0 {
+			// Unlocked. Try to lock.
+			if atomic.Casuintptr(&l.key, v, v|mutex_locked) {
+				return
+			}
+			i = 0
+		}
+		if i < spin {
+			procyield(active_spin_cnt)
+		} else if i < spin+passive_spin {
+			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 {
+				gp.m.nextwaitm = v &^ mutex_locked
+				if atomic.Casuintptr(&l.key, v, uintptr(unsafe.Pointer(gp.m))|mutex_locked) {
+					break
+				}
+				v = atomic.Loaduintptr(&l.key)
+				if v&mutex_locked == 0 {
+					continue Loop
+				}
+			}
+			if v&mutex_locked != 0 {
+				// Queued. Wait.
+				semasleep(-1)
+				i = 0
+			}
+		}
+	}
+}
+
+//go:nowritebarrier
+// We might not be holding a p in this code.
+func unlock(l *mutex) {
+	gp := getg()
+	var mp *m
+	for {
+		v := atomic.Loaduintptr(&l.key)
+		if v == mutex_locked {
+			if atomic.Casuintptr(&l.key, mutex_locked, 0) {
+				break
+			}
+		} else {
+			// Other M's are waiting for the lock.
+			// Dequeue an M.
+			mp = (*m)(unsafe.Pointer(v &^ mutex_locked))
+			if atomic.Casuintptr(&l.key, v, mp.nextwaitm) {
+				// Dequeued an M.  Wake it.
+				semawakeup(mp)
+				break
+			}
+		}
+	}
+	gp.m.locks--
+	if gp.m.locks < 0 {
+		throw("runtime·unlock: lock count")
+	}
+	// if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack
+	//	gp.stackguard0 = stackPreempt
+	// }
+}
+
+// One-time notifications.
+func noteclear(n *note) {
+	n.key = 0
+}
+
+func notewakeup(n *note) {
+	var v uintptr
+	for {
+		v = atomic.Loaduintptr(&n.key)
+		if atomic.Casuintptr(&n.key, v, mutex_locked) {
+			break
+		}
+	}
+
+	// Successfully set waitm to locked.
+	// What was it before?
+	switch {
+	case v == 0:
+		// Nothing was waiting. Done.
+	case v == mutex_locked:
+		// Two notewakeups!  Not allowed.
+		throw("notewakeup - double wakeup")
+	default:
+		// Must be the waiting m. Wake it up.
+		semawakeup((*m)(unsafe.Pointer(v)))
+	}
+}
+
+func notesleep(n *note) {
+	gp := getg()
+
+	// Currently OK to sleep in non-g0 for gccgo.  It happens in
+	// stoptheworld because we have not implemented preemption.
+	// if gp != gp.m.g0 {
+	//	throw("notesleep not on g0")
+	// }
+
+	semacreate(gp.m)
+	if !atomic.Casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) {
+		// Must be locked (got wakeup).
+		if n.key != mutex_locked {
+			throw("notesleep - waitm out of sync")
+		}
+		return
+	}
+	// Queued. Sleep.
+	gp.m.blocked = true
+	semasleep(-1)
+	gp.m.blocked = false
+}
+
+//go:nosplit
+func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
+	// gp and deadline are logically local variables, but they are written
+	// as parameters so that the stack space they require is charged
+	// to the caller.
+	// This reduces the nosplit footprint of notetsleep_internal.
+	gp = getg()
+
+	// Register for wakeup on n->waitm.
+	if !atomic.Casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) {
+		// Must be locked (got wakeup).
+		if n.key != mutex_locked {
+			throw("notetsleep - waitm out of sync")
+		}
+		return true
+	}
+	if ns < 0 {
+		// Queued. Sleep.
+		gp.m.blocked = true
+		semasleep(-1)
+		gp.m.blocked = false
+		return true
+	}
+
+	deadline = nanotime() + ns
+	for {
+		// Registered. Sleep.
+		gp.m.blocked = true
+		if semasleep(ns) >= 0 {
+			gp.m.blocked = false
+			// Acquired semaphore, semawakeup unregistered us.
+			// Done.
+			return true
+		}
+		gp.m.blocked = false
+		// Interrupted or timed out. Still registered. Semaphore not acquired.
+		ns = deadline - 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 {
+		v := atomic.Loaduintptr(&n.key)
+		switch v {
+		case uintptr(unsafe.Pointer(gp.m)):
+			// No wakeup yet; unregister if possible.
+			if atomic.Casuintptr(&n.key, v, 0) {
+				return false
+			}
+		case mutex_locked:
+			// Wakeup happened so semaphore is available.
+			// Grab it to avoid getting out of sync.
+			gp.m.blocked = true
+			if semasleep(-1) < 0 {
+				throw("runtime: unable to acquire - semaphore out of sync")
+			}
+			gp.m.blocked = false
+			return true
+		default:
+			throw("runtime: unexpected waitm - semaphore out of sync")
+		}
+	}
+}
+
+func notetsleep(n *note, ns int64) bool {
+	gp := getg()
+
+	// Currently OK to sleep in non-g0 for gccgo.  It happens in
+	// stoptheworld because we have not implemented preemption.
+	// if gp != gp.m.g0 && gp.m.preemptoff != "" {
+	//	throw("notetsleep not on g0")
+	// }
+
+	semacreate(gp.m)
+	return notetsleep_internal(n, ns, nil, 0)
+}
+
+// same as runtime·notetsleep, but called on user g (not g0)
+// calls only nosplit functions between entersyscallblock/exitsyscall
+func notetsleepg(n *note, ns int64) bool {
+	gp := getg()
+	if gp == gp.m.g0 {
+		throw("notetsleepg on g0")
+	}
+	semacreate(gp.m)
+	entersyscallblock(0)
+	ok := notetsleep_internal(n, ns, nil, 0)
+	exitsyscall(0)
+	return ok
+}
Index: libgo/go/runtime/os_darwin.go
===================================================================
--- libgo/go/runtime/os_darwin.go	(revision 0)
+++ libgo/go/runtime/os_darwin.go	(working copy)
@@ -0,0 +1,326 @@ 
+// Copyright 2009 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.
+
+package runtime
+
+import "unsafe"
+
+type mOS struct {
+	machport uint32 // return address for mach ipc
+	waitsema uint32 // semaphore for parking on locks
+}
+
+//go:noescape
+//extern mach_msg_trap
+func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32
+
+//extern mach_reply_port
+func mach_reply_port() uint32
+
+//extern mach_task_self
+func mach_task_self() uint32
+
+func unimplemented(name string) {
+	println(name, "not implemented")
+	*(*int)(unsafe.Pointer(uintptr(1231))) = 1231
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	mach_semrelease(mp.mos.waitsema)
+}
+
+//go:nosplit
+func semacreate(mp *m) {
+	if mp.mos.waitsema != 0 {
+		return
+	}
+	systemstack(func() {
+		mp.mos.waitsema = mach_semcreate()
+	})
+}
+
+// Mach IPC, to get at semaphores
+// Definitions are in /usr/include/mach on a Mac.
+
+func macherror(r int32, fn string) {
+	print("mach error ", fn, ": ", r, "\n")
+	throw("mach error")
+}
+
+const _DebugMach = false
+
+var zerondr machndr
+
+func mach_msgh_bits(a, b uint32) uint32 {
+	return a | b<<8
+}
+
+func mach_msg(h *machheader, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32 {
+	// TODO: Loop on interrupt.
+	return mach_msg_trap(unsafe.Pointer(h), op, send_size, rcv_size, rcv_name, timeout, notify)
+}
+
+// Mach RPC (MIG)
+const (
+	_MinMachMsg = 48
+	_MachReply  = 100
+)
+
+type codemsg struct {
+	h    machheader
+	ndr  machndr
+	code int32
+}
+
+func machcall(h *machheader, maxsize int32, rxsize int32) int32 {
+	_g_ := getg()
+	port := _g_.m.mos.machport
+	if port == 0 {
+		port = mach_reply_port()
+		_g_.m.mos.machport = port
+	}
+
+	h.msgh_bits |= mach_msgh_bits(_MACH_MSG_TYPE_COPY_SEND, _MACH_MSG_TYPE_MAKE_SEND_ONCE)
+	h.msgh_local_port = port
+	h.msgh_reserved = 0
+	id := h.msgh_id
+
+	if _DebugMach {
+		p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
+		print("send:\t")
+		var i uint32
+		for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
+			print(" ", p[i])
+			if i%8 == 7 {
+				print("\n\t")
+			}
+		}
+		if i%8 != 0 {
+			print("\n")
+		}
+	}
+	ret := mach_msg(h, _MACH_SEND_MSG|_MACH_RCV_MSG, h.msgh_size, uint32(maxsize), port, 0, 0)
+	if ret != 0 {
+		if _DebugMach {
+			print("mach_msg error ", ret, "\n")
+		}
+		return ret
+	}
+	if _DebugMach {
+		p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
+		var i uint32
+		for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
+			print(" ", p[i])
+			if i%8 == 7 {
+				print("\n\t")
+			}
+		}
+		if i%8 != 0 {
+			print("\n")
+		}
+	}
+	if h.msgh_id != id+_MachReply {
+		if _DebugMach {
+			print("mach_msg _MachReply id mismatch ", h.msgh_id, " != ", id+_MachReply, "\n")
+		}
+		return -303 // MIG_REPLY_MISMATCH
+	}
+	// Look for a response giving the return value.
+	// Any call can send this back with an error,
+	// and some calls only have return values so they
+	// send it back on success too. I don't quite see how
+	// you know it's one of these and not the full response
+	// format, so just look if the message is right.
+	c := (*codemsg)(unsafe.Pointer(h))
+	if uintptr(h.msgh_size) == unsafe.Sizeof(*c) && h.msgh_bits&_MACH_MSGH_BITS_COMPLEX == 0 {
+		if _DebugMach {
+			print("mig result ", c.code, "\n")
+		}
+		return c.code
+	}
+	if h.msgh_size != uint32(rxsize) {
+		if _DebugMach {
+			print("mach_msg _MachReply size mismatch ", h.msgh_size, " != ", rxsize, "\n")
+		}
+		return -307 // MIG_ARRAY_TOO_LARGE
+	}
+	return 0
+}
+
+// Semaphores!
+
+const (
+	tmach_semcreate = 3418
+	rmach_semcreate = tmach_semcreate + _MachReply
+
+	tmach_semdestroy = 3419
+	rmach_semdestroy = tmach_semdestroy + _MachReply
+
+	_KERN_ABORTED             = 14
+	_KERN_OPERATION_TIMED_OUT = 49
+)
+
+type tmach_semcreatemsg struct {
+	h      machheader
+	ndr    machndr
+	policy int32
+	value  int32
+}
+
+type rmach_semcreatemsg struct {
+	h         machheader
+	body      machbody
+	semaphore machport
+}
+
+type tmach_semdestroymsg struct {
+	h         machheader
+	body      machbody
+	semaphore machport
+}
+
+func mach_semcreate() uint32 {
+	var m [256]uint8
+	tx := (*tmach_semcreatemsg)(unsafe.Pointer(&m))
+	rx := (*rmach_semcreatemsg)(unsafe.Pointer(&m))
+
+	tx.h.msgh_bits = 0
+	tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
+	tx.h.msgh_remote_port = mach_task_self()
+	tx.h.msgh_id = tmach_semcreate
+	tx.ndr = zerondr
+
+	tx.policy = 0 // 0 = SYNC_POLICY_FIFO
+	tx.value = 0
+
+	for {
+		r := machcall(&tx.h, int32(unsafe.Sizeof(m)), int32(unsafe.Sizeof(*rx)))
+		if r == 0 {
+			break
+		}
+		if r == _KERN_ABORTED { // interrupted
+			continue
+		}
+		macherror(r, "semaphore_create")
+	}
+	if rx.body.msgh_descriptor_count != 1 {
+		unimplemented("mach_semcreate desc count")
+	}
+	return rx.semaphore.name
+}
+
+func mach_semdestroy(sem uint32) {
+	var m [256]uint8
+	tx := (*tmach_semdestroymsg)(unsafe.Pointer(&m))
+
+	tx.h.msgh_bits = _MACH_MSGH_BITS_COMPLEX
+	tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
+	tx.h.msgh_remote_port = mach_task_self()
+	tx.h.msgh_id = tmach_semdestroy
+	tx.body.msgh_descriptor_count = 1
+	tx.semaphore.name = sem
+	tx.semaphore.disposition = _MACH_MSG_TYPE_MOVE_SEND
+	tx.semaphore._type = 0
+
+	for {
+		r := machcall(&tx.h, int32(unsafe.Sizeof(m)), 0)
+		if r == 0 {
+			break
+		}
+		if r == _KERN_ABORTED { // interrupted
+			continue
+		}
+		macherror(r, "semaphore_destroy")
+	}
+}
+
+//extern semaphore_wait
+func mach_semaphore_wait(sema uint32) int32
+
+//extern semaphore_timedwait
+func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
+
+//extern semaphore_signal
+func mach_semaphore_signal(sema uint32) int32
+
+//extern semaphore_signal_all
+func mach_semaphore_signal_all(sema uint32) int32
+
+func semasleep1(ns int64) int32 {
+	_g_ := getg()
+
+	if ns >= 0 {
+		var nsecs int32
+		secs := timediv(ns, 1000000000, &nsecs)
+		r := mach_semaphore_timedwait(_g_.m.mos.waitsema, uint32(secs), uint32(nsecs))
+		if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT {
+			return -1
+		}
+		if r != 0 {
+			macherror(r, "semaphore_wait")
+		}
+		return 0
+	}
+
+	for {
+		r := mach_semaphore_wait(_g_.m.mos.waitsema)
+		if r == 0 {
+			break
+		}
+		if r == _KERN_ABORTED { // interrupted
+			continue
+		}
+		macherror(r, "semaphore_wait")
+	}
+	return 0
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+	var r int32
+	systemstack(func() {
+		r = semasleep1(ns)
+	})
+	return r
+}
+
+//go:nosplit
+func mach_semrelease(sem uint32) {
+	for {
+		r := mach_semaphore_signal(sem)
+		if r == 0 {
+			break
+		}
+		if r == _KERN_ABORTED { // interrupted
+			continue
+		}
+
+		// mach_semrelease must be completely nosplit,
+		// because it is called from Go code.
+		// If we're going to die, start that process on the system stack
+		// to avoid a Go stack split.
+		systemstack(func() { macherror(r, "semaphore_signal") })
+	}
+}
+
+type machheader struct {
+	msgh_bits        uint32
+	msgh_size        uint32
+	msgh_remote_port uint32
+	msgh_local_port  uint32
+	msgh_reserved    uint32
+	msgh_id          int32
+}
+
+type machndr struct {
+	mig_vers     uint8
+	if_vers      uint8
+	reserved1    uint8
+	mig_encoding uint8
+	int_rep      uint8
+	char_rep     uint8
+	float_rep    uint8
+	reserved2    uint8
+}
Index: libgo/go/runtime/os_dragonfly.go
===================================================================
--- libgo/go/runtime/os_dragonfly.go	(revision 0)
+++ libgo/go/runtime/os_dragonfly.go	(working copy)
@@ -0,0 +1,62 @@ 
+// Copyright 2014 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.
+
+package runtime
+
+import "unsafe"
+
+type mOS struct {
+	unused byte
+}
+
+//go:noescape
+//extern umtx_sleep
+func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
+
+//go:noescape
+//extern umtx_wakeup
+func sys_umtx_wakeup(addr *uint32, val int32) int32
+
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+	systemstack(func() {
+		futexsleep1(addr, val, ns)
+	})
+}
+
+func futexsleep1(addr *uint32, val uint32, ns int64) {
+	var timeout int32
+	if ns >= 0 {
+		// The timeout is specified in microseconds - ensure that we
+		// do not end up dividing to zero, which would put us to sleep
+		// indefinitely...
+		timeout = timediv(ns, 1000, nil)
+		if timeout == 0 {
+			timeout = 1
+		}
+	}
+
+	// sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
+	// expires or EBUSY if the mutex value does not match.
+	ret := sys_umtx_sleep(addr, int32(val), timeout)
+	if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY {
+		return
+	}
+
+	print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n")
+	*(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
+}
+
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+	ret := sys_umtx_wakeup(addr, int32(cnt))
+	if ret >= 0 {
+		return
+	}
+
+	systemstack(func() {
+		print("umtx_wake_addr=", addr, " ret=", ret, "\n")
+		*(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
+	})
+}
Index: libgo/go/runtime/os_freebsd.go
===================================================================
--- libgo/go/runtime/os_freebsd.go	(revision 0)
+++ libgo/go/runtime/os_freebsd.go	(working copy)
@@ -0,0 +1,56 @@ 
+// 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.
+
+package runtime
+
+import (
+	"unsafe"
+)
+
+type mOS struct {
+	unused byte
+}
+
+//go:noescape
+//extern _umtx_op
+func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32
+
+// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
+// thus the code is largely similar. See Linux implementation
+// and lock_futex.go for comments.
+
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+	systemstack(func() {
+		futexsleep1(addr, val, ns)
+	})
+}
+
+func futexsleep1(addr *uint32, val uint32, ns int64) {
+	var tsp *timespec
+	if ns >= 0 {
+		var ts timespec
+		ts.tv_nsec = 0
+		ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
+		tsp = &ts
+	}
+	ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp)
+	if ret >= 0 || ret == -_EINTR {
+		return
+	}
+	print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
+	*(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
+}
+
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+	ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil)
+	if ret >= 0 {
+		return
+	}
+
+	systemstack(func() {
+		print("umtx_wake_addr=", addr, " ret=", ret, "\n")
+	})
+}
Index: libgo/go/runtime/os_linux.go
===================================================================
--- libgo/go/runtime/os_linux.go	(revision 240609)
+++ libgo/go/runtime/os_linux.go	(working copy)
@@ -9,6 +9,80 @@  import (
 	"unsafe"
 )
 
+type mOS struct {
+	unused byte
+}
+
+func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32 {
+	return int32(syscall(_SYS_futex, uintptr(addr), uintptr(op), uintptr(val), uintptr(ts), uintptr(addr2), uintptr(val3)))
+}
+
+// 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.
+
+const (
+	_FUTEX_WAIT = 0
+	_FUTEX_WAKE = 1
+)
+
+// Atomically,
+//	if(*addr == val) sleep
+// Might be woken up spuriously; that's allowed.
+// Don't sleep longer than ns; ns < 0 means forever.
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+	var ts timespec
+
+	// 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 {
+		futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, nil, nil, 0)
+		return
+	}
+
+	// It's difficult to live within the no-split stack limits here.
+	// On ARM and 386, a 64-bit divide invokes a general software routine
+	// that needs more stack than we can afford. So we use timediv instead.
+	// But on real 64-bit systems, where words are larger but the stack limit
+	// is not, even timediv is too heavy, and we really need to use just an
+	// ordinary machine instruction.
+	if sys.PtrSize == 8 {
+		ts.set_sec(ns / 1000000000)
+		ts.set_nsec(int32(ns % 1000000000))
+	} else {
+		ts.tv_nsec = 0
+		ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
+	}
+	futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, unsafe.Pointer(&ts), nil, 0)
+}
+
+// If any procs are sleeping on addr, wake up at most cnt.
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+	ret := futex(unsafe.Pointer(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.
+	systemstack(func() {
+		print("futexwakeup addr=", addr, " returned ", ret, "\n")
+	})
+
+	*(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
+}
+
 const (
 	_AT_NULL   = 0  // End of vector
 	_AT_PAGESZ = 6  // System physical page size
Index: libgo/go/runtime/os_netbsd.go
===================================================================
--- libgo/go/runtime/os_netbsd.go	(revision 0)
+++ libgo/go/runtime/os_netbsd.go	(working copy)
@@ -0,0 +1,73 @@ 
+// Copyright 2014 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.
+
+package runtime
+
+import (
+	"runtime/internal/atomic"
+	"unsafe"
+)
+
+type mOS struct {
+	waitsemacount uint32
+}
+
+//go:noescape
+//extern lwp_park
+func lwp_park(abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32
+
+//go:noescape
+//extern lwp_unpark
+func lwp_unpark(lwp int32, hint unsafe.Pointer) int32
+
+//go:nosplit
+func semacreate(mp *m) {
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+	_g_ := getg()
+
+	// Compute sleep deadline.
+	var tsp *timespec
+	if ns >= 0 {
+		var ts timespec
+		var nsec int32
+		ns += nanotime()
+		ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
+		ts.set_nsec(nsec)
+		tsp = &ts
+	}
+
+	for {
+		v := atomic.Load(&_g_.m.mos.waitsemacount)
+		if v > 0 {
+			if atomic.Cas(&_g_.m.mos.waitsemacount, v, v-1) {
+				return 0 // semaphore acquired
+			}
+			continue
+		}
+
+		// Sleep until unparked by semawakeup or timeout.
+		ret := lwp_park(tsp, 0, unsafe.Pointer(&_g_.m.mos.waitsemacount), nil)
+		if ret == _ETIMEDOUT {
+			return -1
+		}
+	}
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	atomic.Xadd(&mp.mos.waitsemacount, 1)
+	// From NetBSD's _lwp_unpark(2) manual:
+	// "If the target LWP is not currently waiting, it will return
+	// immediately upon the next call to _lwp_park()."
+	ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.mos.waitsemacount))
+	if ret != 0 && ret != _ESRCH {
+		// semawakeup can be called on signal stack.
+		systemstack(func() {
+			print("thrwakeup addr=", &mp.mos.waitsemacount, " sem=", mp.mos.waitsemacount, " ret=", ret, "\n")
+		})
+	}
+}
Index: libgo/go/runtime/os_openbsd.go
===================================================================
--- libgo/go/runtime/os_openbsd.go	(revision 0)
+++ libgo/go/runtime/os_openbsd.go	(working copy)
@@ -0,0 +1,76 @@ 
+// 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.
+
+package runtime
+
+import (
+	"runtime/internal/atomic"
+	"unsafe"
+)
+
+type mOS struct {
+	waitsemacount uint32
+}
+
+//go:noescape
+//extern thrsleep
+func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32
+
+//go:noescape
+//extern thrwakeup
+func thrwakeup(ident uintptr, n int32) int32
+
+//go:nosplit
+func semacreate(mp *m) {
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+	_g_ := getg()
+
+	// Compute sleep deadline.
+	var tsp *timespec
+	if ns >= 0 {
+		var ts timespec
+		var nsec int32
+		ns += nanotime()
+		ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
+		ts.set_nsec(nsec)
+		tsp = &ts
+	}
+
+	for {
+		v := atomic.Load(&_g_.m.mos.waitsemacount)
+		if v > 0 {
+			if atomic.Cas(&_g_.m.mos.waitsemacount, v, v-1) {
+				return 0 // semaphore acquired
+			}
+			continue
+		}
+
+		// Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
+		//
+		// From OpenBSD's __thrsleep(2) manual:
+		// "The abort argument, if not NULL, points to an int that will
+		// be examined [...] immediately before blocking. If that int
+		// is non-zero then __thrsleep() will immediately return EINTR
+		// without blocking."
+		ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.mos.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.mos.waitsemacount)
+		if ret == _EWOULDBLOCK {
+			return -1
+		}
+	}
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	atomic.Xadd(&mp.mos.waitsemacount, 1)
+	ret := thrwakeup(uintptr(unsafe.Pointer(&mp.mos.waitsemacount)), 1)
+	if ret != 0 && ret != _ESRCH {
+		// semawakeup can be called on signal stack.
+		systemstack(func() {
+			print("thrwakeup addr=", &mp.mos.waitsemacount, " sem=", mp.mos.waitsemacount, " ret=", ret, "\n")
+		})
+	}
+}
Index: libgo/go/runtime/os_solaris.go
===================================================================
--- libgo/go/runtime/os_solaris.go	(revision 0)
+++ libgo/go/runtime/os_solaris.go	(working copy)
@@ -0,0 +1,85 @@ 
+// 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.
+
+package runtime
+
+import "unsafe"
+
+type mOS struct {
+	waitsema uintptr // semaphore for parking on locks
+}
+
+//extern malloc
+func libc_malloc(uintptr) unsafe.Pointer
+
+//go:noescape
+//extern sem_init
+func sem_init(sem *semt, pshared int32, value uint32) int32
+
+//go:noescape
+//extern sem_wait
+func sem_wait(sem *semt) int32
+
+//go:noescape
+//extern sem_post
+func sem_post(sem *semt) int32
+
+//go:noescape
+//extern sem_reltimedwait_np
+func sem_reltimedwait_np(sem *semt, timeout *timespec) int32
+
+//go:nosplit
+func semacreate(mp *m) {
+	if mp.mos.waitsema != 0 {
+		return
+	}
+
+	var sem *semt
+
+	// Call libc's malloc rather than malloc. This will
+	// allocate space on the C heap. We can't call malloc
+	// here because it could cause a deadlock.
+	sem = (*semt)(libc_malloc(unsafe.Sizeof(*sem)))
+	if sem_init(sem, 0, 0) != 0 {
+		throw("sem_init")
+	}
+	mp.mos.waitsema = uintptr(unsafe.Pointer(sem))
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+	_m_ := getg().m
+	if ns >= 0 {
+		var ts timespec
+		ts.set_sec(ns / 1000000000)
+		ts.set_nsec(int32(ns % 1000000000))
+
+		if sem_reltimedwait_np((*semt)(unsafe.Pointer(_m_.mos.waitsema)), &ts) != 0 {
+			err := errno()
+			if err == _ETIMEDOUT || err == _EAGAIN || err == _EINTR {
+				return -1
+			}
+			throw("sem_reltimedwait_np")
+		}
+		return 0
+	}
+	for {
+		r1 := sem_wait((*semt)(unsafe.Pointer(_m_.mos.waitsema)))
+		if r1 == 0 {
+			break
+		}
+		if errno() == _EINTR {
+			continue
+		}
+		throw("sem_wait")
+	}
+	return 0
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	if sem_post((*semt)(unsafe.Pointer(mp.mos.waitsema))) != 0 {
+		throw("sem_post")
+	}
+}
Index: libgo/go/runtime/runtime2.go
===================================================================
--- libgo/go/runtime/runtime2.go	(revision 240609)
+++ libgo/go/runtime/runtime2.go	(working copy)
@@ -396,7 +396,7 @@  type g struct {
 	gcnextsegment unsafe.Pointer
 	gcnextsp      unsafe.Pointer
 	gcinitialsp   unsafe.Pointer
-	gcregs        _ucontext_t
+	gcregs        g_ucontext_t
 
 	entry    unsafe.Pointer // goroutine entry point
 	fromgogo bool           // whether entered from gogo function
@@ -406,7 +406,7 @@  type g struct {
 
 	traceback *traceback // stack traceback buffer
 
-	context      _ucontext_t        // saved context for setcontext
+	context      g_ucontext_t       // saved context for setcontext
 	stackcontext [10]unsafe.Pointer // split-stack context
 }
 
@@ -474,7 +474,7 @@  type m struct {
 	// Not for gccgo: libcallg  guintptr
 	// Not for gccgo: syscall   libcall // stores syscall parameters on windows
 
-	// Not for gccgo: mOS
+	mos mOS
 
 	// Remaining fields are specific to gccgo.
 
@@ -485,8 +485,6 @@  type m struct {
 
 	gcing int32
 
-	waitsema uintptr // semaphore on systems that don't use futexes
-
 	cgomal *cgoMal // allocations via _cgo_allocate
 }
 
@@ -771,13 +769,15 @@  const (
 const _TracebackMaxFrames = 100
 
 var (
-//	emptystring string
-//	allglen     uintptr
-//	allm        *m
-//	allp        [_MaxGomaxprocs + 1]*p
-//	gomaxprocs  int32
-//	panicking   uint32
-//	ncpu        int32
+	//	emptystring string
+	//	allglen     uintptr
+	//	allm        *m
+	//	allp        [_MaxGomaxprocs + 1]*p
+	//	gomaxprocs  int32
+	//	panicking   uint32
+
+	ncpu int32
+
 //	forcegc     forcegcstate
 //	sched       schedt
 //	newprocs    int32
@@ -803,13 +803,13 @@  var (
 
 // Types that are only used by gccgo.
 
-// _ucontext_t is a Go version of the C ucontext_t type, used by getcontext.
-// _sizeof_ucontext_t is defined by the Makefile from <ucontext.h>.
+// g_ucontext_t is a Go version of the C ucontext_t type, used by getcontext.
+// _sizeof_ucontext_t is defined by mkrsysinfo.sh from <ucontext.h>.
 // On some systems getcontext and friends require a value that is
 // aligned to a 16-byte boundary.  We implement this by increasing the
 // required size and picking an appropriate offset when we use the
 // array.
-type _ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(unsafe.Pointer(nil))]unsafe.Pointer
+type g_ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(unsafe.Pointer(nil))]unsafe.Pointer
 
 // traceback is used to collect stack traces from other goroutines.
 type traceback struct {
Index: libgo/go/runtime/stubs.go
===================================================================
--- libgo/go/runtime/stubs.go	(revision 240609)
+++ libgo/go/runtime/stubs.go	(working copy)
@@ -38,12 +38,7 @@  func getg() *g
 func mcall(fn func(*g))
 
 // systemstack runs fn on a system stack.
-// If systemstack is called from the per-OS-thread (g0) stack, or
-// if systemstack is called from the signal handling (gsignal) stack,
-// systemstack calls fn directly and returns.
-// Otherwise, systemstack is being called from the limited stack
-// of an ordinary goroutine. In this case, systemstack switches
-// to the per-OS-thread stack, calls fn, and switches back.
+//
 // It is common to use a func literal as the argument, in order
 // to share inputs and outputs with the code around the call
 // to system stack:
@@ -54,8 +49,14 @@  func mcall(fn func(*g))
 //	})
 //	... use x ...
 //
-//go:noescape
-func systemstack(fn func())
+// For the gc toolchain this permits running a function that requires
+// additional stack space in a context where the stack can not be
+// split.  For gccgo, however, stack splitting is not managed by the
+// Go runtime. In effect, all stacks are system stacks. So this gccgo
+// version just runs the function.
+func systemstack(fn func()) {
+	fn()
+}
 
 func badsystemstack() {
 	throw("systemstack called from unexpected goroutine")
@@ -215,6 +216,13 @@  func checkASM() bool {
 	return true
 }
 
+// For gccgo this is in the C code.
+func osyield()
+
+// For gccgo this can be called directly.
+//extern syscall
+func syscall(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) uintptr
+
 // throw crashes the program.
 // For gccgo unless and until we port panic.go.
 func throw(string)
@@ -368,3 +376,11 @@  func casp(ptr *unsafe.Pointer, old, new
 // Here for gccgo until we port lock_*.go.
 func lock(l *mutex)
 func unlock(l *mutex)
+
+// Here for gccgo for Solaris.
+func errno() int
+
+// Temporary for gccgo until we port proc.go.
+func entersyscall(int32)
+func entersyscallblock(int32)
+func exitsyscall(int32)
Index: libgo/mkrsysinfo.sh
===================================================================
--- libgo/mkrsysinfo.sh	(revision 0)
+++ libgo/mkrsysinfo.sh	(working copy)
@@ -0,0 +1,103 @@ 
+#!/bin/sh
+
+# Copyright 2016 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.
+
+# Create runtime_sysinfo.go from gen-sysinfo.go and errno.i.
+
+OUT=tmp-runtime_sysinfo.go
+
+set -e
+
+echo 'package runtime' > ${OUT}
+
+# Get all the consts and types, skipping ones which could not be
+# represented in Go and ones which we need to rewrite.  We also skip
+# function declarations, as we don't need them here.  All the symbols
+# will all have a leading underscore.
+grep -v '^// ' gen-sysinfo.go | \
+  grep -v '^func' | \
+  grep -v '^type _timeval ' | \
+  grep -v '^type _timespec_t ' | \
+  grep -v '^type _timespec ' | \
+  grep -v '^type _epoll_' | \
+  grep -v 'in6_addr' | \
+  grep -v 'sockaddr_in6' | \
+  sed -e 's/\([^a-zA-Z0-9_]\)_timeval\([^a-zA-Z0-9_]\)/\1timeval\2/g' \
+      -e 's/\([^a-zA-Z0-9_]\)_timespec_t\([^a-zA-Z0-9_]\)/\1timespec\2/g' \
+      -e 's/\([^a-zA-Z0-9_]\)_timespec\([^a-zA-Z0-9_]\)/\1timespec\2/g' \
+    >> ${OUT}
+
+# The time structures need special handling: we need to name the
+# types, so that we can cast integers to the right types when
+# assigning to the structures.
+timeval=`grep '^type _timeval ' gen-sysinfo.go`
+timeval_sec=`echo $timeval | sed -n -e 's/^.*tv_sec \([^ ]*\);.*$/\1/p'`
+timeval_usec=`echo $timeval | sed -n -e 's/^.*tv_usec \([^ ]*\);.*$/\1/p'`
+echo "type timeval_sec_t $timeval_sec" >> ${OUT}
+echo "type timeval_usec_t $timeval_usec" >> ${OUT}
+echo $timeval | \
+  sed -e 's/type _timeval /type timeval /' \
+      -e 's/tv_sec *[a-zA-Z0-9_]*/tv_sec timeval_sec_t/' \
+      -e 's/tv_usec *[a-zA-Z0-9_]*/tv_usec timeval_usec_t/' >> ${OUT}
+timespec=`grep '^type _timespec ' gen-sysinfo.go || true`
+if test "$timespec" = ""; then
+  # IRIX 6.5 has __timespec instead.
+  timespec=`grep '^type ___timespec ' gen-sysinfo.go || true`
+fi
+timespec_sec=`echo $timespec | sed -n -e 's/^.*tv_sec \([^ ]*\);.*$/\1/p'`
+timespec_nsec=`echo $timespec | sed -n -e 's/^.*tv_nsec \([^ ]*\);.*$/\1/p'`
+echo "type timespec_sec_t $timespec_sec" >> ${OUT}
+echo "type timespec_nsec_t $timespec_nsec" >> ${OUT}
+echo $timespec | \
+  sed -e 's/^type ___timespec /type timespec /' \
+      -e 's/^type _timespec /type timespec /' \
+      -e 's/tv_sec *[a-zA-Z0-9_]*/tv_sec timespec_sec_t/' \
+      -e 's/tv_nsec *[a-zA-Z0-9_]*/tv_nsec timespec_nsec_t/' >> ${OUT}
+echo >> ${OUT}
+echo "func (ts *timespec) set_sec(x int64) {" >> ${OUT}
+echo "	ts.tv_sec = timespec_sec_t(x)" >> ${OUT}
+echo "}" >> ${OUT}
+echo >> ${OUT}
+echo "func (ts *timespec) set_nsec(x int32) {" >> ${OUT}
+echo "	ts.tv_nsec = timespec_nsec_t(x)" >> ${OUT}
+echo "}" >> ${OUT}
+
+# The semt structure, for Solaris.
+grep '^type _sem_t ' gen-sysinfo.go | \
+    sed -e 's/_sem_t/semt/' >> ${OUT}
+
+# Solaris 2 needs _u?pad128_t, but its default definition in terms of long
+# double is commented by -fdump-go-spec.
+if grep "^// type _pad128_t" gen-sysinfo.go > /dev/null 2>&1; then
+  echo "type _pad128_t struct { _l [4]int32; }" >> ${OUT}
+fi
+if grep "^// type _upad128_t" gen-sysinfo.go > /dev/null 2>&1; then
+  echo "type _upad128_t struct { _l [4]uint32; }" >> ${OUT}
+fi
+
+# The Solaris 11 Update 1 _zone_net_addr_t struct.
+grep '^type _zone_net_addr_t ' gen-sysinfo.go | \
+    sed -e 's/_in6_addr/[16]byte/' \
+    >> ${OUT}
+
+# The Solaris 12 _flow_arp_desc_t struct.
+grep '^type _flow_arp_desc_t ' gen-sysinfo.go | \
+    sed -e 's/_in6_addr_t/[16]byte/g' \
+    >> ${OUT}
+
+# The Solaris 12 _flow_l3_desc_t struct.
+grep '^type _flow_l3_desc_t ' gen-sysinfo.go | \
+    sed -e 's/_in6_addr_t/[16]byte/g' \
+    >> ${OUT}
+
+# The Solaris 12 _mac_ipaddr_t struct.
+grep '^type _mac_ipaddr_t ' gen-sysinfo.go | \
+    sed -e 's/_in6_addr_t/[16]byte/g' \
+    >> ${OUT}
+
+# The Solaris 12 _mactun_info_t struct.
+grep '^type _mactun_info_t ' gen-sysinfo.go | \
+    sed -e 's/_in6_addr_t/[16]byte/g' \
+    >> ${OUT}

Property changes on: libgo/mkrsysinfo.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: libgo/runtime/go-cgo.c
===================================================================
--- libgo/runtime/go-cgo.c	(revision 240053)
+++ libgo/runtime/go-cgo.c	(working copy)
@@ -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);
Index: libgo/runtime/lock_futex.c
===================================================================
--- libgo/runtime/lock_futex.c	(revision 240053)
+++ libgo/runtime/lock_futex.c	(working copy)
@@ -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;
-}
Index: libgo/runtime/lock_sema.c
===================================================================
--- libgo/runtime/lock_sema.c	(revision 240053)
+++ libgo/runtime/lock_sema.c	(working copy)
@@ -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;
-}
Index: libgo/runtime/malloc.goc
===================================================================
--- libgo/runtime/malloc.goc	(revision 240334)
+++ libgo/runtime/malloc.goc	(working copy)
@@ -99,7 +99,7 @@  runtime_mallocgc(uintptr size, uintptr t
 		// 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 t
 					m->mallocing = 0;
 					m->locks--;
 					if(incallback)
-						runtime_entersyscall();
+						runtime_entersyscall(0);
 					return v;
 				}
 			}
@@ -256,7 +256,7 @@  runtime_mallocgc(uintptr size, uintptr t
 		runtime_gc(0);
 
 	if(incallback)
-		runtime_entersyscall();
+		runtime_entersyscall(0);
 
 	return v;
 }
Index: libgo/runtime/proc.c
===================================================================
--- libgo/runtime/proc.c	(revision 240334)
+++ libgo/runtime/proc.c	(working copy)
@@ -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
 	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)
 {
Index: libgo/runtime/runtime.c
===================================================================
--- libgo/runtime/runtime.c	(revision 240609)
+++ libgo/runtime/runtime.c	(working copy)
@@ -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;
+}
Index: libgo/runtime/runtime.h
===================================================================
--- libgo/runtime/runtime.h	(revision 240609)
+++ libgo/runtime/runtime.h	(working copy)
@@ -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 cha
 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*
 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);
Index: libgo/runtime/thread-linux.c
===================================================================
--- libgo/runtime/thread-linux.c	(revision 240053)
+++ libgo/runtime/thread-linux.c	(working copy)
@@ -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)
 {
Index: libgo/runtime/thread-sema.c
===================================================================
--- libgo/runtime/thread-sema.c	(revision 240053)
+++ libgo/runtime/thread-sema.c	(working copy)
@@ -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)
 {
Index: libgo/sysinfo.c
===================================================================
--- libgo/sysinfo.c	(revision 240560)
+++ libgo/sysinfo.c	(working copy)
@@ -152,6 +152,9 @@ 
 #if defined(HAVE_SCHED_H)
 #include <sched.h>
 #endif
+#if defined(HAVE_SEMAPHORE_H)
+#include <semaphore.h>
+#endif
 
 /* Constants that may only be defined as expressions on some systems,
    expressions too complex for -fdump-go-spec to handle.  These are