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