runtime: copy internal locking code from Go 1.7 runtime

Remove the old locking code written in C.
    
    Add a shell script mkrsysinfo.sh to generate the runtime_sysinfo.go
    file, so that we can get Go copies of the system time structures and
    other types.
    
    Tweak the compiler so that when compiling the runtime package the
    address operator does not cause local variables to escape.  When the gc
    compiler compiles the runtime, an escaping local variable is treated as
    an error.  We should implement that, instead of this change, when escape
    analysis is turned on.
    
    Tweak the compiler so that the generated C header does not include names
    that start with an underscore followed by a non-upper-case letter,
    except for the special cases of _defer and _panic.  Otherwise we
    translate C types to Go in runtime_sysinfo.go and then generate those Go
    types back as C types in runtime.inc, which is useless and painful for
    the C code.
    
    Change entersyscall and friends to take a dummy argument, as the gc
    versions do, to simplify calls from the shared code.
    
    Reviewed-on: https://go-review.googlesource.com/30079

From-SVN: r240657
This commit is contained in:
Ian Lance Taylor 2016-09-30 13:45:08 +00:00
parent 9e28a77462
commit c0401cf78c
31 changed files with 1541 additions and 819 deletions

View 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.

View 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();

View 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)

View 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) $@

View 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) $@

View File

@ -195,6 +195,9 @@
/* Define to 1 if you have the <sched.h> header file. */
#undef HAVE_SCHED_H
/* Define to 1 if you have the <semaphore.h> header file. */
#undef HAVE_SEMAPHORE_H
/* Define to 1 if you have the `sem_timedwait' function. */
#undef HAVE_SEM_TIMEDWAIT

2
libgo/configure vendored
View File

@ -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"

View 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

View 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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
})
}

View File

@ -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")
})
}

View 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

View File

@ -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")
})
}
}

View File

@ -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")
})
}
}

View File

@ -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")
}
}

View 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 {

View 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)

103
libgo/mkrsysinfo.sh Executable file
View File

@ -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}

View 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);

View File

@ -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;
}

View File

@ -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;
}

View 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;
}

View 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)
{

View 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;
}

View 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);

View 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)
{

View File

@ -10,131 +10,6 @@
#include <time.h>
#include <semaphore.h>
/* If we don't have sem_timedwait, use pthread_cond_timedwait instead.
We don't always use condition variables because on some systems
pthread_mutex_lock and pthread_mutex_unlock must be called by the
same thread. That is never true of semaphores. */
struct go_sem
{
sem_t sem;
#ifndef HAVE_SEM_TIMEDWAIT
int timedwait;
pthread_mutex_t mutex;
pthread_cond_t cond;
#endif
};
/* Create a semaphore. */
uintptr
runtime_semacreate(void)
{
struct go_sem *p;
/* Call malloc rather than runtime_malloc. This will allocate space
on the C heap. We can't call runtime_malloc here because it
could cause a deadlock. */
p = malloc (sizeof (struct go_sem));
if (sem_init (&p->sem, 0, 0) != 0)
runtime_throw ("sem_init");
#ifndef HAVE_SEM_TIMEDWAIT
if (pthread_mutex_init (&p->mutex, NULL) != 0)
runtime_throw ("pthread_mutex_init");
if (pthread_cond_init (&p->cond, NULL) != 0)
runtime_throw ("pthread_cond_init");
#endif
return (uintptr) p;
}
/* Acquire m->waitsema. */
int32
runtime_semasleep (int64 ns)
{
M *m;
struct go_sem *sem;
int r;
m = runtime_m ();
sem = (struct go_sem *) m->waitsema;
if (ns >= 0)
{
int64 abs;
struct timespec ts;
int err;
abs = ns + runtime_nanotime ();
ts.tv_sec = abs / 1000000000LL;
ts.tv_nsec = abs % 1000000000LL;
err = 0;
#ifdef HAVE_SEM_TIMEDWAIT
r = sem_timedwait (&sem->sem, &ts);
if (r != 0)
err = errno;
#else
if (pthread_mutex_lock (&sem->mutex) != 0)
runtime_throw ("pthread_mutex_lock");
while ((r = sem_trywait (&sem->sem)) != 0)
{
r = pthread_cond_timedwait (&sem->cond, &sem->mutex, &ts);
if (r != 0)
{
err = r;
break;
}
}
if (pthread_mutex_unlock (&sem->mutex) != 0)
runtime_throw ("pthread_mutex_unlock");
#endif
if (err != 0)
{
if (err == ETIMEDOUT || err == EAGAIN || err == EINTR)
return -1;
runtime_throw ("sema_timedwait");
}
return 0;
}
while (sem_wait (&sem->sem) != 0)
{
if (errno == EINTR)
continue;
runtime_throw ("sem_wait");
}
return 0;
}
/* Wake up mp->waitsema. */
void
runtime_semawakeup (M *mp)
{
struct go_sem *sem;
sem = (struct go_sem *) mp->waitsema;
if (sem_post (&sem->sem) != 0)
runtime_throw ("sem_post");
#ifndef HAVE_SEM_TIMEDWAIT
if (pthread_mutex_lock (&sem->mutex) != 0)
runtime_throw ("pthread_mutex_lock");
if (pthread_cond_broadcast (&sem->cond) != 0)
runtime_throw ("pthread_cond_broadcast");
if (pthread_mutex_unlock (&sem->mutex) != 0)
runtime_throw ("pthread_mutex_unlock");
#endif
}
void
runtime_osinit (void)
{

View File

@ -152,6 +152,9 @@
#if defined(HAVE_SCHED_H)
#include <sched.h>
#endif
#if defined(HAVE_SEMAPHORE_H)
#include <semaphore.h>
#endif
/* Constants that may only be defined as expressions on some systems,
expressions too complex for -fdump-go-spec to handle. These are