runtime: copy internal locking code from Go 1.7 runtime
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 30 Sep 2016 13:45:08 +0000 (13:45 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 30 Sep 2016 13:45:08 +0000 (13:45 +0000)
    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

31 files changed:
gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/gogo.cc
libgo/Makefile.am
libgo/Makefile.in
libgo/config.h.in
libgo/configure
libgo/configure.ac
libgo/go/runtime/export_test.go
libgo/go/runtime/lock_futex.go [new file with mode: 0644]
libgo/go/runtime/lock_sema.go [new file with mode: 0644]
libgo/go/runtime/os_darwin.go [new file with mode: 0644]
libgo/go/runtime/os_dragonfly.go [new file with mode: 0644]
libgo/go/runtime/os_freebsd.go [new file with mode: 0644]
libgo/go/runtime/os_linux.go
libgo/go/runtime/os_netbsd.go [new file with mode: 0644]
libgo/go/runtime/os_openbsd.go [new file with mode: 0644]
libgo/go/runtime/os_solaris.go [new file with mode: 0644]
libgo/go/runtime/runtime2.go
libgo/go/runtime/stubs.go
libgo/mkrsysinfo.sh [new file with mode: 0755]
libgo/runtime/go-cgo.c
libgo/runtime/lock_futex.c [deleted file]
libgo/runtime/lock_sema.c [deleted file]
libgo/runtime/malloc.goc
libgo/runtime/proc.c
libgo/runtime/runtime.c
libgo/runtime/runtime.h
libgo/runtime/thread-linux.c
libgo/runtime/thread-sema.c
libgo/sysinfo.c

index 6e5d3c4675202a0d17cacd519da228d4c1d05a17..092baa22ced61c3de51f6f86b4997f3398d8dac2 100644 (file)
@@ -1,4 +1,4 @@
-e51657a576367c7a498c94baf985b79066fc082a
+f3fb9bf2d5a009a707962a416fcd1a8435756218
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 5342e45754dc0b6773941f9bd4fdc1ddcd79c115..64b0d3c8341b8b568fce931b4c0665f7ff221556 100644 (file)
@@ -3787,6 +3787,13 @@ Unary_expression::do_flatten(Gogo* gogo, Named_object*,
       if ((n->encoding() & ESCAPE_MASK) == int(Node::ESCAPE_NONE))
        this->escapes_ = false;
 
+      // When compiling the runtime, the address operator does not
+      // cause local variables to escapes.  When escape analysis
+      // becomes the default, this should be changed to make it an
+      // error if we have an address operator that escapes.
+      if (gogo->compiling_runtime() && gogo->package_name() == "runtime")
+       this->escapes_ = false;
+
       Named_object* var = NULL;
       if (this->expr_->var_expression() != NULL)
        var = this->expr_->var_expression()->named_object();
index 587ebd434a9057fe5e39f4dd39eb22d3c6d97f6b..30392f76b3fe11e9505d7ab4668edc6d50700c0a 100644 (file)
@@ -4480,6 +4480,19 @@ Gogo::write_c_header()
        ++p)
     {
       Named_object* no = *p;
+
+      // Skip names that start with underscore followed by something
+      // other than an uppercase letter, as when compiling the runtime
+      // package they are mostly types defined by mkrsysinfo.sh based
+      // on the C system header files.  We don't need to translate
+      // types to C and back to Go.  But do accept the special cases
+      // _defer and _panic.
+      std::string name = Gogo::unpack_hidden_name(no->name());
+      if (name[0] == '_'
+         && (name[1] < 'A' || name[1] > 'Z')
+         && (name != "_defer" && name != "_panic"))
+       continue;
+
       if (no->is_type() && no->type_value()->struct_type() != NULL)
        types.push_back(no);
       if (no->is_const() && no->const_value()->type()->integer_type() != NULL)
index 23cfd07ba945660a13d67a9eebfefa183ce464dd..e5150693fab858c3cb63f9fe6aa8c21ad3965846 100644 (file)
@@ -396,9 +396,9 @@ rtems_task_variable_add_file =
 endif
 
 if LIBGO_IS_LINUX
-runtime_lock_files = runtime/lock_futex.c runtime/thread-linux.c
+runtime_thread_files = runtime/thread-linux.c
 else
-runtime_lock_files = runtime/lock_sema.c runtime/thread-sema.c
+runtime_thread_files = runtime/thread-sema.c
 endif
 
 if LIBGO_IS_LINUX
@@ -502,7 +502,6 @@ runtime_files = \
        runtime/go-varargs.c \
        runtime/env_posix.c \
        runtime/heapdump.c \
-       $(runtime_lock_files) \
        runtime/mcache.c \
        runtime/mcentral.c \
        $(runtime_mem_file) \
@@ -518,6 +517,7 @@ runtime_files = \
        runtime/runtime.c \
        runtime/signal_unix.c \
        runtime/thread.c \
+       $(runtime_thread_files) \
        runtime/yield.c \
        $(rtems_task_variable_add_file) \
        chan.c \
@@ -633,12 +633,8 @@ s-version: Makefile
        $(STAMP) $@
 
 runtime_sysinfo.go: s-runtime_sysinfo; @true
-s-runtime_sysinfo: sysinfo.go
-       rm -f tmp-runtime_sysinfo.go
-       echo 'package runtime' > tmp-runtime_sysinfo.go
-       echo >> tmp-runtime_sysinfo.go
-       grep 'const _sizeof_ucontext_t ' sysinfo.go >> tmp-runtime_sysinfo.go
-       grep 'type _sigset_t ' sysinfo.go >> tmp-runtime_sysinfo.go
+s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go
+       $(SHELL) $(srcdir)/mkrsysinfo.sh
        $(SHELL) $(srcdir)/mvifdiff.sh tmp-runtime_sysinfo.go runtime_sysinfo.go
        $(STAMP) $@
 
index b1fb87c900dc49c1db59e1471859df88e273f535..bc6832dce0fa8d1456733813641db402128b6322 100644 (file)
@@ -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) $@
 
index 298b8d660e3a157416955d617a561536d77dfafd..14938da59c161058cdf62f8edd970f6a2c5db377 100644 (file)
 /* 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
 
index 137e7a66c863dd871b222af8177ed5139b498f6d..e065417fa155b94cd8c6fdfb86e604fa72a69387 100755 (executable)
@@ -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"
index 2224f40c3caa138ea8485a3e8ca67950b8cf6da6..0f98ae83751682abde95a377f07645c56278a623 100644 (file)
@@ -570,7 +570,7 @@ AC_C_BIGENDIAN
 
 GCC_CHECK_UNWIND_GETIPINFO
 
-AC_CHECK_HEADERS(sched.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/icmp6.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h)
+AC_CHECK_HEADERS(sched.h semaphore.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/icmp6.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h)
 
 AC_CHECK_HEADERS([linux/filter.h linux/if_addr.h linux/if_ether.h linux/if_tun.h linux/netlink.h linux/rtnetlink.h], [], [],
 [#ifdef HAVE_SYS_SOCKET_H
index b13e3829423a2c3313406a7590ddbf4cedea986a..711a551d2785bf90bdcbe4526c15655bcf6265a3 100644 (file)
@@ -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 (file)
index 0000000..1ad7911
--- /dev/null
@@ -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 (file)
index 0000000..eaf938a
--- /dev/null
@@ -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 (file)
index 0000000..db403e2
--- /dev/null
@@ -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 (file)
index 0000000..6452984
--- /dev/null
@@ -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 (file)
index 0000000..4512e76
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+       "unsafe"
+)
+
+type mOS struct {
+       unused byte
+}
+
+//go:noescape
+//extern _umtx_op
+func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32
+
+// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
+// thus the code is largely similar. See Linux implementation
+// and lock_futex.go for comments.
+
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+       systemstack(func() {
+               futexsleep1(addr, val, ns)
+       })
+}
+
+func futexsleep1(addr *uint32, val uint32, ns int64) {
+       var tsp *timespec
+       if ns >= 0 {
+               var ts timespec
+               ts.tv_nsec = 0
+               ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
+               tsp = &ts
+       }
+       ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp)
+       if ret >= 0 || ret == -_EINTR {
+               return
+       }
+       print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
+       *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
+}
+
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+       ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil)
+       if ret >= 0 {
+               return
+       }
+
+       systemstack(func() {
+               print("umtx_wake_addr=", addr, " ret=", ret, "\n")
+       })
+}
index c44e4e8287ef42b8b3eda80334b40a2cc9b3b39a..04c690bd42feba990d3014fa85a2ad9c71fb4d9c 100644 (file)
@@ -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 (file)
index 0000000..464ce88
--- /dev/null
@@ -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 (file)
index 0000000..b64d3af
--- /dev/null
@@ -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 (file)
index 0000000..cf45768
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "unsafe"
+
+type mOS struct {
+       waitsema uintptr // semaphore for parking on locks
+}
+
+//extern malloc
+func libc_malloc(uintptr) unsafe.Pointer
+
+//go:noescape
+//extern sem_init
+func sem_init(sem *semt, pshared int32, value uint32) int32
+
+//go:noescape
+//extern sem_wait
+func sem_wait(sem *semt) int32
+
+//go:noescape
+//extern sem_post
+func sem_post(sem *semt) int32
+
+//go:noescape
+//extern sem_reltimedwait_np
+func sem_reltimedwait_np(sem *semt, timeout *timespec) int32
+
+//go:nosplit
+func semacreate(mp *m) {
+       if mp.mos.waitsema != 0 {
+               return
+       }
+
+       var sem *semt
+
+       // Call libc's malloc rather than malloc. This will
+       // allocate space on the C heap. We can't call malloc
+       // here because it could cause a deadlock.
+       sem = (*semt)(libc_malloc(unsafe.Sizeof(*sem)))
+       if sem_init(sem, 0, 0) != 0 {
+               throw("sem_init")
+       }
+       mp.mos.waitsema = uintptr(unsafe.Pointer(sem))
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+       _m_ := getg().m
+       if ns >= 0 {
+               var ts timespec
+               ts.set_sec(ns / 1000000000)
+               ts.set_nsec(int32(ns % 1000000000))
+
+               if sem_reltimedwait_np((*semt)(unsafe.Pointer(_m_.mos.waitsema)), &ts) != 0 {
+                       err := errno()
+                       if err == _ETIMEDOUT || err == _EAGAIN || err == _EINTR {
+                               return -1
+                       }
+                       throw("sem_reltimedwait_np")
+               }
+               return 0
+       }
+       for {
+               r1 := sem_wait((*semt)(unsafe.Pointer(_m_.mos.waitsema)))
+               if r1 == 0 {
+                       break
+               }
+               if errno() == _EINTR {
+                       continue
+               }
+               throw("sem_wait")
+       }
+       return 0
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+       if sem_post((*semt)(unsafe.Pointer(mp.mos.waitsema))) != 0 {
+               throw("sem_post")
+       }
+}
index 4fba428d7af0fa3aecd33d0ccc78e1220a8bd69b..17447eb48bcaf518774fe40ada5ae95f4bbc4540 100644 (file)
@@ -396,7 +396,7 @@ type g struct {
        gcnextsegment unsafe.Pointer
        gcnextsp      unsafe.Pointer
        gcinitialsp   unsafe.Pointer
-       gcregs        _ucontext_t
+       gcregs        g_ucontext_t
 
        entry    unsafe.Pointer // goroutine entry point
        fromgogo bool           // whether entered from gogo function
@@ -406,7 +406,7 @@ type g struct {
 
        traceback *traceback // stack traceback buffer
 
-       context      _ucontext_t        // saved context for setcontext
+       context      g_ucontext_t       // saved context for setcontext
        stackcontext [10]unsafe.Pointer // split-stack context
 }
 
@@ -474,7 +474,7 @@ type m struct {
        // Not for gccgo: libcallg  guintptr
        // Not for gccgo: syscall   libcall // stores syscall parameters on windows
 
-       // Not for gccgo: mOS
+       mos mOS
 
        // Remaining fields are specific to gccgo.
 
@@ -485,8 +485,6 @@ type m struct {
 
        gcing int32
 
-       waitsema uintptr // semaphore on systems that don't use futexes
-
        cgomal *cgoMal // allocations via _cgo_allocate
 }
 
@@ -771,13 +769,15 @@ const (
 const _TracebackMaxFrames = 100
 
 var (
-//     emptystring string
-//     allglen     uintptr
-//     allm        *m
-//     allp        [_MaxGomaxprocs + 1]*p
-//     gomaxprocs  int32
-//     panicking   uint32
-//     ncpu        int32
+       //      emptystring string
+       //      allglen     uintptr
+       //      allm        *m
+       //      allp        [_MaxGomaxprocs + 1]*p
+       //      gomaxprocs  int32
+       //      panicking   uint32
+
+       ncpu int32
+
 //     forcegc     forcegcstate
 //     sched       schedt
 //     newprocs    int32
@@ -803,13 +803,13 @@ var (
 
 // Types that are only used by gccgo.
 
-// _ucontext_t is a Go version of the C ucontext_t type, used by getcontext.
-// _sizeof_ucontext_t is defined by the Makefile from <ucontext.h>.
+// g_ucontext_t is a Go version of the C ucontext_t type, used by getcontext.
+// _sizeof_ucontext_t is defined by mkrsysinfo.sh from <ucontext.h>.
 // On some systems getcontext and friends require a value that is
 // aligned to a 16-byte boundary.  We implement this by increasing the
 // required size and picking an appropriate offset when we use the
 // array.
-type _ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(unsafe.Pointer(nil))]unsafe.Pointer
+type g_ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(unsafe.Pointer(nil))]unsafe.Pointer
 
 // traceback is used to collect stack traces from other goroutines.
 type traceback struct {
index 3ff3aef2216300a0425761cae89194d52cb499bd..bbeac41a4dcc181c14b0a154c9d7a29f90822108 100644 (file)
@@ -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 (executable)
index 0000000..b5c2c70
--- /dev/null
@@ -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}
index 598c2617840f33c231dcb50d68cb728b77c1d6ca..7d0494c3a6580a8ba606b6f36b6d2ddb5405f26e 100644 (file)
@@ -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 (file)
index 33ef073..0000000
+++ /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 (file)
index 06ac6e7..0000000
+++ /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;
-}
index 591d06a7f59fcc453ceb2cc53c674e9678d853ad..a924b8adfa2742b729a56f7ad758fb1dabf2d01c 100644 (file)
@@ -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;
 }
index 32d0fb2a7be7c2c8a5f17490be290ba90c552b76..dac32eb678e738e8aae84ca2cb8fb816236adc10 100644 (file)
@@ -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)
 {
index e5e88ed292f046908eed957bf231e83698f9f150..8e6f1f5052468bd5eb54a74249d49f9d8128157e 100644 (file)
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+#include <errno.h>
 #include <signal.h>
 #include <unistd.h>
 
@@ -210,3 +211,12 @@ go_closefd(int32 fd)
 {
   return runtime_close(fd);
 }
+
+intgo go_errno(void)
+  __asm__ (GOSYM_PREFIX "runtime.errno");
+
+intgo
+go_errno()
+{
+  return (intgo)errno;
+}
index d223ec0ddda672205dbce678a2878473ec105f65..d1aad1e2d73010e3e1d5937c3631c8b60b727687 100644 (file)
@@ -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);
index ae56261e6f57267d7b41aa7a0a65ddae0c06e11c..63a2b7551f6718e333917bde2a8b9abda38adb0c 100644 (file)
@@ -7,69 +7,11 @@
 #include "signal_unix.h"
 
 // Linux futex.
-//
-//     futexsleep(uint32 *addr, uint32 val)
-//     futexwakeup(uint32 *addr)
-//
-// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
-// Futexwakeup wakes up threads sleeping on addr.
-// Futexsleep is allowed to wake up spuriously.
 
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 #include <unistd.h>
 #include <syscall.h>
 #include <linux/futex.h>
 
-typedef struct timespec Timespec;
-
-// Atomically,
-//     if(*addr == val) sleep
-// Might be woken up spuriously; that's allowed.
-// Don't sleep longer than ns; ns < 0 means forever.
-void
-runtime_futexsleep(uint32 *addr, uint32 val, int64 ns)
-{
-       Timespec ts;
-       int32 nsec;
-
-       // Some Linux kernels have a bug where futex of
-       // FUTEX_WAIT returns an internal error code
-       // as an errno.  Libpthread ignores the return value
-       // here, and so can we: as it says a few lines up,
-       // spurious wakeups are allowed.
-
-       if(ns < 0) {
-               syscall(__NR_futex, addr, FUTEX_WAIT, val, nil, nil, 0);
-               return;
-       }
-       ts.tv_sec = runtime_timediv(ns, 1000000000LL, &nsec);
-       ts.tv_nsec = nsec;
-       syscall(__NR_futex, addr, FUTEX_WAIT, val, &ts, nil, 0);
-}
-
-// If any procs are sleeping on addr, wake up at most cnt.
-void
-runtime_futexwakeup(uint32 *addr, uint32 cnt)
-{
-       int64 ret;
-
-       ret = syscall(__NR_futex, addr, FUTEX_WAKE, cnt, nil, nil, 0);
-
-       if(ret >= 0)
-               return;
-
-       // I don't know that futex wakeup can return
-       // EAGAIN or EINTR, but if it does, it would be
-       // safe to loop and call futex again.
-       runtime_printf("futexwakeup addr=%p returned %D\n", addr, ret);
-       *(int32*)0x1006 = 0x1006;
-}
-
 void
 runtime_osinit(void)
 {
index 18827b025d7e2b642b99d0818318c0019b272bd6..b74b1dab1123beb5c638a6602bee3f01569cbfe7 100644 (file)
 #include <time.h>
 #include <semaphore.h>
 
-/* If we don't have sem_timedwait, use pthread_cond_timedwait instead.
-   We don't always use condition variables because on some systems
-   pthread_mutex_lock and pthread_mutex_unlock must be called by the
-   same thread.  That is never true of semaphores.  */
-
-struct go_sem
-{
-  sem_t sem;
-
-#ifndef HAVE_SEM_TIMEDWAIT
-  int timedwait;
-  pthread_mutex_t mutex;
-  pthread_cond_t cond;
-#endif
-};
-
-/* Create a semaphore.  */
-
-uintptr
-runtime_semacreate(void)
-{
-  struct go_sem *p;
-
-  /* Call malloc rather than runtime_malloc.  This will allocate space
-     on the C heap.  We can't call runtime_malloc here because it
-     could cause a deadlock.  */
-  p = malloc (sizeof (struct go_sem));
-  if (sem_init (&p->sem, 0, 0) != 0)
-    runtime_throw ("sem_init");
-
-#ifndef HAVE_SEM_TIMEDWAIT
-  if (pthread_mutex_init (&p->mutex, NULL) != 0)
-    runtime_throw ("pthread_mutex_init");
-  if (pthread_cond_init (&p->cond, NULL) != 0)
-    runtime_throw ("pthread_cond_init");
-#endif
-
-  return (uintptr) p;
-}
-
-/* Acquire m->waitsema.  */
-
-int32
-runtime_semasleep (int64 ns)
-{
-  M *m;
-  struct go_sem *sem;
-  int r;
-
-  m = runtime_m ();
-  sem = (struct go_sem *) m->waitsema;
-  if (ns >= 0)
-    {
-      int64 abs;
-      struct timespec ts;
-      int err;
-
-      abs = ns + runtime_nanotime ();
-      ts.tv_sec = abs / 1000000000LL;
-      ts.tv_nsec = abs % 1000000000LL;
-
-      err = 0;
-
-#ifdef HAVE_SEM_TIMEDWAIT
-      r = sem_timedwait (&sem->sem, &ts);
-      if (r != 0)
-       err = errno;
-#else
-      if (pthread_mutex_lock (&sem->mutex) != 0)
-       runtime_throw ("pthread_mutex_lock");
-
-      while ((r = sem_trywait (&sem->sem)) != 0)
-       {
-         r = pthread_cond_timedwait (&sem->cond, &sem->mutex, &ts);
-         if (r != 0)
-           {
-             err = r;
-             break;
-           }
-       }
-
-      if (pthread_mutex_unlock (&sem->mutex) != 0)
-       runtime_throw ("pthread_mutex_unlock");
-#endif
-
-      if (err != 0)
-       {
-         if (err == ETIMEDOUT || err == EAGAIN || err == EINTR)
-           return -1;
-         runtime_throw ("sema_timedwait");
-       }
-      return 0;
-    }
-
-  while (sem_wait (&sem->sem) != 0)
-    {
-      if (errno == EINTR)
-       continue;
-      runtime_throw ("sem_wait");
-    }
-
-  return 0;
-}
-
-/* Wake up mp->waitsema.  */
-
-void
-runtime_semawakeup (M *mp)
-{
-  struct go_sem *sem;
-
-  sem = (struct go_sem *) mp->waitsema;
-  if (sem_post (&sem->sem) != 0)
-    runtime_throw ("sem_post");
-
-#ifndef HAVE_SEM_TIMEDWAIT
-  if (pthread_mutex_lock (&sem->mutex) != 0)
-    runtime_throw ("pthread_mutex_lock");
-  if (pthread_cond_broadcast (&sem->cond) != 0)
-    runtime_throw ("pthread_cond_broadcast");
-  if (pthread_mutex_unlock (&sem->mutex) != 0)
-    runtime_throw ("pthread_mutex_unlock");
-#endif
-}
-
 void
 runtime_osinit (void)
 {
index 07d68673eb011af53c3dc6e11677a3350bd789ca..09c0f496a6e635439be5a3931ede4189f21287a5 100644 (file)
 #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