diff options
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r-- | src/pkg/runtime/386/arch.h | 3 | ||||
-rw-r--r-- | src/pkg/runtime/Makefile | 172 | ||||
-rw-r--r-- | src/pkg/runtime/alg.c | 484 | ||||
-rw-r--r-- | src/pkg/runtime/amd64/arch.h | 3 | ||||
-rw-r--r-- | src/pkg/runtime/arch_386.h | 4 | ||||
-rw-r--r-- | src/pkg/runtime/arch_amd64.h | 4 | ||||
-rw-r--r-- | src/pkg/runtime/arch_arm.h | 4 | ||||
-rw-r--r-- | src/pkg/runtime/arm/arch.h | 3 | ||||
-rw-r--r-- | src/pkg/runtime/asm_386.s (renamed from src/pkg/runtime/386/asm.s) | 31 | ||||
-rw-r--r-- | src/pkg/runtime/asm_amd64.s (renamed from src/pkg/runtime/amd64/asm.s) | 28 | ||||
-rw-r--r-- | src/pkg/runtime/asm_arm.s (renamed from src/pkg/runtime/arm/asm.s) | 21 | ||||
-rw-r--r-- | src/pkg/runtime/atomic_386.c (renamed from src/pkg/runtime/386/atomic.c) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/atomic_amd64.c (renamed from src/pkg/runtime/amd64/atomic.c) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/atomic_arm.c (renamed from src/pkg/runtime/arm/atomic.c) | 0 | ||||
-rwxr-xr-x | src/pkg/runtime/autogen.sh | 82 | ||||
-rw-r--r-- | src/pkg/runtime/callback_windows_386.c (renamed from src/pkg/runtime/windows/386/callback.c) | 4 | ||||
-rw-r--r-- | src/pkg/runtime/callback_windows_amd64.c (renamed from src/pkg/runtime/windows/amd64/callback.c) | 6 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/Makefile | 14 | ||||
-rw-r--r--[-rwxr-xr-x] | src/pkg/runtime/cgo/gcc_386.S (renamed from src/pkg/runtime/cgo/386.S) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/gcc_amd64.S (renamed from src/pkg/runtime/cgo/amd64.S) | 2 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/gcc_arm.S (renamed from src/pkg/runtime/cgo/arm.S) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/gcc_darwin_386.c (renamed from src/pkg/runtime/cgo/darwin_386.c) | 17 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/gcc_darwin_amd64.c (renamed from src/pkg/runtime/cgo/darwin_amd64.c) | 17 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/gcc_freebsd_386.c (renamed from src/pkg/runtime/cgo/freebsd_386.c) | 11 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/gcc_freebsd_amd64.c (renamed from src/pkg/runtime/cgo/freebsd_amd64.c) | 11 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/gcc_linux_386.c (renamed from src/pkg/runtime/cgo/linux_386.c) | 11 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/gcc_linux_amd64.c (renamed from src/pkg/runtime/cgo/linux_amd64.c) | 12 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/gcc_linux_arm.c (renamed from src/pkg/runtime/cgo/linux_arm.c) | 5 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/gcc_setenv.c (renamed from src/pkg/runtime/cgo/setenv.c) | 2 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/gcc_util.c (renamed from src/pkg/runtime/cgo/util.c) | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/pkg/runtime/cgo/gcc_windows_386.c (renamed from src/pkg/runtime/cgo/windows_386.c) | 25 | ||||
-rw-r--r--[-rwxr-xr-x] | src/pkg/runtime/cgo/gcc_windows_amd64.c (renamed from src/pkg/runtime/cgo/windows_amd64.c) | 25 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/libcgo.h | 2 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/trigger.go | 20 | ||||
-rw-r--r-- | src/pkg/runtime/cgocall.c | 6 | ||||
-rw-r--r-- | src/pkg/runtime/chan.c | 25 | ||||
-rw-r--r-- | src/pkg/runtime/chan_test.go | 9 | ||||
-rw-r--r-- | src/pkg/runtime/closure_386.c (renamed from src/pkg/runtime/386/closure.c) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/closure_amd64.c (renamed from src/pkg/runtime/amd64/closure.c) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/closure_arm.c (renamed from src/pkg/runtime/arm/closure.c) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/cpuprof.c | 1 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/386/defs.h | 289 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/amd64/defs.h | 305 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/defs.c | 159 | ||||
-rw-r--r-- | src/pkg/runtime/debug.go | 5 | ||||
-rw-r--r-- | src/pkg/runtime/defs1_linux.go | 37 | ||||
-rw-r--r-- | src/pkg/runtime/defs2_linux.go | 126 | ||||
-rw-r--r-- | src/pkg/runtime/defs_arm_linux.go | 125 | ||||
-rw-r--r-- | src/pkg/runtime/defs_darwin.go | 163 | ||||
-rw-r--r-- | src/pkg/runtime/defs_darwin_386.h | 366 | ||||
-rw-r--r-- | src/pkg/runtime/defs_darwin_amd64.h | 369 | ||||
-rw-r--r-- | src/pkg/runtime/defs_freebsd.go | 117 | ||||
-rw-r--r-- | src/pkg/runtime/defs_freebsd_386.h (renamed from src/pkg/runtime/freebsd/386/defs.h) | 6 | ||||
-rw-r--r-- | src/pkg/runtime/defs_freebsd_amd64.h (renamed from src/pkg/runtime/freebsd/amd64/defs.h) | 6 | ||||
-rw-r--r-- | src/pkg/runtime/defs_linux.go | 104 | ||||
-rw-r--r-- | src/pkg/runtime/defs_linux_386.h | 191 | ||||
-rw-r--r-- | src/pkg/runtime/defs_linux_amd64.h | 234 | ||||
-rw-r--r-- | src/pkg/runtime/defs_linux_arm.h (renamed from src/pkg/runtime/linux/arm/defs.h) | 1 | ||||
-rw-r--r-- | src/pkg/runtime/defs_netbsd.go | 111 | ||||
-rw-r--r-- | src/pkg/runtime/defs_netbsd_386.h (renamed from src/pkg/runtime/openbsd/386/defs.h) | 6 | ||||
-rw-r--r-- | src/pkg/runtime/defs_netbsd_amd64.h (renamed from src/pkg/runtime/openbsd/amd64/defs.h) | 9 | ||||
-rw-r--r-- | src/pkg/runtime/defs_openbsd.go | 111 | ||||
-rw-r--r-- | src/pkg/runtime/defs_openbsd_386.h | 146 | ||||
-rw-r--r-- | src/pkg/runtime/defs_openbsd_amd64.h | 158 | ||||
-rw-r--r-- | src/pkg/runtime/defs_plan9_386.h (renamed from src/pkg/runtime/plan9/386/defs.h) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/defs_windows.go | 66 | ||||
-rw-r--r-- | src/pkg/runtime/defs_windows_386.h (renamed from src/pkg/runtime/windows/386/defs.h) | 14 | ||||
-rw-r--r-- | src/pkg/runtime/defs_windows_amd64.h (renamed from src/pkg/runtime/windows/amd64/defs.h) | 14 | ||||
-rw-r--r-- | src/pkg/runtime/error.go | 10 | ||||
-rw-r--r-- | src/pkg/runtime/export_test.go | 2 | ||||
-rw-r--r-- | src/pkg/runtime/extern.go | 60 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/defs.c | 108 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/os.h | 12 | ||||
-rw-r--r-- | src/pkg/runtime/gc_test.go | 36 | ||||
-rw-r--r-- | src/pkg/runtime/goc2c.c | 3 | ||||
-rw-r--r-- | src/pkg/runtime/hashmap.c | 422 | ||||
-rw-r--r-- | src/pkg/runtime/hashmap.h | 7 | ||||
-rw-r--r-- | src/pkg/runtime/iface.c | 64 | ||||
-rw-r--r-- | src/pkg/runtime/linux/386/defs.h | 191 | ||||
-rw-r--r-- | src/pkg/runtime/linux/amd64/defs.h | 236 | ||||
-rw-r--r-- | src/pkg/runtime/linux/defs.c | 95 | ||||
-rw-r--r-- | src/pkg/runtime/linux/defs1.c | 24 | ||||
-rw-r--r-- | src/pkg/runtime/linux/defs2.c | 120 | ||||
-rw-r--r-- | src/pkg/runtime/linux/defs_arm.c | 122 | ||||
-rw-r--r-- | src/pkg/runtime/lock_futex.c | 148 | ||||
-rw-r--r-- | src/pkg/runtime/lock_sema.c | 219 | ||||
-rw-r--r-- | src/pkg/runtime/malloc.goc | 50 | ||||
-rw-r--r-- | src/pkg/runtime/malloc.h | 38 | ||||
-rw-r--r-- | src/pkg/runtime/mcache.c | 1 | ||||
-rw-r--r-- | src/pkg/runtime/mcentral.c | 1 | ||||
-rw-r--r-- | src/pkg/runtime/mem_darwin.c (renamed from src/pkg/runtime/darwin/mem.c) | 14 | ||||
-rw-r--r-- | src/pkg/runtime/mem_freebsd.c (renamed from src/pkg/runtime/freebsd/mem.c) | 9 | ||||
-rw-r--r-- | src/pkg/runtime/mem_linux.c (renamed from src/pkg/runtime/linux/mem.c) | 13 | ||||
-rw-r--r-- | src/pkg/runtime/mem_netbsd.c (renamed from src/pkg/runtime/openbsd/mem.c) | 9 | ||||
-rw-r--r-- | src/pkg/runtime/mem_openbsd.c | 85 | ||||
-rw-r--r-- | src/pkg/runtime/mem_plan9.c (renamed from src/pkg/runtime/plan9/mem.c) | 5 | ||||
-rw-r--r-- | src/pkg/runtime/mem_windows.c (renamed from src/pkg/runtime/windows/mem.c) | 5 | ||||
-rw-r--r-- | src/pkg/runtime/memmove_386.s (renamed from src/pkg/runtime/386/memmove.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/memmove_amd64.s (renamed from src/pkg/runtime/amd64/memmove.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/memmove_arm.s (renamed from src/pkg/runtime/arm/memmove.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/memset_arm.s (renamed from src/pkg/runtime/arm/memset.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/mfinal.c | 193 | ||||
-rw-r--r-- | src/pkg/runtime/mfinal_test.go | 64 | ||||
-rw-r--r-- | src/pkg/runtime/mfixalloc.c | 1 | ||||
-rw-r--r-- | src/pkg/runtime/mgc0.c | 689 | ||||
-rw-r--r-- | src/pkg/runtime/mheap.c | 1 | ||||
-rwxr-xr-x | src/pkg/runtime/mkasmh.sh | 41 | ||||
-rwxr-xr-x | src/pkg/runtime/mkgodefs.sh | 33 | ||||
-rw-r--r-- | src/pkg/runtime/mkversion.c | 8 | ||||
-rw-r--r-- | src/pkg/runtime/mprof.goc | 3 | ||||
-rw-r--r-- | src/pkg/runtime/msize.c | 1 | ||||
-rw-r--r-- | src/pkg/runtime/openbsd/defs.c | 103 | ||||
-rw-r--r-- | src/pkg/runtime/openbsd/thread.c | 156 | ||||
-rw-r--r-- | src/pkg/runtime/os_darwin.h (renamed from src/pkg/runtime/darwin/os.h) | 3 | ||||
-rw-r--r-- | src/pkg/runtime/os_freebsd.h | 13 | ||||
-rw-r--r-- | src/pkg/runtime/os_linux.h (renamed from src/pkg/runtime/linux/os.h) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/os_netbsd.h (renamed from src/pkg/runtime/openbsd/os.h) | 5 | ||||
-rw-r--r-- | src/pkg/runtime/os_openbsd.h | 17 | ||||
-rw-r--r-- | src/pkg/runtime/os_plan9.h (renamed from src/pkg/runtime/plan9/os.h) | 29 | ||||
-rw-r--r-- | src/pkg/runtime/os_windows.h (renamed from src/pkg/runtime/windows/os.h) | 2 | ||||
-rw-r--r-- | src/pkg/runtime/plan9/thread.c | 174 | ||||
-rw-r--r-- | src/pkg/runtime/pprof/pprof.go | 8 | ||||
-rw-r--r-- | src/pkg/runtime/print.c | 6 | ||||
-rw-r--r-- | src/pkg/runtime/proc.c | 332 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_darwin_386.s (renamed from src/pkg/runtime/darwin/386/rt0.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_darwin_amd64.s (renamed from src/pkg/runtime/darwin/amd64/rt0.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_freebsd_386.s (renamed from src/pkg/runtime/freebsd/386/rt0.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_freebsd_amd64.s (renamed from src/pkg/runtime/freebsd/amd64/rt0.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_linux_386.s (renamed from src/pkg/runtime/linux/386/rt0.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_linux_amd64.s (renamed from src/pkg/runtime/linux/amd64/rt0.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_linux_arm.s (renamed from src/pkg/runtime/linux/arm/rt0.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_netbsd_386.s | 6 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_netbsd_amd64.s | 8 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_openbsd_386.s (renamed from src/pkg/runtime/openbsd/386/rt0.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_openbsd_amd64.s (renamed from src/pkg/runtime/openbsd/amd64/rt0.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_plan9_386.s (renamed from src/pkg/runtime/plan9/386/rt0.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_windows_386.s (renamed from src/pkg/runtime/windows/386/rt0.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/rt0_windows_amd64.s (renamed from src/pkg/runtime/windows/amd64/rt0.s) | 2 | ||||
-rw-r--r-- | src/pkg/runtime/runtime-gdb.py | 39 | ||||
-rw-r--r-- | src/pkg/runtime/runtime.c | 384 | ||||
-rw-r--r-- | src/pkg/runtime/runtime.h | 184 | ||||
-rw-r--r-- | src/pkg/runtime/runtime1.goc | 4 | ||||
-rw-r--r-- | src/pkg/runtime/sema.goc | 7 | ||||
-rw-r--r-- | src/pkg/runtime/signal_darwin_386.c (renamed from src/pkg/runtime/darwin/386/signal.c) | 16 | ||||
-rw-r--r-- | src/pkg/runtime/signal_darwin_amd64.c (renamed from src/pkg/runtime/darwin/amd64/signal.c) | 16 | ||||
-rw-r--r-- | src/pkg/runtime/signal_freebsd_386.c (renamed from src/pkg/runtime/freebsd/386/signal.c) | 6 | ||||
-rw-r--r-- | src/pkg/runtime/signal_freebsd_amd64.c (renamed from src/pkg/runtime/freebsd/amd64/signal.c) | 6 | ||||
-rw-r--r-- | src/pkg/runtime/signal_linux_386.c (renamed from src/pkg/runtime/linux/386/signal.c) | 6 | ||||
-rw-r--r-- | src/pkg/runtime/signal_linux_amd64.c (renamed from src/pkg/runtime/linux/amd64/signal.c) | 6 | ||||
-rw-r--r-- | src/pkg/runtime/signal_linux_arm.c (renamed from src/pkg/runtime/linux/arm/signal.c) | 6 | ||||
-rw-r--r-- | src/pkg/runtime/signal_netbsd_386.c (renamed from src/pkg/runtime/openbsd/386/signal.c) | 6 | ||||
-rw-r--r-- | src/pkg/runtime/signal_netbsd_amd64.c (renamed from src/pkg/runtime/openbsd/amd64/signal.c) | 6 | ||||
-rw-r--r-- | src/pkg/runtime/signal_openbsd_386.c | 189 | ||||
-rw-r--r-- | src/pkg/runtime/signal_openbsd_amd64.c | 199 | ||||
-rw-r--r-- | src/pkg/runtime/signal_plan9_386.c (renamed from src/pkg/runtime/plan9/386/signal.c) | 5 | ||||
-rw-r--r-- | src/pkg/runtime/signal_windows_386.c (renamed from src/pkg/runtime/windows/386/signal.c) | 11 | ||||
-rw-r--r-- | src/pkg/runtime/signal_windows_amd64.c (renamed from src/pkg/runtime/windows/amd64/signal.c) | 4 | ||||
-rw-r--r-- | src/pkg/runtime/signals_darwin.h (renamed from src/pkg/runtime/darwin/signals.h) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/signals_freebsd.h (renamed from src/pkg/runtime/freebsd/signals.h) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/signals_linux.h (renamed from src/pkg/runtime/linux/signals.h) | 2 | ||||
-rw-r--r-- | src/pkg/runtime/signals_netbsd.h (renamed from src/pkg/runtime/openbsd/signals.h) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/signals_openbsd.h | 52 | ||||
-rw-r--r-- | src/pkg/runtime/signals_plan9.h (renamed from src/pkg/runtime/plan9/signals.h) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/signals_windows.h (renamed from src/pkg/runtime/windows/signals.h) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/sigqueue.goc | 2 | ||||
-rw-r--r-- | src/pkg/runtime/slice.c | 65 | ||||
-rw-r--r-- | src/pkg/runtime/softfloat64_test.go | 2 | ||||
-rw-r--r-- | src/pkg/runtime/softfloat_arm.c (renamed from src/pkg/runtime/arm/softfloat.c) | 4 | ||||
-rw-r--r-- | src/pkg/runtime/stack.h | 2 | ||||
-rw-r--r-- | src/pkg/runtime/string.goc | 56 | ||||
-rw-r--r-- | src/pkg/runtime/symtab.c | 15 | ||||
-rw-r--r-- | src/pkg/runtime/sys_darwin_386.s (renamed from src/pkg/runtime/darwin/386/sys.s) | 81 | ||||
-rw-r--r-- | src/pkg/runtime/sys_darwin_amd64.s (renamed from src/pkg/runtime/darwin/amd64/sys.s) | 82 | ||||
-rw-r--r-- | src/pkg/runtime/sys_freebsd_386.s (renamed from src/pkg/runtime/freebsd/386/sys.s) | 82 | ||||
-rw-r--r-- | src/pkg/runtime/sys_freebsd_amd64.s (renamed from src/pkg/runtime/freebsd/amd64/sys.s) | 65 | ||||
-rw-r--r-- | src/pkg/runtime/sys_linux_386.s (renamed from src/pkg/runtime/linux/386/sys.s) | 81 | ||||
-rw-r--r-- | src/pkg/runtime/sys_linux_amd64.s (renamed from src/pkg/runtime/linux/amd64/sys.s) | 64 | ||||
-rw-r--r-- | src/pkg/runtime/sys_linux_arm.s (renamed from src/pkg/runtime/linux/arm/sys.s) | 91 | ||||
-rw-r--r-- | src/pkg/runtime/sys_netbsd_386.s | 324 | ||||
-rw-r--r-- | src/pkg/runtime/sys_netbsd_amd64.s | 268 | ||||
-rw-r--r-- | src/pkg/runtime/sys_openbsd_386.s (renamed from src/pkg/runtime/openbsd/386/sys.s) | 86 | ||||
-rw-r--r-- | src/pkg/runtime/sys_openbsd_amd64.s (renamed from src/pkg/runtime/openbsd/amd64/sys.s) | 83 | ||||
-rw-r--r-- | src/pkg/runtime/sys_plan9_386.s (renamed from src/pkg/runtime/plan9/386/sys.s) | 27 | ||||
-rw-r--r-- | src/pkg/runtime/sys_windows_386.s (renamed from src/pkg/runtime/windows/386/sys.s) | 64 | ||||
-rw-r--r-- | src/pkg/runtime/sys_windows_amd64.s (renamed from src/pkg/runtime/windows/amd64/sys.s) | 16 | ||||
-rw-r--r-- | src/pkg/runtime/syscall_windows.goc (renamed from src/pkg/runtime/windows/syscall.goc) | 47 | ||||
-rw-r--r-- | src/pkg/runtime/syscall_windows_test.go | 195 | ||||
-rw-r--r-- | src/pkg/runtime/thread_darwin.c (renamed from src/pkg/runtime/darwin/thread.c) | 172 | ||||
-rw-r--r-- | src/pkg/runtime/thread_freebsd.c (renamed from src/pkg/runtime/freebsd/thread.c) | 153 | ||||
-rw-r--r-- | src/pkg/runtime/thread_linux.c (renamed from src/pkg/runtime/linux/thread.c) | 170 | ||||
-rw-r--r-- | src/pkg/runtime/thread_netbsd.c | 203 | ||||
-rw-r--r-- | src/pkg/runtime/thread_openbsd.c | 203 | ||||
-rw-r--r-- | src/pkg/runtime/thread_plan9.c | 237 | ||||
-rw-r--r-- | src/pkg/runtime/thread_windows.c (renamed from src/pkg/runtime/windows/thread.c) | 183 | ||||
-rw-r--r-- | src/pkg/runtime/time.goc | 253 | ||||
-rw-r--r-- | src/pkg/runtime/traceback_arm.c (renamed from src/pkg/runtime/arm/traceback.c) | 1 | ||||
-rw-r--r-- | src/pkg/runtime/traceback_x86.c (renamed from src/pkg/runtime/amd64/traceback.c) | 3 | ||||
-rw-r--r-- | src/pkg/runtime/type.go | 19 | ||||
-rw-r--r-- | src/pkg/runtime/type.h | 3 | ||||
-rw-r--r-- | src/pkg/runtime/vlop_386.s (renamed from src/pkg/runtime/386/vlop.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/vlop_arm.s (renamed from src/pkg/runtime/arm/vlop.s) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/vlrt_386.c (renamed from src/pkg/runtime/386/vlrt.c) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/vlrt_arm.c (renamed from src/pkg/runtime/arm/vlrt.c) | 0 | ||||
-rw-r--r-- | src/pkg/runtime/windows/defs.c | 48 |
204 files changed, 8555 insertions, 4358 deletions
diff --git a/src/pkg/runtime/386/arch.h b/src/pkg/runtime/386/arch.h deleted file mode 100644 index d95c7aa81..000000000 --- a/src/pkg/runtime/386/arch.h +++ /dev/null @@ -1,3 +0,0 @@ -enum { - thechar = '8' -}; diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile index 725c2b07e..50d0515e2 100644 --- a/src/pkg/runtime/Makefile +++ b/src/pkg/runtime/Makefile @@ -6,15 +6,6 @@ include ../../Make.inc TARG=runtime -# Set SIZE to 32 or 64. -SIZE_386=32 -SIZE_amd64=64 -SIZE_arm=32 -SIZE=$(SIZE_$(GOARCH)) - -CFLAGS_windows=-D__WINDOWS__ -CFLAGS=-I$(GOOS) -I$(GOARCH) -I$(GOOS)/$(GOARCH) -FVw $(CFLAGS_$(GOARCH)) $(CFLAGS_$(GOOS)) - GOFILES=\ debug.go\ error.go\ @@ -23,68 +14,99 @@ GOFILES=\ sig.go\ softfloat64.go\ type.go\ - version.go\ - version_$(GOOS).go\ - version_$(GOARCH).go\ - runtime_defs.go\ + zgoarch_$(GOARCH).go\ + zgoos_$(GOOS).go\ + zruntime_defs_$(GOOS)_$(GOARCH).go\ + zversion.go\ + +OFILES_darwin=\ + lock_sema.$O\ + +OFILES_freebsd=\ + lock_futex.$O\ + +OFILES_linux=\ + lock_futex.$O\ + +OFILES_netbsd=\ + lock_sema.$O\ + +OFILES_openbsd=\ + lock_sema.$O\ -CLEANFILES+=version.go version_*.go +OFILES_plan9=\ + lock_sema.$O\ OFILES_windows=\ - callback.$O\ - syscall.$O\ + callback_windows_$(GOARCH).$O\ + lock_sema.$O\ + zsyscall_windows_$(GOARCH).$O\ # 386-specific object files OFILES_386=\ - vlop.$O\ - vlrt.$O\ + vlop_386.$O\ + vlrt_386.$O\ + traceback_x86.$O\ + +# amd64-specific object files +OFILES_amd64=\ + traceback_x86.$O\ # arm-specific object files OFILES_arm=\ - memset.$O\ - softfloat.$O\ - vlop.$O\ - vlrt.$O\ + memset_arm.$O\ + softfloat_arm.$O\ + vlop_arm.$O\ + vlrt_arm.$O\ + traceback_arm.$O\ OFILES=\ - asm.$O\ - atomic.$O\ + $(OFILES_$(GOARCH))\ + $(OFILES_$(GOOS))\ + alg.$O\ + asm_$(GOARCH).$O\ + atomic_$(GOARCH).$O\ cgocall.$O\ chan.$O\ - closure.$O\ + closure_$(GOARCH).$O\ + complex.$O\ cpuprof.$O\ float.$O\ - complex.$O\ hashmap.$O\ iface.$O\ - malloc.$O\ mcache.$O\ mcentral.$O\ - mem.$O\ - memmove.$O\ + mem_$(GOOS).$O\ + memmove_$(GOARCH).$O\ mfinal.$O\ mfixalloc.$O\ mgc0.$O\ mheap.$O\ - mprof.$O\ msize.$O\ print.$O\ proc.$O\ + rt0_$(GOOS)_$(GOARCH).$O\ rune.$O\ runtime.$O\ - runtime1.$O\ - rt0.$O\ - sema.$O\ - signal.$O\ - sigqueue.$O\ + signal_$(GOOS)_$(GOARCH).$O\ slice.$O\ - string.$O\ symtab.$O\ - sys.$O\ - thread.$O\ - traceback.$O\ - $(OFILES_$(GOARCH))\ - $(OFILES_$(GOOS))\ + sys_$(GOOS)_$(GOARCH).$O\ + thread_$(GOOS).$O\ + zmalloc_$(GOARCH).$O\ + zmprof_$(GOARCH).$O\ + zruntime1_$(GOARCH).$O\ + zsema_$(GOARCH).$O\ + zsigqueue_$(GOARCH).$O\ + zstring_$(GOARCH).$O\ + ztime_$(GOARCH).$O\ + +AUTOHFILES=\ + arch_GOARCH.h\ + os_GOOS.h\ + signals_GOOS.h\ + defs_GOOS_GOARCH.h\ + zasm_GOOS_GOARCH.h\ HFILES=\ cgocall.h\ @@ -92,16 +114,17 @@ HFILES=\ hashmap.h\ malloc.h\ stack.h\ - $(GOARCH)/asm.h\ - $(GOOS)/os.h\ - $(GOOS)/signals.h\ - $(GOOS)/$(GOARCH)/defs.h\ + $(AUTOHFILES)\ GOFILES+=$(GOFILES_$(GOOS)) # For use by cgo. INSTALLFILES=$(pkgdir)/runtime.h $(pkgdir)/cgocall.h +# Go tool will do this for package runtime. +AFLAGS+=-DGOOS_$(GOOS) -DGOARCH_$(GOARCH) +CFLAGS+=-DGOOS_$(GOOS) -DGOARCH_$(GOARCH) + # special, out of the way compiler flag that means "add runtime metadata to output" GC+= -+ @@ -114,56 +137,19 @@ $(pkgdir)/%.h: %.h clean: clean-local clean-local: - rm -f goc2c mkversion version.go */asm.h runtime.acid.* runtime_defs.go $$(ls *.goc | sed 's/goc$$/c/') - -$(GOARCH)/asm.h: mkasmh.sh runtime.acid.$(GOARCH) - ./mkasmh.sh >$@.x - mv -f $@.x $@ - -goc2c: goc2c.c - quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a" - -mkversion: mkversion.c - quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a" - -version.go: mkversion - GOROOT="$(GOROOT_FINAL)" ./mkversion >version.go - -version_$(GOARCH).go: - (echo 'package runtime'; echo 'const theGoarch = "$(GOARCH)"') >$@ - -version_$(GOOS).go: - (echo 'package runtime'; echo 'const theGoos = "$(GOOS)"') >$@ - -%.c: %.goc goc2c - ./goc2c "`pwd`/$<" > $@.tmp - mv -f $@.tmp $@ - -%.$O: $(GOARCH)/%.c $(HFILES) - $(CC) $(CFLAGS) $< - -%.$O: $(GOOS)/%.c $(HFILES) - $(CC) $(CFLAGS) $< - -%.$O: $(GOOS)/$(GOARCH)/%.c $(HFILES) - $(CC) $(CFLAGS) $< + rm -f $(AUTOHFILES) runtime_defs.go version*.go asm_*.h -%.$O: $(GOARCH)/%.s $(GOARCH)/asm.h - $(AS) $< +arch_GOARCH.h: arch_$(GOARCH).h + cp $^ $@ -%.$O: $(GOOS)/$(GOARCH)/%.s $(GOARCH)/asm.h - $(AS) $< +defs_GOOS_GOARCH.h: defs_$(GOOS)_$(GOARCH).h + cp $^ $@ -# for discovering offsets inside structs when debugging -runtime.acid.$(GOARCH): runtime.h proc.c - $(CC) $(CFLAGS) -a proc.c >$@ +os_GOOS.h: os_$(GOOS).h + cp $^ $@ -# 386 traceback is really amd64 traceback -ifeq ($(GOARCH),386) -traceback.$O: amd64/traceback.c - $(CC) $(CFLAGS) $< -endif +signals_GOOS.h: signals_$(GOOS).h + cp $^ $@ -runtime_defs.go: proc.c iface.c hashmap.c chan.c - CC="$(CC)" CFLAGS="$(CFLAGS)" ./mkgodefs.sh $^ > $@.x - mv -f $@.x $@ +zasm_GOOS_GOARCH.h: zasm_$(GOOS)_$(GOARCH).h + cp $^ $@ diff --git a/src/pkg/runtime/alg.c b/src/pkg/runtime/alg.c new file mode 100644 index 000000000..56ec2d69e --- /dev/null +++ b/src/pkg/runtime/alg.c @@ -0,0 +1,484 @@ +// 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. + +#include "runtime.h" +#include "type.h" + +/* + * map and chan helpers for + * dealing with unknown types + */ +void +runtime·memhash(uintptr *h, uintptr s, void *a) +{ + byte *b; + uintptr hash; + + b = a; + if(sizeof(hash) == 4) + hash = 2860486313U; + else + hash = 33054211828000289ULL; + while(s > 0) { + if(sizeof(hash) == 4) + hash = (hash ^ *b) * 3267000013UL; + else + hash = (hash ^ *b) * 23344194077549503ULL; + b++; + s--; + } + *h ^= hash; +} + +void +runtime·memequal(bool *eq, uintptr s, void *a, void *b) +{ + byte *ba, *bb, *aend; + + if(a == b) { + *eq = 1; + return; + } + ba = a; + bb = b; + aend = ba+s; + while(ba != aend) { + if(*ba != *bb) { + *eq = 0; + return; + } + ba++; + bb++; + } + *eq = 1; + return; +} + +void +runtime·memprint(uintptr s, void *a) +{ + uint64 v; + + v = 0xbadb00b; + switch(s) { + case 1: + v = *(uint8*)a; + break; + case 2: + v = *(uint16*)a; + break; + case 4: + v = *(uint32*)a; + break; + case 8: + v = *(uint64*)a; + break; + } + runtime·printint(v); +} + +void +runtime·memcopy(uintptr s, void *a, void *b) +{ + if(b == nil) { + runtime·memclr(a, s); + return; + } + runtime·memmove(a, b, s); +} + +void +runtime·memequal0(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + USED(a); + USED(b); + *eq = true; +} + +void +runtime·memcopy0(uintptr s, void *a, void *b) +{ + USED(s); + USED(a); + USED(b); +} + +void +runtime·memequal8(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + *eq = *(uint8*)a == *(uint8*)b; +} + +void +runtime·memcopy8(uintptr s, void *a, void *b) +{ + USED(s); + if(b == nil) { + *(uint8*)a = 0; + return; + } + *(uint8*)a = *(uint8*)b; +} + +void +runtime·memequal16(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + *eq = *(uint16*)a == *(uint16*)b; +} + +void +runtime·memcopy16(uintptr s, void *a, void *b) +{ + USED(s); + if(b == nil) { + *(uint16*)a = 0; + return; + } + *(uint16*)a = *(uint16*)b; +} + +void +runtime·memequal32(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + *eq = *(uint32*)a == *(uint32*)b; +} + +void +runtime·memcopy32(uintptr s, void *a, void *b) +{ + USED(s); + if(b == nil) { + *(uint32*)a = 0; + return; + } + *(uint32*)a = *(uint32*)b; +} + +void +runtime·memequal64(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + *eq = *(uint64*)a == *(uint64*)b; +} + +void +runtime·memcopy64(uintptr s, void *a, void *b) +{ + USED(s); + if(b == nil) { + *(uint64*)a = 0; + return; + } + *(uint64*)a = *(uint64*)b; +} + +void +runtime·memequal128(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + *eq = ((uint64*)a)[0] == ((uint64*)b)[0] && ((uint64*)a)[1] == ((uint64*)b)[1]; +} + +void +runtime·memcopy128(uintptr s, void *a, void *b) +{ + USED(s); + if(b == nil) { + ((uint64*)a)[0] = 0; + ((uint64*)a)[1] = 0; + return; + } + ((uint64*)a)[0] = ((uint64*)b)[0]; + ((uint64*)a)[1] = ((uint64*)b)[1]; +} + +void +runtime·f32equal(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + *eq = *(float32*)a == *(float32*)b; +} + +void +runtime·f64equal(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + *eq = *(float64*)a == *(float64*)b; +} + +void +runtime·c64equal(bool *eq, uintptr s, void *a, void *b) +{ + Complex64 *ca, *cb; + + USED(s); + ca = a; + cb = b; + *eq = ca->real == cb->real && ca->imag == cb->imag; +} + +void +runtime·c128equal(bool *eq, uintptr s, void *a, void *b) +{ + Complex128 *ca, *cb; + + USED(s); + ca = a; + cb = b; + *eq = ca->real == cb->real && ca->imag == cb->imag; +} + +// NOTE: Because NaN != NaN, a map can contain any +// number of (mostly useless) entries keyed with NaNs. +// To avoid long hash chains, we assign a random number +// as the hash value for a NaN. + +void +runtime·f32hash(uintptr *h, uintptr s, void *a) +{ + uintptr hash; + float32 f; + + USED(s); + f = *(float32*)a; + if(f == 0) + hash = 0; // +0, -0 + else if(f != f) + hash = runtime·fastrand1(); // any kind of NaN + else + hash = *(uint32*)a; + *h ^= (*h ^ hash ^ 2860486313U) * 3267000013U; +} + +void +runtime·f64hash(uintptr *h, uintptr s, void *a) +{ + uintptr hash; + float64 f; + uint64 u; + + USED(s); + f = *(float32*)a; + if(f == 0) + hash = 0; // +0, -0 + else if(f != f) + hash = runtime·fastrand1(); // any kind of NaN + else { + u = *(uint64*)a; + if(sizeof(uintptr) == 4) + hash = ((uint32)(u>>32) ^ 2860486313) * (uint32)u; + else + hash = u; + } + if(sizeof(uintptr) == 4) + *h = (*h ^ hash ^ 2860486313U) * 3267000013U; + else + *h = (*h ^ hash ^ 33054211828000289ULL) * 23344194077549503ULL; +} + +void +runtime·c64hash(uintptr *h, uintptr s, void *a) +{ + USED(s); + runtime·f32hash(h, 0, a); + runtime·f32hash(h, 0, (float32*)a+1); +} + +void +runtime·c128hash(uintptr *h, uintptr s, void *a) +{ + USED(s); + runtime·f64hash(h, 0, a); + runtime·f64hash(h, 0, (float64*)a+1); +} + +void +runtime·slicecopy(uintptr s, void *a, void *b) +{ + USED(s); + if(b == nil) { + ((Slice*)a)->array = 0; + ((Slice*)a)->len = 0; + ((Slice*)a)->cap = 0; + return; + } + ((Slice*)a)->array = ((Slice*)b)->array; + ((Slice*)a)->len = ((Slice*)b)->len; + ((Slice*)a)->cap = ((Slice*)b)->cap; +} + +void +runtime·strhash(uintptr *h, uintptr s, void *a) +{ + USED(s); + runtime·memhash(h, ((String*)a)->len, ((String*)a)->str); +} + +void +runtime·strequal(bool *eq, uintptr s, void *a, void *b) +{ + int32 alen; + + USED(s); + alen = ((String*)a)->len; + if(alen != ((String*)b)->len) { + *eq = false; + return; + } + runtime·memequal(eq, alen, ((String*)a)->str, ((String*)b)->str); +} + +void +runtime·strprint(uintptr s, void *a) +{ + USED(s); + runtime·printstring(*(String*)a); +} + +void +runtime·strcopy(uintptr s, void *a, void *b) +{ + USED(s); + if(b == nil) { + ((String*)a)->str = 0; + ((String*)a)->len = 0; + return; + } + ((String*)a)->str = ((String*)b)->str; + ((String*)a)->len = ((String*)b)->len; +} + +void +runtime·interhash(uintptr *h, uintptr s, void *a) +{ + USED(s); + *h ^= runtime·ifacehash(*(Iface*)a); +} + +void +runtime·interprint(uintptr s, void *a) +{ + USED(s); + runtime·printiface(*(Iface*)a); +} + +void +runtime·interequal(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + *eq = runtime·ifaceeq_c(*(Iface*)a, *(Iface*)b); +} + +void +runtime·intercopy(uintptr s, void *a, void *b) +{ + USED(s); + if(b == nil) { + ((Iface*)a)->tab = 0; + ((Iface*)a)->data = 0; + return; + } + ((Iface*)a)->tab = ((Iface*)b)->tab; + ((Iface*)a)->data = ((Iface*)b)->data; +} + +void +runtime·nilinterhash(uintptr *h, uintptr s, void *a) +{ + USED(s); + *h ^= runtime·efacehash(*(Eface*)a); +} + +void +runtime·nilinterprint(uintptr s, void *a) +{ + USED(s); + runtime·printeface(*(Eface*)a); +} + +void +runtime·nilinterequal(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + *eq = runtime·efaceeq_c(*(Eface*)a, *(Eface*)b); +} + +void +runtime·nilintercopy(uintptr s, void *a, void *b) +{ + USED(s); + if(b == nil) { + ((Eface*)a)->type = 0; + ((Eface*)a)->data = 0; + return; + } + ((Eface*)a)->type = ((Eface*)b)->type; + ((Eface*)a)->data = ((Eface*)b)->data; +} + +void +runtime·nohash(uintptr *h, uintptr s, void *a) +{ + USED(s); + USED(a); + USED(h); + runtime·panicstring("hash of unhashable type"); +} + +void +runtime·noequal(bool *eq, uintptr s, void *a, void *b) +{ + USED(s); + USED(a); + USED(b); + USED(eq); + runtime·panicstring("comparing uncomparable types"); +} + +Alg +runtime·algarray[] = +{ +[AMEM] { runtime·memhash, runtime·memequal, runtime·memprint, runtime·memcopy }, +[ANOEQ] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy }, +[ASTRING] { runtime·strhash, runtime·strequal, runtime·strprint, runtime·strcopy }, +[AINTER] { runtime·interhash, runtime·interequal, runtime·interprint, runtime·intercopy }, +[ANILINTER] { runtime·nilinterhash, runtime·nilinterequal, runtime·nilinterprint, runtime·nilintercopy }, +[ASLICE] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·slicecopy }, +[AFLOAT32] { runtime·f32hash, runtime·f32equal, runtime·memprint, runtime·memcopy }, +[AFLOAT64] { runtime·f64hash, runtime·f64equal, runtime·memprint, runtime·memcopy }, +[ACPLX64] { runtime·c64hash, runtime·c64equal, runtime·memprint, runtime·memcopy }, +[ACPLX128] { runtime·c128hash, runtime·c128equal, runtime·memprint, runtime·memcopy }, +[AMEM0] { runtime·memhash, runtime·memequal0, runtime·memprint, runtime·memcopy0 }, +[AMEM8] { runtime·memhash, runtime·memequal8, runtime·memprint, runtime·memcopy8 }, +[AMEM16] { runtime·memhash, runtime·memequal16, runtime·memprint, runtime·memcopy16 }, +[AMEM32] { runtime·memhash, runtime·memequal32, runtime·memprint, runtime·memcopy32 }, +[AMEM64] { runtime·memhash, runtime·memequal64, runtime·memprint, runtime·memcopy64 }, +[AMEM128] { runtime·memhash, runtime·memequal128, runtime·memprint, runtime·memcopy128 }, +[ANOEQ0] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy0 }, +[ANOEQ8] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy8 }, +[ANOEQ16] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy16 }, +[ANOEQ32] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy32 }, +[ANOEQ64] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy64 }, +[ANOEQ128] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy128 }, +}; + +// Runtime helpers. + +// func equal(t *Type, x T, y T) (ret bool) +#pragma textflag 7 +void +runtime·equal(Type *t, ...) +{ + byte *x, *y; + bool *ret; + + x = (byte*)(&t+1); + y = x + t->size; + ret = (bool*)(y + t->size); + t->alg->equal(ret, t->size, x, y); +} diff --git a/src/pkg/runtime/amd64/arch.h b/src/pkg/runtime/amd64/arch.h deleted file mode 100644 index fe10fd89f..000000000 --- a/src/pkg/runtime/amd64/arch.h +++ /dev/null @@ -1,3 +0,0 @@ -enum { - thechar = '6' -}; diff --git a/src/pkg/runtime/arch_386.h b/src/pkg/runtime/arch_386.h new file mode 100644 index 000000000..a0798f99e --- /dev/null +++ b/src/pkg/runtime/arch_386.h @@ -0,0 +1,4 @@ +enum { + thechar = '8', + CacheLineSize = 64 +}; diff --git a/src/pkg/runtime/arch_amd64.h b/src/pkg/runtime/arch_amd64.h new file mode 100644 index 000000000..dd1cfc18d --- /dev/null +++ b/src/pkg/runtime/arch_amd64.h @@ -0,0 +1,4 @@ +enum { + thechar = '6', + CacheLineSize = 64 +}; diff --git a/src/pkg/runtime/arch_arm.h b/src/pkg/runtime/arch_arm.h new file mode 100644 index 000000000..c1a7a0f37 --- /dev/null +++ b/src/pkg/runtime/arch_arm.h @@ -0,0 +1,4 @@ +enum { + thechar = '5', + CacheLineSize = 32 +}; diff --git a/src/pkg/runtime/arm/arch.h b/src/pkg/runtime/arm/arch.h deleted file mode 100644 index 3ddb626dd..000000000 --- a/src/pkg/runtime/arm/arch.h +++ /dev/null @@ -1,3 +0,0 @@ -enum { - thechar = '5' -}; diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/asm_386.s index c64e78f59..52400637b 100644 --- a/src/pkg/runtime/386/asm.s +++ b/src/pkg/runtime/asm_386.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "386/asm.h" +#include "zasm_GOOS_GOARCH.h" TEXT _rt0_386(SB),7,$0 // Linux, Windows start the FPU in extended double precision. @@ -21,17 +21,26 @@ TEXT _rt0_386(SB),7,$0 MOVL AX, 120(SP) // save argc, argv away MOVL BX, 124(SP) + // set default stack bounds. + // initcgo may update stackguard. + MOVL $runtime·g0(SB), BP + LEAL (-64*1024+104)(SP), BX + MOVL BX, g_stackguard(BP) + MOVL SP, g_stackbase(BP) + // if there is an initcgo, call it to let it // initialize and to set up GS. if not, // we set up GS ourselves. MOVL initcgo(SB), AX TESTL AX, AX - JZ 4(PC) + JZ needtls + PUSHL BP CALL AX + POPL BP // skip runtime·ldt0setup(SB) and tls test after initcgo for non-windows CMPL runtime·iswindows(SB), $0 JEQ ok - +needtls: // skip runtime·ldt0setup(SB) and tls test on Plan 9 in all cases CMPL runtime·isplan9(SB), $1 JEQ ok @@ -57,10 +66,6 @@ ok: // save m->g0 = g0 MOVL CX, m_g0(AX) - // create istack out of the OS stack - LEAL (-64*1024+104)(SP), AX // TODO: 104? - MOVL AX, g_stackguard(CX) - MOVL SP, g_stackbase(CX) CALL runtime·emptyfunc(SB) // fault if stack check is wrong // convention is D is always cleared @@ -78,7 +83,7 @@ ok: CALL runtime·schedinit(SB) // create a new goroutine to start program - PUSHL $runtime·mainstart(SB) // entry + PUSHL $runtime·main(SB) // entry PUSHL $0 // arg size CALL runtime·newproc(SB) POPL AX @@ -90,16 +95,6 @@ ok: INT $3 RET -TEXT runtime·mainstart(SB),7,$0 - CALL main·init(SB) - CALL runtime·initdone(SB) - CALL main·main(SB) - PUSHL $0 - CALL runtime·exit(SB) - POPL AX - INT $3 - RET - TEXT runtime·breakpoint(SB),7,$0 INT $3 RET diff --git a/src/pkg/runtime/amd64/asm.s b/src/pkg/runtime/asm_amd64.s index a881e3bbf..308a66036 100644 --- a/src/pkg/runtime/amd64/asm.s +++ b/src/pkg/runtime/asm_amd64.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "amd64/asm.h" +#include "zasm_GOOS_GOARCH.h" TEXT _rt0_amd64(SB),7,$-8 // copy arguments forward on an even stack @@ -12,11 +12,20 @@ TEXT _rt0_amd64(SB),7,$-8 ANDQ $~15, SP MOVQ AX, 16(SP) MOVQ BX, 24(SP) + + // create istack out of the given (operating system) stack. + // initcgo may update stackguard. + MOVQ $runtime·g0(SB), DI + LEAQ (-64*1024+104)(SP), BX + MOVQ BX, g_stackguard(DI) + MOVQ SP, g_stackbase(DI) // if there is an initcgo, call it. MOVQ initcgo(SB), AX TESTQ AX, AX JZ needtls + // g0 already in DI + MOVQ DI, CX // Win64 uses CX for first parameter CALL AX CMPL runtime·iswindows(SB), $0 JEQ ok @@ -43,11 +52,6 @@ ok: // save m->g0 = g0 MOVQ CX, m_g0(AX) - // create istack out of the given (operating system) stack - LEAQ (-8192+104)(SP), AX - MOVQ AX, g_stackguard(CX) - MOVQ SP, g_stackbase(CX) - CLD // convention is D is always left cleared CALL runtime·check(SB) @@ -60,7 +64,7 @@ ok: CALL runtime·schedinit(SB) // create a new goroutine to start program - PUSHQ $runtime·mainstart(SB) // entry + PUSHQ $runtime·main(SB) // entry PUSHQ $0 // arg size CALL runtime·newproc(SB) POPQ AX @@ -72,16 +76,6 @@ ok: CALL runtime·notok(SB) // never returns RET -TEXT runtime·mainstart(SB),7,$0 - CALL main·init(SB) - CALL runtime·initdone(SB) - CALL main·main(SB) - PUSHQ $0 - CALL runtime·exit(SB) - POPQ AX - CALL runtime·notok(SB) - RET - TEXT runtime·breakpoint(SB),7,$0 BYTE $0xcc RET diff --git a/src/pkg/runtime/arm/asm.s b/src/pkg/runtime/asm_arm.s index 63153658f..42c7677e1 100644 --- a/src/pkg/runtime/arm/asm.s +++ b/src/pkg/runtime/asm_arm.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "arm/asm.h" +#include "zasm_GOOS_GOARCH.h" // using frame size $-4 means do not save LR on stack. TEXT _rt0_arm(SB),7,$-4 @@ -43,7 +43,7 @@ TEXT _rt0_arm(SB),7,$-4 BL runtime·schedinit(SB) // create a new goroutine to start program - MOVW $runtime·mainstart(SB), R0 + MOVW $runtime·main(SB), R0 MOVW.W R0, -4(R13) MOVW $8, R0 MOVW.W R0, -4(R13) @@ -60,21 +60,6 @@ TEXT _rt0_arm(SB),7,$-4 MOVW R0, (R1) // fail hard B runtime·_dep_dummy(SB) // Never reached - -TEXT runtime·mainstart(SB),7,$4 - BL main·init(SB) - BL runtime·initdone(SB) - EOR R0, R0 - MOVW R0, 0(R13) - BL main·main(SB) - MOVW $0, R0 - MOVW R0, 4(SP) - BL runtime·exit(SB) - MOVW $1234, R0 - MOVW $1001, R1 - MOVW R0, (R1) // fail hard - RET - // TODO(kaib): remove these once i actually understand how the linker removes symbols // pull in dummy dependencies TEXT runtime·_dep_dummy(SB),7,$0 @@ -292,7 +277,7 @@ TEXT runtime·abort(SB),7,$-4 // }else // return 0; // -// To implement runtime·cas in ../$GOOS/arm/sys.s +// To implement runtime·cas in sys_$GOOS_arm.s // using the native instructions, use: // // TEXT runtime·cas(SB),7,$0 diff --git a/src/pkg/runtime/386/atomic.c b/src/pkg/runtime/atomic_386.c index a4f2a114f..a4f2a114f 100644 --- a/src/pkg/runtime/386/atomic.c +++ b/src/pkg/runtime/atomic_386.c diff --git a/src/pkg/runtime/amd64/atomic.c b/src/pkg/runtime/atomic_amd64.c index a4f2a114f..a4f2a114f 100644 --- a/src/pkg/runtime/amd64/atomic.c +++ b/src/pkg/runtime/atomic_amd64.c diff --git a/src/pkg/runtime/arm/atomic.c b/src/pkg/runtime/atomic_arm.c index 52e4059ae..52e4059ae 100644 --- a/src/pkg/runtime/arm/atomic.c +++ b/src/pkg/runtime/atomic_arm.c diff --git a/src/pkg/runtime/autogen.sh b/src/pkg/runtime/autogen.sh new file mode 100755 index 000000000..ca443ba7d --- /dev/null +++ b/src/pkg/runtime/autogen.sh @@ -0,0 +1,82 @@ +#!/bin/sh +# 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. + +# This script generates the various derived files involved in +# building package runtime. +# +# autogen.sh rebuilds everything +# autogen.sh -clean deletes the generated files + +. ../../buildinfo.sh + +HELPERS="goc2c mkversion" + +rm -f $HELPERS z* + +if [ "$1" = "-clean" ]; then + exit 0 +fi + +set -e + +if [ "$GOROOT" = "" ]; then + echo "$0"': $GOROOT must be set' >&2 + exit 2 +fi + +# Use goc2c to translate .goc files into arch-specific .c files. +quietgcc -o goc2c -I "$GOROOT/include" goc2c.c "$GOROOT/lib/lib9.a" +for file in *.goc +do + for arch in $GOARCHES + do + base=$(echo $file | sed 's/\.goc$//') + GOARCH=$arch ./goc2c $file >z.tmp + mv -f z.tmp z${base}_$arch.c + done +done + +# Version constants. +quietgcc -o mkversion -I "$GOROOT/include" mkversion.c "$GOROOT/lib/lib9.a" +GOROOT="$GOROOT_FINAL" ./mkversion >z.tmp +mv z.tmp zversion.go + +for arch in $GOARCHES +do + ( + echo '// AUTO-GENERATED by autogen.sh; DO NOT EDIT' + echo + echo 'package runtime' + echo + echo 'const theGoarch = "'$arch'"' + ) >zgoarch_$arch.go +done + +for os in $GOOSES +do + ( + echo '// AUTO-GENERATED by autogen.sh; DO NOT EDIT' + echo + echo 'package runtime' + echo + echo 'const theGoos = "'$os'"' + ) >zgoos_$os.go +done + +# Definitions of runtime structs, translated from C to Go. +for osarch in $GOOSARCHES +do + ./mkgodefs.sh $osarch proc.c iface.c hashmap.c chan.c >z.tmp + mv -f z.tmp zruntime_defs_$osarch.go +done + +# Struct field offsets, for use by assembly files. +for osarch in $GOOSARCHES +do + ./mkasmh.sh $osarch proc.c defs.h >z.tmp + mv -f z.tmp zasm_$osarch.h +done + +rm -f $HELPERS diff --git a/src/pkg/runtime/windows/386/callback.c b/src/pkg/runtime/callback_windows_386.c index 11b3d294d..fcd292fbc 100644 --- a/src/pkg/runtime/windows/386/callback.c +++ b/src/pkg/runtime/callback_windows_386.c @@ -4,8 +4,8 @@ #include "runtime.h" #include "type.h" -#include "defs.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" // Will keep all callbacks in a linked list, so they don't get garbage collected. typedef struct Callback Callback; diff --git a/src/pkg/runtime/windows/amd64/callback.c b/src/pkg/runtime/callback_windows_amd64.c index d53822e2b..99d7cb9e3 100644 --- a/src/pkg/runtime/windows/amd64/callback.c +++ b/src/pkg/runtime/callback_windows_amd64.c @@ -4,8 +4,8 @@ #include "runtime.h" #include "type.h" -#include "defs.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" // Will keep all callbacks in a linked list, so they don't get garbage collected. typedef struct Callback Callback; @@ -98,7 +98,7 @@ runtime·compilecallback(Eface fn, bool /*cleanstack*/) // JMP AX *p++ = 0xFF; - *p++ = 0xE0; + *p = 0xE0; return &c->asmbody; } diff --git a/src/pkg/runtime/cgo/Makefile b/src/pkg/runtime/cgo/Makefile index 766794797..05c7ebae7 100644 --- a/src/pkg/runtime/cgo/Makefile +++ b/src/pkg/runtime/cgo/Makefile @@ -14,15 +14,15 @@ ifeq ($(CGO_ENABLED),1) # Unwarranted chumminess with Make.pkg's cgo rules. # Do not try this at home. CGO_OFILES=\ - $(GOARCH).o\ - $(GOOS)_$(GOARCH).o\ - util.o\ + gcc_$(GOARCH).o\ + gcc_$(GOOS)_$(GOARCH).o\ + gcc_util.o\ ifeq ($(GOOS),windows) CGO_LDFLAGS=-lm -mthreads else CGO_LDFLAGS=-lpthread -CGO_OFILES+=setenv.o\ +CGO_OFILES+=gcc_setenv.o\ endif @@ -50,11 +50,11 @@ _cgo_main.c: echo 'int main() { return 0; }' >$@ endif -$(GOARCH).o: $(GOARCH).S +gcc_$(GOARCH).o: gcc_$(GOARCH).S $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^ -$(GOOS)_$(GOARCH).o: $(GOOS)_$(GOARCH).c +gcc_$(GOOS)_$(GOARCH).o: gcc_$(GOOS)_$(GOARCH).c $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^ -%.o: %.c +gcc_%.o: gcc_%.c $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^ diff --git a/src/pkg/runtime/cgo/386.S b/src/pkg/runtime/cgo/gcc_386.S index 9abab7ebd..9abab7ebd 100755..100644 --- a/src/pkg/runtime/cgo/386.S +++ b/src/pkg/runtime/cgo/gcc_386.S diff --git a/src/pkg/runtime/cgo/amd64.S b/src/pkg/runtime/cgo/gcc_amd64.S index 6c1a4c8e9..8e6d506f3 100644 --- a/src/pkg/runtime/cgo/amd64.S +++ b/src/pkg/runtime/cgo/gcc_amd64.S @@ -5,7 +5,7 @@ /* * Apple still insists on underscore prefixes for C function names. */ -#if defined(__APPLE__) || defined(_WIN32) +#if defined(__APPLE__) #define EXT(s) _##s #else #define EXT(s) s diff --git a/src/pkg/runtime/cgo/arm.S b/src/pkg/runtime/cgo/gcc_arm.S index 32d862984..32d862984 100644 --- a/src/pkg/runtime/cgo/arm.S +++ b/src/pkg/runtime/cgo/gcc_arm.S diff --git a/src/pkg/runtime/cgo/darwin_386.c b/src/pkg/runtime/cgo/gcc_darwin_386.c index 6d4e259be..d9f25347a 100644 --- a/src/pkg/runtime/cgo/darwin_386.c +++ b/src/pkg/runtime/cgo/gcc_darwin_386.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 <string.h> /* for strerror */ #include <pthread.h> #include "libcgo.h" @@ -38,8 +39,8 @@ inittls(void) * * The linker and runtime hard-code these constant offsets * from %gs where we expect to find m and g. - * Known to ../cmd/8l/obj.c:/468 - * and to ../pkg/runtime/darwin/386/sys.s:/468 + * Known to ../../../cmd/8l/obj.c:/468 + * and to ../sys_darwin_386.s:/468 * * This is truly disgusting and a bit fragile, but taking care * of it here protects the rest of the system from damage. @@ -100,12 +101,20 @@ inittls(void) } static void -xinitcgo(void) +xinitcgo(G *g) { + pthread_attr_t attr; + size_t size; + + pthread_attr_init(&attr); + pthread_attr_getstacksize(&attr, &size); + g->stackguard = (uintptr)&attr - size + 4096; + pthread_attr_destroy(&attr); + inittls(); } -void (*initcgo)(void) = xinitcgo; +void (*initcgo)(G*) = xinitcgo; void libcgo_sys_thread_start(ThreadStart *ts) diff --git a/src/pkg/runtime/cgo/darwin_amd64.c b/src/pkg/runtime/cgo/gcc_darwin_amd64.c index 3471044c0..a0b026ee2 100644 --- a/src/pkg/runtime/cgo/darwin_amd64.c +++ b/src/pkg/runtime/cgo/gcc_darwin_amd64.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 <string.h> /* for strerror */ #include <pthread.h> #include "libcgo.h" @@ -26,8 +27,8 @@ inittls(void) * * The linker and runtime hard-code these constant offsets * from %gs where we expect to find m and g. - * Known to ../cmd/6l/obj.c:/8a0 - * and to ../pkg/runtime/darwin/amd64/sys.s:/8a0 + * Known to ../../../cmd/6l/obj.c:/8a0 + * and to ../sys_darwin_amd64.s:/8a0 * * As disgusting as on the 386; same justification. */ @@ -70,12 +71,20 @@ inittls(void) } void -xinitcgo(void) +xinitcgo(G *g) { + pthread_attr_t attr; + size_t size; + + pthread_attr_init(&attr); + pthread_attr_getstacksize(&attr, &size); + g->stackguard = (uintptr)&attr - size + 4096; + pthread_attr_destroy(&attr); + inittls(); } -void (*initcgo) = xinitcgo; +void (*initcgo)(G*) = xinitcgo; void libcgo_sys_thread_start(ThreadStart *ts) diff --git a/src/pkg/runtime/cgo/freebsd_386.c b/src/pkg/runtime/cgo/gcc_freebsd_386.c index ae53201b4..ad9468730 100644 --- a/src/pkg/runtime/cgo/freebsd_386.c +++ b/src/pkg/runtime/cgo/gcc_freebsd_386.c @@ -8,11 +8,18 @@ static void* threadentry(void*); static void -xinitcgo(void) +xinitcgo(G *g) { + pthread_attr_t attr; + size_t size; + + pthread_attr_init(&attr); + pthread_attr_getstacksize(&attr, &size); + g->stackguard = (uintptr)&attr - size + 4096; + pthread_attr_destroy(&attr); } -void (*initcgo)(void) = xinitcgo; +void (*initcgo)(G*) = xinitcgo; void libcgo_sys_thread_start(ThreadStart *ts) diff --git a/src/pkg/runtime/cgo/freebsd_amd64.c b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c index 5afc1dfea..b18d1bc67 100644 --- a/src/pkg/runtime/cgo/freebsd_amd64.c +++ b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c @@ -8,11 +8,18 @@ static void* threadentry(void*); static void -xinitcgo(void) +xinitcgo(G *g) { + pthread_attr_t attr; + size_t size; + + pthread_attr_init(&attr); + pthread_attr_getstacksize(&attr, &size); + g->stackguard = (uintptr)&attr - size + 4096; + pthread_attr_destroy(&attr); } -void (*initcgo)(void) = xinitcgo; +void (*initcgo)(G*) = xinitcgo; void libcgo_sys_thread_start(ThreadStart *ts) diff --git a/src/pkg/runtime/cgo/linux_386.c b/src/pkg/runtime/cgo/gcc_linux_386.c index e9df5ffdc..8401a75ca 100644 --- a/src/pkg/runtime/cgo/linux_386.c +++ b/src/pkg/runtime/cgo/gcc_linux_386.c @@ -9,11 +9,18 @@ static void *threadentry(void*); static void -xinitcgo(void) +xinitcgo(G *g) { + pthread_attr_t attr; + size_t size; + + pthread_attr_init(&attr); + pthread_attr_getstacksize(&attr, &size); + g->stackguard = (uintptr)&attr - size + 4096; + pthread_attr_destroy(&attr); } -void (*initcgo) = xinitcgo; +void (*initcgo)(G*) = xinitcgo; void libcgo_sys_thread_start(ThreadStart *ts) diff --git a/src/pkg/runtime/cgo/linux_amd64.c b/src/pkg/runtime/cgo/gcc_linux_amd64.c index d9b8b3706..6ce3333a8 100644 --- a/src/pkg/runtime/cgo/linux_amd64.c +++ b/src/pkg/runtime/cgo/gcc_linux_amd64.c @@ -3,16 +3,24 @@ // license that can be found in the LICENSE file. #include <pthread.h> +#include <string.h> // strerror #include "libcgo.h" static void* threadentry(void*); void -xinitcgo(void) +xinitcgo(G* g) { + pthread_attr_t attr; + size_t size; + + pthread_attr_init(&attr); + pthread_attr_getstacksize(&attr, &size); + g->stackguard = (uintptr)&attr - size + 4096; + pthread_attr_destroy(&attr); } -void (*initcgo)(void) = xinitcgo; +void (*initcgo)(G*) = xinitcgo; void libcgo_sys_thread_start(ThreadStart *ts) diff --git a/src/pkg/runtime/cgo/linux_arm.c b/src/pkg/runtime/cgo/gcc_linux_arm.c index e556c433c..8397c75bb 100644 --- a/src/pkg/runtime/cgo/linux_arm.c +++ b/src/pkg/runtime/cgo/gcc_linux_arm.c @@ -5,11 +5,12 @@ #include "libcgo.h" static void -xinitcgo(void) +xinitcgo(G *g) { + // unimplemented } -void (*initcgo)(void) = xinitcgo; +void (*initcgo)(G*) = xinitcgo; void libcgo_sys_thread_start(ThreadStart *ts) diff --git a/src/pkg/runtime/cgo/setenv.c b/src/pkg/runtime/cgo/gcc_setenv.c index c911b8392..7da4ad915 100644 --- a/src/pkg/runtime/cgo/setenv.c +++ b/src/pkg/runtime/cgo/gcc_setenv.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build darwin freebsd linux netbsd openbsd + #include "libcgo.h" #include <stdlib.h> diff --git a/src/pkg/runtime/cgo/util.c b/src/pkg/runtime/cgo/gcc_util.c index e06b6f64d..e06b6f64d 100644 --- a/src/pkg/runtime/cgo/util.c +++ b/src/pkg/runtime/cgo/gcc_util.c diff --git a/src/pkg/runtime/cgo/windows_386.c b/src/pkg/runtime/cgo/gcc_windows_386.c index f39309cb1..2b940d362 100755..100644 --- a/src/pkg/runtime/cgo/windows_386.c +++ b/src/pkg/runtime/cgo/gcc_windows_386.c @@ -8,22 +8,24 @@ static void *threadentry(void*); -/* From what I've read 1MB is default for 32-bit Linux. - Allocation granularity on Windows is typically 64 KB. */ +/* 1MB is default stack size for 32-bit Windows. + Allocation granularity on Windows is typically 64 KB. + The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */ #define STACKSIZE (1*1024*1024) static void -xinitcgo(void) +xinitcgo(G *g) { + int tmp; + g->stackguard = (uintptr)&tmp - STACKSIZE + 8*1024; } -void (*initcgo)(void) = xinitcgo; +void (*initcgo)(G*) = xinitcgo; void libcgo_sys_thread_start(ThreadStart *ts) { - ts->g->stackguard = STACKSIZE; - _beginthread(threadentry, STACKSIZE, ts); + _beginthread(threadentry, 0, ts); } static void* @@ -36,20 +38,15 @@ threadentry(void *v) free(v); ts.g->stackbase = (uintptr)&ts; - - /* - * libcgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; + ts.g->stackguard = (uintptr)&ts - STACKSIZE + 8*1024; /* * Set specific keys in thread local storage. */ tls0 = (void*)LocalAlloc(LPTR, 32); asm volatile ( - "movl %0, %%fs:0x2c\n" // MOVL tls0, 0x2c(FS) - "movl %%fs:0x2c, %%eax\n" // MOVL 0x2c(FS), tmp + "movl %0, %%fs:0x14\n" // MOVL tls0, 0x14(FS) + "movl %%fs:0x14, %%eax\n" // MOVL 0x14(FS), tmp "movl %1, 0(%%eax)\n" // MOVL g, 0(FS) "movl %2, 4(%%eax)\n" // MOVL m, 4(FS) :: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%eax" diff --git a/src/pkg/runtime/cgo/windows_amd64.c b/src/pkg/runtime/cgo/gcc_windows_amd64.c index e8313e250..0d2f5d233 100755..100644 --- a/src/pkg/runtime/cgo/windows_amd64.c +++ b/src/pkg/runtime/cgo/gcc_windows_amd64.c @@ -8,22 +8,24 @@ static void *threadentry(void*); -/* From what I've read 2MB is default for 64-bit Linux. - Allocation granularity on Windows is typically 64 KB. */ +/* 2MB is default stack size for 64-bit Windows. + Allocation granularity on Windows is typically 64 KB. + The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */ #define STACKSIZE (2*1024*1024) static void -xinitcgo(void) +xinitcgo(G *g) { + int tmp; + g->stackguard = (uintptr)&tmp - STACKSIZE + 8*1024; } -void (*initcgo)(void) = xinitcgo; +void (*initcgo)(G*) = xinitcgo; void libcgo_sys_thread_start(ThreadStart *ts) { - ts->g->stackguard = STACKSIZE; - _beginthread(threadentry, STACKSIZE, ts); + _beginthread(threadentry, 0, ts); } static void* @@ -36,20 +38,15 @@ threadentry(void *v) free(v); ts.g->stackbase = (uintptr)&ts; - - /* - * libcgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; + ts.g->stackguard = (uintptr)&ts - STACKSIZE + 8*1024; /* * Set specific keys in thread local storage. */ tls0 = (void*)LocalAlloc(LPTR, 64); asm volatile ( - "movq %0, %%gs:0x58\n" // MOVL tls0, 0x58(GS) - "movq %%gs:0x58, %%rax\n" // MOVQ 0x58(GS), tmp + "movq %0, %%gs:0x28\n" // MOVL tls0, 0x28(GS) + "movq %%gs:0x28, %%rax\n" // MOVQ 0x28(GS), tmp "movq %1, 0(%%rax)\n" // MOVQ g, 0(GS) "movq %2, 8(%%rax)\n" // MOVQ m, 8(GS) :: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%rax" diff --git a/src/pkg/runtime/cgo/libcgo.h b/src/pkg/runtime/cgo/libcgo.h index 91032959c..c31d19d76 100644 --- a/src/pkg/runtime/cgo/libcgo.h +++ b/src/pkg/runtime/cgo/libcgo.h @@ -42,7 +42,7 @@ struct ThreadStart * Makes a local copy of the ThreadStart and * calls libcgo_sys_thread_start(ts). */ -void (*libcgo_thread_start)(ThreadStart *ts); +extern void (*libcgo_thread_start)(ThreadStart *ts); /* * Creates the new operating system thread (OS, arch dependent). diff --git a/src/pkg/runtime/cgo/trigger.go b/src/pkg/runtime/cgo/trigger.go new file mode 100644 index 000000000..a7788118f --- /dev/null +++ b/src/pkg/runtime/cgo/trigger.go @@ -0,0 +1,20 @@ +// 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. + +// This tells the go tool that this package builds using cgo. +// TODO: Once we stop using Make, this import can move into cgo.go. + +package cgo + +/* + +#cgo darwin LDFLAGS: -lpthread +#cgo freebsd LDFLAGS: -lpthread +#cgo linux LDFLAGS: -lpthread +#cgo netbsd LDFLAGS: -lpthread +#cgo openbsd LDFLAGS: -lpthread +#cgo windows LDFLAGS: -lm -mthreads + +*/ +import "C" diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c index 4fdb912fa..756eff38f 100644 --- a/src/pkg/runtime/cgocall.c +++ b/src/pkg/runtime/cgocall.c @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "arch.h" +#include "arch_GOARCH.h" #include "stack.h" #include "cgocall.h" @@ -17,7 +17,7 @@ // so as not to block other goroutines or the garbage collector, // and then calls runtime.asmcgocall(_cgo_Cfunc_f, frame). // -// runtime.asmcgocall (in $GOARCH/asm.s) switches to the m->g0 stack +// runtime.asmcgocall (in asm_$GOARCH.s) switches to the m->g0 stack // (assumed to be an operating system-allocated stack, so safe to run // gcc-compiled code on) and calls _cgo_Cfunc_f(frame). // @@ -55,7 +55,7 @@ // with 6c instead of gcc, can refer to dotted names like // runtime.cgocallback and p.GoF.) // -// runtime.cgocallback (in $GOOS/asm.s) switches from m->g0's +// runtime.cgocallback (in asm_$GOARCH.s) switches from m->g0's // stack to the original g (m->curg)'s stack, on which it calls // runtime.cgocallbackg(p.GoF, frame, framesize). // As part of the stack switch, runtime.cgocallback saves the current diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c index eac2098c3..bea1a34f8 100644 --- a/src/pkg/runtime/chan.c +++ b/src/pkg/runtime/chan.c @@ -92,11 +92,6 @@ runtime·makechan_c(ChanType *t, int64 hint) if(hint < 0 || (int32)hint != hint || (elem->size > 0 && hint > ((uintptr)-1) / elem->size)) runtime·panicstring("makechan: size out of range"); - if(elem->alg >= nelem(runtime·algarray)) { - runtime·printf("chan(alg=%d)\n", elem->alg); - runtime·throw("runtime.makechan: unsupported elem type"); - } - // calculate rounded size of Hchan n = sizeof(*c); while(n & MAXALIGN) @@ -104,16 +99,13 @@ runtime·makechan_c(ChanType *t, int64 hint) // allocate memory in one call c = (Hchan*)runtime·mal(n + hint*elem->size); - if(runtime·destroylock) - runtime·addfinalizer(c, (void*)destroychan, 0); - c->elemsize = elem->size; - c->elemalg = &runtime·algarray[elem->alg]; + c->elemalg = elem->alg; c->elemalign = elem->align; c->dataqsiz = hint; if(debug) - runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%d; elemalign=%d; dataqsiz=%d\n", + runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%p; elemalign=%d; dataqsiz=%d\n", c, (int64)elem->size, elem->alg, elem->align, c->dataqsiz); return c; @@ -128,13 +120,6 @@ reflect·makechan(ChanType *t, uint32 size, Hchan *c) FLUSH(&c); } -static void -destroychan(Hchan *c) -{ - runtime·destroylock(&c->Lock); -} - - // makechan(t *ChanType, hint int64) (hchan *chan any); void runtime·makechan(ChanType *t, int64 hint, Hchan *ret) @@ -1024,7 +1009,8 @@ syncsend: selunlock(sel); if(debug) runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o); - c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem); + if(sg->elem != nil) + c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem); gp = sg->g; gp->param = sg; runtime·ready(gp); @@ -1051,6 +1037,9 @@ runtime·closechan(Hchan *c) SudoG *sg; G* gp; + if(c == nil) + runtime·panicstring("close of nil channel"); + if(runtime·gcwaiting) runtime·gosched(); diff --git a/src/pkg/runtime/chan_test.go b/src/pkg/runtime/chan_test.go index 7cea906ce..eb2c7c60d 100644 --- a/src/pkg/runtime/chan_test.go +++ b/src/pkg/runtime/chan_test.go @@ -371,3 +371,12 @@ func BenchmarkChanCreation(b *testing.B) { <-c } } + +func BenchmarkChanSem(b *testing.B) { + type Empty struct{} + c := make(chan Empty, 1) + for i := 0; i < b.N; i++ { + c <- Empty{} + <-c + } +} diff --git a/src/pkg/runtime/386/closure.c b/src/pkg/runtime/closure_386.c index b4d867711..b4d867711 100644 --- a/src/pkg/runtime/386/closure.c +++ b/src/pkg/runtime/closure_386.c diff --git a/src/pkg/runtime/amd64/closure.c b/src/pkg/runtime/closure_amd64.c index 481b4a888..481b4a888 100644 --- a/src/pkg/runtime/amd64/closure.c +++ b/src/pkg/runtime/closure_amd64.c diff --git a/src/pkg/runtime/arm/closure.c b/src/pkg/runtime/closure_arm.c index 119e91b61..119e91b61 100644 --- a/src/pkg/runtime/arm/closure.c +++ b/src/pkg/runtime/closure_arm.c diff --git a/src/pkg/runtime/cpuprof.c b/src/pkg/runtime/cpuprof.c index 74b795b7e..05fa0cf61 100644 --- a/src/pkg/runtime/cpuprof.c +++ b/src/pkg/runtime/cpuprof.c @@ -49,6 +49,7 @@ // in the situation when normally the goroutine "owns" handoff. #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" enum diff --git a/src/pkg/runtime/darwin/386/defs.h b/src/pkg/runtime/darwin/386/defs.h deleted file mode 100644 index bb70207fd..000000000 --- a/src/pkg/runtime/darwin/386/defs.h +++ /dev/null @@ -1,289 +0,0 @@ -// godefs -f -m32 defs.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants -enum { - PROT_NONE = 0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - MAP_ANON = 0x1000, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - MACH_MSG_TYPE_MOVE_RECEIVE = 0x10, - MACH_MSG_TYPE_MOVE_SEND = 0x11, - MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12, - MACH_MSG_TYPE_COPY_SEND = 0x13, - MACH_MSG_TYPE_MAKE_SEND = 0x14, - MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15, - MACH_MSG_TYPE_COPY_RECEIVE = 0x16, - MACH_MSG_PORT_DESCRIPTOR = 0, - MACH_MSG_OOL_DESCRIPTOR = 0x1, - MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2, - MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3, - MACH_MSGH_BITS_COMPLEX = 0x80000000, - MACH_SEND_MSG = 0x1, - MACH_RCV_MSG = 0x2, - MACH_RCV_LARGE = 0x4, - MACH_SEND_TIMEOUT = 0x10, - MACH_SEND_INTERRUPT = 0x40, - MACH_SEND_CANCEL = 0x80, - MACH_SEND_ALWAYS = 0x10000, - MACH_SEND_TRAILER = 0x20000, - MACH_RCV_TIMEOUT = 0x100, - MACH_RCV_NOTIFY = 0x200, - MACH_RCV_INTERRUPT = 0x400, - MACH_RCV_OVERWRITE = 0x1000, - NDR_PROTOCOL_2_0 = 0, - NDR_INT_BIG_ENDIAN = 0, - NDR_INT_LITTLE_ENDIAN = 0x1, - NDR_FLOAT_IEEE = 0, - NDR_CHAR_ASCII = 0, - SA_SIGINFO = 0x40, - SA_RESTART = 0x2, - SA_ONSTACK = 0x1, - SA_USERTRAMP = 0x100, - SA_64REGSET = 0x200, - SIGHUP = 0x1, - SIGINT = 0x2, - SIGQUIT = 0x3, - SIGILL = 0x4, - SIGTRAP = 0x5, - SIGABRT = 0x6, - SIGEMT = 0x7, - SIGFPE = 0x8, - SIGKILL = 0x9, - SIGBUS = 0xa, - SIGSEGV = 0xb, - SIGSYS = 0xc, - SIGPIPE = 0xd, - SIGALRM = 0xe, - SIGTERM = 0xf, - SIGURG = 0x10, - SIGSTOP = 0x11, - SIGTSTP = 0x12, - SIGCONT = 0x13, - SIGCHLD = 0x14, - SIGTTIN = 0x15, - SIGTTOU = 0x16, - SIGIO = 0x17, - SIGXCPU = 0x18, - SIGXFSZ = 0x19, - SIGVTALRM = 0x1a, - SIGPROF = 0x1b, - SIGWINCH = 0x1c, - SIGINFO = 0x1d, - SIGUSR1 = 0x1e, - SIGUSR2 = 0x1f, - FPE_INTDIV = 0x7, - FPE_INTOVF = 0x8, - FPE_FLTDIV = 0x1, - FPE_FLTOVF = 0x2, - FPE_FLTUND = 0x3, - FPE_FLTRES = 0x4, - FPE_FLTINV = 0x5, - FPE_FLTSUB = 0x6, - BUS_ADRALN = 0x1, - BUS_ADRERR = 0x2, - BUS_OBJERR = 0x3, - SEGV_MAPERR = 0x1, - SEGV_ACCERR = 0x2, - ITIMER_REAL = 0, - ITIMER_VIRTUAL = 0x1, - ITIMER_PROF = 0x2, -}; - -// Types -#pragma pack on - -typedef struct MachBody MachBody; -struct MachBody { - uint32 msgh_descriptor_count; -}; - -typedef struct MachHeader MachHeader; -struct MachHeader { - uint32 msgh_bits; - uint32 msgh_size; - uint32 msgh_remote_port; - uint32 msgh_local_port; - uint32 msgh_reserved; - int32 msgh_id; -}; - -typedef struct MachNDR MachNDR; -struct MachNDR { - uint8 mig_vers; - uint8 if_vers; - uint8 reserved1; - uint8 mig_encoding; - uint8 int_rep; - uint8 char_rep; - uint8 float_rep; - uint8 reserved2; -}; - -typedef struct MachPort MachPort; -struct MachPort { - uint32 name; - uint32 pad1; - uint16 pad2; - uint8 disposition; - uint8 type; -}; - -typedef struct StackT StackT; -struct StackT { - void *ss_sp; - uint32 ss_size; - int32 ss_flags; -}; - -typedef union Sighandler Sighandler; -union Sighandler { - uint32 __sa_handler; - uint32 __sa_sigaction; -}; - -typedef struct Sigaction Sigaction; -struct Sigaction { - Sighandler __sigaction_u; - uint32 sa_tramp; - uint32 sa_mask; - int32 sa_flags; -}; - -typedef union Sigval Sigval; -union Sigval { - int32 sival_int; - void *sival_ptr; -}; - -typedef struct Siginfo Siginfo; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - int32 si_pid; - uint32 si_uid; - int32 si_status; - void *si_addr; - Sigval si_value; - int32 si_band; - uint32 __pad[7]; -}; - -typedef struct Timeval Timeval; -struct Timeval { - int32 tv_sec; - int32 tv_usec; -}; - -typedef struct Itimerval Itimerval; -struct Itimerval { - Timeval it_interval; - Timeval it_value; -}; - -typedef struct FPControl FPControl; -struct FPControl { - byte pad_godefs_0[2]; -}; - -typedef struct FPStatus FPStatus; -struct FPStatus { - byte pad_godefs_0[2]; -}; - -typedef struct RegMMST RegMMST; -struct RegMMST { - int8 mmst_reg[10]; - int8 mmst_rsrv[6]; -}; - -typedef struct RegXMM RegXMM; -struct RegXMM { - int8 xmm_reg[16]; -}; - -typedef struct Regs Regs; -struct Regs { - uint32 eax; - uint32 ebx; - uint32 ecx; - uint32 edx; - uint32 edi; - uint32 esi; - uint32 ebp; - uint32 esp; - uint32 ss; - uint32 eflags; - uint32 eip; - uint32 cs; - uint32 ds; - uint32 es; - uint32 fs; - uint32 gs; -}; - -typedef struct FloatState FloatState; -struct FloatState { - uint64 fpu_reserved; - FPControl fpu_fcw; - FPStatus fpu_fsw; - uint8 fpu_ftw; - uint8 fpu_rsrv1; - uint16 fpu_fop; - uint32 fpu_ip; - uint16 fpu_cs; - uint16 fpu_rsrv2; - uint32 fpu_dp; - uint16 fpu_ds; - uint16 fpu_rsrv3; - uint32 fpu_mxcsr; - uint32 fpu_mxcsrmask; - RegMMST fpu_stmm0; - RegMMST fpu_stmm1; - RegMMST fpu_stmm2; - RegMMST fpu_stmm3; - RegMMST fpu_stmm4; - RegMMST fpu_stmm5; - RegMMST fpu_stmm6; - RegMMST fpu_stmm7; - RegXMM fpu_xmm0; - RegXMM fpu_xmm1; - RegXMM fpu_xmm2; - RegXMM fpu_xmm3; - RegXMM fpu_xmm4; - RegXMM fpu_xmm5; - RegXMM fpu_xmm6; - RegXMM fpu_xmm7; - int8 fpu_rsrv4[224]; - int32 fpu_reserved1; -}; - -typedef struct ExceptionState ExceptionState; -struct ExceptionState { - uint32 trapno; - uint32 err; - uint32 faultvaddr; -}; - -typedef struct Mcontext Mcontext; -struct Mcontext { - ExceptionState es; - Regs ss; - FloatState fs; -}; - -typedef struct Ucontext Ucontext; -struct Ucontext { - int32 uc_onstack; - uint32 uc_sigmask; - StackT uc_stack; - uint32 uc_link; - uint32 uc_mcsize; - Mcontext *uc_mcontext; -}; -#pragma pack off diff --git a/src/pkg/runtime/darwin/amd64/defs.h b/src/pkg/runtime/darwin/amd64/defs.h deleted file mode 100644 index 90f798e8a..000000000 --- a/src/pkg/runtime/darwin/amd64/defs.h +++ /dev/null @@ -1,305 +0,0 @@ -// godefs -f -m64 defs.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants -enum { - PROT_NONE = 0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - MAP_ANON = 0x1000, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - MACH_MSG_TYPE_MOVE_RECEIVE = 0x10, - MACH_MSG_TYPE_MOVE_SEND = 0x11, - MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12, - MACH_MSG_TYPE_COPY_SEND = 0x13, - MACH_MSG_TYPE_MAKE_SEND = 0x14, - MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15, - MACH_MSG_TYPE_COPY_RECEIVE = 0x16, - MACH_MSG_PORT_DESCRIPTOR = 0, - MACH_MSG_OOL_DESCRIPTOR = 0x1, - MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2, - MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3, - MACH_MSGH_BITS_COMPLEX = 0x80000000, - MACH_SEND_MSG = 0x1, - MACH_RCV_MSG = 0x2, - MACH_RCV_LARGE = 0x4, - MACH_SEND_TIMEOUT = 0x10, - MACH_SEND_INTERRUPT = 0x40, - MACH_SEND_CANCEL = 0x80, - MACH_SEND_ALWAYS = 0x10000, - MACH_SEND_TRAILER = 0x20000, - MACH_RCV_TIMEOUT = 0x100, - MACH_RCV_NOTIFY = 0x200, - MACH_RCV_INTERRUPT = 0x400, - MACH_RCV_OVERWRITE = 0x1000, - NDR_PROTOCOL_2_0 = 0, - NDR_INT_BIG_ENDIAN = 0, - NDR_INT_LITTLE_ENDIAN = 0x1, - NDR_FLOAT_IEEE = 0, - NDR_CHAR_ASCII = 0, - SA_SIGINFO = 0x40, - SA_RESTART = 0x2, - SA_ONSTACK = 0x1, - SA_USERTRAMP = 0x100, - SA_64REGSET = 0x200, - SIGHUP = 0x1, - SIGINT = 0x2, - SIGQUIT = 0x3, - SIGILL = 0x4, - SIGTRAP = 0x5, - SIGABRT = 0x6, - SIGEMT = 0x7, - SIGFPE = 0x8, - SIGKILL = 0x9, - SIGBUS = 0xa, - SIGSEGV = 0xb, - SIGSYS = 0xc, - SIGPIPE = 0xd, - SIGALRM = 0xe, - SIGTERM = 0xf, - SIGURG = 0x10, - SIGSTOP = 0x11, - SIGTSTP = 0x12, - SIGCONT = 0x13, - SIGCHLD = 0x14, - SIGTTIN = 0x15, - SIGTTOU = 0x16, - SIGIO = 0x17, - SIGXCPU = 0x18, - SIGXFSZ = 0x19, - SIGVTALRM = 0x1a, - SIGPROF = 0x1b, - SIGWINCH = 0x1c, - SIGINFO = 0x1d, - SIGUSR1 = 0x1e, - SIGUSR2 = 0x1f, - FPE_INTDIV = 0x7, - FPE_INTOVF = 0x8, - FPE_FLTDIV = 0x1, - FPE_FLTOVF = 0x2, - FPE_FLTUND = 0x3, - FPE_FLTRES = 0x4, - FPE_FLTINV = 0x5, - FPE_FLTSUB = 0x6, - BUS_ADRALN = 0x1, - BUS_ADRERR = 0x2, - BUS_OBJERR = 0x3, - SEGV_MAPERR = 0x1, - SEGV_ACCERR = 0x2, - ITIMER_REAL = 0, - ITIMER_VIRTUAL = 0x1, - ITIMER_PROF = 0x2, -}; - -// Types -#pragma pack on - -typedef struct MachBody MachBody; -struct MachBody { - uint32 msgh_descriptor_count; -}; - -typedef struct MachHeader MachHeader; -struct MachHeader { - uint32 msgh_bits; - uint32 msgh_size; - uint32 msgh_remote_port; - uint32 msgh_local_port; - uint32 msgh_reserved; - int32 msgh_id; -}; - -typedef struct MachNDR MachNDR; -struct MachNDR { - uint8 mig_vers; - uint8 if_vers; - uint8 reserved1; - uint8 mig_encoding; - uint8 int_rep; - uint8 char_rep; - uint8 float_rep; - uint8 reserved2; -}; - -typedef struct MachPort MachPort; -struct MachPort { - uint32 name; - uint32 pad1; - uint16 pad2; - uint8 disposition; - uint8 type; -}; - -typedef struct StackT StackT; -struct StackT { - void *ss_sp; - uint64 ss_size; - int32 ss_flags; - byte pad_godefs_0[4]; -}; - -typedef union Sighandler Sighandler; -union Sighandler { - uint64 __sa_handler; - uint64 __sa_sigaction; -}; - -typedef struct Sigaction Sigaction; -struct Sigaction { - Sighandler __sigaction_u; - uint64 sa_tramp; - uint32 sa_mask; - int32 sa_flags; -}; - -typedef union Sigval Sigval; -union Sigval { - int32 sival_int; - void *sival_ptr; -}; - -typedef struct Siginfo Siginfo; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - int32 si_pid; - uint32 si_uid; - int32 si_status; - void *si_addr; - Sigval si_value; - int64 si_band; - uint64 __pad[7]; -}; - -typedef struct Timeval Timeval; -struct Timeval { - int64 tv_sec; - int32 tv_usec; - byte pad_godefs_0[4]; -}; - -typedef struct Itimerval Itimerval; -struct Itimerval { - Timeval it_interval; - Timeval it_value; -}; - -typedef struct FPControl FPControl; -struct FPControl { - byte pad_godefs_0[2]; -}; - -typedef struct FPStatus FPStatus; -struct FPStatus { - byte pad_godefs_0[2]; -}; - -typedef struct RegMMST RegMMST; -struct RegMMST { - int8 mmst_reg[10]; - int8 mmst_rsrv[6]; -}; - -typedef struct RegXMM RegXMM; -struct RegXMM { - int8 xmm_reg[16]; -}; - -typedef struct Regs Regs; -struct Regs { - uint64 rax; - uint64 rbx; - uint64 rcx; - uint64 rdx; - uint64 rdi; - uint64 rsi; - uint64 rbp; - uint64 rsp; - uint64 r8; - uint64 r9; - uint64 r10; - uint64 r11; - uint64 r12; - uint64 r13; - uint64 r14; - uint64 r15; - uint64 rip; - uint64 rflags; - uint64 cs; - uint64 fs; - uint64 gs; -}; - -typedef struct FloatState FloatState; -struct FloatState { - uint64 fpu_reserved; - FPControl fpu_fcw; - FPStatus fpu_fsw; - uint8 fpu_ftw; - uint8 fpu_rsrv1; - uint16 fpu_fop; - uint32 fpu_ip; - uint16 fpu_cs; - uint16 fpu_rsrv2; - uint32 fpu_dp; - uint16 fpu_ds; - uint16 fpu_rsrv3; - uint32 fpu_mxcsr; - uint32 fpu_mxcsrmask; - RegMMST fpu_stmm0; - RegMMST fpu_stmm1; - RegMMST fpu_stmm2; - RegMMST fpu_stmm3; - RegMMST fpu_stmm4; - RegMMST fpu_stmm5; - RegMMST fpu_stmm6; - RegMMST fpu_stmm7; - RegXMM fpu_xmm0; - RegXMM fpu_xmm1; - RegXMM fpu_xmm2; - RegXMM fpu_xmm3; - RegXMM fpu_xmm4; - RegXMM fpu_xmm5; - RegXMM fpu_xmm6; - RegXMM fpu_xmm7; - RegXMM fpu_xmm8; - RegXMM fpu_xmm9; - RegXMM fpu_xmm10; - RegXMM fpu_xmm11; - RegXMM fpu_xmm12; - RegXMM fpu_xmm13; - RegXMM fpu_xmm14; - RegXMM fpu_xmm15; - int8 fpu_rsrv4[96]; - int32 fpu_reserved1; -}; - -typedef struct ExceptionState ExceptionState; -struct ExceptionState { - uint32 trapno; - uint32 err; - uint64 faultvaddr; -}; - -typedef struct Mcontext Mcontext; -struct Mcontext { - ExceptionState es; - Regs ss; - FloatState fs; - byte pad_godefs_0[4]; -}; - -typedef struct Ucontext Ucontext; -struct Ucontext { - int32 uc_onstack; - uint32 uc_sigmask; - StackT uc_stack; - uint64 uc_link; - uint64 uc_mcsize; - Mcontext *uc_mcontext; -}; -#pragma pack off diff --git a/src/pkg/runtime/darwin/defs.c b/src/pkg/runtime/darwin/defs.c deleted file mode 100644 index 032a6bcbb..000000000 --- a/src/pkg/runtime/darwin/defs.c +++ /dev/null @@ -1,159 +0,0 @@ -// 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. - -/* - * Input to godefs. - * - godefs -f -m64 defs.c >amd64/defs.h - godefs -f -m32 defs.c >386/defs.h - */ - -#define __DARWIN_UNIX03 0 - -#include <mach/mach.h> -#include <mach/message.h> -#include <sys/types.h> -#include <sys/time.h> -#include <signal.h> -#include <sys/mman.h> - -enum { - $PROT_NONE = PROT_NONE, - $PROT_READ = PROT_READ, - $PROT_WRITE = PROT_WRITE, - $PROT_EXEC = PROT_EXEC, - - $MAP_ANON = MAP_ANON, - $MAP_PRIVATE = MAP_PRIVATE, - $MAP_FIXED = MAP_FIXED, - - $MACH_MSG_TYPE_MOVE_RECEIVE = MACH_MSG_TYPE_MOVE_RECEIVE, - $MACH_MSG_TYPE_MOVE_SEND = MACH_MSG_TYPE_MOVE_SEND, - $MACH_MSG_TYPE_MOVE_SEND_ONCE = MACH_MSG_TYPE_MOVE_SEND_ONCE, - $MACH_MSG_TYPE_COPY_SEND = MACH_MSG_TYPE_COPY_SEND, - $MACH_MSG_TYPE_MAKE_SEND = MACH_MSG_TYPE_MAKE_SEND, - $MACH_MSG_TYPE_MAKE_SEND_ONCE = MACH_MSG_TYPE_MAKE_SEND_ONCE, - $MACH_MSG_TYPE_COPY_RECEIVE = MACH_MSG_TYPE_COPY_RECEIVE, - - $MACH_MSG_PORT_DESCRIPTOR = MACH_MSG_PORT_DESCRIPTOR, - $MACH_MSG_OOL_DESCRIPTOR = MACH_MSG_OOL_DESCRIPTOR, - $MACH_MSG_OOL_PORTS_DESCRIPTOR = MACH_MSG_OOL_PORTS_DESCRIPTOR, - $MACH_MSG_OOL_VOLATILE_DESCRIPTOR = MACH_MSG_OOL_VOLATILE_DESCRIPTOR, - - $MACH_MSGH_BITS_COMPLEX = MACH_MSGH_BITS_COMPLEX, - - $MACH_SEND_MSG = MACH_SEND_MSG, - $MACH_RCV_MSG = MACH_RCV_MSG, - $MACH_RCV_LARGE = MACH_RCV_LARGE, - - $MACH_SEND_TIMEOUT = MACH_SEND_TIMEOUT, - $MACH_SEND_INTERRUPT = MACH_SEND_INTERRUPT, - $MACH_SEND_CANCEL = MACH_SEND_CANCEL, - $MACH_SEND_ALWAYS = MACH_SEND_ALWAYS, - $MACH_SEND_TRAILER = MACH_SEND_TRAILER, - $MACH_RCV_TIMEOUT = MACH_RCV_TIMEOUT, - $MACH_RCV_NOTIFY = MACH_RCV_NOTIFY, - $MACH_RCV_INTERRUPT = MACH_RCV_INTERRUPT, - $MACH_RCV_OVERWRITE = MACH_RCV_OVERWRITE, - - $NDR_PROTOCOL_2_0 = NDR_PROTOCOL_2_0, - $NDR_INT_BIG_ENDIAN = NDR_INT_BIG_ENDIAN, - $NDR_INT_LITTLE_ENDIAN = NDR_INT_LITTLE_ENDIAN, - $NDR_FLOAT_IEEE = NDR_FLOAT_IEEE, - $NDR_CHAR_ASCII = NDR_CHAR_ASCII, - - $SA_SIGINFO = SA_SIGINFO, - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - $SA_USERTRAMP = SA_USERTRAMP, - $SA_64REGSET = SA_64REGSET, - - $SIGHUP = SIGHUP, - $SIGINT = SIGINT, - $SIGQUIT = SIGQUIT, - $SIGILL = SIGILL, - $SIGTRAP = SIGTRAP, - $SIGABRT = SIGABRT, - $SIGEMT = SIGEMT, - $SIGFPE = SIGFPE, - $SIGKILL = SIGKILL, - $SIGBUS = SIGBUS, - $SIGSEGV = SIGSEGV, - $SIGSYS = SIGSYS, - $SIGPIPE = SIGPIPE, - $SIGALRM = SIGALRM, - $SIGTERM = SIGTERM, - $SIGURG = SIGURG, - $SIGSTOP = SIGSTOP, - $SIGTSTP = SIGTSTP, - $SIGCONT = SIGCONT, - $SIGCHLD = SIGCHLD, - $SIGTTIN = SIGTTIN, - $SIGTTOU = SIGTTOU, - $SIGIO = SIGIO, - $SIGXCPU = SIGXCPU, - $SIGXFSZ = SIGXFSZ, - $SIGVTALRM = SIGVTALRM, - $SIGPROF = SIGPROF, - $SIGWINCH = SIGWINCH, - $SIGINFO = SIGINFO, - $SIGUSR1 = SIGUSR1, - $SIGUSR2 = SIGUSR2, - - $FPE_INTDIV = FPE_INTDIV, - $FPE_INTOVF = FPE_INTOVF, - $FPE_FLTDIV = FPE_FLTDIV, - $FPE_FLTOVF = FPE_FLTOVF, - $FPE_FLTUND = FPE_FLTUND, - $FPE_FLTRES = FPE_FLTRES, - $FPE_FLTINV = FPE_FLTINV, - $FPE_FLTSUB = FPE_FLTSUB, - - $BUS_ADRALN = BUS_ADRALN, - $BUS_ADRERR = BUS_ADRERR, - $BUS_OBJERR = BUS_OBJERR, - - $SEGV_MAPERR = SEGV_MAPERR, - $SEGV_ACCERR = SEGV_ACCERR, - - $ITIMER_REAL = ITIMER_REAL, - $ITIMER_VIRTUAL = ITIMER_VIRTUAL, - $ITIMER_PROF = ITIMER_PROF, -}; - -typedef mach_msg_body_t $MachBody; -typedef mach_msg_header_t $MachHeader; -typedef NDR_record_t $MachNDR; -typedef mach_msg_port_descriptor_t $MachPort; - -typedef stack_t $StackT; -typedef union __sigaction_u $Sighandler; - -typedef struct __sigaction $Sigaction; // used in syscalls -// typedef struct sigaction $Sigaction; // used by the C library -typedef union sigval $Sigval; -typedef siginfo_t $Siginfo; -typedef struct timeval $Timeval; -typedef struct itimerval $Itimerval; - -typedef struct fp_control $FPControl; -typedef struct fp_status $FPStatus; -typedef struct mmst_reg $RegMMST; -typedef struct xmm_reg $RegXMM; - -#ifdef __LP64__ -// amd64 -typedef x86_thread_state64_t $Regs; -typedef x86_float_state64_t $FloatState; -typedef x86_exception_state64_t $ExceptionState; -typedef struct mcontext64 $Mcontext; -#else -// 386 -typedef x86_thread_state32_t $Regs; -typedef x86_float_state32_t $FloatState; -typedef x86_exception_state32_t $ExceptionState; -typedef struct mcontext32 $Mcontext; -#endif - -typedef ucontext_t $Ucontext; diff --git a/src/pkg/runtime/debug.go b/src/pkg/runtime/debug.go index 6370a57d8..4f09146fa 100644 --- a/src/pkg/runtime/debug.go +++ b/src/pkg/runtime/debug.go @@ -10,7 +10,6 @@ func Breakpoint() // LockOSThread wires the calling goroutine to its current operating system thread. // Until the calling goroutine exits or calls UnlockOSThread, it will always // execute in that thread, and no other goroutine can. -// LockOSThread cannot be used during init functions. func LockOSThread() // UnlockOSThread unwires the calling goroutine from its fixed operating system thread. @@ -20,9 +19,13 @@ func UnlockOSThread() // GOMAXPROCS sets the maximum number of CPUs that can be executing // simultaneously and returns the previous setting. If n < 1, it does not // change the current setting. +// The number of logical CPUs on the local machine can be queried with NumCPU. // This call will go away when the scheduler improves. func GOMAXPROCS(n int) int +// NumCPU returns the number of logical CPUs on the local machine. +func NumCPU() int + // Cgocalls returns the number of cgo calls made by the current process. func Cgocalls() int64 diff --git a/src/pkg/runtime/defs1_linux.go b/src/pkg/runtime/defs1_linux.go new file mode 100644 index 000000000..451817a67 --- /dev/null +++ b/src/pkg/runtime/defs1_linux.go @@ -0,0 +1,37 @@ +// 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. + +// +build ignore + +/* +Input to cgo -cdefs + +GOARCH=amd64 cgo -cdefs defs.go defs1.go >amd64/defs.h +*/ + +package runtime + +/* +#include <ucontext.h> +#include <fcntl.h> +*/ +import "C" + +const ( + O_RDONLY = C.O_RDONLY + O_CLOEXEC = C.O_CLOEXEC +) + +type Usigset C.__sigset_t +type Fpxreg C.struct__libc_fpxreg +type Xmmreg C.struct__libc_xmmreg +type Fpstate C.struct__libc_fpstate +type Fpxreg1 C.struct__fpxreg +type Xmmreg1 C.struct__xmmreg +type Fpstate1 C.struct__fpstate +type Fpreg1 C.struct__fpreg +type Sigaltstack C.struct_sigaltstack +type Mcontext C.mcontext_t +type Ucontext C.ucontext_t +type Sigcontext C.struct_sigcontext diff --git a/src/pkg/runtime/defs2_linux.go b/src/pkg/runtime/defs2_linux.go new file mode 100644 index 000000000..9b0702955 --- /dev/null +++ b/src/pkg/runtime/defs2_linux.go @@ -0,0 +1,126 @@ +// 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. + +// +build ignore + +/* + * Input to cgo -cdefs + +GOARCH=386 cgo -cdefs defs2.go >386/defs.h + +The asm header tricks we have to use for Linux on amd64 +(see defs.c and defs1.c) don't work here, so this is yet another +file. Sigh. +*/ + +package runtime + +/* +#cgo CFLAGS: -I/home/rsc/pub/linux-2.6/arch/x86/include -I/home/rsc/pub/linux-2.6/include -D_LOOSE_KERNEL_NAMES -D__ARCH_SI_UID_T=__kernel_uid32_t + +#define size_t __kernel_size_t +#include <asm/signal.h> +#include <asm/mman.h> +#include <asm/sigcontext.h> +#include <asm/ucontext.h> +#include <asm/siginfo.h> +#include <asm-generic/fcntl.h> + +// This is the sigaction structure from the Linux 2.1.68 kernel which +// is used with the rt_sigaction system call. For 386 this is not +// defined in any public header file. + +struct kernel_sigaction { + __sighandler_t k_sa_handler; + unsigned long sa_flags; + void (*sa_restorer) (void); + sigset_t sa_mask; +}; +*/ +import "C" + +const ( + PROT_NONE = C.PROT_NONE + PROT_READ = C.PROT_READ + PROT_WRITE = C.PROT_WRITE + PROT_EXEC = C.PROT_EXEC + + MAP_ANON = C.MAP_ANONYMOUS + MAP_PRIVATE = C.MAP_PRIVATE + MAP_FIXED = C.MAP_FIXED + + MADV_DONTNEED = C.MADV_DONTNEED + + SA_RESTART = C.SA_RESTART + SA_ONSTACK = C.SA_ONSTACK + SA_RESTORER = C.SA_RESTORER + SA_SIGINFO = C.SA_SIGINFO + + SIGHUP = C.SIGHUP + SIGINT = C.SIGINT + SIGQUIT = C.SIGQUIT + SIGILL = C.SIGILL + SIGTRAP = C.SIGTRAP + SIGABRT = C.SIGABRT + SIGBUS = C.SIGBUS + SIGFPE = C.SIGFPE + SIGKILL = C.SIGKILL + SIGUSR1 = C.SIGUSR1 + SIGSEGV = C.SIGSEGV + SIGUSR2 = C.SIGUSR2 + SIGPIPE = C.SIGPIPE + SIGALRM = C.SIGALRM + SIGSTKFLT = C.SIGSTKFLT + SIGCHLD = C.SIGCHLD + SIGCONT = C.SIGCONT + SIGSTOP = C.SIGSTOP + SIGTSTP = C.SIGTSTP + SIGTTIN = C.SIGTTIN + SIGTTOU = C.SIGTTOU + SIGURG = C.SIGURG + SIGXCPU = C.SIGXCPU + SIGXFSZ = C.SIGXFSZ + SIGVTALRM = C.SIGVTALRM + SIGPROF = C.SIGPROF + SIGWINCH = C.SIGWINCH + SIGIO = C.SIGIO + SIGPWR = C.SIGPWR + SIGSYS = C.SIGSYS + + FPE_INTDIV = C.FPE_INTDIV + FPE_INTOVF = C.FPE_INTOVF + FPE_FLTDIV = C.FPE_FLTDIV + FPE_FLTOVF = C.FPE_FLTOVF + FPE_FLTUND = C.FPE_FLTUND + FPE_FLTRES = C.FPE_FLTRES + FPE_FLTINV = C.FPE_FLTINV + FPE_FLTSUB = C.FPE_FLTSUB + + BUS_ADRALN = C.BUS_ADRALN + BUS_ADRERR = C.BUS_ADRERR + BUS_OBJERR = C.BUS_OBJERR + + SEGV_MAPERR = C.SEGV_MAPERR + SEGV_ACCERR = C.SEGV_ACCERR + + ITIMER_REAL = C.ITIMER_REAL + ITIMER_VIRTUAL = C.ITIMER_VIRTUAL + ITIMER_PROF = C.ITIMER_PROF + + O_RDONLY = C.O_RDONLY + O_CLOEXEC = C.O_CLOEXEC +) + +type Fpreg C.struct__fpreg +type Fpxreg C.struct__fpxreg +type Xmmreg C.struct__xmmreg +type Fpstate C.struct__fpstate +type Timespec C.struct_timespec +type Timeval C.struct_timeval +type Sigaction C.struct_kernel_sigaction +type Siginfo C.siginfo_t +type Sigaltstack C.struct_sigaltstack +type Sigcontext C.struct_sigcontext +type Ucontext C.struct_ucontext +type Itimerval C.struct_itimerval diff --git a/src/pkg/runtime/defs_arm_linux.go b/src/pkg/runtime/defs_arm_linux.go new file mode 100644 index 000000000..2063efb06 --- /dev/null +++ b/src/pkg/runtime/defs_arm_linux.go @@ -0,0 +1,125 @@ +// 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. + +// +build ignore + +/* +Input to cgo. +On a Debian Lenny arm linux distribution: + +cgo -cdefs defs_arm.c >arm/defs.h +*/ + +package runtime + +/* +#cgo CFLAGS: -I/usr/src/linux-headers-2.6.26-2-versatile/include + +#define __ARCH_SI_UID_T int +#include <asm/signal.h> +#include <asm/mman.h> +#include <asm/sigcontext.h> +#include <asm/ucontext.h> +#include <asm/siginfo.h> +#include <linux/time.h> + +struct xsiginfo { + int si_signo; + int si_errno; + int si_code; + char _sifields[4]; +}; + +#undef sa_handler +#undef sa_flags +#undef sa_restorer +#undef sa_mask + +struct xsigaction { + void (*sa_handler)(void); + unsigned long sa_flags; + void (*sa_restorer)(void); + unsigned int sa_mask; // mask last for extensibility +}; +*/ +import "C" + +const ( + PROT_NONE = C.PROT_NONE + PROT_READ = C.PROT_READ + PROT_WRITE = C.PROT_WRITE + PROT_EXEC = C.PROT_EXEC + + MAP_ANON = C.MAP_ANONYMOUS + MAP_PRIVATE = C.MAP_PRIVATE + MAP_FIXED = C.MAP_FIXED + + MADV_DONTNEED = C.MADV_DONTNEED + + SA_RESTART = C.SA_RESTART + SA_ONSTACK = C.SA_ONSTACK + SA_RESTORER = C.SA_RESTORER + SA_SIGINFO = C.SA_SIGINFO + + SIGHUP = C.SIGHUP + SIGINT = C.SIGINT + SIGQUIT = C.SIGQUIT + SIGILL = C.SIGILL + SIGTRAP = C.SIGTRAP + SIGABRT = C.SIGABRT + SIGBUS = C.SIGBUS + SIGFPE = C.SIGFPE + SIGKILL = C.SIGKILL + SIGUSR1 = C.SIGUSR1 + SIGSEGV = C.SIGSEGV + SIGUSR2 = C.SIGUSR2 + SIGPIPE = C.SIGPIPE + SIGALRM = C.SIGALRM + SIGSTKFLT = C.SIGSTKFLT + SIGCHLD = C.SIGCHLD + SIGCONT = C.SIGCONT + SIGSTOP = C.SIGSTOP + SIGTSTP = C.SIGTSTP + SIGTTIN = C.SIGTTIN + SIGTTOU = C.SIGTTOU + SIGURG = C.SIGURG + SIGXCPU = C.SIGXCPU + SIGXFSZ = C.SIGXFSZ + SIGVTALRM = C.SIGVTALRM + SIGPROF = C.SIGPROF + SIGWINCH = C.SIGWINCH + SIGIO = C.SIGIO + SIGPWR = C.SIGPWR + SIGSYS = C.SIGSYS + + FPE_INTDIV = C.FPE_INTDIV & 0xFFFF + FPE_INTOVF = C.FPE_INTOVF & 0xFFFF + FPE_FLTDIV = C.FPE_FLTDIV & 0xFFFF + FPE_FLTOVF = C.FPE_FLTOVF & 0xFFFF + FPE_FLTUND = C.FPE_FLTUND & 0xFFFF + FPE_FLTRES = C.FPE_FLTRES & 0xFFFF + FPE_FLTINV = C.FPE_FLTINV & 0xFFFF + FPE_FLTSUB = C.FPE_FLTSUB & 0xFFFF + + BUS_ADRALN = C.BUS_ADRALN & 0xFFFF + BUS_ADRERR = C.BUS_ADRERR & 0xFFFF + BUS_OBJERR = C.BUS_OBJERR & 0xFFFF + + SEGV_MAPERR = C.SEGV_MAPERR & 0xFFFF + SEGV_ACCERR = C.SEGV_ACCERR & 0xFFFF + + ITIMER_REAL = C.ITIMER_REAL + ITIMER_PROF = C.ITIMER_PROF + ITIMER_VIRTUAL = C.ITIMER_VIRTUAL +) + +type Sigset C.sigset_t +type Timespec C.struct_timespec +type Sigaltstack C.struct_sigaltstack +type Sigcontext C.struct_sigcontext +type Ucontext C.struct_ucontext +type Timeval C.struct_timeval +type Itimerval C.struct_itimerval +type Siginfo C.struct_xsiginfo +type Sigaction C.struct_xsigaction diff --git a/src/pkg/runtime/defs_darwin.go b/src/pkg/runtime/defs_darwin.go new file mode 100644 index 000000000..7f22b0b8e --- /dev/null +++ b/src/pkg/runtime/defs_darwin.go @@ -0,0 +1,163 @@ +// 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. + +// +build ignore + +/* +Input to cgo. + +GOARCH=amd64 cgo -cdefs defs_darwin.go >defs_darwin_amd64.h +GOARCH=386 cgo -cdefs defs_darwin.go >defs_darwin_386.h +*/ + +package runtime + +/* +#define __DARWIN_UNIX03 0 +#include <mach/mach.h> +#include <mach/message.h> +#include <sys/types.h> +#include <sys/time.h> +#include <signal.h> +#include <sys/mman.h> +*/ +import "C" + +const ( + PROT_NONE = C.PROT_NONE + PROT_READ = C.PROT_READ + PROT_WRITE = C.PROT_WRITE + PROT_EXEC = C.PROT_EXEC + + MAP_ANON = C.MAP_ANON + MAP_PRIVATE = C.MAP_PRIVATE + MAP_FIXED = C.MAP_FIXED + + MADV_DONTNEED = C.MADV_DONTNEED + MADV_FREE = C.MADV_FREE + + MACH_MSG_TYPE_MOVE_RECEIVE = C.MACH_MSG_TYPE_MOVE_RECEIVE + MACH_MSG_TYPE_MOVE_SEND = C.MACH_MSG_TYPE_MOVE_SEND + MACH_MSG_TYPE_MOVE_SEND_ONCE = C.MACH_MSG_TYPE_MOVE_SEND_ONCE + MACH_MSG_TYPE_COPY_SEND = C.MACH_MSG_TYPE_COPY_SEND + MACH_MSG_TYPE_MAKE_SEND = C.MACH_MSG_TYPE_MAKE_SEND + MACH_MSG_TYPE_MAKE_SEND_ONCE = C.MACH_MSG_TYPE_MAKE_SEND_ONCE + MACH_MSG_TYPE_COPY_RECEIVE = C.MACH_MSG_TYPE_COPY_RECEIVE + + MACH_MSG_PORT_DESCRIPTOR = C.MACH_MSG_PORT_DESCRIPTOR + MACH_MSG_OOL_DESCRIPTOR = C.MACH_MSG_OOL_DESCRIPTOR + MACH_MSG_OOL_PORTS_DESCRIPTOR = C.MACH_MSG_OOL_PORTS_DESCRIPTOR + MACH_MSG_OOL_VOLATILE_DESCRIPTOR = C.MACH_MSG_OOL_VOLATILE_DESCRIPTOR + + MACH_MSGH_BITS_COMPLEX = C.MACH_MSGH_BITS_COMPLEX + + MACH_SEND_MSG = C.MACH_SEND_MSG + MACH_RCV_MSG = C.MACH_RCV_MSG + MACH_RCV_LARGE = C.MACH_RCV_LARGE + + MACH_SEND_TIMEOUT = C.MACH_SEND_TIMEOUT + MACH_SEND_INTERRUPT = C.MACH_SEND_INTERRUPT + MACH_SEND_ALWAYS = C.MACH_SEND_ALWAYS + MACH_SEND_TRAILER = C.MACH_SEND_TRAILER + MACH_RCV_TIMEOUT = C.MACH_RCV_TIMEOUT + MACH_RCV_NOTIFY = C.MACH_RCV_NOTIFY + MACH_RCV_INTERRUPT = C.MACH_RCV_INTERRUPT + MACH_RCV_OVERWRITE = C.MACH_RCV_OVERWRITE + + NDR_PROTOCOL_2_0 = C.NDR_PROTOCOL_2_0 + NDR_INT_BIG_ENDIAN = C.NDR_INT_BIG_ENDIAN + NDR_INT_LITTLE_ENDIAN = C.NDR_INT_LITTLE_ENDIAN + NDR_FLOAT_IEEE = C.NDR_FLOAT_IEEE + NDR_CHAR_ASCII = C.NDR_CHAR_ASCII + + SA_SIGINFO = C.SA_SIGINFO + SA_RESTART = C.SA_RESTART + SA_ONSTACK = C.SA_ONSTACK + SA_USERTRAMP = C.SA_USERTRAMP + SA_64REGSET = C.SA_64REGSET + + SIGHUP = C.SIGHUP + SIGINT = C.SIGINT + SIGQUIT = C.SIGQUIT + SIGILL = C.SIGILL + SIGTRAP = C.SIGTRAP + SIGABRT = C.SIGABRT + SIGEMT = C.SIGEMT + SIGFPE = C.SIGFPE + SIGKILL = C.SIGKILL + SIGBUS = C.SIGBUS + SIGSEGV = C.SIGSEGV + SIGSYS = C.SIGSYS + SIGPIPE = C.SIGPIPE + SIGALRM = C.SIGALRM + SIGTERM = C.SIGTERM + SIGURG = C.SIGURG + SIGSTOP = C.SIGSTOP + SIGTSTP = C.SIGTSTP + SIGCONT = C.SIGCONT + SIGCHLD = C.SIGCHLD + SIGTTIN = C.SIGTTIN + SIGTTOU = C.SIGTTOU + SIGIO = C.SIGIO + SIGXCPU = C.SIGXCPU + SIGXFSZ = C.SIGXFSZ + SIGVTALRM = C.SIGVTALRM + SIGPROF = C.SIGPROF + SIGWINCH = C.SIGWINCH + SIGINFO = C.SIGINFO + SIGUSR1 = C.SIGUSR1 + SIGUSR2 = C.SIGUSR2 + + FPE_INTDIV = C.FPE_INTDIV + FPE_INTOVF = C.FPE_INTOVF + FPE_FLTDIV = C.FPE_FLTDIV + FPE_FLTOVF = C.FPE_FLTOVF + FPE_FLTUND = C.FPE_FLTUND + FPE_FLTRES = C.FPE_FLTRES + FPE_FLTINV = C.FPE_FLTINV + FPE_FLTSUB = C.FPE_FLTSUB + + BUS_ADRALN = C.BUS_ADRALN + BUS_ADRERR = C.BUS_ADRERR + BUS_OBJERR = C.BUS_OBJERR + + SEGV_MAPERR = C.SEGV_MAPERR + SEGV_ACCERR = C.SEGV_ACCERR + + ITIMER_REAL = C.ITIMER_REAL + ITIMER_VIRTUAL = C.ITIMER_VIRTUAL + ITIMER_PROF = C.ITIMER_PROF +) + +type MachBody C.mach_msg_body_t +type MachHeader C.mach_msg_header_t +type MachNDR C.NDR_record_t +type MachPort C.mach_msg_port_descriptor_t + +type StackT C.struct_sigaltstack +type Sighandler C.union___sigaction_u + +type Sigaction C.struct___sigaction // used in syscalls +// type Sigaction C.struct_sigaction // used by the C library +type Sigval C.union_sigval +type Siginfo C.siginfo_t +type Timeval C.struct_timeval +type Itimerval C.struct_itimerval + +type FPControl C.struct_fp_control +type FPStatus C.struct_fp_status +type RegMMST C.struct_mmst_reg +type RegXMM C.struct_xmm_reg + +type Regs64 C.struct_x86_thread_state64 +type FloatState64 C.struct_x86_float_state64 +type ExceptionState64 C.struct_x86_exception_state64 +type Mcontext64 C.struct_mcontext64 + +type Regs32 C.struct_i386_thread_state +type FloatState32 C.struct_i386_float_state +type ExceptionState32 C.struct_i386_exception_state +type Mcontext32 C.struct_mcontext32 + +type Ucontext C.struct_ucontext diff --git a/src/pkg/runtime/defs_darwin_386.h b/src/pkg/runtime/defs_darwin_386.h new file mode 100644 index 000000000..92732f460 --- /dev/null +++ b/src/pkg/runtime/defs_darwin_386.h @@ -0,0 +1,366 @@ +// Created by cgo -cdefs - DO NOT EDIT +// cgo -cdefs defs_darwin.go + + +enum { + PROT_NONE = 0x0, + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + + MAP_ANON = 0x1000, + MAP_PRIVATE = 0x2, + MAP_FIXED = 0x10, + + MADV_DONTNEED = 0x4, + MADV_FREE = 0x5, + + MACH_MSG_TYPE_MOVE_RECEIVE = 0x10, + MACH_MSG_TYPE_MOVE_SEND = 0x11, + MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12, + MACH_MSG_TYPE_COPY_SEND = 0x13, + MACH_MSG_TYPE_MAKE_SEND = 0x14, + MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15, + MACH_MSG_TYPE_COPY_RECEIVE = 0x16, + + MACH_MSG_PORT_DESCRIPTOR = 0x0, + MACH_MSG_OOL_DESCRIPTOR = 0x1, + MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2, + MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3, + + MACH_MSGH_BITS_COMPLEX = 0x80000000, + + MACH_SEND_MSG = 0x1, + MACH_RCV_MSG = 0x2, + MACH_RCV_LARGE = 0x4, + + MACH_SEND_TIMEOUT = 0x10, + MACH_SEND_INTERRUPT = 0x40, + MACH_SEND_ALWAYS = 0x10000, + MACH_SEND_TRAILER = 0x20000, + MACH_RCV_TIMEOUT = 0x100, + MACH_RCV_NOTIFY = 0x200, + MACH_RCV_INTERRUPT = 0x400, + MACH_RCV_OVERWRITE = 0x1000, + + NDR_PROTOCOL_2_0 = 0x0, + NDR_INT_BIG_ENDIAN = 0x0, + NDR_INT_LITTLE_ENDIAN = 0x1, + NDR_FLOAT_IEEE = 0x0, + NDR_CHAR_ASCII = 0x0, + + SA_SIGINFO = 0x40, + SA_RESTART = 0x2, + SA_ONSTACK = 0x1, + SA_USERTRAMP = 0x100, + SA_64REGSET = 0x200, + + SIGHUP = 0x1, + SIGINT = 0x2, + SIGQUIT = 0x3, + SIGILL = 0x4, + SIGTRAP = 0x5, + SIGABRT = 0x6, + SIGEMT = 0x7, + SIGFPE = 0x8, + SIGKILL = 0x9, + SIGBUS = 0xa, + SIGSEGV = 0xb, + SIGSYS = 0xc, + SIGPIPE = 0xd, + SIGALRM = 0xe, + SIGTERM = 0xf, + SIGURG = 0x10, + SIGSTOP = 0x11, + SIGTSTP = 0x12, + SIGCONT = 0x13, + SIGCHLD = 0x14, + SIGTTIN = 0x15, + SIGTTOU = 0x16, + SIGIO = 0x17, + SIGXCPU = 0x18, + SIGXFSZ = 0x19, + SIGVTALRM = 0x1a, + SIGPROF = 0x1b, + SIGWINCH = 0x1c, + SIGINFO = 0x1d, + SIGUSR1 = 0x1e, + SIGUSR2 = 0x1f, + + FPE_INTDIV = 0x7, + FPE_INTOVF = 0x8, + FPE_FLTDIV = 0x1, + FPE_FLTOVF = 0x2, + FPE_FLTUND = 0x3, + FPE_FLTRES = 0x4, + FPE_FLTINV = 0x5, + FPE_FLTSUB = 0x6, + + BUS_ADRALN = 0x1, + BUS_ADRERR = 0x2, + BUS_OBJERR = 0x3, + + SEGV_MAPERR = 0x1, + SEGV_ACCERR = 0x2, + + ITIMER_REAL = 0x0, + ITIMER_VIRTUAL = 0x1, + ITIMER_PROF = 0x2, +}; + +typedef struct MachBody MachBody; +typedef struct MachHeader MachHeader; +typedef struct MachNDR MachNDR; +typedef struct MachPort MachPort; +typedef struct StackT StackT; +typedef struct Sigaction Sigaction; +typedef struct Siginfo Siginfo; +typedef struct Timeval Timeval; +typedef struct Itimerval Itimerval; +typedef struct FPControl FPControl; +typedef struct FPStatus FPStatus; +typedef struct RegMMST RegMMST; +typedef struct RegXMM RegXMM; +typedef struct Regs64 Regs64; +typedef struct FloatState64 FloatState64; +typedef struct ExceptionState64 ExceptionState64; +typedef struct Mcontext64 Mcontext64; +typedef struct Regs32 Regs32; +typedef struct FloatState32 FloatState32; +typedef struct ExceptionState32 ExceptionState32; +typedef struct Mcontext32 Mcontext32; +typedef struct Ucontext Ucontext; + +#pragma pack on + +struct MachBody { + uint32 msgh_descriptor_count; +}; +struct MachHeader { + uint32 msgh_bits; + uint32 msgh_size; + uint32 msgh_remote_port; + uint32 msgh_local_port; + uint32 msgh_reserved; + int32 msgh_id; +}; +struct MachNDR { + uint8 mig_vers; + uint8 if_vers; + uint8 reserved1; + uint8 mig_encoding; + uint8 int_rep; + uint8 char_rep; + uint8 float_rep; + uint8 reserved2; +}; +struct MachPort { + uint32 name; + uint32 pad1; + uint16 pad2; + uint8 disposition; + uint8 type; +}; + +struct StackT { + byte *ss_sp; + uint32 ss_size; + int32 ss_flags; +}; +typedef byte Sighandler[4]; + +struct Sigaction { + Sighandler __sigaction_u; + void *sa_tramp; + uint32 sa_mask; + int32 sa_flags; +}; + +typedef byte Sigval[4]; +struct Siginfo { + int32 si_signo; + int32 si_errno; + int32 si_code; + int32 si_pid; + uint32 si_uid; + int32 si_status; + byte *si_addr; + Sigval si_value; + int32 si_band; + uint32 __pad[7]; +}; +struct Timeval { + int32 tv_sec; + int32 tv_usec; +}; +struct Itimerval { + Timeval it_interval; + Timeval it_value; +}; + +struct FPControl { + byte Pad_cgo_0[2]; +}; +struct FPStatus { + byte Pad_cgo_0[2]; +}; +struct RegMMST { + int8 mmst_reg[10]; + int8 mmst_rsrv[6]; +}; +struct RegXMM { + int8 xmm_reg[16]; +}; + +struct Regs64 { + uint64 rax; + uint64 rbx; + uint64 rcx; + uint64 rdx; + uint64 rdi; + uint64 rsi; + uint64 rbp; + uint64 rsp; + uint64 r8; + uint64 r9; + uint64 r10; + uint64 r11; + uint64 r12; + uint64 r13; + uint64 r14; + uint64 r15; + uint64 rip; + uint64 rflags; + uint64 cs; + uint64 fs; + uint64 gs; +}; +struct FloatState64 { + int32 fpu_reserved[2]; + FPControl fpu_fcw; + FPStatus fpu_fsw; + uint8 fpu_ftw; + uint8 fpu_rsrv1; + uint16 fpu_fop; + uint32 fpu_ip; + uint16 fpu_cs; + uint16 fpu_rsrv2; + uint32 fpu_dp; + uint16 fpu_ds; + uint16 fpu_rsrv3; + uint32 fpu_mxcsr; + uint32 fpu_mxcsrmask; + RegMMST fpu_stmm0; + RegMMST fpu_stmm1; + RegMMST fpu_stmm2; + RegMMST fpu_stmm3; + RegMMST fpu_stmm4; + RegMMST fpu_stmm5; + RegMMST fpu_stmm6; + RegMMST fpu_stmm7; + RegXMM fpu_xmm0; + RegXMM fpu_xmm1; + RegXMM fpu_xmm2; + RegXMM fpu_xmm3; + RegXMM fpu_xmm4; + RegXMM fpu_xmm5; + RegXMM fpu_xmm6; + RegXMM fpu_xmm7; + RegXMM fpu_xmm8; + RegXMM fpu_xmm9; + RegXMM fpu_xmm10; + RegXMM fpu_xmm11; + RegXMM fpu_xmm12; + RegXMM fpu_xmm13; + RegXMM fpu_xmm14; + RegXMM fpu_xmm15; + int8 fpu_rsrv4[96]; + int32 fpu_reserved1; +}; +struct ExceptionState64 { + uint16 trapno; + uint16 cpu; + uint32 err; + uint64 faultvaddr; +}; +struct Mcontext64 { + ExceptionState64 es; + Regs64 ss; + FloatState64 fs; +}; + +struct Regs32 { + uint32 eax; + uint32 ebx; + uint32 ecx; + uint32 edx; + uint32 edi; + uint32 esi; + uint32 ebp; + uint32 esp; + uint32 ss; + uint32 eflags; + uint32 eip; + uint32 cs; + uint32 ds; + uint32 es; + uint32 fs; + uint32 gs; +}; +struct FloatState32 { + int32 fpu_reserved[2]; + FPControl fpu_fcw; + FPStatus fpu_fsw; + uint8 fpu_ftw; + uint8 fpu_rsrv1; + uint16 fpu_fop; + uint32 fpu_ip; + uint16 fpu_cs; + uint16 fpu_rsrv2; + uint32 fpu_dp; + uint16 fpu_ds; + uint16 fpu_rsrv3; + uint32 fpu_mxcsr; + uint32 fpu_mxcsrmask; + RegMMST fpu_stmm0; + RegMMST fpu_stmm1; + RegMMST fpu_stmm2; + RegMMST fpu_stmm3; + RegMMST fpu_stmm4; + RegMMST fpu_stmm5; + RegMMST fpu_stmm6; + RegMMST fpu_stmm7; + RegXMM fpu_xmm0; + RegXMM fpu_xmm1; + RegXMM fpu_xmm2; + RegXMM fpu_xmm3; + RegXMM fpu_xmm4; + RegXMM fpu_xmm5; + RegXMM fpu_xmm6; + RegXMM fpu_xmm7; + int8 fpu_rsrv4[224]; + int32 fpu_reserved1; +}; +struct ExceptionState32 { + uint16 trapno; + uint16 cpu; + uint32 err; + uint32 faultvaddr; +}; +struct Mcontext32 { + ExceptionState32 es; + Regs32 ss; + FloatState32 fs; +}; + +struct Ucontext { + int32 uc_onstack; + uint32 uc_sigmask; + StackT uc_stack; + Ucontext *uc_link; + uint32 uc_mcsize; + Mcontext32 *uc_mcontext; +}; + + +#pragma pack off diff --git a/src/pkg/runtime/defs_darwin_amd64.h b/src/pkg/runtime/defs_darwin_amd64.h new file mode 100644 index 000000000..d4fbfef49 --- /dev/null +++ b/src/pkg/runtime/defs_darwin_amd64.h @@ -0,0 +1,369 @@ +// Created by cgo -cdefs - DO NOT EDIT +// cgo -cdefs defs_darwin.go + + +enum { + PROT_NONE = 0x0, + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + + MAP_ANON = 0x1000, + MAP_PRIVATE = 0x2, + MAP_FIXED = 0x10, + + MADV_DONTNEED = 0x4, + MADV_FREE = 0x5, + + MACH_MSG_TYPE_MOVE_RECEIVE = 0x10, + MACH_MSG_TYPE_MOVE_SEND = 0x11, + MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12, + MACH_MSG_TYPE_COPY_SEND = 0x13, + MACH_MSG_TYPE_MAKE_SEND = 0x14, + MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15, + MACH_MSG_TYPE_COPY_RECEIVE = 0x16, + + MACH_MSG_PORT_DESCRIPTOR = 0x0, + MACH_MSG_OOL_DESCRIPTOR = 0x1, + MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2, + MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3, + + MACH_MSGH_BITS_COMPLEX = 0x80000000, + + MACH_SEND_MSG = 0x1, + MACH_RCV_MSG = 0x2, + MACH_RCV_LARGE = 0x4, + + MACH_SEND_TIMEOUT = 0x10, + MACH_SEND_INTERRUPT = 0x40, + MACH_SEND_ALWAYS = 0x10000, + MACH_SEND_TRAILER = 0x20000, + MACH_RCV_TIMEOUT = 0x100, + MACH_RCV_NOTIFY = 0x200, + MACH_RCV_INTERRUPT = 0x400, + MACH_RCV_OVERWRITE = 0x1000, + + NDR_PROTOCOL_2_0 = 0x0, + NDR_INT_BIG_ENDIAN = 0x0, + NDR_INT_LITTLE_ENDIAN = 0x1, + NDR_FLOAT_IEEE = 0x0, + NDR_CHAR_ASCII = 0x0, + + SA_SIGINFO = 0x40, + SA_RESTART = 0x2, + SA_ONSTACK = 0x1, + SA_USERTRAMP = 0x100, + SA_64REGSET = 0x200, + + SIGHUP = 0x1, + SIGINT = 0x2, + SIGQUIT = 0x3, + SIGILL = 0x4, + SIGTRAP = 0x5, + SIGABRT = 0x6, + SIGEMT = 0x7, + SIGFPE = 0x8, + SIGKILL = 0x9, + SIGBUS = 0xa, + SIGSEGV = 0xb, + SIGSYS = 0xc, + SIGPIPE = 0xd, + SIGALRM = 0xe, + SIGTERM = 0xf, + SIGURG = 0x10, + SIGSTOP = 0x11, + SIGTSTP = 0x12, + SIGCONT = 0x13, + SIGCHLD = 0x14, + SIGTTIN = 0x15, + SIGTTOU = 0x16, + SIGIO = 0x17, + SIGXCPU = 0x18, + SIGXFSZ = 0x19, + SIGVTALRM = 0x1a, + SIGPROF = 0x1b, + SIGWINCH = 0x1c, + SIGINFO = 0x1d, + SIGUSR1 = 0x1e, + SIGUSR2 = 0x1f, + + FPE_INTDIV = 0x7, + FPE_INTOVF = 0x8, + FPE_FLTDIV = 0x1, + FPE_FLTOVF = 0x2, + FPE_FLTUND = 0x3, + FPE_FLTRES = 0x4, + FPE_FLTINV = 0x5, + FPE_FLTSUB = 0x6, + + BUS_ADRALN = 0x1, + BUS_ADRERR = 0x2, + BUS_OBJERR = 0x3, + + SEGV_MAPERR = 0x1, + SEGV_ACCERR = 0x2, + + ITIMER_REAL = 0x0, + ITIMER_VIRTUAL = 0x1, + ITIMER_PROF = 0x2, +}; + +typedef struct MachBody MachBody; +typedef struct MachHeader MachHeader; +typedef struct MachNDR MachNDR; +typedef struct MachPort MachPort; +typedef struct StackT StackT; +typedef struct Sigaction Sigaction; +typedef struct Siginfo Siginfo; +typedef struct Timeval Timeval; +typedef struct Itimerval Itimerval; +typedef struct FPControl FPControl; +typedef struct FPStatus FPStatus; +typedef struct RegMMST RegMMST; +typedef struct RegXMM RegXMM; +typedef struct Regs64 Regs64; +typedef struct FloatState64 FloatState64; +typedef struct ExceptionState64 ExceptionState64; +typedef struct Mcontext64 Mcontext64; +typedef struct Regs32 Regs32; +typedef struct FloatState32 FloatState32; +typedef struct ExceptionState32 ExceptionState32; +typedef struct Mcontext32 Mcontext32; +typedef struct Ucontext Ucontext; + +#pragma pack on + +struct MachBody { + uint32 msgh_descriptor_count; +}; +struct MachHeader { + uint32 msgh_bits; + uint32 msgh_size; + uint32 msgh_remote_port; + uint32 msgh_local_port; + uint32 msgh_reserved; + int32 msgh_id; +}; +struct MachNDR { + uint8 mig_vers; + uint8 if_vers; + uint8 reserved1; + uint8 mig_encoding; + uint8 int_rep; + uint8 char_rep; + uint8 float_rep; + uint8 reserved2; +}; +struct MachPort { + uint32 name; + uint32 pad1; + uint16 pad2; + uint8 disposition; + uint8 type; +}; + +struct StackT { + byte *ss_sp; + uint64 ss_size; + int32 ss_flags; + byte Pad_cgo_0[4]; +}; +typedef byte Sighandler[8]; + +struct Sigaction { + Sighandler __sigaction_u; + void *sa_tramp; + uint32 sa_mask; + int32 sa_flags; +}; + +typedef byte Sigval[8]; +struct Siginfo { + int32 si_signo; + int32 si_errno; + int32 si_code; + int32 si_pid; + uint32 si_uid; + int32 si_status; + byte *si_addr; + Sigval si_value; + int64 si_band; + uint64 __pad[7]; +}; +struct Timeval { + int64 tv_sec; + int32 tv_usec; + byte Pad_cgo_0[4]; +}; +struct Itimerval { + Timeval it_interval; + Timeval it_value; +}; + +struct FPControl { + byte Pad_cgo_0[2]; +}; +struct FPStatus { + byte Pad_cgo_0[2]; +}; +struct RegMMST { + int8 mmst_reg[10]; + int8 mmst_rsrv[6]; +}; +struct RegXMM { + int8 xmm_reg[16]; +}; + +struct Regs64 { + uint64 rax; + uint64 rbx; + uint64 rcx; + uint64 rdx; + uint64 rdi; + uint64 rsi; + uint64 rbp; + uint64 rsp; + uint64 r8; + uint64 r9; + uint64 r10; + uint64 r11; + uint64 r12; + uint64 r13; + uint64 r14; + uint64 r15; + uint64 rip; + uint64 rflags; + uint64 cs; + uint64 fs; + uint64 gs; +}; +struct FloatState64 { + int32 fpu_reserved[2]; + FPControl fpu_fcw; + FPStatus fpu_fsw; + uint8 fpu_ftw; + uint8 fpu_rsrv1; + uint16 fpu_fop; + uint32 fpu_ip; + uint16 fpu_cs; + uint16 fpu_rsrv2; + uint32 fpu_dp; + uint16 fpu_ds; + uint16 fpu_rsrv3; + uint32 fpu_mxcsr; + uint32 fpu_mxcsrmask; + RegMMST fpu_stmm0; + RegMMST fpu_stmm1; + RegMMST fpu_stmm2; + RegMMST fpu_stmm3; + RegMMST fpu_stmm4; + RegMMST fpu_stmm5; + RegMMST fpu_stmm6; + RegMMST fpu_stmm7; + RegXMM fpu_xmm0; + RegXMM fpu_xmm1; + RegXMM fpu_xmm2; + RegXMM fpu_xmm3; + RegXMM fpu_xmm4; + RegXMM fpu_xmm5; + RegXMM fpu_xmm6; + RegXMM fpu_xmm7; + RegXMM fpu_xmm8; + RegXMM fpu_xmm9; + RegXMM fpu_xmm10; + RegXMM fpu_xmm11; + RegXMM fpu_xmm12; + RegXMM fpu_xmm13; + RegXMM fpu_xmm14; + RegXMM fpu_xmm15; + int8 fpu_rsrv4[96]; + int32 fpu_reserved1; +}; +struct ExceptionState64 { + uint16 trapno; + uint16 cpu; + uint32 err; + uint64 faultvaddr; +}; +struct Mcontext64 { + ExceptionState64 es; + Regs64 ss; + FloatState64 fs; + byte Pad_cgo_0[4]; +}; + +struct Regs32 { + uint32 eax; + uint32 ebx; + uint32 ecx; + uint32 edx; + uint32 edi; + uint32 esi; + uint32 ebp; + uint32 esp; + uint32 ss; + uint32 eflags; + uint32 eip; + uint32 cs; + uint32 ds; + uint32 es; + uint32 fs; + uint32 gs; +}; +struct FloatState32 { + int32 fpu_reserved[2]; + FPControl fpu_fcw; + FPStatus fpu_fsw; + uint8 fpu_ftw; + uint8 fpu_rsrv1; + uint16 fpu_fop; + uint32 fpu_ip; + uint16 fpu_cs; + uint16 fpu_rsrv2; + uint32 fpu_dp; + uint16 fpu_ds; + uint16 fpu_rsrv3; + uint32 fpu_mxcsr; + uint32 fpu_mxcsrmask; + RegMMST fpu_stmm0; + RegMMST fpu_stmm1; + RegMMST fpu_stmm2; + RegMMST fpu_stmm3; + RegMMST fpu_stmm4; + RegMMST fpu_stmm5; + RegMMST fpu_stmm6; + RegMMST fpu_stmm7; + RegXMM fpu_xmm0; + RegXMM fpu_xmm1; + RegXMM fpu_xmm2; + RegXMM fpu_xmm3; + RegXMM fpu_xmm4; + RegXMM fpu_xmm5; + RegXMM fpu_xmm6; + RegXMM fpu_xmm7; + int8 fpu_rsrv4[224]; + int32 fpu_reserved1; +}; +struct ExceptionState32 { + uint16 trapno; + uint16 cpu; + uint32 err; + uint32 faultvaddr; +}; +struct Mcontext32 { + ExceptionState32 es; + Regs32 ss; + FloatState32 fs; +}; + +struct Ucontext { + int32 uc_onstack; + uint32 uc_sigmask; + StackT uc_stack; + Ucontext *uc_link; + uint64 uc_mcsize; + Mcontext64 *uc_mcontext; +}; + + +#pragma pack off diff --git a/src/pkg/runtime/defs_freebsd.go b/src/pkg/runtime/defs_freebsd.go new file mode 100644 index 000000000..306e32197 --- /dev/null +++ b/src/pkg/runtime/defs_freebsd.go @@ -0,0 +1,117 @@ +// 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. + +// +build ignore + +/* +Input to cgo. + +GOARCH=amd64 cgo -cdefs defs.go >amd64/defs.h +GOARCH=386 cgo -cdefs defs.go >386/defs.h +*/ + +package runtime + +/* +#include <sys/types.h> +#include <sys/time.h> +#include <signal.h> +#include <errno.h> +#include <sys/mman.h> +#include <sys/ucontext.h> +#include <sys/umtx.h> +#include <sys/rtprio.h> +#include <sys/thr.h> +#include <sys/_sigset.h> +#include <sys/unistd.h> +*/ +import "C" + +const ( + PROT_NONE = C.PROT_NONE + PROT_READ = C.PROT_READ + PROT_WRITE = C.PROT_WRITE + PROT_EXEC = C.PROT_EXEC + + MAP_ANON = C.MAP_ANON + MAP_PRIVATE = C.MAP_PRIVATE + MAP_FIXED = C.MAP_FIXED + + SA_SIGINFO = C.SA_SIGINFO + SA_RESTART = C.SA_RESTART + SA_ONSTACK = C.SA_ONSTACK + + UMTX_OP_WAIT = C.UMTX_OP_WAIT + UMTX_OP_WAKE = C.UMTX_OP_WAKE + + EINTR = C.EINTR + + SIGHUP = C.SIGHUP + SIGINT = C.SIGINT + SIGQUIT = C.SIGQUIT + SIGILL = C.SIGILL + SIGTRAP = C.SIGTRAP + SIGABRT = C.SIGABRT + SIGEMT = C.SIGEMT + SIGFPE = C.SIGFPE + SIGKILL = C.SIGKILL + SIGBUS = C.SIGBUS + SIGSEGV = C.SIGSEGV + SIGSYS = C.SIGSYS + SIGPIPE = C.SIGPIPE + SIGALRM = C.SIGALRM + SIGTERM = C.SIGTERM + SIGURG = C.SIGURG + SIGSTOP = C.SIGSTOP + SIGTSTP = C.SIGTSTP + SIGCONT = C.SIGCONT + SIGCHLD = C.SIGCHLD + SIGTTIN = C.SIGTTIN + SIGTTOU = C.SIGTTOU + SIGIO = C.SIGIO + SIGXCPU = C.SIGXCPU + SIGXFSZ = C.SIGXFSZ + SIGVTALRM = C.SIGVTALRM + SIGPROF = C.SIGPROF + SIGWINCH = C.SIGWINCH + SIGINFO = C.SIGINFO + SIGUSR1 = C.SIGUSR1 + SIGUSR2 = C.SIGUSR2 + + FPE_INTDIV = C.FPE_INTDIV + FPE_INTOVF = C.FPE_INTOVF + FPE_FLTDIV = C.FPE_FLTDIV + FPE_FLTOVF = C.FPE_FLTOVF + FPE_FLTUND = C.FPE_FLTUND + FPE_FLTRES = C.FPE_FLTRES + FPE_FLTINV = C.FPE_FLTINV + FPE_FLTSUB = C.FPE_FLTSUB + + BUS_ADRALN = C.BUS_ADRALN + BUS_ADRERR = C.BUS_ADRERR + BUS_OBJERR = C.BUS_OBJERR + + SEGV_MAPERR = C.SEGV_MAPERR + SEGV_ACCERR = C.SEGV_ACCERR + + ITIMER_REAL = C.ITIMER_REAL + ITIMER_VIRTUAL = C.ITIMER_VIRTUAL + ITIMER_PROF = C.ITIMER_PROF +) + +type Rtprio C.struct_rtprio +type ThrParam C.struct_thr_param +type Sigaltstack C.struct_sigaltstack +type Sigset C.struct___sigset +type Sigval C.union_sigval +type StackT C.stack_t + +type Siginfo C.siginfo_t + +type Mcontext C.mcontext_t +type Ucontext C.ucontext_t + +type Timespec C.struct_timespec +type Timeval C.struct_timeval +type Itimerval C.struct_itimerval diff --git a/src/pkg/runtime/freebsd/386/defs.h b/src/pkg/runtime/defs_freebsd_386.h index ae12b2019..29fcb8b57 100644 --- a/src/pkg/runtime/freebsd/386/defs.h +++ b/src/pkg/runtime/defs_freebsd_386.h @@ -173,6 +173,12 @@ struct Ucontext { byte pad_godefs_0[12]; }; +typedef struct Timespec Timespec; +struct Timespec { + int32 tv_sec; + int32 tv_nsec; +}; + typedef struct Timeval Timeval; struct Timeval { int32 tv_sec; diff --git a/src/pkg/runtime/freebsd/amd64/defs.h b/src/pkg/runtime/defs_freebsd_amd64.h index b101b1932..8a222dca4 100644 --- a/src/pkg/runtime/freebsd/amd64/defs.h +++ b/src/pkg/runtime/defs_freebsd_amd64.h @@ -184,6 +184,12 @@ struct Ucontext { byte pad_godefs_0[12]; }; +typedef struct Timespec Timespec; +struct Timespec { + int64 tv_sec; + int64 tv_nsec; +}; + typedef struct Timeval Timeval; struct Timeval { int64 tv_sec; diff --git a/src/pkg/runtime/defs_linux.go b/src/pkg/runtime/defs_linux.go new file mode 100644 index 000000000..c0275e111 --- /dev/null +++ b/src/pkg/runtime/defs_linux.go @@ -0,0 +1,104 @@ +// 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. + +// +build ignore + +/* +Input to cgo -cdefs + +GOARCH=amd64 cgo -cdefs defs.go defs1.go >amd64/defs.h +*/ + +package runtime + +/* +// Linux glibc and Linux kernel define different and conflicting +// definitions for struct sigaction, struct timespec, etc. +// We want the kernel ones, which are in the asm/* headers. +// But then we'd get conflicts when we include the system +// headers for things like ucontext_t, so that happens in +// a separate file, defs1.go. + +#include <asm/posix_types.h> +#define size_t __kernel_size_t +#include <asm/signal.h> +#include <asm/siginfo.h> +#include <asm/mman.h> +*/ +import "C" + +const ( + PROT_NONE = C.PROT_NONE + PROT_READ = C.PROT_READ + PROT_WRITE = C.PROT_WRITE + PROT_EXEC = C.PROT_EXEC + + MAP_ANON = C.MAP_ANONYMOUS + MAP_PRIVATE = C.MAP_PRIVATE + MAP_FIXED = C.MAP_FIXED + + MADV_DONTNEED = C.MADV_DONTNEED + + SA_RESTART = C.SA_RESTART + SA_ONSTACK = C.SA_ONSTACK + SA_RESTORER = C.SA_RESTORER + SA_SIGINFO = C.SA_SIGINFO + + SIGHUP = C.SIGHUP + SIGINT = C.SIGINT + SIGQUIT = C.SIGQUIT + SIGILL = C.SIGILL + SIGTRAP = C.SIGTRAP + SIGABRT = C.SIGABRT + SIGBUS = C.SIGBUS + SIGFPE = C.SIGFPE + SIGKILL = C.SIGKILL + SIGUSR1 = C.SIGUSR1 + SIGSEGV = C.SIGSEGV + SIGUSR2 = C.SIGUSR2 + SIGPIPE = C.SIGPIPE + SIGALRM = C.SIGALRM + SIGSTKFLT = C.SIGSTKFLT + SIGCHLD = C.SIGCHLD + SIGCONT = C.SIGCONT + SIGSTOP = C.SIGSTOP + SIGTSTP = C.SIGTSTP + SIGTTIN = C.SIGTTIN + SIGTTOU = C.SIGTTOU + SIGURG = C.SIGURG + SIGXCPU = C.SIGXCPU + SIGXFSZ = C.SIGXFSZ + SIGVTALRM = C.SIGVTALRM + SIGPROF = C.SIGPROF + SIGWINCH = C.SIGWINCH + SIGIO = C.SIGIO + SIGPWR = C.SIGPWR + SIGSYS = C.SIGSYS + + FPE_INTDIV = C.FPE_INTDIV + FPE_INTOVF = C.FPE_INTOVF + FPE_FLTDIV = C.FPE_FLTDIV + FPE_FLTOVF = C.FPE_FLTOVF + FPE_FLTUND = C.FPE_FLTUND + FPE_FLTRES = C.FPE_FLTRES + FPE_FLTINV = C.FPE_FLTINV + FPE_FLTSUB = C.FPE_FLTSUB + + BUS_ADRALN = C.BUS_ADRALN + BUS_ADRERR = C.BUS_ADRERR + BUS_OBJERR = C.BUS_OBJERR + + SEGV_MAPERR = C.SEGV_MAPERR + SEGV_ACCERR = C.SEGV_ACCERR + + ITIMER_REAL = C.ITIMER_REAL + ITIMER_VIRTUAL = C.ITIMER_VIRTUAL + ITIMER_PROF = C.ITIMER_PROF +) + +type Timespec C.struct_timespec +type Timeval C.struct_timeval +type Sigaction C.struct_sigaction +type Siginfo C.siginfo_t +type Itimerval C.struct_itimerval diff --git a/src/pkg/runtime/defs_linux_386.h b/src/pkg/runtime/defs_linux_386.h new file mode 100644 index 000000000..02760f987 --- /dev/null +++ b/src/pkg/runtime/defs_linux_386.h @@ -0,0 +1,191 @@ +// Created by cgo -cdefs - DO NOT EDIT +// cgo -cdefs defs2.go + + +enum { + PROT_NONE = 0x0, + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + + MAP_ANON = 0x20, + MAP_PRIVATE = 0x2, + MAP_FIXED = 0x10, + + MADV_DONTNEED = 0x4, + + SA_RESTART = 0x10000000, + SA_ONSTACK = 0x8000000, + SA_RESTORER = 0x4000000, + SA_SIGINFO = 0x4, + + SIGHUP = 0x1, + SIGINT = 0x2, + SIGQUIT = 0x3, + SIGILL = 0x4, + SIGTRAP = 0x5, + SIGABRT = 0x6, + SIGBUS = 0x7, + SIGFPE = 0x8, + SIGKILL = 0x9, + SIGUSR1 = 0xa, + SIGSEGV = 0xb, + SIGUSR2 = 0xc, + SIGPIPE = 0xd, + SIGALRM = 0xe, + SIGSTKFLT = 0x10, + SIGCHLD = 0x11, + SIGCONT = 0x12, + SIGSTOP = 0x13, + SIGTSTP = 0x14, + SIGTTIN = 0x15, + SIGTTOU = 0x16, + SIGURG = 0x17, + SIGXCPU = 0x18, + SIGXFSZ = 0x19, + SIGVTALRM = 0x1a, + SIGPROF = 0x1b, + SIGWINCH = 0x1c, + SIGIO = 0x1d, + SIGPWR = 0x1e, + SIGSYS = 0x1f, + + FPE_INTDIV = 0x1, + FPE_INTOVF = 0x2, + FPE_FLTDIV = 0x3, + FPE_FLTOVF = 0x4, + FPE_FLTUND = 0x5, + FPE_FLTRES = 0x6, + FPE_FLTINV = 0x7, + FPE_FLTSUB = 0x8, + + BUS_ADRALN = 0x1, + BUS_ADRERR = 0x2, + BUS_OBJERR = 0x3, + + SEGV_MAPERR = 0x1, + SEGV_ACCERR = 0x2, + + ITIMER_REAL = 0x0, + ITIMER_VIRTUAL = 0x1, + ITIMER_PROF = 0x2, + + O_RDONLY = 0x0, + O_CLOEXEC = 0x80000, +}; + +typedef struct Fpreg Fpreg; +typedef struct Fpxreg Fpxreg; +typedef struct Xmmreg Xmmreg; +typedef struct Fpstate Fpstate; +typedef struct Timespec Timespec; +typedef struct Timeval Timeval; +typedef struct Sigaction Sigaction; +typedef struct Siginfo Siginfo; +typedef struct Sigaltstack Sigaltstack; +typedef struct Sigcontext Sigcontext; +typedef struct Ucontext Ucontext; +typedef struct Itimerval Itimerval; + +#pragma pack on + +struct Fpreg { + uint16 significand[4]; + uint16 exponent; +}; +struct Fpxreg { + uint16 significand[4]; + uint16 exponent; + uint16 padding[3]; +}; +struct Xmmreg { + uint32 element[4]; +}; +struct Fpstate { + uint32 cw; + uint32 sw; + uint32 tag; + uint32 ipoff; + uint32 cssel; + uint32 dataoff; + uint32 datasel; + Fpreg _st[8]; + uint16 status; + uint16 magic; + uint32 _fxsr_env[6]; + uint32 mxcsr; + uint32 reserved; + Fpxreg _fxsr_st[8]; + Xmmreg _xmm[8]; + uint32 padding1[44]; + byte anon0[48]; +}; +struct Timespec { + int32 tv_sec; + int32 tv_nsec; +}; +struct Timeval { + int32 tv_sec; + int32 tv_usec; +}; +struct Sigaction { + void *k_sa_handler; + uint32 sa_flags; + void *sa_restorer; + uint32 sa_mask; +}; +struct Siginfo { + int32 si_signo; + int32 si_errno; + int32 si_code; + byte _sifields[116]; +}; +struct Sigaltstack { + byte *ss_sp; + int32 ss_flags; + uint32 ss_size; +}; +struct Sigcontext { + uint16 gs; + uint16 __gsh; + uint16 fs; + uint16 __fsh; + uint16 es; + uint16 __esh; + uint16 ds; + uint16 __dsh; + uint32 edi; + uint32 esi; + uint32 ebp; + uint32 esp; + uint32 ebx; + uint32 edx; + uint32 ecx; + uint32 eax; + uint32 trapno; + uint32 err; + uint32 eip; + uint16 cs; + uint16 __csh; + uint32 eflags; + uint32 esp_at_signal; + uint16 ss; + uint16 __ssh; + Fpstate *fpstate; + uint32 oldmask; + uint32 cr2; +}; +struct Ucontext { + uint32 uc_flags; + Ucontext *uc_link; + Sigaltstack uc_stack; + Sigcontext uc_mcontext; + uint32 uc_sigmask; +}; +struct Itimerval { + Timeval it_interval; + Timeval it_value; +}; + + +#pragma pack off diff --git a/src/pkg/runtime/defs_linux_amd64.h b/src/pkg/runtime/defs_linux_amd64.h new file mode 100644 index 000000000..bf5f79b0e --- /dev/null +++ b/src/pkg/runtime/defs_linux_amd64.h @@ -0,0 +1,234 @@ +// Created by cgo -cdefs - DO NOT EDIT +// cgo -cdefs defs.go defs1.go + + +enum { + PROT_NONE = 0x0, + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + + MAP_ANON = 0x20, + MAP_PRIVATE = 0x2, + MAP_FIXED = 0x10, + + MADV_DONTNEED = 0x4, + + SA_RESTART = 0x10000000, + SA_ONSTACK = 0x8000000, + SA_RESTORER = 0x4000000, + SA_SIGINFO = 0x4, + + SIGHUP = 0x1, + SIGINT = 0x2, + SIGQUIT = 0x3, + SIGILL = 0x4, + SIGTRAP = 0x5, + SIGABRT = 0x6, + SIGBUS = 0x7, + SIGFPE = 0x8, + SIGKILL = 0x9, + SIGUSR1 = 0xa, + SIGSEGV = 0xb, + SIGUSR2 = 0xc, + SIGPIPE = 0xd, + SIGALRM = 0xe, + SIGSTKFLT = 0x10, + SIGCHLD = 0x11, + SIGCONT = 0x12, + SIGSTOP = 0x13, + SIGTSTP = 0x14, + SIGTTIN = 0x15, + SIGTTOU = 0x16, + SIGURG = 0x17, + SIGXCPU = 0x18, + SIGXFSZ = 0x19, + SIGVTALRM = 0x1a, + SIGPROF = 0x1b, + SIGWINCH = 0x1c, + SIGIO = 0x1d, + SIGPWR = 0x1e, + SIGSYS = 0x1f, + + FPE_INTDIV = 0x1, + FPE_INTOVF = 0x2, + FPE_FLTDIV = 0x3, + FPE_FLTOVF = 0x4, + FPE_FLTUND = 0x5, + FPE_FLTRES = 0x6, + FPE_FLTINV = 0x7, + FPE_FLTSUB = 0x8, + + BUS_ADRALN = 0x1, + BUS_ADRERR = 0x2, + BUS_OBJERR = 0x3, + + SEGV_MAPERR = 0x1, + SEGV_ACCERR = 0x2, + + ITIMER_REAL = 0x0, + ITIMER_VIRTUAL = 0x1, + ITIMER_PROF = 0x2, +}; + +typedef struct Timespec Timespec; +typedef struct Timeval Timeval; +typedef struct Sigaction Sigaction; +typedef struct Siginfo Siginfo; +typedef struct Itimerval Itimerval; + +#pragma pack on + +struct Timespec { + int64 tv_sec; + int64 tv_nsec; +}; +struct Timeval { + int64 tv_sec; + int64 tv_usec; +}; +struct Sigaction { + void *sa_handler; + uint64 sa_flags; + void *sa_restorer; + uint64 sa_mask; +}; +struct Siginfo { + int32 si_signo; + int32 si_errno; + int32 si_code; + byte Pad_cgo_0[4]; + byte _sifields[112]; +}; +struct Itimerval { + Timeval it_interval; + Timeval it_value; +}; + + +#pragma pack off +// Created by cgo -cdefs - DO NOT EDIT +// cgo -cdefs defs.go defs1.go + + +enum { + O_RDONLY = 0x0, + O_CLOEXEC = 0x80000, +}; + +typedef struct Usigset Usigset; +typedef struct Fpxreg Fpxreg; +typedef struct Xmmreg Xmmreg; +typedef struct Fpstate Fpstate; +typedef struct Fpxreg1 Fpxreg1; +typedef struct Xmmreg1 Xmmreg1; +typedef struct Fpstate1 Fpstate1; +typedef struct Fpreg1 Fpreg1; +typedef struct Sigaltstack Sigaltstack; +typedef struct Mcontext Mcontext; +typedef struct Ucontext Ucontext; +typedef struct Sigcontext Sigcontext; + +#pragma pack on + +struct Usigset { + uint64 __val[16]; +}; +struct Fpxreg { + uint16 significand[4]; + uint16 exponent; + uint16 padding[3]; +}; +struct Xmmreg { + uint32 element[4]; +}; +struct Fpstate { + uint16 cwd; + uint16 swd; + uint16 ftw; + uint16 fop; + uint64 rip; + uint64 rdp; + uint32 mxcsr; + uint32 mxcr_mask; + Fpxreg _st[8]; + Xmmreg _xmm[16]; + uint32 padding[24]; +}; +struct Fpxreg1 { + uint16 significand[4]; + uint16 exponent; + uint16 padding[3]; +}; +struct Xmmreg1 { + uint32 element[4]; +}; +struct Fpstate1 { + uint16 cwd; + uint16 swd; + uint16 ftw; + uint16 fop; + uint64 rip; + uint64 rdp; + uint32 mxcsr; + uint32 mxcr_mask; + Fpxreg1 _st[8]; + Xmmreg1 _xmm[16]; + uint32 padding[24]; +}; +struct Fpreg1 { + uint16 significand[4]; + uint16 exponent; +}; +struct Sigaltstack { + byte *ss_sp; + int32 ss_flags; + byte Pad_cgo_0[4]; + uint64 ss_size; +}; +struct Mcontext { + int64 gregs[23]; + Fpstate *fpregs; + uint64 __reserved1[8]; +}; +struct Ucontext { + uint64 uc_flags; + Ucontext *uc_link; + Sigaltstack uc_stack; + Mcontext uc_mcontext; + Usigset uc_sigmask; + Fpstate __fpregs_mem; +}; +struct Sigcontext { + uint64 r8; + uint64 r9; + uint64 r10; + uint64 r11; + uint64 r12; + uint64 r13; + uint64 r14; + uint64 r15; + uint64 rdi; + uint64 rsi; + uint64 rbp; + uint64 rbx; + uint64 rdx; + uint64 rax; + uint64 rcx; + uint64 rsp; + uint64 rip; + uint64 eflags; + uint16 cs; + uint16 gs; + uint16 fs; + uint16 __pad0; + uint64 err; + uint64 trapno; + uint64 oldmask; + uint64 cr2; + Fpstate1 *fpstate; + uint64 __reserved1[8]; +}; + + +#pragma pack off diff --git a/src/pkg/runtime/linux/arm/defs.h b/src/pkg/runtime/defs_linux_arm.h index 09b558ed0..da97a8433 100644 --- a/src/pkg/runtime/linux/arm/defs.h +++ b/src/pkg/runtime/defs_linux_arm.h @@ -11,6 +11,7 @@ enum { MAP_ANON = 0x20, MAP_PRIVATE = 0x2, MAP_FIXED = 0x10, + MADV_DONTNEED = 0x4, SA_RESTART = 0x10000000, SA_ONSTACK = 0x8000000, SA_RESTORER = 0x4000000, diff --git a/src/pkg/runtime/defs_netbsd.go b/src/pkg/runtime/defs_netbsd.go new file mode 100644 index 000000000..47c30cf10 --- /dev/null +++ b/src/pkg/runtime/defs_netbsd.go @@ -0,0 +1,111 @@ +// 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. + +// +build ignore + +/* +Input to cgo. + +GOARCH=amd64 cgo -cdefs defs.go >amd64/defs.h +GOARCH=386 cgo -cdefs defs.go >386/defs.h +*/ + +package runtime + +/* +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/unistd.h> +#include <sys/signal.h> +#include <errno.h> +#include <signal.h> +*/ +import "C" + +const ( + PROT_NONE = C.PROT_NONE + PROT_READ = C.PROT_READ + PROT_WRITE = C.PROT_WRITE + PROT_EXEC = C.PROT_EXEC + + MAP_ANON = C.MAP_ANON + MAP_PRIVATE = C.MAP_PRIVATE + MAP_FIXED = C.MAP_FIXED + + SA_SIGINFO = C.SA_SIGINFO + SA_RESTART = C.SA_RESTART + SA_ONSTACK = C.SA_ONSTACK + + EINTR = C.EINTR + + SIGHUP = C.SIGHUP + SIGINT = C.SIGINT + SIGQUIT = C.SIGQUIT + SIGILL = C.SIGILL + SIGTRAP = C.SIGTRAP + SIGABRT = C.SIGABRT + SIGEMT = C.SIGEMT + SIGFPE = C.SIGFPE + SIGKILL = C.SIGKILL + SIGBUS = C.SIGBUS + SIGSEGV = C.SIGSEGV + SIGSYS = C.SIGSYS + SIGPIPE = C.SIGPIPE + SIGALRM = C.SIGALRM + SIGTERM = C.SIGTERM + SIGURG = C.SIGURG + SIGSTOP = C.SIGSTOP + SIGTSTP = C.SIGTSTP + SIGCONT = C.SIGCONT + SIGCHLD = C.SIGCHLD + SIGTTIN = C.SIGTTIN + SIGTTOU = C.SIGTTOU + SIGIO = C.SIGIO + SIGXCPU = C.SIGXCPU + SIGXFSZ = C.SIGXFSZ + SIGVTALRM = C.SIGVTALRM + SIGPROF = C.SIGPROF + SIGWINCH = C.SIGWINCH + SIGINFO = C.SIGINFO + SIGUSR1 = C.SIGUSR1 + SIGUSR2 = C.SIGUSR2 + + FPE_INTDIV = C.FPE_INTDIV + FPE_INTOVF = C.FPE_INTOVF + FPE_FLTDIV = C.FPE_FLTDIV + FPE_FLTOVF = C.FPE_FLTOVF + FPE_FLTUND = C.FPE_FLTUND + FPE_FLTRES = C.FPE_FLTRES + FPE_FLTINV = C.FPE_FLTINV + FPE_FLTSUB = C.FPE_FLTSUB + + BUS_ADRALN = C.BUS_ADRALN + BUS_ADRERR = C.BUS_ADRERR + BUS_OBJERR = C.BUS_OBJERR + + SEGV_MAPERR = C.SEGV_MAPERR + SEGV_ACCERR = C.SEGV_ACCERR + + ITIMER_REAL = C.ITIMER_REAL + ITIMER_VIRTUAL = C.ITIMER_VIRTUAL + ITIMER_PROF = C.ITIMER_PROF +) + +type Sigaltstack C.struct_sigaltstack +type Sigset C.sigset_t +type Siginfo C.siginfo_t +type Sigval C.union_sigval + +type StackT C.stack_t + +type Timespec C.struct_timespec +type Timeval C.struct_timeval +type Itimerval C.struct_itimerval + +// This is a hack to avoid pulling in machine/fpu.h. +type sfxsave64 struct{} +type usavefpu struct{} + +type Sigcontext C.struct_sigcontext diff --git a/src/pkg/runtime/openbsd/386/defs.h b/src/pkg/runtime/defs_netbsd_386.h index d61462c6f..aff87fb3b 100644 --- a/src/pkg/runtime/openbsd/386/defs.h +++ b/src/pkg/runtime/defs_netbsd_386.h @@ -97,6 +97,12 @@ struct StackT { int32 ss_flags; }; +typedef struct Timespec Timespec; +struct Timespec { + int32 tv_sec; + int32 tv_nsec; +}; + typedef struct Timeval Timeval; struct Timeval { int32 tv_sec; diff --git a/src/pkg/runtime/openbsd/amd64/defs.h b/src/pkg/runtime/defs_netbsd_amd64.h index 4eb5cd205..27bf4b9d6 100644 --- a/src/pkg/runtime/openbsd/amd64/defs.h +++ b/src/pkg/runtime/defs_netbsd_amd64.h @@ -100,6 +100,13 @@ struct StackT { byte pad_godefs_0[4]; }; +typedef struct Timespec Timespec; +struct Timespec { + int32 tv_sec; + byte pad_godefs_0[4]; + int64 tv_nsec; +}; + typedef struct Timeval Timeval; struct Timeval { int64 tv_sec; @@ -114,6 +121,8 @@ struct Itimerval { typedef void sfxsave64; +typedef void usavefpu; + typedef struct Sigcontext Sigcontext; struct Sigcontext { int64 sc_rdi; diff --git a/src/pkg/runtime/defs_openbsd.go b/src/pkg/runtime/defs_openbsd.go new file mode 100644 index 000000000..47c30cf10 --- /dev/null +++ b/src/pkg/runtime/defs_openbsd.go @@ -0,0 +1,111 @@ +// 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. + +// +build ignore + +/* +Input to cgo. + +GOARCH=amd64 cgo -cdefs defs.go >amd64/defs.h +GOARCH=386 cgo -cdefs defs.go >386/defs.h +*/ + +package runtime + +/* +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/unistd.h> +#include <sys/signal.h> +#include <errno.h> +#include <signal.h> +*/ +import "C" + +const ( + PROT_NONE = C.PROT_NONE + PROT_READ = C.PROT_READ + PROT_WRITE = C.PROT_WRITE + PROT_EXEC = C.PROT_EXEC + + MAP_ANON = C.MAP_ANON + MAP_PRIVATE = C.MAP_PRIVATE + MAP_FIXED = C.MAP_FIXED + + SA_SIGINFO = C.SA_SIGINFO + SA_RESTART = C.SA_RESTART + SA_ONSTACK = C.SA_ONSTACK + + EINTR = C.EINTR + + SIGHUP = C.SIGHUP + SIGINT = C.SIGINT + SIGQUIT = C.SIGQUIT + SIGILL = C.SIGILL + SIGTRAP = C.SIGTRAP + SIGABRT = C.SIGABRT + SIGEMT = C.SIGEMT + SIGFPE = C.SIGFPE + SIGKILL = C.SIGKILL + SIGBUS = C.SIGBUS + SIGSEGV = C.SIGSEGV + SIGSYS = C.SIGSYS + SIGPIPE = C.SIGPIPE + SIGALRM = C.SIGALRM + SIGTERM = C.SIGTERM + SIGURG = C.SIGURG + SIGSTOP = C.SIGSTOP + SIGTSTP = C.SIGTSTP + SIGCONT = C.SIGCONT + SIGCHLD = C.SIGCHLD + SIGTTIN = C.SIGTTIN + SIGTTOU = C.SIGTTOU + SIGIO = C.SIGIO + SIGXCPU = C.SIGXCPU + SIGXFSZ = C.SIGXFSZ + SIGVTALRM = C.SIGVTALRM + SIGPROF = C.SIGPROF + SIGWINCH = C.SIGWINCH + SIGINFO = C.SIGINFO + SIGUSR1 = C.SIGUSR1 + SIGUSR2 = C.SIGUSR2 + + FPE_INTDIV = C.FPE_INTDIV + FPE_INTOVF = C.FPE_INTOVF + FPE_FLTDIV = C.FPE_FLTDIV + FPE_FLTOVF = C.FPE_FLTOVF + FPE_FLTUND = C.FPE_FLTUND + FPE_FLTRES = C.FPE_FLTRES + FPE_FLTINV = C.FPE_FLTINV + FPE_FLTSUB = C.FPE_FLTSUB + + BUS_ADRALN = C.BUS_ADRALN + BUS_ADRERR = C.BUS_ADRERR + BUS_OBJERR = C.BUS_OBJERR + + SEGV_MAPERR = C.SEGV_MAPERR + SEGV_ACCERR = C.SEGV_ACCERR + + ITIMER_REAL = C.ITIMER_REAL + ITIMER_VIRTUAL = C.ITIMER_VIRTUAL + ITIMER_PROF = C.ITIMER_PROF +) + +type Sigaltstack C.struct_sigaltstack +type Sigset C.sigset_t +type Siginfo C.siginfo_t +type Sigval C.union_sigval + +type StackT C.stack_t + +type Timespec C.struct_timespec +type Timeval C.struct_timeval +type Itimerval C.struct_itimerval + +// This is a hack to avoid pulling in machine/fpu.h. +type sfxsave64 struct{} +type usavefpu struct{} + +type Sigcontext C.struct_sigcontext diff --git a/src/pkg/runtime/defs_openbsd_386.h b/src/pkg/runtime/defs_openbsd_386.h new file mode 100644 index 000000000..aff87fb3b --- /dev/null +++ b/src/pkg/runtime/defs_openbsd_386.h @@ -0,0 +1,146 @@ +// godefs -f -m32 defs.c + +// MACHINE GENERATED - DO NOT EDIT. + +// Constants +enum { + PROT_NONE = 0, + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + MAP_ANON = 0x1000, + MAP_PRIVATE = 0x2, + MAP_FIXED = 0x10, + SA_SIGINFO = 0x40, + SA_RESTART = 0x2, + SA_ONSTACK = 0x1, + EINTR = 0x4, + SIGHUP = 0x1, + SIGINT = 0x2, + SIGQUIT = 0x3, + SIGILL = 0x4, + SIGTRAP = 0x5, + SIGABRT = 0x6, + SIGEMT = 0x7, + SIGFPE = 0x8, + SIGKILL = 0x9, + SIGBUS = 0xa, + SIGSEGV = 0xb, + SIGSYS = 0xc, + SIGPIPE = 0xd, + SIGALRM = 0xe, + SIGTERM = 0xf, + SIGURG = 0x10, + SIGSTOP = 0x11, + SIGTSTP = 0x12, + SIGCONT = 0x13, + SIGCHLD = 0x14, + SIGTTIN = 0x15, + SIGTTOU = 0x16, + SIGIO = 0x17, + SIGXCPU = 0x18, + SIGXFSZ = 0x19, + SIGVTALRM = 0x1a, + SIGPROF = 0x1b, + SIGWINCH = 0x1c, + SIGINFO = 0x1d, + SIGUSR1 = 0x1e, + SIGUSR2 = 0x1f, + FPE_INTDIV = 0x1, + FPE_INTOVF = 0x2, + FPE_FLTDIV = 0x3, + FPE_FLTOVF = 0x4, + FPE_FLTUND = 0x5, + FPE_FLTRES = 0x6, + FPE_FLTINV = 0x7, + FPE_FLTSUB = 0x8, + BUS_ADRALN = 0x1, + BUS_ADRERR = 0x2, + BUS_OBJERR = 0x3, + SEGV_MAPERR = 0x1, + SEGV_ACCERR = 0x2, + ITIMER_REAL = 0, + ITIMER_VIRTUAL = 0x1, + ITIMER_PROF = 0x2, +}; + +// Types +#pragma pack on + +typedef struct Sigaltstack Sigaltstack; +struct Sigaltstack { + void *ss_sp; + uint32 ss_size; + int32 ss_flags; +}; + +typedef uint32 Sigset; + +typedef struct Siginfo Siginfo; +struct Siginfo { + int32 si_signo; + int32 si_code; + int32 si_errno; + byte _data[116]; +}; + +typedef union Sigval Sigval; +union Sigval { + int32 sival_int; + void *sival_ptr; +}; + +typedef struct StackT StackT; +struct StackT { + void *ss_sp; + uint32 ss_size; + int32 ss_flags; +}; + +typedef struct Timespec Timespec; +struct Timespec { + int32 tv_sec; + int32 tv_nsec; +}; + +typedef struct Timeval Timeval; +struct Timeval { + int32 tv_sec; + int32 tv_usec; +}; + +typedef struct Itimerval Itimerval; +struct Itimerval { + Timeval it_interval; + Timeval it_value; +}; + +typedef void sfxsave64; + +typedef void usavefpu; + +typedef struct Sigcontext Sigcontext; +struct Sigcontext { + int32 sc_gs; + int32 sc_fs; + int32 sc_es; + int32 sc_ds; + int32 sc_edi; + int32 sc_esi; + int32 sc_ebp; + int32 sc_ebx; + int32 sc_edx; + int32 sc_ecx; + int32 sc_eax; + int32 sc_eip; + int32 sc_cs; + int32 sc_eflags; + int32 sc_esp; + int32 sc_ss; + int32 sc_onstack; + int32 sc_mask; + int32 sc_trapno; + int32 sc_err; + usavefpu *sc_fpstate; +}; +#pragma pack off diff --git a/src/pkg/runtime/defs_openbsd_amd64.h b/src/pkg/runtime/defs_openbsd_amd64.h new file mode 100644 index 000000000..27bf4b9d6 --- /dev/null +++ b/src/pkg/runtime/defs_openbsd_amd64.h @@ -0,0 +1,158 @@ +// godefs -f -m64 defs.c + +// MACHINE GENERATED - DO NOT EDIT. + +// Constants +enum { + PROT_NONE = 0, + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + MAP_ANON = 0x1000, + MAP_PRIVATE = 0x2, + MAP_FIXED = 0x10, + SA_SIGINFO = 0x40, + SA_RESTART = 0x2, + SA_ONSTACK = 0x1, + EINTR = 0x4, + SIGHUP = 0x1, + SIGINT = 0x2, + SIGQUIT = 0x3, + SIGILL = 0x4, + SIGTRAP = 0x5, + SIGABRT = 0x6, + SIGEMT = 0x7, + SIGFPE = 0x8, + SIGKILL = 0x9, + SIGBUS = 0xa, + SIGSEGV = 0xb, + SIGSYS = 0xc, + SIGPIPE = 0xd, + SIGALRM = 0xe, + SIGTERM = 0xf, + SIGURG = 0x10, + SIGSTOP = 0x11, + SIGTSTP = 0x12, + SIGCONT = 0x13, + SIGCHLD = 0x14, + SIGTTIN = 0x15, + SIGTTOU = 0x16, + SIGIO = 0x17, + SIGXCPU = 0x18, + SIGXFSZ = 0x19, + SIGVTALRM = 0x1a, + SIGPROF = 0x1b, + SIGWINCH = 0x1c, + SIGINFO = 0x1d, + SIGUSR1 = 0x1e, + SIGUSR2 = 0x1f, + FPE_INTDIV = 0x1, + FPE_INTOVF = 0x2, + FPE_FLTDIV = 0x3, + FPE_FLTOVF = 0x4, + FPE_FLTUND = 0x5, + FPE_FLTRES = 0x6, + FPE_FLTINV = 0x7, + FPE_FLTSUB = 0x8, + BUS_ADRALN = 0x1, + BUS_ADRERR = 0x2, + BUS_OBJERR = 0x3, + SEGV_MAPERR = 0x1, + SEGV_ACCERR = 0x2, + ITIMER_REAL = 0, + ITIMER_VIRTUAL = 0x1, + ITIMER_PROF = 0x2, +}; + +// Types +#pragma pack on + +typedef struct Sigaltstack Sigaltstack; +struct Sigaltstack { + void *ss_sp; + uint64 ss_size; + int32 ss_flags; + byte pad_godefs_0[4]; +}; + +typedef uint32 Sigset; + +typedef struct Siginfo Siginfo; +struct Siginfo { + int32 si_signo; + int32 si_code; + int32 si_errno; + byte pad_godefs_0[4]; + byte _data[120]; +}; + +typedef union Sigval Sigval; +union Sigval { + int32 sival_int; + void *sival_ptr; +}; + +typedef struct StackT StackT; +struct StackT { + void *ss_sp; + uint64 ss_size; + int32 ss_flags; + byte pad_godefs_0[4]; +}; + +typedef struct Timespec Timespec; +struct Timespec { + int32 tv_sec; + byte pad_godefs_0[4]; + int64 tv_nsec; +}; + +typedef struct Timeval Timeval; +struct Timeval { + int64 tv_sec; + int64 tv_usec; +}; + +typedef struct Itimerval Itimerval; +struct Itimerval { + Timeval it_interval; + Timeval it_value; +}; + +typedef void sfxsave64; + +typedef void usavefpu; + +typedef struct Sigcontext Sigcontext; +struct Sigcontext { + int64 sc_rdi; + int64 sc_rsi; + int64 sc_rdx; + int64 sc_rcx; + int64 sc_r8; + int64 sc_r9; + int64 sc_r10; + int64 sc_r11; + int64 sc_r12; + int64 sc_r13; + int64 sc_r14; + int64 sc_r15; + int64 sc_rbp; + int64 sc_rbx; + int64 sc_rax; + int64 sc_gs; + int64 sc_fs; + int64 sc_es; + int64 sc_ds; + int64 sc_trapno; + int64 sc_err; + int64 sc_rip; + int64 sc_cs; + int64 sc_rflags; + int64 sc_rsp; + int64 sc_ss; + sfxsave64 *sc_fpstate; + int32 sc_onstack; + int32 sc_mask; +}; +#pragma pack off diff --git a/src/pkg/runtime/plan9/386/defs.h b/src/pkg/runtime/defs_plan9_386.h index 58fd9d94d..58fd9d94d 100644 --- a/src/pkg/runtime/plan9/386/defs.h +++ b/src/pkg/runtime/defs_plan9_386.h diff --git a/src/pkg/runtime/defs_windows.go b/src/pkg/runtime/defs_windows.go new file mode 100644 index 000000000..0d525b932 --- /dev/null +++ b/src/pkg/runtime/defs_windows.go @@ -0,0 +1,66 @@ +// 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. + +// +build ignore + +/* +Input to cgo. + +GOARCH=amd64 cgo -cdefs defs.go >amd64/defs.h +GOARCH=386 cgo -cdefs defs.go >386/defs.h +*/ + +package runtime + +/* +#include <signal.h> +#include <stdarg.h> +#include <windef.h> +#include <winbase.h> +#include <wincon.h> + +#ifndef _X86_ +typedef struct {} FLOATING_SAVE_AREA; +#endif +#ifndef _AMD64_ +typedef struct {} M128A; +#endif +*/ +import "C" + +const ( + PROT_NONE = 0 + PROT_READ = 1 + PROT_WRITE = 2 + PROT_EXEC = 4 + + MAP_ANON = 1 + MAP_PRIVATE = 2 + + DUPLICATE_SAME_ACCESS = C.DUPLICATE_SAME_ACCESS + THREAD_PRIORITY_HIGHEST = C.THREAD_PRIORITY_HIGHEST + + SIGINT = C.SIGINT + CTRL_C_EVENT = C.CTRL_C_EVENT + CTRL_BREAK_EVENT = C.CTRL_BREAK_EVENT + + CONTEXT_CONTROL = C.CONTEXT_CONTROL + CONTEXT_FULL = C.CONTEXT_FULL + + EXCEPTION_ACCESS_VIOLATION = C.STATUS_ACCESS_VIOLATION + EXCEPTION_BREAKPOINT = C.STATUS_BREAKPOINT + EXCEPTION_FLT_DENORMAL_OPERAND = C.STATUS_FLOAT_DENORMAL_OPERAND + EXCEPTION_FLT_DIVIDE_BY_ZERO = C.STATUS_FLOAT_DIVIDE_BY_ZERO + EXCEPTION_FLT_INEXACT_RESULT = C.STATUS_FLOAT_INEXACT_RESULT + EXCEPTION_FLT_OVERFLOW = C.STATUS_FLOAT_OVERFLOW + EXCEPTION_FLT_UNDERFLOW = C.STATUS_FLOAT_UNDERFLOW + EXCEPTION_INT_DIVIDE_BY_ZERO = C.STATUS_INTEGER_DIVIDE_BY_ZERO + EXCEPTION_INT_OVERFLOW = C.STATUS_INTEGER_OVERFLOW +) + +type SystemInfo C.SYSTEM_INFO +type ExceptionRecord C.EXCEPTION_RECORD +type FloatingSaveArea C.FLOATING_SAVE_AREA +type M128a C.M128A +type Context C.CONTEXT diff --git a/src/pkg/runtime/windows/386/defs.h b/src/pkg/runtime/defs_windows_386.h index 6cc5336a9..e64a82faf 100644 --- a/src/pkg/runtime/windows/386/defs.h +++ b/src/pkg/runtime/defs_windows_386.h @@ -31,6 +31,20 @@ enum { // Types #pragma pack on +typedef struct SystemInfo SystemInfo; +struct SystemInfo { + byte Pad_godefs_0[4]; + uint32 dwPageSize; + void *lpMinimumApplicationAddress; + void *lpMaximumApplicationAddress; + uint32 dwActiveProcessorMask; + uint32 dwNumberOfProcessors; + uint32 dwProcessorType; + uint32 dwAllocationGranularity; + uint16 wProcessorLevel; + uint16 wProcessorRevision; +}; + typedef struct ExceptionRecord ExceptionRecord; struct ExceptionRecord { uint32 ExceptionCode; diff --git a/src/pkg/runtime/windows/amd64/defs.h b/src/pkg/runtime/defs_windows_amd64.h index d5191a3d7..da4c19d90 100644 --- a/src/pkg/runtime/windows/amd64/defs.h +++ b/src/pkg/runtime/defs_windows_amd64.h @@ -31,6 +31,20 @@ enum { // Types #pragma pack on +typedef struct SystemInfo SystemInfo; +struct SystemInfo { + byte Pad_godefs_0[4]; + uint32 dwPageSize; + void *lpMinimumApplicationAddress; + void *lpMaximumApplicationAddress; + uint64 dwActiveProcessorMask; + uint32 dwNumberOfProcessors; + uint32 dwProcessorType; + uint32 dwAllocationGranularity; + uint16 wProcessorLevel; + uint16 wProcessorRevision; +}; + typedef struct ExceptionRecord ExceptionRecord; struct ExceptionRecord { uint32 ExceptionCode; diff --git a/src/pkg/runtime/error.go b/src/pkg/runtime/error.go index 6c37f888f..4b0ee4931 100644 --- a/src/pkg/runtime/error.go +++ b/src/pkg/runtime/error.go @@ -6,11 +6,11 @@ package runtime // The Error interface identifies a run time error. type Error interface { - String() string + error // RuntimeError is a no-op function but // serves to distinguish types that are runtime - // errors from ordinary os.Errors: a type is a + // errors from ordinary errors: a type is a // runtime error if it has a RuntimeError method. RuntimeError() } @@ -28,7 +28,7 @@ type TypeAssertionError struct { func (*TypeAssertionError) RuntimeError() {} -func (e *TypeAssertionError) String() string { +func (e *TypeAssertionError) Error() string { inter := e.interfaceString if inter == "" { inter = "interface" @@ -98,7 +98,7 @@ type errorString string func (e errorString) RuntimeError() {} -func (e errorString) String() string { +func (e errorString) Error() string { return "runtime error: " + string(e) } @@ -123,6 +123,8 @@ func printany(i interface{}) { print("nil") case stringer: print(v.String()) + case error: + print(v.Error()) case int: print(v) case string: diff --git a/src/pkg/runtime/export_test.go b/src/pkg/runtime/export_test.go index 53c5fcba4..c603e1b0d 100644 --- a/src/pkg/runtime/export_test.go +++ b/src/pkg/runtime/export_test.go @@ -18,6 +18,8 @@ var F64toint = f64toint func entersyscall() func exitsyscall() +func golockedOSThread() bool var Entersyscall = entersyscall var Exitsyscall = exitsyscall +var LockedOSThread = golockedOSThread diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go index 9da3423c6..eafa2f19f 100644 --- a/src/pkg/runtime/extern.go +++ b/src/pkg/runtime/extern.go @@ -19,15 +19,15 @@ func Gosched() func Goexit() // Caller reports file and line number information about function invocations on -// the calling goroutine's stack. The argument skip is the number of stack frames to -// ascend, with 0 identifying the the caller of Caller. The return values report the +// the calling goroutine's stack. The argument skip is the number of stack frames +// to ascend, with 0 identifying the caller of Caller. The return values report the // program counter, file name, and line number within the file of the corresponding // call. The boolean ok is false if it was not possible to recover the information. func Caller(skip int) (pc uintptr, file string, line int, ok bool) // Callers fills the slice pc with the program counters of function invocations // on the calling goroutine's stack. The argument skip is the number of stack frames -// to skip before recording in pc, with 0 starting at the caller of Caller. +// to skip before recording in pc, with 0 starting at the caller of Callers. // It returns the number of entries written to pc. func Callers(skip int, pc []uintptr) int @@ -59,51 +59,12 @@ func (f *Func) Entry() uintptr { return f.entry } // The result will not be accurate if pc is not a program // counter within f. func (f *Func) FileLine(pc uintptr) (file string, line int) { - // NOTE(rsc): If you edit this function, also edit - // symtab.c:/^funcline. That function also has the - // comments explaining the logic. - targetpc := pc - - var pcQuant uintptr = 1 - if GOARCH == "arm" { - pcQuant = 4 - } - - p := f.pcln - pc = f.pc0 - line = int(f.ln0) - i := 0 - //print("FileLine start pc=", pc, " targetpc=", targetpc, " line=", line, - // " tab=", p, " ", p[0], " quant=", pcQuant, " GOARCH=", GOARCH, "\n") - for { - for i < len(p) && p[i] > 128 { - pc += pcQuant * uintptr(p[i]-128) - i++ - } - //print("pc<", pc, " targetpc=", targetpc, " line=", line, "\n") - if pc > targetpc || i >= len(p) { - break - } - if p[i] == 0 { - if i+5 > len(p) { - break - } - line += int(p[i+1]<<24) | int(p[i+2]<<16) | int(p[i+3]<<8) | int(p[i+4]) - i += 5 - } else if p[i] <= 64 { - line += int(p[i]) - i++ - } else { - line -= int(p[i] - 64) - i++ - } - //print("pc=", pc, " targetpc=", targetpc, " line=", line, "\n") - pc += pcQuant - } - file = f.src - return + return funcline_go(f, pc) } +// implemented in symtab.c +func funcline_go(*Func, uintptr) (string, int) + // mid returns the current os thread (m) id. func mid() uint32 @@ -131,8 +92,8 @@ func Semrelease(s *uint32) // The argument x must be a pointer to an object allocated by // calling new or by taking the address of a composite literal. // The argument f must be a function that takes a single argument -// of x's type and returns no arguments. If either of these is not -// true, SetFinalizer aborts the program. +// of x's type and can have arbitrary ignored return values. +// If either of these is not true, SetFinalizer aborts the program. // // Finalizers are run in dependency order: if A points at B, both have // finalizers, and they are otherwise unreachable, only the finalizer @@ -156,9 +117,6 @@ func Semrelease(s *uint32) // A single goroutine runs all finalizers for a program, sequentially. // If a finalizer must run for a long time, it should do so by starting // a new goroutine. -// -// TODO(rsc): allow f to have (ignored) return values -// func SetFinalizer(x, f interface{}) func getgoroot() string diff --git a/src/pkg/runtime/freebsd/defs.c b/src/pkg/runtime/freebsd/defs.c deleted file mode 100644 index 2ce4fdc51..000000000 --- a/src/pkg/runtime/freebsd/defs.c +++ /dev/null @@ -1,108 +0,0 @@ -// 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. - -/* - * Input to godefs. - * - godefs -f -m64 defs.c >amd64/defs.h - godefs -f -m32 defs.c >386/defs.h - */ - -#include <sys/types.h> -#include <sys/time.h> -#include <signal.h> -#include <errno.h> -#include <sys/mman.h> -#include <sys/ucontext.h> -#include <sys/umtx.h> -#include <sys/rtprio.h> -#include <sys/thr.h> -#include <sys/_sigset.h> -#include <sys/unistd.h> - -enum { - $PROT_NONE = PROT_NONE, - $PROT_READ = PROT_READ, - $PROT_WRITE = PROT_WRITE, - $PROT_EXEC = PROT_EXEC, - - $MAP_ANON = MAP_ANON, - $MAP_PRIVATE = MAP_PRIVATE, - $MAP_FIXED = MAP_FIXED, - - $SA_SIGINFO = SA_SIGINFO, - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - - $UMTX_OP_WAIT = UMTX_OP_WAIT, - $UMTX_OP_WAKE = UMTX_OP_WAKE, - - $EINTR = EINTR, - - $SIGHUP = SIGHUP, - $SIGINT = SIGINT, - $SIGQUIT = SIGQUIT, - $SIGILL = SIGILL, - $SIGTRAP = SIGTRAP, - $SIGABRT = SIGABRT, - $SIGEMT = SIGEMT, - $SIGFPE = SIGFPE, - $SIGKILL = SIGKILL, - $SIGBUS = SIGBUS, - $SIGSEGV = SIGSEGV, - $SIGSYS = SIGSYS, - $SIGPIPE = SIGPIPE, - $SIGALRM = SIGALRM, - $SIGTERM = SIGTERM, - $SIGURG = SIGURG, - $SIGSTOP = SIGSTOP, - $SIGTSTP = SIGTSTP, - $SIGCONT = SIGCONT, - $SIGCHLD = SIGCHLD, - $SIGTTIN = SIGTTIN, - $SIGTTOU = SIGTTOU, - $SIGIO = SIGIO, - $SIGXCPU = SIGXCPU, - $SIGXFSZ = SIGXFSZ, - $SIGVTALRM = SIGVTALRM, - $SIGPROF = SIGPROF, - $SIGWINCH = SIGWINCH, - $SIGINFO = SIGINFO, - $SIGUSR1 = SIGUSR1, - $SIGUSR2 = SIGUSR2, - - $FPE_INTDIV = FPE_INTDIV, - $FPE_INTOVF = FPE_INTOVF, - $FPE_FLTDIV = FPE_FLTDIV, - $FPE_FLTOVF = FPE_FLTOVF, - $FPE_FLTUND = FPE_FLTUND, - $FPE_FLTRES = FPE_FLTRES, - $FPE_FLTINV = FPE_FLTINV, - $FPE_FLTSUB = FPE_FLTSUB, - - $BUS_ADRALN = BUS_ADRALN, - $BUS_ADRERR = BUS_ADRERR, - $BUS_OBJERR = BUS_OBJERR, - - $SEGV_MAPERR = SEGV_MAPERR, - $SEGV_ACCERR = SEGV_ACCERR, - - $ITIMER_REAL = ITIMER_REAL, - $ITIMER_VIRTUAL = ITIMER_VIRTUAL, - $ITIMER_PROF = ITIMER_PROF, -}; - -typedef struct rtprio $Rtprio; -typedef struct thr_param $ThrParam; -typedef struct sigaltstack $Sigaltstack; -typedef struct __sigset $Sigset; -typedef union sigval $Sigval; -typedef stack_t $StackT; - -typedef siginfo_t $Siginfo; - -typedef mcontext_t $Mcontext; -typedef ucontext_t $Ucontext; -typedef struct timeval $Timeval; -typedef struct itimerval $Itimerval; diff --git a/src/pkg/runtime/freebsd/os.h b/src/pkg/runtime/freebsd/os.h deleted file mode 100644 index 007856c6b..000000000 --- a/src/pkg/runtime/freebsd/os.h +++ /dev/null @@ -1,12 +0,0 @@ -#define SIG_DFL ((void*)0) -#define SIG_IGN ((void*)1) - -int32 runtime·thr_new(ThrParam*, int32); -void runtime·sigpanic(void); -void runtime·sigaltstack(Sigaltstack*, Sigaltstack*); -struct sigaction; -void runtime·sigaction(int32, struct sigaction*, struct sigaction*); -void runtiem·setitimerval(int32, Itimerval*, Itimerval*); -void runtime·setitimer(int32, Itimerval*, Itimerval*); - -void runtime·raisesigpipe(void); diff --git a/src/pkg/runtime/gc_test.go b/src/pkg/runtime/gc_test.go new file mode 100644 index 000000000..00b3a04ce --- /dev/null +++ b/src/pkg/runtime/gc_test.go @@ -0,0 +1,36 @@ +// 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_test + +import ( + "runtime" + "testing" +) + +func TestGcSys(t *testing.T) { + runtime.GC() + runtime.UpdateMemStats() + sys := runtime.MemStats.Sys + + for i := 0; i < 1000000; i++ { + workthegc() + } + + // Should only be using a few MB. + runtime.UpdateMemStats() + if sys > runtime.MemStats.Sys { + sys = 0 + } else { + sys = runtime.MemStats.Sys - sys + } + t.Logf("used %d extra bytes", sys) + if sys > 4<<20 { + t.Fatalf("using too much memory: %d bytes", sys) + } +} + +func workthegc() []byte { + return make([]byte, 1029) +} diff --git a/src/pkg/runtime/goc2c.c b/src/pkg/runtime/goc2c.c index fcac9c060..b59a69c5e 100644 --- a/src/pkg/runtime/goc2c.c +++ b/src/pkg/runtime/goc2c.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build ignore + /* * Translate a .goc file into a .c file. A .goc file is a combination * of a limited form of Go with C. @@ -742,6 +744,7 @@ main(int argc, char **argv) } } + printf("// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n"); process_file(); exits(0); } diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c index 0c0e3e4a2..642995df8 100644 --- a/src/pkg/runtime/hashmap.c +++ b/src/pkg/runtime/hashmap.c @@ -6,41 +6,14 @@ #include "hashmap.h" #include "type.h" -/* Return a pointer to the struct/union of type "type" - whose "field" field is addressed by pointer "p". */ - struct Hmap { /* a hash table; initialize with hash_init() */ uint32 count; /* elements in table - must be first */ - uint8 datasize; /* amount of data to store in entry */ uint8 max_power; /* max power of 2 to create sub-tables */ - uint8 max_probes; /* max entries to probe before rehashing */ - uint8 indirectval; /* storing pointers to values */ + uint8 indirectval; /* storing pointers to values */ + uint8 valoff; /* offset of value in key+value data block */ int32 changes; /* inc'ed whenever a subtable is created/grown */ - hash_hash_t (*data_hash) (uint32, void *a); /* return hash of *a */ - uint32 (*data_eq) (uint32, void *a, void *b); /* return whether *a == *b */ - void (*data_del) (uint32, void *arg, void *data); /* invoked on deletion */ struct hash_subtable *st; /* first-level table */ - - uint32 keysize; - uint32 valsize; - uint32 datavo; - - // three sets of offsets: the digit counts how many - // of key, value are passed as inputs: - // 0 = func() (key, value) - // 1 = func(key) (value) - // 2 = func(key, value) - uint32 ko0; - uint32 vo0; - uint32 ko1; - uint32 vo1; - uint32 po1; - uint32 ko2; - uint32 vo2; - uint32 po2; - Alg* keyalg; - Alg* valalg; }; struct hash_entry { @@ -54,11 +27,11 @@ struct hash_subtable { uint8 datasize; /* bytes of client data in an entry */ uint8 max_probes; /* max number of probes when searching */ int16 limit_bytes; /* max_probes * (datasize+sizeof (hash_hash_t)) */ - struct hash_entry *end; /* points just past end of entry[] */ + struct hash_entry *last; /* points to last element of entry[] */ struct hash_entry entry[1]; /* 2**power+max_probes-1 elements of elemsize bytes */ }; -#define HASH_DATA_EQ(h,x,y) ((*h->data_eq) (h->keysize, (x), (y))) +#define HASH_DATA_EQ(eq, t, h,x,y) ((eq)=0, (*t->key->alg->equal) (&(eq), t->key->size, (x), (y)), (eq)) #define HASH_REHASH 0x2 /* an internal flag */ /* the number of bits used is stored in the flags word too */ @@ -79,6 +52,7 @@ struct hash_subtable { #define HASH_OFFSET(base, byte_offset) \ ((struct hash_entry *) (((byte *) (base)) + (byte_offset))) +#define HASH_MAX_PROBES 15 /* max entries to probe before rehashing */ /* return a hash layer with 2**power empty entries */ static struct hash_subtable * @@ -87,8 +61,8 @@ hash_subtable_new (Hmap *h, int32 power, int32 used) int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); int32 bytes = elemsize << power; struct hash_subtable *st; - int32 limit_bytes = h->max_probes * elemsize; - int32 max_probes = h->max_probes; + int32 limit_bytes = HASH_MAX_PROBES * elemsize; + int32 max_probes = HASH_MAX_PROBES; if (bytes < limit_bytes) { limit_bytes = bytes; @@ -101,7 +75,7 @@ hash_subtable_new (Hmap *h, int32 power, int32 used) st->datasize = h->datasize; st->max_probes = max_probes; st->limit_bytes = limit_bytes; - st->end = HASH_OFFSET (st->entry, bytes); + st->last = HASH_OFFSET (st->entry, bytes) - 1; memset (st->entry, HASH_NIL_MEMSET, bytes); return (st); } @@ -127,12 +101,7 @@ init_sizes (int64 hint, int32 *init_power, int32 *max_power) } static void -hash_init (Hmap *h, - int32 datasize, - hash_hash_t (*data_hash) (uint32, void *), - uint32 (*data_eq) (uint32, void *, void *), - void (*data_del) (uint32, void *, void *), - int64 hint) +hash_init (Hmap *h, int32 datasize, int64 hint) { int32 init_power; int32 max_power; @@ -143,15 +112,11 @@ hash_init (Hmap *h, init_sizes (hint, &init_power, &max_power); h->datasize = datasize; h->max_power = max_power; - h->max_probes = 15; assert (h->datasize == datasize); assert (h->max_power == max_power); assert (sizeof (void *) <= h->datasize || h->max_power == 255); h->count = 0; h->changes = 0; - h->data_hash = data_hash; - h->data_eq = data_eq; - h->data_del = data_del; h->st = hash_subtable_new (h, init_power, 0); } @@ -160,7 +125,7 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n) { int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]); struct hash_entry *src_e = HASH_OFFSET (dst_e, n * elemsize); - struct hash_entry *end_e = st->end; + struct hash_entry *last_e = st->last; int32 shift = HASH_BITS - (st->power + st->used); int32 index_mask = (((hash_hash_t)1) << st->power) - 1; int32 dst_i = (((byte *) dst_e) - ((byte *) st->entry)) / elemsize; @@ -170,10 +135,10 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n) int32 bytes; while (dst_e != src_e) { - if (src_e != end_e) { + if (src_e <= last_e) { struct hash_entry *cp_e = src_e; int32 save_dst_i = dst_i; - while (cp_e != end_e && (hash = cp_e->hash) != HASH_NIL && + while (cp_e <= last_e && (hash = cp_e->hash) != HASH_NIL && ((hash >> shift) & index_mask) <= dst_i) { cp_e = HASH_OFFSET (cp_e, elemsize); dst_i++; @@ -183,7 +148,7 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n) dst_e = HASH_OFFSET (dst_e, bytes); src_e = cp_e; src_i += dst_i - save_dst_i; - if (src_e != end_e && (hash = src_e->hash) != HASH_NIL) { + if (src_e <= last_e && (hash = src_e->hash) != HASH_NIL) { skip = ((hash >> shift) & index_mask) - dst_i; } else { skip = src_i - dst_i; @@ -199,11 +164,11 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n) } static int32 -hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash, +hash_insert_internal (MapType*, struct hash_subtable **pst, int32 flags, hash_hash_t hash, Hmap *h, void *data, void **pres); static void -hash_conv (Hmap *h, +hash_conv (MapType *t, Hmap *h, struct hash_subtable *st, int32 flags, hash_hash_t hash, struct hash_entry *e) @@ -224,7 +189,7 @@ hash_conv (Hmap *h, } de = e; - while (e != st->end && + while (e <= st->last && (e_hash = e->hash) != HASH_NIL && (e_hash & HASH_MASK) != HASH_SUBHASH) { struct hash_entry *target_e = HASH_OFFSET (st->entry, ((e_hash >> shift) & index_mask) * elemsize); @@ -235,16 +200,16 @@ hash_conv (Hmap *h, de = target_e; } if ((hash & prefix_mask) == current || - (ne != st->end && (e_hash = ne->hash) != HASH_NIL && + (ne <= st->last && (e_hash = ne->hash) != HASH_NIL && (e_hash & prefix_mask) == current)) { struct hash_subtable *new_st = hash_subtable_new (h, 1, HASH_USED (new_flags)); - int32 rc = hash_insert_internal (&new_st, new_flags, e->hash, h, e->data, &dummy_result); + int32 rc = hash_insert_internal (t, &new_st, new_flags, e->hash, h, e->data, &dummy_result); assert (rc == 0); memcpy(dummy_result, e->data, h->datasize); e = ne; - while (e != st->end && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) { + while (e <= st->last && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) { assert ((e_hash & HASH_MASK) != HASH_SUBHASH); - rc = hash_insert_internal (&new_st, new_flags, e_hash, h, e->data, &dummy_result); + rc = hash_insert_internal (t, &new_st, new_flags, e_hash, h, e->data, &dummy_result); assert (rc == 0); memcpy(dummy_result, e->data, h->datasize); e = HASH_OFFSET (e, elemsize); @@ -266,21 +231,21 @@ hash_conv (Hmap *h, } static void -hash_grow (Hmap *h, struct hash_subtable **pst, int32 flags) +hash_grow (MapType *t, Hmap *h, struct hash_subtable **pst, int32 flags) { struct hash_subtable *old_st = *pst; int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); *pst = hash_subtable_new (h, old_st->power + 1, HASH_USED (flags)); - struct hash_entry *end_e = old_st->end; + struct hash_entry *last_e = old_st->last; struct hash_entry *e; void *dummy_result; int32 used = 0; flags |= HASH_REHASH; - for (e = old_st->entry; e != end_e; e = HASH_OFFSET (e, elemsize)) { + for (e = old_st->entry; e <= last_e; e = HASH_OFFSET (e, elemsize)) { hash_hash_t hash = e->hash; if (hash != HASH_NIL) { - int32 rc = hash_insert_internal (pst, flags, e->hash, h, e->data, &dummy_result); + int32 rc = hash_insert_internal (t, pst, flags, e->hash, h, e->data, &dummy_result); assert (rc == 0); memcpy(dummy_result, e->data, h->datasize); used++; @@ -290,16 +255,20 @@ hash_grow (Hmap *h, struct hash_subtable **pst, int32 flags) } static int32 -hash_lookup (Hmap *h, void *data, void **pres) +hash_lookup (MapType *t, Hmap *h, void *data, void **pres) { int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); - hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK; + hash_hash_t hash; struct hash_subtable *st = h->st; int32 used = 0; hash_hash_t e_hash; struct hash_entry *e; struct hash_entry *end_e; - + bool eq; + + hash = 0; + (*t->key->alg->hash) (&hash, t->key->size, data); + hash &= ~HASH_MASK; hash += HASH_ADJUST (hash); for (;;) { int32 shift = HASH_BITS - (st->power + used); @@ -319,7 +288,7 @@ hash_lookup (Hmap *h, void *data, void **pres) e = HASH_OFFSET (e, elemsize); } while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) { - if (HASH_DATA_EQ (h, data, e->data)) { /* a match */ + if (HASH_DATA_EQ (eq, t, h, data, e->data)) { /* a match */ *pres = e->data; return (1); } @@ -331,16 +300,20 @@ hash_lookup (Hmap *h, void *data, void **pres) } static int32 -hash_remove (Hmap *h, void *data, void *arg) +hash_remove (MapType *t, Hmap *h, void *data) { int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); - hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK; + hash_hash_t hash; struct hash_subtable *st = h->st; int32 used = 0; hash_hash_t e_hash; struct hash_entry *e; struct hash_entry *end_e; + bool eq; + hash = 0; + (*t->key->alg->hash) (&hash, t->key->size, data); + hash &= ~HASH_MASK; hash += HASH_ADJUST (hash); for (;;) { int32 shift = HASH_BITS - (st->power + used); @@ -360,8 +333,9 @@ hash_remove (Hmap *h, void *data, void *arg) e = HASH_OFFSET (e, elemsize); } while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) { - if (HASH_DATA_EQ (h, data, e->data)) { /* a match */ - (*h->data_del) (h->datavo, arg, e->data); + if (HASH_DATA_EQ (eq, t, h, data, e->data)) { /* a match */ + if (h->indirectval) + free (*(void**)((byte*)e->data + h->valoff)); hash_remove_n (st, e, 1); h->count--; return (1); @@ -373,10 +347,11 @@ hash_remove (Hmap *h, void *data, void *arg) } static int32 -hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash, +hash_insert_internal (MapType *t, struct hash_subtable **pst, int32 flags, hash_hash_t hash, Hmap *h, void *data, void **pres) { int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); + bool eq; if ((flags & HASH_REHASH) == 0) { hash += HASH_ADJUST (hash); @@ -409,7 +384,7 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash, int32 ins_i = i; hash_hash_t ins_e_hash; while (ins_e != end_e && ((e_hash = ins_e->hash) ^ hash) < HASH_SUBHASH) { - if (HASH_DATA_EQ (h, data, ins_e->data)) { /* a match */ + if (HASH_DATA_EQ (eq, t, h, data, ins_e->data)) { /* a match */ *pres = ins_e->data; return (1); } @@ -428,13 +403,13 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash, ins_e_hash = 0; /* move ins_e to point at the end of the contiguous block, but stop if any element can't be moved by one up */ - while (ins_e != st->end && (ins_e_hash = ins_e->hash) != HASH_NIL && + while (ins_e <= st->last && (ins_e_hash = ins_e->hash) != HASH_NIL && ins_i + 1 - ((ins_e_hash >> shift) & index_mask) < st->max_probes && (ins_e_hash & HASH_MASK) != HASH_SUBHASH) { ins_e = HASH_OFFSET (ins_e, elemsize); ins_i++; } - if (e == end_e || ins_e == st->end || ins_e_hash != HASH_NIL) { + if (e == end_e || ins_e > st->last || ins_e_hash != HASH_NIL) { e = end_e; /* can't insert; must grow or convert to subtable */ } else { /* make space for element */ memmove (HASH_OFFSET (e, elemsize), e, ((byte *) ins_e) - (byte *) e); @@ -447,17 +422,22 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash, } h->changes++; if (st->power < h->max_power) { - hash_grow (h, pst, flags); + hash_grow (t, h, pst, flags); } else { - hash_conv (h, st, flags, hash, start_e); + hash_conv (t, h, st, flags, hash, start_e); } } } static int32 -hash_insert (Hmap *h, void *data, void **pres) +hash_insert (MapType *t, Hmap *h, void *data, void **pres) { - int32 rc = hash_insert_internal (&h->st, 0, (*h->data_hash) (h->keysize, data), h, data, pres); + uintptr hash; + int32 rc; + + hash = 0; + (*t->key->alg->hash) (&hash, t->key->size, data); + rc = hash_insert_internal (t, &h->st, 0, hash, h, data, pres); h->count += (rc == 0); /* increment count if element didn't previously exist */ return (rc); @@ -477,17 +457,17 @@ iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used) struct hash_entry *e; hash_hash_t e_hash; struct hash_iter_sub *sub = &it->subtable_state[it->i]; - struct hash_entry *end; + struct hash_entry *last; for (;;) { int32 shift = HASH_BITS - (st->power + used); int32 index_mask = (1 << st->power) - 1; int32 i = (last_hash >> shift) & index_mask; - end = st->end; + last = st->last; e = HASH_OFFSET (st->entry, i * elemsize); sub->start = st->entry; - sub->end = end; + sub->last = last; if ((e->hash & HASH_MASK) != HASH_SUBHASH) { break; @@ -497,7 +477,7 @@ iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used) used += st->power; st = *(struct hash_subtable **)e->data; } - while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) { + while (e <= last && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) { e = HASH_OFFSET (e, elemsize); } sub->e = e; @@ -506,22 +486,29 @@ iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used) static void * hash_next (struct hash_iter *it) { - int32 elemsize = it->elemsize; - struct hash_iter_sub *sub = &it->subtable_state[it->i]; - struct hash_entry *e = sub->e; - struct hash_entry *end = sub->end; - hash_hash_t e_hash = 0; + int32 elemsize; + struct hash_iter_sub *sub; + struct hash_entry *e; + struct hash_entry *last; + hash_hash_t e_hash; if (it->changes != it->h->changes) { /* hash table's structure changed; recompute */ + if (~it->last_hash == 0) + return (0); it->changes = it->h->changes; it->i = 0; iter_restart (it, it->h->st, 0); - sub = &it->subtable_state[it->i]; - e = sub->e; - end = sub->end; } + elemsize = it->elemsize; + +Again: + e_hash = 0; + sub = &it->subtable_state[it->i]; + e = sub->e; + last = sub->last; + if (e != sub->start && it->last_hash != HASH_OFFSET (e, -elemsize)->hash) { - struct hash_entry *start = HASH_OFFSET (e, -(elemsize * it->h->max_probes)); + struct hash_entry *start = HASH_OFFSET (e, -(elemsize * HASH_MAX_PROBES)); struct hash_entry *pe = HASH_OFFSET (e, -elemsize); hash_hash_t last_hash = it->last_hash; if (start < sub->start) { @@ -531,27 +518,48 @@ hash_next (struct hash_iter *it) e = pe; pe = HASH_OFFSET (pe, -elemsize); } - while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) { + while (e <= last && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) { e = HASH_OFFSET (e, elemsize); } } for (;;) { - while (e != end && (e_hash = e->hash) == HASH_NIL) { + while (e <= last && (e_hash = e->hash) == HASH_NIL) { e = HASH_OFFSET (e, elemsize); } - if (e == end) { + if (e > last) { if (it->i == 0) { - it->last_hash = HASH_OFFSET (e, -elemsize)->hash; - sub->e = e; + if(!it->cycled) { + // Wrap to zero and iterate up until it->cycle. + it->cycled = true; + it->last_hash = 0; + it->subtable_state[0].e = it->h->st->entry; + it->subtable_state[0].start = it->h->st->entry; + it->subtable_state[0].last = it->h->st->last; + goto Again; + } + // Set last_hash to impossible value and + // break it->changes, so that check at top of + // hash_next will be used if we get called again. + it->last_hash = ~(uintptr_t)0; + it->changes--; return (0); } else { it->i--; sub = &it->subtable_state[it->i]; e = sub->e; - end = sub->end; + last = sub->last; } } else if ((e_hash & HASH_MASK) != HASH_SUBHASH) { + if(it->cycled && e->hash > it->cycle) { + // Already returned this. + // Set last_hash to impossible value and + // break it->changes, so that check at top of + // hash_next will be used if we get called again. + it->last_hash = ~(uintptr_t)0; + it->changes--; + return (0); + } it->last_hash = e->hash; sub->e = HASH_OFFSET (e, elemsize); return (e->data); @@ -565,22 +573,34 @@ hash_next (struct hash_iter *it) sub = &it->subtable_state[it->i]; sub->e = e = st->entry; sub->start = st->entry; - sub->end = end = st->end; + sub->last = last = st->last; } } } static void -hash_iter_init (Hmap *h, struct hash_iter *it) +hash_iter_init (MapType *t, Hmap *h, struct hash_iter *it) { it->elemsize = h->datasize + offsetof (struct hash_entry, data[0]); it->changes = h->changes; it->i = 0; it->h = h; + it->t = t; it->last_hash = 0; it->subtable_state[0].e = h->st->entry; it->subtable_state[0].start = h->st->entry; - it->subtable_state[0].end = h->st->end; + it->subtable_state[0].last = h->st->last; + + // fastrand1 returns 31 useful bits. + // We don't care about not having a bottom bit but we + // do want top bits. + if(sizeof(void*) == 8) + it->cycle = (uint64)runtime·fastrand1()<<33 | (uint64)runtime·fastrand1()<<2; + else + it->cycle = runtime·fastrand1()<<1; + it->cycled = false; + it->last_hash = it->cycle; + iter_restart(it, it->h->st, 0); } static void @@ -588,11 +608,11 @@ clean_st (struct hash_subtable *st, int32 *slots, int32 *used) { int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]); struct hash_entry *e = st->entry; - struct hash_entry *end = st->end; - int32 lslots = (((byte *) end) - (byte *) e) / elemsize; + struct hash_entry *last = st->last; + int32 lslots = (((byte *) (last+1)) - (byte *) e) / elemsize; int32 lused = 0; - while (e != end) { + while (e <= last) { hash_hash_t hash = e->hash; if ((hash & HASH_MASK) == HASH_SUBHASH) { clean_st (*(struct hash_subtable **)e->data, slots, used); @@ -627,7 +647,7 @@ hash_visit_internal (struct hash_subtable *st, int32 shift = HASH_BITS - (used + st->power); int32 i = 0; - while (e != st->end) { + while (e <= st->last) { int32 index = ((e->hash >> (shift - 1)) >> 1) & ((1 << st->power) - 1); if ((e->hash & HASH_MASK) == HASH_SUBHASH) { (*data_visit) (arg, level, e->data); @@ -662,24 +682,6 @@ enum { MaxValsize = 256 - 64 }; -static void -donothing(uint32 s, void *a, void *b) -{ - USED(s); - USED(a); - USED(b); -} - -static void -freedata(uint32 datavo, void *a, void *b) -{ - void *p; - - USED(a); - p = *(void**)((byte*)b + datavo); - free(p); -} - static void** hash_indirect(Hmap *h, void *p) { @@ -695,8 +697,7 @@ Hmap* runtime·makemap_c(MapType *typ, int64 hint) { Hmap *h; - int32 keyalg, valalg, keysize, valsize, valsize_in_hash; - void (*data_del)(uint32, void*, void*); + int32 valsize_in_hash; Type *key, *val; key = typ->key; @@ -705,68 +706,30 @@ runtime·makemap_c(MapType *typ, int64 hint) if(hint < 0 || (int32)hint != hint) runtime·panicstring("makemap: size out of range"); - keyalg = key->alg; - valalg = val->alg; - keysize = key->size; - valsize = val->size; - - if(keyalg >= nelem(runtime·algarray) || runtime·algarray[keyalg].hash == runtime·nohash) { - runtime·printf("map(keyalg=%d)\n", keyalg); + if(key->alg->hash == runtime·nohash) runtime·throw("runtime.makemap: unsupported map key type"); - } - - if(valalg >= nelem(runtime·algarray)) { - runtime·printf("map(valalg=%d)\n", valalg); - runtime·throw("runtime.makemap: unsupported map value type"); - } h = runtime·mal(sizeof(*h)); - valsize_in_hash = valsize; - data_del = donothing; - if (valsize > MaxValsize) { + valsize_in_hash = val->size; + if (val->size > MaxValsize) { h->indirectval = 1; - data_del = freedata; valsize_in_hash = sizeof(void*); } - // align value inside data so that mark-sweep gc can find it. - // might remove in the future and just assume datavo == keysize. - h->datavo = keysize; + // Align value inside data so that mark-sweep gc can find it. + h->valoff = key->size; if(valsize_in_hash >= sizeof(void*)) - h->datavo = runtime·rnd(keysize, sizeof(void*)); - - hash_init(h, h->datavo+valsize_in_hash, - runtime·algarray[keyalg].hash, - runtime·algarray[keyalg].equal, - data_del, - hint); + h->valoff = runtime·rnd(key->size, sizeof(void*)); - h->keysize = keysize; - h->valsize = valsize; - h->keyalg = &runtime·algarray[keyalg]; - h->valalg = &runtime·algarray[valalg]; + hash_init(h, h->valoff+valsize_in_hash, hint); // these calculations are compiler dependent. // figure out offsets of map call arguments. - // func() (key, val) - h->ko0 = runtime·rnd(sizeof(h), Structrnd); - h->vo0 = runtime·rnd(h->ko0+keysize, val->align); - - // func(key) (val[, pres]) - h->ko1 = runtime·rnd(sizeof(h), key->align); - h->vo1 = runtime·rnd(h->ko1+keysize, Structrnd); - h->po1 = h->vo1 + valsize; - - // func(key, val[, pres]) - h->ko2 = runtime·rnd(sizeof(h), key->align); - h->vo2 = runtime·rnd(h->ko2+keysize, val->align); - h->po2 = h->vo2 + valsize; - if(debug) { - runtime·printf("makemap: map=%p; keysize=%d; valsize=%d; keyalg=%d; valalg=%d; offsets=%d,%d; %d,%d,%d; %d,%d,%d\n", - h, keysize, valsize, keyalg, valalg, h->ko0, h->vo0, h->ko1, h->vo1, h->po1, h->ko2, h->vo2, h->po2); + runtime·printf("makemap: map=%p; keysize=%p; valsize=%p; keyalg=%p; valalg=%p\n", + h, key->size, val->size, key->alg, val->alg); } return h; @@ -795,9 +758,9 @@ runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres) byte *res; Type *elem; + elem = t->elem; if(h == nil) { - elem = t->elem; - runtime·algarray[elem->alg].copy(elem->size, av, nil); + elem->alg->copy(elem->size, av, nil); *pres = false; return; } @@ -806,12 +769,12 @@ runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres) runtime·gosched(); res = nil; - if(hash_lookup(h, ak, (void**)&res)) { + if(hash_lookup(t, h, ak, (void**)&res)) { *pres = true; - h->valalg->copy(h->valsize, av, hash_indirect(h, res+h->datavo)); + elem->alg->copy(elem->size, av, hash_indirect(h, res+h->valoff)); } else { *pres = false; - h->valalg->copy(h->valsize, av, nil); + elem->alg->copy(elem->size, av, nil); } } @@ -823,13 +786,8 @@ runtime·mapaccess1(MapType *t, Hmap *h, ...) byte *ak, *av; bool pres; - if(h == nil) { - ak = (byte*)(&h + 1); - av = ak + runtime·rnd(t->key->size, Structrnd); - } else { - ak = (byte*)&h + h->ko1; - av = (byte*)&h + h->vo1; - } + ak = (byte*)(&h + 1); + av = ak + runtime·rnd(t->key->size, Structrnd); runtime·mapaccess(t, h, ak, av, &pres); @@ -837,9 +795,9 @@ runtime·mapaccess1(MapType *t, Hmap *h, ...) runtime·prints("runtime.mapaccess1: map="); runtime·printpointer(h); runtime·prints("; key="); - h->keyalg->print(h->keysize, ak); + t->key->alg->print(t->key->size, ak); runtime·prints("; val="); - h->valalg->print(h->valsize, av); + t->elem->alg->print(t->elem->size, av); runtime·prints("; pres="); runtime·printbool(pres); runtime·prints("\n"); @@ -853,15 +811,9 @@ runtime·mapaccess2(MapType *t, Hmap *h, ...) { byte *ak, *av, *ap; - if(h == nil) { - ak = (byte*)(&h + 1); - av = ak + runtime·rnd(t->key->size, Structrnd); - ap = av + t->elem->size; - } else { - ak = (byte*)&h + h->ko1; - av = (byte*)&h + h->vo1; - ap = (byte*)&h + h->po1; - } + ak = (byte*)(&h + 1); + av = ak + runtime·rnd(t->key->size, Structrnd); + ap = av + t->elem->size; runtime·mapaccess(t, h, ak, av, ap); @@ -869,9 +821,9 @@ runtime·mapaccess2(MapType *t, Hmap *h, ...) runtime·prints("runtime.mapaccess2: map="); runtime·printpointer(h); runtime·prints("; key="); - h->keyalg->print(h->keysize, ak); + t->key->alg->print(t->key->size, ak); runtime·prints("; val="); - h->valalg->print(h->valsize, av); + t->elem->alg->print(t->key->size, av); runtime·prints("; pres="); runtime·printbool(*ap); runtime·prints("\n"); @@ -910,33 +862,31 @@ runtime·mapassign(MapType *t, Hmap *h, byte *ak, byte *av) byte *res; int32 hit; - USED(t); - if(h == nil) runtime·panicstring("assignment to entry in nil map"); if(runtime·gcwaiting) runtime·gosched(); - res = nil; if(av == nil) { - hash_remove(h, ak, (void**)&res); + hash_remove(t, h, ak); return; } - hit = hash_insert(h, ak, (void**)&res); + res = nil; + hit = hash_insert(t, h, ak, (void**)&res); if(!hit && h->indirectval) - *(void**)(res+h->datavo) = runtime·mal(h->valsize); - h->keyalg->copy(h->keysize, res, ak); - h->valalg->copy(h->valsize, hash_indirect(h, res+h->datavo), av); + *(void**)(res+h->valoff) = runtime·mal(t->elem->size); + t->key->alg->copy(t->key->size, res, ak); + t->elem->alg->copy(t->elem->size, hash_indirect(h, res+h->valoff), av); if(debug) { runtime·prints("mapassign: map="); runtime·printpointer(h); runtime·prints("; key="); - h->keyalg->print(h->keysize, ak); + t->key->alg->print(t->key->size, ak); runtime·prints("; val="); - h->valalg->print(h->valsize, av); + t->elem->alg->print(t->elem->size, av); runtime·prints("; hit="); runtime·printint(hit); runtime·prints("; res="); @@ -955,36 +905,30 @@ runtime·mapassign1(MapType *t, Hmap *h, ...) if(h == nil) runtime·panicstring("assignment to entry in nil map"); - ak = (byte*)&h + h->ko2; - av = (byte*)&h + h->vo2; + ak = (byte*)(&h + 1); + av = ak + runtime·rnd(t->key->size, t->elem->align); runtime·mapassign(t, h, ak, av); } -// mapassign2(mapType *type, hmap *map[any]any, key any, val any, pres bool); +// mapdelete(mapType *type, hmap *map[any]any, key any) #pragma textflag 7 void -runtime·mapassign2(MapType *t, Hmap *h, ...) +runtime·mapdelete(MapType *t, Hmap *h, ...) { - byte *ak, *av, *ap; + byte *ak; if(h == nil) - runtime·panicstring("assignment to entry in nil map"); - - ak = (byte*)&h + h->ko2; - av = (byte*)&h + h->vo2; - ap = (byte*)&h + h->po2; + runtime·panicstring("deletion of entry in nil map"); - if(*ap == false) - av = nil; // delete - - runtime·mapassign(t, h, ak, av); + ak = (byte*)(&h + 1); + runtime·mapassign(t, h, ak, nil); if(debug) { - runtime·prints("mapassign2: map="); + runtime·prints("mapdelete: map="); runtime·printpointer(h); runtime·prints("; key="); - h->keyalg->print(h->keysize, ak); + t->key->alg->print(t->key->size, ak); runtime·prints("\n"); } } @@ -1000,11 +944,11 @@ reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres) if(h == nil) runtime·panicstring("assignment to entry in nil map"); - if(h->keysize <= sizeof(key)) + if(t->key->size <= sizeof(key)) ak = (byte*)&key; else ak = (byte*)key; - if(h->valsize <= sizeof(val)) + if(t->elem->size <= sizeof(val)) av = (byte*)&val; else av = (byte*)val; @@ -1015,13 +959,13 @@ reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres) // mapiterinit(mapType *type, hmap *map[any]any, hiter *any); void -runtime·mapiterinit(MapType*, Hmap *h, struct hash_iter *it) +runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it) { if(h == nil) { it->data = nil; return; } - hash_iter_init(h, it); + hash_iter_init(t, h, it); it->data = hash_next(it); if(debug) { runtime·prints("runtime.mapiterinit: map="); @@ -1076,15 +1020,17 @@ runtime·mapiter1(struct hash_iter *it, ...) { Hmap *h; byte *ak, *res; + Type *key; h = it->h; - ak = (byte*)&it + h->ko0; + ak = (byte*)(&it + 1); res = it->data; if(res == nil) runtime·throw("runtime.mapiter1: key:val nil pointer"); - h->keyalg->copy(h->keysize, ak, res); + key = it->t->key; + key->alg->copy(key->size, ak, res); if(debug) { runtime·prints("mapiter2: iter="); @@ -1098,14 +1044,14 @@ runtime·mapiter1(struct hash_iter *it, ...) bool runtime·mapiterkey(struct hash_iter *it, void *ak) { - Hmap *h; byte *res; + Type *key; - h = it->h; res = it->data; if(res == nil) return false; - h->keyalg->copy(h->keysize, ak, res); + key = it->t->key; + key->alg->copy(key->size, ak, res); return true; } @@ -1116,20 +1062,20 @@ runtime·mapiterkey(struct hash_iter *it, void *ak) void reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok) { - Hmap *h; byte *res; + Type *tkey; key = 0; ok = false; - h = it->h; res = it->data; if(res == nil) { key = 0; ok = false; } else { + tkey = it->t->key; key = 0; - if(h->keysize <= sizeof(key)) - h->keyalg->copy(h->keysize, (byte*)&key, res); + if(tkey->size <= sizeof(key)) + tkey->alg->copy(tkey->size, (byte*)&key, res); else key = (uintptr)res; ok = true; @@ -1158,17 +1104,19 @@ runtime·mapiter2(struct hash_iter *it, ...) { Hmap *h; byte *ak, *av, *res; + MapType *t; - h = it->h; - ak = (byte*)&it + h->ko0; - av = (byte*)&it + h->vo0; + t = it->t; + ak = (byte*)(&it + 1); + av = ak + runtime·rnd(t->key->size, t->elem->align); res = it->data; if(res == nil) runtime·throw("runtime.mapiter2: key:val nil pointer"); - h->keyalg->copy(h->keysize, ak, res); - h->valalg->copy(h->valsize, av, hash_indirect(h, res+h->datavo)); + h = it->h; + t->key->alg->copy(t->key->size, ak, res); + t->elem->alg->copy(t->elem->size, av, hash_indirect(h, res+h->valoff)); if(debug) { runtime·prints("mapiter2: iter="); diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h index 19ff41697..4c10cf6ef 100644 --- a/src/pkg/runtime/hashmap.h +++ b/src/pkg/runtime/hashmap.h @@ -66,7 +66,7 @@ #define malloc runtime·mal #define memset(a,b,c) runtime·memclr((byte*)(a), (uint32)(c)) #define memcpy(a,b,c) runtime·memmove((byte*)(a),(byte*)(b),(uint32)(c)) -#define assert(a) if(!(a)) runtime·throw("assert") +#define assert(a) if(!(a)) runtime·throw("hashmap assert") #define free(x) runtime·free(x) #define memmove(a,b,c) runtime·memmove(a, b, c) @@ -82,12 +82,15 @@ struct hash_iter { int32 elemsize; /* size of elements in table */ int32 changes; /* number of changes observed last time */ int32 i; /* stack pointer in subtable_state */ + bool cycled; /* have reached the end and wrapped to 0 */ hash_hash_t last_hash; /* last hash value returned */ + hash_hash_t cycle; /* hash value where we started */ struct Hmap *h; /* the hash table */ + MapType *t; /* the map type */ struct hash_iter_sub { struct hash_entry *e; /* pointer into subtable */ struct hash_entry *start; /* start of subtable */ - struct hash_entry *end; /* end of subtable */ + struct hash_entry *last; /* last entry in subtable */ } subtable_state[4]; /* Should be large enough unless the hashing is so bad that many distinct data values hash to the same hash value. */ diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c index 000f834cf..9f709355a 100644 --- a/src/pkg/runtime/iface.c +++ b/src/pkg/runtime/iface.c @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "arch_GOARCH.h" #include "type.h" #include "malloc.h" @@ -158,17 +159,18 @@ out: static void copyin(Type *t, void *src, void **dst) { - int32 wid, alg; + uintptr size; void *p; + Alg *alg; - wid = t->size; + size = t->size; alg = t->alg; - if(wid <= sizeof(*dst)) - runtime·algarray[alg].copy(wid, dst, src); + if(size <= sizeof(*dst)) + alg->copy(size, dst, src); else { - p = runtime·mal(wid); - runtime·algarray[alg].copy(wid, p, src); + p = runtime·mal(size); + alg->copy(size, p, src); *dst = p; } } @@ -176,15 +178,16 @@ copyin(Type *t, void *src, void **dst) static void copyout(Type *t, void **src, void *dst) { - int32 wid, alg; + uintptr size; + Alg *alg; - wid = t->size; + size = t->size; alg = t->alg; - if(wid <= sizeof(*src)) - runtime·algarray[alg].copy(wid, dst, src); + if(size <= sizeof(*src)) + alg->copy(size, dst, src); else - runtime·algarray[alg].copy(wid, dst, *src); + alg->copy(size, dst, *src); } // func convT2I(typ *byte, typ2 *byte, elem any) (ret any) @@ -547,23 +550,27 @@ runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok) static uintptr ifacehash1(void *data, Type *t) { - int32 alg, wid; + Alg *alg; + uintptr size, h; Eface err; if(t == nil) return 0; alg = t->alg; - wid = t->size; - if(runtime·algarray[alg].hash == runtime·nohash) { + size = t->size; + if(alg->hash == runtime·nohash) { // calling nohash will panic too, // but we can print a better error. runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err); runtime·panic(err); } - if(wid <= sizeof(data)) - return runtime·algarray[alg].hash(wid, &data); - return runtime·algarray[alg].hash(wid, data); + h = 0; + if(size <= sizeof(data)) + alg->hash(&h, size, &data); + else + alg->hash(&h, size, data); + return h; } uintptr @@ -583,22 +590,27 @@ runtime·efacehash(Eface a) static bool ifaceeq1(void *data1, void *data2, Type *t) { - int32 alg, wid; + uintptr size; + Alg *alg; Eface err; + bool eq; alg = t->alg; - wid = t->size; + size = t->size; - if(runtime·algarray[alg].equal == runtime·noequal) { + if(alg->equal == runtime·noequal) { // calling noequal will panic too, // but we can print a better error. runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err); runtime·panic(err); } - if(wid <= sizeof(data1)) - return runtime·algarray[alg].equal(wid, &data1, &data2); - return runtime·algarray[alg].equal(wid, data1, data2); + eq = 0; + if(size <= sizeof(data1)) + alg->equal(&eq, size, &data1, &data2); + else + alg->equal(&eq, size, data1, data2); + return eq; } bool @@ -700,7 +712,7 @@ unsafe·Reflect(Eface e, Eface rettype, void *retaddr) if(e.type->size <= sizeof(uintptr)) { // Copy data into x ... x = 0; - runtime·algarray[e.type->alg].copy(e.type->size, &x, &e.data); + e.type->alg->copy(e.type->size, &x, &e.data); // but then build pointer to x so that Reflect // always returns pointer to data. @@ -710,7 +722,7 @@ unsafe·Reflect(Eface e, Eface rettype, void *retaddr) // Already a pointer, but still make a copy, // to preserve value semantics for interface data. p = runtime·mal(e.type->size); - runtime·algarray[e.type->alg].copy(e.type->size, p, e.data); + e.type->alg->copy(e.type->size, p, e.data); } retaddr = p; } @@ -733,7 +745,7 @@ unsafe·Unreflect(Eface typ, void *addr, Eface e) // Interface holds either pointer to data // or copy of original data. if(e.type->size <= sizeof(uintptr)) - runtime·algarray[e.type->alg].copy(e.type->size, &e.data, addr); + e.type->alg->copy(e.type->size, &e.data, addr); else { // Easier: already a pointer to data. // TODO(rsc): Should this make a copy? diff --git a/src/pkg/runtime/linux/386/defs.h b/src/pkg/runtime/linux/386/defs.h deleted file mode 100644 index 73fe23ef9..000000000 --- a/src/pkg/runtime/linux/386/defs.h +++ /dev/null @@ -1,191 +0,0 @@ -// godefs -f -m32 -f -I/home/rsc/pub/linux-2.6/arch/x86/include -f -I/home/rsc/pub/linux-2.6/include -f -D_LOOSE_KERNEL_NAMES -f -D__ARCH_SI_UID_T=__kernel_uid32_t defs2.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants -enum { - PROT_NONE = 0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - MAP_ANON = 0x20, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_RESTORER = 0x4000000, - SA_SIGINFO = 0x4, - SIGHUP = 0x1, - SIGINT = 0x2, - SIGQUIT = 0x3, - SIGILL = 0x4, - SIGTRAP = 0x5, - SIGABRT = 0x6, - SIGBUS = 0x7, - SIGFPE = 0x8, - SIGKILL = 0x9, - SIGUSR1 = 0xa, - SIGSEGV = 0xb, - SIGUSR2 = 0xc, - SIGPIPE = 0xd, - SIGALRM = 0xe, - SIGSTKFLT = 0x10, - SIGCHLD = 0x11, - SIGCONT = 0x12, - SIGSTOP = 0x13, - SIGTSTP = 0x14, - SIGTTIN = 0x15, - SIGTTOU = 0x16, - SIGURG = 0x17, - SIGXCPU = 0x18, - SIGXFSZ = 0x19, - SIGVTALRM = 0x1a, - SIGPROF = 0x1b, - SIGWINCH = 0x1c, - SIGIO = 0x1d, - SIGPWR = 0x1e, - SIGSYS = 0x1f, - FPE_INTDIV = 0x1, - FPE_INTOVF = 0x2, - FPE_FLTDIV = 0x3, - FPE_FLTOVF = 0x4, - FPE_FLTUND = 0x5, - FPE_FLTRES = 0x6, - FPE_FLTINV = 0x7, - FPE_FLTSUB = 0x8, - BUS_ADRALN = 0x1, - BUS_ADRERR = 0x2, - BUS_OBJERR = 0x3, - SEGV_MAPERR = 0x1, - SEGV_ACCERR = 0x2, - ITIMER_REAL = 0, - ITIMER_VIRTUAL = 0x1, - ITIMER_PROF = 0x2, - O_RDONLY = 0, - O_CLOEXEC = 02000000, -}; - -// Types -#pragma pack on - -typedef struct Fpreg Fpreg; -struct Fpreg { - uint16 significand[4]; - uint16 exponent; -}; - -typedef struct Fpxreg Fpxreg; -struct Fpxreg { - uint16 significand[4]; - uint16 exponent; - uint16 padding[3]; -}; - -typedef struct Xmmreg Xmmreg; -struct Xmmreg { - uint32 element[4]; -}; - -typedef struct Fpstate Fpstate; -struct Fpstate { - uint32 cw; - uint32 sw; - uint32 tag; - uint32 ipoff; - uint32 cssel; - uint32 dataoff; - uint32 datasel; - Fpreg _st[8]; - uint16 status; - uint16 magic; - uint32 _fxsr_env[6]; - uint32 mxcsr; - uint32 reserved; - Fpxreg _fxsr_st[8]; - Xmmreg _xmm[8]; - uint32 padding1[44]; - byte Pad_godefs_0[48]; -}; - -typedef struct Timespec Timespec; -struct Timespec { - int32 tv_sec; - int32 tv_nsec; -}; - -typedef struct Timeval Timeval; -struct Timeval { - int32 tv_sec; - int32 tv_usec; -}; - -typedef struct Sigaction Sigaction; -struct Sigaction { - void *k_sa_handler; - uint32 sa_flags; - void *sa_restorer; - uint32 sa_mask; -}; - -typedef struct Siginfo Siginfo; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - byte _sifields[116]; -}; - -typedef struct Sigaltstack Sigaltstack; -struct Sigaltstack { - void *ss_sp; - int32 ss_flags; - uint32 ss_size; -}; - -typedef struct Sigcontext Sigcontext; -struct Sigcontext { - uint16 gs; - uint16 __gsh; - uint16 fs; - uint16 __fsh; - uint16 es; - uint16 __esh; - uint16 ds; - uint16 __dsh; - uint32 edi; - uint32 esi; - uint32 ebp; - uint32 esp; - uint32 ebx; - uint32 edx; - uint32 ecx; - uint32 eax; - uint32 trapno; - uint32 err; - uint32 eip; - uint16 cs; - uint16 __csh; - uint32 eflags; - uint32 esp_at_signal; - uint16 ss; - uint16 __ssh; - Fpstate *fpstate; - uint32 oldmask; - uint32 cr2; -}; - -typedef struct Ucontext Ucontext; -struct Ucontext { - uint32 uc_flags; - Ucontext *uc_link; - Sigaltstack uc_stack; - Sigcontext uc_mcontext; - uint32 uc_sigmask; -}; - -typedef struct Itimerval Itimerval; -struct Itimerval { - Timeval it_interval; - Timeval it_value; -}; -#pragma pack off diff --git a/src/pkg/runtime/linux/amd64/defs.h b/src/pkg/runtime/linux/amd64/defs.h deleted file mode 100644 index 8053dd16f..000000000 --- a/src/pkg/runtime/linux/amd64/defs.h +++ /dev/null @@ -1,236 +0,0 @@ -// godefs -f -m64 defs.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants -enum { - PROT_NONE = 0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - MAP_ANON = 0x20, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_RESTORER = 0x4000000, - SA_SIGINFO = 0x4, - SIGHUP = 0x1, - SIGINT = 0x2, - SIGQUIT = 0x3, - SIGILL = 0x4, - SIGTRAP = 0x5, - SIGABRT = 0x6, - SIGBUS = 0x7, - SIGFPE = 0x8, - SIGKILL = 0x9, - SIGUSR1 = 0xa, - SIGSEGV = 0xb, - SIGUSR2 = 0xc, - SIGPIPE = 0xd, - SIGALRM = 0xe, - SIGSTKFLT = 0x10, - SIGCHLD = 0x11, - SIGCONT = 0x12, - SIGSTOP = 0x13, - SIGTSTP = 0x14, - SIGTTIN = 0x15, - SIGTTOU = 0x16, - SIGURG = 0x17, - SIGXCPU = 0x18, - SIGXFSZ = 0x19, - SIGVTALRM = 0x1a, - SIGPROF = 0x1b, - SIGWINCH = 0x1c, - SIGIO = 0x1d, - SIGPWR = 0x1e, - SIGSYS = 0x1f, - FPE_INTDIV = 0x1, - FPE_INTOVF = 0x2, - FPE_FLTDIV = 0x3, - FPE_FLTOVF = 0x4, - FPE_FLTUND = 0x5, - FPE_FLTRES = 0x6, - FPE_FLTINV = 0x7, - FPE_FLTSUB = 0x8, - BUS_ADRALN = 0x1, - BUS_ADRERR = 0x2, - BUS_OBJERR = 0x3, - SEGV_MAPERR = 0x1, - SEGV_ACCERR = 0x2, - ITIMER_REAL = 0, - ITIMER_VIRTUAL = 0x1, - ITIMER_PROF = 0x2, - O_RDONLY = 0, - O_CLOEXEC = 02000000, -}; - -// Types -#pragma pack on - -typedef struct Timespec Timespec; -struct Timespec { - int64 tv_sec; - int64 tv_nsec; -}; - -typedef struct Timeval Timeval; -struct Timeval { - int64 tv_sec; - int64 tv_usec; -}; - -typedef struct Sigaction Sigaction; -struct Sigaction { - void *sa_handler; - uint64 sa_flags; - void *sa_restorer; - uint64 sa_mask; -}; - -typedef struct Siginfo Siginfo; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - byte pad_godefs_0[4]; - byte _sifields[112]; -}; - -typedef struct Itimerval Itimerval; -struct Itimerval { - Timeval it_interval; - Timeval it_value; -}; -#pragma pack off -// godefs -f -m64 defs1.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants - -// Types -#pragma pack on - -typedef struct Usigset Usigset; -struct Usigset { - uint64 __val[16]; -}; - -typedef struct Fpxreg Fpxreg; -struct Fpxreg { - uint16 significand[4]; - uint16 exponent; - uint16 padding[3]; -}; - -typedef struct Xmmreg Xmmreg; -struct Xmmreg { - uint32 element[4]; -}; - -typedef struct Fpstate Fpstate; -struct Fpstate { - uint16 cwd; - uint16 swd; - uint16 ftw; - uint16 fop; - uint64 rip; - uint64 rdp; - uint32 mxcsr; - uint32 mxcr_mask; - Fpxreg _st[8]; - Xmmreg _xmm[16]; - uint32 padding[24]; -}; - -typedef struct Fpxreg1 Fpxreg1; -struct Fpxreg1 { - uint16 significand[4]; - uint16 exponent; - uint16 padding[3]; -}; - -typedef struct Xmmreg1 Xmmreg1; -struct Xmmreg1 { - uint32 element[4]; -}; - -typedef struct Fpstate1 Fpstate1; -struct Fpstate1 { - uint16 cwd; - uint16 swd; - uint16 ftw; - uint16 fop; - uint64 rip; - uint64 rdp; - uint32 mxcsr; - uint32 mxcr_mask; - Fpxreg1 _st[8]; - Xmmreg1 _xmm[16]; - uint32 padding[24]; -}; - -typedef struct Fpreg1 Fpreg1; -struct Fpreg1 { - uint16 significand[4]; - uint16 exponent; -}; - -typedef struct Sigaltstack Sigaltstack; -struct Sigaltstack { - void *ss_sp; - int32 ss_flags; - byte pad_godefs_0[4]; - uint64 ss_size; -}; - -typedef struct Mcontext Mcontext; -struct Mcontext { - int64 gregs[23]; - Fpstate *fpregs; - uint64 __reserved1[8]; -}; - -typedef struct Ucontext Ucontext; -struct Ucontext { - uint64 uc_flags; - Ucontext *uc_link; - Sigaltstack uc_stack; - Mcontext uc_mcontext; - Usigset uc_sigmask; - Fpstate __fpregs_mem; -}; - -typedef struct Sigcontext Sigcontext; -struct Sigcontext { - uint64 r8; - uint64 r9; - uint64 r10; - uint64 r11; - uint64 r12; - uint64 r13; - uint64 r14; - uint64 r15; - uint64 rdi; - uint64 rsi; - uint64 rbp; - uint64 rbx; - uint64 rdx; - uint64 rax; - uint64 rcx; - uint64 rsp; - uint64 rip; - uint64 eflags; - uint16 cs; - uint16 gs; - uint16 fs; - uint16 __pad0; - uint64 err; - uint64 trapno; - uint64 oldmask; - uint64 cr2; - Fpstate1 *fpstate; - uint64 __reserved1[8]; -}; -#pragma pack off diff --git a/src/pkg/runtime/linux/defs.c b/src/pkg/runtime/linux/defs.c deleted file mode 100644 index 5dda78789..000000000 --- a/src/pkg/runtime/linux/defs.c +++ /dev/null @@ -1,95 +0,0 @@ -// 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. - -/* - * Input to godefs - godefs -f -m64 defs.c >amd64/defs.h - godefs -f -m64 defs1.c >>amd64/defs.h - */ - -// Linux glibc and Linux kernel define different and conflicting -// definitions for struct sigaction, struct timespec, etc. -// We want the kernel ones, which are in the asm/* headers. -// But then we'd get conflicts when we include the system -// headers for things like ucontext_t, so that happens in -// a separate file, defs1.c. - -#include <asm/posix_types.h> -#define size_t __kernel_size_t -#include <asm/signal.h> -#include <asm/siginfo.h> -#include <asm/mman.h> - -enum { - $PROT_NONE = PROT_NONE, - $PROT_READ = PROT_READ, - $PROT_WRITE = PROT_WRITE, - $PROT_EXEC = PROT_EXEC, - - $MAP_ANON = MAP_ANONYMOUS, - $MAP_PRIVATE = MAP_PRIVATE, - $MAP_FIXED = MAP_FIXED, - - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - $SA_RESTORER = SA_RESTORER, - $SA_SIGINFO = SA_SIGINFO, - - $SIGHUP = SIGHUP, - $SIGINT = SIGINT, - $SIGQUIT = SIGQUIT, - $SIGILL = SIGILL, - $SIGTRAP = SIGTRAP, - $SIGABRT = SIGABRT, - $SIGBUS = SIGBUS, - $SIGFPE = SIGFPE, - $SIGKILL = SIGKILL, - $SIGUSR1 = SIGUSR1, - $SIGSEGV = SIGSEGV, - $SIGUSR2 = SIGUSR2, - $SIGPIPE = SIGPIPE, - $SIGALRM = SIGALRM, - $SIGSTKFLT = SIGSTKFLT, - $SIGCHLD = SIGCHLD, - $SIGCONT = SIGCONT, - $SIGSTOP = SIGSTOP, - $SIGTSTP = SIGTSTP, - $SIGTTIN = SIGTTIN, - $SIGTTOU = SIGTTOU, - $SIGURG = SIGURG, - $SIGXCPU = SIGXCPU, - $SIGXFSZ = SIGXFSZ, - $SIGVTALRM = SIGVTALRM, - $SIGPROF = SIGPROF, - $SIGWINCH = SIGWINCH, - $SIGIO = SIGIO, - $SIGPWR = SIGPWR, - $SIGSYS = SIGSYS, - - $FPE_INTDIV = FPE_INTDIV, - $FPE_INTOVF = FPE_INTOVF, - $FPE_FLTDIV = FPE_FLTDIV, - $FPE_FLTOVF = FPE_FLTOVF, - $FPE_FLTUND = FPE_FLTUND, - $FPE_FLTRES = FPE_FLTRES, - $FPE_FLTINV = FPE_FLTINV, - $FPE_FLTSUB = FPE_FLTSUB, - - $BUS_ADRALN = BUS_ADRALN, - $BUS_ADRERR = BUS_ADRERR, - $BUS_OBJERR = BUS_OBJERR, - - $SEGV_MAPERR = SEGV_MAPERR, - $SEGV_ACCERR = SEGV_ACCERR, - - $ITIMER_REAL = ITIMER_REAL, - $ITIMER_VIRTUAL = ITIMER_VIRTUAL, - $ITIMER_PROF = ITIMER_PROF, -}; - -typedef struct timespec $Timespec; -typedef struct timeval $Timeval; -typedef struct sigaction $Sigaction; -typedef siginfo_t $Siginfo; -typedef struct itimerval $Itimerval; diff --git a/src/pkg/runtime/linux/defs1.c b/src/pkg/runtime/linux/defs1.c deleted file mode 100644 index e737f8e9e..000000000 --- a/src/pkg/runtime/linux/defs1.c +++ /dev/null @@ -1,24 +0,0 @@ -// 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. - -/* - * Input to godefs - godefs -f -m64 defs.c >amd64/defs.h - godefs -f -m64 defs1.c >>amd64/defs.h - */ - -#include <ucontext.h> - -typedef __sigset_t $Usigset; -typedef struct _libc_fpxreg $Fpxreg; -typedef struct _libc_xmmreg $Xmmreg; -typedef struct _libc_fpstate $Fpstate; -typedef struct _fpxreg $Fpxreg1; -typedef struct _xmmreg $Xmmreg1; -typedef struct _fpstate $Fpstate1; -typedef struct _fpreg $Fpreg1; -typedef struct sigaltstack $Sigaltstack; -typedef mcontext_t $Mcontext; -typedef ucontext_t $Ucontext; -typedef struct sigcontext $Sigcontext; diff --git a/src/pkg/runtime/linux/defs2.c b/src/pkg/runtime/linux/defs2.c deleted file mode 100644 index ff641fff2..000000000 --- a/src/pkg/runtime/linux/defs2.c +++ /dev/null @@ -1,120 +0,0 @@ -// 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. - -/* - * Input to godefs - godefs -f -m32 \ - -f -I/home/rsc/pub/linux-2.6/arch/x86/include \ - -f -I/home/rsc/pub/linux-2.6/include \ - -f -D_LOOSE_KERNEL_NAMES \ - -f -D__ARCH_SI_UID_T'='__kernel_uid32_t \ - defs2.c >386/defs.h - - * The asm header tricks we have to use for Linux on amd64 - * (see defs.c and defs1.c) don't work here, so this is yet another - * file. Sigh. - */ - -#include <asm/signal.h> -#include <asm/mman.h> -#include <asm/sigcontext.h> -#include <asm/ucontext.h> -#include <asm/siginfo.h> - -/* -#include <sys/signal.h> -#include <sys/mman.h> -#include <ucontext.h> -*/ - -/* This is the sigaction structure from the Linux 2.1.68 kernel which - is used with the rt_sigaction system call. For 386 this is not - defined in any public header file. */ - -struct kernel_sigaction { - __sighandler_t k_sa_handler; - unsigned long sa_flags; - void (*sa_restorer) (void); - sigset_t sa_mask; -}; - -enum { - $PROT_NONE = PROT_NONE, - $PROT_READ = PROT_READ, - $PROT_WRITE = PROT_WRITE, - $PROT_EXEC = PROT_EXEC, - - $MAP_ANON = MAP_ANONYMOUS, - $MAP_PRIVATE = MAP_PRIVATE, - $MAP_FIXED = MAP_FIXED, - - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - $SA_RESTORER = SA_RESTORER, - $SA_SIGINFO = SA_SIGINFO, - - $SIGHUP = SIGHUP, - $SIGINT = SIGINT, - $SIGQUIT = SIGQUIT, - $SIGILL = SIGILL, - $SIGTRAP = SIGTRAP, - $SIGABRT = SIGABRT, - $SIGBUS = SIGBUS, - $SIGFPE = SIGFPE, - $SIGKILL = SIGKILL, - $SIGUSR1 = SIGUSR1, - $SIGSEGV = SIGSEGV, - $SIGUSR2 = SIGUSR2, - $SIGPIPE = SIGPIPE, - $SIGALRM = SIGALRM, - $SIGSTKFLT = SIGSTKFLT, - $SIGCHLD = SIGCHLD, - $SIGCONT = SIGCONT, - $SIGSTOP = SIGSTOP, - $SIGTSTP = SIGTSTP, - $SIGTTIN = SIGTTIN, - $SIGTTOU = SIGTTOU, - $SIGURG = SIGURG, - $SIGXCPU = SIGXCPU, - $SIGXFSZ = SIGXFSZ, - $SIGVTALRM = SIGVTALRM, - $SIGPROF = SIGPROF, - $SIGWINCH = SIGWINCH, - $SIGIO = SIGIO, - $SIGPWR = SIGPWR, - $SIGSYS = SIGSYS, - - $FPE_INTDIV = FPE_INTDIV, - $FPE_INTOVF = FPE_INTOVF, - $FPE_FLTDIV = FPE_FLTDIV, - $FPE_FLTOVF = FPE_FLTOVF, - $FPE_FLTUND = FPE_FLTUND, - $FPE_FLTRES = FPE_FLTRES, - $FPE_FLTINV = FPE_FLTINV, - $FPE_FLTSUB = FPE_FLTSUB, - - $BUS_ADRALN = BUS_ADRALN, - $BUS_ADRERR = BUS_ADRERR, - $BUS_OBJERR = BUS_OBJERR, - - $SEGV_MAPERR = SEGV_MAPERR, - $SEGV_ACCERR = SEGV_ACCERR, - - $ITIMER_REAL = ITIMER_REAL, - $ITIMER_VIRTUAL = ITIMER_VIRTUAL, - $ITIMER_PROF = ITIMER_PROF, -}; - -typedef struct _fpreg $Fpreg; -typedef struct _fpxreg $Fpxreg; -typedef struct _xmmreg $Xmmreg; -typedef struct _fpstate $Fpstate; -typedef struct timespec $Timespec; -typedef struct timeval $Timeval; -typedef struct kernel_sigaction $Sigaction; -typedef siginfo_t $Siginfo; -typedef struct sigaltstack $Sigaltstack; -typedef struct sigcontext $Sigcontext; -typedef struct ucontext $Ucontext; -typedef struct itimerval $Itimerval; diff --git a/src/pkg/runtime/linux/defs_arm.c b/src/pkg/runtime/linux/defs_arm.c deleted file mode 100644 index 1f935046e..000000000 --- a/src/pkg/runtime/linux/defs_arm.c +++ /dev/null @@ -1,122 +0,0 @@ -// 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. - -/* - * Input to godefs - * On a Debian Lenny arm linux distribution: - godefs -f-I/usr/src/linux-headers-2.6.26-2-versatile/include defs_arm.c - */ - -#define __ARCH_SI_UID_T int - -#include <asm/signal.h> -#include <asm/mman.h> -#include <asm/sigcontext.h> -#include <asm/ucontext.h> -#include <asm/siginfo.h> -#include <linux/time.h> - -/* -#include <sys/signal.h> -#include <sys/mman.h> -#include <ucontext.h> -*/ - -enum { - $PROT_NONE = PROT_NONE, - $PROT_READ = PROT_READ, - $PROT_WRITE = PROT_WRITE, - $PROT_EXEC = PROT_EXEC, - - $MAP_ANON = MAP_ANONYMOUS, - $MAP_PRIVATE = MAP_PRIVATE, - $MAP_FIXED = MAP_FIXED, - - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - $SA_RESTORER = SA_RESTORER, - $SA_SIGINFO = SA_SIGINFO, - - $SIGHUP = SIGHUP, - $SIGINT = SIGINT, - $SIGQUIT = SIGQUIT, - $SIGILL = SIGILL, - $SIGTRAP = SIGTRAP, - $SIGABRT = SIGABRT, - $SIGBUS = SIGBUS, - $SIGFPE = SIGFPE, - $SIGKILL = SIGKILL, - $SIGUSR1 = SIGUSR1, - $SIGSEGV = SIGSEGV, - $SIGUSR2 = SIGUSR2, - $SIGPIPE = SIGPIPE, - $SIGALRM = SIGALRM, - $SIGSTKFLT = SIGSTKFLT, - $SIGCHLD = SIGCHLD, - $SIGCONT = SIGCONT, - $SIGSTOP = SIGSTOP, - $SIGTSTP = SIGTSTP, - $SIGTTIN = SIGTTIN, - $SIGTTOU = SIGTTOU, - $SIGURG = SIGURG, - $SIGXCPU = SIGXCPU, - $SIGXFSZ = SIGXFSZ, - $SIGVTALRM = SIGVTALRM, - $SIGPROF = SIGPROF, - $SIGWINCH = SIGWINCH, - $SIGIO = SIGIO, - $SIGPWR = SIGPWR, - $SIGSYS = SIGSYS, - - $FPE_INTDIV = FPE_INTDIV & 0xFFFF, - $FPE_INTOVF = FPE_INTOVF & 0xFFFF, - $FPE_FLTDIV = FPE_FLTDIV & 0xFFFF, - $FPE_FLTOVF = FPE_FLTOVF & 0xFFFF, - $FPE_FLTUND = FPE_FLTUND & 0xFFFF, - $FPE_FLTRES = FPE_FLTRES & 0xFFFF, - $FPE_FLTINV = FPE_FLTINV & 0xFFFF, - $FPE_FLTSUB = FPE_FLTSUB & 0xFFFF, - - $BUS_ADRALN = BUS_ADRALN & 0xFFFF, - $BUS_ADRERR = BUS_ADRERR & 0xFFFF, - $BUS_OBJERR = BUS_OBJERR & 0xFFFF, - - $SEGV_MAPERR = SEGV_MAPERR & 0xFFFF, - $SEGV_ACCERR = SEGV_ACCERR & 0xFFFF, - - $ITIMER_REAL = ITIMER_REAL, - $ITIMER_PROF = ITIMER_PROF, - $ITIMER_VIRTUAL = ITIMER_VIRTUAL, -}; - -typedef sigset_t $Sigset; -typedef struct timespec $Timespec; -typedef struct sigaltstack $Sigaltstack; -typedef struct sigcontext $Sigcontext; -typedef struct ucontext $Ucontext; -typedef struct timeval $Timeval; -typedef struct itimerval $Itimerval; - -struct xsiginfo { - int si_signo; - int si_errno; - int si_code; - char _sifields[4]; -}; - -typedef struct xsiginfo $Siginfo; - -#undef sa_handler -#undef sa_flags -#undef sa_restorer -#undef sa_mask - -struct xsigaction { - void (*sa_handler)(void); - unsigned long sa_flags; - void (*sa_restorer)(void); - unsigned int sa_mask; /* mask last for extensibility */ -}; - -typedef struct xsigaction $Sigaction; diff --git a/src/pkg/runtime/lock_futex.c b/src/pkg/runtime/lock_futex.c new file mode 100644 index 000000000..6ec4aee7b --- /dev/null +++ b/src/pkg/runtime/lock_futex.c @@ -0,0 +1,148 @@ +// 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 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(m->locks++ < 0) + runtime·throw("runtime·lock: lock count"); + + // Speculative grab for lock. + v = runtime·xchg(&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(&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(&l->key, MUTEX_UNLOCKED, wait)) + return; + runtime·osyield(); + } + + // Sleep. + v = runtime·xchg(&l->key, MUTEX_SLEEPING); + if(v == MUTEX_UNLOCKED) + return; + wait = MUTEX_SLEEPING; + runtime·futexsleep(&l->key, MUTEX_SLEEPING, -1); + } +} + +void +runtime·unlock(Lock *l) +{ + uint32 v; + + if(--m->locks < 0) + runtime·throw("runtime·unlock: lock count"); + + v = runtime·xchg(&l->key, MUTEX_UNLOCKED); + if(v == MUTEX_UNLOCKED) + runtime·throw("unlock of unlocked lock"); + if(v == MUTEX_SLEEPING) + runtime·futexwakeup(&l->key, 1); +} + +// One-time notifications. +void +runtime·noteclear(Note *n) +{ + n->key = 0; +} + +void +runtime·notewakeup(Note *n) +{ + runtime·xchg(&n->key, 1); + runtime·futexwakeup(&n->key, 1); +} + +void +runtime·notesleep(Note *n) +{ + while(runtime·atomicload(&n->key) == 0) + runtime·futexsleep(&n->key, 0, -1); +} + +void +runtime·notetsleep(Note *n, int64 ns) +{ + int64 deadline, now; + + if(ns < 0) { + runtime·notesleep(n); + return; + } + + if(runtime·atomicload(&n->key) != 0) + return; + + deadline = runtime·nanotime() + ns; + for(;;) { + runtime·futexsleep(&n->key, 0, ns); + if(runtime·atomicload(&n->key) != 0) + return; + now = runtime·nanotime(); + if(now >= deadline) + return; + ns = deadline - now; + } +} diff --git a/src/pkg/runtime/lock_sema.c b/src/pkg/runtime/lock_sema.c new file mode 100644 index 000000000..28d2c3281 --- /dev/null +++ b/src/pkg/runtime/lock_sema.c @@ -0,0 +1,219 @@ +// 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 netbsd openbsd plan9 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) +{ + uintptr v; + uint32 i, spin; + + if(m->locks++ < 0) + runtime·throw("runtime·lock: lock count"); + + // Speculative grab for lock. + if(runtime·casp(&l->waitm, 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(&l->waitm); + if((v&LOCKED) == 0) { +unlocked: + if(runtime·casp(&l->waitm, (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 = (void*)(v&~LOCKED); + if(runtime·casp(&l->waitm, (void*)v, (void*)((uintptr)m|LOCKED))) + break; + v = (uintptr)runtime·atomicloadp(&l->waitm); + 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; + + if(--m->locks < 0) + runtime·throw("runtime·unlock: lock count"); + + for(;;) { + v = (uintptr)runtime·atomicloadp(&l->waitm); + if(v == LOCKED) { + if(runtime·casp(&l->waitm, (void*)LOCKED, nil)) + break; + } else { + // Other M's are waiting for the lock. + // Dequeue an M. + mp = (void*)(v&~LOCKED); + if(runtime·casp(&l->waitm, (void*)v, mp->nextwaitm)) { + // Dequeued an M. Wake it. + runtime·semawakeup(mp); + break; + } + } + } +} + +// One-time notifications. +void +runtime·noteclear(Note *n) +{ + n->waitm = nil; +} + +void +runtime·notewakeup(Note *n) +{ + M *mp; + + do + mp = runtime·atomicloadp(&n->waitm); + while(!runtime·casp(&n->waitm, 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) +{ + if(m->waitsema == 0) + m->waitsema = runtime·semacreate(); + if(!runtime·casp(&n->waitm, nil, m)) { // must be LOCKED (got wakeup) + if(n->waitm != (void*)LOCKED) + runtime·throw("notesleep - waitm out of sync"); + return; + } + // Queued. Sleep. + runtime·semasleep(-1); +} + +void +runtime·notetsleep(Note *n, int64 ns) +{ + M *mp; + int64 deadline, now; + + if(ns < 0) { + runtime·notesleep(n); + return; + } + + if(m->waitsema == 0) + m->waitsema = runtime·semacreate(); + + // Register for wakeup on n->waitm. + if(!runtime·casp(&n->waitm, nil, m)) { // must be LOCKED (got wakeup already) + if(n->waitm != (void*)LOCKED) + runtime·throw("notetsleep - waitm out of sync"); + return; + } + + deadline = runtime·nanotime() + ns; + for(;;) { + // Registered. Sleep. + if(runtime·semasleep(ns) >= 0) { + // Acquired semaphore, semawakeup unregistered us. + // Done. + return; + } + + // Interrupted or timed out. Still registered. Semaphore not acquired. + now = runtime·nanotime(); + if(now >= deadline) + break; + + // Deadline hasn't arrived. Keep sleeping. + ns = deadline - now; + } + + // 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(&n->waitm); + if(mp == m) { + // No wakeup yet; unregister if possible. + if(runtime·casp(&n->waitm, mp, nil)) + return; + } else if(mp == (M*)LOCKED) { + // Wakeup happened so semaphore is available. + // Grab it to avoid getting out of sync. + if(runtime·semasleep(-1) < 0) + runtime·throw("runtime: unable to acquire - semaphore out of sync"); + return; + } else { + runtime·throw("runtime: unexpected waitm - semaphore out of sync"); + } + } +} diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc index 84e0ac479..f1509cd9d 100644 --- a/src/pkg/runtime/malloc.goc +++ b/src/pkg/runtime/malloc.goc @@ -8,9 +8,10 @@ package runtime #include "runtime.h" +#include "arch_GOARCH.h" #include "stack.h" #include "malloc.h" -#include "defs.h" +#include "defs_GOOS_GOARCH.h" #include "type.h" MHeap runtime·mheap; @@ -80,11 +81,12 @@ runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed) m->mcache->next_sample -= size; else { // pick next profile time + // If you change this, also change allocmcache. if(rate > 0x3fffffff) // make 2*rate not overflow rate = 0x3fffffff; m->mcache->next_sample = runtime·fastrand1() % (2*rate); profile: - runtime·setblockspecial(v); + runtime·setblockspecial(v, true); runtime·MProf_Malloc(v, size); } } @@ -113,7 +115,7 @@ runtime·free(void *v) if(v == nil) return; - // If you change this also change mgc0.c:/^sweepspan, + // If you change this also change mgc0.c:/^sweep, // which has a copy of the guts of free. if(m->mallocing) @@ -205,6 +207,7 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp) MCache* runtime·allocmcache(void) { + int32 rate; MCache *c; runtime·lock(&runtime·mheap); @@ -212,6 +215,14 @@ runtime·allocmcache(void) mstats.mcache_inuse = runtime·mheap.cachealloc.inuse; mstats.mcache_sys = runtime·mheap.cachealloc.sys; runtime·unlock(&runtime·mheap); + + // Set first allocation sample size. + rate = runtime·MemProfileRate; + if(rate > 0x3fffffff) // make 2*rate not overflow + rate = 0x3fffffff; + if(rate != 0) + c->next_sample = runtime·fastrand1() % (2*rate); + return c; } @@ -383,8 +394,10 @@ runtime·mal(uintptr n) return runtime·mallocgc(n, 0, 1, 1); } -func new(n uint32) (ret *uint8) { - ret = runtime·mal(n); +func new(typ *Type) (ret *uint8) { + uint32 flag = typ->kind&KindNoPointers ? FlagNoPointers : 0; + ret = runtime·mallocgc(typ->size, flag, 1, 1); + FLUSH(&ret); } void* @@ -448,8 +461,7 @@ func SetFinalizer(obj Eface, finalizer Eface) { if(obj.type == nil) { runtime·printf("runtime.SetFinalizer: first argument is nil interface\n"); - throw: - runtime·throw("runtime.SetFinalizer"); + goto throw; } if(obj.type->kind != KindPtr) { runtime·printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string); @@ -461,11 +473,8 @@ func SetFinalizer(obj Eface, finalizer Eface) { } nret = 0; if(finalizer.type != nil) { - if(finalizer.type->kind != KindFunc) { - badfunc: - runtime·printf("runtime.SetFinalizer: second argument is %S, not func(%S)\n", *finalizer.type->string, *obj.type->string); - goto throw; - } + if(finalizer.type->kind != KindFunc) + goto badfunc; ft = (FuncType*)finalizer.type; if(ft->dotdotdot || ft->in.len != 1 || *(Type**)ft->in.array != obj.type) goto badfunc; @@ -477,11 +486,16 @@ func SetFinalizer(obj Eface, finalizer Eface) { nret += t->size; } nret = (nret + sizeof(void*)-1) & ~(sizeof(void*)-1); - - if(runtime·getfinalizer(obj.data, 0)) { - runtime·printf("runtime.SetFinalizer: finalizer already set\n"); - goto throw; - } } - runtime·addfinalizer(obj.data, finalizer.data, nret); + + if(!runtime·addfinalizer(obj.data, finalizer.data, nret)) { + runtime·printf("runtime.SetFinalizer: finalizer already set\n"); + goto throw; + } + return; + +badfunc: + runtime·printf("runtime.SetFinalizer: second argument is %S, not func(%S)\n", *finalizer.type->string, *obj.type->string); +throw: + runtime·throw("runtime.SetFinalizer"); } diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h index 5bc80f4df..a85e1af8c 100644 --- a/src/pkg/runtime/malloc.h +++ b/src/pkg/runtime/malloc.h @@ -120,6 +120,12 @@ enum #else MHeapMap_Bits = 20, #endif + + // Max number of threads to run garbage collection. + // 2, 3, and 4 are all plausible maximums depending + // on the hardware details of the machine. The garbage + // collector scales well to 4 cpus. + MaxGcproc = 4, }; // A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).) @@ -192,7 +198,7 @@ struct MStats uint64 nlookup; // number of pointer lookups uint64 nmalloc; // number of mallocs uint64 nfree; // number of frees - + // Statistics about malloc heap. // protected by mheap.Lock uint64 heap_alloc; // bytes allocated and still in use @@ -210,7 +216,7 @@ struct MStats uint64 mcache_inuse; // MCache structures uint64 mcache_sys; uint64 buckhash_sys; // profiling bucket hash table - + // Statistics about garbage collector. // Protected by stopping the world during GC. uint64 next_gc; // next GC (in heap_alloc time) @@ -219,7 +225,7 @@ struct MStats uint32 numgc; bool enablegc; bool debuggc; - + // Statistics about allocation size classes. struct { uint32 size; @@ -240,7 +246,7 @@ extern MStats mstats; // // class_to_size[i] = largest size in class i // class_to_allocnpages[i] = number of pages to allocate when -// making new objects in class i +// making new objects in class i // class_to_transfercount[i] = number of objects to move when // taking a bunch of objects out of the central lists // and putting them in the thread free list. @@ -279,7 +285,7 @@ struct MCache int64 nmalloc; int64 nfree; } local_by_size[NumSizeClasses]; - + }; void* runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed); @@ -352,14 +358,14 @@ struct MHeap byte *arena_start; byte *arena_used; byte *arena_end; - + // central free lists for small size classes. // the union makes sure that the MCentrals are - // spaced 64 bytes apart, so that each MCentral.Lock + // spaced CacheLineSize bytes apart, so that each MCentral.Lock // gets its own cache line. union { MCentral; - byte pad[64]; + byte pad[CacheLineSize]; } central[NumSizeClasses]; FixAlloc spanalloc; // allocator for Span* @@ -387,7 +393,7 @@ int32 runtime·checking; void runtime·markspan(void *v, uintptr size, uintptr n, bool leftover); void runtime·unmarkspan(void *v, uintptr size); bool runtime·blockspecial(void*); -void runtime·setblockspecial(void*); +void runtime·setblockspecial(void*, bool); void runtime·purgecachedstats(M*); enum @@ -400,6 +406,8 @@ enum void runtime·MProf_Malloc(void*, uintptr); void runtime·MProf_Free(void*, uintptr); +int32 runtime·helpgc(bool*); +void runtime·gchelper(void); // Malloc profiling settings. // Must match definition in extern.go. @@ -410,13 +418,5 @@ enum { }; extern int32 runtime·malloc_profile; -typedef struct Finalizer Finalizer; -struct Finalizer -{ - Finalizer *next; // for use by caller of getfinalizer - void (*fn)(void*); - void *arg; - int32 nret; -}; - -Finalizer* runtime·getfinalizer(void*, bool); +bool runtime·getfinalizer(void *p, bool del, void (**fn)(void*), int32 *nret); +void runtime·walkfintab(void (*fn)(void*)); diff --git a/src/pkg/runtime/mcache.c b/src/pkg/runtime/mcache.c index 711e938fc..518e00c12 100644 --- a/src/pkg/runtime/mcache.c +++ b/src/pkg/runtime/mcache.c @@ -7,6 +7,7 @@ // See malloc.h for an overview. #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" void* diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c index 29b03b58f..ff0c2d11a 100644 --- a/src/pkg/runtime/mcentral.c +++ b/src/pkg/runtime/mcentral.c @@ -15,6 +15,7 @@ // so that it is faster to move those lists between MCaches and MCentrals. #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" static bool MCentral_Grow(MCentral *c); diff --git a/src/pkg/runtime/darwin/mem.c b/src/pkg/runtime/mem_darwin.c index 935c032bc..cde5601cf 100644 --- a/src/pkg/runtime/darwin/mem.c +++ b/src/pkg/runtime/mem_darwin.c @@ -1,6 +1,11 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + #include "runtime.h" -#include "defs.h" -#include "os.h" +#include "arch_GOARCH.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" #include "malloc.h" void* @@ -18,9 +23,8 @@ runtime·SysAlloc(uintptr n) void runtime·SysUnused(void *v, uintptr n) { - USED(v); - USED(n); - // TODO(rsc): call madvise MADV_DONTNEED + // Linux's MADV_DONTNEED is like BSD's MADV_FREE. + runtime·madvise(v, n, MADV_FREE); } void diff --git a/src/pkg/runtime/freebsd/mem.c b/src/pkg/runtime/mem_freebsd.c index 07abf2cfe..d1c22583d 100644 --- a/src/pkg/runtime/freebsd/mem.c +++ b/src/pkg/runtime/mem_freebsd.c @@ -1,6 +1,11 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + #include "runtime.h" -#include "defs.h" -#include "os.h" +#include "arch_GOARCH.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" #include "malloc.h" void* diff --git a/src/pkg/runtime/linux/mem.c b/src/pkg/runtime/mem_linux.c index 6c5c908cc..fdf02c2ca 100644 --- a/src/pkg/runtime/linux/mem.c +++ b/src/pkg/runtime/mem_linux.c @@ -1,6 +1,11 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + #include "runtime.h" -#include "defs.h" -#include "os.h" +#include "arch_GOARCH.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" #include "malloc.h" enum @@ -51,9 +56,7 @@ runtime·SysAlloc(uintptr n) void runtime·SysUnused(void *v, uintptr n) { - USED(v); - USED(n); - // TODO(rsc): call madvise MADV_DONTNEED + runtime·madvise(v, n, MADV_DONTNEED); } void diff --git a/src/pkg/runtime/openbsd/mem.c b/src/pkg/runtime/mem_netbsd.c index 46b6b07ee..34ff31d90 100644 --- a/src/pkg/runtime/openbsd/mem.c +++ b/src/pkg/runtime/mem_netbsd.c @@ -1,6 +1,11 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + #include "runtime.h" -#include "defs.h" -#include "os.h" +#include "arch_GOARCH.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" #include "malloc.h" enum diff --git a/src/pkg/runtime/mem_openbsd.c b/src/pkg/runtime/mem_openbsd.c new file mode 100644 index 000000000..34ff31d90 --- /dev/null +++ b/src/pkg/runtime/mem_openbsd.c @@ -0,0 +1,85 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" +#include "arch_GOARCH.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "malloc.h" + +enum +{ + ENOMEM = 12, +}; + +void* +runtime·SysAlloc(uintptr n) +{ + void *v; + + mstats.sys += n; + v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0); + if(v < (void*)4096) + return nil; + return v; +} + +void +runtime·SysUnused(void *v, uintptr n) +{ + USED(v); + USED(n); + // TODO(rsc): call madvise MADV_DONTNEED +} + +void +runtime·SysFree(void *v, uintptr n) +{ + mstats.sys -= n; + runtime·munmap(v, n); +} + +void* +runtime·SysReserve(void *v, uintptr n) +{ + void *p; + + // On 64-bit, people with ulimit -v set complain if we reserve too + // much address space. Instead, assume that the reservation is okay + // and check the assumption in SysMap. + if(sizeof(void*) == 8) + return v; + + p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); + if (p == ((void *)-ENOMEM)) + return nil; + else + return p; +} + +void +runtime·SysMap(void *v, uintptr n) +{ + void *p; + + mstats.sys += n; + + // On 64-bit, we don't actually have v reserved, so tread carefully. + if(sizeof(void*) == 8) { + p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0); + if(p == (void*)-ENOMEM) + runtime·throw("runtime: out of memory"); + if(p != v) { + runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p); + runtime·throw("runtime: address space conflict"); + } + return; + } + + p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0); + if(p == (void*)-ENOMEM) + runtime·throw("runtime: out of memory"); + if(p != v) + runtime·throw("runtime: cannot map pages in arena address space"); +} diff --git a/src/pkg/runtime/plan9/mem.c b/src/pkg/runtime/mem_plan9.c index f795b2c01..15cbc176b 100644 --- a/src/pkg/runtime/plan9/mem.c +++ b/src/pkg/runtime/mem_plan9.c @@ -3,8 +3,9 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" -#include "os.h" +#include "os_GOOS.h" extern byte end[]; static byte *bloc = { end }; @@ -26,7 +27,7 @@ runtime·SysAlloc(uintptr nbytes) bl = ((uintptr)bloc + Round) & ~Round; if(runtime·brk_((void*)(bl + nbytes)) < 0) { runtime·unlock(&memlock); - return (void*)-1; + return nil; } bloc = (byte*)bl + nbytes; runtime·unlock(&memlock); diff --git a/src/pkg/runtime/windows/mem.c b/src/pkg/runtime/mem_windows.c index 5d2291fa3..7840daa22 100644 --- a/src/pkg/runtime/windows/mem.c +++ b/src/pkg/runtime/mem_windows.c @@ -3,8 +3,9 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "os.h" -#include "defs.h" +#include "arch_GOARCH.h" +#include "os_GOOS.h" +#include "defs_GOOS_GOARCH.h" #include "malloc.h" enum { diff --git a/src/pkg/runtime/386/memmove.s b/src/pkg/runtime/memmove_386.s index 203a8187c..203a8187c 100644 --- a/src/pkg/runtime/386/memmove.s +++ b/src/pkg/runtime/memmove_386.s diff --git a/src/pkg/runtime/amd64/memmove.s b/src/pkg/runtime/memmove_amd64.s index e78be8145..e78be8145 100644 --- a/src/pkg/runtime/amd64/memmove.s +++ b/src/pkg/runtime/memmove_amd64.s diff --git a/src/pkg/runtime/arm/memmove.s b/src/pkg/runtime/memmove_arm.s index 5c0e57404..5c0e57404 100644 --- a/src/pkg/runtime/arm/memmove.s +++ b/src/pkg/runtime/memmove_arm.s diff --git a/src/pkg/runtime/arm/memset.s b/src/pkg/runtime/memset_arm.s index 974b8da7a..974b8da7a 100644 --- a/src/pkg/runtime/arm/memset.s +++ b/src/pkg/runtime/memset_arm.s diff --git a/src/pkg/runtime/mfinal.c b/src/pkg/runtime/mfinal.c index f3138145b..c6f2b5421 100644 --- a/src/pkg/runtime/mfinal.c +++ b/src/pkg/runtime/mfinal.c @@ -3,12 +3,17 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" -// Lock to protect finalizer data structures. -// Cannot reuse mheap.Lock because the finalizer -// maintenance requires allocation. -static Lock finlock; +enum { debug = 0 }; + +typedef struct Fin Fin; +struct Fin +{ + void (*fn)(void*); + int32 nret; +}; // Finalizer hash table. Direct hash, linear scan, at most 3/4 full. // Table size is power of 3 so that hash can be key % max. @@ -20,15 +25,24 @@ static Lock finlock; typedef struct Fintab Fintab; struct Fintab { + Lock; void **key; - Finalizer **val; + Fin *val; int32 nkey; // number of non-nil entries in key int32 ndead; // number of dead (-1) entries in key int32 max; // size of key, val allocations }; +#define TABSZ 17 +#define TAB(p) (&fintab[((uintptr)(p)>>3)%TABSZ]) + +static struct { + Fintab; + uint8 pad[CacheLineSize - sizeof(Fintab)]; +} fintab[TABSZ]; + static void -addfintab(Fintab *t, void *k, Finalizer *v) +addfintab(Fintab *t, void *k, void (*fn)(void*), int32 nret) { int32 i, j; @@ -51,29 +65,31 @@ addfintab(Fintab *t, void *k, Finalizer *v) ret: t->key[i] = k; - t->val[i] = v; + t->val[i].fn = fn; + t->val[i].nret = nret; } -static Finalizer* -lookfintab(Fintab *t, void *k, bool del) +static bool +lookfintab(Fintab *t, void *k, bool del, Fin *f) { int32 i, j; - Finalizer *v; if(t->max == 0) - return nil; + return false; i = (uintptr)k % (uintptr)t->max; for(j=0; j<t->max; j++) { if(t->key[i] == nil) - return nil; + return false; if(t->key[i] == k) { - v = t->val[i]; + if(f) + *f = t->val[i]; if(del) { t->key[i] = (void*)-1; - t->val[i] = nil; + t->val[i].fn = nil; + t->val[i].nret = 0; t->ndead++; } - return v; + return true; } if(++i == t->max) i = 0; @@ -81,88 +97,100 @@ lookfintab(Fintab *t, void *k, bool del) // cannot happen - table is known to be non-full runtime·throw("finalizer table inconsistent"); - return nil; + return false; } -static Fintab fintab; - -// add finalizer; caller is responsible for making sure not already in table -void -runtime·addfinalizer(void *p, void (*f)(void*), int32 nret) +static void +resizefintab(Fintab *tab) { Fintab newtab; + void *k; int32 i; - byte *base; - Finalizer *e; + + runtime·memclr((byte*)&newtab, sizeof newtab); + newtab.max = tab->max; + if(newtab.max == 0) + newtab.max = 3*3*3; + else if(tab->ndead < tab->nkey/2) { + // grow table if not many dead values. + // otherwise just rehash into table of same size. + newtab.max *= 3; + } - e = nil; - if(f != nil) { - e = runtime·mal(sizeof *e); - e->fn = f; - e->nret = nret; + newtab.key = runtime·mallocgc(newtab.max*sizeof newtab.key[0], FlagNoPointers, 0, 1); + newtab.val = runtime·mallocgc(newtab.max*sizeof newtab.val[0], 0, 0, 1); + + for(i=0; i<tab->max; i++) { + k = tab->key[i]; + if(k != nil && k != (void*)-1) + addfintab(&newtab, k, tab->val[i].fn, tab->val[i].nret); } + + runtime·free(tab->key); + runtime·free(tab->val); + + tab->key = newtab.key; + tab->val = newtab.val; + tab->nkey = newtab.nkey; + tab->ndead = newtab.ndead; + tab->max = newtab.max; +} - runtime·lock(&finlock); - if(!runtime·mlookup(p, &base, nil, nil) || p != base) { - runtime·unlock(&finlock); - runtime·throw("addfinalizer on invalid pointer"); +bool +runtime·addfinalizer(void *p, void (*f)(void*), int32 nret) +{ + Fintab *tab; + byte *base; + + if(debug) { + if(!runtime·mlookup(p, &base, nil, nil) || p != base) + runtime·throw("addfinalizer on invalid pointer"); } + + tab = TAB(p); + runtime·lock(tab); if(f == nil) { - lookfintab(&fintab, p, 1); - runtime·unlock(&finlock); - return; + if(lookfintab(tab, p, true, nil)) + runtime·setblockspecial(p, false); + runtime·unlock(tab); + return true; } - if(lookfintab(&fintab, p, 0)) { - runtime·unlock(&finlock); - runtime·throw("double finalizer"); + if(lookfintab(tab, p, false, nil)) { + runtime·unlock(tab); + return false; } - runtime·setblockspecial(p); - if(fintab.nkey >= fintab.max/2+fintab.max/4) { + if(tab->nkey >= tab->max/2+tab->max/4) { // keep table at most 3/4 full: // allocate new table and rehash. - - runtime·memclr((byte*)&newtab, sizeof newtab); - newtab.max = fintab.max; - if(newtab.max == 0) - newtab.max = 3*3*3; - else if(fintab.ndead < fintab.nkey/2) { - // grow table if not many dead values. - // otherwise just rehash into table of same size. - newtab.max *= 3; - } - - newtab.key = runtime·mallocgc(newtab.max*sizeof newtab.key[0], FlagNoPointers, 0, 1); - newtab.val = runtime·mallocgc(newtab.max*sizeof newtab.val[0], 0, 0, 1); - - for(i=0; i<fintab.max; i++) { - void *k; - - k = fintab.key[i]; - if(k != nil && k != (void*)-1) - addfintab(&newtab, k, fintab.val[i]); - } - runtime·free(fintab.key); - runtime·free(fintab.val); - fintab = newtab; + resizefintab(tab); } - addfintab(&fintab, p, e); - runtime·unlock(&finlock); + addfintab(tab, p, f, nret); + runtime·setblockspecial(p, true); + runtime·unlock(tab); + return true; } // get finalizer; if del, delete finalizer. -// caller is responsible for updating RefHasFinalizer bit. -Finalizer* -runtime·getfinalizer(void *p, bool del) +// caller is responsible for updating RefHasFinalizer (special) bit. +bool +runtime·getfinalizer(void *p, bool del, void (**fn)(void*), int32 *nret) { - Finalizer *f; + Fintab *tab; + bool res; + Fin f; - runtime·lock(&finlock); - f = lookfintab(&fintab, p, del); - runtime·unlock(&finlock); - return f; + tab = TAB(p); + runtime·lock(tab); + res = lookfintab(tab, p, del, &f); + runtime·unlock(tab); + if(res==false) + return false; + *fn = f.fn; + *nret = f.nret; + return true; } void @@ -170,12 +198,15 @@ runtime·walkfintab(void (*fn)(void*)) { void **key; void **ekey; + int32 i; - runtime·lock(&finlock); - key = fintab.key; - ekey = key + fintab.max; - for(; key < ekey; key++) - if(*key != nil && *key != ((void*)-1)) - fn(*key); - runtime·unlock(&finlock); + for(i=0; i<TABSZ; i++) { + runtime·lock(&fintab[i]); + key = fintab[i].key; + ekey = key + fintab[i].max; + for(; key < ekey; key++) + if(*key != nil && *key != ((void*)-1)) + fn(*key); + runtime·unlock(&fintab[i]); + } } diff --git a/src/pkg/runtime/mfinal_test.go b/src/pkg/runtime/mfinal_test.go new file mode 100644 index 000000000..de632717a --- /dev/null +++ b/src/pkg/runtime/mfinal_test.go @@ -0,0 +1,64 @@ +// 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_test + +import ( + "runtime" + "sync" + "sync/atomic" + "testing" +) + +func fin(v *int) { +} + +func BenchmarkFinalizer(b *testing.B) { + const CallsPerSched = 1000 + procs := runtime.GOMAXPROCS(-1) + N := int32(b.N / CallsPerSched) + var wg sync.WaitGroup + wg.Add(procs) + for p := 0; p < procs; p++ { + go func() { + var data [CallsPerSched]*int + for i := 0; i < CallsPerSched; i++ { + data[i] = new(int) + } + for atomic.AddInt32(&N, -1) >= 0 { + runtime.Gosched() + for i := 0; i < CallsPerSched; i++ { + runtime.SetFinalizer(data[i], fin) + } + for i := 0; i < CallsPerSched; i++ { + runtime.SetFinalizer(data[i], nil) + } + } + wg.Done() + }() + } + wg.Wait() +} + +func BenchmarkFinalizerRun(b *testing.B) { + const CallsPerSched = 1000 + procs := runtime.GOMAXPROCS(-1) + N := int32(b.N / CallsPerSched) + var wg sync.WaitGroup + wg.Add(procs) + for p := 0; p < procs; p++ { + go func() { + for atomic.AddInt32(&N, -1) >= 0 { + runtime.Gosched() + for i := 0; i < CallsPerSched; i++ { + v := new(int) + runtime.SetFinalizer(v, fin) + } + runtime.GC() + } + wg.Done() + }() + } + wg.Wait() +} diff --git a/src/pkg/runtime/mfixalloc.c b/src/pkg/runtime/mfixalloc.c index ab9df3196..c916d588f 100644 --- a/src/pkg/runtime/mfixalloc.c +++ b/src/pkg/runtime/mfixalloc.c @@ -7,6 +7,7 @@ // See malloc.h for overview. #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" // Initialize f to allocate objects of the given size, diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 03d6f7d62..78daa7836 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -5,14 +5,15 @@ // Garbage collector. #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" #include "stack.h" enum { Debug = 0, - UseCas = 1, PtrSize = sizeof(void*), - + DebugMark = 0, // run second pass to check mark + // Four bits per word (see #defines below). wordsPerBitmapWord = sizeof(void*)*8/4, bitShift = sizeof(void*)*8/4, @@ -51,17 +52,35 @@ enum { #define bitMask (bitBlockBoundary | bitAllocated | bitMarked | bitSpecial) -static uint64 nlookup; -static uint64 nsizelookup; -static uint64 naddrlookup; +// TODO: Make these per-M. +static uint64 nhandoff; + static int32 gctrace; typedef struct Workbuf Workbuf; struct Workbuf { Workbuf *next; - uintptr nw; - byte *w[2048-2]; + uintptr nobj; + byte *obj[512-2]; +}; + +typedef struct Finalizer Finalizer; +struct Finalizer +{ + void (*fn)(void*); + void *arg; + int32 nret; +}; + +typedef struct FinBlock FinBlock; +struct FinBlock +{ + FinBlock *alllink; + FinBlock *next; + int32 cnt; + int32 cap; + Finalizer fin[1]; }; extern byte data[]; @@ -69,12 +88,35 @@ extern byte etext[]; extern byte end[]; static G *fing; -static Finalizer *finq; +static FinBlock *finq; // list of finalizers that are to be executed +static FinBlock *finc; // cache of free blocks +static FinBlock *allfin; // list of all blocks +static Lock finlock; static int32 fingwait; static void runfinq(void); static Workbuf* getempty(Workbuf*); static Workbuf* getfull(Workbuf*); +static void putempty(Workbuf*); +static Workbuf* handoff(Workbuf*); + +static struct { + Lock fmu; + Workbuf *full; + Lock emu; + Workbuf *empty; + uint32 nproc; + volatile uint32 nwait; + volatile uint32 ndone; + Note alldone; + Lock markgate; + Lock sweepgate; + MSpan *spans; + + Lock; + byte *chunk; + uintptr nchunk; +} work; // scanblock scans a block of n bytes starting at pointer b for references // to other objects, scanning any it finds recursively until there are no @@ -85,13 +127,14 @@ static Workbuf* getfull(Workbuf*); static void scanblock(byte *b, int64 n) { - byte *obj, *arena_start, *p; + byte *obj, *arena_start, *arena_used, *p; void **vp; - uintptr size, *bitp, bits, shift, i, j, x, xbits, off; + uintptr size, *bitp, bits, shift, i, j, x, xbits, off, nobj, nproc; MSpan *s; PageID k; - void **bw, **w, **ew; + void **wp; Workbuf *wbuf; + bool keepworking; if((int64)(uintptr)n != n || n < 0) { runtime·printf("scanblock %p %D\n", b, n); @@ -100,11 +143,19 @@ scanblock(byte *b, int64 n) // Memory arena parameters. arena_start = runtime·mheap.arena_start; - + arena_used = runtime·mheap.arena_used; + nproc = work.nproc; + wbuf = nil; // current work buffer - ew = nil; // end of work buffer - bw = nil; // beginning of work buffer - w = nil; // current pointer into work buffer + wp = nil; // storage for next queued pointer (write pointer) + nobj = 0; // number of queued objects + + // Scanblock helpers pass b==nil. + // The main proc needs to return to make more + // calls to scanblock. But if work.nproc==1 then + // might as well process blocks as soon as we + // have them. + keepworking = b == nil || work.nproc == 1; // Align b to a word boundary. off = (uintptr)b & (PtrSize-1); @@ -120,17 +171,17 @@ scanblock(byte *b, int64 n) runtime·printf("scanblock %p %D\n", b, n); vp = (void**)b; - n /= PtrSize; + n >>= (2+PtrSize/8); /* n /= PtrSize (4 or 8) */ for(i=0; i<n; i++) { obj = (byte*)vp[i]; - + // Words outside the arena cannot be pointers. - if((byte*)obj < arena_start || (byte*)obj >= runtime·mheap.arena_used) + if((byte*)obj < arena_start || (byte*)obj >= arena_used) continue; - + // obj may be a pointer to a live object. // Try to find the beginning of the object. - + // Round down to word boundary. obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1)); @@ -158,8 +209,6 @@ scanblock(byte *b, int64 n) // Otherwise consult span table to find beginning. // (Manually inlined copy of MHeap_LookupMaybe.) - nlookup++; - naddrlookup++; k = (uintptr)obj>>PageShift; x = k; if(sizeof(void*) == 8) @@ -188,83 +237,67 @@ scanblock(byte *b, int64 n) found: // Now we have bits, bitp, and shift correct for // obj pointing at the base of the object. - // If not allocated or already marked, done. - if((bits & bitAllocated) == 0 || (bits & bitMarked) != 0) + // Only care about allocated and not marked. + if((bits & (bitAllocated|bitMarked)) != bitAllocated) continue; - *bitp |= bitMarked<<shift; + if(nproc == 1) + *bitp |= bitMarked<<shift; + else { + for(;;) { + x = *bitp; + if(x & (bitMarked<<shift)) + goto continue_obj; + if(runtime·casp((void**)bitp, (void*)x, (void*)(x|(bitMarked<<shift)))) + break; + } + } // If object has no pointers, don't need to scan further. if((bits & bitNoPointers) != 0) continue; + // If another proc wants a pointer, give it some. + if(nobj > 4 && work.nwait > 0 && work.full == nil) { + wbuf->nobj = nobj; + wbuf = handoff(wbuf); + nobj = wbuf->nobj; + wp = wbuf->obj + nobj; + } + // If buffer is full, get a new one. - if(w >= ew) { + if(wbuf == nil || nobj >= nelem(wbuf->obj)) { + if(wbuf != nil) + wbuf->nobj = nobj; wbuf = getempty(wbuf); - bw = wbuf->w; - w = bw; - ew = bw + nelem(wbuf->w); + wp = wbuf->obj; + nobj = 0; } - *w++ = obj; + *wp++ = obj; + nobj++; + continue_obj:; } - + // Done scanning [b, b+n). Prepare for the next iteration of // the loop by setting b and n to the parameters for the next block. - // Fetch b from the work buffers. - if(w <= bw) { + // Fetch b from the work buffer. + if(nobj == 0) { + if(!keepworking) { + putempty(wbuf); + return; + } // Emptied our buffer: refill. wbuf = getfull(wbuf); if(wbuf == nil) - break; - bw = wbuf->w; - ew = wbuf->w + nelem(wbuf->w); - w = bw+wbuf->nw; - } - b = *--w; - - // Figure out n = size of b. Start by loading bits for b. - off = (uintptr*)b - (uintptr*)arena_start; - bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1; - shift = off % wordsPerBitmapWord; - xbits = *bitp; - bits = xbits >> shift; - - // Might be small; look for nearby block boundary. - // A block boundary is marked by either bitBlockBoundary - // or bitAllocated being set (see notes near their definition). - enum { - boundary = bitBlockBoundary|bitAllocated - }; - // Look for a block boundary both after and before b - // in the same bitmap word. - // - // A block boundary j words after b is indicated by - // bits>>j & boundary - // assuming shift+j < bitShift. (If shift+j >= bitShift then - // we'll be bleeding other bit types like bitMarked into our test.) - // Instead of inserting the conditional shift+j < bitShift into the loop, - // we can let j range from 1 to bitShift as long as we first - // apply a mask to keep only the bits corresponding - // to shift+j < bitShift aka j < bitShift-shift. - bits &= (boundary<<(bitShift-shift)) - boundary; - - // A block boundary j words before b is indicated by - // xbits>>(shift-j) & boundary - // (assuming shift >= j). There is no cleverness here - // avoid the test, because when j gets too large the shift - // turns negative, which is undefined in C. - - for(j=1; j<bitShift; j++) { - if(((bits>>j)&boundary) != 0 || shift>=j && ((xbits>>(shift-j))&boundary) != 0) { - n = j*PtrSize; - goto scan; - } + return; + nobj = wbuf->nobj; + wp = wbuf->obj + wbuf->nobj; } - - // Fall back to asking span about size class. + b = *--wp; + nobj--; + + // Ask span about size class. // (Manually inlined copy of MHeap_Lookup.) - nlookup++; - nsizelookup++; x = (uintptr)b>>PageShift; if(sizeof(void*) == 8) x -= (uintptr)arena_start>>PageShift; @@ -273,33 +306,126 @@ scanblock(byte *b, int64 n) n = s->npages<<PageShift; else n = runtime·class_to_size[s->sizeclass]; - scan:; } } -static struct { - Workbuf *full; - Workbuf *empty; - byte *chunk; - uintptr nchunk; -} work; +// debug_scanblock is the debug copy of scanblock. +// it is simpler, slower, single-threaded, recursive, +// and uses bitSpecial as the mark bit. +static void +debug_scanblock(byte *b, int64 n) +{ + byte *obj, *p; + void **vp; + uintptr size, *bitp, bits, shift, i, xbits, off; + MSpan *s; + + if(!DebugMark) + runtime·throw("debug_scanblock without DebugMark"); + + if((int64)(uintptr)n != n || n < 0) { + runtime·printf("debug_scanblock %p %D\n", b, n); + runtime·throw("debug_scanblock"); + } + + // Align b to a word boundary. + off = (uintptr)b & (PtrSize-1); + if(off != 0) { + b += PtrSize - off; + n -= PtrSize - off; + } + + vp = (void**)b; + n /= PtrSize; + for(i=0; i<n; i++) { + obj = (byte*)vp[i]; + + // Words outside the arena cannot be pointers. + if((byte*)obj < runtime·mheap.arena_start || (byte*)obj >= runtime·mheap.arena_used) + continue; + + // Round down to word boundary. + obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1)); + + // Consult span table to find beginning. + s = runtime·MHeap_LookupMaybe(&runtime·mheap, obj); + if(s == nil) + continue; + + + p = (byte*)((uintptr)s->start<<PageShift); + if(s->sizeclass == 0) { + obj = p; + size = (uintptr)s->npages<<PageShift; + } else { + if((byte*)obj >= (byte*)s->limit) + continue; + size = runtime·class_to_size[s->sizeclass]; + int32 i = ((byte*)obj - p)/size; + obj = p+i*size; + } + + // Now that we know the object header, reload bits. + off = (uintptr*)obj - (uintptr*)runtime·mheap.arena_start; + bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; + shift = off % wordsPerBitmapWord; + xbits = *bitp; + bits = xbits >> shift; + + // Now we have bits, bitp, and shift correct for + // obj pointing at the base of the object. + // If not allocated or already marked, done. + if((bits & bitAllocated) == 0 || (bits & bitSpecial) != 0) // NOTE: bitSpecial not bitMarked + continue; + *bitp |= bitSpecial<<shift; + if(!(bits & bitMarked)) + runtime·printf("found unmarked block %p in %p\n", obj, vp+i); + + // If object has no pointers, don't need to scan further. + if((bits & bitNoPointers) != 0) + continue; + + debug_scanblock(obj, size); + } +} // Get an empty work buffer off the work.empty list, // allocating new buffers as needed. static Workbuf* getempty(Workbuf *b) { - if(b != nil) { - b->nw = nelem(b->w); - b->next = work.full; - work.full = b; - } - b = work.empty; - if(b != nil) { - work.empty = b->next; - return b; + if(work.nproc == 1) { + // Put b on full list. + if(b != nil) { + b->next = work.full; + work.full = b; + } + // Grab from empty list if possible. + b = work.empty; + if(b != nil) { + work.empty = b->next; + goto haveb; + } + } else { + // Put b on full list. + if(b != nil) { + runtime·lock(&work.fmu); + b->next = work.full; + work.full = b; + runtime·unlock(&work.fmu); + } + // Grab from empty list if possible. + runtime·lock(&work.emu); + b = work.empty; + if(b != nil) + work.empty = b->next; + runtime·unlock(&work.emu); + if(b != nil) + goto haveb; } - + + // Need to allocate. + runtime·lock(&work); if(work.nchunk < sizeof *b) { work.nchunk = 1<<20; work.chunk = runtime·SysAlloc(work.nchunk); @@ -307,28 +433,124 @@ getempty(Workbuf *b) b = (Workbuf*)work.chunk; work.chunk += sizeof *b; work.nchunk -= sizeof *b; + runtime·unlock(&work); + +haveb: + b->nobj = 0; return b; } +static void +putempty(Workbuf *b) +{ + if(b == nil) + return; + + if(work.nproc == 1) { + b->next = work.empty; + work.empty = b; + return; + } + + runtime·lock(&work.emu); + b->next = work.empty; + work.empty = b; + runtime·unlock(&work.emu); +} + // Get a full work buffer off the work.full list, or return nil. static Workbuf* getfull(Workbuf *b) { - if(b != nil) { - b->nw = 0; - b->next = work.empty; - work.empty = b; + int32 i; + Workbuf *b1; + + if(work.nproc == 1) { + // Put b on empty list. + if(b != nil) { + b->next = work.empty; + work.empty = b; + } + // Grab from full list if possible. + // Since work.nproc==1, no one else is + // going to give us work. + b = work.full; + if(b != nil) + work.full = b->next; + return b; } - b = work.full; - if(b != nil) - work.full = b->next; - return b; + + putempty(b); + + // Grab buffer from full list if possible. + for(;;) { + b1 = work.full; + if(b1 == nil) + break; + runtime·lock(&work.fmu); + if(work.full != nil) { + b1 = work.full; + work.full = b1->next; + runtime·unlock(&work.fmu); + return b1; + } + runtime·unlock(&work.fmu); + } + + runtime·xadd(&work.nwait, +1); + for(i=0;; i++) { + b1 = work.full; + if(b1 != nil) { + runtime·lock(&work.fmu); + if(work.full != nil) { + runtime·xadd(&work.nwait, -1); + b1 = work.full; + work.full = b1->next; + runtime·unlock(&work.fmu); + return b1; + } + runtime·unlock(&work.fmu); + continue; + } + if(work.nwait == work.nproc) + return nil; + if(i < 10) + runtime·procyield(20); + else if(i < 20) + runtime·osyield(); + else + runtime·usleep(100); + } +} + +static Workbuf* +handoff(Workbuf *b) +{ + int32 n; + Workbuf *b1; + + // Make new buffer with half of b's pointers. + b1 = getempty(nil); + n = b->nobj/2; + b->nobj -= n; + b1->nobj = n; + runtime·memmove(b1->obj, b->obj+b->nobj, n*sizeof b1->obj[0]); + nhandoff += n; + + // Put b on full list - let first half of b get stolen. + runtime·lock(&work.fmu); + b->next = work.full; + work.full = b; + runtime·unlock(&work.fmu); + + return b1; } // Scanstack calls scanblock on each of gp's stack segments. static void -scanstack(G *gp) +scanstack(void (*scanblock)(byte*, int64), G *gp) { + M *mp; int32 n; Stktop *stk; byte *sp, *guard; @@ -339,6 +561,9 @@ scanstack(G *gp) if(gp == g) { // Scanning our own stack: start at &gp. sp = (byte*)&gp; + } else if((mp = gp->m) != nil && mp->helpgc) { + // gchelper's stack is in active use and has no interesting pointers. + return; } else { // Scanning another goroutine's stack. // The goroutine is usually asleep (the world is stopped). @@ -387,17 +612,28 @@ markfin(void *v) scanblock(v, size); } -// Mark static void -mark(void) +debug_markfin(void *v) +{ + uintptr size; + + if(!runtime·mlookup(v, &v, &size, nil)) + runtime·throw("debug_mark - finalizer inconsistency"); + debug_scanblock(v, size); +} + +// Mark +static void +mark(void (*scan)(byte*, int64)) { G *gp; + FinBlock *fb; // mark data+bss. // skip runtime·mheap itself, which has no interesting pointers // and is mostly zeroed and would not otherwise be paged in. - scanblock(data, (byte*)&runtime·mheap - data); - scanblock((byte*)(&runtime·mheap+1), end - (byte*)(&runtime·mheap+1)); + scan(data, (byte*)&runtime·mheap - data); + scan((byte*)(&runtime·mheap+1), end - (byte*)(&runtime·mheap+1)); // mark stacks for(gp=runtime·allg; gp!=nil; gp=gp->alllink) { @@ -410,21 +646,66 @@ mark(void) case Grunning: if(gp != g) runtime·throw("mark - world not stopped"); - scanstack(gp); + scanstack(scan, gp); break; case Grunnable: case Gsyscall: case Gwaiting: - scanstack(gp); + scanstack(scan, gp); break; } } // mark things pointed at by objects with finalizers - runtime·walkfintab(markfin); + if(scan == debug_scanblock) + runtime·walkfintab(debug_markfin); + else + runtime·walkfintab(markfin); + + for(fb=allfin; fb; fb=fb->alllink) + scanblock((byte*)fb->fin, fb->cnt*sizeof(fb->fin[0])); + + // in multiproc mode, join in the queued work. + scan(nil, 0); +} + +static bool +handlespecial(byte *p, uintptr size) +{ + void (*fn)(void*); + int32 nret; + FinBlock *block; + Finalizer *f; + + if(!runtime·getfinalizer(p, true, &fn, &nret)) { + runtime·setblockspecial(p, false); + runtime·MProf_Free(p, size); + return false; + } + + runtime·lock(&finlock); + if(finq == nil || finq->cnt == finq->cap) { + if(finc == nil) { + finc = runtime·SysAlloc(PageSize); + finc->cap = (PageSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1; + finc->alllink = allfin; + allfin = finc; + } + block = finc; + finc = block->next; + block->next = finq; + finq = block; + } + f = &finq->fin[finq->cnt]; + finq->cnt++; + f->fn = fn; + f->nret = nret; + f->arg = p; + runtime·unlock(&finlock); + return true; } -// Sweep frees or calls finalizers for blocks not marked in the mark phase. +// Sweep frees or collects finalizers for blocks not marked in the mark phase. // It clears the mark bits in preparation for the next GC round. static void sweep(void) @@ -434,9 +715,17 @@ sweep(void) uintptr size; byte *p; MCache *c; - Finalizer *f; + byte *arena_start; + + arena_start = runtime·mheap.arena_start; + + for(;;) { + s = work.spans; + if(s == nil) + break; + if(!runtime·casp(&work.spans, s, s->allnext)) + continue; - for(s = runtime·mheap.allspans; s != nil; s = s->allnext) { if(s->state != MSpanInUse) continue; @@ -451,13 +740,15 @@ sweep(void) npages = runtime·class_to_allocnpages[cl]; n = (npages << PageShift) / size; } - - // sweep through n objects of given size starting at p. + + // Sweep through n objects of given size starting at p. + // This thread owns the span now, so it can manipulate + // the block bitmap without atomic operations. for(; n > 0; n--, p += size) { uintptr off, *bitp, shift, bits; - off = (uintptr*)p - (uintptr*)runtime·mheap.arena_start; - bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; + off = (uintptr*)p - (uintptr*)arena_start; + bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1; shift = off % wordsPerBitmapWord; bits = *bitp>>shift; @@ -465,20 +756,21 @@ sweep(void) continue; if((bits & bitMarked) != 0) { + if(DebugMark) { + if(!(bits & bitSpecial)) + runtime·printf("found spurious mark on %p\n", p); + *bitp &= ~(bitSpecial<<shift); + } *bitp &= ~(bitMarked<<shift); continue; } - if((bits & bitSpecial) != 0) { - // Special means it has a finalizer or is being profiled. - f = runtime·getfinalizer(p, 1); - if(f != nil) { - f->arg = p; - f->next = finq; - finq = f; + // Special means it has a finalizer or is being profiled. + // In DebugMark mode, the bit has been coopted so + // we have to assume all blocks are special. + if(DebugMark || (bits & bitSpecial) != 0) { + if(handlespecial(p, size)) continue; - } - runtime·MProf_Free(p, size); } // Mark freed; restore block boundary bit. @@ -503,6 +795,23 @@ sweep(void) } } +void +runtime·gchelper(void) +{ + // Wait until main proc is ready for mark help. + runtime·lock(&work.markgate); + runtime·unlock(&work.markgate); + scanblock(nil, 0); + + // Wait until main proc is ready for sweep help. + runtime·lock(&work.sweepgate); + runtime·unlock(&work.sweepgate); + sweep(); + + if(runtime·xadd(&work.ndone, +1) == work.nproc-1) + runtime·notewakeup(&work.alldone); +} + // Semaphore, not Lock, so that the goroutine // reschedules when there is contention rather // than spinning. @@ -523,7 +832,7 @@ static void stealcache(void) { M *m; - + for(m=runtime·allm; m; m=m->alllink) runtime·MCache_ReleaseAll(m->mcache); } @@ -561,7 +870,7 @@ runtime·gc(int32 force) int64 t0, t1, t2, t3; uint64 heap0, heap1, obj0, obj1; byte *p; - Finalizer *fp; + bool extra; // The gc is turned off (via enablegc) until // the bootstrap has completed. @@ -582,7 +891,7 @@ runtime·gc(int32 force) gcpercent = -1; else gcpercent = runtime·atoi(p); - + p = runtime·getenv("GOGCTRACE"); if(p != nil) gctrace = runtime·atoi(p); @@ -597,9 +906,7 @@ runtime·gc(int32 force) } t0 = runtime·nanotime(); - nlookup = 0; - nsizelookup = 0; - naddrlookup = 0; + nhandoff = 0; m->gcing = 1; runtime·stoptheworld(); @@ -608,10 +915,31 @@ runtime·gc(int32 force) heap0 = mstats.heap_alloc; obj0 = mstats.nmalloc - mstats.nfree; - mark(); + runtime·lock(&work.markgate); + runtime·lock(&work.sweepgate); + + extra = false; + work.nproc = 1; + if(runtime·gomaxprocs > 1 && runtime·ncpu > 1) { + runtime·noteclear(&work.alldone); + work.nproc += runtime·helpgc(&extra); + } + work.nwait = 0; + work.ndone = 0; + + runtime·unlock(&work.markgate); // let the helpers in + mark(scanblock); + if(DebugMark) + mark(debug_scanblock); t1 = runtime·nanotime(); + + work.spans = runtime·mheap.allspans; + runtime·unlock(&work.sweepgate); // let the helpers in sweep(); + if(work.nproc > 1) + runtime·notesleep(&work.alldone); t2 = runtime·nanotime(); + stealcache(); cachestats(); @@ -619,8 +947,7 @@ runtime·gc(int32 force) m->gcing = 0; m->locks++; // disable gc during the mallocs in newproc - fp = finq; - if(fp != nil) { + if(finq != nil) { // kick off or wake up goroutine to run queued finalizers if(fing == nil) fing = runtime·newproc1((byte*)runfinq, nil, 0, 0, runtime·gc); @@ -641,22 +968,30 @@ runtime·gc(int32 force) mstats.numgc++; if(mstats.debuggc) runtime·printf("pause %D\n", t3-t0); - + if(gctrace) { - runtime·printf("gc%d: %D+%D+%D ms %D -> %D MB %D -> %D (%D-%D) objects %D pointer lookups (%D size, %D addr)\n", - mstats.numgc, (t1-t0)/1000000, (t2-t1)/1000000, (t3-t2)/1000000, + runtime·printf("gc%d(%d): %D+%D+%D ms %D -> %D MB %D -> %D (%D-%D) objects %D handoff\n", + mstats.numgc, work.nproc, (t1-t0)/1000000, (t2-t1)/1000000, (t3-t2)/1000000, heap0>>20, heap1>>20, obj0, obj1, mstats.nmalloc, mstats.nfree, - nlookup, nsizelookup, naddrlookup); + nhandoff); } runtime·semrelease(&gcsema); - runtime·starttheworld(); - - // give the queued finalizers, if any, a chance to run - if(fp != nil) + + // If we could have used another helper proc, start one now, + // in the hope that it will be available next time. + // It would have been even better to start it before the collection, + // but doing so requires allocating memory, so it's tricky to + // coordinate. This lazy approach works out in practice: + // we don't mind if the first couple gc rounds don't have quite + // the maximum number of procs. + runtime·starttheworld(extra); + + // give the queued finalizers, if any, a chance to run + if(finq != nil) runtime·gosched(); - + if(gctrace > 1 && !force) runtime·gc(1); } @@ -674,15 +1009,19 @@ runtime·UpdateMemStats(void) cachestats(); m->gcing = 0; runtime·semrelease(&gcsema); - runtime·starttheworld(); + runtime·starttheworld(false); } static void runfinq(void) { - Finalizer *f, *next; + Finalizer *f; + FinBlock *fb, *next; byte *frame; + uint32 framesz, framecap, i; + frame = nil; + framecap = 0; for(;;) { // There's no need for a lock in this section // because it only conflicts with the garbage @@ -690,25 +1029,34 @@ runfinq(void) // runs when everyone else is stopped, and // runfinq only stops at the gosched() or // during the calls in the for loop. - f = finq; + fb = finq; finq = nil; - if(f == nil) { + if(fb == nil) { fingwait = 1; g->status = Gwaiting; g->waitreason = "finalizer wait"; runtime·gosched(); continue; } - for(; f; f=next) { - next = f->next; - frame = runtime·mal(sizeof(uintptr) + f->nret); - *(void**)frame = f->arg; - reflect·call((byte*)f->fn, frame, sizeof(uintptr) + f->nret); - runtime·free(frame); - f->fn = nil; - f->arg = nil; - f->next = nil; - runtime·free(f); + for(; fb; fb=next) { + next = fb->next; + for(i=0; i<fb->cnt; i++) { + f = &fb->fin[i]; + framesz = sizeof(uintptr) + f->nret; + if(framecap < framesz) { + runtime·free(frame); + frame = runtime·mal(framesz); + framecap = framesz; + } + *(void**)frame = f->arg; + runtime·setblockspecial(f->arg, false); + reflect·call((byte*)f->fn, frame, sizeof(uintptr) + f->nret); + f->fn = nil; + f->arg = nil; + } + fb->cnt = 0; + fb->next = finc; + finc = fb; } runtime·gc(1); // trigger another gc to clean up the finalized objects, if possible } @@ -858,6 +1206,9 @@ runtime·blockspecial(void *v) { uintptr *b, off, shift; + if(DebugMark) + return true; + off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; shift = off % wordsPerBitmapWord; @@ -866,17 +1217,23 @@ runtime·blockspecial(void *v) } void -runtime·setblockspecial(void *v) +runtime·setblockspecial(void *v, bool s) { uintptr *b, off, shift, bits, obits; + if(DebugMark) + return; + off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; shift = off % wordsPerBitmapWord; for(;;) { obits = *b; - bits = obits | (bitSpecial<<shift); + if(s) + bits = obits | (bitSpecial<<shift); + else + bits = obits & ~(bitSpecial<<shift); if(runtime·singleproc) { *b = bits; break; @@ -887,7 +1244,7 @@ runtime·setblockspecial(void *v) } } } - + void runtime·MHeap_MapBits(MHeap *h) { @@ -898,7 +1255,7 @@ runtime·MHeap_MapBits(MHeap *h) bitmapChunk = 8192 }; uintptr n; - + n = (h->arena_used - h->arena_start) / wordsPerBitmapWord; n = (n+bitmapChunk-1) & ~(bitmapChunk-1); if(h->bitmap_mapped >= n) diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c index 7d24a6540..d75c18d82 100644 --- a/src/pkg/runtime/mheap.c +++ b/src/pkg/runtime/mheap.c @@ -13,6 +13,7 @@ // and heapmap(i) == span for all s->start <= i < s->start+s->npages. #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" static MSpan *MHeap_AllocLocked(MHeap*, uintptr, int32); diff --git a/src/pkg/runtime/mkasmh.sh b/src/pkg/runtime/mkasmh.sh index 920e79a02..26a1263be 100755 --- a/src/pkg/runtime/mkasmh.sh +++ b/src/pkg/runtime/mkasmh.sh @@ -5,21 +5,44 @@ set -e +SYS=$1 +export GOOS=$(echo $SYS | sed 's/_.*//') +export GOARCH=$(echo $SYS | sed 's/.*_//') +shift + +case "$GOARCH" in +386) CC=8c;; +amd64) CC=6c;; +arm) CC=5c;; +esac +export CC + +export CFLAGS="-Dos_$GOOS -Darch_$GOARCH" + +cp arch_$GOARCH.h arch_GOARCH.h +cp defs_${GOOS}_$GOARCH.h defs_GOOS_GOARCH.h +cp os_$GOOS.h os_GOOS.h +cp signals_$GOOS.h signals_GOOS.h + cat <<'EOF' // Assembly constants. -// AUTOMATICALLY GENERATED BY mkasmh.sh DURING BUILD +// AUTO-GENERATED by autogen.sh; DO NOT EDIT EOF +if [ ! -x "${GOBIN:=$GOROOT/bin}/$CC" ]; then + echo "// dummy file for cmd/go to correctly generate buildscript" + exit +fi case "$GOARCH" in 386) # The offsets 0 and 4 are also known to: # ../../cmd/8l/pass.c:/D_GS - # ../../libcgo/linux_386.c:/^threadentry - # ../../libcgo/darwin_386.c:/^threadentry + # cgo/gcc_linux_386.c:/^threadentry + # cgo/gcc_darwin_386.c:/^threadentry case "$GOOS" in windows) - echo '#define get_tls(r) MOVL 0x2c(FS), r' + echo '#define get_tls(r) MOVL 0x14(FS), r' echo '#define g(r) 0(r)' echo '#define m(r) 4(r)' ;; @@ -63,15 +86,15 @@ case "$GOARCH" in amd64) case "$GOOS" in windows) - echo '#define get_tls(r) MOVQ 0x58(GS), r' + echo '#define get_tls(r) MOVQ 0x28(GS), r' echo '#define g(r) 0(r)' echo '#define m(r) 8(r)' ;; *) # The offsets 0 and 8 are known to: # ../../cmd/6l/pass.c:/D_GS - # ../../libcgo/linux_amd64.c:/^threadentry - # ../../libcgo/darwin_amd64.c:/^threadentry + # cgo/gcc_linux_amd64.c:/^threadentry + # cgo/gcc_darwin_amd64.c:/^threadentry # echo '#define get_tls(r)' echo '#define g(r) 0(GS)' @@ -91,6 +114,7 @@ arm) esac echo +$GOBIN/$CC $CFLAGS -a proc.c | awk ' { gsub(/\r/, ""); } /^aggr G$/ { aggr="g" } @@ -109,5 +133,6 @@ aggr != "" && /^ / { offset=$(NF-1); printf("#define %s_%s %s\n", aggr, name, offset); } -' runtime.acid.$GOARCH +' +rm -f arch_GOARCH.h defs_GOOS_GOARCH.h os_GOOS.h signals_GOOS.h diff --git a/src/pkg/runtime/mkgodefs.sh b/src/pkg/runtime/mkgodefs.sh index b6e97213e..b7cd229b7 100755 --- a/src/pkg/runtime/mkgodefs.sh +++ b/src/pkg/runtime/mkgodefs.sh @@ -5,11 +5,36 @@ set -e +SYS=$1 +export GOOS=$(echo $SYS | sed 's/_.*//') +export GOARCH=$(echo $SYS | sed 's/.*_//') +shift + +case "$GOARCH" in +386) CC=8c;; +amd64) CC=6c;; +arm) CC=5c;; +esac +export CC + +export CFLAGS="-DGOOS_$GOOS -DGOARCH_$GOARCH" + +cp arch_$GOARCH.h arch_GOARCH.h +cp defs_${GOOS}_$GOARCH.h defs_GOOS_GOARCH.h +cp os_$GOOS.h os_GOOS.h +cp signals_$GOOS.h signals_GOOS.h + cat <<EOF // Go definitions for C variables and types. -// AUTOMATICALLY GENERATED BY THE FOLLOWING COMMAND. DO NOT EDIT. -// CC="$CC" CFLAGS="$CFLAGS" ./mkgodefs.sh $@ +// AUTO-GENERATED by autogen.sh; DO NOT EDIT +EOF +if [ ! -x "${GOBIN:=$GOROOT/bin}/$CC" ]; then + echo "// dummy file for cmd/go to correctly generate buildscript" + echo "package runtime" + exit +fi +cat <<EOF package runtime import "unsafe" var _ unsafe.Pointer @@ -17,7 +42,7 @@ var _ unsafe.Pointer EOF for i in "$@"; do - $CC $CFLAGS -q $i + $GOBIN/$CC $CFLAGS -q $i done | awk ' /^func/ { next } /^const/ { next } @@ -37,3 +62,5 @@ skip { {print} ' + +rm -f arch_GOARCH.h defs_GOOS_GOARCH.h os_GOOS.h signals_GOOS.h diff --git a/src/pkg/runtime/mkversion.c b/src/pkg/runtime/mkversion.c index 0d96aa356..94ad0d9e5 100644 --- a/src/pkg/runtime/mkversion.c +++ b/src/pkg/runtime/mkversion.c @@ -1,8 +1,14 @@ +// 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. + +// +build ignore + #include <u.h> #include <libc.h> char *template = - "// generated by mkversion.c; do not edit.\n" + "// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n" "package runtime\n" "const defaultGoroot = `%s`\n" "const theVersion = \"%s\"\n"; diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc index 517f96a31..b297d4138 100644 --- a/src/pkg/runtime/mprof.goc +++ b/src/pkg/runtime/mprof.goc @@ -7,8 +7,9 @@ package runtime #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" -#include "defs.h" +#include "defs_GOOS_GOARCH.h" #include "type.h" // NOTE(rsc): Everything here could use cas if contention became an issue. diff --git a/src/pkg/runtime/msize.c b/src/pkg/runtime/msize.c index 770ef38ce..e6cfcdb02 100644 --- a/src/pkg/runtime/msize.c +++ b/src/pkg/runtime/msize.c @@ -26,6 +26,7 @@ // TODO(rsc): Compute max waste for any given size. #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" int32 runtime·class_to_size[NumSizeClasses]; diff --git a/src/pkg/runtime/openbsd/defs.c b/src/pkg/runtime/openbsd/defs.c deleted file mode 100644 index d0e0a19c3..000000000 --- a/src/pkg/runtime/openbsd/defs.c +++ /dev/null @@ -1,103 +0,0 @@ -// 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. - -/* - * Input to godefs. - * - godefs -f -m64 defs.c >amd64/defs.h - godefs -f -m32 defs.c >386/defs.h - */ - -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/time.h> -#include <sys/unistd.h> -#include <sys/signal.h> -#include <errno.h> -#include <signal.h> - -enum { - $PROT_NONE = PROT_NONE, - $PROT_READ = PROT_READ, - $PROT_WRITE = PROT_WRITE, - $PROT_EXEC = PROT_EXEC, - - $MAP_ANON = MAP_ANON, - $MAP_PRIVATE = MAP_PRIVATE, - $MAP_FIXED = MAP_FIXED, - - $SA_SIGINFO = SA_SIGINFO, - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - - $EINTR = EINTR, - - $SIGHUP = SIGHUP, - $SIGINT = SIGINT, - $SIGQUIT = SIGQUIT, - $SIGILL = SIGILL, - $SIGTRAP = SIGTRAP, - $SIGABRT = SIGABRT, - $SIGEMT = SIGEMT, - $SIGFPE = SIGFPE, - $SIGKILL = SIGKILL, - $SIGBUS = SIGBUS, - $SIGSEGV = SIGSEGV, - $SIGSYS = SIGSYS, - $SIGPIPE = SIGPIPE, - $SIGALRM = SIGALRM, - $SIGTERM = SIGTERM, - $SIGURG = SIGURG, - $SIGSTOP = SIGSTOP, - $SIGTSTP = SIGTSTP, - $SIGCONT = SIGCONT, - $SIGCHLD = SIGCHLD, - $SIGTTIN = SIGTTIN, - $SIGTTOU = SIGTTOU, - $SIGIO = SIGIO, - $SIGXCPU = SIGXCPU, - $SIGXFSZ = SIGXFSZ, - $SIGVTALRM = SIGVTALRM, - $SIGPROF = SIGPROF, - $SIGWINCH = SIGWINCH, - $SIGINFO = SIGINFO, - $SIGUSR1 = SIGUSR1, - $SIGUSR2 = SIGUSR2, - - $FPE_INTDIV = FPE_INTDIV, - $FPE_INTOVF = FPE_INTOVF, - $FPE_FLTDIV = FPE_FLTDIV, - $FPE_FLTOVF = FPE_FLTOVF, - $FPE_FLTUND = FPE_FLTUND, - $FPE_FLTRES = FPE_FLTRES, - $FPE_FLTINV = FPE_FLTINV, - $FPE_FLTSUB = FPE_FLTSUB, - - $BUS_ADRALN = BUS_ADRALN, - $BUS_ADRERR = BUS_ADRERR, - $BUS_OBJERR = BUS_OBJERR, - - $SEGV_MAPERR = SEGV_MAPERR, - $SEGV_ACCERR = SEGV_ACCERR, - - $ITIMER_REAL = ITIMER_REAL, - $ITIMER_VIRTUAL = ITIMER_VIRTUAL, - $ITIMER_PROF = ITIMER_PROF, -}; - -typedef struct sigaltstack $Sigaltstack; -typedef sigset_t $Sigset; -typedef siginfo_t $Siginfo; -typedef union sigval $Sigval; - -typedef stack_t $StackT; - -typedef struct timeval $Timeval; -typedef struct itimerval $Itimerval; - -// This is a hack to avoid pulling in machine/fpu.h. -typedef void $sfxsave64; -typedef void $usavefpu; - -typedef struct sigcontext $Sigcontext; diff --git a/src/pkg/runtime/openbsd/thread.c b/src/pkg/runtime/openbsd/thread.c deleted file mode 100644 index 909db8cdc..000000000 --- a/src/pkg/runtime/openbsd/thread.c +++ /dev/null @@ -1,156 +0,0 @@ -// Use of this source file is governed by a BSD-style -// license that can be found in the LICENSE file.` - -#include "runtime.h" -#include "defs.h" -#include "os.h" -#include "stack.h" - -extern SigTab runtime·sigtab[]; - -extern int64 runtime·rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); - -enum -{ - ENOTSUP = 91, -}; - -// Basic spinlocks using CAS. We can improve on these later. -static void -lock(Lock *l) -{ - for(;;) { - if(runtime·cas(&l->key, 0, 1)) - return; - runtime·osyield(); - } -} - -static void -unlock(Lock *l) -{ - uint32 v; - - for (;;) { - v = l->key; - if((v&1) == 0) - runtime·throw("unlock of unlocked lock"); - if(runtime·cas(&l->key, v, 0)) - break; - } -} - -void -runtime·lock(Lock *l) -{ - if(m->locks < 0) - runtime·throw("lock count"); - m->locks++; - lock(l); -} - -void -runtime·unlock(Lock *l) -{ - m->locks--; - if(m->locks < 0) - runtime·throw("lock count"); - unlock(l); -} - -// Event notifications. -void -runtime·noteclear(Note *n) -{ - n->lock.key = 0; - lock(&n->lock); -} - -void -runtime·notesleep(Note *n) -{ - lock(&n->lock); - unlock(&n->lock); -} - -void -runtime·notewakeup(Note *n) -{ - unlock(&n->lock); -} - -// From OpenBSD's sys/param.h -#define RFPROC (1<<4) /* change child (else changes curproc) */ -#define RFMEM (1<<5) /* share `address space' */ -#define RFNOWAIT (1<<6) /* parent need not wait() on child */ -#define RFTHREAD (1<<13) /* create a thread, not a process */ - -void -runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) -{ - int32 flags; - int32 ret; - - flags = RFPROC | RFTHREAD | RFMEM | RFNOWAIT; - - if (0) { - runtime·printf( - "newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n", - stk, m, g, fn, m->id, m->tls[0], &m); - } - - m->tls[0] = m->id; // so 386 asm can find it - - if((ret = runtime·rfork_thread(flags, stk, m, g, fn)) < 0) { - runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret); - if (ret == -ENOTSUP) - runtime·printf("runtime: is kern.rthreads disabled?\n"); - runtime·throw("runtime.newosproc"); - } -} - -void -runtime·osinit(void) -{ -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); -} - -// Called to initialize a new m (including the bootstrap m). -void -runtime·minit(void) -{ - // Initialize signal handling - m->gsignal = runtime·malg(32*1024); - runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024); -} - -void -runtime·sigpanic(void) -{ - switch(g->sig) { - case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) - runtime·panicstring("invalid memory address or nil pointer dereference"); - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGSEGV: - if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) - runtime·panicstring("invalid memory address or nil pointer dereference"); - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGFPE: - switch(g->sigcode0) { - case FPE_INTDIV: - runtime·panicstring("integer divide by zero"); - case FPE_INTOVF: - runtime·panicstring("integer overflow"); - } - runtime·panicstring("floating point error"); - } - runtime·panicstring(runtime·sigtab[g->sig].name); -} diff --git a/src/pkg/runtime/darwin/os.h b/src/pkg/runtime/os_darwin.h index db3c2e8a7..3e96071ba 100644 --- a/src/pkg/runtime/darwin/os.h +++ b/src/pkg/runtime/os_darwin.h @@ -9,7 +9,7 @@ int32 runtime·bsdthread_create(void*, M*, G*, void(*)(void)); void runtime·bsdthread_register(void); int32 runtime·mach_msg_trap(MachHeader*, int32, uint32, uint32, uint32, uint32, uint32); uint32 runtime·mach_reply_port(void); -void runtime·mach_semacquire(uint32); +int32 runtime·mach_semacquire(uint32, int64); uint32 runtime·mach_semcreate(void); void runtime·mach_semdestroy(uint32); void runtime·mach_semrelease(uint32); @@ -18,6 +18,7 @@ uint32 runtime·mach_task_self(void); uint32 runtime·mach_task_self(void); uint32 runtime·mach_thread_self(void); uint32 runtime·mach_thread_self(void); +int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr); struct Sigaction; void runtime·sigaction(uintptr, struct Sigaction*, struct Sigaction*); diff --git a/src/pkg/runtime/os_freebsd.h b/src/pkg/runtime/os_freebsd.h new file mode 100644 index 000000000..8ef4c3987 --- /dev/null +++ b/src/pkg/runtime/os_freebsd.h @@ -0,0 +1,13 @@ +#define SIG_DFL ((void*)0) +#define SIG_IGN ((void*)1) + +int32 runtime·thr_new(ThrParam*, int32); +void runtime·sigpanic(void); +void runtime·sigaltstack(Sigaltstack*, Sigaltstack*); +struct sigaction; +void runtime·sigaction(int32, struct sigaction*, struct sigaction*); +void runtiem·setitimerval(int32, Itimerval*, Itimerval*); +void runtime·setitimer(int32, Itimerval*, Itimerval*); +int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr); + +void runtime·raisesigpipe(void); diff --git a/src/pkg/runtime/linux/os.h b/src/pkg/runtime/os_linux.h index 0bb8d0339..0bb8d0339 100644 --- a/src/pkg/runtime/linux/os.h +++ b/src/pkg/runtime/os_linux.h diff --git a/src/pkg/runtime/openbsd/os.h b/src/pkg/runtime/os_netbsd.h index eba53b7cc..cf35402ca 100644 --- a/src/pkg/runtime/openbsd/os.h +++ b/src/pkg/runtime/os_netbsd.h @@ -1,3 +1,7 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + #define SIG_DFL ((void*)0) #define SIG_IGN ((void*)1) @@ -8,5 +12,6 @@ void runtime·sigaltstack(Sigaltstack*, Sigaltstack*); void runtime·sigaction(int32, struct sigaction*, struct sigaction*); void runtime·setitimerval(int32, Itimerval*, Itimerval*); void runtime·setitimer(int32, Itimerval*, Itimerval*); +int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr); void runtime·raisesigpipe(void); diff --git a/src/pkg/runtime/os_openbsd.h b/src/pkg/runtime/os_openbsd.h new file mode 100644 index 000000000..cf35402ca --- /dev/null +++ b/src/pkg/runtime/os_openbsd.h @@ -0,0 +1,17 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#define SIG_DFL ((void*)0) +#define SIG_IGN ((void*)1) + +struct sigaction; + +void runtime·sigpanic(void); +void runtime·sigaltstack(Sigaltstack*, Sigaltstack*); +void runtime·sigaction(int32, struct sigaction*, struct sigaction*); +void runtime·setitimerval(int32, Itimerval*, Itimerval*); +void runtime·setitimer(int32, Itimerval*, Itimerval*); +int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr); + +void runtime·raisesigpipe(void); diff --git a/src/pkg/runtime/plan9/os.h b/src/pkg/runtime/os_plan9.h index b2f7357ec..b7b838349 100644 --- a/src/pkg/runtime/plan9/os.h +++ b/src/pkg/runtime/os_plan9.h @@ -2,16 +2,30 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -extern int32 runtime·write(int32 fd, void* buffer, int32 nbytes); -extern void runtime·exits(int8* msg); -extern int32 runtime·brk_(void*); +// Plan 9-specific system calls +int32 runtime·open(uint8 *file, int32 mode); +int32 runtime·pread(int32 fd, void *buf, int32 nbytes, int64 offset); +int32 runtime·pwrite(int32 fd, void *buf, int32 nbytes, int64 offset); +int32 runtime·read(int32 fd, void *buf, int32 nbytes); +int32 runtime·close(int32 fd); +void runtime·exits(int8* msg); +int32 runtime·brk_(void*); +int32 runtime·sleep(int32 ms); +int32 runtime·rfork(int32 flags, void *stk, M *m, G *g, void (*fn)(void)); +int32 runtime·plan9_semacquire(uint32 *addr, int32 block); +int32 runtime·plan9_semrelease(uint32 *addr, int32 count); /* open */ enum { - OREAD = 0, - OWRITE = 1, - ORDWR = 2 + OREAD = 0, + OWRITE = 1, + ORDWR = 2, + OEXEC = 3, + OTRUNC = 16, + OCEXEC = 32, + ORCLOSE = 64, + OEXCL = 0x1000 }; /* rfork */ @@ -52,6 +66,3 @@ struct Tos { /* top of stack is here */ }; -extern int32 runtime·rfork(int32 flags, void *stk, M *m, G *g, void (*fn)(void)); -extern int32 runtime·plan9_semacquire(uint32 *addr, int32 block); -extern int32 runtime·plan9_semrelease(uint32 *addr, int32 count); diff --git a/src/pkg/runtime/windows/os.h b/src/pkg/runtime/os_windows.h index 21277c64b..2ad95d958 100644 --- a/src/pkg/runtime/windows/os.h +++ b/src/pkg/runtime/os_windows.h @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -extern void *runtime·LoadLibraryEx; +extern void *runtime·LoadLibrary; extern void *runtime·GetProcAddress; // Call a Windows function with stdcall conventions, diff --git a/src/pkg/runtime/plan9/thread.c b/src/pkg/runtime/plan9/thread.c deleted file mode 100644 index 776989242..000000000 --- a/src/pkg/runtime/plan9/thread.c +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "os.h" - -int8 *goos = "plan9"; - -void -runtime·minit(void) -{ -} - -void -runtime·osinit(void) -{ -} - -void -runtime·goenvs(void) -{ -} - -void -runtime·initsig(int32 queue) -{ -} - -extern Tos *_tos; -void -runtime·exit(int32) -{ - int32 fd; - uint8 buf[128]; - uint8 tmp[16]; - uint8 *p, *q; - int32 pid; - - runtime·memclr(buf, sizeof buf); - runtime·memclr(tmp, sizeof tmp); - pid = _tos->pid; - - /* build path string /proc/pid/notepg */ - for(q=tmp; pid > 0;) { - *q++ = '0' + (pid%10); - pid = pid/10; - } - p = buf; - runtime·memmove((void*)p, (void*)"/proc/", 6); - p += 6; - for(q--; q >= tmp;) - *p++ = *q--; - runtime·memmove((void*)p, (void*)"/notepg", 7); - - /* post interrupt note */ - fd = runtime·open(buf, OWRITE); - runtime·write(fd, "interrupt", 9); - runtime·exits(nil); -} - -void -runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) -{ - m->tls[0] = m->id; // so 386 asm can find it - if(0){ - runtime·printf("newosproc stk=%p m=%p g=%p fn=%p rfork=%p id=%d/%d ostk=%p\n", - stk, m, g, fn, runtime·rfork, m->id, m->tls[0], &m); - } - - if (runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, m, g, fn) < 0 ) - runtime·throw("newosproc: rfork failed"); -} - -// Blocking locks. - -// Implement Locks, using semaphores. -// l->key is the number of threads who want the lock. -// In a race, one thread increments l->key from 0 to 1 -// and the others increment it from >0 to >1. The thread -// who does the 0->1 increment gets the lock, and the -// others wait on the semaphore. When the 0->1 thread -// releases the lock by decrementing l->key, l->key will -// be >0, so it will increment the semaphore to wake up -// one of the others. This is the same algorithm used -// in Plan 9's user-level locks. - -void -runtime·lock(Lock *l) -{ - if(m->locks < 0) - runtime·throw("lock count"); - m->locks++; - - if(runtime·xadd(&l->key, 1) == 1) - return; // changed from 0 -> 1; we hold lock - // otherwise wait in kernel - while(runtime·plan9_semacquire(&l->sema, 1) < 0) { - /* interrupted; try again */ - } -} - -void -runtime·unlock(Lock *l) -{ - m->locks--; - if(m->locks < 0) - runtime·throw("lock count"); - - if(runtime·xadd(&l->key, -1) == 0) - return; // changed from 1 -> 0: no contention - - runtime·plan9_semrelease(&l->sema, 1); -} - - -// User-level semaphore implementation: -// try to do the operations in user space on u, -// but when it's time to block, fall back on the kernel semaphore k. -// This is the same algorithm used in Plan 9. -void -runtime·usemacquire(Usema *s) -{ - if((int32)runtime·xadd(&s->u, -1) < 0) - while(runtime·plan9_semacquire(&s->k, 1) < 0) { - /* interrupted; try again */ - } -} - -void -runtime·usemrelease(Usema *s) -{ - if((int32)runtime·xadd(&s->u, 1) <= 0) - runtime·plan9_semrelease(&s->k, 1); -} - - -// Event notifications. -void -runtime·noteclear(Note *n) -{ - n->wakeup = 0; -} - -void -runtime·notesleep(Note *n) -{ - while(!n->wakeup) - runtime·usemacquire(&n->sema); -} - -void -runtime·notewakeup(Note *n) -{ - n->wakeup = 1; - runtime·usemrelease(&n->sema); -} - -void -os·sigpipe(void) -{ - runtime·throw("too many writes on closed pipe"); -} - -/* - * placeholder - once notes are implemented, - * a signal generating a panic must appear as - * a call to this function for correct handling by - * traceback. - */ -void -runtime·sigpanic(void) -{ -} diff --git a/src/pkg/runtime/pprof/pprof.go b/src/pkg/runtime/pprof/pprof.go index fdeceb4e8..d14bb141c 100644 --- a/src/pkg/runtime/pprof/pprof.go +++ b/src/pkg/runtime/pprof/pprof.go @@ -12,15 +12,17 @@ import ( "bufio" "fmt" "io" - "os" "runtime" "sync" ) +// BUG(rsc): CPU profiling is broken on OS X, due to an Apple kernel bug. +// For details, see http://code.google.com/p/go/source/detail?r=35b716c94225. + // WriteHeapProfile writes a pprof-formatted heap profile to w. // If a write to w returns an error, WriteHeapProfile returns that error. // Otherwise, WriteHeapProfile returns nil. -func WriteHeapProfile(w io.Writer) os.Error { +func WriteHeapProfile(w io.Writer) error { // Find out how many records there are (MemProfile(nil, false)), // allocate that many records, and get the data. // There's a race—more records might be added between @@ -116,7 +118,7 @@ var cpu struct { // StartCPUProfile enables CPU profiling for the current process. // While profiling, the profile will be buffered and written to w. // StartCPUProfile returns an error if profiling is already enabled. -func StartCPUProfile(w io.Writer) os.Error { +func StartCPUProfile(w io.Writer) error { // The runtime routines allow a variable profiling rate, // but in practice operating systems cannot trigger signals // at more than about 500 Hz, and our processing of the diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c index 3ce779495..0d8caaf91 100644 --- a/src/pkg/runtime/print.c +++ b/src/pkg/runtime/print.c @@ -51,7 +51,7 @@ vprintf(int8 *s, byte *base) uintptr arg, narg; byte *v; -// lock(&debuglock); + //runtime·lock(&debuglock); lp = p = s; arg = 0; @@ -152,7 +152,7 @@ vprintf(int8 *s, byte *base) if(p > lp) runtime·write(2, lp, p-lp); -// unlock(&debuglock); + //runtime·unlock(&debuglock); } #pragma textflag 7 @@ -348,4 +348,4 @@ runtime·typestring(Eface e, String s) s = *e.type->string; FLUSH(&s); } - + diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index cc075741d..cb45a0c29 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -3,18 +3,16 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "arch.h" -#include "defs.h" +#include "arch_GOARCH.h" +#include "defs_GOOS_GOARCH.h" #include "malloc.h" -#include "os.h" +#include "os_GOOS.h" #include "stack.h" bool runtime·iscgo; static void unwindstack(G*, byte*); static void schedule(G*); -static void acquireproc(void); -static void releaseproc(void); typedef struct Sched Sched; @@ -70,9 +68,11 @@ struct Sched { volatile uint32 atomic; // atomic scheduling word (see below) - int32 predawn; // running initialization, don't run new g's. int32 profilehz; // cpu profiling rate + bool init; // running initialization + bool lockmain; // init called runtime.LockOSThread + Note stopped; // one g can set waitstop and wait here for m's to stop }; @@ -128,6 +128,8 @@ Sched runtime·sched; int32 runtime·gomaxprocs; bool runtime·singleproc; +static bool canaddmcpu(void); + // An m that is waiting for notewakeup(&m->havenextg). This may // only be accessed while the scheduler lock is held. This is used to // minimize the number of times we call notewakeup while the scheduler @@ -169,11 +171,7 @@ setmcpumax(uint32 n) // make & queue new G // call runtime·mstart // -// The new G does: -// -// call main·init_function -// call initdone -// call main·main +// The new G calls runtime·main. void runtime·schedinit(void) { @@ -201,11 +199,41 @@ runtime·schedinit(void) } setmcpumax(runtime·gomaxprocs); runtime·singleproc = runtime·gomaxprocs == 1; - runtime·sched.predawn = 1; + canaddmcpu(); // mcpu++ to account for bootstrap m + m->helpgc = 1; // flag to tell schedule() to mcpu-- + runtime·sched.grunning++; + + mstats.enablegc = 1; m->nomemprof--; } +extern void main·init(void); +extern void main·main(void); + +// The main goroutine. +void +runtime·main(void) +{ + // Lock the main goroutine onto this, the main OS thread, + // during initialization. Most programs won't care, but a few + // do require certain calls to be made by the main thread. + // Those can arrange for main.main to run in the main thread + // by calling runtime.LockOSThread during initialization + // to preserve the lock. + runtime·LockOSThread(); + runtime·sched.init = true; + main·init(); + runtime·sched.init = false; + if(!runtime·sched.lockmain) + runtime·UnlockOSThread(); + + main·main(); + runtime·exit(0); + for(;;) + *(int32*)runtime·main = 0; +} + // Lock the scheduler. static void schedlock(void) @@ -226,22 +254,6 @@ schedunlock(void) runtime·notewakeup(&m->havenextg); } -// Called after main·init_function; main·main will be called on return. -void -runtime·initdone(void) -{ - // Let's go. - runtime·sched.predawn = 0; - mstats.enablegc = 1; - - // If main·init_function started other goroutines, - // kick off new m's to handle them, like ready - // would have, had it not been pre-dawn. - schedlock(); - matchmg(); - schedunlock(); -} - void runtime·goexit(void) { @@ -323,6 +335,9 @@ mcommoninit(M *m) m->fastrand = 0x49f6428aUL + m->id; m->stackalloc = runtime·malloc(sizeof(*m->stackalloc)); runtime·FixAlloc_Init(m->stackalloc, FixedStack, runtime·SysAlloc, nil, nil); + + if(m->mcache == nil) + m->mcache = runtime·allocmcache(); } // Try to increment mcpu. Report whether succeeded. @@ -422,7 +437,7 @@ mget(G *g) M *m; // if g has its own m, use it. - if((m = g->lockedm) != nil) + if(g && (m = g->lockedm) != nil) return m; // otherwise use general m pool. @@ -463,8 +478,7 @@ readylocked(G *g) g->status = Grunnable; gput(g); - if(!runtime·sched.predawn) - matchmg(); + matchmg(); } static void @@ -507,6 +521,7 @@ nextgandunlock(void) G *gp; uint32 v; +top: if(atomic_mcpu(runtime·sched.atomic) >= maxgomaxprocs) runtime·throw("negative mcpu"); @@ -584,12 +599,50 @@ nextgandunlock(void) schedunlock(); runtime·notesleep(&m->havenextg); + if(m->helpgc) { + runtime·gchelper(); + m->helpgc = 0; + runtime·lock(&runtime·sched); + goto top; + } if((gp = m->nextg) == nil) runtime·throw("bad m->nextg in nextgoroutine"); m->nextg = nil; return gp; } +int32 +runtime·helpgc(bool *extra) +{ + M *mp; + int32 n, max; + + // Figure out how many CPUs to use. + // Limited by gomaxprocs, number of actual CPUs, and MaxGcproc. + max = runtime·gomaxprocs; + if(max > runtime·ncpu) + max = runtime·ncpu; + if(max > MaxGcproc) + max = MaxGcproc; + + // We're going to use one CPU no matter what. + // Figure out the max number of additional CPUs. + max--; + + runtime·lock(&runtime·sched); + n = 0; + while(n < max && (mp = mget(nil)) != nil) { + n++; + mp->helpgc = 1; + mp->waitnextg = 0; + runtime·notewakeup(&mp->havenextg); + } + runtime·unlock(&runtime·sched); + if(extra) + *extra = n != max; + return n; +} + void runtime·stoptheworld(void) { @@ -626,15 +679,29 @@ runtime·stoptheworld(void) schedunlock(); } -// TODO(rsc): Remove. This is only temporary, -// for the mark and sweep collector. void -runtime·starttheworld(void) +runtime·starttheworld(bool extra) { + M *m; + schedlock(); runtime·gcwaiting = 0; setmcpumax(runtime·gomaxprocs); matchmg(); + if(extra && canaddmcpu()) { + // Start a new m that will (we hope) be idle + // and so available to help when the next + // garbage collection happens. + // canaddmcpu above did mcpu++ + // (necessary, because m will be doing various + // initialization work so is definitely running), + // but m is not running a specific goroutine, + // so set the helpgc flag as a signal to m's + // first schedule(nil) to mcpu-- and grunning--. + m = runtime·newm(); + m->helpgc = 1; + runtime·sched.grunning++; + } schedunlock(); } @@ -644,8 +711,6 @@ runtime·mstart(void) { if(g != m->g0) runtime·throw("bad runtime·mstart"); - if(m->mcache == nil) - m->mcache = runtime·allocmcache(); // Record top of stack for use by mcall. // Once we call schedule we're never coming back, @@ -671,50 +736,58 @@ struct CgoThreadStart }; // Kick off new m's as needed (up to mcpumax). -// There are already `other' other cpus that will -// start looking for goroutines shortly. // Sched is locked. static void matchmg(void) { - G *g; + G *gp; + M *mp; if(m->mallocing || m->gcing) return; while(haveg() && canaddmcpu()) { - g = gget(); - if(g == nil) + gp = gget(); + if(gp == nil) runtime·throw("gget inconsistency"); - // Find the m that will run g. - M *m; - if((m = mget(g)) == nil){ - m = runtime·malloc(sizeof(M)); - mcommoninit(m); - - if(runtime·iscgo) { - CgoThreadStart ts; - - if(libcgo_thread_start == nil) - runtime·throw("libcgo_thread_start missing"); - // pthread_create will make us a stack. - m->g0 = runtime·malg(-1); - ts.m = m; - ts.g = m->g0; - ts.fn = runtime·mstart; - runtime·asmcgocall(libcgo_thread_start, &ts); - } else { - if(Windows) - // windows will layout sched stack on os stack - m->g0 = runtime·malg(-1); - else - m->g0 = runtime·malg(8192); - runtime·newosproc(m, m->g0, m->g0->stackbase, runtime·mstart); - } - } - mnextg(m, g); + // Find the m that will run gp. + if((mp = mget(gp)) == nil) + mp = runtime·newm(); + mnextg(mp, gp); + } +} + +// Create a new m. It will start off with a call to runtime·mstart. +M* +runtime·newm(void) +{ + M *m; + + m = runtime·malloc(sizeof(M)); + mcommoninit(m); + + if(runtime·iscgo) { + CgoThreadStart ts; + + if(libcgo_thread_start == nil) + runtime·throw("libcgo_thread_start missing"); + // pthread_create will make us a stack. + m->g0 = runtime·malg(-1); + ts.m = m; + ts.g = m->g0; + ts.fn = runtime·mstart; + runtime·asmcgocall(libcgo_thread_start, &ts); + } else { + if(Windows) + // windows will layout sched stack on os stack + m->g0 = runtime·malg(-1); + else + m->g0 = runtime·malg(8192); + runtime·newosproc(m, m->g0, m->g0->stackbase, runtime·mstart); } + + return m; } // One round of scheduler: find a goroutine and run it. @@ -729,9 +802,6 @@ schedule(G *gp) schedlock(); if(gp != nil) { - if(runtime·sched.predawn) - runtime·throw("init rescheduling"); - // Just finished running gp. gp->m = nil; runtime·sched.grunning--; @@ -767,6 +837,19 @@ schedule(G *gp) gp->readyonstop = 0; readylocked(gp); } + } else if(m->helpgc) { + // Bootstrap m or new m started by starttheworld. + // atomic { mcpu-- } + v = runtime·xadd(&runtime·sched.atomic, -1<<mcpuShift); + if(atomic_mcpu(v) > maxgomaxprocs) + runtime·throw("negative mcpu in scheduler"); + // Compensate for increment in starttheworld(). + runtime·sched.grunning--; + m->helpgc = 0; + } else if(m->nextg != nil) { + // New m started by matchmg. + } else { + runtime·throw("invalid m state in scheduler"); } // Find (or wait for) g to run. Unlocks runtime·sched. @@ -821,9 +904,6 @@ runtime·entersyscall(void) { uint32 v; - if(runtime·sched.predawn) - return; - // Leave SP around for gc and traceback. runtime·gosave(&g->sched); g->gcsp = g->sched.sp; @@ -875,9 +955,6 @@ runtime·exitsyscall(void) { uint32 v; - if(runtime·sched.predawn) - return; - // Fast path. // If we can do the mcpu++ bookkeeping and // find that we still have mcpu <= mcpumax, then we can @@ -914,6 +991,9 @@ runtime·exitsyscall(void) g->gcstack = nil; } +// Called from runtime·lessstack when returning from a function which +// allocated a new stack segment. The function's return value is in +// m->cret. void runtime·oldstack(void) { @@ -945,6 +1025,11 @@ runtime·oldstack(void) runtime·gogo(&old.gobuf, m->cret); } +// Called from reflect·call or from runtime·morestack when a new +// stack segment is needed. Allocate a new stack big enough for +// m->moreframesize bytes, copy m->moreargsize bytes to the new frame, +// and then act as though runtime·lessstack called the function at +// m->morepc. void runtime·newstack(void) { @@ -1032,6 +1117,10 @@ runtime·newstack(void) *(int32*)345 = 123; // never return } +// Hook used by runtime·malg to call runtime·stackalloc on the +// scheduler stack. This exists because runtime·stackalloc insists +// on being called on the scheduler stack, to avoid trying to grow +// the stack while allocating a new stack segment. static void mstackalloc(G *gp) { @@ -1039,6 +1128,7 @@ mstackalloc(G *gp) runtime·gogo(&gp->sched, 0); } +// Allocate a new g, with a stack big enough for stacksize bytes. G* runtime·malg(int32 stacksize) { @@ -1065,15 +1155,13 @@ runtime·malg(int32 stacksize) return newg; } -/* - * Newproc and deferproc need to be textflag 7 - * (no possible stack split when nearing overflow) - * because they assume that the arguments to fn - * are available sequentially beginning at &arg0. - * If a stack split happened, only the one word - * arg0 would be copied. It's okay if any functions - * they call split the stack below the newproc frame. - */ +// 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. #pragma textflag 7 void runtime·newproc(int32 siz, byte* fn, ...) @@ -1087,6 +1175,10 @@ runtime·newproc(int32 siz, byte* fn, ...) runtime·newproc1(fn, argp, siz, 0, runtime·getcallerpc(&siz)); } +// Create a new g running fn with narg bytes of arguments starting +// at argp and returning nret bytes of results. callerpc is the +// address of the go statement that created this. The new g is put +// on the queue of g's waiting to run. G* runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc) { @@ -1097,7 +1189,7 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc) //printf("newproc1 %p %p narg=%d nret=%d\n", fn, argp, narg, nret); siz = narg + nret; siz = (siz+7) & ~7; - + // We could instead create a secondary stack frame // and make it look like goexit was on the original but // the call to the actual goroutine function was split. @@ -1147,6 +1239,12 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc) //printf(" goid=%d\n", newg->goid); } +// Create a new deferred function fn with siz bytes of arguments. +// The compiler turns a defer 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. #pragma textflag 7 uintptr runtime·deferproc(int32 siz, byte* fn, ...) @@ -1175,6 +1273,16 @@ runtime·deferproc(int32 siz, byte* fn, ...) return 0; } +// Run a deferred function if there is one. +// The compiler inserts a call to this at the end of any +// function which calls defer. +// If there is a deferred function, this will call runtime·jmpdefer, +// which will jump to the deferred function such that it appears +// to have been called by the caller of deferreturn at the point +// just before deferreturn was called. The effect is that deferreturn +// is called again and again until there are no more deferred functions. +// Cannot split the stack because we reuse the caller's frame to +// call the deferred function. #pragma textflag 7 void runtime·deferreturn(uintptr arg0) @@ -1196,6 +1304,7 @@ runtime·deferreturn(uintptr arg0) runtime·jmpdefer(fn, argp); } +// Run all deferred functions for the current goroutine. static void rundefer(void) { @@ -1237,6 +1346,7 @@ unwindstack(G *gp, byte *sp) } } +// Print all currently active panics. Used when crashing. static void printpanics(Panic *p) { @@ -1253,6 +1363,7 @@ printpanics(Panic *p) static void recovery(G*); +// The implementation of the predeclared function panic. void runtime·panic(Eface e) { @@ -1295,6 +1406,9 @@ runtime·panic(Eface e) runtime·dopanic(0); } +// Unwind the stack after a deferred function calls recover +// after a panic. Then arrange to continue running as though +// the caller of the deferred function returned normally. static void recovery(G *gp) { @@ -1326,7 +1440,10 @@ recovery(G *gp) runtime·gogo(&gp->sched, 1); } -#pragma textflag 7 /* no split, or else g->stackguard is not the stack for fp */ +// The implementation of the predeclared function recover. +// Cannot split the stack because it needs to reliably +// find the stack segment of its caller. +#pragma textflag 7 void runtime·recover(byte *argp, Eface ret) { @@ -1438,15 +1555,7 @@ runtime·Gosched(void) runtime·gosched(); } -void -runtime·LockOSThread(void) -{ - if(runtime·sched.predawn) - runtime·throw("cannot wire during init"); - m->lockedg = g; - g->lockedm = m; -} - +// Implementation of runtime.GOMAXPROCS. // delete when scheduler is stronger int32 runtime·gomaxprocsfunc(int32 n) @@ -1487,8 +1596,23 @@ runtime·gomaxprocsfunc(int32 n) } void +runtime·LockOSThread(void) +{ + if(m == &runtime·m0 && runtime·sched.init) { + runtime·sched.lockmain = true; + return; + } + m->lockedg = g; + g->lockedm = m; +} + +void runtime·UnlockOSThread(void) { + if(m == &runtime·m0 && runtime·sched.init) { + runtime·sched.lockmain = false; + return; + } m->lockedg = nil; g->lockedm = nil; } @@ -1499,6 +1623,14 @@ runtime·lockedOSThread(void) return g->lockedm != nil && m->lockedg != nil; } +// for testing of callbacks +void +runtime·golockedOSThread(bool ret) +{ + ret = runtime·lockedOSThread(); + FLUSH(&ret); +} + // for testing of wire, unwire void runtime·mid(uint32 ret) @@ -1539,6 +1671,7 @@ static struct { uintptr pcbuf[100]; } prof; +// Called if we receive a SIGPROF signal. void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp) { @@ -1558,6 +1691,7 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp) runtime·unlock(&prof); } +// Arrange to call fn with a traceback hz times a second. void runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz) { @@ -1588,8 +1722,10 @@ runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz) void (*libcgo_setenv)(byte**); +// Update the C environment if cgo is loaded. +// Called from syscall.Setenv. void -os·setenv_c(String k, String v) +syscall·setenv_c(String k, String v) { byte *arg[2]; diff --git a/src/pkg/runtime/darwin/386/rt0.s b/src/pkg/runtime/rt0_darwin_386.s index 30b497f5e..30b497f5e 100644 --- a/src/pkg/runtime/darwin/386/rt0.s +++ b/src/pkg/runtime/rt0_darwin_386.s diff --git a/src/pkg/runtime/darwin/amd64/rt0.s b/src/pkg/runtime/rt0_darwin_amd64.s index 4cfab5876..4cfab5876 100644 --- a/src/pkg/runtime/darwin/amd64/rt0.s +++ b/src/pkg/runtime/rt0_darwin_amd64.s diff --git a/src/pkg/runtime/freebsd/386/rt0.s b/src/pkg/runtime/rt0_freebsd_386.s index 3ca981b3a..3ca981b3a 100644 --- a/src/pkg/runtime/freebsd/386/rt0.s +++ b/src/pkg/runtime/rt0_freebsd_386.s diff --git a/src/pkg/runtime/freebsd/amd64/rt0.s b/src/pkg/runtime/rt0_freebsd_amd64.s index 5d2eeeeff..5d2eeeeff 100644 --- a/src/pkg/runtime/freebsd/amd64/rt0.s +++ b/src/pkg/runtime/rt0_freebsd_amd64.s diff --git a/src/pkg/runtime/linux/386/rt0.s b/src/pkg/runtime/rt0_linux_386.s index 83149540e..83149540e 100644 --- a/src/pkg/runtime/linux/386/rt0.s +++ b/src/pkg/runtime/rt0_linux_386.s diff --git a/src/pkg/runtime/linux/amd64/rt0.s b/src/pkg/runtime/rt0_linux_amd64.s index dac9ae181..dac9ae181 100644 --- a/src/pkg/runtime/linux/amd64/rt0.s +++ b/src/pkg/runtime/rt0_linux_amd64.s diff --git a/src/pkg/runtime/linux/arm/rt0.s b/src/pkg/runtime/rt0_linux_arm.s index 8838b4891..8838b4891 100644 --- a/src/pkg/runtime/linux/arm/rt0.s +++ b/src/pkg/runtime/rt0_linux_arm.s diff --git a/src/pkg/runtime/rt0_netbsd_386.s b/src/pkg/runtime/rt0_netbsd_386.s new file mode 100644 index 000000000..829e4133b --- /dev/null +++ b/src/pkg/runtime/rt0_netbsd_386.s @@ -0,0 +1,6 @@ +// 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. + +TEXT _rt0_386_netbsd(SB),7,$0 + JMP _rt0_386(SB) diff --git a/src/pkg/runtime/rt0_netbsd_amd64.s b/src/pkg/runtime/rt0_netbsd_amd64.s new file mode 100644 index 000000000..85482b98d --- /dev/null +++ b/src/pkg/runtime/rt0_netbsd_amd64.s @@ -0,0 +1,8 @@ +// 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. + +TEXT _rt0_amd64_netbsd(SB),7,$-8 + MOVQ $_rt0_amd64(SB), DX + MOVQ SP, DI + JMP DX diff --git a/src/pkg/runtime/openbsd/386/rt0.s b/src/pkg/runtime/rt0_openbsd_386.s index e7e0da78f..e7e0da78f 100644 --- a/src/pkg/runtime/openbsd/386/rt0.s +++ b/src/pkg/runtime/rt0_openbsd_386.s diff --git a/src/pkg/runtime/openbsd/amd64/rt0.s b/src/pkg/runtime/rt0_openbsd_amd64.s index e7fce5969..e7fce5969 100644 --- a/src/pkg/runtime/openbsd/amd64/rt0.s +++ b/src/pkg/runtime/rt0_openbsd_amd64.s diff --git a/src/pkg/runtime/plan9/386/rt0.s b/src/pkg/runtime/rt0_plan9_386.s index b56c8b325..b56c8b325 100644 --- a/src/pkg/runtime/plan9/386/rt0.s +++ b/src/pkg/runtime/rt0_plan9_386.s diff --git a/src/pkg/runtime/windows/386/rt0.s b/src/pkg/runtime/rt0_windows_386.s index 3b023de2f..3b023de2f 100644 --- a/src/pkg/runtime/windows/386/rt0.s +++ b/src/pkg/runtime/rt0_windows_386.s diff --git a/src/pkg/runtime/windows/amd64/rt0.s b/src/pkg/runtime/rt0_windows_amd64.s index 35978bc74..dc1408adc 100644 --- a/src/pkg/runtime/windows/amd64/rt0.s +++ b/src/pkg/runtime/rt0_windows_amd64.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "amd64/asm.h" +#include "zasm_GOOS_GOARCH.h" TEXT _rt0_amd64_windows(SB),7,$-8 MOVQ $_rt0_amd64(SB), AX diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py index a96f3f382..dff4e2b83 100644 --- a/src/pkg/runtime/runtime-gdb.py +++ b/src/pkg/runtime/runtime-gdb.py @@ -91,8 +91,8 @@ class MapTypePrinter: def traverse_hash(self, stab): ptr = stab['entry'].address - end = stab['end'] - while ptr < end: + last = stab['last'] + while ptr <= last: v = ptr.dereference() ptr = ptr + 1 if v['hash'] == 0: continue @@ -122,8 +122,8 @@ class ChanTypePrinter: return str(self.val.type) def children(self): - # see chan.c chanbuf() - et = [x.type for x in self.val['free'].type.target().fields() if x.name == 'elem'][0] + # see chan.c chanbuf(). et is the type stolen from hchan<T>::recvq->first->elem + et = [x.type for x in self.val['recvq']['first'].type.target().fields() if x.name == 'elem'][0] ptr = (self.val.address + 1).cast(et.pointer()) for i in range(self.val["qcount"]): j = (self.val["recvx"] + i) % self.val["dataqsiz"] @@ -187,6 +187,8 @@ def lookup_type(name): def iface_dtype(obj): "Decode type of the data field of an eface or iface struct." + # known issue: dtype_name decoded from runtime.commonType is "nested.Foo" + # but the dwarf table lists it as "full/path/to/nested.Foo" if is_iface(obj): go_type_ptr = obj['tab']['_type'] @@ -198,13 +200,30 @@ def iface_dtype(obj): ct = gdb.lookup_type("struct runtime.commonType").pointer() dynamic_go_type = go_type_ptr['ptr'].cast(ct).dereference() dtype_name = dynamic_go_type['string'].dereference()['str'].string() - type_size = int(dynamic_go_type['size']) - uintptr_size = int(dynamic_go_type['size'].type.sizeof) # size is itself an uintptr + dynamic_gdb_type = lookup_type(dtype_name) - if type_size > uintptr_size: - dynamic_gdb_type = dynamic_gdb_type.pointer() + if dynamic_gdb_type: + type_size = int(dynamic_go_type['size']) + uintptr_size = int(dynamic_go_type['size'].type.sizeof) # size is itself an uintptr + if type_size > uintptr_size: + dynamic_gdb_type = dynamic_gdb_type.pointer() + return dynamic_gdb_type +def iface_dtype_name(obj): + "Decode type name of the data field of an eface or iface struct." + + if is_iface(obj): + go_type_ptr = obj['tab']['_type'] + elif is_eface(obj): + go_type_ptr = obj['_type'] + else: + return + + ct = gdb.lookup_type("struct runtime.commonType").pointer() + dynamic_go_type = go_type_ptr['ptr'].cast(ct).dereference() + return dynamic_go_type['string'].dereference()['str'].string() + class IfacePrinter: """Pretty print interface values @@ -224,6 +243,10 @@ class IfacePrinter: dtype = iface_dtype(self.val) except: return "<bad dynamic type>" + + if not dtype: # trouble looking up, print something reasonable + return "(%s)%s" % (iface_dtype_name(self.val), self.val['data']) + try: return self.val['data'].cast(dtype).dereference() except: diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c index ae6fd877c..81caccad3 100644 --- a/src/pkg/runtime/runtime.c +++ b/src/pkg/runtime/runtime.c @@ -172,7 +172,7 @@ static int32 argc; static uint8** argv; Slice os·Args; -Slice os·Envs; +Slice syscall·envs; void runtime·args(int32 c, uint8 **v) @@ -214,9 +214,9 @@ runtime·goenvs_unix(void) s = runtime·malloc(n*sizeof s[0]); for(i=0; i<n; i++) s[i] = runtime·gostringnocopy(argv[argc+1+i]); - os·Envs.array = (byte*)s; - os·Envs.len = n; - os·Envs.cap = n; + syscall·envs.array = (byte*)s; + syscall·envs.len = n; + syscall·envs.cap = n; } byte* @@ -229,8 +229,8 @@ runtime·getenv(int8 *s) bs = (byte*)s; len = runtime·findnull(bs); - envv = (String*)os·Envs.array; - envc = os·Envs.len; + envv = (String*)syscall·envs.array; + envc = syscall·envs.len; for(i=0; i<envc; i++){ if(envv[i].len <= len) continue; @@ -278,8 +278,8 @@ runtime·check(void) uint32 f; int64 g; uint64 h; - float32 i; - float64 j; + float32 i, i1; + float64 j, j1; void* k; uint16* l; struct x1 { @@ -319,351 +319,31 @@ runtime·check(void) if(z != 4) runtime·throw("cas4"); - runtime·initsig(0); -} - -/* - * map and chan helpers for - * dealing with unknown types - */ -static uintptr -memhash(uint32 s, void *a) -{ - byte *b; - uintptr hash; - - b = a; - if(sizeof(hash) == 4) - hash = 2860486313U; - else - hash = 33054211828000289ULL; - while(s > 0) { - if(sizeof(hash) == 4) - hash = (hash ^ *b) * 3267000013UL; - else - hash = (hash ^ *b) * 23344194077549503ULL; - b++; - s--; - } - return hash; -} - -static uint32 -memequal(uint32 s, void *a, void *b) -{ - byte *ba, *bb, *aend; - - if(a == b) - return 1; - ba = a; - bb = b; - aend = ba+s; - while(ba != aend) { - if(*ba != *bb) - return 0; - ba++; - bb++; - } - return 1; -} - -static void -memprint(uint32 s, void *a) -{ - uint64 v; - - v = 0xbadb00b; - switch(s) { - case 1: - v = *(uint8*)a; - break; - case 2: - v = *(uint16*)a; - break; - case 4: - v = *(uint32*)a; - break; - case 8: - v = *(uint64*)a; - break; - } - runtime·printint(v); -} - -static void -memcopy(uint32 s, void *a, void *b) -{ - if(b == nil) { - runtime·memclr(a,s); - return; - } - runtime·memmove(a,b,s); -} - -static uint32 -memequal8(uint32 s, uint8 *a, uint8 *b) -{ - USED(s); - return *a == *b; -} - -static void -memcopy8(uint32 s, uint8 *a, uint8 *b) -{ - USED(s); - if(b == nil) { - *a = 0; - return; - } - *a = *b; -} - -static uint32 -memequal16(uint32 s, uint16 *a, uint16 *b) -{ - USED(s); - return *a == *b; -} - -static void -memcopy16(uint32 s, uint16 *a, uint16 *b) -{ - USED(s); - if(b == nil) { - *a = 0; - return; - } - *a = *b; -} - -static uint32 -memequal32(uint32 s, uint32 *a, uint32 *b) -{ - USED(s); - return *a == *b; -} - -static void -memcopy32(uint32 s, uint32 *a, uint32 *b) -{ - USED(s); - if(b == nil) { - *a = 0; - return; - } - *a = *b; -} - -static uint32 -memequal64(uint32 s, uint64 *a, uint64 *b) -{ - USED(s); - return *a == *b; -} - -static void -memcopy64(uint32 s, uint64 *a, uint64 *b) -{ - USED(s); - if(b == nil) { - *a = 0; - return; - } - *a = *b; -} - -static uint32 -memequal128(uint32 s, uint64 *a, uint64 *b) -{ - USED(s); - return a[0] == b[0] && a[1] == b[1]; -} - -static void -memcopy128(uint32 s, uint64 *a, uint64 *b) -{ - USED(s); - if(b == nil) { - a[0] = 0; - a[1] = 0; - return; - } - a[0] = b[0]; - a[1] = b[1]; -} + *(uint64*)&j = ~0ULL; + if(j == j) + runtime·throw("float64nan"); + if(!(j != j)) + runtime·throw("float64nan1"); + + *(uint64*)&j1 = ~1ULL; + if(j == j1) + runtime·throw("float64nan2"); + if(!(j != j1)) + runtime·throw("float64nan3"); + + *(uint32*)&i = ~0UL; + if(i == i) + runtime·throw("float32nan"); + if(!(i != i)) + runtime·throw("float32nan1"); + + *(uint32*)&i1 = ~1UL; + if(i == i1) + runtime·throw("float32nan2"); + if(!(i != i1)) + runtime·throw("float32nan3"); -static void -slicecopy(uint32 s, Slice *a, Slice *b) -{ - USED(s); - if(b == nil) { - a->array = 0; - a->len = 0; - a->cap = 0; - return; - } - a->array = b->array; - a->len = b->len; - a->cap = b->cap; -} - -static uintptr -strhash(uint32 s, String *a) -{ - USED(s); - return memhash((*a).len, (*a).str); -} - -static uint32 -strequal(uint32 s, String *a, String *b) -{ - int32 alen; - - USED(s); - alen = a->len; - if(alen != b->len) - return false; - return memequal(alen, a->str, b->str); -} - -static void -strprint(uint32 s, String *a) -{ - USED(s); - runtime·printstring(*a); -} - -static void -strcopy(uint32 s, String *a, String *b) -{ - USED(s); - if(b == nil) { - a->str = 0; - a->len = 0; - return; - } - a->str = b->str; - a->len = b->len; -} - -static uintptr -interhash(uint32 s, Iface *a) -{ - USED(s); - return runtime·ifacehash(*a); -} - -static void -interprint(uint32 s, Iface *a) -{ - USED(s); - runtime·printiface(*a); -} - -static uint32 -interequal(uint32 s, Iface *a, Iface *b) -{ - USED(s); - return runtime·ifaceeq_c(*a, *b); -} - -static void -intercopy(uint32 s, Iface *a, Iface *b) -{ - USED(s); - if(b == nil) { - a->tab = 0; - a->data = 0; - return; - } - a->tab = b->tab; - a->data = b->data; -} - -static uintptr -nilinterhash(uint32 s, Eface *a) -{ - USED(s); - return runtime·efacehash(*a); -} - -static void -nilinterprint(uint32 s, Eface *a) -{ - USED(s); - runtime·printeface(*a); -} - -static uint32 -nilinterequal(uint32 s, Eface *a, Eface *b) -{ - USED(s); - return runtime·efaceeq_c(*a, *b); -} - -static void -nilintercopy(uint32 s, Eface *a, Eface *b) -{ - USED(s); - if(b == nil) { - a->type = 0; - a->data = 0; - return; - } - a->type = b->type; - a->data = b->data; -} - -uintptr -runtime·nohash(uint32 s, void *a) -{ - USED(s); - USED(a); - runtime·panicstring("hash of unhashable type"); - return 0; -} - -uint32 -runtime·noequal(uint32 s, void *a, void *b) -{ - USED(s); - USED(a); - USED(b); - runtime·panicstring("comparing uncomparable types"); - return 0; -} - -Alg -runtime·algarray[] = -{ -[AMEM] { memhash, memequal, memprint, memcopy }, -[ANOEQ] { runtime·nohash, runtime·noequal, memprint, memcopy }, -[ASTRING] { (void*)strhash, (void*)strequal, (void*)strprint, (void*)strcopy }, -[AINTER] { (void*)interhash, (void*)interequal, (void*)interprint, (void*)intercopy }, -[ANILINTER] { (void*)nilinterhash, (void*)nilinterequal, (void*)nilinterprint, (void*)nilintercopy }, -[ASLICE] { (void*)runtime·nohash, (void*)runtime·noequal, (void*)memprint, (void*)slicecopy }, -[AMEM8] { memhash, (void*)memequal8, memprint, (void*)memcopy8 }, -[AMEM16] { memhash, (void*)memequal16, memprint, (void*)memcopy16 }, -[AMEM32] { memhash, (void*)memequal32, memprint, (void*)memcopy32 }, -[AMEM64] { memhash, (void*)memequal64, memprint, (void*)memcopy64 }, -[AMEM128] { memhash, (void*)memequal128, memprint, (void*)memcopy128 }, -[ANOEQ8] { runtime·nohash, runtime·noequal, memprint, (void*)memcopy8 }, -[ANOEQ16] { runtime·nohash, runtime·noequal, memprint, (void*)memcopy16 }, -[ANOEQ32] { runtime·nohash, runtime·noequal, memprint, (void*)memcopy32 }, -[ANOEQ64] { runtime·nohash, runtime·noequal, memprint, (void*)memcopy64 }, -[ANOEQ128] { runtime·nohash, runtime·noequal, memprint, (void*)memcopy128 }, -}; - -int64 -runtime·nanotime(void) -{ - int64 sec; - int32 usec; - - sec = 0; - usec = 0; - runtime·gettime(&sec, &usec); - return sec*1000000000 + (int64)usec*1000; + runtime·initsig(0); } void diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index 999511ac2..df2cd149f 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -43,21 +43,19 @@ typedef int32 intptr; */ typedef uint8 bool; typedef uint8 byte; -typedef struct Alg Alg; typedef struct Func Func; typedef struct G G; typedef struct Gobuf Gobuf; -typedef struct Lock Lock; +typedef union Lock Lock; typedef struct M M; typedef struct Mem Mem; typedef union Note Note; typedef struct Slice Slice; typedef struct Stktop Stktop; typedef struct String String; -typedef struct Usema Usema; typedef struct SigTab SigTab; typedef struct MCache MCache; -typedef struct FixAlloc FixAlloc; +typedef struct FixAlloc FixAlloc; typedef struct Iface Iface; typedef struct Itab Itab; typedef struct Eface Eface; @@ -71,6 +69,8 @@ typedef struct Hchan Hchan; typedef struct Complex64 Complex64; typedef struct Complex128 Complex128; typedef struct WinCall WinCall; +typedef struct Timers Timers; +typedef struct Timer Timer; /* * per-cpu declaration. @@ -117,32 +117,15 @@ enum /* * structures */ -struct Lock -{ -#ifdef __WINDOWS__ - M* waitm; // linked list of waiting M's -#else - uint32 key; - uint32 sema; // for OS X -#endif -}; -struct Usema +union Lock { - uint32 u; - uint32 k; + uint32 key; // futex-based impl + M* waitm; // linked list of waiting M's (sema-based impl) }; union Note { - struct { // Linux - uint32 state; - }; - struct { // Windows - Lock lock; - }; - struct { // OS X - int32 wakeup; - Usema sema; - }; + uint32 key; // futex-based impl + M* waitm; // waiting M (sema-based impl) }; struct String { @@ -185,8 +168,8 @@ struct Gobuf }; struct G { - byte* stackguard; // cannot move - also known to linker, libmach, libcgo - byte* stackbase; // cannot move - also known to libmach, libcgo + byte* stackguard; // cannot move - also known to linker, libmach, runtime/cgo + byte* stackbase; // cannot move - also known to libmach, runtime/cgo Defer* defer; Panic* panic; Gobuf sched; @@ -238,6 +221,7 @@ struct M int32 waitnextg; int32 dying; int32 profilehz; + int32 helpgc; uint32 fastrand; uint64 ncgocall; Note havenextg; @@ -252,11 +236,13 @@ struct M uint32 freglo[16]; // D[i] lsb and F[i] uint32 freghi[16]; // D[i] msb and F[i+16] uint32 fflag; // floating point compare flags + M* nextwaitm; // next M waiting for lock + uintptr waitsema; // semaphore for parking on locks + uint32 waitsemacount; + uint32 waitsemalock; -#ifdef __WINDOWS__ +#ifdef GOOS_windows void* thread; // thread handle - void* event; // event for signalling - M* nextwaitm; // next M waiting for lock #endif uintptr end[]; }; @@ -273,13 +259,6 @@ struct Stktop uintptr free; // if free>0, call stackfree using free as size bool panic; // is this frame the top of a panic? }; -struct Alg -{ - uintptr (*hash)(uint32, void*); - uint32 (*equal)(uint32, void*, void*); - void (*print)(uint32, void*); - void (*copy)(uint32, void*, void*); -}; struct SigTab { int32 flags; @@ -320,7 +299,7 @@ struct WinCall uintptr err; // error number }; -#ifdef __WINDOWS__ +#ifdef GOOS_windows enum { Windows = 1 }; @@ -330,6 +309,33 @@ enum { }; #endif +struct Timers +{ + Lock; + G *timerproc; + bool sleeping; + bool rescheduling; + Note waitnote; + Timer **t; + int32 len; + int32 cap; +}; + +// Package time knows the layout of this structure. +// If this struct changes, adjust ../time/sleep.go:/runtimeTimer. +struct Timer +{ + int32 i; // heap index + + // Timer wakes up at when, and then at when+period, ... (period > 0 only) + // each time calling f(now, arg) in the timer goroutine, so f must be + // a well-behaved function and not block. + int64 when; + int64 period; + void (*f)(int64, Eface); + Eface arg; +}; + /* * defined macros * you need super-gopher-guru privilege @@ -342,31 +348,78 @@ enum { /* * known to compiler */ +enum { + Structrnd = sizeof(uintptr) +}; + +/* + * type algorithms - known to compiler + */ enum { AMEM, - ANOEQ, - ASTRING, - AINTER, - ANILINTER, - ASLICE, + AMEM0, AMEM8, AMEM16, AMEM32, AMEM64, AMEM128, + ANOEQ, + ANOEQ0, ANOEQ8, ANOEQ16, ANOEQ32, ANOEQ64, ANOEQ128, + ASTRING, + AINTER, + ANILINTER, + ASLICE, + AFLOAT32, + AFLOAT64, + ACPLX64, + ACPLX128, Amax }; +typedef struct Alg Alg; +struct Alg +{ + void (*hash)(uintptr*, uintptr, void*); + void (*equal)(bool*, uintptr, void*, void*); + void (*print)(uintptr, void*); + void (*copy)(uintptr, void*, void*); +}; +extern Alg runtime·algarray[Amax]; -enum { - Structrnd = sizeof(uintptr) -}; +void runtime·memhash(uintptr*, uintptr, void*); +void runtime·nohash(uintptr*, uintptr, void*); +void runtime·strhash(uintptr*, uintptr, void*); +void runtime·interhash(uintptr*, uintptr, void*); +void runtime·nilinterhash(uintptr*, uintptr, void*); + +void runtime·memequal(bool*, uintptr, void*, void*); +void runtime·noequal(bool*, uintptr, void*, void*); +void runtime·strequal(bool*, uintptr, void*, void*); +void runtime·interequal(bool*, uintptr, void*, void*); +void runtime·nilinterequal(bool*, uintptr, void*, void*); + +void runtime·memprint(uintptr, void*); +void runtime·strprint(uintptr, void*); +void runtime·interprint(uintptr, void*); +void runtime·nilinterprint(uintptr, void*); + +void runtime·memcopy(uintptr, void*, void*); +void runtime·memcopy8(uintptr, void*, void*); +void runtime·memcopy16(uintptr, void*, void*); +void runtime·memcopy32(uintptr, void*, void*); +void runtime·memcopy64(uintptr, void*, void*); +void runtime·memcopy128(uintptr, void*, void*); +void runtime·memcopy(uintptr, void*, void*); +void runtime·strcopy(uintptr, void*, void*); +void runtime·algslicecopy(uintptr, void*, void*); +void runtime·intercopy(uintptr, void*, void*); +void runtime·nilintercopy(uintptr, void*, void*); /* * deferred subroutine calls @@ -396,7 +449,6 @@ struct Panic /* * external data */ -extern Alg runtime·algarray[Amax]; extern String runtime·emptystring; G* runtime·allg; G* runtime·lastg; @@ -406,8 +458,8 @@ extern bool runtime·singleproc; extern uint32 runtime·panicking; extern int32 runtime·gcwaiting; // gc is waiting to run int8* runtime·goos; +int32 runtime·ncpu; extern bool runtime·iscgo; -extern void (*runtime·destroylock)(Lock*); /* * common functions and data @@ -484,12 +536,9 @@ bool runtime·ifaceeq_c(Iface, Iface); bool runtime·efaceeq_c(Eface, Eface); uintptr runtime·ifacehash(Iface); uintptr runtime·efacehash(Eface); -uintptr runtime·nohash(uint32, void*); -uint32 runtime·noequal(uint32, void*, void*); void* runtime·malloc(uintptr size); void runtime·free(void *v); -void runtime·addfinalizer(void*, void(*fn)(void*), int32); -void runtime·walkfintab(void (*fn)(void*)); +bool runtime·addfinalizer(void*, void(*fn)(void*), int32); void runtime·runpanic(Panic*); void* runtime·getcallersp(void*); int32 runtime·mcount(void); @@ -499,6 +548,8 @@ uint32 runtime·fastrand1(void); void runtime·exit(int32); void runtime·breakpoint(void); void runtime·gosched(void); +void runtime·tsleep(int64); +M* runtime·newm(void); void runtime·goexit(void); void runtime·asmcgocall(void (*fn)(void*), void*); void runtime·entersyscall(void); @@ -506,7 +557,6 @@ void runtime·exitsyscall(void); G* runtime·newproc1(byte*, byte*, int32, int32, void*); void runtime·siginit(void); bool runtime·sigsend(int32 sig); -void runtime·gettime(int64*, int32*); int32 runtime·callers(int32, uintptr*, int32); int32 runtime·gentraceback(byte*, byte*, byte*, G*, int32, uintptr*, int32); int64 runtime·nanotime(void); @@ -515,6 +565,7 @@ void runtime·startpanic(void); void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp); void runtime·resetcpuprofiler(int32); void runtime·setcpuprofilerate(void(*)(uintptr*, int32), int32); +void runtime·usleep(uint32); #pragma varargck argpos runtime·printf 1 #pragma varargck type "d" int32 @@ -534,7 +585,7 @@ void runtime·setcpuprofilerate(void(*)(uintptr*, int32), int32); // TODO(rsc): Remove. These are only temporary, // for the mark and sweep collector. void runtime·stoptheworld(void); -void runtime·starttheworld(void); +void runtime·starttheworld(bool); /* * mutual exclusion locks. in the uncontended case, @@ -556,10 +607,28 @@ void runtime·unlock(Lock*); * subsequent noteclear must be called only after * previous notesleep has returned, e.g. it's disallowed * to call noteclear straight after notewakeup. + * + * notetsleep is like notesleep but wakes up after + * a given number of nanoseconds even if the event + * has not yet happened. if a goroutine uses notetsleep to + * wake up early, it must wait to call noteclear until it + * can be sure that no other goroutine is calling + * notewakeup. */ void runtime·noteclear(Note*); void runtime·notesleep(Note*); void runtime·notewakeup(Note*); +void runtime·notetsleep(Note*, int64); + +/* + * 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); /* * This is consistent across Linux and BSD. @@ -572,7 +641,8 @@ void runtime·notewakeup(Note*); * low level C-called */ uint8* runtime·mmap(byte*, uintptr, int32, int32, int32, uint32); -void runtime·munmap(uint8*, uintptr); +void runtime·munmap(byte*, uintptr); +void runtime·madvise(byte*, uintptr, int32); void runtime·memclr(byte*, uintptr); void runtime·setcallerpc(void*, void*); void* runtime·getcallerpc(void*); @@ -635,6 +705,8 @@ String runtime·signame(int32 sig); int32 runtime·gomaxprocsfunc(int32 n); void runtime·procyield(uint32); void runtime·osyield(void); +void runtime·LockOSThread(void); +void runtime·UnlockOSThread(void); void runtime·mapassign(MapType*, Hmap*, byte*, byte*); void runtime·mapaccess(MapType*, Hmap*, byte*, byte*, bool*); diff --git a/src/pkg/runtime/runtime1.goc b/src/pkg/runtime/runtime1.goc index da2d0c572..667131c1e 100644 --- a/src/pkg/runtime/runtime1.goc +++ b/src/pkg/runtime/runtime1.goc @@ -8,3 +8,7 @@ package runtime func GOMAXPROCS(n int32) (ret int32) { ret = runtime·gomaxprocsfunc(n); } + +func NumCPU() (ret int32) { + ret = runtime·ncpu; +} diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc index d202a9d0a..67c90350b 100644 --- a/src/pkg/runtime/sema.goc +++ b/src/pkg/runtime/sema.goc @@ -19,6 +19,7 @@ package runtime #include "runtime.h" +#include "arch_GOARCH.h" typedef struct Sema Sema; struct Sema @@ -45,11 +46,7 @@ struct SemaRoot static union { SemaRoot; - // Modern processors tend to have 64-byte cache lines, - // potentially with 128-byte effective cache line size for reading. - // While there are hypothetical architectures - // with 16-4096 byte cache lines, 128 looks like a good compromise. - uint8 pad[128]; + uint8 pad[CacheLineSize]; } semtable[SEMTABLESZ]; static SemaRoot* diff --git a/src/pkg/runtime/darwin/386/signal.c b/src/pkg/runtime/signal_darwin_386.c index 29170b669..14f99115b 100644 --- a/src/pkg/runtime/darwin/386/signal.c +++ b/src/pkg/runtime/signal_darwin_386.c @@ -3,12 +3,12 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "os.h" -#include "signals.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signals_GOOS.h" void -runtime·dumpregs(Regs *r) +runtime·dumpregs(Regs32 *r) { runtime·printf("eax %x\n", r->eax); runtime·printf("ebx %x\n", r->ebx); @@ -37,8 +37,8 @@ void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; - Mcontext *mc; - Regs *r; + Mcontext32 *mc; + Regs32 *r; uintptr *sp; byte *pc; @@ -141,8 +141,8 @@ sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) if(restart) sa.sa_flags |= SA_RESTART; sa.sa_mask = ~0U; - sa.sa_tramp = (uintptr)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler - sa.__sigaction_u.__sa_sigaction = (uintptr)fn; + sa.sa_tramp = (void*)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler + *(uintptr*)sa.__sigaction_u = (uintptr)fn; runtime·sigaction(i, &sa, nil); } diff --git a/src/pkg/runtime/darwin/amd64/signal.c b/src/pkg/runtime/signal_darwin_amd64.c index 036a3aca7..c7621ddca 100644 --- a/src/pkg/runtime/darwin/amd64/signal.c +++ b/src/pkg/runtime/signal_darwin_amd64.c @@ -3,12 +3,12 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "os.h" -#include "signals.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signals_GOOS.h" void -runtime·dumpregs(Regs *r) +runtime·dumpregs(Regs64 *r) { runtime·printf("rax %X\n", r->rax); runtime·printf("rbx %X\n", r->rbx); @@ -45,8 +45,8 @@ void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; - Mcontext *mc; - Regs *r; + Mcontext64 *mc; + Regs64 *r; uintptr *sp; byte *pc; @@ -151,8 +151,8 @@ sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) if(restart) sa.sa_flags |= SA_RESTART; sa.sa_mask = ~0ULL; - sa.sa_tramp = (uintptr)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler - sa.__sigaction_u.__sa_sigaction = (uintptr)fn; + sa.sa_tramp = runtime·sigtramp; // runtime·sigtramp's job is to call into real handler + *(uintptr*)sa.__sigaction_u = (uintptr)fn; runtime·sigaction(i, &sa, nil); } diff --git a/src/pkg/runtime/freebsd/386/signal.c b/src/pkg/runtime/signal_freebsd_386.c index 2fe7ecd70..ff4aaabdb 100644 --- a/src/pkg/runtime/freebsd/386/signal.c +++ b/src/pkg/runtime/signal_freebsd_386.c @@ -3,9 +3,9 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "signals.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "signals_GOOS.h" +#include "os_GOOS.h" extern void runtime·sigtramp(void); diff --git a/src/pkg/runtime/freebsd/amd64/signal.c b/src/pkg/runtime/signal_freebsd_amd64.c index 8015e366e..2683f4fd0 100644 --- a/src/pkg/runtime/freebsd/amd64/signal.c +++ b/src/pkg/runtime/signal_freebsd_amd64.c @@ -3,9 +3,9 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "signals.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "signals_GOOS.h" +#include "os_GOOS.h" extern void runtime·sigtramp(void); diff --git a/src/pkg/runtime/linux/386/signal.c b/src/pkg/runtime/signal_linux_386.c index 4045b2efc..4f3abcebb 100644 --- a/src/pkg/runtime/linux/386/signal.c +++ b/src/pkg/runtime/signal_linux_386.c @@ -3,9 +3,9 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "signals.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "signals_GOOS.h" +#include "os_GOOS.h" void runtime·dumpregs(Sigcontext *r) diff --git a/src/pkg/runtime/linux/amd64/signal.c b/src/pkg/runtime/signal_linux_amd64.c index ee90271ed..937d5c347 100644 --- a/src/pkg/runtime/linux/amd64/signal.c +++ b/src/pkg/runtime/signal_linux_amd64.c @@ -3,9 +3,9 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "signals.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "signals_GOOS.h" +#include "os_GOOS.h" void runtime·dumpregs(Sigcontext *r) diff --git a/src/pkg/runtime/linux/arm/signal.c b/src/pkg/runtime/signal_linux_arm.c index 88a84d112..b32ec7a22 100644 --- a/src/pkg/runtime/linux/arm/signal.c +++ b/src/pkg/runtime/signal_linux_arm.c @@ -3,9 +3,9 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "signals.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "signals_GOOS.h" +#include "os_GOOS.h" void runtime·dumpregs(Sigcontext *r) diff --git a/src/pkg/runtime/openbsd/386/signal.c b/src/pkg/runtime/signal_netbsd_386.c index 8b0d4ac61..74fa1d490 100644 --- a/src/pkg/runtime/openbsd/386/signal.c +++ b/src/pkg/runtime/signal_netbsd_386.c @@ -3,9 +3,9 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "signals.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "signals_GOOS.h" +#include "os_GOOS.h" extern void runtime·sigtramp(void); diff --git a/src/pkg/runtime/openbsd/amd64/signal.c b/src/pkg/runtime/signal_netbsd_amd64.c index 01bc76d20..6c69fa733 100644 --- a/src/pkg/runtime/openbsd/amd64/signal.c +++ b/src/pkg/runtime/signal_netbsd_amd64.c @@ -3,9 +3,9 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "signals.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "signals_GOOS.h" +#include "os_GOOS.h" extern void runtime·sigtramp(void); diff --git a/src/pkg/runtime/signal_openbsd_386.c b/src/pkg/runtime/signal_openbsd_386.c new file mode 100644 index 000000000..74fa1d490 --- /dev/null +++ b/src/pkg/runtime/signal_openbsd_386.c @@ -0,0 +1,189 @@ +// 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. + +#include "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "signals_GOOS.h" +#include "os_GOOS.h" + +extern void runtime·sigtramp(void); + +typedef struct sigaction { + union { + void (*__sa_handler)(int32); + void (*__sa_sigaction)(int32, Siginfo*, void *); + } __sigaction_u; /* signal handler */ + uint32 sa_mask; /* signal mask to apply */ + int32 sa_flags; /* see signal options below */ +} Sigaction; + +void +runtime·dumpregs(Sigcontext *r) +{ + runtime·printf("eax %x\n", r->sc_eax); + runtime·printf("ebx %x\n", r->sc_ebx); + runtime·printf("ecx %x\n", r->sc_ecx); + runtime·printf("edx %x\n", r->sc_edx); + runtime·printf("edi %x\n", r->sc_edi); + runtime·printf("esi %x\n", r->sc_esi); + runtime·printf("ebp %x\n", r->sc_ebp); + runtime·printf("esp %x\n", r->sc_esp); + runtime·printf("eip %x\n", r->sc_eip); + runtime·printf("eflags %x\n", r->sc_eflags); + runtime·printf("cs %x\n", r->sc_cs); + runtime·printf("fs %x\n", r->sc_fs); + runtime·printf("gs %x\n", r->sc_gs); +} + +String +runtime·signame(int32 sig) +{ + if(sig < 0 || sig >= NSIG) + return runtime·emptystring; + return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name); +} + +void +runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) +{ + Sigcontext *r = context; + uintptr *sp; + + if(sig == SIGPROF) { + runtime·sigprof((uint8*)r->sc_eip, (uint8*)r->sc_esp, nil, gp); + return; + } + + if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) { + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = sig; + gp->sigcode0 = info->si_code; + gp->sigcode1 = *(uintptr*)((byte*)info + 12); /* si_addr */ + gp->sigpc = r->sc_eip; + + // Only push runtime·sigpanic if r->sc_eip != 0. + // If r->sc_eip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if(r->sc_eip != 0) { + sp = (uintptr*)r->sc_esp; + *--sp = r->sc_eip; + r->sc_esp = (uintptr)sp; + } + r->sc_eip = (uintptr)runtime·sigpanic; + return; + } + + if(runtime·sigtab[sig].flags & SigQueue) { + if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore)) + return; + runtime·exit(2); // SIGINT, SIGTERM, etc + } + + if(runtime·panicking) // traceback already printed + runtime·exit(2); + runtime·panicking = 1; + + if(sig < 0 || sig >= NSIG) + runtime·printf("Signal %d\n", sig); + else + runtime·printf("%s\n", runtime·sigtab[sig].name); + + runtime·printf("PC=%X\n", r->sc_eip); + runtime·printf("\n"); + + if(runtime·gotraceback()){ + runtime·traceback((void*)r->sc_eip, (void*)r->sc_esp, 0, gp); + runtime·tracebackothers(gp); + runtime·dumpregs(r); + } + + runtime·exit(2); +} + +// Called from kernel on signal stack, so no stack split. +#pragma textflag 7 +void +runtime·sigignore(void) +{ +} + +void +runtime·signalstack(byte *p, int32 n) +{ + Sigaltstack st; + + st.ss_sp = (int8*)p; + st.ss_size = n; + st.ss_flags = 0; + runtime·sigaltstack(&st, nil); +} + +static void +sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) +{ + Sigaction sa; + + runtime·memclr((byte*)&sa, sizeof sa); + sa.sa_flags = SA_SIGINFO|SA_ONSTACK; + if(restart) + sa.sa_flags |= SA_RESTART; + sa.sa_mask = ~0ULL; + if (fn == runtime·sighandler) + fn = (void*)runtime·sigtramp; + sa.__sigaction_u.__sa_sigaction = (void*)fn; + runtime·sigaction(i, &sa, nil); +} + +void +runtime·initsig(int32 queue) +{ + int32 i; + void *fn; + + runtime·siginit(); + + for(i = 0; i<NSIG; i++) { + if(runtime·sigtab[i].flags) { + if((runtime·sigtab[i].flags & SigQueue) != queue) + continue; + if(runtime·sigtab[i].flags & (SigCatch | SigQueue)) + fn = runtime·sighandler; + else + fn = runtime·sigignore; + sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0); + } + } +} + +void +runtime·resetcpuprofiler(int32 hz) +{ + Itimerval it; + + runtime·memclr((byte*)&it, sizeof it); + if(hz == 0) { + runtime·setitimer(ITIMER_PROF, &it, nil); + sigaction(SIGPROF, SIG_IGN, true); + } else { + sigaction(SIGPROF, runtime·sighandler, true); + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 1000000 / hz; + it.it_value = it.it_interval; + runtime·setitimer(ITIMER_PROF, &it, nil); + } + m->profilehz = hz; +} + +void +os·sigpipe(void) +{ + sigaction(SIGPIPE, SIG_DFL, false); + runtime·raisesigpipe(); +} diff --git a/src/pkg/runtime/signal_openbsd_amd64.c b/src/pkg/runtime/signal_openbsd_amd64.c new file mode 100644 index 000000000..6c69fa733 --- /dev/null +++ b/src/pkg/runtime/signal_openbsd_amd64.c @@ -0,0 +1,199 @@ +// 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. + +#include "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "signals_GOOS.h" +#include "os_GOOS.h" + +extern void runtime·sigtramp(void); + +typedef struct sigaction { + union { + void (*__sa_handler)(int32); + void (*__sa_sigaction)(int32, Siginfo*, void *); + } __sigaction_u; /* signal handler */ + uint32 sa_mask; /* signal mask to apply */ + int32 sa_flags; /* see signal options below */ +} Sigaction; + +void +runtime·dumpregs(Sigcontext *r) +{ + runtime·printf("rax %X\n", r->sc_rax); + runtime·printf("rbx %X\n", r->sc_rbx); + runtime·printf("rcx %X\n", r->sc_rcx); + runtime·printf("rdx %X\n", r->sc_rdx); + runtime·printf("rdi %X\n", r->sc_rdi); + runtime·printf("rsi %X\n", r->sc_rsi); + runtime·printf("rbp %X\n", r->sc_rbp); + runtime·printf("rsp %X\n", r->sc_rsp); + runtime·printf("r8 %X\n", r->sc_r8); + runtime·printf("r9 %X\n", r->sc_r9); + runtime·printf("r10 %X\n", r->sc_r10); + runtime·printf("r11 %X\n", r->sc_r11); + runtime·printf("r12 %X\n", r->sc_r12); + runtime·printf("r13 %X\n", r->sc_r13); + runtime·printf("r14 %X\n", r->sc_r14); + runtime·printf("r15 %X\n", r->sc_r15); + runtime·printf("rip %X\n", r->sc_rip); + runtime·printf("rflags %X\n", r->sc_rflags); + runtime·printf("cs %X\n", r->sc_cs); + runtime·printf("fs %X\n", r->sc_fs); + runtime·printf("gs %X\n", r->sc_gs); +} + +String +runtime·signame(int32 sig) +{ + if(sig < 0 || sig >= NSIG) + return runtime·emptystring; + return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name); +} + +void +runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) +{ + Sigcontext *r = context; + uintptr *sp; + + if(sig == SIGPROF) { + runtime·sigprof((uint8*)r->sc_rip, + (uint8*)r->sc_rsp, nil, gp); + return; + } + + if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) { + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = sig; + gp->sigcode0 = info->si_code; + gp->sigcode1 = *(uintptr*)((byte*)info + 16); /* si_addr */ + gp->sigpc = r->sc_rip; + + // Only push runtime·sigpanic if r->mc_rip != 0. + // If r->mc_rip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if(r->sc_rip != 0) { + sp = (uintptr*)r->sc_rsp; + *--sp = r->sc_rip; + r->sc_rsp = (uintptr)sp; + } + r->sc_rip = (uintptr)runtime·sigpanic; + return; + } + + if(runtime·sigtab[sig].flags & SigQueue) { + if(runtime·sigsend(sig) + || (runtime·sigtab[sig].flags & SigIgnore)) + return; + runtime·exit(2); // SIGINT, SIGTERM, etc + } + + if(runtime·panicking) // traceback already printed + runtime·exit(2); + runtime·panicking = 1; + + if(sig < 0 || sig >= NSIG) + runtime·printf("Signal %d\n", sig); + else + runtime·printf("%s\n", runtime·sigtab[sig].name); + + runtime·printf("PC=%X\n", r->sc_rip); + runtime·printf("\n"); + + if(runtime·gotraceback()){ + runtime·traceback((void*)r->sc_rip, (void*)r->sc_rsp, 0, gp); + runtime·tracebackothers(gp); + runtime·dumpregs(r); + } + + runtime·exit(2); +} + +// Called from kernel on signal stack, so no stack split. +#pragma textflag 7 +void +runtime·sigignore(void) +{ +} + +void +runtime·signalstack(byte *p, int32 n) +{ + Sigaltstack st; + + st.ss_sp = (int8*)p; + st.ss_size = n; + st.ss_flags = 0; + runtime·sigaltstack(&st, nil); +} + +static void +sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) +{ + Sigaction sa; + + runtime·memclr((byte*)&sa, sizeof sa); + sa.sa_flags = SA_SIGINFO|SA_ONSTACK; + if(restart) + sa.sa_flags |= SA_RESTART; + sa.sa_mask = ~0ULL; + if (fn == runtime·sighandler) + fn = (void*)runtime·sigtramp; + sa.__sigaction_u.__sa_sigaction = (void*)fn; + runtime·sigaction(i, &sa, nil); +} + +void +runtime·initsig(int32 queue) +{ + int32 i; + void *fn; + + runtime·siginit(); + + for(i = 0; i<NSIG; i++) { + if(runtime·sigtab[i].flags) { + if((runtime·sigtab[i].flags & SigQueue) != queue) + continue; + if(runtime·sigtab[i].flags & (SigCatch | SigQueue)) + fn = runtime·sighandler; + else + fn = runtime·sigignore; + sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0); + } + } +} + +void +runtime·resetcpuprofiler(int32 hz) +{ + Itimerval it; + + runtime·memclr((byte*)&it, sizeof it); + if(hz == 0) { + runtime·setitimer(ITIMER_PROF, &it, nil); + sigaction(SIGPROF, SIG_IGN, true); + } else { + sigaction(SIGPROF, runtime·sighandler, true); + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 1000000 / hz; + it.it_value = it.it_interval; + runtime·setitimer(ITIMER_PROF, &it, nil); + } + m->profilehz = hz; +} + +void +os·sigpipe(void) +{ + sigaction(SIGPIPE, SIG_DFL, false); + runtime·raisesigpipe(); +} diff --git a/src/pkg/runtime/plan9/386/signal.c b/src/pkg/runtime/signal_plan9_386.c index 364fd1c41..c0b759c71 100644 --- a/src/pkg/runtime/plan9/386/signal.c +++ b/src/pkg/runtime/signal_plan9_386.c @@ -4,11 +4,6 @@ #include "runtime.h" -void -runtime·gettime(int64*, int32*) -{ -} - String runtime·signame(int32) { diff --git a/src/pkg/runtime/windows/386/signal.c b/src/pkg/runtime/signal_windows_386.c index 9c912ede4..48d2a8bff 100644 --- a/src/pkg/runtime/windows/386/signal.c +++ b/src/pkg/runtime/signal_windows_386.c @@ -3,8 +3,8 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" void runtime·dumpregs(Context *r) @@ -31,12 +31,9 @@ runtime·initsig(int32) } uint32 -runtime·sighandler(ExceptionRecord *info, void *frame, Context *r) +runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) { uintptr *sp; - G *gp; - - USED(frame); switch(info->ExceptionCode) { case EXCEPTION_BREAKPOINT: @@ -44,7 +41,7 @@ runtime·sighandler(ExceptionRecord *info, void *frame, Context *r) return 1; } - if((gp = m->curg) != nil && runtime·issigpanic(info->ExceptionCode)) { + if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break diff --git a/src/pkg/runtime/windows/amd64/signal.c b/src/pkg/runtime/signal_windows_amd64.c index 97106c8b8..92cdb8054 100644 --- a/src/pkg/runtime/windows/amd64/signal.c +++ b/src/pkg/runtime/signal_windows_amd64.c @@ -3,8 +3,8 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" extern void *runtime·sigtramp; diff --git a/src/pkg/runtime/darwin/signals.h b/src/pkg/runtime/signals_darwin.h index 035027fad..035027fad 100644 --- a/src/pkg/runtime/darwin/signals.h +++ b/src/pkg/runtime/signals_darwin.h diff --git a/src/pkg/runtime/freebsd/signals.h b/src/pkg/runtime/signals_freebsd.h index 63a84671d..63a84671d 100644 --- a/src/pkg/runtime/freebsd/signals.h +++ b/src/pkg/runtime/signals_freebsd.h diff --git a/src/pkg/runtime/linux/signals.h b/src/pkg/runtime/signals_linux.h index 919b80ea2..1fc5f8c87 100644 --- a/src/pkg/runtime/linux/signals.h +++ b/src/pkg/runtime/signals_linux.h @@ -13,7 +13,7 @@ SigTab runtime·sigtab[] = { /* 1 */ Q+R, "SIGHUP: terminal line hangup", /* 2 */ Q+R, "SIGINT: interrupt", /* 3 */ C, "SIGQUIT: quit", - /* 4 */ C+P, "SIGILL: illegal instruction", + /* 4 */ C, "SIGILL: illegal instruction", /* 5 */ C, "SIGTRAP: trace trap", /* 6 */ C, "SIGABRT: abort", /* 7 */ C+P, "SIGBUS: bus error", diff --git a/src/pkg/runtime/openbsd/signals.h b/src/pkg/runtime/signals_netbsd.h index 63a84671d..63a84671d 100644 --- a/src/pkg/runtime/openbsd/signals.h +++ b/src/pkg/runtime/signals_netbsd.h diff --git a/src/pkg/runtime/signals_openbsd.h b/src/pkg/runtime/signals_openbsd.h new file mode 100644 index 000000000..63a84671d --- /dev/null +++ b/src/pkg/runtime/signals_openbsd.h @@ -0,0 +1,52 @@ +// 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. + +#define C SigCatch +#define I SigIgnore +#define R SigRestart +#define Q SigQueue +#define P SigPanic + +SigTab runtime·sigtab[] = { + /* 0 */ 0, "SIGNONE: no trap", + /* 1 */ Q+R, "SIGHUP: terminal line hangup", + /* 2 */ Q+R, "SIGINT: interrupt", + /* 3 */ C, "SIGQUIT: quit", + /* 4 */ C, "SIGILL: illegal instruction", + /* 5 */ C, "SIGTRAP: trace trap", + /* 6 */ C, "SIGABRT: abort", + /* 7 */ C, "SIGEMT: EMT instruction", + /* 8 */ C+P, "SIGFPE: floating-point exception", + /* 9 */ 0, "SIGKILL: kill", + /* 10 */ C+P, "SIGBUS: bus error", + /* 11 */ C+P, "SIGSEGV: segmentation violation", + /* 12 */ C, "SIGSYS: bad system call", + /* 13 */ I, "SIGPIPE: write to broken pipe", + /* 14 */ Q+I+R, "SIGALRM: alarm clock", + /* 15 */ Q+R, "SIGTERM: termination", + /* 16 */ Q+I+R, "SIGURG: urgent condition on socket", + /* 17 */ 0, "SIGSTOP: stop, unblockable", + /* 18 */ Q+I+R, "SIGTSTP: stop from tty", + /* 19 */ 0, "SIGCONT: continue", + /* 20 */ Q+I+R, "SIGCHLD: child status has changed", + /* 21 */ Q+I+R, "SIGTTIN: background read from tty", + /* 22 */ Q+I+R, "SIGTTOU: background write to tty", + /* 23 */ Q+I+R, "SIGIO: i/o now possible", + /* 24 */ Q+I+R, "SIGXCPU: cpu limit exceeded", + /* 25 */ Q+I+R, "SIGXFSZ: file size limit exceeded", + /* 26 */ Q+I+R, "SIGVTALRM: virtual alarm clock", + /* 27 */ Q+I+R, "SIGPROF: profiling alarm clock", + /* 28 */ Q+I+R, "SIGWINCH: window size change", + /* 29 */ Q+I+R, "SIGINFO: information request", + /* 30 */ Q+I+R, "SIGUSR1: user-defined signal 1", + /* 31 */ Q+I+R, "SIGUSR2: user-defined signal 2", + /* 32 */ Q+I+R, "SIGTHR: reserved", +}; +#undef C +#undef I +#undef R +#undef Q +#undef P + +#define NSIG 33 diff --git a/src/pkg/runtime/plan9/signals.h b/src/pkg/runtime/signals_plan9.h index 5df757613..5df757613 100644 --- a/src/pkg/runtime/plan9/signals.h +++ b/src/pkg/runtime/signals_plan9.h diff --git a/src/pkg/runtime/windows/signals.h b/src/pkg/runtime/signals_windows.h index 6943714b0..6943714b0 100644 --- a/src/pkg/runtime/windows/signals.h +++ b/src/pkg/runtime/signals_windows.h diff --git a/src/pkg/runtime/sigqueue.goc b/src/pkg/runtime/sigqueue.goc index 504590a54..3c12e5caf 100644 --- a/src/pkg/runtime/sigqueue.goc +++ b/src/pkg/runtime/sigqueue.goc @@ -38,7 +38,7 @@ package runtime #include "runtime.h" -#include "defs.h" +#include "defs_GOOS_GOARCH.h" static struct { Note; diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.c index 70534279b..e5726c93b 100644 --- a/src/pkg/runtime/slice.c +++ b/src/pkg/runtime/slice.c @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "arch_GOARCH.h" #include "type.h" #include "malloc.h" @@ -10,8 +11,7 @@ static int32 debug = 0; static void makeslice1(SliceType*, int32, int32, Slice*); static void growslice1(SliceType*, Slice, int32, Slice *); -static void appendslice1(SliceType*, Slice, Slice, Slice*); - void runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret); + void runtime·copy(Slice to, Slice fm, uintptr width, int32 ret); // see also unsafe·NewArray // makeslice(typ *Type, len, cap int64) (ary []any); @@ -28,13 +28,18 @@ runtime·makeslice(SliceType *t, int64 len, int64 cap, Slice ret) if(debug) { runtime·printf("makeslice(%S, %D, %D); ret=", *t->string, len, cap); - runtime·printslice(ret); + runtime·printslice(ret); } } +// Dummy word to use as base pointer for make([]T, 0). +// Since you cannot take the address of such a slice, +// you can't tell that they all have the same base pointer. +static uintptr zerobase; + static void makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret) -{ +{ uintptr size; size = cap*t->elem->size; @@ -42,7 +47,9 @@ makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret) ret->len = len; ret->cap = cap; - if((t->elem->kind&KindNoPointers)) + if(cap == 0) + ret->array = (byte*)&zerobase; + else if((t->elem->kind&KindNoPointers)) ret->array = runtime·mallocgc(size, FlagNoPointers, 1, 1); else ret->array = runtime·mal(size); @@ -52,14 +59,31 @@ makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret) void runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret) { - appendslice1(t, x, y, &ret); + int32 m; + uintptr w; + + m = x.len+y.len; + + if(m < x.len) + runtime·throw("append: slice overflow"); + + if(m > x.cap) + growslice1(t, x, m, &ret); + else + ret = x; + + w = t->elem->size; + runtime·memmove(ret.array + ret.len*w, y.array, y.len*w); + ret.len += y.len; + FLUSH(&ret); } -static void -appendslice1(SliceType *t, Slice x, Slice y, Slice *ret) + +// appendstr([]byte, string) []byte +void +runtime·appendstr(SliceType *t, Slice x, String y, Slice ret) { int32 m; - uintptr w; m = x.len+y.len; @@ -67,15 +91,16 @@ appendslice1(SliceType *t, Slice x, Slice y, Slice *ret) runtime·throw("append: slice overflow"); if(m > x.cap) - growslice1(t, x, m, ret); + growslice1(t, x, m, &ret); else - *ret = x; + ret = x; - w = t->elem->size; - runtime·memmove(ret->array + ret->len*w, y.array, y.len*w); - ret->len += y.len; + runtime·memmove(ret.array + ret.len, y.str, y.len); + ret.len += y.len; + FLUSH(&ret); } + // growslice(type *Type, x, []T, n int64) []T void runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret) @@ -96,9 +121,9 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret) if(debug) { runtime·printf("growslice(%S,", *t->string); - runtime·printslice(old); + runtime·printslice(old); runtime·printf(", new cap=%D) =", cap); - runtime·printslice(ret); + runtime·printslice(ret); } } @@ -265,9 +290,9 @@ runtime·slicearray(byte* old, uint64 nel, uint64 lb, uint64 hb, uint64 width, S } } -// slicecopy(to any, fr any, wid uint32) int +// copy(to any, fr any, wid uint32) int void -runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret) +runtime·copy(Slice to, Slice fm, uintptr width, int32 ret) { if(fm.len == 0 || to.len == 0 || width == 0) { ret = 0; @@ -307,11 +332,11 @@ runtime·slicestringcopy(Slice to, String fm, int32 ret) ret = 0; goto out; } - + ret = fm.len; if(to.len < ret) ret = to.len; - + runtime·memmove(to.array, fm.str, ret); out: diff --git a/src/pkg/runtime/softfloat64_test.go b/src/pkg/runtime/softfloat64_test.go index fb7f3d3c0..df63010fb 100644 --- a/src/pkg/runtime/softfloat64_test.go +++ b/src/pkg/runtime/softfloat64_test.go @@ -6,7 +6,7 @@ package runtime_test import ( "math" - "rand" + "math/rand" . "runtime" "testing" ) diff --git a/src/pkg/runtime/arm/softfloat.c b/src/pkg/runtime/softfloat_arm.c index 0a071dada..fbe0b0413 100644 --- a/src/pkg/runtime/arm/softfloat.c +++ b/src/pkg/runtime/softfloat_arm.c @@ -15,7 +15,7 @@ #define FLAGS_V (1 << 28) void runtime·abort(void); -void math·sqrtGoC(uint64, uint64*); +void math·sqrtC(uint64, uint64*); static uint32 trace = 0; @@ -359,7 +359,7 @@ stage3: // regd, regm are 4bit variables break; case 0xeeb10bc0: // D[regd] = sqrt D[regm] - math·sqrtGoC(getd(regm), &uval); + math·sqrtC(getd(regm), &uval); putd(regd, uval); if(trace) diff --git a/src/pkg/runtime/stack.h b/src/pkg/runtime/stack.h index 483233876..f56dac120 100644 --- a/src/pkg/runtime/stack.h +++ b/src/pkg/runtime/stack.h @@ -57,7 +57,7 @@ enum { // to each stack below the usual guard area for OS-specific // purposes like signal handling. Used on Windows because // it does not use a separate stack. -#ifdef __WINDOWS__ +#ifdef GOOS_windows StackSystem = 512 * sizeof(uintptr), #else StackSystem = 0, diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc index 322706c0c..7e1f8a1e8 100644 --- a/src/pkg/runtime/string.goc +++ b/src/pkg/runtime/string.goc @@ -4,6 +4,7 @@ package runtime #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" String runtime·emptystring; @@ -34,16 +35,18 @@ runtime·findnullw(uint16 *s) uint32 runtime·maxstring = 256; -String -runtime·gostringsize(int32 l) +static String +gostringsize(int32 l) { String s; uint32 ms; if(l == 0) return runtime·emptystring; - s.str = runtime·mal(l+1); // leave room for NUL for C runtime (e.g., callers of getenv) + // leave room for NUL for C runtime (e.g., callers of getenv) + s.str = runtime·mallocgc(l+1, FlagNoPointers, 1, 0); s.len = l; + s.str[l] = 0; for(;;) { ms = runtime·maxstring; if((uint32)l <= ms || runtime·cas(&runtime·maxstring, ms, (uint32)l)) @@ -59,7 +62,7 @@ runtime·gostring(byte *str) String s; l = runtime·findnull(str); - s = runtime·gostringsize(l); + s = gostringsize(l); runtime·memmove(s.str, str, l); return s; } @@ -69,7 +72,7 @@ runtime·gostringn(byte *str, int32 l) { String s; - s = runtime·gostringsize(l); + s = gostringsize(l); runtime·memmove(s.str, str, l); return s; } @@ -99,18 +102,23 @@ runtime·gostringnocopy(byte *str) String runtime·gostringw(uint16 *str) { - int32 n, i; + int32 n1, n2, i; byte buf[8]; String s; - n = 0; - for(i=0; str[i]; i++) - n += runtime·runetochar(buf, str[i]); - s = runtime·gostringsize(n+4); - n = 0; + n1 = 0; for(i=0; str[i]; i++) - n += runtime·runetochar(s.str+n, str[i]); - s.len = n; + n1 += runtime·runetochar(buf, str[i]); + s = gostringsize(n1+4); + n2 = 0; + for(i=0; str[i]; i++) { + // check for race + if(n2 >= n1) + break; + n2 += runtime·runetochar(s.str+n2, str[i]); + } + s.len = n2; + s.str[s.len] = 0; return s; } @@ -124,7 +132,7 @@ runtime·catstring(String s1, String s2) if(s2.len == 0) return s1; - s3 = runtime·gostringsize(s1.len + s2.len); + s3 = gostringsize(s1.len + s2.len); runtime·memmove(s3.str, s1.str, s1.len); runtime·memmove(s3.str+s1.len, s2.str, s2.len); return s3; @@ -143,7 +151,7 @@ concatstring(int32 n, String *s) l += s[i].len; } - out = runtime·gostringsize(l); + out = gostringsize(l); l = 0; for(i=0; i<n; i++) { runtime·memmove(out.str+l, s[i].str, s[i].len); @@ -253,23 +261,24 @@ func slicestring1(si String, lindex int32) (so String) { } func intstring(v int64) (s String) { - s = runtime·gostringsize(8); + s = gostringsize(8); s.len = runtime·runetochar(s.str, v); + s.str[s.len] = 0; } func slicebytetostring(b Slice) (s String) { - s = runtime·gostringsize(b.len); + s = gostringsize(b.len); runtime·memmove(s.str, b.array, s.len); } func stringtoslicebyte(s String) (b Slice) { - b.array = runtime·mallocgc(s.len, FlagNoPointers, 1, 1); + b.array = runtime·mallocgc(s.len, FlagNoPointers, 1, 0); b.len = s.len; b.cap = s.len; runtime·memmove(b.array, s.str, s.len); } -func sliceinttostring(b Slice) (s String) { +func slicerunetostring(b Slice) (s String) { int32 siz1, siz2, i; int32 *a; byte dum[8]; @@ -280,7 +289,7 @@ func sliceinttostring(b Slice) (s String) { siz1 += runtime·runetochar(dum, a[i]); } - s = runtime·gostringsize(siz1+4); + s = gostringsize(siz1+4); siz2 = 0; for(i=0; i<b.len; i++) { // check for race @@ -289,15 +298,16 @@ func sliceinttostring(b Slice) (s String) { siz2 += runtime·runetochar(s.str+siz2, a[i]); } s.len = siz2; + s.str[s.len] = 0; } -func stringtosliceint(s String) (b Slice) { +func stringtoslicerune(s String) (b Slice) { int32 n; int32 dum, *r; uint8 *p, *ep; // two passes. - // unlike sliceinttostring, no race because strings are immutable. + // unlike slicerunetostring, no race because strings are immutable. p = s.str; ep = s.str+s.len; n = 0; @@ -306,7 +316,7 @@ func stringtosliceint(s String) (b Slice) { n++; } - b.array = runtime·mallocgc(n*sizeof(r[0]), FlagNoPointers, 1, 1); + b.array = runtime·mallocgc(n*sizeof(r[0]), FlagNoPointers, 1, 0); b.len = n; b.cap = n; p = s.str; diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c index d0468c6dd..0346a420b 100644 --- a/src/pkg/runtime/symtab.c +++ b/src/pkg/runtime/symtab.c @@ -13,9 +13,9 @@ // and figure out exactly what we want. #include "runtime.h" -#include "defs.h" -#include "os.h" -#include "arch.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "arch_GOARCH.h" extern byte pclntab[], epclntab[], symtab[], esymtab[]; @@ -381,6 +381,15 @@ runtime·funcline(Func *f, uintptr targetpc) return line; } +void +runtime·funcline_go(Func *f, uintptr targetpc, String retfile, int32 retline) +{ + retfile = f->src; + retline = runtime·funcline(f, targetpc); + FLUSH(&retfile); + FLUSH(&retline); +} + static void buildfuncs(void) { diff --git a/src/pkg/runtime/darwin/386/sys.s b/src/pkg/runtime/sys_darwin_386.s index 87fbdbb79..24eac766a 100644 --- a/src/pkg/runtime/darwin/386/sys.s +++ b/src/pkg/runtime/sys_darwin_386.s @@ -6,7 +6,7 @@ // See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228 // or /usr/include/sys/syscall.h (on a Mac) for system call numbers. -#include "386/asm.h" +#include "zasm_GOOS_GOARCH.h" TEXT runtime·notok(SB),7,$0 MOVL $0xf1, 0xf1 @@ -48,6 +48,13 @@ TEXT runtime·mmap(SB),7,$0 INT $0x80 RET +TEXT runtime·madvise(SB),7,$0 + MOVL $75, AX + INT $0x80 + JAE 2(PC) + CALL runtime·notok(SB) + RET + TEXT runtime·munmap(SB),7,$0 MOVL $73, AX INT $0x80 @@ -60,20 +67,43 @@ TEXT runtime·setitimer(SB),7,$0 INT $0x80 RET -// void gettime(int64 *sec, int32 *usec) -TEXT runtime·gettime(SB), 7, $32 +// func now() (sec int64, nsec int32) +TEXT time·now(SB), 7, $32 LEAL 12(SP), AX // must be non-nil, unused MOVL AX, 4(SP) MOVL $0, 8(SP) // time zone pointer MOVL $116, AX INT $0x80 + MOVL DX, BX - MOVL sec+0(FP), DI - MOVL AX, (DI) - MOVL $0, 4(DI) // zero extend 32 -> 64 + // sec is in AX, usec in BX + MOVL AX, sec+0(FP) + MOVL $0, sec+4(FP) + IMULL $1000, BX + MOVL BX, nsec+8(FP) + RET - MOVL usec+4(FP), DI - MOVL DX, (DI) +// int64 nanotime(void) so really +// void nanotime(int64 *nsec) +TEXT runtime·nanotime(SB), 7, $32 + LEAL 12(SP), AX // must be non-nil, unused + MOVL AX, 4(SP) + MOVL $0, 8(SP) // time zone pointer + MOVL $116, AX + INT $0x80 + MOVL DX, BX + + // sec is in AX, usec in BX + // convert to DX:AX nsec + MOVL $1000000000, CX + MULL CX + IMULL $1000, BX + ADDL BX, AX + ADCL $0, DX + + MOVL ret+0(FP), DI + MOVL AX, 0(DI) + MOVL DX, 4(DI) RET TEXT runtime·sigaction(SB),7,$0 @@ -97,7 +127,7 @@ TEXT runtime·sigtramp(SB),7,$40 // save g MOVL g(CX), DI MOVL DI, 20(SP) - + // g = m->gsignal MOVL m(CX), BP MOVL m_gsignal(BP), BP @@ -111,7 +141,7 @@ TEXT runtime·sigtramp(SB),7,$40 MOVL context+16(FP), BX MOVL BX, 8(SP) MOVL DI, 12(SP) - + MOVL handler+0(FP), BX CALL BX @@ -138,6 +168,26 @@ TEXT runtime·sigaltstack(SB),7,$0 CALL runtime·notok(SB) RET +TEXT runtime·usleep(SB),7,$32 + MOVL $0, DX + MOVL usec+0(FP), AX + MOVL $1000000, CX + DIVL CX + MOVL AX, 24(SP) // sec + MOVL DX, 28(SP) // usec + + // select(0, 0, 0, 0, &tv) + MOVL $0, 0(SP) // "return PC" - ignored + MOVL $0, 4(SP) + MOVL $0, 8(SP) + MOVL $0, 12(SP) + MOVL $0, 16(SP) + LEAL 24(SP), AX + MOVL AX, 20(SP) + MOVL $93, AX + INT $0x80 + RET + // void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void)) // System call args are: func arg stack pthread flags. TEXT runtime·bsdthread_create(SB),7,$32 @@ -288,7 +338,7 @@ TEXT runtime·setldt(SB),7,$32 * To accommodate that rewrite, we translate the * address and limit here so that 0x468(GS) maps to 0(address). * - * See ../../../../libcgo/darwin_386.c for the derivation + * See cgo/gcc_darwin_386.c:/468 for the derivation * of the constant. */ SUBL $0x468, BX @@ -309,3 +359,12 @@ TEXT runtime·setldt(SB),7,$32 XORL AX, AX MOVW GS, AX RET + +TEXT runtime·sysctl(SB),7,$0 + MOVL $202, AX + INT $0x80 + JAE 3(PC) + NEGL AX + RET + MOVL $0, AX + RET diff --git a/src/pkg/runtime/darwin/amd64/sys.s b/src/pkg/runtime/sys_darwin_amd64.s index 8d1b20f11..9d2ecbe2a 100644 --- a/src/pkg/runtime/darwin/amd64/sys.s +++ b/src/pkg/runtime/sys_darwin_amd64.s @@ -11,7 +11,7 @@ // The high 8 bits specify the kind of system call: 1=Mach, 2=BSD, 3=Machine-Dependent. // -#include "amd64/asm.h" +#include "zasm_GOOS_GOARCH.h" // Exit the entire program (like C exit) TEXT runtime·exit(SB),7,$0 @@ -55,16 +55,41 @@ TEXT runtime·setitimer(SB), 7, $0 SYSCALL RET -// void gettime(int64 *sec, int32 *usec) -TEXT runtime·gettime(SB), 7, $32 +TEXT runtime·madvise(SB), 7, $0 + MOVQ 8(SP), DI // arg 1 addr + MOVQ 16(SP), SI // arg 2 len + MOVL 24(SP), DX // arg 3 advice + MOVL $(0x2000000+75), AX // syscall entry madvise + SYSCALL + JCC 2(PC) + CALL runtime·notok(SB) + RET + +// func now() (sec int64, nsec int32) +TEXT time·now(SB), 7, $32 + MOVQ SP, DI // must be non-nil, unused + MOVQ $0, SI + MOVL $(0x2000000+116), AX + SYSCALL + + // sec is in AX, usec in DX + MOVQ AX, sec+0(FP) + IMULQ $1000, DX + MOVL DX, nsec+8(FP) + RET + +// int64 nanotime(void) +TEXT runtime·nanotime(SB), 7, $32 MOVQ SP, DI // must be non-nil, unused MOVQ $0, SI MOVL $(0x2000000+116), AX SYSCALL - MOVQ sec+0(FP), DI - MOVQ AX, (DI) - MOVQ usec+8(FP), DI - MOVL DX, (DI) + + // sec is in AX, usec in DX + // return nsec in AX + IMULQ $1000000000, AX + IMULQ $1000, DX + ADDQ DX, AX RET TEXT runtime·sigaction(SB),7,$0 @@ -81,11 +106,11 @@ TEXT runtime·sigaction(SB),7,$0 TEXT runtime·sigtramp(SB),7,$64 get_tls(BX) - + // save g MOVQ g(BX), R10 MOVQ R10, 48(SP) - + // g = m->gsignal MOVQ m(BX), BP MOVQ m_gsignal(BP), BP @@ -146,6 +171,24 @@ TEXT runtime·sigaltstack(SB),7,$0 CALL runtime·notok(SB) RET +TEXT runtime·usleep(SB),7,$16 + MOVL $0, DX + MOVL usec+0(FP), AX + MOVL $1000000, CX + DIVL CX + MOVQ AX, 0(SP) // sec + MOVL DX, 8(SP) // usec + + // select(0, 0, 0, 0, &tv) + MOVL $0, DI + MOVL $0, SI + MOVL $0, DX + MOVL $0, R10 + MOVQ SP, R8 + MOVL $(0x2000000+93), AX + SYSCALL + RET + // void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void)) TEXT runtime·bsdthread_create(SB),7,$0 // Set up arguments to bsdthread_create system call. @@ -189,7 +232,7 @@ TEXT runtime·bsdthread_start(SB),7,$0 POPQ SI POPQ CX POPQ DX - + get_tls(BX) MOVQ CX, m(BX) MOVQ SI, m_procid(CX) // thread port is m->procid @@ -284,8 +327,8 @@ TEXT runtime·mach_semaphore_signal_all(SB),7,$0 // set tls base to DI TEXT runtime·settls(SB),7,$32 /* - * Same as in ../386/sys.s:/ugliness, different constant. - * See ../../../../libcgo/darwin_amd64.c for the derivation + * Same as in sys_darwin_386.s:/ugliness, different constant. + * See cgo/gcc_darwin_amd64.c for the derivation * of the constant. */ SUBQ $0x8a0, DI @@ -293,3 +336,18 @@ TEXT runtime·settls(SB),7,$32 MOVL $(0x3000000+3), AX // thread_fast_set_cthread_self - machdep call #3 SYSCALL RET + +TEXT runtime·sysctl(SB),7,$0 + MOVQ 8(SP), DI + MOVL 16(SP), SI + MOVQ 24(SP), DX + MOVQ 32(SP), R10 + MOVQ 40(SP), R8 + MOVQ 48(SP), R9 + MOVL $(0x2000000+202), AX // syscall entry + SYSCALL + JCC 3(PC) + NEGL AX + RET + MOVL $0, AX + RET diff --git a/src/pkg/runtime/freebsd/386/sys.s b/src/pkg/runtime/sys_freebsd_386.s index 765e2fcc4..d8dc40d8f 100644 --- a/src/pkg/runtime/freebsd/386/sys.s +++ b/src/pkg/runtime/sys_freebsd_386.s @@ -6,7 +6,7 @@ // /usr/src/sys/kern/syscalls.master for syscall numbers. // -#include "386/asm.h" +#include "zasm_GOOS_GOARCH.h" TEXT runtime·sys_umtx_op(SB),7,$-4 MOVL $454, AX @@ -106,23 +106,48 @@ TEXT runtime·setitimer(SB), 7, $-4 INT $0x80 RET -TEXT runtime·gettime(SB), 7, $32 +// func now() (sec int64, nsec int32) +TEXT time·now(SB), 7, $32 MOVL $116, AX LEAL 12(SP), BX MOVL BX, 4(SP) MOVL $0, 8(SP) INT $0x80 + MOVL 12(SP), AX // sec + MOVL 16(SP), BX // usec - MOVL 12(SP), BX // sec - MOVL sec+0(FP), DI - MOVL BX, (DI) - MOVL $0, 4(DI) // zero extend 32 -> 64 bits + // sec is in AX, usec in BX + MOVL AX, sec+0(FP) + MOVL $0, sec+4(FP) + IMULL $1000, BX + MOVL BX, nsec+8(FP) + RET +// int64 nanotime(void) so really +// void nanotime(int64 *nsec) +TEXT runtime·nanotime(SB), 7, $32 + MOVL $116, AX + LEAL 12(SP), BX + MOVL BX, 4(SP) + MOVL $0, 8(SP) + INT $0x80 + MOVL 12(SP), AX // sec MOVL 16(SP), BX // usec - MOVL usec+4(FP), DI - MOVL BX, (DI) + + // sec is in AX, usec in BX + // convert to DX:AX nsec + MOVL $1000000000, CX + MULL CX + IMULL $1000, BX + ADDL BX, AX + ADCL $0, DX + + MOVL ret+0(FP), DI + MOVL AX, 0(DI) + MOVL DX, 4(DI) RET + TEXT runtime·sigaction(SB),7,$-4 MOVL $416, AX INT $0x80 @@ -174,6 +199,26 @@ TEXT runtime·sigaltstack(SB),7,$0 CALL runtime·notok(SB) RET +TEXT runtime·usleep(SB),7,$20 + MOVL $0, DX + MOVL usec+0(FP), AX + MOVL $1000000, CX + DIVL CX + MOVL AX, 12(SP) // tv_sec + MOVL $1000, AX + MULL DX + MOVL AX, 16(SP) // tv_nsec + + MOVL $0, 0(SP) + LEAL 12(SP), AX + MOVL AX, 4(SP) // arg 1 - rqtp + MOVL $0, 8(SP) // arg 2 - rmtp + MOVL $240, AX // sys_nanosleep + INT $0x80 + JAE 2(PC) + CALL runtime·notok(SB) + RET + /* descriptor entry format for system call is the native machine format, ugly as it is: @@ -193,7 +238,7 @@ int i386_set_ldt(int, const union ldt_entry *, int); // setldt(int entry, int address, int limit) TEXT runtime·setldt(SB),7,$32 MOVL address+4(FP), BX // aka base - // see comment in linux/386/sys.s; freebsd is similar + // see comment in sys_linux_386.s; freebsd is similar ADDL $0x8, BX // set up data_desc @@ -236,4 +281,23 @@ TEXT runtime·i386_set_ldt(SB),7,$16 INT $3 RET +TEXT runtime·sysctl(SB),7,$28 + LEAL arg0+0(FP), SI + LEAL 4(SP), DI + CLD + MOVSL // arg 1 - name + MOVSL // arg 2 - namelen + MOVSL // arg 3 - oldp + MOVSL // arg 4 - oldlenp + MOVSL // arg 5 - newp + MOVSL // arg 6 - newlen + MOVL $202, AX // sys___sysctl + INT $0x80 + JCC 3(PC) + NEGL AX + RET + MOVL $0, AX + RET + + GLOBL runtime·tlsoffset(SB),$4 diff --git a/src/pkg/runtime/freebsd/amd64/sys.s b/src/pkg/runtime/sys_freebsd_amd64.s index c5cc082e4..dcd55855a 100644 --- a/src/pkg/runtime/freebsd/amd64/sys.s +++ b/src/pkg/runtime/sys_freebsd_amd64.s @@ -6,7 +6,7 @@ // /usr/src/sys/kern/syscalls.master for syscall numbers. // -#include "amd64/asm.h" +#include "zasm_GOOS_GOARCH.h" TEXT runtime·sys_umtx_op(SB),7,$0 MOVQ 8(SP), DI @@ -85,19 +85,34 @@ TEXT runtime·setitimer(SB), 7, $-8 SYSCALL RET -TEXT runtime·gettime(SB), 7, $32 +// func now() (sec int64, nsec int32) +TEXT time·now(SB), 7, $32 MOVL $116, AX LEAQ 8(SP), DI MOVQ $0, SI SYSCALL + MOVQ 8(SP), AX // sec + MOVL 16(SP), DX // usec - MOVQ 8(SP), BX // sec - MOVQ sec+0(FP), DI - MOVQ BX, (DI) + // sec is in AX, usec in DX + MOVQ AX, sec+0(FP) + IMULQ $1000, DX + MOVL DX, nsec+8(FP) + RET - MOVL 16(SP), BX // usec - MOVQ usec+8(FP), DI - MOVL BX, (DI) +TEXT runtime·nanotime(SB), 7, $32 + MOVL $116, AX + LEAQ 8(SP), DI + MOVQ $0, SI + SYSCALL + MOVQ 8(SP), AX // sec + MOVL 16(SP), DX // usec + + // sec is in AX, usec in DX + // return nsec in AX + IMULQ $1000000000, AX + IMULQ $1000, DX + ADDQ DX, AX RET TEXT runtime·sigaction(SB),7,$-8 @@ -169,6 +184,24 @@ TEXT runtime·sigaltstack(SB),7,$-8 CALL runtime·notok(SB) RET +TEXT runtime·usleep(SB),7,$16 + MOVL $0, DX + MOVL usec+0(FP), AX + MOVL $1000000, CX + DIVL CX + MOVQ AX, 0(SP) // tv_sec + MOVL $1000, AX + MULL DX + MOVQ AX, 8(SP) // tv_nsec + + MOVQ SP, DI // arg 1 - rqtp + MOVQ $0, SI // arg 2 - rmtp + MOVL $240, AX // sys_nanosleep + SYSCALL + JCC 2(PC) + CALL runtime·notok(SB) + RET + // set tls base to DI TEXT runtime·settls(SB),7,$8 ADDQ $16, DI // adjust for ELF: wants to use -16(FS) and -8(FS) for g and m @@ -180,3 +213,19 @@ TEXT runtime·settls(SB),7,$8 JCC 2(PC) CALL runtime·notok(SB) RET + +TEXT runtime·sysctl(SB),7,$0 + MOVQ 8(SP), DI // arg 1 - name + MOVL 16(SP), SI // arg 2 - namelen + MOVQ 24(SP), DX // arg 3 - oldp + MOVQ 32(SP), R10 // arg 4 - oldlenp + MOVQ 40(SP), R8 // arg 5 - newp + MOVQ 48(SP), R9 // arg 6 - newlen + MOVQ $202, AX // sys___sysctl + SYSCALL + JCC 3(PC) + NEGL AX + RET + MOVL $0, AX + RET + diff --git a/src/pkg/runtime/linux/386/sys.s b/src/pkg/runtime/sys_linux_386.s index f87420f78..b745bc502 100644 --- a/src/pkg/runtime/linux/386/sys.s +++ b/src/pkg/runtime/sys_linux_386.s @@ -6,7 +6,7 @@ // System calls and other sys.stuff for 386, Linux // -#include "386/asm.h" +#include "zasm_GOOS_GOARCH.h" TEXT runtime·exit(SB),7,$0 MOVL $252, AX // syscall number @@ -52,6 +52,24 @@ TEXT runtime·read(SB),7,$0 CALL *runtime·_vdso(SB) RET +TEXT runtime·usleep(SB),7,$8 + MOVL $0, DX + MOVL usec+0(FP), AX + MOVL $1000000, CX + DIVL CX + MOVL AX, 0(SP) + MOVL DX, 4(SP) + + // select(0, 0, 0, 0, &tv) + MOVL $142, AX + MOVL $0, BX + MOVL $0, CX + MOVL $0, DX + MOVL $0, SI + LEAL 0(SP), DI + CALL *runtime·_vdso(SB) + RET + TEXT runtime·raisesigpipe(SB),7,$12 MOVL $224, AX // syscall - gettid CALL *runtime·_vdso(SB) @@ -77,21 +95,45 @@ TEXT runtime·mincore(SB),7,$0-24 CALL *runtime·_vdso(SB) RET -TEXT runtime·gettime(SB), 7, $32 +// func now() (sec int64, nsec int32) +TEXT time·now(SB), 7, $32 MOVL $78, AX // syscall - gettimeofday LEAL 8(SP), BX MOVL $0, CX MOVL $0, DX CALL *runtime·_vdso(SB) + MOVL 8(SP), AX // sec + MOVL 12(SP), BX // usec - MOVL 8(SP), BX // sec - MOVL sec+0(FP), DI - MOVL BX, (DI) - MOVL $0, 4(DI) // zero extend 32 -> 64 bits + // sec is in AX, usec in BX + MOVL AX, sec+0(FP) + MOVL $0, sec+4(FP) + IMULL $1000, BX + MOVL BX, nsec+8(FP) + RET +// int64 nanotime(void) so really +// void nanotime(int64 *nsec) +TEXT runtime·nanotime(SB), 7, $32 + MOVL $78, AX // syscall - gettimeofday + LEAL 8(SP), BX + MOVL $0, CX + MOVL $0, DX + CALL *runtime·_vdso(SB) + MOVL 8(SP), AX // sec MOVL 12(SP), BX // usec - MOVL usec+4(FP), DI - MOVL BX, (DI) + + // sec is in AX, usec in BX + // convert to DX:AX nsec + MOVL $1000000000, CX + MULL CX + IMULL $1000, BX + ADDL BX, AX + ADCL $0, DX + + MOVL ret+0(FP), DI + MOVL AX, 0(DI) + MOVL DX, 4(DI) RET TEXT runtime·rt_sigaction(SB),7,$0 @@ -105,16 +147,16 @@ TEXT runtime·rt_sigaction(SB),7,$0 TEXT runtime·sigtramp(SB),7,$44 get_tls(CX) - + // save g MOVL g(CX), DI MOVL DI, 20(SP) - + // g = m->gsignal MOVL m(CX), BX MOVL m_gsignal(BX), BX MOVL BX, g(CX) - + // copy arguments for call to sighandler MOVL sig+0(FP), BX MOVL BX, 0(SP) @@ -125,12 +167,12 @@ TEXT runtime·sigtramp(SB),7,$44 MOVL DI, 12(SP) CALL runtime·sighandler(SB) - + // restore g get_tls(CX) MOVL 20(SP), BX MOVL BX, g(CX) - + RET TEXT runtime·sigignore(SB),7,$0 @@ -170,6 +212,17 @@ TEXT runtime·munmap(SB),7,$0 INT $3 RET +TEXT runtime·madvise(SB),7,$0 + MOVL $219, AX // madvise + MOVL 4(SP), BX + MOVL 8(SP), CX + MOVL 12(SP), DX + CALL *runtime·_vdso(SB) + CMPL AX, $0xfffff001 + JLS 2(PC) + INT $3 + RET + // int32 futex(int32 *uaddr, int32 op, int32 val, // struct timespec *timeout, int32 *uaddr2, int32 val2); TEXT runtime·futex(SB),7,$0 @@ -202,7 +255,7 @@ TEXT runtime·clone(SB),7,$0 MOVL $1234, 12(CX) // cannot use CALL *runtime·_vdso(SB) here, because - // the stack changes during the system call (after + // the stack changes during the system call (after // CALL *runtime·_vdso(SB), the child is still using // the parent's stack when executing its RET instruction). INT $0x80 diff --git a/src/pkg/runtime/linux/amd64/sys.s b/src/pkg/runtime/sys_linux_amd64.s index 8b4dcd921..ef7bb2864 100644 --- a/src/pkg/runtime/linux/amd64/sys.s +++ b/src/pkg/runtime/sys_linux_amd64.s @@ -6,7 +6,7 @@ // System calls and other sys.stuff for AMD64, Linux // -#include "amd64/asm.h" +#include "zasm_GOOS_GOARCH.h" TEXT runtime·exit(SB),7,$0-8 MOVL 8(SP), DI @@ -50,6 +50,24 @@ TEXT runtime·read(SB),7,$0-24 SYSCALL RET +TEXT runtime·usleep(SB),7,$16 + MOVL $0, DX + MOVL usec+0(FP), AX + MOVL $1000000, CX + DIVL CX + MOVQ AX, 0(SP) + MOVQ DX, 8(SP) + + // select(0, 0, 0, 0, &tv) + MOVL $0, DI + MOVL $0, SI + MOVL $0, DX + MOVL $0, R10 + MOVQ SP, R8 + MOVL $23, AX + SYSCALL + RET + TEXT runtime·raisesigpipe(SB),7,$12 MOVL $186, AX // syscall - gettid SYSCALL @@ -75,19 +93,34 @@ TEXT runtime·mincore(SB),7,$0-24 SYSCALL RET -TEXT runtime·gettime(SB), 7, $32 +// func now() (sec int64, nsec int32) +TEXT time·now(SB), 7, $32 LEAQ 8(SP), DI MOVQ $0, SI MOVQ $0xffffffffff600000, AX CALL AX + MOVQ 8(SP), AX // sec + MOVL 16(SP), DX // usec - MOVQ 8(SP), BX // sec - MOVQ sec+0(FP), DI - MOVQ BX, (DI) + // sec is in AX, usec in DX + MOVQ AX, sec+0(FP) + IMULQ $1000, DX + MOVL DX, nsec+8(FP) + RET - MOVL 16(SP), BX // usec - MOVQ usec+8(FP), DI - MOVL BX, (DI) +TEXT runtime·nanotime(SB), 7, $32 + LEAQ 8(SP), DI + MOVQ $0, SI + MOVQ $0xffffffffff600000, AX + CALL AX + MOVQ 8(SP), AX // sec + MOVL 16(SP), DX // usec + + // sec is in AX, usec in DX + // return nsec in AX + IMULQ $1000000000, AX + IMULQ $1000, DX + ADDQ DX, AX RET TEXT runtime·rt_sigaction(SB),7,$0-32 @@ -159,6 +192,17 @@ TEXT runtime·munmap(SB),7,$0 CALL runtime·notok(SB) RET +TEXT runtime·madvise(SB),7,$0 + MOVQ 8(SP), DI + MOVQ 16(SP), SI + MOVQ 24(SP), DX + MOVQ $28, AX // madvise + SYSCALL + CMPQ AX, $0xfffffffffffff001 + JLS 2(PC) + CALL runtime·notok(SB) + RET + TEXT runtime·notok(SB),7,$0 MOVQ $0xf1, BP MOVQ BP, (BP) @@ -195,10 +239,10 @@ TEXT runtime·clone(SB),7,$0 CMPQ AX, $0 JEQ 2(PC) RET - + // In child, on new stack. MOVQ SI, SP - + // Initialize m->procid to Linux tid MOVL $186, AX // gettid SYSCALL diff --git a/src/pkg/runtime/linux/arm/sys.s b/src/pkg/runtime/sys_linux_arm.s index 8619f0945..c3a828a92 100644 --- a/src/pkg/runtime/linux/arm/sys.s +++ b/src/pkg/runtime/sys_linux_arm.s @@ -6,7 +6,7 @@ // System calls and other sys.stuff for arm, Linux // -#include "arm/asm.h" +#include "zasm_GOOS_GOARCH.h" // OABI //#define SYS_BASE 0x00900000 @@ -28,11 +28,13 @@ #define SYS_futex (SYS_BASE + 240) #define SYS_exit_group (SYS_BASE + 248) #define SYS_munmap (SYS_BASE + 91) +#define SYS_madvise (SYS_BASE + 220) #define SYS_setitimer (SYS_BASE + 104) #define SYS_mincore (SYS_BASE + 219) #define SYS_gettid (SYS_BASE + 224) #define SYS_tkill (SYS_BASE + 238) #define SYS_sched_yield (SYS_BASE + 158) +#define SYS_select (SYS_BASE + 142) // newselect #define ARM_BASE (SYS_BASE + 0x0f0000) #define SYS_ARM_cacheflush (ARM_BASE + 2) @@ -110,6 +112,14 @@ TEXT runtime·munmap(SB),7,$0 SWI $0 RET +TEXT runtime·madvise(SB),7,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW $SYS_madvise, R7 + SWI $0 + RET + TEXT runtime·setitimer(SB),7,$0 MOVW 0(FP), R0 MOVW 4(FP), R1 @@ -126,31 +136,45 @@ TEXT runtime·mincore(SB),7,$0 SWI $0 RET -TEXT runtime·gettime(SB),7,$32 - /* dummy version - return 0,0 */ - MOVW $0, R1 - MOVW 0(FP), R0 - MOVW R1, 0(R0) - MOVW R1, 4(R0) - MOVW 4(FP), R0 - MOVW R1, 0(R0) - -/* - attempt at real version - seg faults - - MOVW $8(SP), R0 +TEXT time·now(SB), 7, $32 + MOVW $8(R13), R0 // timeval + MOVW $0, R1 // zone + MOVW $SYS_gettimeofday, R7 + SWI $0 + + MOVW 8(R13), R0 // sec + MOVW 12(R13), R2 // usec + + MOVW R0, 0(FP) MOVW $0, R1 + MOVW R1, 4(FP) + MOVW $1000, R3 + MUL R3, R2 + MOVW R2, 8(FP) + RET + +// int64 nanotime(void) so really +// void nanotime(int64 *nsec) +TEXT runtime·nanotime(SB),7,$32 + MOVW $8(R13), R0 // timeval + MOVW $0, R1 // zone MOVW $SYS_gettimeofday, R7 SWI $0 - - MOVW 0(FP), R0 // sec - MOVW 8(SP), R1 - MOVW R1, 0(R0) - - MOVW 4(FP), R0 // usec - MOVW 12(SP), R1 - MOVW R1, 0(R0) -*/ + + MOVW 8(R13), R0 // sec + MOVW 12(R13), R2 // usec + + MOVW $1000000000, R3 + MULLU R0, R3, (R1, R0) + MOVW $1000, R3 + MOVW $0, R4 + MUL R3, R2 + ADD.S R2, R0 + ADC R4, R1 + + MOVW 0(FP), R3 + MOVW R0, 0(R3) + MOVW R1, 4(R3) RET // int32 futex(int32 *uaddr, int32 op, int32 val, @@ -254,7 +278,7 @@ TEXT runtime·sigtramp(SB),7,$24 // save g MOVW g, R3 MOVW g, 20(R13) - + // g = m->gsignal MOVW m_gsignal(m), g @@ -265,7 +289,7 @@ TEXT runtime·sigtramp(SB),7,$24 MOVW R3, 16(R13) BL runtime·sighandler(SB) - + // restore g MOVW 20(R13), g @@ -285,6 +309,23 @@ TEXT runtime·sigreturn(SB),7,$0 SWI $0 RET +TEXT runtime·usleep(SB),7,$12 + MOVW usec+0(FP), R0 + MOVW R0, R1 + MOVW $1000000, R2 + DIV R2, R0 + MOD R2, R1 + MOVW R0, 4(SP) + MOVW R1, 8(SP) + MOVW $0, R0 + MOVW $0, R1 + MOVW $0, R2 + MOVW $0, R3 + MOVW $4(SP), R4 + MOVW $SYS_select, R7 + SWI $0 + RET + // Use kernel version instead of native armcas in ../../arm.s. // See ../../../sync/atomic/asm_linux_arm.s for details. TEXT cas<>(SB),7,$0 diff --git a/src/pkg/runtime/sys_netbsd_386.s b/src/pkg/runtime/sys_netbsd_386.s new file mode 100644 index 000000000..632286102 --- /dev/null +++ b/src/pkg/runtime/sys_netbsd_386.s @@ -0,0 +1,324 @@ +// 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. +// +// System calls and other sys.stuff for 386, NetBSD +// /usr/src/sys/kern/syscalls.master for syscall numbers. +// + +#include "zasm_GOOS_GOARCH.h" + +// Exit the entire program (like C exit) +TEXT runtime·exit(SB),7,$-4 + MOVL $1, AX + INT $0x80 + CALL runtime·notok(SB) + RET + +TEXT runtime·exit1(SB),7,$-4 + MOVL $302, AX // sys_threxit + INT $0x80 + JAE 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·write(SB),7,$-4 + MOVL $4, AX // sys_write + INT $0x80 + RET + +TEXT runtime·usleep(SB),7,$20 + MOVL $0, DX + MOVL usec+0(FP), AX + MOVL $1000000, CX + DIVL CX + MOVL AX, 12(SP) // tv_sec + MOVL $1000, AX + MULL DX + MOVL AX, 16(SP) // tv_nsec + + MOVL $0, 0(SP) + LEAL 12(SP), AX + MOVL AX, 4(SP) // arg 1 - rqtp + MOVL $0, 8(SP) // arg 2 - rmtp + MOVL $240, AX // sys_nanosleep + INT $0x80 + RET + +TEXT runtime·raisesigpipe(SB),7,$12 + MOVL $299, AX // sys_getthrid + INT $0x80 + MOVL $0, 0(SP) + MOVL AX, 4(SP) // arg 1 - pid + MOVL $13, 8(SP) // arg 2 - signum == SIGPIPE + MOVL $37, AX // sys_kill + INT $0x80 + RET + +TEXT runtime·notok(SB),7,$0 + MOVL $0xf1, 0xf1 + RET + +TEXT runtime·mmap(SB),7,$36 + LEAL arg0+0(FP), SI + LEAL 4(SP), DI + CLD + MOVSL // arg 1 - addr + MOVSL // arg 2 - len + MOVSL // arg 3 - prot + MOVSL // arg 4 - flags + MOVSL // arg 5 - fd + MOVL $0, AX + STOSL // arg 6 - pad + MOVSL // arg 7 - offset + MOVL $0, AX // top 64 bits of file offset + STOSL + MOVL $197, AX // sys_mmap + INT $0x80 + JCC 2(PC) + NEGL AX + RET + +TEXT runtime·munmap(SB),7,$-4 + MOVL $73, AX // sys_munmap + INT $0x80 + JAE 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·setitimer(SB),7,$-4 + MOVL $83, AX + INT $0x80 + RET + +// func now() (sec int64, nsec int32) +TEXT time·now(SB), 7, $32 + MOVL $116, AX + LEAL 12(SP), BX + MOVL BX, 4(SP) + MOVL $0, 8(SP) + INT $0x80 + MOVL 12(SP), AX // sec + MOVL 16(SP), BX // usec + + // sec is in AX, usec in BX + MOVL AX, sec+0(FP) + MOVL $0, sec+4(FP) + IMULL $1000, BX + MOVL BX, nsec+8(FP) + RET + +// int64 nanotime(void) so really +// void nanotime(int64 *nsec) +TEXT runtime·nanotime(SB),7,$32 + MOVL $116, AX + LEAL 12(SP), BX + MOVL BX, 4(SP) + MOVL $0, 8(SP) + INT $0x80 + MOVL 12(SP), AX // sec + MOVL 16(SP), BX // usec + + // sec is in AX, usec in BX + // convert to DX:AX nsec + MOVL $1000000000, CX + MULL CX + IMULL $1000, BX + ADDL BX, AX + ADCL $0, DX + + MOVL ret+0(FP), DI + MOVL AX, 0(DI) + MOVL DX, 4(DI) + RET + +TEXT runtime·sigaction(SB),7,$-4 + MOVL $46, AX // sys_sigaction + INT $0x80 + JAE 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·sigtramp(SB),7,$44 + get_tls(CX) + + // save g + MOVL g(CX), DI + MOVL DI, 20(SP) + + // g = m->gsignal + MOVL m(CX), BX + MOVL m_gsignal(BX), BX + MOVL BX, g(CX) + + // copy arguments for call to sighandler + MOVL signo+0(FP), BX + MOVL BX, 0(SP) + MOVL info+4(FP), BX + MOVL BX, 4(SP) + MOVL context+8(FP), BX + MOVL BX, 8(SP) + MOVL DI, 12(SP) + + CALL runtime·sighandler(SB) + + // restore g + get_tls(CX) + MOVL 20(SP), BX + MOVL BX, g(CX) + + // call sigreturn + MOVL context+8(FP), AX + MOVL $0, 0(SP) // syscall gap + MOVL AX, 4(SP) // arg 1 - sigcontext + MOVL $103, AX // sys_sigreturn + INT $0x80 + CALL runtime·notok(SB) + RET + +// int32 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); +TEXT runtime·rfork_thread(SB),7,$8 + MOVL flags+8(SP), AX + MOVL stack+12(SP), CX + + // Copy m, g, fn off parent stack for use by child. + SUBL $16, CX + MOVL mm+16(SP), SI + MOVL SI, 0(CX) + MOVL gg+20(SP), SI + MOVL SI, 4(CX) + MOVL fn+24(SP), SI + MOVL SI, 8(CX) + MOVL $1234, 12(CX) + MOVL CX, SI + + MOVL $0, 0(SP) // syscall gap + MOVL AX, 4(SP) // arg 1 - flags + MOVL $251, AX // sys_rfork + INT $0x80 + + // Return if rfork syscall failed + JCC 4(PC) + NEGL AX + MOVL AX, 48(SP) + RET + + // In parent, return. + CMPL AX, $0 + JEQ 3(PC) + MOVL AX, 48(SP) + RET + + // In child, on new stack. + MOVL SI, SP + + // Paranoia: check that SP is as we expect. + MOVL 12(SP), BP + CMPL BP, $1234 + JEQ 2(PC) + INT $3 + + // Reload registers + MOVL 0(SP), BX // m + MOVL 4(SP), DX // g + MOVL 8(SP), SI // fn + + // Initialize m->procid to thread ID + MOVL $299, AX // sys_getthrid + INT $0x80 + MOVL AX, m_procid(BX) + + // Set FS to point at m->tls + LEAL m_tls(BX), BP + PUSHAL // save registers + PUSHL BP + CALL runtime·settls(SB) + POPL AX + POPAL + + // Now segment is established. Initialize m, g. + get_tls(AX) + MOVL DX, g(AX) + MOVL BX, m(AX) + + CALL runtime·stackcheck(SB) // smashes AX, CX + MOVL 0(DX), DX // paranoia; check they are not nil + MOVL 0(BX), BX + + // more paranoia; check that stack splitting code works + PUSHAL + CALL runtime·emptyfunc(SB) + POPAL + + // Call fn + CALL SI + + CALL runtime·exit1(SB) + MOVL $0x1234, 0x1005 + RET + +TEXT runtime·sigaltstack(SB),7,$-8 + MOVL $288, AX // sys_sigaltstack + MOVL new+4(SP), BX + MOVL old+8(SP), CX + INT $0x80 + CMPL AX, $0xfffff001 + JLS 2(PC) + INT $3 + RET + +TEXT runtime·setldt(SB),7,$8 + // Under NetBSD we set the GS base instead of messing with the LDT. + MOVL 16(SP), AX // tls0 + MOVL AX, 0(SP) + CALL runtime·settls(SB) + RET + +TEXT runtime·settls(SB),7,$16 + // adjust for ELF: wants to use -8(GS) and -4(GS) for g and m + MOVL 20(SP), CX + ADDL $8, CX + MOVL CX, 0(CX) + MOVL $0, 0(SP) // syscall gap + MOVL $9, 4(SP) // I386_SET_GSBASE (machine/sysarch.h) + MOVL CX, 8(SP) // pointer to base + MOVL $165, AX // sys_sysarch + INT $0x80 + JCC 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·osyield(SB),7,$-4 + MOVL $298, AX // sys_sched_yield + INT $0x80 + RET + +TEXT runtime·thrsleep(SB),7,$-4 + MOVL $300, AX // sys_thrsleep + INT $0x80 + RET + +TEXT runtime·thrwakeup(SB),7,$-4 + MOVL $301, AX // sys_thrwakeup + INT $0x80 + RET + +TEXT runtime·sysctl(SB),7,$28 + LEAL arg0+0(FP), SI + LEAL 4(SP), DI + CLD + MOVSL // arg 1 - name + MOVSL // arg 2 - namelen + MOVSL // arg 3 - oldp + MOVSL // arg 4 - oldlenp + MOVSL // arg 5 - newp + MOVSL // arg 6 - newlen + MOVL $202, AX // sys___sysctl + INT $0x80 + JCC 3(PC) + NEGL AX + RET + MOVL $0, AX + RET + +GLOBL runtime·tlsoffset(SB),$4 diff --git a/src/pkg/runtime/sys_netbsd_amd64.s b/src/pkg/runtime/sys_netbsd_amd64.s new file mode 100644 index 000000000..7abeb159b --- /dev/null +++ b/src/pkg/runtime/sys_netbsd_amd64.s @@ -0,0 +1,268 @@ +// 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. +// +// System calls and other sys.stuff for AMD64, NetBSD +// /usr/src/sys/kern/syscalls.master for syscall numbers. +// + +#include "zasm_GOOS_GOARCH.h" + +// int64 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); +TEXT runtime·rfork_thread(SB),7,$0 + MOVL flags+8(SP), DI + MOVQ stack+16(SP), SI + + // Copy m, g, fn off parent stack for use by child. + MOVQ mm+24(SP), R8 + MOVQ gg+32(SP), R9 + MOVQ fn+40(SP), R12 + + MOVL $251, AX // sys_rfork + SYSCALL + + // Return if rfork syscall failed + JCC 3(PC) + NEGL AX + RET + + // In parent, return. + CMPL AX, $0 + JEQ 2(PC) + RET + + // In child, on new stack. + MOVQ SI, SP + + // Initialize m->procid to thread ID + MOVL $299, AX // sys_getthrid + SYSCALL + MOVQ AX, m_procid(R8) + + // Set FS to point at m->tls. + LEAQ m_tls(R8), DI + CALL runtime·settls(SB) + + // In child, set up new stack + get_tls(CX) + MOVQ R8, m(CX) + MOVQ R9, g(CX) + CALL runtime·stackcheck(SB) + + // Call fn + CALL R12 + + // It shouldn't return. If it does, exit + MOVL $302, AX // sys_threxit + SYSCALL + JMP -3(PC) // keep exiting + +TEXT runtime·osyield(SB),7,$0 + MOVL $298, AX // sys_sched_yield + SYSCALL + RET + +TEXT runtime·thrsleep(SB),7,$0 + MOVQ 8(SP), DI // arg 1 - ident + MOVL 16(SP), SI // arg 2 - clock_id + MOVQ 24(SP), DX // arg 3 - tp + MOVQ 32(SP), R10 // arg 4 - lock + MOVL $300, AX // sys_thrsleep + SYSCALL + RET + +TEXT runtime·thrwakeup(SB),7,$0 + MOVQ 8(SP), DI // arg 1 - ident + MOVL 16(SP), SI // arg 2 - n + MOVL $301, AX // sys_thrwakeup + SYSCALL + RET + +// Exit the entire program (like C exit) +TEXT runtime·exit(SB),7,$-8 + MOVL 8(SP), DI // arg 1 - exit status + MOVL $1, AX // sys_exit + SYSCALL + CALL runtime·notok(SB) + RET + +TEXT runtime·exit1(SB),7,$-8 + MOVL $302, AX // sys_threxit + SYSCALL + CALL runtime·notok(SB) + RET + +TEXT runtime·write(SB),7,$-8 + MOVL 8(SP), DI // arg 1 - fd + MOVQ 16(SP), SI // arg 2 - buf + MOVL 24(SP), DX // arg 3 - nbyte + MOVL $4, AX // sys_write + SYSCALL + RET + +TEXT runtime·usleep(SB),7,$16 + MOVL $0, DX + MOVL usec+0(FP), AX + MOVL $1000000, CX + DIVL CX + MOVQ AX, 0(SP) // tv_sec + MOVL $1000, AX + MULL DX + MOVQ AX, 8(SP) // tv_nsec + + MOVQ SP, DI // arg 1 - rqtp + MOVQ $0, SI // arg 2 - rmtp + MOVL $240, AX // sys_nanosleep + SYSCALL + RET + +TEXT runtime·raisesigpipe(SB),7,$16 + MOVL $299, AX // sys_getthrid + SYSCALL + MOVQ AX, DI // arg 1 - pid + MOVQ $13, SI // arg 2 - signum == SIGPIPE + MOVL $37, AX // sys_kill + SYSCALL + RET + +TEXT runtime·setitimer(SB),7,$-8 + MOVL 8(SP), DI // arg 1 - which + MOVQ 16(SP), SI // arg 2 - itv + MOVQ 24(SP), DX // arg 3 - oitv + MOVL $83, AX // sys_setitimer + SYSCALL + RET + +// func now() (sec int64, nsec int32) +TEXT time·now(SB), 7, $32 + LEAQ 8(SP), DI // arg 1 - tp + MOVQ $0, SI // arg 2 - tzp + MOVL $116, AX // sys_gettimeofday + SYSCALL + MOVQ 8(SP), AX // sec + MOVL 16(SP), DX // usec + + // sec is in AX, usec in DX + MOVQ AX, sec+0(FP) + IMULQ $1000, DX + MOVL DX, nsec+8(FP) + RET + +TEXT runtime·nanotime(SB),7,$32 + LEAQ 8(SP), DI // arg 1 - tp + MOVQ $0, SI // arg 2 - tzp + MOVL $116, AX // sys_gettimeofday + SYSCALL + MOVQ 8(SP), AX // sec + MOVL 16(SP), DX // usec + + // sec is in AX, usec in DX + // return nsec in AX + IMULQ $1000000000, AX + IMULQ $1000, DX + ADDQ DX, AX + RET + +TEXT runtime·sigaction(SB),7,$-8 + MOVL 8(SP), DI // arg 1 - signum + MOVQ 16(SP), SI // arg 2 - nsa + MOVQ 24(SP), DX // arg 3 - osa + MOVL $46, AX + SYSCALL + JCC 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·sigtramp(SB),7,$64 + get_tls(BX) + + // save g + MOVQ g(BX), R10 + MOVQ R10, 40(SP) + + // g = m->signal + MOVQ m(BX), BP + MOVQ m_gsignal(BP), BP + MOVQ BP, g(BX) + + MOVQ DI, 0(SP) + MOVQ SI, 8(SP) + MOVQ DX, 16(SP) + MOVQ R10, 24(SP) + + CALL runtime·sighandler(SB) + + // restore g + get_tls(BX) + MOVQ 40(SP), R10 + MOVQ R10, g(BX) + RET + +TEXT runtime·mmap(SB),7,$0 + MOVQ 8(SP), DI // arg 1 - addr + MOVQ 16(SP), SI // arg 2 - len + MOVL 24(SP), DX // arg 3 - prot + MOVL 28(SP), R10 // arg 4 - flags + MOVL 32(SP), R8 // arg 5 - fd + MOVQ 36(SP), R9 + SUBQ $16, SP + MOVQ R9, 8(SP) // arg 7 - offset (passed on stack) + MOVQ $0, R9 // arg 6 - pad + MOVL $197, AX + SYSCALL + JCC 2(PC) + NEGL AX + ADDQ $16, SP + RET + +TEXT runtime·munmap(SB),7,$0 + MOVQ 8(SP), DI // arg 1 - addr + MOVQ 16(SP), SI // arg 2 - len + MOVL $73, AX // sys_munmap + SYSCALL + JCC 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·notok(SB),7,$-8 + MOVL $0xf1, BP + MOVQ BP, (BP) + RET + +TEXT runtime·sigaltstack(SB),7,$-8 + MOVQ new+8(SP), DI // arg 1 - nss + MOVQ old+16(SP), SI // arg 2 - oss + MOVQ $288, AX // sys_sigaltstack + SYSCALL + JCC 2(PC) + CALL runtime·notok(SB) + RET + +// set tls base to DI +TEXT runtime·settls(SB),7,$8 + // adjust for ELF: wants to use -16(FS) and -8(FS) for g and m + ADDQ $16, DI + MOVQ DI, 0(SP) + MOVQ SP, SI + MOVQ $12, DI // AMD64_SET_FSBASE (machine/sysarch.h) + MOVQ $165, AX // sys_sysarch + SYSCALL + JCC 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·sysctl(SB),7,$0 + MOVQ 8(SP), DI // arg 1 - name + MOVL 16(SP), SI // arg 2 - namelen + MOVQ 24(SP), DX // arg 3 - oldp + MOVQ 32(SP), R10 // arg 4 - oldlenp + MOVQ 40(SP), R8 // arg 5 - newp + MOVQ 48(SP), R9 // arg 6 - newlen + MOVQ $202, AX // sys___sysctl + SYSCALL + JCC 3(PC) + NEGL AX + RET + MOVL $0, AX + RET + diff --git a/src/pkg/runtime/openbsd/386/sys.s b/src/pkg/runtime/sys_openbsd_386.s index 3a78679bc..d49d32b95 100644 --- a/src/pkg/runtime/openbsd/386/sys.s +++ b/src/pkg/runtime/sys_openbsd_386.s @@ -6,7 +6,7 @@ // /usr/src/sys/kern/syscalls.master for syscall numbers. // -#include "386/asm.h" +#include "zasm_GOOS_GOARCH.h" // Exit the entire program (like C exit) TEXT runtime·exit(SB),7,$-4 @@ -27,6 +27,24 @@ TEXT runtime·write(SB),7,$-4 INT $0x80 RET +TEXT runtime·usleep(SB),7,$20 + MOVL $0, DX + MOVL usec+0(FP), AX + MOVL $1000000, CX + DIVL CX + MOVL AX, 12(SP) // tv_sec + MOVL $1000, AX + MULL DX + MOVL AX, 16(SP) // tv_nsec + + MOVL $0, 0(SP) + LEAL 12(SP), AX + MOVL AX, 4(SP) // arg 1 - rqtp + MOVL $0, 8(SP) // arg 2 - rmtp + MOVL $240, AX // sys_nanosleep + INT $0x80 + RET + TEXT runtime·raisesigpipe(SB),7,$12 MOVL $299, AX // sys_getthrid INT $0x80 @@ -73,21 +91,45 @@ TEXT runtime·setitimer(SB),7,$-4 INT $0x80 RET -TEXT runtime·gettime(SB),7,$32 +// func now() (sec int64, nsec int32) +TEXT time·now(SB), 7, $32 MOVL $116, AX LEAL 12(SP), BX MOVL BX, 4(SP) MOVL $0, 8(SP) INT $0x80 + MOVL 12(SP), AX // sec + MOVL 16(SP), BX // usec - MOVL 12(SP), BX // sec - MOVL sec+0(FP), DI - MOVL BX, (DI) - MOVL $0, 4(DI) // zero extend 32 -> 64 bits + // sec is in AX, usec in BX + MOVL AX, sec+0(FP) + MOVL $0, sec+4(FP) + IMULL $1000, BX + MOVL BX, nsec+8(FP) + RET +// int64 nanotime(void) so really +// void nanotime(int64 *nsec) +TEXT runtime·nanotime(SB),7,$32 + MOVL $116, AX + LEAL 12(SP), BX + MOVL BX, 4(SP) + MOVL $0, 8(SP) + INT $0x80 + MOVL 12(SP), AX // sec MOVL 16(SP), BX // usec - MOVL usec+4(FP), DI - MOVL BX, (DI) + + // sec is in AX, usec in BX + // convert to DX:AX nsec + MOVL $1000000000, CX + MULL CX + IMULL $1000, BX + ADDL BX, AX + ADCL $0, DX + + MOVL ret+0(FP), DI + MOVL AX, 0(DI) + MOVL DX, 4(DI) RET TEXT runtime·sigaction(SB),7,$-4 @@ -251,4 +293,32 @@ TEXT runtime·osyield(SB),7,$-4 INT $0x80 RET +TEXT runtime·thrsleep(SB),7,$-4 + MOVL $300, AX // sys_thrsleep + INT $0x80 + RET + +TEXT runtime·thrwakeup(SB),7,$-4 + MOVL $301, AX // sys_thrwakeup + INT $0x80 + RET + +TEXT runtime·sysctl(SB),7,$28 + LEAL arg0+0(FP), SI + LEAL 4(SP), DI + CLD + MOVSL // arg 1 - name + MOVSL // arg 2 - namelen + MOVSL // arg 3 - oldp + MOVSL // arg 4 - oldlenp + MOVSL // arg 5 - newp + MOVSL // arg 6 - newlen + MOVL $202, AX // sys___sysctl + INT $0x80 + JCC 3(PC) + NEGL AX + RET + MOVL $0, AX + RET + GLOBL runtime·tlsoffset(SB),$4 diff --git a/src/pkg/runtime/openbsd/amd64/sys.s b/src/pkg/runtime/sys_openbsd_amd64.s index 38b3dbc9c..5bf2e813e 100644 --- a/src/pkg/runtime/openbsd/amd64/sys.s +++ b/src/pkg/runtime/sys_openbsd_amd64.s @@ -6,7 +6,7 @@ // /usr/src/sys/kern/syscalls.master for syscall numbers. // -#include "amd64/asm.h" +#include "zasm_GOOS_GOARCH.h" // int64 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); TEXT runtime·rfork_thread(SB),7,$0 @@ -62,19 +62,19 @@ TEXT runtime·osyield(SB),7,$0 SYSCALL RET -TEXT runtime·sys_thrsleep(SB),7,$0 - MOVQ 8(SP), DI - MOVL 16(SP), SI - MOVQ 24(SP), DX - MOVQ 32(SP), R10 - MOVL $300, AX +TEXT runtime·thrsleep(SB),7,$0 + MOVQ 8(SP), DI // arg 1 - ident + MOVL 16(SP), SI // arg 2 - clock_id + MOVQ 24(SP), DX // arg 3 - tp + MOVQ 32(SP), R10 // arg 4 - lock + MOVL $300, AX // sys_thrsleep SYSCALL RET -TEXT runtime·sys_thrwakeup(SB),7,$0 - MOVQ 8(SP), DI - MOVL 16(SP), SI - MOVL $301, AX +TEXT runtime·thrwakeup(SB),7,$0 + MOVQ 8(SP), DI // arg 1 - ident + MOVL 16(SP), SI // arg 2 - n + MOVL $301, AX // sys_thrwakeup SYSCALL RET @@ -100,6 +100,22 @@ TEXT runtime·write(SB),7,$-8 SYSCALL RET +TEXT runtime·usleep(SB),7,$16 + MOVL $0, DX + MOVL usec+0(FP), AX + MOVL $1000000, CX + DIVL CX + MOVQ AX, 0(SP) // tv_sec + MOVL $1000, AX + MULL DX + MOVQ AX, 8(SP) // tv_nsec + + MOVQ SP, DI // arg 1 - rqtp + MOVQ $0, SI // arg 2 - rmtp + MOVL $240, AX // sys_nanosleep + SYSCALL + RET + TEXT runtime·raisesigpipe(SB),7,$16 MOVL $299, AX // sys_getthrid SYSCALL @@ -117,19 +133,34 @@ TEXT runtime·setitimer(SB),7,$-8 SYSCALL RET -TEXT runtime·gettime(SB),7,$32 +// func now() (sec int64, nsec int32) +TEXT time·now(SB), 7, $32 LEAQ 8(SP), DI // arg 1 - tp MOVQ $0, SI // arg 2 - tzp MOVL $116, AX // sys_gettimeofday SYSCALL + MOVQ 8(SP), AX // sec + MOVL 16(SP), DX // usec - MOVQ 8(SP), BX // sec - MOVQ sec+0(FP), DI - MOVQ BX, (DI) + // sec is in AX, usec in DX + MOVQ AX, sec+0(FP) + IMULQ $1000, DX + MOVL DX, nsec+8(FP) + RET + +TEXT runtime·nanotime(SB),7,$32 + LEAQ 8(SP), DI // arg 1 - tp + MOVQ $0, SI // arg 2 - tzp + MOVL $116, AX // sys_gettimeofday + SYSCALL + MOVQ 8(SP), AX // sec + MOVL 16(SP), DX // usec - MOVL 16(SP), BX // usec - MOVQ usec+8(FP), DI - MOVL BX, (DI) + // sec is in AX, usec in DX + // return nsec in AX + IMULQ $1000000000, AX + IMULQ $1000, DX + ADDQ DX, AX RET TEXT runtime·sigaction(SB),7,$-8 @@ -219,3 +250,19 @@ TEXT runtime·settls(SB),7,$8 JCC 2(PC) CALL runtime·notok(SB) RET + +TEXT runtime·sysctl(SB),7,$0 + MOVQ 8(SP), DI // arg 1 - name + MOVL 16(SP), SI // arg 2 - namelen + MOVQ 24(SP), DX // arg 3 - oldp + MOVQ 32(SP), R10 // arg 4 - oldlenp + MOVQ 40(SP), R8 // arg 5 - newp + MOVQ 48(SP), R9 // arg 6 - newlen + MOVQ $202, AX // sys___sysctl + SYSCALL + JCC 3(PC) + NEGL AX + RET + MOVL $0, AX + RET + diff --git a/src/pkg/runtime/plan9/386/sys.s b/src/pkg/runtime/sys_plan9_386.s index 1cb570b68..94c36aa41 100644 --- a/src/pkg/runtime/plan9/386/sys.s +++ b/src/pkg/runtime/sys_plan9_386.s @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "defs.h" -#include "386/asm.h" +#include "defs_GOOS_GOARCH.h" +#include "zasm_GOOS_GOARCH.h" // setldt(int entry, int address, int limit) TEXT runtime·setldt(SB),7,$0 @@ -14,11 +14,21 @@ TEXT runtime·open(SB),7,$0 INT $64 RET -TEXT runtime·write(SB),7,$0 - MOVL $20, AX +TEXT runtime·pread(SB),7,$0 + MOVL $50, AX INT $64 RET +TEXT runtime·pwrite(SB),7,$0 + MOVL $51, AX + INT $64 + RET + +TEXT runtime·close(SB),7,$0 + MOVL $4, AX + INT $64 + RET + TEXT runtime·exits(SB),7,$0 MOVL $8, AX INT $64 @@ -29,6 +39,11 @@ TEXT runtime·brk_(SB),7,$0 INT $64 RET +TEXT runtime·sleep(SB),7,$0 + MOVL $17, AX + INT $64 + RET + TEXT runtime·plan9_semacquire(SB),7,$0 MOVL $37, AX INT $64 @@ -73,9 +88,9 @@ TEXT runtime·rfork(SB),7,$0 MOVL 0(BX), BX // more paranoia; check that stack splitting code works - PUSHAL + PUSHL SI CALL runtime·emptyfunc(SB) - POPAL + POPL SI CALL SI // fn() CALL runtime·exit(SB) diff --git a/src/pkg/runtime/windows/386/sys.s b/src/pkg/runtime/sys_windows_386.s index 95ae5336b..5290f6093 100644 --- a/src/pkg/runtime/windows/386/sys.s +++ b/src/pkg/runtime/sys_windows_386.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "386/asm.h" +#include "zasm_GOOS_GOARCH.h" // void runtime·asmstdcall(void *c); TEXT runtime·asmstdcall(SB),7,$0 @@ -48,51 +48,33 @@ TEXT runtime·setlasterror(SB),7,$0 MOVL AX, 0x34(FS) RET -TEXT runtime·sigtramp(SB),7,$0 - PUSHL BP // cdecl - PUSHL BX - PUSHL SI - PUSHL DI - PUSHL 0(FS) - CALL runtime·sigtramp1(SB) - POPL 0(FS) - POPL DI - POPL SI - POPL BX - POPL BP - RET - -TEXT runtime·sigtramp1(SB),0,$16-40 +TEXT runtime·sigtramp(SB),7,$28 // unwinding? - MOVL info+24(FP), BX - MOVL 4(BX), CX // exception flags - ANDL $6, CX + MOVL info+0(FP), CX + TESTL $6, 4(CX) // exception flags MOVL $1, AX JNZ sigdone - // place ourselves at the top of the SEH chain to - // ensure SEH frames lie within thread stack bounds - MOVL frame+28(FP), CX // our SEH frame - MOVL CX, 0(FS) - // copy arguments for call to sighandler - MOVL BX, 0(SP) + MOVL CX, 0(SP) + MOVL context+8(FP), CX MOVL CX, 4(SP) - MOVL context+32(FP), BX - MOVL BX, 8(SP) - MOVL dispatcher+36(FP), BX + get_tls(CX) + MOVL g(CX), CX + MOVL CX, 8(SP) + MOVL BX, 12(SP) + MOVL BP, 16(SP) + MOVL SI, 20(SP) + MOVL DI, 24(SP) CALL runtime·sighandler(SB) - TESTL AX, AX - JZ sigdone - - // call windows default handler early - MOVL 4(SP), BX // our SEH frame - MOVL 0(BX), BX // SEH frame of default handler - MOVL BX, 4(SP) // set establisher frame - CALL 4(BX) + // AX is set to report result back to Windows + MOVL 24(SP), DI + MOVL 20(SP), SI + MOVL 16(SP), BP + MOVL 12(SP), BX sigdone: RET @@ -116,7 +98,7 @@ TEXT runtime·externalthreadhandler(SB),7,$0 PUSHL BX PUSHL SI PUSHL DI - PUSHL 0x2c(FS) + PUSHL 0x14(FS) MOVL SP, DX // setup dummy m, g @@ -126,7 +108,7 @@ TEXT runtime·externalthreadhandler(SB),7,$0 CALL runtime·memclr(SB) // smashes AX,BX,CX LEAL m_tls(SP), CX - MOVL CX, 0x2c(FS) + MOVL CX, 0x14(FS) MOVL SP, m(CX) MOVL SP, BX SUBL $g_end, SP // space for G @@ -147,7 +129,7 @@ TEXT runtime·externalthreadhandler(SB),7,$0 get_tls(CX) MOVL g(CX), CX MOVL g_stackbase(CX), SP - POPL 0x2c(FS) + POPL 0x14(FS) POPL DI POPL SI POPL BX @@ -226,7 +208,7 @@ TEXT runtime·tstart(SB),7,$0 // Set up tls. LEAL m_tls(CX), SI - MOVL SI, 0x2c(FS) + MOVL SI, 0x14(FS) MOVL CX, m(SI) MOVL DX, g(SI) @@ -264,5 +246,5 @@ TEXT runtime·tstart_stdcall(SB),7,$0 // setldt(int entry, int address, int limit) TEXT runtime·setldt(SB),7,$0 MOVL address+4(FP), CX - MOVL CX, 0x2c(FS) + MOVL CX, 0x14(FS) RET diff --git a/src/pkg/runtime/windows/amd64/sys.s b/src/pkg/runtime/sys_windows_amd64.s index 113db2004..76b5ee5fb 100644 --- a/src/pkg/runtime/windows/amd64/sys.s +++ b/src/pkg/runtime/sys_windows_amd64.s @@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "amd64/asm.h" +#include "zasm_GOOS_GOARCH.h" -#define maxargs 12 +// maxargs should be divisible by 2, as Windows stack +// must be kept 16-byte aligned on syscall entry. +#define maxargs 16 // void runtime·asmstdcall(void *c); TEXT runtime·asmstdcall(SB),7,$0 @@ -119,7 +121,7 @@ TEXT runtime·externalthreadhandler(SB),7,$0 PUSHQ BX PUSHQ SI PUSHQ DI - PUSHQ 0x58(GS) + PUSHQ 0x28(GS) MOVQ SP, DX // setup dummy m, g @@ -129,7 +131,7 @@ TEXT runtime·externalthreadhandler(SB),7,$0 CALL runtime·memclr(SB) // smashes AX,BX,CX LEAQ m_tls(SP), CX - MOVQ CX, 0x58(GS) + MOVQ CX, 0x28(GS) MOVQ SP, m(CX) MOVQ SP, BX SUBQ $g_end, SP // space for G @@ -150,7 +152,7 @@ TEXT runtime·externalthreadhandler(SB),7,$0 get_tls(CX) MOVQ g(CX), CX MOVQ g_stackbase(CX), SP - POPQ 0x58(GS) + POPQ 0x28(GS) POPQ DI POPQ SI POPQ BX @@ -252,7 +254,7 @@ TEXT runtime·tstart_stdcall(SB),7,$0 // Set up tls. LEAQ m_tls(CX), SI - MOVQ SI, 0x58(GS) + MOVQ SI, 0x28(GS) MOVQ CX, m(SI) MOVQ DX, g(SI) @@ -274,5 +276,5 @@ TEXT runtime·notok(SB),7,$0 // set tls base to DI TEXT runtime·settls(SB),7,$0 CALL runtime·setstacklimits(SB) - MOVQ DI, 0x58(GS) + MOVQ DI, 0x28(GS) RET diff --git a/src/pkg/runtime/windows/syscall.goc b/src/pkg/runtime/syscall_windows.goc index 68c3a4dfa..781ec908d 100644 --- a/src/pkg/runtime/windows/syscall.goc +++ b/src/pkg/runtime/syscall_windows.goc @@ -4,21 +4,24 @@ package syscall #include "runtime.h" -#include "os.h" +#include "os_GOOS.h" #include "cgocall.h" -func loadlibraryex(filename uintptr) (handle uintptr) { - uintptr args[3] = { filename }; +func loadlibrary(filename *uint16) (handle uintptr, err uintptr) { WinCall c; - c.fn = runtime·LoadLibraryEx; - c.n = 3; - c.args = &args[0]; + c.fn = runtime·LoadLibrary; + c.n = 1; + c.args = &filename; runtime·cgocall(runtime·asmstdcall, &c); handle = c.r1; + if(handle == 0) + err = c.err; + else + err = 0; } -func getprocaddress(handle uintptr, procname uintptr) (proc uintptr) { +func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err uintptr) { WinCall c; USED(procname); @@ -27,6 +30,10 @@ func getprocaddress(handle uintptr, procname uintptr) (proc uintptr) { c.args = &handle; runtime·cgocall(runtime·asmstdcall, &c); proc = c.r1; + if(proc == 0) + err = c.err; + else + err = 0; } func NewCallback(fn Eface) (code uintptr) { @@ -110,3 +117,29 @@ func Syscall12(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 r1 = c.r1; r2 = c.r2; } + +func Syscall15(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr, a13 uintptr, a14 uintptr, a15 uintptr) (r1 uintptr, r2 uintptr, err uintptr) { + WinCall c; + + USED(a2); + USED(a3); + USED(a4); + USED(a5); + USED(a6); + USED(a7); + USED(a8); + USED(a9); + USED(a10); + USED(a11); + USED(a12); + USED(a13); + USED(a14); + USED(a15); + c.fn = (void*)fn; + c.n = nargs; + c.args = &a1; + runtime·cgocall(runtime·asmstdcall, &c); + err = c.err; + r1 = c.r1; + r2 = c.r2; +} diff --git a/src/pkg/runtime/syscall_windows_test.go b/src/pkg/runtime/syscall_windows_test.go index 32eb0533f..c8327fdef 100644 --- a/src/pkg/runtime/syscall_windows_test.go +++ b/src/pkg/runtime/syscall_windows_test.go @@ -5,29 +5,40 @@ package runtime_test import ( + "runtime" "syscall" - "unsafe" "testing" + "unsafe" ) -func TestStdCall(t *testing.T) { - type Rect struct { - left, top, right, bottom int32 - } +type DLL struct { + *syscall.DLL + t *testing.T +} - h, e := syscall.LoadLibrary("user32.dll") - if e != 0 { - t.Fatal("LoadLibrary(USER32)") +func GetDLL(t *testing.T, name string) *DLL { + d, e := syscall.LoadDLL(name) + if e != nil { + t.Fatal(e) } - p, e := syscall.GetProcAddress(h, "UnionRect") - if e != 0 { - t.Fatal("GetProcAddress(USER32.UnionRect)") + return &DLL{DLL: d, t: t} +} + +func (d *DLL) Proc(name string) *syscall.Proc { + p, e := d.FindProc(name) + if e != nil { + d.t.Fatal(e) } + return p +} +func TestStdCall(t *testing.T) { + type Rect struct { + left, top, right, bottom int32 + } res := Rect{} expected := Rect{1, 1, 40, 60} - a, _, _ := syscall.Syscall(uintptr(p), - 3, + a, _, _ := GetDLL(t, "user32.dll").Proc("UnionRect").Call( uintptr(unsafe.Pointer(&res)), uintptr(unsafe.Pointer(&Rect{10, 1, 14, 60})), uintptr(unsafe.Pointer(&Rect{1, 2, 40, 50}))) @@ -57,7 +68,7 @@ func Test64BitReturnStdCall(t *testing.T) { VER_LESS = 4 VER_LESS_EQUAL = 5 - ERROR_OLD_WIN_VERSION = 1150 + ERROR_OLD_WIN_VERSION syscall.Errno = 1150 ) type OSVersionInfoEx struct { @@ -74,24 +85,14 @@ func Test64BitReturnStdCall(t *testing.T) { Reserve byte } - kernel32, e := syscall.LoadLibrary("kernel32.dll") - if e != 0 { - t.Fatalf("LoadLibrary(kernel32.dll) failed: %s", syscall.Errstr(e)) - } - setMask, e := syscall.GetProcAddress(kernel32, "VerSetConditionMask") - if e != 0 { - t.Fatalf("GetProcAddress(kernel32.dll, VerSetConditionMask) failed: %s", syscall.Errstr(e)) - } - verifyVersion, e := syscall.GetProcAddress(kernel32, "VerifyVersionInfoW") - if e != 0 { - t.Fatalf("GetProcAddress(kernel32.dll, VerifyVersionInfoW) failed: %s", syscall.Errstr(e)) - } + d := GetDLL(t, "kernel32.dll") var m1, m2 uintptr - m1, m2, _ = syscall.Syscall6(setMask, 4, m1, m2, VER_MAJORVERSION, VER_GREATER_EQUAL, 0, 0) - m1, m2, _ = syscall.Syscall6(setMask, 4, m1, m2, VER_MINORVERSION, VER_GREATER_EQUAL, 0, 0) - m1, m2, _ = syscall.Syscall6(setMask, 4, m1, m2, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL, 0, 0) - m1, m2, _ = syscall.Syscall6(setMask, 4, m1, m2, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL, 0, 0) + VerSetConditionMask := d.Proc("VerSetConditionMask") + m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_MAJORVERSION, VER_GREATER_EQUAL) + m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_MINORVERSION, VER_GREATER_EQUAL) + m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL) + m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL) vi := OSVersionInfoEx{ MajorVersion: 5, @@ -100,63 +101,42 @@ func Test64BitReturnStdCall(t *testing.T) { ServicePackMinor: 0, } vi.OSVersionInfoSize = uint32(unsafe.Sizeof(vi)) - r, _, e2 := syscall.Syscall6(verifyVersion, - 4, + r, _, e2 := d.Proc("VerifyVersionInfoW").Call( uintptr(unsafe.Pointer(&vi)), VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR|VER_SERVICEPACKMINOR, - m1, m2, 0, 0) + m1, m2) if r == 0 && e2 != ERROR_OLD_WIN_VERSION { - t.Errorf("VerifyVersionInfo failed: (%d) %s", e2, syscall.Errstr(int(e2))) + t.Errorf("VerifyVersionInfo failed: %s", e2) } } func TestCDecl(t *testing.T) { - h, e := syscall.LoadLibrary("user32.dll") - if e != 0 { - t.Fatal("LoadLibrary(USER32)") - } - p, e := syscall.GetProcAddress(h, "wsprintfA") - if e != 0 { - t.Fatal("GetProcAddress(USER32.wsprintfA)") - } - var buf [50]byte - a, _, _ := syscall.Syscall6(uintptr(p), - 5, + a, _, _ := GetDLL(t, "user32.dll").Proc("wsprintfA").Call( uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(syscall.StringBytePtr("%d %d %d"))), - 1000, 2000, 3000, 0) + 1000, 2000, 3000) if string(buf[:a]) != "1000 2000 3000" { t.Error("cdecl USER32.wsprintfA returns", a, "buf=", buf[:a]) } } -func TestCallback(t *testing.T) { - h, e := syscall.LoadLibrary("user32.dll") - if e != 0 { - t.Fatal("LoadLibrary(USER32)") - } - pEnumWindows, e := syscall.GetProcAddress(h, "EnumWindows") - if e != 0 { - t.Fatal("GetProcAddress(USER32.EnumWindows)") - } - pIsWindow, e := syscall.GetProcAddress(h, "IsWindow") - if e != 0 { - t.Fatal("GetProcAddress(USER32.IsWindow)") - } +func TestEnumWindows(t *testing.T) { + d := GetDLL(t, "user32.dll") + isWindows := d.Proc("IsWindow") counter := 0 cb := syscall.NewCallback(func(hwnd syscall.Handle, lparam uintptr) uintptr { if lparam != 888 { t.Error("lparam was not passed to callback") } - b, _, _ := syscall.Syscall(uintptr(pIsWindow), 1, uintptr(hwnd), 0, 0) + b, _, _ := isWindows.Call(uintptr(hwnd)) if b == 0 { t.Error("USER32.IsWindow returns FALSE") } counter++ return 1 // continue enumeration }) - a, _, _ := syscall.Syscall(uintptr(pEnumWindows), 2, cb, 888, 0) + a, _, _ := d.Proc("EnumWindows").Call(cb, 888) if a == 0 { t.Error("USER32.EnumWindows returns FALSE") } @@ -165,6 +145,99 @@ func TestCallback(t *testing.T) { } } +func callback(hwnd syscall.Handle, lparam uintptr) uintptr { + (*(*func())(unsafe.Pointer(&lparam)))() + return 0 // stop enumeration +} + +// nestedCall calls into Windows, back into Go, and finally to f. +func nestedCall(t *testing.T, f func()) { + c := syscall.NewCallback(callback) + d := GetDLL(t, "user32.dll") + defer d.Release() + d.Proc("EnumWindows").Call(c, uintptr(*(*unsafe.Pointer)(unsafe.Pointer(&f)))) +} + +func TestCallback(t *testing.T) { + var x = false + nestedCall(t, func() { x = true }) + if !x { + t.Fatal("nestedCall did not call func") + } +} + +func TestCallbackGC(t *testing.T) { + nestedCall(t, runtime.GC) +} + +func TestCallbackPanic(t *testing.T) { + // Make sure panic during callback unwinds properly. + if runtime.LockedOSThread() { + t.Fatal("locked OS thread on entry to TestCallbackPanic") + } + defer func() { + s := recover() + if s == nil { + t.Fatal("did not panic") + } + if s.(string) != "callback panic" { + t.Fatal("wrong panic:", s) + } + if runtime.LockedOSThread() { + t.Fatal("locked OS thread on exit from TestCallbackPanic") + } + }() + nestedCall(t, func() { panic("callback panic") }) + panic("nestedCall returned") +} + +func TestCallbackPanicLoop(t *testing.T) { + // Make sure we don't blow out m->g0 stack. + for i := 0; i < 100000; i++ { + TestCallbackPanic(t) + } +} + +func TestCallbackPanicLocked(t *testing.T) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if !runtime.LockedOSThread() { + t.Fatal("runtime.LockOSThread didn't") + } + defer func() { + s := recover() + if s == nil { + t.Fatal("did not panic") + } + if s.(string) != "callback panic" { + t.Fatal("wrong panic:", s) + } + if !runtime.LockedOSThread() { + t.Fatal("lost lock on OS thread after panic") + } + }() + nestedCall(t, func() { panic("callback panic") }) + panic("nestedCall returned") +} + +func TestBlockingCallback(t *testing.T) { + c := make(chan int) + go func() { + for i := 0; i < 10; i++ { + c <- <-c + } + }() + nestedCall(t, func() { + for i := 0; i < 10; i++ { + c <- i + if j := <-c; j != i { + t.Errorf("out of sync %d != %d", j, i) + } + } + }) +} + func TestCallbackInAnotherThread(t *testing.T) { // TODO: test a function which calls back in another thread: QueueUserAPC() or CreateThread() } diff --git a/src/pkg/runtime/darwin/thread.c b/src/pkg/runtime/thread_darwin.c index 6733e815e..832c74bea 100644 --- a/src/pkg/runtime/darwin/thread.c +++ b/src/pkg/runtime/thread_darwin.c @@ -3,8 +3,8 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" #include "stack.h" extern SigTab runtime·sigtab[]; @@ -17,137 +17,47 @@ unimplemented(int8 *name) *(int32*)1231 = 1231; } -// Thread-safe allocation of a semaphore. -// Psema points at a kernel semaphore key. -// It starts out zero, meaning no semaphore. -// Fill it in, being careful of others calling initsema -// simultaneously. -static void -initsema(uint32 *psema) +int32 +runtime·semasleep(int64 ns) { - uint32 sema; - - if(*psema != 0) // already have one - return; - - sema = runtime·mach_semcreate(); - if(!runtime·cas(psema, 0, sema)){ - // Someone else filled it in. Use theirs. - runtime·mach_semdestroy(sema); - return; - } + return runtime·mach_semacquire(m->waitsema, ns); } - -// Blocking locks. - -// Implement Locks, using semaphores. -// l->key is the number of threads who want the lock. -// In a race, one thread increments l->key from 0 to 1 -// and the others increment it from >0 to >1. The thread -// who does the 0->1 increment gets the lock, and the -// others wait on the semaphore. When the 0->1 thread -// releases the lock by decrementing l->key, l->key will -// be >0, so it will increment the semaphore to wake up -// one of the others. This is the same algorithm used -// in Plan 9's user-level locks. - void -runtime·lock(Lock *l) +runtime·semawakeup(M *mp) { - if(m->locks < 0) - runtime·throw("lock count"); - m->locks++; - - if(runtime·xadd(&l->key, 1) > 1) { // someone else has it; wait - // Allocate semaphore if needed. - if(l->sema == 0) - initsema(&l->sema); - runtime·mach_semacquire(l->sema); - } + runtime·mach_semrelease(mp->waitsema); } -void -runtime·unlock(Lock *l) +uintptr +runtime·semacreate(void) { - m->locks--; - if(m->locks < 0) - runtime·throw("lock count"); - - if(runtime·xadd(&l->key, -1) > 0) { // someone else is waiting - // Allocate semaphore if needed. - if(l->sema == 0) - initsema(&l->sema); - runtime·mach_semrelease(l->sema); - } -} - -static void -destroylock(Lock *l) -{ - if(l->sema != 0) { - runtime·mach_semdestroy(l->sema); - l->sema = 0; - } -} - -// User-level semaphore implementation: -// try to do the operations in user space on u, -// but when it's time to block, fall back on the kernel semaphore k. -// This is the same algorithm used in Plan 9. -void -runtime·usemacquire(Usema *s) -{ - if((int32)runtime·xadd(&s->u, -1) < 0) { - if(s->k == 0) - initsema(&s->k); - runtime·mach_semacquire(s->k); - } -} - -void -runtime·usemrelease(Usema *s) -{ - if((int32)runtime·xadd(&s->u, 1) <= 0) { - if(s->k == 0) - initsema(&s->k); - runtime·mach_semrelease(s->k); - } + return runtime·mach_semcreate(); } - -// Event notifications. -void -runtime·noteclear(Note *n) -{ - n->wakeup = 0; -} - -void -runtime·notesleep(Note *n) -{ - while(!n->wakeup) - runtime·usemacquire(&n->sema); -} - -void -runtime·notewakeup(Note *n) -{ - n->wakeup = 1; - runtime·usemrelease(&n->sema); -} - - // BSD interface for threading. void runtime·osinit(void) { - // Register our thread-creation callback (see {amd64,386}/sys.s) + // Register our thread-creation callback (see sys_darwin_{amd64,386}.s) // but only if we're not using cgo. If we are using cgo we need // to let the C pthread libary install its own thread-creation callback. if(!runtime·iscgo) runtime·bsdthread_register(); - runtime·destroylock = destroylock; + + // Use sysctl to fetch hw.ncpu. + uint32 mib[2]; + uint32 out; + int32 ret; + uintptr nout; + + mib[0] = 6; + mib[1] = 3; + nout = sizeof out; + out = 0; + ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); + if(ret >= 0) + runtime·ncpu = out; } void @@ -342,6 +252,7 @@ enum // Mach calls that get interrupted by Unix signals // return this error code. We retry them. KERN_ABORTED = 14, + KERN_OPERATION_TIMED_OUT = 49, }; typedef struct Tmach_semcreateMsg Tmach_semcreateMsg; @@ -427,22 +338,31 @@ runtime·mach_semdestroy(uint32 sem) } } -// The other calls have simple system call traps in sys.s +// The other calls have simple system call traps in sys_darwin_{amd64,386}.s int32 runtime·mach_semaphore_wait(uint32 sema); int32 runtime·mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec); int32 runtime·mach_semaphore_signal(uint32 sema); int32 runtime·mach_semaphore_signal_all(uint32 sema); -void -runtime·mach_semacquire(uint32 sem) +int32 +runtime·mach_semacquire(uint32 sem, int64 ns) { int32 r; + if(ns >= 0) { + r = runtime·mach_semaphore_timedwait(sem, ns/1000000000LL, ns%1000000000LL); + if(r == KERN_ABORTED || r == KERN_OPERATION_TIMED_OUT) + return -1; + if(r != 0) + macherror(r, "semaphore_wait"); + return 0; + } while((r = runtime·mach_semaphore_wait(sem)) != 0) { if(r == KERN_ABORTED) // interrupted continue; macherror(r, "semaphore_wait"); } + return 0; } void @@ -462,13 +382,19 @@ runtime·sigpanic(void) { switch(g->sig) { case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) + if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); runtime·panicstring("invalid memory address or nil pointer dereference"); + } runtime·printf("unexpected fault address %p\n", g->sigcode1); runtime·throw("fault"); case SIGSEGV: - if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) + if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); runtime·panicstring("invalid memory address or nil pointer dereference"); + } runtime·printf("unexpected fault address %p\n", g->sigcode1); runtime·throw("fault"); case SIGFPE: @@ -482,3 +408,9 @@ runtime·sigpanic(void) } runtime·panicstring(runtime·sigtab[g->sig].name); } + +// TODO(rsc): place holder to fix build. +void +runtime·osyield(void) +{ +} diff --git a/src/pkg/runtime/freebsd/thread.c b/src/pkg/runtime/thread_freebsd.c index f8c550f57..1c48865a2 100644 --- a/src/pkg/runtime/freebsd/thread.c +++ b/src/pkg/runtime/thread_freebsd.c @@ -2,22 +2,55 @@ // license that can be found in the LICENSE file.` #include "runtime.h" -#include "defs.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" #include "stack.h" extern SigTab runtime·sigtab[]; extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*); +// From FreeBSD's <sys/sysctl.h> +#define CTL_HW 6 +#define HW_NCPU 3 + +static int32 +getncpu(void) +{ + uint32 mib[2]; + uint32 out; + int32 ret; + uintptr nout; + + // Fetch hw.ncpu via sysctl. + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + nout = sizeof out; + out = 0; + ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); + if(ret >= 0) + return out; + else + return 1; +} + // FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and -// thus the code is largely similar. See linux/thread.c for comments. +// thus the code is largely similar. See linux/thread.c and lock_futex.c for comments. -static void -umtx_wait(uint32 *addr, uint32 val) +void +runtime·futexsleep(uint32 *addr, uint32 val, int64 ns) { int32 ret; + Timespec ts, *tsp; + + if(ns < 0) + tsp = nil; + else { + ts.tv_sec = ns / 1000000000LL; + ts.tv_nsec = ns % 1000000000LL; + tsp = &ts; + } - ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, nil); + ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, tsp); if(ret >= 0 || ret == -EINTR) return; @@ -25,12 +58,12 @@ umtx_wait(uint32 *addr, uint32 val) *(int32*)0x1005 = 0x1005; } -static void -umtx_wake(uint32 *addr) +void +runtime·futexwakeup(uint32 *addr, uint32 cnt) { int32 ret; - ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, 1, nil, nil); + ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, cnt, nil, nil); if(ret >= 0) return; @@ -38,91 +71,6 @@ umtx_wake(uint32 *addr) *(int32*)0x1006 = 0x1006; } -// See linux/thread.c for comments about the algorithm. -static void -umtx_lock(Lock *l) -{ - uint32 v; - -again: - v = l->key; - if((v&1) == 0){ - if(runtime·cas(&l->key, v, v|1)) - return; - goto again; - } - - if(!runtime·cas(&l->key, v, v+2)) - goto again; - - umtx_wait(&l->key, v+2); - - for(;;){ - v = l->key; - if(v < 2) - runtime·throw("bad lock key"); - if(runtime·cas(&l->key, v, v-2)) - break; - } - - goto again; -} - -static void -umtx_unlock(Lock *l) -{ - uint32 v; - -again: - v = l->key; - if((v&1) == 0) - runtime·throw("unlock of unlocked lock"); - if(!runtime·cas(&l->key, v, v&~1)) - goto again; - - if(v&~1) - umtx_wake(&l->key); -} - -void -runtime·lock(Lock *l) -{ - if(m->locks < 0) - runtime·throw("lock count"); - m->locks++; - umtx_lock(l); -} - -void -runtime·unlock(Lock *l) -{ - m->locks--; - if(m->locks < 0) - runtime·throw("lock count"); - umtx_unlock(l); -} - -// Event notifications. -void -runtime·noteclear(Note *n) -{ - n->lock.key = 0; - umtx_lock(&n->lock); -} - -void -runtime·notesleep(Note *n) -{ - umtx_lock(&n->lock); - umtx_unlock(&n->lock); -} - -void -runtime·notewakeup(Note *n) -{ - umtx_unlock(&n->lock); -} - void runtime·thr_start(void*); void @@ -157,6 +105,7 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) void runtime·osinit(void) { + runtime·ncpu = getncpu(); } void @@ -179,13 +128,19 @@ runtime·sigpanic(void) { switch(g->sig) { case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) + if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); runtime·panicstring("invalid memory address or nil pointer dereference"); + } runtime·printf("unexpected fault address %p\n", g->sigcode1); runtime·throw("fault"); case SIGSEGV: - if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) + if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); runtime·panicstring("invalid memory address or nil pointer dereference"); + } runtime·printf("unexpected fault address %p\n", g->sigcode1); runtime·throw("fault"); case SIGFPE: @@ -199,3 +154,9 @@ runtime·sigpanic(void) } runtime·panicstring(runtime·sigtab[g->sig].name); } + +// TODO: fill this in properly. +void +runtime·osyield(void) +{ +} diff --git a/src/pkg/runtime/linux/thread.c b/src/pkg/runtime/thread_linux.c index 4878a00f2..d18574145 100644 --- a/src/pkg/runtime/linux/thread.c +++ b/src/pkg/runtime/thread_linux.c @@ -3,12 +3,11 @@ // license that can be found in the LICENSE file. #include "runtime.h" -#include "defs.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" #include "stack.h" extern SigTab runtime·sigtab[]; -static int32 proccount; int32 runtime·open(uint8*, int32, int32); int32 runtime·close(int32); @@ -25,14 +24,6 @@ int32 runtime·read(int32, void*, int32); enum { - MUTEX_UNLOCKED = 0, - MUTEX_LOCKED = 1, - MUTEX_SLEEPING = 2, - - ACTIVE_SPIN = 4, - ACTIVE_SPIN_CNT = 30, - PASSIVE_SPIN = 1, - FUTEX_WAIT = 0, FUTEX_WAKE = 1, @@ -40,34 +31,37 @@ enum EAGAIN = 11, }; -// TODO(rsc): I tried using 1<<40 here but futex woke up (-ETIMEDOUT). -// I wonder if the timespec that gets to the kernel -// actually has two 32-bit numbers in it, so that -// a 64-bit 1<<40 ends up being 0 seconds, -// 1<<8 nanoseconds. -static Timespec longtime = -{ - 1<<30, // 34 years - 0 -}; - // Atomically, // if(*addr == val) sleep // Might be woken up spuriously; that's allowed. -static void -futexsleep(uint32 *addr, uint32 val) -{ +// Don't sleep longer than ns; ns < 0 means forever. +void +runtime·futexsleep(uint32 *addr, uint32 val, int64 ns) +{ + Timespec ts, *tsp; + + if(ns < 0) + tsp = nil; + else { + ts.tv_sec = ns/1000000000LL; + ts.tv_nsec = ns%1000000000LL; + // Avoid overflow + if(ts.tv_sec > 1<<30) + ts.tv_sec = 1<<30; + tsp = &ts; + } + // 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. - runtime·futex(addr, FUTEX_WAIT, val, &longtime, nil, 0); + runtime·futex(addr, FUTEX_WAIT, val, tsp, nil, 0); } // If any procs are sleeping on addr, wake up at most cnt. -static void -futexwakeup(uint32 *addr, uint32 cnt) +void +runtime·futexwakeup(uint32 *addr, uint32 cnt) { int64 ret; @@ -113,115 +107,6 @@ getproccount(void) return cnt ? cnt : 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. -static void -futexlock(Lock *l) -{ - uint32 i, v, wait, spin; - - // Speculative grab for lock. - v = runtime·xchg(&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; - - if(proccount == 0) - proccount = getproccount(); - - // On uniprocessor's, no point spinning. - // On multiprocessors, spin for ACTIVE_SPIN attempts. - spin = 0; - if(proccount > 1) - spin = ACTIVE_SPIN; - - for(;;) { - // Try for lock, spinning. - for(i = 0; i < spin; i++) { - while(l->key == MUTEX_UNLOCKED) - if(runtime·cas(&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(&l->key, MUTEX_UNLOCKED, wait)) - return; - runtime·osyield(); - } - - // Sleep. - v = runtime·xchg(&l->key, MUTEX_SLEEPING); - if(v == MUTEX_UNLOCKED) - return; - wait = MUTEX_SLEEPING; - futexsleep(&l->key, MUTEX_SLEEPING); - } -} - -static void -futexunlock(Lock *l) -{ - uint32 v; - - v = runtime·xchg(&l->key, MUTEX_UNLOCKED); - if(v == MUTEX_UNLOCKED) - runtime·throw("unlock of unlocked lock"); - if(v == MUTEX_SLEEPING) - futexwakeup(&l->key, 1); -} - -void -runtime·lock(Lock *l) -{ - if(m->locks++ < 0) - runtime·throw("runtime·lock: lock count"); - futexlock(l); -} - -void -runtime·unlock(Lock *l) -{ - if(--m->locks < 0) - runtime·throw("runtime·unlock: lock count"); - futexunlock(l); -} - - -// One-time notifications. -void -runtime·noteclear(Note *n) -{ - n->state = 0; -} - -void -runtime·notewakeup(Note *n) -{ - runtime·xchg(&n->state, 1); - futexwakeup(&n->state, 1<<30); -} - -void -runtime·notesleep(Note *n) -{ - while(runtime·atomicload(&n->state) == 0) - futexsleep(&n->state, 0); -} - - // Clone, the Linux rfork. enum { @@ -276,6 +161,7 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) void runtime·osinit(void) { + runtime·ncpu = getproccount(); } void @@ -298,13 +184,19 @@ runtime·sigpanic(void) { switch(g->sig) { case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) + if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + } runtime·panicstring("invalid memory address or nil pointer dereference"); runtime·printf("unexpected fault address %p\n", g->sigcode1); runtime·throw("fault"); case SIGSEGV: - if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) + if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); runtime·panicstring("invalid memory address or nil pointer dereference"); + } runtime·printf("unexpected fault address %p\n", g->sigcode1); runtime·throw("fault"); case SIGFPE: diff --git a/src/pkg/runtime/thread_netbsd.c b/src/pkg/runtime/thread_netbsd.c new file mode 100644 index 000000000..cba7adecf --- /dev/null +++ b/src/pkg/runtime/thread_netbsd.c @@ -0,0 +1,203 @@ +// Use of this source file is governed by a BSD-style +// license that can be found in the LICENSE file.` + +#include "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "stack.h" + +enum +{ + ESRCH = 3, + ENOTSUP = 91, + + // From NetBSD's sys/time.h + CLOCK_REALTIME = 0, + CLOCK_VIRTUAL = 1, + CLOCK_PROF = 2, + CLOCK_MONOTONIC = 3 +}; + +extern SigTab runtime·sigtab[]; + +extern int64 runtime·rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); +extern int32 runtime·thrsleep(void *ident, int32 clock_id, void *tsp, void *lock); +extern int32 runtime·thrwakeup(void *ident, int32 n); + +// From NetBSD's <sys/sysctl.h> +#define CTL_HW 6 +#define HW_NCPU 3 + +static int32 +getncpu(void) +{ + uint32 mib[2]; + uint32 out; + int32 ret; + uintptr nout; + + // Fetch hw.ncpu via sysctl. + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + nout = sizeof out; + out = 0; + ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); + if(ret >= 0) + return out; + else + return 1; +} + +uintptr +runtime·semacreate(void) +{ + return 1; +} + +int32 +runtime·semasleep(int64 ns) +{ + Timespec ts; + + // spin-mutex lock + while(runtime·xchg(&m->waitsemalock, 1)) + runtime·osyield(); + + for(;;) { + // lock held + if(m->waitsemacount == 0) { + // sleep until semaphore != 0 or timeout. + // thrsleep unlocks m->waitsemalock. + if(ns < 0) + runtime·thrsleep(&m->waitsemacount, 0, nil, &m->waitsemalock); + else { + ns += runtime·nanotime(); + ts.tv_sec = ns/1000000000LL; + ts.tv_nsec = ns%1000000000LL; + runtime·thrsleep(&m->waitsemacount, CLOCK_REALTIME, &ts, &m->waitsemalock); + } + // reacquire lock + while(runtime·xchg(&m->waitsemalock, 1)) + runtime·osyield(); + } + + // lock held (again) + if(m->waitsemacount != 0) { + // semaphore is available. + m->waitsemacount--; + // spin-mutex unlock + runtime·atomicstore(&m->waitsemalock, 0); + return 0; // semaphore acquired + } + + // semaphore not available. + // if there is a timeout, stop now. + // otherwise keep trying. + if(ns >= 0) + break; + } + + // lock held but giving up + // spin-mutex unlock + runtime·atomicstore(&m->waitsemalock, 0); + return -1; +} + +void +runtime·semawakeup(M *mp) +{ + uint32 ret; + + // spin-mutex lock + while(runtime·xchg(&mp->waitsemalock, 1)) + runtime·osyield(); + mp->waitsemacount++; + ret = runtime·thrwakeup(&mp->waitsemacount, 1); + if(ret != 0 && ret != ESRCH) + runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret); + // spin-mutex unlock + runtime·atomicstore(&mp->waitsemalock, 0); +} + +// From NetBSD's sys/param.h +#define RFPROC (1<<4) /* change child (else changes curproc) */ +#define RFMEM (1<<5) /* share `address space' */ +#define RFNOWAIT (1<<6) /* parent need not wait() on child */ +#define RFTHREAD (1<<13) /* create a thread, not a process */ + +void +runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) +{ + int32 flags; + int32 ret; + + flags = RFPROC | RFTHREAD | RFMEM | RFNOWAIT; + + if (0) { + runtime·printf( + "newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n", + stk, m, g, fn, m->id, m->tls[0], &m); + } + + m->tls[0] = m->id; // so 386 asm can find it + + if((ret = runtime·rfork_thread(flags, stk, m, g, fn)) < 0) { + runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret); + if (ret == -ENOTSUP) + runtime·printf("runtime: is kern.rthreads disabled?\n"); + runtime·throw("runtime.newosproc"); + } +} + +void +runtime·osinit(void) +{ + runtime·ncpu = getncpu(); +} + +void +runtime·goenvs(void) +{ + runtime·goenvs_unix(); +} + +// Called to initialize a new m (including the bootstrap m). +void +runtime·minit(void) +{ + // Initialize signal handling + m->gsignal = runtime·malg(32*1024); + runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024); +} + +void +runtime·sigpanic(void) +{ + switch(g->sig) { + case SIGBUS: + if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + runtime·panicstring("invalid memory address or nil pointer dereference"); + } + runtime·printf("unexpected fault address %p\n", g->sigcode1); + runtime·throw("fault"); + case SIGSEGV: + if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + runtime·panicstring("invalid memory address or nil pointer dereference"); + } + runtime·printf("unexpected fault address %p\n", g->sigcode1); + runtime·throw("fault"); + case SIGFPE: + switch(g->sigcode0) { + case FPE_INTDIV: + runtime·panicstring("integer divide by zero"); + case FPE_INTOVF: + runtime·panicstring("integer overflow"); + } + runtime·panicstring("floating point error"); + } + runtime·panicstring(runtime·sigtab[g->sig].name); +} diff --git a/src/pkg/runtime/thread_openbsd.c b/src/pkg/runtime/thread_openbsd.c new file mode 100644 index 000000000..efe03e371 --- /dev/null +++ b/src/pkg/runtime/thread_openbsd.c @@ -0,0 +1,203 @@ +// Use of this source file is governed by a BSD-style +// license that can be found in the LICENSE file.` + +#include "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "stack.h" + +enum +{ + ESRCH = 3, + ENOTSUP = 91, + + // From OpenBSD's sys/time.h + CLOCK_REALTIME = 0, + CLOCK_VIRTUAL = 1, + CLOCK_PROF = 2, + CLOCK_MONOTONIC = 3 +}; + +extern SigTab runtime·sigtab[]; + +extern int64 runtime·rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); +extern int32 runtime·thrsleep(void *ident, int32 clock_id, void *tsp, void *lock); +extern int32 runtime·thrwakeup(void *ident, int32 n); + +// From OpenBSD's <sys/sysctl.h> +#define CTL_HW 6 +#define HW_NCPU 3 + +static int32 +getncpu(void) +{ + uint32 mib[2]; + uint32 out; + int32 ret; + uintptr nout; + + // Fetch hw.ncpu via sysctl. + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + nout = sizeof out; + out = 0; + ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); + if(ret >= 0) + return out; + else + return 1; +} + +uintptr +runtime·semacreate(void) +{ + return 1; +} + +int32 +runtime·semasleep(int64 ns) +{ + Timespec ts; + + // spin-mutex lock + while(runtime·xchg(&m->waitsemalock, 1)) + runtime·osyield(); + + for(;;) { + // lock held + if(m->waitsemacount == 0) { + // sleep until semaphore != 0 or timeout. + // thrsleep unlocks m->waitsemalock. + if(ns < 0) + runtime·thrsleep(&m->waitsemacount, 0, nil, &m->waitsemalock); + else { + ns += runtime·nanotime(); + ts.tv_sec = ns/1000000000LL; + ts.tv_nsec = ns%1000000000LL; + runtime·thrsleep(&m->waitsemacount, CLOCK_REALTIME, &ts, &m->waitsemalock); + } + // reacquire lock + while(runtime·xchg(&m->waitsemalock, 1)) + runtime·osyield(); + } + + // lock held (again) + if(m->waitsemacount != 0) { + // semaphore is available. + m->waitsemacount--; + // spin-mutex unlock + runtime·atomicstore(&m->waitsemalock, 0); + return 0; // semaphore acquired + } + + // semaphore not available. + // if there is a timeout, stop now. + // otherwise keep trying. + if(ns >= 0) + break; + } + + // lock held but giving up + // spin-mutex unlock + runtime·atomicstore(&m->waitsemalock, 0); + return -1; +} + +void +runtime·semawakeup(M *mp) +{ + uint32 ret; + + // spin-mutex lock + while(runtime·xchg(&mp->waitsemalock, 1)) + runtime·osyield(); + mp->waitsemacount++; + ret = runtime·thrwakeup(&mp->waitsemacount, 1); + if(ret != 0 && ret != ESRCH) + runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret); + // spin-mutex unlock + runtime·atomicstore(&mp->waitsemalock, 0); +} + +// From OpenBSD's sys/param.h +#define RFPROC (1<<4) /* change child (else changes curproc) */ +#define RFMEM (1<<5) /* share `address space' */ +#define RFNOWAIT (1<<6) /* parent need not wait() on child */ +#define RFTHREAD (1<<13) /* create a thread, not a process */ + +void +runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) +{ + int32 flags; + int32 ret; + + flags = RFPROC | RFTHREAD | RFMEM | RFNOWAIT; + + if (0) { + runtime·printf( + "newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n", + stk, m, g, fn, m->id, m->tls[0], &m); + } + + m->tls[0] = m->id; // so 386 asm can find it + + if((ret = runtime·rfork_thread(flags, stk, m, g, fn)) < 0) { + runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret); + if (ret == -ENOTSUP) + runtime·printf("runtime: is kern.rthreads disabled?\n"); + runtime·throw("runtime.newosproc"); + } +} + +void +runtime·osinit(void) +{ + runtime·ncpu = getncpu(); +} + +void +runtime·goenvs(void) +{ + runtime·goenvs_unix(); +} + +// Called to initialize a new m (including the bootstrap m). +void +runtime·minit(void) +{ + // Initialize signal handling + m->gsignal = runtime·malg(32*1024); + runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024); +} + +void +runtime·sigpanic(void) +{ + switch(g->sig) { + case SIGBUS: + if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + runtime·panicstring("invalid memory address or nil pointer dereference"); + } + runtime·printf("unexpected fault address %p\n", g->sigcode1); + runtime·throw("fault"); + case SIGSEGV: + if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + runtime·panicstring("invalid memory address or nil pointer dereference"); + } + runtime·printf("unexpected fault address %p\n", g->sigcode1); + runtime·throw("fault"); + case SIGFPE: + switch(g->sigcode0) { + case FPE_INTDIV: + runtime·panicstring("integer divide by zero"); + case FPE_INTOVF: + runtime·panicstring("integer overflow"); + } + runtime·panicstring("floating point error"); + } + runtime·panicstring(runtime·sigtab[g->sig].name); +} diff --git a/src/pkg/runtime/thread_plan9.c b/src/pkg/runtime/thread_plan9.c new file mode 100644 index 000000000..a9b156d02 --- /dev/null +++ b/src/pkg/runtime/thread_plan9.c @@ -0,0 +1,237 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" +#include "os_GOOS.h" +#include "arch_GOARCH.h" + +int8 *goos = "plan9"; + +void +runtime·minit(void) +{ +} + +static int32 +getproccount(void) +{ + int32 fd, i, n, ncpu; + byte buf[2048]; + + fd = runtime·open((byte*)"/dev/sysstat", OREAD); + if(fd < 0) + return 1; + ncpu = 0; + for(;;) { + n = runtime·read(fd, buf, sizeof buf); + if(n <= 0) + break; + for(i = 0; i < n; i++) { + if(buf[i] == '\n') + ncpu++; + } + } + runtime·close(fd); + return ncpu > 0 ? ncpu : 1; +} + +void +runtime·osinit(void) +{ + runtime·ncpu = getproccount(); +} + +void +runtime·goenvs(void) +{ +} + +void +runtime·initsig(int32) +{ +} + +void +runtime·osyield(void) +{ + runtime·sleep(0); +} + +void +runtime·usleep(uint32 µs) +{ + uint32 ms; + + ms = µs/1000; + if(ms == 0) + ms = 1; + runtime·sleep(ms); +} + +int64 +runtime·nanotime(void) +{ + static int32 fd = -1; + byte b[8]; + uint32 hi, lo; + + // As long as all goroutines share the same file + // descriptor table we can get away with using + // just a static fd. Without a lock the file can + // be opened twice but that's okay. + // + // Using /dev/bintime gives us a latency on the + // order of ten microseconds between two calls. + // + // The naïve implementation (without the cached + // file descriptor) is roughly four times slower + // in 9vx on a 2.16 GHz Intel Core 2 Duo. + + if(fd < 0 && (fd = runtime·open((byte*)"/dev/bintime", OREAD|OCEXEC)) < 0) + return 0; + if(runtime·pread(fd, b, sizeof b, 0) != sizeof b) + return 0; + hi = b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3]; + lo = b[4]<<24 | b[5]<<16 | b[6]<<8 | b[7]; + return (int64)hi<<32 | (int64)lo; +} + +void +time·now(int64 sec, int32 nsec) +{ + int64 ns; + + ns = runtime·nanotime(); + sec = ns / 1000000000LL; + nsec = ns - sec * 1000000000LL; + FLUSH(&sec); + FLUSH(&nsec); +} + +extern Tos *_tos; +void +runtime·exit(int32) +{ + int32 fd; + uint8 buf[128]; + uint8 tmp[16]; + uint8 *p, *q; + int32 pid; + + runtime·memclr(buf, sizeof buf); + runtime·memclr(tmp, sizeof tmp); + pid = _tos->pid; + + /* build path string /proc/pid/notepg */ + for(q=tmp; pid > 0;) { + *q++ = '0' + (pid%10); + pid = pid/10; + } + p = buf; + runtime·memmove((void*)p, (void*)"/proc/", 6); + p += 6; + for(q--; q >= tmp;) + *p++ = *q--; + runtime·memmove((void*)p, (void*)"/notepg", 7); + + /* post interrupt note */ + fd = runtime·open(buf, OWRITE); + runtime·write(fd, "interrupt", 9); + runtime·exits(nil); +} + +void +runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) +{ + m->tls[0] = m->id; // so 386 asm can find it + if(0){ + runtime·printf("newosproc stk=%p m=%p g=%p fn=%p rfork=%p id=%d/%d ostk=%p\n", + stk, m, g, fn, runtime·rfork, m->id, m->tls[0], &m); + } + + if(runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, m, g, fn) < 0) + runtime·throw("newosproc: rfork failed"); +} + +uintptr +runtime·semacreate(void) +{ + return 1; +} + +int32 +runtime·semasleep(int64 ns) +{ + int32 ret; + int32 ms; + + if(ns >= 0) { + // TODO: Plan 9 needs a new system call, tsemacquire. + // The kernel implementation is the same as semacquire + // except with a tsleep and check for timeout. + // It would be great if the implementation returned the + // value that was added to the semaphore, so that on + // timeout the return value would be 0, on success 1. + // Then the error string does not have to be parsed + // to detect timeout. + // + // If a negative time indicates no timeout, then + // semacquire can be implemented (in the kernel) + // as tsemacquire(p, v, -1). + runtime·throw("semasleep: timed sleep not implemented on Plan 9"); + + /* + if(ns < 0) + ms = -1; + else if(ns/1000 > 0x7fffffffll) + ms = 0x7fffffff; + else + ms = ns/1000; + ret = runtime·plan9_tsemacquire(&m->waitsemacount, 1, ms); + if(ret == 1) + return 0; // success + return -1; // timeout or interrupted + */ + } + + while(runtime·plan9_semacquire(&m->waitsemacount, 1) < 0) { + /* interrupted; try again */ + } + return 0; // success +} + +void +runtime·semawakeup(M *mp) +{ + runtime·plan9_semrelease(&mp->waitsemacount, 1); +} + +void +os·sigpipe(void) +{ + runtime·throw("too many writes on closed pipe"); +} + +/* + * placeholder - once notes are implemented, + * a signal generating a panic must appear as + * a call to this function for correct handling by + * traceback. + */ +void +runtime·sigpanic(void) +{ +} + +int32 +runtime·read(int32 fd, void *buf, int32 nbytes) +{ + return runtime·pread(fd, buf, nbytes, -1LL); +} + +int32 +runtime·write(int32 fd, void *buf, int32 nbytes) +{ + return runtime·pwrite(fd, buf, nbytes, -1LL); +} diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/thread_windows.c index 97a42d73a..516d1d0d1 100644 --- a/src/pkg/runtime/windows/thread.c +++ b/src/pkg/runtime/thread_windows.c @@ -4,8 +4,8 @@ #include "runtime.h" #include "type.h" -#include "defs.h" -#include "os.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" #pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll" #pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll" @@ -17,15 +17,16 @@ #pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll" #pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll" #pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll" +#pragma dynimport runtime·GetSystemInfo GetSystemInfo "kernel32.dll" +#pragma dynimport runtime·GetSystemTimeAsFileTime GetSystemTimeAsFileTime "kernel32.dll" #pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll" -#pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll" -#pragma dynimport runtime·QueryPerformanceCounter QueryPerformanceCounter "kernel32.dll" -#pragma dynimport runtime·QueryPerformanceFrequency QueryPerformanceFrequency "kernel32.dll" +#pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll" #pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll" #pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll" #pragma dynimport runtime·SetEvent SetEvent "kernel32.dll" #pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll" #pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll" +#pragma dynimport runtime·Sleep Sleep "kernel32.dll" #pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll" #pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll" #pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll" @@ -41,21 +42,29 @@ extern void *runtime·FreeEnvironmentStringsW; extern void *runtime·GetEnvironmentStringsW; extern void *runtime·GetProcAddress; extern void *runtime·GetStdHandle; +extern void *runtime·GetSystemInfo; +extern void *runtime·GetSystemTimeAsFileTime; extern void *runtime·GetThreadContext; -extern void *runtime·LoadLibraryEx; -extern void *runtime·QueryPerformanceCounter; -extern void *runtime·QueryPerformanceFrequency; +extern void *runtime·LoadLibrary; extern void *runtime·ResumeThread; extern void *runtime·SetConsoleCtrlHandler; extern void *runtime·SetEvent; extern void *runtime·SetThreadPriority; extern void *runtime·SetWaitableTimer; +extern void *runtime·Sleep; extern void *runtime·SuspendThread; extern void *runtime·timeBeginPeriod; extern void *runtime·WaitForSingleObject; extern void *runtime·WriteFile; -static int64 timerfreq; +static int32 +getproccount(void) +{ + SystemInfo info; + + runtime·stdcall(runtime·GetSystemInfo, 1, &info); + return info.dwNumberOfProcessors; +} void runtime·osinit(void) @@ -64,15 +73,15 @@ runtime·osinit(void) runtime·stdcall(runtime·DuplicateHandle, 7, (uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread, (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS); - runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq); runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1); runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1); + runtime·ncpu = getproccount(); } void runtime·goenvs(void) { - extern Slice os·Envs; + extern Slice syscall·envs; uint16 *env; String *s; @@ -92,9 +101,9 @@ runtime·goenvs(void) s[i] = runtime·gostringw(p); p += runtime·findnullw(p)+1; } - os·Envs.array = (byte*)s; - os·Envs.len = n; - os·Envs.cap = n; + syscall·envs.array = (byte*)s; + syscall·envs.len = n; + syscall·envs.cap = n; runtime·stdcall(runtime·FreeEnvironmentStringsW, 1, env); } @@ -126,103 +135,56 @@ runtime·write(int32 fd, void *buf, int32 n) return written; } -// Thread-safe allocation of an event. -static void -initevent(void **pevent) -{ - void *event; - - event = runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0); - if(!runtime·casp(pevent, 0, event)) { - // Someone else filled it in. Use theirs. - runtime·stdcall(runtime·CloseHandle, 1, event); - } -} - -#define LOCK_HELD ((M*)-1) - -static void -eventlock(Lock *l) -{ - // Allocate event if needed. - if(m->event == nil) - initevent(&m->event); - - for(;;) { - m->nextwaitm = runtime·atomicloadp(&l->waitm); - if(m->nextwaitm == nil) { - if(runtime·casp(&l->waitm, nil, LOCK_HELD)) - return; - // 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. - } else if(runtime·casp(&l->waitm, m->nextwaitm, m)) - break; - } - - // Wait. - runtime·stdcall(runtime·WaitForSingleObject, 2, m->event, (uintptr)-1); -} - -static void -eventunlock(Lock *l) -{ - M *mp; - - for(;;) { - mp = runtime·atomicloadp(&l->waitm); - if(mp == LOCK_HELD) { - if(runtime·casp(&l->waitm, LOCK_HELD, nil)) - return; - // Other M's are waiting for the lock. - // Dequeue a M. - } else if(runtime·casp(&l->waitm, mp, mp->nextwaitm)) - break; - } - - // Wake that M. - runtime·stdcall(runtime·SetEvent, 1, mp->event); -} - void -runtime·lock(Lock *l) +runtime·osyield(void) { - if(m->locks < 0) - runtime·throw("lock count"); - m->locks++; - eventlock(l); + runtime·stdcall(runtime·Sleep, 1, (uintptr)0); } void -runtime·unlock(Lock *l) +runtime·usleep(uint32 us) { - m->locks--; - if(m->locks < 0) - runtime·throw("lock count"); - eventunlock(l); + us /= 1000; + if(us == 0) + us = 1; + runtime·stdcall(runtime·Sleep, 1, (uintptr)us); } -void -runtime·noteclear(Note *n) +#define INFINITE ((uintptr)0xFFFFFFFF) + +int32 +runtime·semasleep(int64 ns) { - n->lock.waitm = nil; - eventlock(&n->lock); + uintptr ms; + + if(ns < 0) + ms = INFINITE; + else if(ns/1000000 > 0x7fffffffLL) + ms = 0x7fffffff; + else { + ms = ns/1000000; + if(ms == 0) + ms = 1; + } + if(runtime·stdcall(runtime·WaitForSingleObject, 2, m->waitsema, ms) != 0) + return -1; // timeout + return 0; } void -runtime·notewakeup(Note *n) +runtime·semawakeup(M *mp) { - eventunlock(&n->lock); + runtime·stdcall(runtime·SetEvent, 1, mp->waitsema); } -void -runtime·notesleep(Note *n) +uintptr +runtime·semacreate(void) { - eventlock(&n->lock); - eventunlock(&n->lock); // Let other sleepers find out too. + return (uintptr)runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0); } +#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000) + void runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) { @@ -233,7 +195,8 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) USED(fn); // assuming fn = mstart thandle = runtime·stdcall(runtime·CreateThread, 6, - nil, nil, runtime·tstart_stdcall, m, nil, nil); + nil, (uintptr)0x20000, runtime·tstart_stdcall, m, + STACK_SIZE_PARAM_IS_A_RESERVATION, nil); if(thandle == nil) { runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror()); runtime·throw("runtime.newosproc"); @@ -247,15 +210,28 @@ runtime·minit(void) { } -void -runtime·gettime(int64 *sec, int32 *usec) +int64 +runtime·nanotime(void) { - int64 count; + int64 filetime; + + runtime·stdcall(runtime·GetSystemTimeAsFileTime, 1, &filetime); - runtime·stdcall(runtime·QueryPerformanceCounter, 1, &count); - *sec = count / timerfreq; - count %= timerfreq; - *usec = count*1000000 / timerfreq; + // Filetime is 100s of nanoseconds since January 1, 1601. + // Convert to nanoseconds since January 1, 1970. + return (filetime - 116444736000000000LL) * 100LL; +} + +void +time·now(int64 sec, int32 usec) +{ + int64 ns; + + ns = runtime·nanotime(); + sec = ns / 1000000000LL; + usec = ns - sec * 1000000000LL; + FLUSH(&sec); + FLUSH(&usec); } // Calling stdcall on os stack. @@ -294,8 +270,11 @@ runtime·sigpanic(void) { switch(g->sig) { case EXCEPTION_ACCESS_VIOLATION: - if(g->sigcode1 < 0x1000) + if(g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); runtime·panicstring("invalid memory address or nil pointer dereference"); + } runtime·printf("unexpected fault address %p\n", g->sigcode1); runtime·throw("fault"); case EXCEPTION_INT_DIVIDE_BY_ZERO: diff --git a/src/pkg/runtime/time.goc b/src/pkg/runtime/time.goc new file mode 100644 index 000000000..a6b835247 --- /dev/null +++ b/src/pkg/runtime/time.goc @@ -0,0 +1,253 @@ +// 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. + +// Time-related runtime and pieces of package time. + +package time + +#include "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "arch_GOARCH.h" +#include "malloc.h" + +static Timers timers; +static void addtimer(Timer*); +static bool deltimer(Timer*); + +// Package time APIs. +// Godoc uses the comments in package time, not these. + +// time.now is implemented in assembly. + +// Sleep puts the current goroutine to sleep for at least ns nanoseconds. +func Sleep(ns int64) { + g->status = Gwaiting; + g->waitreason = "sleep"; + runtime·tsleep(ns); +} + +// startTimer adds t to the timer heap. +func startTimer(t *Timer) { + addtimer(t); +} + +// stopTimer removes t from the timer heap if it is there. +// It returns true if t was removed, false if t wasn't even there. +func stopTimer(t *Timer) (stopped bool) { + stopped = deltimer(t); +} + +// C runtime. + +static void timerproc(void); +static void siftup(int32); +static void siftdown(int32); + +// Ready the goroutine e.data. +static void +ready(int64 now, Eface e) +{ + USED(now); + + runtime·ready(e.data); +} + +// Put the current goroutine to sleep for ns nanoseconds. +// The caller must have set g->status and g->waitreason. +void +runtime·tsleep(int64 ns) +{ + Timer t; + + if(ns <= 0) + return; + + t.when = runtime·nanotime() + ns; + t.period = 0; + t.f = ready; + t.arg.data = g; + addtimer(&t); + runtime·gosched(); +} + +// Add a timer to the heap and start or kick the timer proc +// if the new timer is earlier than any of the others. +static void +addtimer(Timer *t) +{ + int32 n; + Timer **nt; + + runtime·lock(&timers); + if(timers.len >= timers.cap) { + // Grow slice. + n = 16; + if(n <= timers.cap) + n = timers.cap*3 / 2; + nt = runtime·malloc(n*sizeof nt[0]); + runtime·memmove(nt, timers.t, timers.len*sizeof nt[0]); + runtime·free(timers.t); + timers.t = nt; + timers.cap = n; + } + t->i = timers.len++; + timers.t[t->i] = t; + siftup(t->i); + if(t->i == 0) { + // siftup moved to top: new earliest deadline. + if(timers.sleeping) { + timers.sleeping = false; + runtime·notewakeup(&timers.waitnote); + } + if(timers.rescheduling) { + timers.rescheduling = false; + runtime·ready(timers.timerproc); + } + } + if(timers.timerproc == nil) + timers.timerproc = runtime·newproc1((byte*)timerproc, nil, 0, 0, addtimer); + runtime·unlock(&timers); +} + +// Delete timer t from the heap. +// Do not need to update the timerproc: +// if it wakes up early, no big deal. +static bool +deltimer(Timer *t) +{ + int32 i; + + runtime·lock(&timers); + + // t may not be registered anymore and may have + // a bogus i (typically 0, if generated by Go). + // Verify it before proceeding. + i = t->i; + if(i < 0 || i >= timers.len || timers.t[i] != t) { + runtime·unlock(&timers); + return false; + } + + timers.len--; + if(i == timers.len) { + timers.t[i] = nil; + } else { + timers.t[i] = timers.t[timers.len]; + timers.t[timers.len] = nil; + timers.t[i]->i = i; + siftup(i); + siftdown(i); + } + runtime·unlock(&timers); + return true; +} + +// Timerproc runs the time-driven events. +// It sleeps until the next event in the timers heap. +// If addtimer inserts a new earlier event, addtimer +// wakes timerproc early. +static void +timerproc(void) +{ + int64 delta, now; + Timer *t; + void (*f)(int64, Eface); + Eface arg; + + for(;;) { + runtime·lock(&timers); + now = runtime·nanotime(); + for(;;) { + if(timers.len == 0) { + delta = -1; + break; + } + t = timers.t[0]; + delta = t->when - now; + if(delta > 0) + break; + if(t->period > 0) { + // leave in heap but adjust next time to fire + t->when += t->period * (1 + -delta/t->period); + siftdown(0); + } else { + // remove from heap + timers.t[0] = timers.t[--timers.len]; + timers.t[0]->i = 0; + siftdown(0); + t->i = -1; // mark as removed + } + f = t->f; + arg = t->arg; + runtime·unlock(&timers); + f(now, arg); + runtime·lock(&timers); + } + if(delta < 0) { + // No timers left - put goroutine to sleep. + timers.rescheduling = true; + g->status = Gwaiting; + g->waitreason = "timer goroutine (idle)"; + runtime·unlock(&timers); + runtime·gosched(); + continue; + } + // At least one timer pending. Sleep until then. + timers.sleeping = true; + runtime·noteclear(&timers.waitnote); + runtime·unlock(&timers); + runtime·entersyscall(); + runtime·notetsleep(&timers.waitnote, delta); + runtime·exitsyscall(); + } +} + +// heap maintenance algorithms. + +static void +siftup(int32 i) +{ + int32 p; + Timer **t, *tmp; + + t = timers.t; + while(i > 0) { + p = (i-1)/2; // parent + if(t[i]->when >= t[p]->when) + break; + tmp = t[i]; + t[i] = t[p]; + t[p] = tmp; + t[i]->i = i; + t[p]->i = p; + i = p; + } +} + +static void +siftdown(int32 i) +{ + int32 c, len; + Timer **t, *tmp; + + t = timers.t; + len = timers.len; + for(;;) { + c = i*2 + 1; // left child + if(c >= len) { + break; + } + if(c+1 < len && t[c+1]->when < t[c]->when) + c++; + if(t[c]->when >= t[i]->when) + break; + tmp = t[i]; + t[i] = t[c]; + t[c] = tmp; + t[i]->i = i; + t[c]->i = c; + i = c; + } +} diff --git a/src/pkg/runtime/arm/traceback.c b/src/pkg/runtime/traceback_arm.c index 63528104c..22e0bc3a6 100644 --- a/src/pkg/runtime/arm/traceback.c +++ b/src/pkg/runtime/traceback_arm.c @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" void runtime·deferproc(void); diff --git a/src/pkg/runtime/amd64/traceback.c b/src/pkg/runtime/traceback_x86.c index c03a6f7cc..be35bab00 100644 --- a/src/pkg/runtime/amd64/traceback.c +++ b/src/pkg/runtime/traceback_x86.c @@ -2,7 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build amd64 386 + #include "runtime.h" +#include "arch_GOARCH.h" #include "malloc.h" static uintptr isclosureentry(uintptr); diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go index 30f3ec642..1e0d723bd 100644 --- a/src/pkg/runtime/type.go +++ b/src/pkg/runtime/type.go @@ -27,15 +27,16 @@ type Type interface{} // All types begin with a few common fields needed for // the interface runtime. type commonType struct { - size uintptr // size in bytes - hash uint32 // hash of type; avoids computation in hash tables - alg uint8 // algorithm for copy+hash+cmp (../runtime/runtime.h:/AMEM) - align uint8 // alignment of variable with this type - fieldAlign uint8 // alignment of struct field with this type - kind uint8 // enumeration for C - string *string // string form; unnecessary but undeniably useful - *uncommonType // (relatively) uncommon fields - ptrToThis *Type // pointer to this type, if used in binary or has methods + size uintptr // size in bytes + hash uint32 // hash of type; avoids computation in hash tables + _ uint8 // unused + align uint8 // alignment of variable with this type + fieldAlign uint8 // alignment of struct field with this type + kind uint8 // enumeration for C + alg *uintptr // algorithm table (../runtime/runtime.h:/Alg) + string *string // string form; unnecessary but undeniably useful + *uncommonType // (relatively) uncommon fields + ptrToThis *Type // pointer to this type, if used in binary or has methods } // Values for commonType.kind. diff --git a/src/pkg/runtime/type.h b/src/pkg/runtime/type.h index 8c80c62d3..c1d9facd1 100644 --- a/src/pkg/runtime/type.h +++ b/src/pkg/runtime/type.h @@ -23,10 +23,11 @@ struct CommonType { uintptr size; uint32 hash; - uint8 alg; + uint8 _unused; uint8 align; uint8 fieldAlign; uint8 kind; + Alg *alg; String *string; UncommonType *x; Type *ptrto; diff --git a/src/pkg/runtime/386/vlop.s b/src/pkg/runtime/vlop_386.s index 28f6da82d..28f6da82d 100644 --- a/src/pkg/runtime/386/vlop.s +++ b/src/pkg/runtime/vlop_386.s diff --git a/src/pkg/runtime/arm/vlop.s b/src/pkg/runtime/vlop_arm.s index fc679f0ee..fc679f0ee 100644 --- a/src/pkg/runtime/arm/vlop.s +++ b/src/pkg/runtime/vlop_arm.s diff --git a/src/pkg/runtime/386/vlrt.c b/src/pkg/runtime/vlrt_386.c index 1631dbe10..1631dbe10 100644 --- a/src/pkg/runtime/386/vlrt.c +++ b/src/pkg/runtime/vlrt_386.c diff --git a/src/pkg/runtime/arm/vlrt.c b/src/pkg/runtime/vlrt_arm.c index 50f33710b..50f33710b 100644 --- a/src/pkg/runtime/arm/vlrt.c +++ b/src/pkg/runtime/vlrt_arm.c diff --git a/src/pkg/runtime/windows/defs.c b/src/pkg/runtime/windows/defs.c deleted file mode 100644 index 1b07dfbc1..000000000 --- a/src/pkg/runtime/windows/defs.c +++ /dev/null @@ -1,48 +0,0 @@ -// 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. - -#include <signal.h> -#include <stdarg.h> -#include <windef.h> -#include <winbase.h> -#include <wincon.h> - -enum { - $PROT_NONE = 0, - $PROT_READ = 1, - $PROT_WRITE = 2, - $PROT_EXEC = 4, - - $MAP_ANON = 1, - $MAP_PRIVATE = 2, - - $DUPLICATE_SAME_ACCESS = DUPLICATE_SAME_ACCESS, - $THREAD_PRIORITY_HIGHEST = THREAD_PRIORITY_HIGHEST, - - $SIGINT = SIGINT, - $CTRL_C_EVENT = CTRL_C_EVENT, - $CTRL_BREAK_EVENT = CTRL_BREAK_EVENT, - - $CONTEXT_CONTROL = CONTEXT_CONTROL, - $CONTEXT_FULL = CONTEXT_FULL, - - $EXCEPTION_ACCESS_VIOLATION = STATUS_ACCESS_VIOLATION, - $EXCEPTION_BREAKPOINT = STATUS_BREAKPOINT, - $EXCEPTION_FLT_DENORMAL_OPERAND = STATUS_FLOAT_DENORMAL_OPERAND, - $EXCEPTION_FLT_DIVIDE_BY_ZERO = STATUS_FLOAT_DIVIDE_BY_ZERO, - $EXCEPTION_FLT_INEXACT_RESULT = STATUS_FLOAT_INEXACT_RESULT, - $EXCEPTION_FLT_OVERFLOW = STATUS_FLOAT_OVERFLOW, - $EXCEPTION_FLT_UNDERFLOW = STATUS_FLOAT_UNDERFLOW, - $EXCEPTION_INT_DIVIDE_BY_ZERO = STATUS_INTEGER_DIVIDE_BY_ZERO, - $EXCEPTION_INT_OVERFLOW = STATUS_INTEGER_OVERFLOW, -}; - -typedef EXCEPTION_RECORD $ExceptionRecord; -#ifdef _X86_ -typedef FLOATING_SAVE_AREA $FloatingSaveArea; -#endif -#ifdef _AMD64_ -typedef M128A $M128a; -#endif -typedef CONTEXT $Context; |