diff options
Diffstat (limited to 'libgo')
28 files changed, 1520 insertions, 818 deletions
diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 23cfd07ba94..e5150693fab 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -396,9 +396,9 @@ rtems_task_variable_add_file = endif if LIBGO_IS_LINUX -runtime_lock_files = runtime/lock_futex.c runtime/thread-linux.c +runtime_thread_files = runtime/thread-linux.c else -runtime_lock_files = runtime/lock_sema.c runtime/thread-sema.c +runtime_thread_files = runtime/thread-sema.c endif if LIBGO_IS_LINUX @@ -502,7 +502,6 @@ runtime_files = \ runtime/go-varargs.c \ runtime/env_posix.c \ runtime/heapdump.c \ - $(runtime_lock_files) \ runtime/mcache.c \ runtime/mcentral.c \ $(runtime_mem_file) \ @@ -518,6 +517,7 @@ runtime_files = \ runtime/runtime.c \ runtime/signal_unix.c \ runtime/thread.c \ + $(runtime_thread_files) \ runtime/yield.c \ $(rtems_task_variable_add_file) \ chan.c \ @@ -633,12 +633,8 @@ s-version: Makefile $(STAMP) $@ runtime_sysinfo.go: s-runtime_sysinfo; @true -s-runtime_sysinfo: sysinfo.go - rm -f tmp-runtime_sysinfo.go - echo 'package runtime' > tmp-runtime_sysinfo.go - echo >> tmp-runtime_sysinfo.go - grep 'const _sizeof_ucontext_t ' sysinfo.go >> tmp-runtime_sysinfo.go - grep 'type _sigset_t ' sysinfo.go >> tmp-runtime_sysinfo.go +s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go + $(SHELL) $(srcdir)/mkrsysinfo.sh $(SHELL) $(srcdir)/mvifdiff.sh tmp-runtime_sysinfo.go runtime_sysinfo.go $(STAMP) $@ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index b1fb87c900d..bc6832dce0f 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -223,13 +223,13 @@ am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) \ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) libgo_llgo_la_DEPENDENCIES = $(am__DEPENDENCIES_3) -@LIBGO_IS_LINUX_FALSE@am__objects_1 = lock_sema.lo thread-sema.lo -@LIBGO_IS_LINUX_TRUE@am__objects_1 = lock_futex.lo thread-linux.lo -@HAVE_SYS_MMAN_H_FALSE@am__objects_2 = mem_posix_memalign.lo -@HAVE_SYS_MMAN_H_TRUE@am__objects_2 = mem.lo -@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_3 = netpoll_kqueue.lo -@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_3 = netpoll_select.lo -@LIBGO_IS_LINUX_TRUE@am__objects_3 = netpoll_epoll.lo +@HAVE_SYS_MMAN_H_FALSE@am__objects_1 = mem_posix_memalign.lo +@HAVE_SYS_MMAN_H_TRUE@am__objects_1 = mem.lo +@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_2 = netpoll_kqueue.lo +@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_2 = netpoll_select.lo +@LIBGO_IS_LINUX_TRUE@am__objects_2 = netpoll_epoll.lo +@LIBGO_IS_LINUX_FALSE@am__objects_3 = thread-sema.lo +@LIBGO_IS_LINUX_TRUE@am__objects_3 = thread-linux.lo @LIBGO_IS_RTEMS_TRUE@am__objects_4 = rtems-task-variable-add.lo @LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_5 = getncpu-none.lo @LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@am__objects_5 = getncpu-bsd.lo @@ -259,13 +259,13 @@ am__objects_6 = go-append.lo go-assert.lo go-assert-interface.lo \ go-type-identity.lo go-type-interface.lo go-type-string.lo \ go-typedesc-equal.lo go-unsafe-new.lo go-unsafe-newarray.lo \ go-unsafe-pointer.lo go-unsetenv.lo go-unwind.lo go-varargs.lo \ - env_posix.lo heapdump.lo $(am__objects_1) mcache.lo \ - mcentral.lo $(am__objects_2) mfixalloc.lo mgc0.lo mheap.lo \ - msize.lo $(am__objects_3) panic.lo parfor.lo print.lo proc.lo \ - runtime.lo signal_unix.lo thread.lo yield.lo $(am__objects_4) \ - chan.lo cpuprof.lo go-iface.lo lfstack.lo malloc.lo mprof.lo \ - netpoll.lo rdebug.lo reflect.lo runtime1.lo sema.lo \ - sigqueue.lo string.lo time.lo $(am__objects_5) + env_posix.lo heapdump.lo mcache.lo mcentral.lo \ + $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo msize.lo \ + $(am__objects_2) panic.lo parfor.lo print.lo proc.lo \ + runtime.lo signal_unix.lo thread.lo $(am__objects_3) yield.lo \ + $(am__objects_4) chan.lo cpuprof.lo go-iface.lo lfstack.lo \ + malloc.lo mprof.lo netpoll.lo rdebug.lo reflect.lo runtime1.lo \ + sema.lo sigqueue.lo string.lo time.lo $(am__objects_5) am_libgo_llgo_la_OBJECTS = $(am__objects_6) libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS) libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -826,8 +826,8 @@ toolexeclibgounicode_DATA = \ @HAVE_SYS_MMAN_H_TRUE@runtime_mem_file = runtime/mem.c @LIBGO_IS_RTEMS_FALSE@rtems_task_variable_add_file = @LIBGO_IS_RTEMS_TRUE@rtems_task_variable_add_file = runtime/rtems-task-variable-add.c -@LIBGO_IS_LINUX_FALSE@runtime_lock_files = runtime/lock_sema.c runtime/thread-sema.c -@LIBGO_IS_LINUX_TRUE@runtime_lock_files = runtime/lock_futex.c runtime/thread-linux.c +@LIBGO_IS_LINUX_FALSE@runtime_thread_files = runtime/thread-sema.c +@LIBGO_IS_LINUX_TRUE@runtime_thread_files = runtime/thread-linux.c @LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@runtime_getncpu_file = runtime/getncpu-none.c @LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@runtime_getncpu_file = runtime/getncpu-bsd.c @LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@runtime_getncpu_file = runtime/getncpu-bsd.c @@ -903,7 +903,6 @@ runtime_files = \ runtime/go-varargs.c \ runtime/env_posix.c \ runtime/heapdump.c \ - $(runtime_lock_files) \ runtime/mcache.c \ runtime/mcentral.c \ $(runtime_mem_file) \ @@ -919,6 +918,7 @@ runtime_files = \ runtime/runtime.c \ runtime/signal_unix.c \ runtime/thread.c \ + $(runtime_thread_files) \ runtime/yield.c \ $(rtems_task_variable_add_file) \ chan.c \ @@ -1633,8 +1633,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgobegin_a-go-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgobegin_llgo_a-go-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgolibbegin_a-go-libmain.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock_futex.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock_sema.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcentral.Plo@am__quote@ @@ -2179,34 +2177,6 @@ heapdump.lo: runtime/heapdump.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o heapdump.lo `test -f 'runtime/heapdump.c' || echo '$(srcdir)/'`runtime/heapdump.c -lock_sema.lo: runtime/lock_sema.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lock_sema.lo -MD -MP -MF $(DEPDIR)/lock_sema.Tpo -c -o lock_sema.lo `test -f 'runtime/lock_sema.c' || echo '$(srcdir)/'`runtime/lock_sema.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/lock_sema.Tpo $(DEPDIR)/lock_sema.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/lock_sema.c' object='lock_sema.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lock_sema.lo `test -f 'runtime/lock_sema.c' || echo '$(srcdir)/'`runtime/lock_sema.c - -thread-sema.lo: runtime/thread-sema.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread-sema.lo -MD -MP -MF $(DEPDIR)/thread-sema.Tpo -c -o thread-sema.lo `test -f 'runtime/thread-sema.c' || echo '$(srcdir)/'`runtime/thread-sema.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/thread-sema.Tpo $(DEPDIR)/thread-sema.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/thread-sema.c' object='thread-sema.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread-sema.lo `test -f 'runtime/thread-sema.c' || echo '$(srcdir)/'`runtime/thread-sema.c - -lock_futex.lo: runtime/lock_futex.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lock_futex.lo -MD -MP -MF $(DEPDIR)/lock_futex.Tpo -c -o lock_futex.lo `test -f 'runtime/lock_futex.c' || echo '$(srcdir)/'`runtime/lock_futex.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/lock_futex.Tpo $(DEPDIR)/lock_futex.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/lock_futex.c' object='lock_futex.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lock_futex.lo `test -f 'runtime/lock_futex.c' || echo '$(srcdir)/'`runtime/lock_futex.c - -thread-linux.lo: runtime/thread-linux.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread-linux.lo -MD -MP -MF $(DEPDIR)/thread-linux.Tpo -c -o thread-linux.lo `test -f 'runtime/thread-linux.c' || echo '$(srcdir)/'`runtime/thread-linux.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/thread-linux.Tpo $(DEPDIR)/thread-linux.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/thread-linux.c' object='thread-linux.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread-linux.lo `test -f 'runtime/thread-linux.c' || echo '$(srcdir)/'`runtime/thread-linux.c - mcache.lo: runtime/mcache.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mcache.lo -MD -MP -MF $(DEPDIR)/mcache.Tpo -c -o mcache.lo `test -f 'runtime/mcache.c' || echo '$(srcdir)/'`runtime/mcache.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mcache.Tpo $(DEPDIR)/mcache.Plo @@ -2333,6 +2303,20 @@ thread.lo: runtime/thread.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread.lo `test -f 'runtime/thread.c' || echo '$(srcdir)/'`runtime/thread.c +thread-sema.lo: runtime/thread-sema.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread-sema.lo -MD -MP -MF $(DEPDIR)/thread-sema.Tpo -c -o thread-sema.lo `test -f 'runtime/thread-sema.c' || echo '$(srcdir)/'`runtime/thread-sema.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/thread-sema.Tpo $(DEPDIR)/thread-sema.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/thread-sema.c' object='thread-sema.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread-sema.lo `test -f 'runtime/thread-sema.c' || echo '$(srcdir)/'`runtime/thread-sema.c + +thread-linux.lo: runtime/thread-linux.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread-linux.lo -MD -MP -MF $(DEPDIR)/thread-linux.Tpo -c -o thread-linux.lo `test -f 'runtime/thread-linux.c' || echo '$(srcdir)/'`runtime/thread-linux.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/thread-linux.Tpo $(DEPDIR)/thread-linux.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/thread-linux.c' object='thread-linux.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread-linux.lo `test -f 'runtime/thread-linux.c' || echo '$(srcdir)/'`runtime/thread-linux.c + yield.lo: runtime/yield.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT yield.lo -MD -MP -MF $(DEPDIR)/yield.Tpo -c -o yield.lo `test -f 'runtime/yield.c' || echo '$(srcdir)/'`runtime/yield.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/yield.Tpo $(DEPDIR)/yield.Plo @@ -3599,12 +3583,8 @@ s-version: Makefile $(STAMP) $@ runtime_sysinfo.go: s-runtime_sysinfo; @true -s-runtime_sysinfo: sysinfo.go - rm -f tmp-runtime_sysinfo.go - echo 'package runtime' > tmp-runtime_sysinfo.go - echo >> tmp-runtime_sysinfo.go - grep 'const _sizeof_ucontext_t ' sysinfo.go >> tmp-runtime_sysinfo.go - grep 'type _sigset_t ' sysinfo.go >> tmp-runtime_sysinfo.go +s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go + $(SHELL) $(srcdir)/mkrsysinfo.sh $(SHELL) $(srcdir)/mvifdiff.sh tmp-runtime_sysinfo.go runtime_sysinfo.go $(STAMP) $@ diff --git a/libgo/config.h.in b/libgo/config.h.in index 298b8d660e3..14938da59c1 100644 --- a/libgo/config.h.in +++ b/libgo/config.h.in @@ -195,6 +195,9 @@ /* Define to 1 if you have the <sched.h> header file. */ #undef HAVE_SCHED_H +/* Define to 1 if you have the <semaphore.h> header file. */ +#undef HAVE_SEMAPHORE_H + /* Define to 1 if you have the `sem_timedwait' function. */ #undef HAVE_SEM_TIMEDWAIT diff --git a/libgo/configure b/libgo/configure index 137e7a66c86..e065417fa15 100755 --- a/libgo/configure +++ b/libgo/configure @@ -14714,7 +14714,7 @@ $as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h fi -for ac_header in sched.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/icmp6.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h +for ac_header in sched.h semaphore.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/icmp6.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" diff --git a/libgo/configure.ac b/libgo/configure.ac index 2224f40c3ca..0f98ae83751 100644 --- a/libgo/configure.ac +++ b/libgo/configure.ac @@ -570,7 +570,7 @@ AC_C_BIGENDIAN GCC_CHECK_UNWIND_GETIPINFO -AC_CHECK_HEADERS(sched.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/icmp6.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h) +AC_CHECK_HEADERS(sched.h semaphore.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/icmp6.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h) AC_CHECK_HEADERS([linux/filter.h linux/if_addr.h linux/if_ether.h linux/if_tun.h linux/netlink.h linux/rtnetlink.h], [], [], [#ifdef HAVE_SYS_SOCKET_H diff --git a/libgo/go/runtime/export_test.go b/libgo/go/runtime/export_test.go index b13e3829423..711a551d278 100644 --- a/libgo/go/runtime/export_test.go +++ b/libgo/go/runtime/export_test.go @@ -17,8 +17,6 @@ package runtime //var F64toint = f64toint //var Sqrt = sqrt -func entersyscall(int32) -func exitsyscall(int32) func golockedOSThread() bool var Entersyscall = entersyscall diff --git a/libgo/go/runtime/lock_futex.go b/libgo/go/runtime/lock_futex.go new file mode 100644 index 00000000000..1ad79111108 --- /dev/null +++ b/libgo/go/runtime/lock_futex.go @@ -0,0 +1,225 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build dragonfly freebsd linux + +package runtime + +import ( + "runtime/internal/atomic" + "unsafe" +) + +// For gccgo, while we still have C runtime code, use go:linkname to +// rename some functions to themselves, so that the compiler will +// export them. +// +//go:linkname lock runtime.lock +//go:linkname unlock runtime.unlock +//go:linkname noteclear runtime.noteclear +//go:linkname notewakeup runtime.notewakeup +//go:linkname notesleep runtime.notesleep +//go:linkname notetsleep runtime.notetsleep +//go:linkname notetsleepg runtime.notetsleepg + +// This implementation depends on OS-specific implementations of +// +// futexsleep(addr *uint32, val uint32, ns int64) +// Atomically, +// if *addr == val { sleep } +// Might be woken up spuriously; that's allowed. +// Don't sleep longer than ns; ns < 0 means forever. +// +// futexwakeup(addr *uint32, cnt uint32) +// If any procs are sleeping on addr, wake up at most cnt. + +const ( + mutex_unlocked = 0 + mutex_locked = 1 + mutex_sleeping = 2 + + active_spin = 4 + active_spin_cnt = 30 + passive_spin = 1 +) + +// Possible lock states are mutex_unlocked, mutex_locked and mutex_sleeping. +// mutex_sleeping means that there is presumably at least one sleeping thread. +// Note that there can be spinning threads during all states - they do not +// affect mutex's state. + +// We use the uintptr mutex.key and note.key as a uint32. +func key32(p *uintptr) *uint32 { + return (*uint32)(unsafe.Pointer(p)) +} + +func lock(l *mutex) { + gp := getg() + + if gp.m.locks < 0 { + throw("runtime·lock: lock count") + } + gp.m.locks++ + + // Speculative grab for lock. + v := atomic.Xchg(key32(&l.key), mutex_locked) + if v == mutex_unlocked { + return + } + + // wait is either MUTEX_LOCKED or MUTEX_SLEEPING + // depending on whether there is a thread sleeping + // on this mutex. If we ever change l->key from + // MUTEX_SLEEPING to some other value, we must be + // careful to change it back to MUTEX_SLEEPING before + // returning, to ensure that the sleeping thread gets + // its wakeup call. + wait := v + + // On uniprocessors, no point spinning. + // On multiprocessors, spin for ACTIVE_SPIN attempts. + spin := 0 + if ncpu > 1 { + spin = active_spin + } + for { + // Try for lock, spinning. + for i := 0; i < spin; i++ { + for l.key == mutex_unlocked { + if atomic.Cas(key32(&l.key), mutex_unlocked, wait) { + return + } + } + procyield(active_spin_cnt) + } + + // Try for lock, rescheduling. + for i := 0; i < passive_spin; i++ { + for l.key == mutex_unlocked { + if atomic.Cas(key32(&l.key), mutex_unlocked, wait) { + return + } + } + osyield() + } + + // Sleep. + v = atomic.Xchg(key32(&l.key), mutex_sleeping) + if v == mutex_unlocked { + return + } + wait = mutex_sleeping + futexsleep(key32(&l.key), mutex_sleeping, -1) + } +} + +func unlock(l *mutex) { + v := atomic.Xchg(key32(&l.key), mutex_unlocked) + if v == mutex_unlocked { + throw("unlock of unlocked lock") + } + if v == mutex_sleeping { + futexwakeup(key32(&l.key), 1) + } + + gp := getg() + gp.m.locks-- + if gp.m.locks < 0 { + throw("runtime·unlock: lock count") + } + // if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack + // gp.stackguard0 = stackPreempt + // } +} + +// One-time notifications. +func noteclear(n *note) { + n.key = 0 +} + +func notewakeup(n *note) { + old := atomic.Xchg(key32(&n.key), 1) + if old != 0 { + print("notewakeup - double wakeup (", old, ")\n") + throw("notewakeup - double wakeup") + } + futexwakeup(key32(&n.key), 1) +} + +func notesleep(n *note) { + gp := getg() + + // Currently OK to sleep in non-g0 for gccgo. It happens in + // stoptheworld because we have not implemented preemption. + // if gp != gp.m.g0 { + // throw("notesleep not on g0") + // } + + for atomic.Load(key32(&n.key)) == 0 { + gp.m.blocked = true + futexsleep(key32(&n.key), 0, -1) + gp.m.blocked = false + } +} + +// May run with m.p==nil if called from notetsleep, so write barriers +// are not allowed. +// +//go:nosplit +//go:nowritebarrier +func notetsleep_internal(n *note, ns int64) bool { + gp := getg() + + if ns < 0 { + for atomic.Load(key32(&n.key)) == 0 { + gp.m.blocked = true + futexsleep(key32(&n.key), 0, -1) + gp.m.blocked = false + } + return true + } + + if atomic.Load(key32(&n.key)) != 0 { + return true + } + + deadline := nanotime() + ns + for { + gp.m.blocked = true + futexsleep(key32(&n.key), 0, ns) + gp.m.blocked = false + if atomic.Load(key32(&n.key)) != 0 { + break + } + now := nanotime() + if now >= deadline { + break + } + ns = deadline - now + } + return atomic.Load(key32(&n.key)) != 0 +} + +func notetsleep(n *note, ns int64) bool { + gp := getg() + if gp != gp.m.g0 && gp.m.preemptoff != "" { + throw("notetsleep not on g0") + } + + return notetsleep_internal(n, ns) +} + +// same as runtime·notetsleep, but called on user g (not g0) +// calls only nosplit functions between entersyscallblock/exitsyscall +func notetsleepg(n *note, ns int64) bool { + gp := getg() + if gp == gp.m.g0 { + throw("notetsleepg on g0") + } + + entersyscallblock(0) + ok := notetsleep_internal(n, ns) + exitsyscall(0) + return ok +} diff --git a/libgo/go/runtime/lock_sema.go b/libgo/go/runtime/lock_sema.go new file mode 100644 index 00000000000..eaf938a9bb3 --- /dev/null +++ b/libgo/go/runtime/lock_sema.go @@ -0,0 +1,281 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin nacl netbsd openbsd plan9 solaris windows + +package runtime + +import ( + "runtime/internal/atomic" + "unsafe" +) + +// For gccgo, while we still have C runtime code, use go:linkname to +// rename some functions to themselves, so that the compiler will +// export them. +// +//go:linkname lock runtime.lock +//go:linkname unlock runtime.unlock +//go:linkname noteclear runtime.noteclear +//go:linkname notewakeup runtime.notewakeup +//go:linkname notesleep runtime.notesleep +//go:linkname notetsleep runtime.notetsleep +//go:linkname notetsleepg runtime.notetsleepg + +// This implementation depends on OS-specific implementations of +// +// func semacreate(mp *m) +// Create a semaphore for mp, if it does not already have one. +// +// func semasleep(ns int64) int32 +// If ns < 0, acquire m's semaphore and return 0. +// If ns >= 0, try to acquire m's semaphore for at most ns nanoseconds. +// Return 0 if the semaphore was acquired, -1 if interrupted or timed out. +// +// func semawakeup(mp *m) +// Wake up mp, which is or will soon be sleeping on its semaphore. +// +const ( + mutex_locked uintptr = 1 + + active_spin = 4 + active_spin_cnt = 30 + passive_spin = 1 +) + +func lock(l *mutex) { + gp := getg() + if gp.m.locks < 0 { + throw("runtime·lock: lock count") + } + gp.m.locks++ + + // Speculative grab for lock. + if atomic.Casuintptr(&l.key, 0, mutex_locked) { + return + } + semacreate(gp.m) + + // On uniprocessor's, no point spinning. + // On multiprocessors, spin for ACTIVE_SPIN attempts. + spin := 0 + if ncpu > 1 { + spin = active_spin + } +Loop: + for i := 0; ; i++ { + v := atomic.Loaduintptr(&l.key) + if v&mutex_locked == 0 { + // Unlocked. Try to lock. + if atomic.Casuintptr(&l.key, v, v|mutex_locked) { + return + } + i = 0 + } + if i < spin { + procyield(active_spin_cnt) + } else if i < spin+passive_spin { + osyield() + } else { + // Someone else has it. + // l->waitm points to a linked list of M's waiting + // for this lock, chained through m->nextwaitm. + // Queue this M. + for { + gp.m.nextwaitm = v &^ mutex_locked + if atomic.Casuintptr(&l.key, v, uintptr(unsafe.Pointer(gp.m))|mutex_locked) { + break + } + v = atomic.Loaduintptr(&l.key) + if v&mutex_locked == 0 { + continue Loop + } + } + if v&mutex_locked != 0 { + // Queued. Wait. + semasleep(-1) + i = 0 + } + } + } +} + +//go:nowritebarrier +// We might not be holding a p in this code. +func unlock(l *mutex) { + gp := getg() + var mp *m + for { + v := atomic.Loaduintptr(&l.key) + if v == mutex_locked { + if atomic.Casuintptr(&l.key, mutex_locked, 0) { + break + } + } else { + // Other M's are waiting for the lock. + // Dequeue an M. + mp = (*m)(unsafe.Pointer(v &^ mutex_locked)) + if atomic.Casuintptr(&l.key, v, mp.nextwaitm) { + // Dequeued an M. Wake it. + semawakeup(mp) + break + } + } + } + gp.m.locks-- + if gp.m.locks < 0 { + throw("runtime·unlock: lock count") + } + // if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack + // gp.stackguard0 = stackPreempt + // } +} + +// One-time notifications. +func noteclear(n *note) { + n.key = 0 +} + +func notewakeup(n *note) { + var v uintptr + for { + v = atomic.Loaduintptr(&n.key) + if atomic.Casuintptr(&n.key, v, mutex_locked) { + break + } + } + + // Successfully set waitm to locked. + // What was it before? + switch { + case v == 0: + // Nothing was waiting. Done. + case v == mutex_locked: + // Two notewakeups! Not allowed. + throw("notewakeup - double wakeup") + default: + // Must be the waiting m. Wake it up. + semawakeup((*m)(unsafe.Pointer(v))) + } +} + +func notesleep(n *note) { + gp := getg() + + // Currently OK to sleep in non-g0 for gccgo. It happens in + // stoptheworld because we have not implemented preemption. + // if gp != gp.m.g0 { + // throw("notesleep not on g0") + // } + + semacreate(gp.m) + if !atomic.Casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) { + // Must be locked (got wakeup). + if n.key != mutex_locked { + throw("notesleep - waitm out of sync") + } + return + } + // Queued. Sleep. + gp.m.blocked = true + semasleep(-1) + gp.m.blocked = false +} + +//go:nosplit +func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool { + // gp and deadline are logically local variables, but they are written + // as parameters so that the stack space they require is charged + // to the caller. + // This reduces the nosplit footprint of notetsleep_internal. + gp = getg() + + // Register for wakeup on n->waitm. + if !atomic.Casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) { + // Must be locked (got wakeup). + if n.key != mutex_locked { + throw("notetsleep - waitm out of sync") + } + return true + } + if ns < 0 { + // Queued. Sleep. + gp.m.blocked = true + semasleep(-1) + gp.m.blocked = false + return true + } + + deadline = nanotime() + ns + for { + // Registered. Sleep. + gp.m.blocked = true + if semasleep(ns) >= 0 { + gp.m.blocked = false + // Acquired semaphore, semawakeup unregistered us. + // Done. + return true + } + gp.m.blocked = false + // Interrupted or timed out. Still registered. Semaphore not acquired. + ns = deadline - nanotime() + if ns <= 0 { + break + } + // Deadline hasn't arrived. Keep sleeping. + } + + // Deadline arrived. Still registered. Semaphore not acquired. + // Want to give up and return, but have to unregister first, + // so that any notewakeup racing with the return does not + // try to grant us the semaphore when we don't expect it. + for { + v := atomic.Loaduintptr(&n.key) + switch v { + case uintptr(unsafe.Pointer(gp.m)): + // No wakeup yet; unregister if possible. + if atomic.Casuintptr(&n.key, v, 0) { + return false + } + case mutex_locked: + // Wakeup happened so semaphore is available. + // Grab it to avoid getting out of sync. + gp.m.blocked = true + if semasleep(-1) < 0 { + throw("runtime: unable to acquire - semaphore out of sync") + } + gp.m.blocked = false + return true + default: + throw("runtime: unexpected waitm - semaphore out of sync") + } + } +} + +func notetsleep(n *note, ns int64) bool { + gp := getg() + + // Currently OK to sleep in non-g0 for gccgo. It happens in + // stoptheworld because we have not implemented preemption. + // if gp != gp.m.g0 && gp.m.preemptoff != "" { + // throw("notetsleep not on g0") + // } + + semacreate(gp.m) + return notetsleep_internal(n, ns, nil, 0) +} + +// same as runtime·notetsleep, but called on user g (not g0) +// calls only nosplit functions between entersyscallblock/exitsyscall +func notetsleepg(n *note, ns int64) bool { + gp := getg() + if gp == gp.m.g0 { + throw("notetsleepg on g0") + } + semacreate(gp.m) + entersyscallblock(0) + ok := notetsleep_internal(n, ns, nil, 0) + exitsyscall(0) + return ok +} diff --git a/libgo/go/runtime/os_darwin.go b/libgo/go/runtime/os_darwin.go new file mode 100644 index 00000000000..db403e2eb37 --- /dev/null +++ b/libgo/go/runtime/os_darwin.go @@ -0,0 +1,326 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +type mOS struct { + machport uint32 // return address for mach ipc + waitsema uint32 // semaphore for parking on locks +} + +//go:noescape +//extern mach_msg_trap +func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32 + +//extern mach_reply_port +func mach_reply_port() uint32 + +//extern mach_task_self +func mach_task_self() uint32 + +func unimplemented(name string) { + println(name, "not implemented") + *(*int)(unsafe.Pointer(uintptr(1231))) = 1231 +} + +//go:nosplit +func semawakeup(mp *m) { + mach_semrelease(mp.mos.waitsema) +} + +//go:nosplit +func semacreate(mp *m) { + if mp.mos.waitsema != 0 { + return + } + systemstack(func() { + mp.mos.waitsema = mach_semcreate() + }) +} + +// Mach IPC, to get at semaphores +// Definitions are in /usr/include/mach on a Mac. + +func macherror(r int32, fn string) { + print("mach error ", fn, ": ", r, "\n") + throw("mach error") +} + +const _DebugMach = false + +var zerondr machndr + +func mach_msgh_bits(a, b uint32) uint32 { + return a | b<<8 +} + +func mach_msg(h *machheader, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32 { + // TODO: Loop on interrupt. + return mach_msg_trap(unsafe.Pointer(h), op, send_size, rcv_size, rcv_name, timeout, notify) +} + +// Mach RPC (MIG) +const ( + _MinMachMsg = 48 + _MachReply = 100 +) + +type codemsg struct { + h machheader + ndr machndr + code int32 +} + +func machcall(h *machheader, maxsize int32, rxsize int32) int32 { + _g_ := getg() + port := _g_.m.mos.machport + if port == 0 { + port = mach_reply_port() + _g_.m.mos.machport = port + } + + h.msgh_bits |= mach_msgh_bits(_MACH_MSG_TYPE_COPY_SEND, _MACH_MSG_TYPE_MAKE_SEND_ONCE) + h.msgh_local_port = port + h.msgh_reserved = 0 + id := h.msgh_id + + if _DebugMach { + p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h)) + print("send:\t") + var i uint32 + for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ { + print(" ", p[i]) + if i%8 == 7 { + print("\n\t") + } + } + if i%8 != 0 { + print("\n") + } + } + ret := mach_msg(h, _MACH_SEND_MSG|_MACH_RCV_MSG, h.msgh_size, uint32(maxsize), port, 0, 0) + if ret != 0 { + if _DebugMach { + print("mach_msg error ", ret, "\n") + } + return ret + } + if _DebugMach { + p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h)) + var i uint32 + for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ { + print(" ", p[i]) + if i%8 == 7 { + print("\n\t") + } + } + if i%8 != 0 { + print("\n") + } + } + if h.msgh_id != id+_MachReply { + if _DebugMach { + print("mach_msg _MachReply id mismatch ", h.msgh_id, " != ", id+_MachReply, "\n") + } + return -303 // MIG_REPLY_MISMATCH + } + // Look for a response giving the return value. + // Any call can send this back with an error, + // and some calls only have return values so they + // send it back on success too. I don't quite see how + // you know it's one of these and not the full response + // format, so just look if the message is right. + c := (*codemsg)(unsafe.Pointer(h)) + if uintptr(h.msgh_size) == unsafe.Sizeof(*c) && h.msgh_bits&_MACH_MSGH_BITS_COMPLEX == 0 { + if _DebugMach { + print("mig result ", c.code, "\n") + } + return c.code + } + if h.msgh_size != uint32(rxsize) { + if _DebugMach { + print("mach_msg _MachReply size mismatch ", h.msgh_size, " != ", rxsize, "\n") + } + return -307 // MIG_ARRAY_TOO_LARGE + } + return 0 +} + +// Semaphores! + +const ( + tmach_semcreate = 3418 + rmach_semcreate = tmach_semcreate + _MachReply + + tmach_semdestroy = 3419 + rmach_semdestroy = tmach_semdestroy + _MachReply + + _KERN_ABORTED = 14 + _KERN_OPERATION_TIMED_OUT = 49 +) + +type tmach_semcreatemsg struct { + h machheader + ndr machndr + policy int32 + value int32 +} + +type rmach_semcreatemsg struct { + h machheader + body machbody + semaphore machport +} + +type tmach_semdestroymsg struct { + h machheader + body machbody + semaphore machport +} + +func mach_semcreate() uint32 { + var m [256]uint8 + tx := (*tmach_semcreatemsg)(unsafe.Pointer(&m)) + rx := (*rmach_semcreatemsg)(unsafe.Pointer(&m)) + + tx.h.msgh_bits = 0 + tx.h.msgh_size = uint32(unsafe.Sizeof(*tx)) + tx.h.msgh_remote_port = mach_task_self() + tx.h.msgh_id = tmach_semcreate + tx.ndr = zerondr + + tx.policy = 0 // 0 = SYNC_POLICY_FIFO + tx.value = 0 + + for { + r := machcall(&tx.h, int32(unsafe.Sizeof(m)), int32(unsafe.Sizeof(*rx))) + if r == 0 { + break + } + if r == _KERN_ABORTED { // interrupted + continue + } + macherror(r, "semaphore_create") + } + if rx.body.msgh_descriptor_count != 1 { + unimplemented("mach_semcreate desc count") + } + return rx.semaphore.name +} + +func mach_semdestroy(sem uint32) { + var m [256]uint8 + tx := (*tmach_semdestroymsg)(unsafe.Pointer(&m)) + + tx.h.msgh_bits = _MACH_MSGH_BITS_COMPLEX + tx.h.msgh_size = uint32(unsafe.Sizeof(*tx)) + tx.h.msgh_remote_port = mach_task_self() + tx.h.msgh_id = tmach_semdestroy + tx.body.msgh_descriptor_count = 1 + tx.semaphore.name = sem + tx.semaphore.disposition = _MACH_MSG_TYPE_MOVE_SEND + tx.semaphore._type = 0 + + for { + r := machcall(&tx.h, int32(unsafe.Sizeof(m)), 0) + if r == 0 { + break + } + if r == _KERN_ABORTED { // interrupted + continue + } + macherror(r, "semaphore_destroy") + } +} + +//extern semaphore_wait +func mach_semaphore_wait(sema uint32) int32 + +//extern semaphore_timedwait +func mach_semaphore_timedwait(sema, sec, nsec uint32) int32 + +//extern semaphore_signal +func mach_semaphore_signal(sema uint32) int32 + +//extern semaphore_signal_all +func mach_semaphore_signal_all(sema uint32) int32 + +func semasleep1(ns int64) int32 { + _g_ := getg() + + if ns >= 0 { + var nsecs int32 + secs := timediv(ns, 1000000000, &nsecs) + r := mach_semaphore_timedwait(_g_.m.mos.waitsema, uint32(secs), uint32(nsecs)) + if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT { + return -1 + } + if r != 0 { + macherror(r, "semaphore_wait") + } + return 0 + } + + for { + r := mach_semaphore_wait(_g_.m.mos.waitsema) + if r == 0 { + break + } + if r == _KERN_ABORTED { // interrupted + continue + } + macherror(r, "semaphore_wait") + } + return 0 +} + +//go:nosplit +func semasleep(ns int64) int32 { + var r int32 + systemstack(func() { + r = semasleep1(ns) + }) + return r +} + +//go:nosplit +func mach_semrelease(sem uint32) { + for { + r := mach_semaphore_signal(sem) + if r == 0 { + break + } + if r == _KERN_ABORTED { // interrupted + continue + } + + // mach_semrelease must be completely nosplit, + // because it is called from Go code. + // If we're going to die, start that process on the system stack + // to avoid a Go stack split. + systemstack(func() { macherror(r, "semaphore_signal") }) + } +} + +type machheader struct { + msgh_bits uint32 + msgh_size uint32 + msgh_remote_port uint32 + msgh_local_port uint32 + msgh_reserved uint32 + msgh_id int32 +} + +type machndr struct { + mig_vers uint8 + if_vers uint8 + reserved1 uint8 + mig_encoding uint8 + int_rep uint8 + char_rep uint8 + float_rep uint8 + reserved2 uint8 +} diff --git a/libgo/go/runtime/os_dragonfly.go b/libgo/go/runtime/os_dragonfly.go new file mode 100644 index 00000000000..645298436b5 --- /dev/null +++ b/libgo/go/runtime/os_dragonfly.go @@ -0,0 +1,62 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +type mOS struct { + unused byte +} + +//go:noescape +//extern umtx_sleep +func sys_umtx_sleep(addr *uint32, val, timeout int32) int32 + +//go:noescape +//extern umtx_wakeup +func sys_umtx_wakeup(addr *uint32, val int32) int32 + +//go:nosplit +func futexsleep(addr *uint32, val uint32, ns int64) { + systemstack(func() { + futexsleep1(addr, val, ns) + }) +} + +func futexsleep1(addr *uint32, val uint32, ns int64) { + var timeout int32 + if ns >= 0 { + // The timeout is specified in microseconds - ensure that we + // do not end up dividing to zero, which would put us to sleep + // indefinitely... + timeout = timediv(ns, 1000, nil) + if timeout == 0 { + timeout = 1 + } + } + + // sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout + // expires or EBUSY if the mutex value does not match. + ret := sys_umtx_sleep(addr, int32(val), timeout) + if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY { + return + } + + print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n") + *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005 +} + +//go:nosplit +func futexwakeup(addr *uint32, cnt uint32) { + ret := sys_umtx_wakeup(addr, int32(cnt)) + if ret >= 0 { + return + } + + systemstack(func() { + print("umtx_wake_addr=", addr, " ret=", ret, "\n") + *(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006 + }) +} diff --git a/libgo/go/runtime/os_freebsd.go b/libgo/go/runtime/os_freebsd.go new file mode 100644 index 00000000000..4512e7699fe --- /dev/null +++ b/libgo/go/runtime/os_freebsd.go @@ -0,0 +1,56 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "unsafe" +) + +type mOS struct { + unused byte +} + +//go:noescape +//extern _umtx_op +func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32 + +// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and +// thus the code is largely similar. See Linux implementation +// and lock_futex.go for comments. + +//go:nosplit +func futexsleep(addr *uint32, val uint32, ns int64) { + systemstack(func() { + futexsleep1(addr, val, ns) + }) +} + +func futexsleep1(addr *uint32, val uint32, ns int64) { + var tsp *timespec + if ns >= 0 { + var ts timespec + ts.tv_nsec = 0 + ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec))))) + tsp = &ts + } + ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp) + if ret >= 0 || ret == -_EINTR { + return + } + print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n") + *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005 +} + +//go:nosplit +func futexwakeup(addr *uint32, cnt uint32) { + ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil) + if ret >= 0 { + return + } + + systemstack(func() { + print("umtx_wake_addr=", addr, " ret=", ret, "\n") + }) +} diff --git a/libgo/go/runtime/os_linux.go b/libgo/go/runtime/os_linux.go index c44e4e8287e..04c690bd42f 100644 --- a/libgo/go/runtime/os_linux.go +++ b/libgo/go/runtime/os_linux.go @@ -9,6 +9,80 @@ import ( "unsafe" ) +type mOS struct { + unused byte +} + +func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32 { + return int32(syscall(_SYS_futex, uintptr(addr), uintptr(op), uintptr(val), uintptr(ts), uintptr(addr2), uintptr(val3))) +} + +// Linux futex. +// +// futexsleep(uint32 *addr, uint32 val) +// futexwakeup(uint32 *addr) +// +// Futexsleep atomically checks if *addr == val and if so, sleeps on addr. +// Futexwakeup wakes up threads sleeping on addr. +// Futexsleep is allowed to wake up spuriously. + +const ( + _FUTEX_WAIT = 0 + _FUTEX_WAKE = 1 +) + +// Atomically, +// if(*addr == val) sleep +// Might be woken up spuriously; that's allowed. +// Don't sleep longer than ns; ns < 0 means forever. +//go:nosplit +func futexsleep(addr *uint32, val uint32, ns int64) { + var ts timespec + + // Some Linux kernels have a bug where futex of + // FUTEX_WAIT returns an internal error code + // as an errno. Libpthread ignores the return value + // here, and so can we: as it says a few lines up, + // spurious wakeups are allowed. + if ns < 0 { + futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, nil, nil, 0) + return + } + + // It's difficult to live within the no-split stack limits here. + // On ARM and 386, a 64-bit divide invokes a general software routine + // that needs more stack than we can afford. So we use timediv instead. + // But on real 64-bit systems, where words are larger but the stack limit + // is not, even timediv is too heavy, and we really need to use just an + // ordinary machine instruction. + if sys.PtrSize == 8 { + ts.set_sec(ns / 1000000000) + ts.set_nsec(int32(ns % 1000000000)) + } else { + ts.tv_nsec = 0 + ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec))))) + } + futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, unsafe.Pointer(&ts), nil, 0) +} + +// If any procs are sleeping on addr, wake up at most cnt. +//go:nosplit +func futexwakeup(addr *uint32, cnt uint32) { + ret := futex(unsafe.Pointer(addr), _FUTEX_WAKE, cnt, nil, nil, 0) + if ret >= 0 { + return + } + + // I don't know that futex wakeup can return + // EAGAIN or EINTR, but if it does, it would be + // safe to loop and call futex again. + systemstack(func() { + print("futexwakeup addr=", addr, " returned ", ret, "\n") + }) + + *(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006 +} + const ( _AT_NULL = 0 // End of vector _AT_PAGESZ = 6 // System physical page size diff --git a/libgo/go/runtime/os_netbsd.go b/libgo/go/runtime/os_netbsd.go new file mode 100644 index 00000000000..464ce88d9c4 --- /dev/null +++ b/libgo/go/runtime/os_netbsd.go @@ -0,0 +1,73 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "runtime/internal/atomic" + "unsafe" +) + +type mOS struct { + waitsemacount uint32 +} + +//go:noescape +//extern lwp_park +func lwp_park(abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32 + +//go:noescape +//extern lwp_unpark +func lwp_unpark(lwp int32, hint unsafe.Pointer) int32 + +//go:nosplit +func semacreate(mp *m) { +} + +//go:nosplit +func semasleep(ns int64) int32 { + _g_ := getg() + + // Compute sleep deadline. + var tsp *timespec + if ns >= 0 { + var ts timespec + var nsec int32 + ns += nanotime() + ts.set_sec(int64(timediv(ns, 1000000000, &nsec))) + ts.set_nsec(nsec) + tsp = &ts + } + + for { + v := atomic.Load(&_g_.m.mos.waitsemacount) + if v > 0 { + if atomic.Cas(&_g_.m.mos.waitsemacount, v, v-1) { + return 0 // semaphore acquired + } + continue + } + + // Sleep until unparked by semawakeup or timeout. + ret := lwp_park(tsp, 0, unsafe.Pointer(&_g_.m.mos.waitsemacount), nil) + if ret == _ETIMEDOUT { + return -1 + } + } +} + +//go:nosplit +func semawakeup(mp *m) { + atomic.Xadd(&mp.mos.waitsemacount, 1) + // From NetBSD's _lwp_unpark(2) manual: + // "If the target LWP is not currently waiting, it will return + // immediately upon the next call to _lwp_park()." + ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.mos.waitsemacount)) + if ret != 0 && ret != _ESRCH { + // semawakeup can be called on signal stack. + systemstack(func() { + print("thrwakeup addr=", &mp.mos.waitsemacount, " sem=", mp.mos.waitsemacount, " ret=", ret, "\n") + }) + } +} diff --git a/libgo/go/runtime/os_openbsd.go b/libgo/go/runtime/os_openbsd.go new file mode 100644 index 00000000000..b64d3af385f --- /dev/null +++ b/libgo/go/runtime/os_openbsd.go @@ -0,0 +1,76 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "runtime/internal/atomic" + "unsafe" +) + +type mOS struct { + waitsemacount uint32 +} + +//go:noescape +//extern thrsleep +func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32 + +//go:noescape +//extern thrwakeup +func thrwakeup(ident uintptr, n int32) int32 + +//go:nosplit +func semacreate(mp *m) { +} + +//go:nosplit +func semasleep(ns int64) int32 { + _g_ := getg() + + // Compute sleep deadline. + var tsp *timespec + if ns >= 0 { + var ts timespec + var nsec int32 + ns += nanotime() + ts.set_sec(int64(timediv(ns, 1000000000, &nsec))) + ts.set_nsec(nsec) + tsp = &ts + } + + for { + v := atomic.Load(&_g_.m.mos.waitsemacount) + if v > 0 { + if atomic.Cas(&_g_.m.mos.waitsemacount, v, v-1) { + return 0 // semaphore acquired + } + continue + } + + // Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0. + // + // From OpenBSD's __thrsleep(2) manual: + // "The abort argument, if not NULL, points to an int that will + // be examined [...] immediately before blocking. If that int + // is non-zero then __thrsleep() will immediately return EINTR + // without blocking." + ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.mos.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.mos.waitsemacount) + if ret == _EWOULDBLOCK { + return -1 + } + } +} + +//go:nosplit +func semawakeup(mp *m) { + atomic.Xadd(&mp.mos.waitsemacount, 1) + ret := thrwakeup(uintptr(unsafe.Pointer(&mp.mos.waitsemacount)), 1) + if ret != 0 && ret != _ESRCH { + // semawakeup can be called on signal stack. + systemstack(func() { + print("thrwakeup addr=", &mp.mos.waitsemacount, " sem=", mp.mos.waitsemacount, " ret=", ret, "\n") + }) + } +} diff --git a/libgo/go/runtime/os_solaris.go b/libgo/go/runtime/os_solaris.go new file mode 100644 index 00000000000..cf457680f71 --- /dev/null +++ b/libgo/go/runtime/os_solaris.go @@ -0,0 +1,85 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +type mOS struct { + waitsema uintptr // semaphore for parking on locks +} + +//extern malloc +func libc_malloc(uintptr) unsafe.Pointer + +//go:noescape +//extern sem_init +func sem_init(sem *semt, pshared int32, value uint32) int32 + +//go:noescape +//extern sem_wait +func sem_wait(sem *semt) int32 + +//go:noescape +//extern sem_post +func sem_post(sem *semt) int32 + +//go:noescape +//extern sem_reltimedwait_np +func sem_reltimedwait_np(sem *semt, timeout *timespec) int32 + +//go:nosplit +func semacreate(mp *m) { + if mp.mos.waitsema != 0 { + return + } + + var sem *semt + + // Call libc's malloc rather than malloc. This will + // allocate space on the C heap. We can't call malloc + // here because it could cause a deadlock. + sem = (*semt)(libc_malloc(unsafe.Sizeof(*sem))) + if sem_init(sem, 0, 0) != 0 { + throw("sem_init") + } + mp.mos.waitsema = uintptr(unsafe.Pointer(sem)) +} + +//go:nosplit +func semasleep(ns int64) int32 { + _m_ := getg().m + if ns >= 0 { + var ts timespec + ts.set_sec(ns / 1000000000) + ts.set_nsec(int32(ns % 1000000000)) + + if sem_reltimedwait_np((*semt)(unsafe.Pointer(_m_.mos.waitsema)), &ts) != 0 { + err := errno() + if err == _ETIMEDOUT || err == _EAGAIN || err == _EINTR { + return -1 + } + throw("sem_reltimedwait_np") + } + return 0 + } + for { + r1 := sem_wait((*semt)(unsafe.Pointer(_m_.mos.waitsema))) + if r1 == 0 { + break + } + if errno() == _EINTR { + continue + } + throw("sem_wait") + } + return 0 +} + +//go:nosplit +func semawakeup(mp *m) { + if sem_post((*semt)(unsafe.Pointer(mp.mos.waitsema))) != 0 { + throw("sem_post") + } +} diff --git a/libgo/go/runtime/runtime2.go b/libgo/go/runtime/runtime2.go index 4fba428d7af..17447eb48bc 100644 --- a/libgo/go/runtime/runtime2.go +++ b/libgo/go/runtime/runtime2.go @@ -396,7 +396,7 @@ type g struct { gcnextsegment unsafe.Pointer gcnextsp unsafe.Pointer gcinitialsp unsafe.Pointer - gcregs _ucontext_t + gcregs g_ucontext_t entry unsafe.Pointer // goroutine entry point fromgogo bool // whether entered from gogo function @@ -406,7 +406,7 @@ type g struct { traceback *traceback // stack traceback buffer - context _ucontext_t // saved context for setcontext + context g_ucontext_t // saved context for setcontext stackcontext [10]unsafe.Pointer // split-stack context } @@ -474,7 +474,7 @@ type m struct { // Not for gccgo: libcallg guintptr // Not for gccgo: syscall libcall // stores syscall parameters on windows - // Not for gccgo: mOS + mos mOS // Remaining fields are specific to gccgo. @@ -485,8 +485,6 @@ type m struct { gcing int32 - waitsema uintptr // semaphore on systems that don't use futexes - cgomal *cgoMal // allocations via _cgo_allocate } @@ -771,13 +769,15 @@ const ( const _TracebackMaxFrames = 100 var ( -// emptystring string -// allglen uintptr -// allm *m -// allp [_MaxGomaxprocs + 1]*p -// gomaxprocs int32 -// panicking uint32 -// ncpu int32 + // emptystring string + // allglen uintptr + // allm *m + // allp [_MaxGomaxprocs + 1]*p + // gomaxprocs int32 + // panicking uint32 + + ncpu int32 + // forcegc forcegcstate // sched schedt // newprocs int32 @@ -803,13 +803,13 @@ var ( // Types that are only used by gccgo. -// _ucontext_t is a Go version of the C ucontext_t type, used by getcontext. -// _sizeof_ucontext_t is defined by the Makefile from <ucontext.h>. +// g_ucontext_t is a Go version of the C ucontext_t type, used by getcontext. +// _sizeof_ucontext_t is defined by mkrsysinfo.sh from <ucontext.h>. // On some systems getcontext and friends require a value that is // aligned to a 16-byte boundary. We implement this by increasing the // required size and picking an appropriate offset when we use the // array. -type _ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(unsafe.Pointer(nil))]unsafe.Pointer +type g_ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(unsafe.Pointer(nil))]unsafe.Pointer // traceback is used to collect stack traces from other goroutines. type traceback struct { diff --git a/libgo/go/runtime/stubs.go b/libgo/go/runtime/stubs.go index 3ff3aef2216..bbeac41a4dc 100644 --- a/libgo/go/runtime/stubs.go +++ b/libgo/go/runtime/stubs.go @@ -38,12 +38,7 @@ func getg() *g func mcall(fn func(*g)) // systemstack runs fn on a system stack. -// If systemstack is called from the per-OS-thread (g0) stack, or -// if systemstack is called from the signal handling (gsignal) stack, -// systemstack calls fn directly and returns. -// Otherwise, systemstack is being called from the limited stack -// of an ordinary goroutine. In this case, systemstack switches -// to the per-OS-thread stack, calls fn, and switches back. +// // It is common to use a func literal as the argument, in order // to share inputs and outputs with the code around the call // to system stack: @@ -54,8 +49,14 @@ func mcall(fn func(*g)) // }) // ... use x ... // -//go:noescape -func systemstack(fn func()) +// For the gc toolchain this permits running a function that requires +// additional stack space in a context where the stack can not be +// split. For gccgo, however, stack splitting is not managed by the +// Go runtime. In effect, all stacks are system stacks. So this gccgo +// version just runs the function. +func systemstack(fn func()) { + fn() +} func badsystemstack() { throw("systemstack called from unexpected goroutine") @@ -215,6 +216,13 @@ func checkASM() bool { return true } +// For gccgo this is in the C code. +func osyield() + +// For gccgo this can be called directly. +//extern syscall +func syscall(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) uintptr + // throw crashes the program. // For gccgo unless and until we port panic.go. func throw(string) @@ -368,3 +376,11 @@ func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool { // Here for gccgo until we port lock_*.go. func lock(l *mutex) func unlock(l *mutex) + +// Here for gccgo for Solaris. +func errno() int + +// Temporary for gccgo until we port proc.go. +func entersyscall(int32) +func entersyscallblock(int32) +func exitsyscall(int32) diff --git a/libgo/mkrsysinfo.sh b/libgo/mkrsysinfo.sh new file mode 100755 index 00000000000..b5c2c709c20 --- /dev/null +++ b/libgo/mkrsysinfo.sh @@ -0,0 +1,103 @@ +#!/bin/sh + +# Copyright 2016 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# Create runtime_sysinfo.go from gen-sysinfo.go and errno.i. + +OUT=tmp-runtime_sysinfo.go + +set -e + +echo 'package runtime' > ${OUT} + +# Get all the consts and types, skipping ones which could not be +# represented in Go and ones which we need to rewrite. We also skip +# function declarations, as we don't need them here. All the symbols +# will all have a leading underscore. +grep -v '^// ' gen-sysinfo.go | \ + grep -v '^func' | \ + grep -v '^type _timeval ' | \ + grep -v '^type _timespec_t ' | \ + grep -v '^type _timespec ' | \ + grep -v '^type _epoll_' | \ + grep -v 'in6_addr' | \ + grep -v 'sockaddr_in6' | \ + sed -e 's/\([^a-zA-Z0-9_]\)_timeval\([^a-zA-Z0-9_]\)/\1timeval\2/g' \ + -e 's/\([^a-zA-Z0-9_]\)_timespec_t\([^a-zA-Z0-9_]\)/\1timespec\2/g' \ + -e 's/\([^a-zA-Z0-9_]\)_timespec\([^a-zA-Z0-9_]\)/\1timespec\2/g' \ + >> ${OUT} + +# The time structures need special handling: we need to name the +# types, so that we can cast integers to the right types when +# assigning to the structures. +timeval=`grep '^type _timeval ' gen-sysinfo.go` +timeval_sec=`echo $timeval | sed -n -e 's/^.*tv_sec \([^ ]*\);.*$/\1/p'` +timeval_usec=`echo $timeval | sed -n -e 's/^.*tv_usec \([^ ]*\);.*$/\1/p'` +echo "type timeval_sec_t $timeval_sec" >> ${OUT} +echo "type timeval_usec_t $timeval_usec" >> ${OUT} +echo $timeval | \ + sed -e 's/type _timeval /type timeval /' \ + -e 's/tv_sec *[a-zA-Z0-9_]*/tv_sec timeval_sec_t/' \ + -e 's/tv_usec *[a-zA-Z0-9_]*/tv_usec timeval_usec_t/' >> ${OUT} +timespec=`grep '^type _timespec ' gen-sysinfo.go || true` +if test "$timespec" = ""; then + # IRIX 6.5 has __timespec instead. + timespec=`grep '^type ___timespec ' gen-sysinfo.go || true` +fi +timespec_sec=`echo $timespec | sed -n -e 's/^.*tv_sec \([^ ]*\);.*$/\1/p'` +timespec_nsec=`echo $timespec | sed -n -e 's/^.*tv_nsec \([^ ]*\);.*$/\1/p'` +echo "type timespec_sec_t $timespec_sec" >> ${OUT} +echo "type timespec_nsec_t $timespec_nsec" >> ${OUT} +echo $timespec | \ + sed -e 's/^type ___timespec /type timespec /' \ + -e 's/^type _timespec /type timespec /' \ + -e 's/tv_sec *[a-zA-Z0-9_]*/tv_sec timespec_sec_t/' \ + -e 's/tv_nsec *[a-zA-Z0-9_]*/tv_nsec timespec_nsec_t/' >> ${OUT} +echo >> ${OUT} +echo "func (ts *timespec) set_sec(x int64) {" >> ${OUT} +echo " ts.tv_sec = timespec_sec_t(x)" >> ${OUT} +echo "}" >> ${OUT} +echo >> ${OUT} +echo "func (ts *timespec) set_nsec(x int32) {" >> ${OUT} +echo " ts.tv_nsec = timespec_nsec_t(x)" >> ${OUT} +echo "}" >> ${OUT} + +# The semt structure, for Solaris. +grep '^type _sem_t ' gen-sysinfo.go | \ + sed -e 's/_sem_t/semt/' >> ${OUT} + +# Solaris 2 needs _u?pad128_t, but its default definition in terms of long +# double is commented by -fdump-go-spec. +if grep "^// type _pad128_t" gen-sysinfo.go > /dev/null 2>&1; then + echo "type _pad128_t struct { _l [4]int32; }" >> ${OUT} +fi +if grep "^// type _upad128_t" gen-sysinfo.go > /dev/null 2>&1; then + echo "type _upad128_t struct { _l [4]uint32; }" >> ${OUT} +fi + +# The Solaris 11 Update 1 _zone_net_addr_t struct. +grep '^type _zone_net_addr_t ' gen-sysinfo.go | \ + sed -e 's/_in6_addr/[16]byte/' \ + >> ${OUT} + +# The Solaris 12 _flow_arp_desc_t struct. +grep '^type _flow_arp_desc_t ' gen-sysinfo.go | \ + sed -e 's/_in6_addr_t/[16]byte/g' \ + >> ${OUT} + +# The Solaris 12 _flow_l3_desc_t struct. +grep '^type _flow_l3_desc_t ' gen-sysinfo.go | \ + sed -e 's/_in6_addr_t/[16]byte/g' \ + >> ${OUT} + +# The Solaris 12 _mac_ipaddr_t struct. +grep '^type _mac_ipaddr_t ' gen-sysinfo.go | \ + sed -e 's/_in6_addr_t/[16]byte/g' \ + >> ${OUT} + +# The Solaris 12 _mactun_info_t struct. +grep '^type _mactun_info_t ' gen-sysinfo.go | \ + sed -e 's/_in6_addr_t/[16]byte/g' \ + >> ${OUT} diff --git a/libgo/runtime/go-cgo.c b/libgo/runtime/go-cgo.c index 598c2617840..7d0494c3a65 100644 --- a/libgo/runtime/go-cgo.c +++ b/libgo/runtime/go-cgo.c @@ -45,7 +45,7 @@ syscall_cgocall () m = runtime_m (); ++m->ncgocall; ++m->ncgo; - runtime_entersyscall (); + runtime_entersyscall (0); } /* Prepare to return to Go code from C/C++ code. */ @@ -69,7 +69,7 @@ syscall_cgocalldone () /* If we are invoked because the C function called _cgo_panic, then _cgo_panic will already have exited syscall mode. */ if (g->atomicstatus == _Gsyscall) - runtime_exitsyscall (); + runtime_exitsyscall (0); runtime_unlockOSThread(); } @@ -89,7 +89,7 @@ syscall_cgocallback () mp->dropextram = true; } - runtime_exitsyscall (); + runtime_exitsyscall (0); if (runtime_m ()->ncgo == 0) { @@ -115,7 +115,7 @@ syscall_cgocallbackdone () { M *mp; - runtime_entersyscall (); + runtime_entersyscall (0); mp = runtime_m (); if (mp->dropextram && mp->ncgo == 0) { @@ -154,9 +154,9 @@ _cgo_allocate (size_t n) { void *ret; - runtime_exitsyscall (); + runtime_exitsyscall (0); ret = alloc_saved (n); - runtime_entersyscall (); + runtime_entersyscall (0); return ret; } @@ -171,7 +171,7 @@ _cgo_panic (const char *p) String *ps; struct __go_empty_interface e; - runtime_exitsyscall (); + runtime_exitsyscall (0); len = __builtin_strlen (p); data = alloc_saved (len); __builtin_memcpy (data, p, len); diff --git a/libgo/runtime/lock_futex.c b/libgo/runtime/lock_futex.c deleted file mode 100644 index 33ef073c907..00000000000 --- a/libgo/runtime/lock_futex.c +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build dragonfly freebsd linux - -#include "runtime.h" - -// This implementation depends on OS-specific implementations of -// -// runtime_futexsleep(uint32 *addr, uint32 val, int64 ns) -// Atomically, -// if(*addr == val) sleep -// Might be woken up spuriously; that's allowed. -// Don't sleep longer than ns; ns < 0 means forever. -// -// runtime_futexwakeup(uint32 *addr, uint32 cnt) -// If any procs are sleeping on addr, wake up at most cnt. - -enum -{ - MUTEX_UNLOCKED = 0, - MUTEX_LOCKED = 1, - MUTEX_SLEEPING = 2, - - ACTIVE_SPIN = 4, - ACTIVE_SPIN_CNT = 30, - PASSIVE_SPIN = 1, -}; - -// Possible lock states are MUTEX_UNLOCKED, MUTEX_LOCKED and MUTEX_SLEEPING. -// MUTEX_SLEEPING means that there is presumably at least one sleeping thread. -// Note that there can be spinning threads during all states - they do not -// affect mutex's state. -void -runtime_lock(Lock *l) -{ - uint32 i, v, wait, spin; - - if(runtime_m()->locks++ < 0) - runtime_throw("runtime_lock: lock count"); - - // Speculative grab for lock. - v = runtime_xchg((uint32*)&l->key, MUTEX_LOCKED); - if(v == MUTEX_UNLOCKED) - return; - - // wait is either MUTEX_LOCKED or MUTEX_SLEEPING - // depending on whether there is a thread sleeping - // on this mutex. If we ever change l->key from - // MUTEX_SLEEPING to some other value, we must be - // careful to change it back to MUTEX_SLEEPING before - // returning, to ensure that the sleeping thread gets - // its wakeup call. - wait = v; - - // On uniprocessor's, no point spinning. - // On multiprocessors, spin for ACTIVE_SPIN attempts. - spin = 0; - if(runtime_ncpu > 1) - spin = ACTIVE_SPIN; - - for(;;) { - // Try for lock, spinning. - for(i = 0; i < spin; i++) { - while(l->key == MUTEX_UNLOCKED) - if(runtime_cas((uint32*)&l->key, MUTEX_UNLOCKED, wait)) - return; - runtime_procyield(ACTIVE_SPIN_CNT); - } - - // Try for lock, rescheduling. - for(i=0; i < PASSIVE_SPIN; i++) { - while(l->key == MUTEX_UNLOCKED) - if(runtime_cas((uint32*)&l->key, MUTEX_UNLOCKED, wait)) - return; - runtime_osyield(); - } - - // Sleep. - v = runtime_xchg((uint32*)&l->key, MUTEX_SLEEPING); - if(v == MUTEX_UNLOCKED) - return; - wait = MUTEX_SLEEPING; - runtime_futexsleep((uint32*)&l->key, MUTEX_SLEEPING, -1); - } -} - -void -runtime_unlock(Lock *l) -{ - uint32 v; - - v = runtime_xchg((uint32*)&l->key, MUTEX_UNLOCKED); - if(v == MUTEX_UNLOCKED) - runtime_throw("unlock of unlocked lock"); - if(v == MUTEX_SLEEPING) - runtime_futexwakeup((uint32*)&l->key, 1); - - if(--runtime_m()->locks < 0) - runtime_throw("runtime_unlock: lock count"); -} - -// One-time notifications. -void -runtime_noteclear(Note *n) -{ - n->key = 0; -} - -void -runtime_notewakeup(Note *n) -{ - uint32 old; - - old = runtime_xchg((uint32*)&n->key, 1); - if(old != 0) { - runtime_printf("notewakeup - double wakeup (%d)\n", old); - runtime_throw("notewakeup - double wakeup"); - } - runtime_futexwakeup((uint32*)&n->key, 1); -} - -void -runtime_notesleep(Note *n) -{ - M *m = runtime_m(); - - /* For gccgo it's OK to sleep in non-g0, and it happens in - stoptheworld because we have not implemented preemption. - - if(runtime_g() != runtime_m()->g0) - runtime_throw("notesleep not on g0"); - */ - while(runtime_atomicload((uint32*)&n->key) == 0) { - m->blocked = true; - runtime_futexsleep((uint32*)&n->key, 0, -1); - m->blocked = false; - } -} - -static bool -notetsleep(Note *n, int64 ns, int64 deadline, int64 now) -{ - M *m = runtime_m(); - - // Conceptually, deadline and now are local variables. - // They are passed as arguments so that the space for them - // does not count against our nosplit stack sequence. - - if(ns < 0) { - while(runtime_atomicload((uint32*)&n->key) == 0) { - m->blocked = true; - runtime_futexsleep((uint32*)&n->key, 0, -1); - m->blocked = false; - } - return true; - } - - if(runtime_atomicload((uint32*)&n->key) != 0) - return true; - - deadline = runtime_nanotime() + ns; - for(;;) { - m->blocked = true; - runtime_futexsleep((uint32*)&n->key, 0, ns); - m->blocked = false; - if(runtime_atomicload((uint32*)&n->key) != 0) - break; - now = runtime_nanotime(); - if(now >= deadline) - break; - ns = deadline - now; - } - return runtime_atomicload((uint32*)&n->key) != 0; -} - -bool -runtime_notetsleep(Note *n, int64 ns) -{ - bool res; - - if(runtime_g() != runtime_m()->g0 && !runtime_m()->gcing) - runtime_throw("notetsleep not on g0"); - - res = notetsleep(n, ns, 0, 0); - return res; -} - -// same as runtime_notetsleep, but called on user g (not g0) -// calls only nosplit functions between entersyscallblock/exitsyscall -bool -runtime_notetsleepg(Note *n, int64 ns) -{ - bool res; - - if(runtime_g() == runtime_m()->g0) - runtime_throw("notetsleepg on g0"); - - runtime_entersyscallblock(); - res = notetsleep(n, ns, 0, 0); - runtime_exitsyscall(); - return res; -} diff --git a/libgo/runtime/lock_sema.c b/libgo/runtime/lock_sema.c deleted file mode 100644 index 06ac6e7f90d..00000000000 --- a/libgo/runtime/lock_sema.c +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin nacl netbsd openbsd plan9 solaris windows - -#include "runtime.h" - -// This implementation depends on OS-specific implementations of -// -// uintptr runtime_semacreate(void) -// Create a semaphore, which will be assigned to m->waitsema. -// The zero value is treated as absence of any semaphore, -// so be sure to return a non-zero value. -// -// int32 runtime_semasleep(int64 ns) -// If ns < 0, acquire m->waitsema and return 0. -// If ns >= 0, try to acquire m->waitsema for at most ns nanoseconds. -// Return 0 if the semaphore was acquired, -1 if interrupted or timed out. -// -// int32 runtime_semawakeup(M *mp) -// Wake up mp, which is or will soon be sleeping on mp->waitsema. -// - -enum -{ - LOCKED = 1, - - ACTIVE_SPIN = 4, - ACTIVE_SPIN_CNT = 30, - PASSIVE_SPIN = 1, -}; - -void -runtime_lock(Lock *l) -{ - M *m; - uintptr v; - uint32 i, spin; - - m = runtime_m(); - if(m->locks++ < 0) - runtime_throw("runtime_lock: lock count"); - - // Speculative grab for lock. - if(runtime_casp((void**)&l->key, nil, (void*)LOCKED)) - return; - - if(m->waitsema == 0) - m->waitsema = runtime_semacreate(); - - // On uniprocessor's, no point spinning. - // On multiprocessors, spin for ACTIVE_SPIN attempts. - spin = 0; - if(runtime_ncpu > 1) - spin = ACTIVE_SPIN; - - for(i=0;; i++) { - v = (uintptr)runtime_atomicloadp((void**)&l->key); - if((v&LOCKED) == 0) { -unlocked: - if(runtime_casp((void**)&l->key, (void*)v, (void*)(v|LOCKED))) - return; - i = 0; - } - if(i<spin) - runtime_procyield(ACTIVE_SPIN_CNT); - else if(i<spin+PASSIVE_SPIN) - runtime_osyield(); - else { - // Someone else has it. - // l->waitm points to a linked list of M's waiting - // for this lock, chained through m->nextwaitm. - // Queue this M. - for(;;) { - m->nextwaitm = v&~LOCKED; - if(runtime_casp((void**)&l->key, (void*)v, (void*)((uintptr)m|LOCKED))) - break; - v = (uintptr)runtime_atomicloadp((void**)&l->key); - if((v&LOCKED) == 0) - goto unlocked; - } - if(v&LOCKED) { - // Queued. Wait. - runtime_semasleep(-1); - i = 0; - } - } - } -} - -void -runtime_unlock(Lock *l) -{ - uintptr v; - M *mp; - - for(;;) { - v = (uintptr)runtime_atomicloadp((void**)&l->key); - if(v == LOCKED) { - if(runtime_casp((void**)&l->key, (void*)LOCKED, nil)) - break; - } else { - // Other M's are waiting for the lock. - // Dequeue an M. - mp = (void*)(v&~LOCKED); - if(runtime_cas(&l->key, v, mp->nextwaitm)) { - // Dequeued an M. Wake it. - runtime_semawakeup(mp); - break; - } - } - } - - if(--runtime_m()->locks < 0) - runtime_throw("runtime_unlock: lock count"); -} - -// One-time notifications. -void -runtime_noteclear(Note *n) -{ - n->key = 0; -} - -void -runtime_notewakeup(Note *n) -{ - M *mp; - - do - mp = runtime_atomicloadp((void**)&n->key); - while(!runtime_casp((void**)&n->key, mp, (void*)LOCKED)); - - // Successfully set waitm to LOCKED. - // What was it before? - if(mp == nil) { - // Nothing was waiting. Done. - } else if(mp == (M*)LOCKED) { - // Two notewakeups! Not allowed. - runtime_throw("notewakeup - double wakeup"); - } else { - // Must be the waiting m. Wake it up. - runtime_semawakeup(mp); - } -} - -void -runtime_notesleep(Note *n) -{ - M *m; - - m = runtime_m(); - - /* For gccgo it's OK to sleep in non-g0, and it happens in - stoptheworld because we have not implemented preemption. - - if(runtime_g() != m->g0) - runtime_throw("notesleep not on g0"); - */ - - if(m->waitsema == 0) - m->waitsema = runtime_semacreate(); - if(!runtime_casp((void**)&n->key, nil, m)) { // must be LOCKED (got wakeup) - if(n->key != LOCKED) - runtime_throw("notesleep - waitm out of sync"); - return; - } - // Queued. Sleep. - m->blocked = true; - runtime_semasleep(-1); - m->blocked = false; -} - -static bool -notetsleep(Note *n, int64 ns, int64 deadline, M *mp) -{ - M *m; - - m = runtime_m(); - - // Conceptually, deadline and mp are local variables. - // They are passed as arguments so that the space for them - // does not count against our nosplit stack sequence. - - // Register for wakeup on n->waitm. - if(!runtime_casp((void**)&n->key, nil, m)) { // must be LOCKED (got wakeup already) - if(n->key != LOCKED) - runtime_throw("notetsleep - waitm out of sync"); - return true; - } - - if(ns < 0) { - // Queued. Sleep. - m->blocked = true; - runtime_semasleep(-1); - m->blocked = false; - return true; - } - - deadline = runtime_nanotime() + ns; - for(;;) { - // Registered. Sleep. - m->blocked = true; - if(runtime_semasleep(ns) >= 0) { - m->blocked = false; - // Acquired semaphore, semawakeup unregistered us. - // Done. - return true; - } - m->blocked = false; - - // Interrupted or timed out. Still registered. Semaphore not acquired. - ns = deadline - runtime_nanotime(); - if(ns <= 0) - break; - // Deadline hasn't arrived. Keep sleeping. - } - - // Deadline arrived. Still registered. Semaphore not acquired. - // Want to give up and return, but have to unregister first, - // so that any notewakeup racing with the return does not - // try to grant us the semaphore when we don't expect it. - for(;;) { - mp = runtime_atomicloadp((void**)&n->key); - if(mp == m) { - // No wakeup yet; unregister if possible. - if(runtime_casp((void**)&n->key, mp, nil)) - return false; - } else if(mp == (M*)LOCKED) { - // Wakeup happened so semaphore is available. - // Grab it to avoid getting out of sync. - m->blocked = true; - if(runtime_semasleep(-1) < 0) - runtime_throw("runtime: unable to acquire - semaphore out of sync"); - m->blocked = false; - return true; - } else - runtime_throw("runtime: unexpected waitm - semaphore out of sync"); - } -} - -bool -runtime_notetsleep(Note *n, int64 ns) -{ - M *m; - bool res; - - m = runtime_m(); - - if(runtime_g() != m->g0 && !m->gcing) - runtime_throw("notetsleep not on g0"); - - if(m->waitsema == 0) - m->waitsema = runtime_semacreate(); - - res = notetsleep(n, ns, 0, nil); - return res; -} - -// same as runtime_notetsleep, but called on user g (not g0) -// calls only nosplit functions between entersyscallblock/exitsyscall -bool -runtime_notetsleepg(Note *n, int64 ns) -{ - M *m; - bool res; - - m = runtime_m(); - - if(runtime_g() == m->g0) - runtime_throw("notetsleepg on g0"); - - if(m->waitsema == 0) - m->waitsema = runtime_semacreate(); - - runtime_entersyscallblock(); - res = notetsleep(n, ns, 0, nil); - runtime_exitsyscall(); - return res; -} diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc index 591d06a7f59..a924b8adfa2 100644 --- a/libgo/runtime/malloc.goc +++ b/libgo/runtime/malloc.goc @@ -99,7 +99,7 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag) // returns a non-pointer, so memory allocation occurs // after syscall.Cgocall but before syscall.CgocallDone. // We treat it as a callback. - runtime_exitsyscall(); + runtime_exitsyscall(0); m = runtime_m(); incallback = true; flag |= FlagNoInvokeGC; @@ -171,7 +171,7 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag) m->mallocing = 0; m->locks--; if(incallback) - runtime_entersyscall(); + runtime_entersyscall(0); return v; } } @@ -256,7 +256,7 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag) runtime_gc(0); if(incallback) - runtime_entersyscall(); + runtime_entersyscall(0); return v; } diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index 32d0fb2a7be..dac32eb678e 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -2021,11 +2021,11 @@ goexit0(G *gp) // make g->sched refer to the caller's stack segment, because // entersyscall is going to return immediately after. -void runtime_entersyscall(void) __attribute__ ((no_split_stack)); +void runtime_entersyscall(int32) __attribute__ ((no_split_stack)); static void doentersyscall(void) __attribute__ ((no_split_stack, noinline)); void -runtime_entersyscall() +runtime_entersyscall(int32 dummy __attribute__ ((unused))) { // Save the registers in the g structure so that any pointers // held in registers will be seen by the garbage collector. @@ -2095,7 +2095,7 @@ doentersyscall() // The same as runtime_entersyscall(), but with a hint that the syscall is blocking. void -runtime_entersyscallblock(void) +runtime_entersyscallblock(int32 dummy __attribute__ ((unused))) { P *p; @@ -2133,7 +2133,7 @@ runtime_entersyscallblock(void) // This is called only from the go syscall library, not // from the low-level system calls used by the runtime. void -runtime_exitsyscall(void) +runtime_exitsyscall(int32 dummy __attribute__ ((unused))) { G *gp; @@ -2254,6 +2254,28 @@ exitsyscall0(G *gp) schedule(); // Never returns. } +void syscall_entersyscall(void) + __asm__(GOSYM_PREFIX "syscall.Entersyscall"); + +void syscall_entersyscall(void) __attribute__ ((no_split_stack)); + +void +syscall_entersyscall() +{ + runtime_entersyscall(0); +} + +void syscall_exitsyscall(void) + __asm__(GOSYM_PREFIX "syscall.Exitsyscall"); + +void syscall_exitsyscall(void) __attribute__ ((no_split_stack)); + +void +syscall_exitsyscall() +{ + runtime_exitsyscall(0); +} + // Called from syscall package before fork. void syscall_runtime_BeforeFork(void) __asm__(GOSYM_PREFIX "syscall.runtime_BeforeFork"); @@ -2323,33 +2345,6 @@ runtime_malg(int32 stacksize, byte** ret_stack, uintptr* ret_stacksize) return newg; } -/* For runtime package testing. */ - - -// Create a new g running fn with siz bytes of arguments. -// Put it on the queue of g's waiting to run. -// The compiler turns a go statement into a call to this. -// Cannot split the stack because it assumes that the arguments -// are available sequentially after &fn; they would not be -// copied if a stack split occurred. It's OK for this to call -// functions that split the stack. -void runtime_testing_entersyscall(int32) - __asm__ (GOSYM_PREFIX "runtime.entersyscall"); -void -runtime_testing_entersyscall(int32 dummy __attribute__ ((unused))) -{ - runtime_entersyscall(); -} - -void runtime_testing_exitsyscall(int32) - __asm__ (GOSYM_PREFIX "runtime.exitsyscall"); - -void -runtime_testing_exitsyscall(int32 dummy __attribute__ ((unused))) -{ - runtime_exitsyscall(); -} - G* __go_go(void (*fn)(void*), void* arg) { diff --git a/libgo/runtime/runtime.c b/libgo/runtime/runtime.c index e5e88ed292f..8e6f1f50524 100644 --- a/libgo/runtime/runtime.c +++ b/libgo/runtime/runtime.c @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <errno.h> #include <signal.h> #include <unistd.h> @@ -210,3 +211,12 @@ go_closefd(int32 fd) { return runtime_close(fd); } + +intgo go_errno(void) + __asm__ (GOSYM_PREFIX "runtime.errno"); + +intgo +go_errno() +{ + return (intgo)errno; +} diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index d223ec0ddda..d1aad1e2d73 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -108,8 +108,16 @@ struct FuncVal #include "array.h" #include "interface.h" +// Rename Go types generated by mkrsysinfo.sh from C types, to avoid +// the name conflict. +#define timeval go_timeval +#define timespec go_timespec + #include "runtime.inc" +#undef timeval +#undef timespec + /* * Per-CPU declaration. */ @@ -392,9 +400,12 @@ void runtime_parkunlock(Lock*, const char*); void runtime_tsleep(int64, const char*); M* runtime_newm(void); void runtime_goexit(void); -void runtime_entersyscall(void) __asm__ (GOSYM_PREFIX "syscall.Entersyscall"); -void runtime_entersyscallblock(void); -void runtime_exitsyscall(void) __asm__ (GOSYM_PREFIX "syscall.Exitsyscall"); +void runtime_entersyscall(int32) + __asm__ (GOSYM_PREFIX "runtime.entersyscall"); +void runtime_entersyscallblock(int32) + __asm__ (GOSYM_PREFIX "runtime.entersyscallblock"); +void runtime_exitsyscall(int32) + __asm__ (GOSYM_PREFIX "runtime.exitsyscall"); G* __go_go(void (*pfn)(void*), void*); void siginit(void); bool __go_sigsend(int32 sig); @@ -476,21 +487,16 @@ void runtime_unlock(Lock*) * notesleep/notetsleep are generally called on g0, * notetsleepg is similar to notetsleep but is called on user g. */ -void runtime_noteclear(Note*); -void runtime_notesleep(Note*); -void runtime_notewakeup(Note*); -bool runtime_notetsleep(Note*, int64); // false - timeout -bool runtime_notetsleepg(Note*, int64); // false - timeout - -/* - * low-level synchronization for implementing the above - */ -uintptr runtime_semacreate(void); -int32 runtime_semasleep(int64); -void runtime_semawakeup(M*); -// or -void runtime_futexsleep(uint32*, uint32, int64); -void runtime_futexwakeup(uint32*, uint32); +void runtime_noteclear(Note*) + __asm__ (GOSYM_PREFIX "runtime.noteclear"); +void runtime_notesleep(Note*) + __asm__ (GOSYM_PREFIX "runtime.notesleep"); +void runtime_notewakeup(Note*) + __asm__ (GOSYM_PREFIX "runtime.notewakeup"); +bool runtime_notetsleep(Note*, int64) // false - timeout + __asm__ (GOSYM_PREFIX "runtime.notetsleep"); +bool runtime_notetsleepg(Note*, int64) // false - timeout + __asm__ (GOSYM_PREFIX "runtime.notetsleepg"); /* * Lock-free stack. @@ -578,8 +584,10 @@ void runtime_newErrorCString(const char*, Eface*) void runtime_semacquire(uint32 volatile *, bool); void runtime_semrelease(uint32 volatile *); int32 runtime_gomaxprocsfunc(int32 n); -void runtime_procyield(uint32); -void runtime_osyield(void); +void runtime_procyield(uint32) + __asm__(GOSYM_PREFIX "runtime.procyield"); +void runtime_osyield(void) + __asm__(GOSYM_PREFIX "runtime.osyield"); void runtime_lockOSThread(void); void runtime_unlockOSThread(void); bool runtime_lockedOSThread(void); diff --git a/libgo/runtime/thread-linux.c b/libgo/runtime/thread-linux.c index ae56261e6f5..63a2b7551f6 100644 --- a/libgo/runtime/thread-linux.c +++ b/libgo/runtime/thread-linux.c @@ -7,69 +7,11 @@ #include "signal_unix.h" // Linux futex. -// -// futexsleep(uint32 *addr, uint32 val) -// futexwakeup(uint32 *addr) -// -// Futexsleep atomically checks if *addr == val and if so, sleeps on addr. -// Futexwakeup wakes up threads sleeping on addr. -// Futexsleep is allowed to wake up spuriously. -#include <errno.h> -#include <string.h> -#include <time.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> #include <unistd.h> #include <syscall.h> #include <linux/futex.h> -typedef struct timespec Timespec; - -// Atomically, -// if(*addr == val) sleep -// Might be woken up spuriously; that's allowed. -// Don't sleep longer than ns; ns < 0 means forever. -void -runtime_futexsleep(uint32 *addr, uint32 val, int64 ns) -{ - Timespec ts; - int32 nsec; - - // Some Linux kernels have a bug where futex of - // FUTEX_WAIT returns an internal error code - // as an errno. Libpthread ignores the return value - // here, and so can we: as it says a few lines up, - // spurious wakeups are allowed. - - if(ns < 0) { - syscall(__NR_futex, addr, FUTEX_WAIT, val, nil, nil, 0); - return; - } - ts.tv_sec = runtime_timediv(ns, 1000000000LL, &nsec); - ts.tv_nsec = nsec; - syscall(__NR_futex, addr, FUTEX_WAIT, val, &ts, nil, 0); -} - -// If any procs are sleeping on addr, wake up at most cnt. -void -runtime_futexwakeup(uint32 *addr, uint32 cnt) -{ - int64 ret; - - ret = syscall(__NR_futex, addr, FUTEX_WAKE, cnt, nil, nil, 0); - - if(ret >= 0) - return; - - // I don't know that futex wakeup can return - // EAGAIN or EINTR, but if it does, it would be - // safe to loop and call futex again. - runtime_printf("futexwakeup addr=%p returned %D\n", addr, ret); - *(int32*)0x1006 = 0x1006; -} - void runtime_osinit(void) { diff --git a/libgo/runtime/thread-sema.c b/libgo/runtime/thread-sema.c index 18827b025d7..b74b1dab112 100644 --- a/libgo/runtime/thread-sema.c +++ b/libgo/runtime/thread-sema.c @@ -10,131 +10,6 @@ #include <time.h> #include <semaphore.h> -/* If we don't have sem_timedwait, use pthread_cond_timedwait instead. - We don't always use condition variables because on some systems - pthread_mutex_lock and pthread_mutex_unlock must be called by the - same thread. That is never true of semaphores. */ - -struct go_sem -{ - sem_t sem; - -#ifndef HAVE_SEM_TIMEDWAIT - int timedwait; - pthread_mutex_t mutex; - pthread_cond_t cond; -#endif -}; - -/* Create a semaphore. */ - -uintptr -runtime_semacreate(void) -{ - struct go_sem *p; - - /* Call malloc rather than runtime_malloc. This will allocate space - on the C heap. We can't call runtime_malloc here because it - could cause a deadlock. */ - p = malloc (sizeof (struct go_sem)); - if (sem_init (&p->sem, 0, 0) != 0) - runtime_throw ("sem_init"); - -#ifndef HAVE_SEM_TIMEDWAIT - if (pthread_mutex_init (&p->mutex, NULL) != 0) - runtime_throw ("pthread_mutex_init"); - if (pthread_cond_init (&p->cond, NULL) != 0) - runtime_throw ("pthread_cond_init"); -#endif - - return (uintptr) p; -} - -/* Acquire m->waitsema. */ - -int32 -runtime_semasleep (int64 ns) -{ - M *m; - struct go_sem *sem; - int r; - - m = runtime_m (); - sem = (struct go_sem *) m->waitsema; - if (ns >= 0) - { - int64 abs; - struct timespec ts; - int err; - - abs = ns + runtime_nanotime (); - ts.tv_sec = abs / 1000000000LL; - ts.tv_nsec = abs % 1000000000LL; - - err = 0; - -#ifdef HAVE_SEM_TIMEDWAIT - r = sem_timedwait (&sem->sem, &ts); - if (r != 0) - err = errno; -#else - if (pthread_mutex_lock (&sem->mutex) != 0) - runtime_throw ("pthread_mutex_lock"); - - while ((r = sem_trywait (&sem->sem)) != 0) - { - r = pthread_cond_timedwait (&sem->cond, &sem->mutex, &ts); - if (r != 0) - { - err = r; - break; - } - } - - if (pthread_mutex_unlock (&sem->mutex) != 0) - runtime_throw ("pthread_mutex_unlock"); -#endif - - if (err != 0) - { - if (err == ETIMEDOUT || err == EAGAIN || err == EINTR) - return -1; - runtime_throw ("sema_timedwait"); - } - return 0; - } - - while (sem_wait (&sem->sem) != 0) - { - if (errno == EINTR) - continue; - runtime_throw ("sem_wait"); - } - - return 0; -} - -/* Wake up mp->waitsema. */ - -void -runtime_semawakeup (M *mp) -{ - struct go_sem *sem; - - sem = (struct go_sem *) mp->waitsema; - if (sem_post (&sem->sem) != 0) - runtime_throw ("sem_post"); - -#ifndef HAVE_SEM_TIMEDWAIT - if (pthread_mutex_lock (&sem->mutex) != 0) - runtime_throw ("pthread_mutex_lock"); - if (pthread_cond_broadcast (&sem->cond) != 0) - runtime_throw ("pthread_cond_broadcast"); - if (pthread_mutex_unlock (&sem->mutex) != 0) - runtime_throw ("pthread_mutex_unlock"); -#endif -} - void runtime_osinit (void) { diff --git a/libgo/sysinfo.c b/libgo/sysinfo.c index 07d68673eb0..09c0f496a6e 100644 --- a/libgo/sysinfo.c +++ b/libgo/sysinfo.c @@ -152,6 +152,9 @@ #if defined(HAVE_SCHED_H) #include <sched.h> #endif +#if defined(HAVE_SEMAPHORE_H) +#include <semaphore.h> +#endif /* Constants that may only be defined as expressions on some systems, expressions too complex for -fdump-go-spec to handle. These are |