diff options
Diffstat (limited to 'libgo')
-rw-r--r-- | libgo/Makefile.am | 16 | ||||
-rw-r--r-- | libgo/Makefile.in | 182 | ||||
-rw-r--r-- | libgo/runtime/chan.c | 1248 | ||||
-rw-r--r-- | libgo/runtime/chan.goc | 57 | ||||
-rw-r--r-- | libgo/runtime/channel.h | 152 | ||||
-rw-r--r-- | libgo/runtime/go-chan-cap.c | 41 | ||||
-rw-r--r-- | libgo/runtime/go-chan-len.c | 41 | ||||
-rw-r--r-- | libgo/runtime/go-close.c | 42 | ||||
-rw-r--r-- | libgo/runtime/go-new-channel.c | 70 | ||||
-rw-r--r-- | libgo/runtime/go-rec-big.c | 43 | ||||
-rw-r--r-- | libgo/runtime/go-rec-nb-big.c | 46 | ||||
-rw-r--r-- | libgo/runtime/go-rec-nb-small.c | 123 | ||||
-rw-r--r-- | libgo/runtime/go-rec-small.c | 304 | ||||
-rw-r--r-- | libgo/runtime/go-reflect-chan.c | 200 | ||||
-rw-r--r-- | libgo/runtime/go-select.c | 758 | ||||
-rw-r--r-- | libgo/runtime/go-send-big.c | 34 | ||||
-rw-r--r-- | libgo/runtime/go-send-nb-big.c | 33 | ||||
-rw-r--r-- | libgo/runtime/go-send-nb-small.c | 107 | ||||
-rw-r--r-- | libgo/runtime/go-send-small.c | 159 | ||||
-rw-r--r-- | libgo/runtime/go-signal.c | 4 | ||||
-rw-r--r-- | libgo/runtime/runtime.h | 11 | ||||
-rw-r--r-- | libgo/runtime/thread.c | 24 |
22 files changed, 1282 insertions, 2413 deletions
diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 5ab10a61f3d..19ce7152cf1 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -409,10 +409,7 @@ runtime_files = \ runtime/go-caller.c \ runtime/go-can-convert-interface.c \ runtime/go-cgo.c \ - runtime/go-chan-cap.c \ - runtime/go-chan-len.c \ runtime/go-check-interface.c \ - runtime/go-close.c \ runtime/go-construct-map.c \ runtime/go-convert-interface.c \ runtime/go-copy.c \ @@ -432,27 +429,16 @@ runtime_files = \ runtime/go-map-len.c \ runtime/go-map-range.c \ runtime/go-nanotime.c \ - runtime/go-new-channel.c \ runtime/go-new-map.c \ runtime/go-new.c \ runtime/go-panic.c \ runtime/go-print.c \ - runtime/go-rec-big.c \ - runtime/go-rec-nb-big.c \ - runtime/go-rec-nb-small.c \ - runtime/go-rec-small.c \ runtime/go-recover.c \ runtime/go-reflect.c \ runtime/go-reflect-call.c \ - runtime/go-reflect-chan.c \ runtime/go-reflect-map.c \ runtime/go-rune.c \ runtime/go-runtime-error.c \ - runtime/go-select.c \ - runtime/go-send-big.c \ - runtime/go-send-nb-big.c \ - runtime/go-send-nb-small.c \ - runtime/go-send-small.c \ runtime/go-setenv.c \ runtime/go-signal.c \ runtime/go-strcmp.c \ @@ -473,6 +459,7 @@ runtime_files = \ runtime/go-unsafe-newarray.c \ runtime/go-unsafe-pointer.c \ runtime/go-unwind.c \ + runtime/chan.c \ runtime/cpuprof.c \ $(runtime_lock_files) \ runtime/mcache.c \ @@ -488,7 +475,6 @@ runtime_files = \ runtime/thread.c \ runtime/yield.c \ $(rtems_task_variable_add_file) \ - chan.c \ iface.c \ malloc.c \ map.c \ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index f7c293a66cc..1a76f0b5a20 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -183,8 +183,7 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ runtime/go-assert-interface.c \ runtime/go-byte-array-to-string.c runtime/go-breakpoint.c \ runtime/go-caller.c runtime/go-can-convert-interface.c \ - runtime/go-cgo.c runtime/go-chan-cap.c runtime/go-chan-len.c \ - runtime/go-check-interface.c runtime/go-close.c \ + runtime/go-cgo.c runtime/go-check-interface.c \ runtime/go-construct-map.c runtime/go-convert-interface.c \ runtime/go-copy.c runtime/go-defer.c \ runtime/go-deferred-recover.c runtime/go-eface-compare.c \ @@ -195,17 +194,11 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ runtime/go-interface-val-compare.c runtime/go-make-slice.c \ runtime/go-map-delete.c runtime/go-map-index.c \ runtime/go-map-len.c runtime/go-map-range.c \ - runtime/go-nanotime.c runtime/go-new-channel.c \ - runtime/go-new-map.c runtime/go-new.c runtime/go-panic.c \ - runtime/go-print.c runtime/go-rec-big.c \ - runtime/go-rec-nb-big.c runtime/go-rec-nb-small.c \ - runtime/go-rec-small.c runtime/go-recover.c \ + runtime/go-nanotime.c runtime/go-new-map.c runtime/go-new.c \ + runtime/go-panic.c runtime/go-print.c runtime/go-recover.c \ runtime/go-reflect.c runtime/go-reflect-call.c \ - runtime/go-reflect-chan.c runtime/go-reflect-map.c \ - runtime/go-rune.c runtime/go-runtime-error.c \ - runtime/go-select.c runtime/go-send-big.c \ - runtime/go-send-nb-big.c runtime/go-send-nb-small.c \ - runtime/go-send-small.c runtime/go-setenv.c \ + runtime/go-reflect-map.c runtime/go-rune.c \ + runtime/go-runtime-error.c runtime/go-setenv.c \ runtime/go-signal.c runtime/go-strcmp.c \ runtime/go-string-to-byte-array.c \ runtime/go-string-to-int-array.c runtime/go-strplus.c \ @@ -215,15 +208,15 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ runtime/go-type-string.c runtime/go-typedesc-equal.c \ runtime/go-typestring.c runtime/go-unreflect.c \ runtime/go-unsafe-new.c runtime/go-unsafe-newarray.c \ - runtime/go-unsafe-pointer.c runtime/go-unwind.c \ + runtime/go-unsafe-pointer.c runtime/go-unwind.c runtime/chan.c \ runtime/cpuprof.c runtime/lock_sema.c runtime/thread-sema.c \ runtime/lock_futex.c runtime/thread-linux.c runtime/mcache.c \ runtime/mcentral.c runtime/mem_posix_memalign.c runtime/mem.c \ runtime/mfinal.c runtime/mfixalloc.c runtime/mgc0.c \ runtime/mheap.c runtime/msize.c runtime/proc.c \ runtime/runtime.c runtime/thread.c runtime/yield.c \ - runtime/rtems-task-variable-add.c chan.c iface.c malloc.c \ - map.c mprof.c reflect.c runtime1.c sema.c sigqueue.c string.c + runtime/rtems-task-variable-add.c iface.c malloc.c map.c \ + mprof.c reflect.c runtime1.c sema.c sigqueue.c string.c @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 @@ -231,8 +224,7 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ @LIBGO_IS_RTEMS_TRUE@am__objects_3 = rtems-task-variable-add.lo am__objects_4 = go-append.lo go-assert.lo go-assert-interface.lo \ go-byte-array-to-string.lo go-breakpoint.lo go-caller.lo \ - go-can-convert-interface.lo go-cgo.lo go-chan-cap.lo \ - go-chan-len.lo go-check-interface.lo go-close.lo \ + go-can-convert-interface.lo go-cgo.lo go-check-interface.lo \ go-construct-map.lo go-convert-interface.lo go-copy.lo \ go-defer.lo go-deferred-recover.lo go-eface-compare.lo \ go-eface-val-compare.lo go-getgoroot.lo \ @@ -240,23 +232,20 @@ am__objects_4 = go-append.lo go-assert.lo go-assert-interface.lo \ go-interface-compare.lo go-interface-eface-compare.lo \ go-interface-val-compare.lo go-make-slice.lo go-map-delete.lo \ go-map-index.lo go-map-len.lo go-map-range.lo go-nanotime.lo \ - go-new-channel.lo go-new-map.lo go-new.lo go-panic.lo \ - go-print.lo go-rec-big.lo go-rec-nb-big.lo go-rec-nb-small.lo \ - go-rec-small.lo go-recover.lo go-reflect.lo go-reflect-call.lo \ - go-reflect-chan.lo go-reflect-map.lo go-rune.lo \ - go-runtime-error.lo go-select.lo go-send-big.lo \ - go-send-nb-big.lo go-send-nb-small.lo go-send-small.lo \ - go-setenv.lo go-signal.lo go-strcmp.lo \ + go-new-map.lo go-new.lo go-panic.lo go-print.lo go-recover.lo \ + go-reflect.lo go-reflect-call.lo go-reflect-map.lo go-rune.lo \ + go-runtime-error.lo go-setenv.lo go-signal.lo go-strcmp.lo \ go-string-to-byte-array.lo go-string-to-int-array.lo \ go-strplus.lo go-strslice.lo go-trampoline.lo go-type-eface.lo \ go-type-error.lo go-type-identity.lo go-type-interface.lo \ go-type-string.lo go-typedesc-equal.lo go-typestring.lo \ go-unreflect.lo go-unsafe-new.lo go-unsafe-newarray.lo \ - go-unsafe-pointer.lo go-unwind.lo cpuprof.lo $(am__objects_1) \ - mcache.lo mcentral.lo $(am__objects_2) mfinal.lo mfixalloc.lo \ - mgc0.lo mheap.lo msize.lo proc.lo runtime.lo thread.lo \ - yield.lo $(am__objects_3) chan.lo iface.lo malloc.lo map.lo \ - mprof.lo reflect.lo runtime1.lo sema.lo sigqueue.lo string.lo + go-unsafe-pointer.lo go-unwind.lo chan.lo cpuprof.lo \ + $(am__objects_1) mcache.lo mcentral.lo $(am__objects_2) \ + mfinal.lo mfixalloc.lo mgc0.lo mheap.lo msize.lo proc.lo \ + runtime.lo thread.lo yield.lo $(am__objects_3) iface.lo \ + malloc.lo map.lo mprof.lo reflect.lo runtime1.lo sema.lo \ + sigqueue.lo string.lo am_libgo_la_OBJECTS = $(am__objects_4) libgo_la_OBJECTS = $(am_libgo_la_OBJECTS) libgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ @@ -836,10 +825,7 @@ runtime_files = \ runtime/go-caller.c \ runtime/go-can-convert-interface.c \ runtime/go-cgo.c \ - runtime/go-chan-cap.c \ - runtime/go-chan-len.c \ runtime/go-check-interface.c \ - runtime/go-close.c \ runtime/go-construct-map.c \ runtime/go-convert-interface.c \ runtime/go-copy.c \ @@ -859,27 +845,16 @@ runtime_files = \ runtime/go-map-len.c \ runtime/go-map-range.c \ runtime/go-nanotime.c \ - runtime/go-new-channel.c \ runtime/go-new-map.c \ runtime/go-new.c \ runtime/go-panic.c \ runtime/go-print.c \ - runtime/go-rec-big.c \ - runtime/go-rec-nb-big.c \ - runtime/go-rec-nb-small.c \ - runtime/go-rec-small.c \ runtime/go-recover.c \ runtime/go-reflect.c \ runtime/go-reflect-call.c \ - runtime/go-reflect-chan.c \ runtime/go-reflect-map.c \ runtime/go-rune.c \ runtime/go-runtime-error.c \ - runtime/go-select.c \ - runtime/go-send-big.c \ - runtime/go-send-nb-big.c \ - runtime/go-send-nb-small.c \ - runtime/go-send-small.c \ runtime/go-setenv.c \ runtime/go-signal.c \ runtime/go-strcmp.c \ @@ -900,6 +875,7 @@ runtime_files = \ runtime/go-unsafe-newarray.c \ runtime/go-unsafe-pointer.c \ runtime/go-unwind.c \ + runtime/chan.c \ runtime/cpuprof.c \ $(runtime_lock_files) \ runtime/mcache.c \ @@ -915,7 +891,6 @@ runtime_files = \ runtime/thread.c \ runtime/yield.c \ $(rtems_task_variable_add_file) \ - chan.c \ iface.c \ malloc.c \ map.c \ @@ -2461,10 +2436,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-caller.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-can-convert-interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-cgo.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-chan-cap.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-chan-len.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-check-interface.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-close.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-construct-map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-convert-interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-copy.Plo@am__quote@ @@ -2485,27 +2457,16 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-len.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-range.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-nanotime.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-channel.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-panic.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-print.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-big.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-nb-big.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-nb-small.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-small.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-recover.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-call.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-chan.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rune.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-runtime-error.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-select.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-big.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-nb-big.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-nb-small.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-small.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-setenv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-signal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strcmp.Plo@am__quote@ @@ -2645,20 +2606,6 @@ go-cgo.lo: runtime/go-cgo.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 go-cgo.lo `test -f 'runtime/go-cgo.c' || echo '$(srcdir)/'`runtime/go-cgo.c -go-chan-cap.lo: runtime/go-chan-cap.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-chan-cap.lo -MD -MP -MF $(DEPDIR)/go-chan-cap.Tpo -c -o go-chan-cap.lo `test -f 'runtime/go-chan-cap.c' || echo '$(srcdir)/'`runtime/go-chan-cap.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-chan-cap.Tpo $(DEPDIR)/go-chan-cap.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-chan-cap.c' object='go-chan-cap.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 go-chan-cap.lo `test -f 'runtime/go-chan-cap.c' || echo '$(srcdir)/'`runtime/go-chan-cap.c - -go-chan-len.lo: runtime/go-chan-len.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-chan-len.lo -MD -MP -MF $(DEPDIR)/go-chan-len.Tpo -c -o go-chan-len.lo `test -f 'runtime/go-chan-len.c' || echo '$(srcdir)/'`runtime/go-chan-len.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-chan-len.Tpo $(DEPDIR)/go-chan-len.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-chan-len.c' object='go-chan-len.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 go-chan-len.lo `test -f 'runtime/go-chan-len.c' || echo '$(srcdir)/'`runtime/go-chan-len.c - go-check-interface.lo: runtime/go-check-interface.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-check-interface.lo -MD -MP -MF $(DEPDIR)/go-check-interface.Tpo -c -o go-check-interface.lo `test -f 'runtime/go-check-interface.c' || echo '$(srcdir)/'`runtime/go-check-interface.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-check-interface.Tpo $(DEPDIR)/go-check-interface.Plo @@ -2666,13 +2613,6 @@ go-check-interface.lo: runtime/go-check-interface.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 go-check-interface.lo `test -f 'runtime/go-check-interface.c' || echo '$(srcdir)/'`runtime/go-check-interface.c -go-close.lo: runtime/go-close.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-close.lo -MD -MP -MF $(DEPDIR)/go-close.Tpo -c -o go-close.lo `test -f 'runtime/go-close.c' || echo '$(srcdir)/'`runtime/go-close.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-close.Tpo $(DEPDIR)/go-close.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-close.c' object='go-close.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 go-close.lo `test -f 'runtime/go-close.c' || echo '$(srcdir)/'`runtime/go-close.c - go-construct-map.lo: runtime/go-construct-map.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-construct-map.lo -MD -MP -MF $(DEPDIR)/go-construct-map.Tpo -c -o go-construct-map.lo `test -f 'runtime/go-construct-map.c' || echo '$(srcdir)/'`runtime/go-construct-map.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-construct-map.Tpo $(DEPDIR)/go-construct-map.Plo @@ -2806,13 +2746,6 @@ go-nanotime.lo: runtime/go-nanotime.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 go-nanotime.lo `test -f 'runtime/go-nanotime.c' || echo '$(srcdir)/'`runtime/go-nanotime.c -go-new-channel.lo: runtime/go-new-channel.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-channel.lo -MD -MP -MF $(DEPDIR)/go-new-channel.Tpo -c -o go-new-channel.lo `test -f 'runtime/go-new-channel.c' || echo '$(srcdir)/'`runtime/go-new-channel.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new-channel.Tpo $(DEPDIR)/go-new-channel.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-new-channel.c' object='go-new-channel.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 go-new-channel.lo `test -f 'runtime/go-new-channel.c' || echo '$(srcdir)/'`runtime/go-new-channel.c - go-new-map.lo: runtime/go-new-map.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-map.lo -MD -MP -MF $(DEPDIR)/go-new-map.Tpo -c -o go-new-map.lo `test -f 'runtime/go-new-map.c' || echo '$(srcdir)/'`runtime/go-new-map.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new-map.Tpo $(DEPDIR)/go-new-map.Plo @@ -2841,34 +2774,6 @@ go-print.lo: runtime/go-print.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 go-print.lo `test -f 'runtime/go-print.c' || echo '$(srcdir)/'`runtime/go-print.c -go-rec-big.lo: runtime/go-rec-big.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-big.lo -MD -MP -MF $(DEPDIR)/go-rec-big.Tpo -c -o go-rec-big.lo `test -f 'runtime/go-rec-big.c' || echo '$(srcdir)/'`runtime/go-rec-big.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-big.Tpo $(DEPDIR)/go-rec-big.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-big.c' object='go-rec-big.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 go-rec-big.lo `test -f 'runtime/go-rec-big.c' || echo '$(srcdir)/'`runtime/go-rec-big.c - -go-rec-nb-big.lo: runtime/go-rec-nb-big.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-nb-big.lo -MD -MP -MF $(DEPDIR)/go-rec-nb-big.Tpo -c -o go-rec-nb-big.lo `test -f 'runtime/go-rec-nb-big.c' || echo '$(srcdir)/'`runtime/go-rec-nb-big.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-nb-big.Tpo $(DEPDIR)/go-rec-nb-big.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-nb-big.c' object='go-rec-nb-big.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 go-rec-nb-big.lo `test -f 'runtime/go-rec-nb-big.c' || echo '$(srcdir)/'`runtime/go-rec-nb-big.c - -go-rec-nb-small.lo: runtime/go-rec-nb-small.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-nb-small.lo -MD -MP -MF $(DEPDIR)/go-rec-nb-small.Tpo -c -o go-rec-nb-small.lo `test -f 'runtime/go-rec-nb-small.c' || echo '$(srcdir)/'`runtime/go-rec-nb-small.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-nb-small.Tpo $(DEPDIR)/go-rec-nb-small.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-nb-small.c' object='go-rec-nb-small.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 go-rec-nb-small.lo `test -f 'runtime/go-rec-nb-small.c' || echo '$(srcdir)/'`runtime/go-rec-nb-small.c - -go-rec-small.lo: runtime/go-rec-small.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-small.lo -MD -MP -MF $(DEPDIR)/go-rec-small.Tpo -c -o go-rec-small.lo `test -f 'runtime/go-rec-small.c' || echo '$(srcdir)/'`runtime/go-rec-small.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-small.Tpo $(DEPDIR)/go-rec-small.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-small.c' object='go-rec-small.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 go-rec-small.lo `test -f 'runtime/go-rec-small.c' || echo '$(srcdir)/'`runtime/go-rec-small.c - go-recover.lo: runtime/go-recover.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-recover.lo -MD -MP -MF $(DEPDIR)/go-recover.Tpo -c -o go-recover.lo `test -f 'runtime/go-recover.c' || echo '$(srcdir)/'`runtime/go-recover.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-recover.Tpo $(DEPDIR)/go-recover.Plo @@ -2890,13 +2795,6 @@ go-reflect-call.lo: runtime/go-reflect-call.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 go-reflect-call.lo `test -f 'runtime/go-reflect-call.c' || echo '$(srcdir)/'`runtime/go-reflect-call.c -go-reflect-chan.lo: runtime/go-reflect-chan.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-chan.lo -MD -MP -MF $(DEPDIR)/go-reflect-chan.Tpo -c -o go-reflect-chan.lo `test -f 'runtime/go-reflect-chan.c' || echo '$(srcdir)/'`runtime/go-reflect-chan.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-reflect-chan.Tpo $(DEPDIR)/go-reflect-chan.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-reflect-chan.c' object='go-reflect-chan.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 go-reflect-chan.lo `test -f 'runtime/go-reflect-chan.c' || echo '$(srcdir)/'`runtime/go-reflect-chan.c - go-reflect-map.lo: runtime/go-reflect-map.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-map.lo -MD -MP -MF $(DEPDIR)/go-reflect-map.Tpo -c -o go-reflect-map.lo `test -f 'runtime/go-reflect-map.c' || echo '$(srcdir)/'`runtime/go-reflect-map.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-reflect-map.Tpo $(DEPDIR)/go-reflect-map.Plo @@ -2918,41 +2816,6 @@ go-runtime-error.lo: runtime/go-runtime-error.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 go-runtime-error.lo `test -f 'runtime/go-runtime-error.c' || echo '$(srcdir)/'`runtime/go-runtime-error.c -go-select.lo: runtime/go-select.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-select.lo -MD -MP -MF $(DEPDIR)/go-select.Tpo -c -o go-select.lo `test -f 'runtime/go-select.c' || echo '$(srcdir)/'`runtime/go-select.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-select.Tpo $(DEPDIR)/go-select.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-select.c' object='go-select.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 go-select.lo `test -f 'runtime/go-select.c' || echo '$(srcdir)/'`runtime/go-select.c - -go-send-big.lo: runtime/go-send-big.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-big.lo -MD -MP -MF $(DEPDIR)/go-send-big.Tpo -c -o go-send-big.lo `test -f 'runtime/go-send-big.c' || echo '$(srcdir)/'`runtime/go-send-big.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-big.Tpo $(DEPDIR)/go-send-big.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-big.c' object='go-send-big.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 go-send-big.lo `test -f 'runtime/go-send-big.c' || echo '$(srcdir)/'`runtime/go-send-big.c - -go-send-nb-big.lo: runtime/go-send-nb-big.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-nb-big.lo -MD -MP -MF $(DEPDIR)/go-send-nb-big.Tpo -c -o go-send-nb-big.lo `test -f 'runtime/go-send-nb-big.c' || echo '$(srcdir)/'`runtime/go-send-nb-big.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-nb-big.Tpo $(DEPDIR)/go-send-nb-big.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-nb-big.c' object='go-send-nb-big.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 go-send-nb-big.lo `test -f 'runtime/go-send-nb-big.c' || echo '$(srcdir)/'`runtime/go-send-nb-big.c - -go-send-nb-small.lo: runtime/go-send-nb-small.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-nb-small.lo -MD -MP -MF $(DEPDIR)/go-send-nb-small.Tpo -c -o go-send-nb-small.lo `test -f 'runtime/go-send-nb-small.c' || echo '$(srcdir)/'`runtime/go-send-nb-small.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-nb-small.Tpo $(DEPDIR)/go-send-nb-small.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-nb-small.c' object='go-send-nb-small.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 go-send-nb-small.lo `test -f 'runtime/go-send-nb-small.c' || echo '$(srcdir)/'`runtime/go-send-nb-small.c - -go-send-small.lo: runtime/go-send-small.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-small.lo -MD -MP -MF $(DEPDIR)/go-send-small.Tpo -c -o go-send-small.lo `test -f 'runtime/go-send-small.c' || echo '$(srcdir)/'`runtime/go-send-small.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-small.Tpo $(DEPDIR)/go-send-small.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-small.c' object='go-send-small.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 go-send-small.lo `test -f 'runtime/go-send-small.c' || echo '$(srcdir)/'`runtime/go-send-small.c - go-setenv.lo: runtime/go-setenv.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-setenv.lo -MD -MP -MF $(DEPDIR)/go-setenv.Tpo -c -o go-setenv.lo `test -f 'runtime/go-setenv.c' || echo '$(srcdir)/'`runtime/go-setenv.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-setenv.Tpo $(DEPDIR)/go-setenv.Plo @@ -3093,6 +2956,13 @@ go-unwind.lo: runtime/go-unwind.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 go-unwind.lo `test -f 'runtime/go-unwind.c' || echo '$(srcdir)/'`runtime/go-unwind.c +chan.lo: runtime/chan.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT chan.lo -MD -MP -MF $(DEPDIR)/chan.Tpo -c -o chan.lo `test -f 'runtime/chan.c' || echo '$(srcdir)/'`runtime/chan.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/chan.Tpo $(DEPDIR)/chan.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/chan.c' object='chan.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 chan.lo `test -f 'runtime/chan.c' || echo '$(srcdir)/'`runtime/chan.c + cpuprof.lo: runtime/cpuprof.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cpuprof.lo -MD -MP -MF $(DEPDIR)/cpuprof.Tpo -c -o cpuprof.lo `test -f 'runtime/cpuprof.c' || echo '$(srcdir)/'`runtime/cpuprof.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cpuprof.Tpo $(DEPDIR)/cpuprof.Plo diff --git a/libgo/runtime/chan.c b/libgo/runtime/chan.c new file mode 100644 index 00000000000..a246992c60b --- /dev/null +++ b/libgo/runtime/chan.c @@ -0,0 +1,1248 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" +#include "go-type.h" + +#define NOSELGEN 1 + +static int32 debug = 0; + +typedef struct WaitQ WaitQ; +typedef struct SudoG SudoG; +typedef struct Select Select; +typedef struct Scase Scase; + +typedef struct __go_type_descriptor Type; +typedef struct __go_channel_type ChanType; + +struct SudoG +{ + G* g; // g and selgen constitute + uint32 selgen; // a weak pointer to g + SudoG* link; + byte* elem; // data element +}; + +struct WaitQ +{ + SudoG* first; + SudoG* last; +}; + +struct Hchan +{ + uint32 qcount; // total data in the q + uint32 dataqsiz; // size of the circular q + uint16 elemsize; + bool closed; + uint8 elemalign; + uint32 sendx; // send index + uint32 recvx; // receive index + WaitQ recvq; // list of recv waiters + WaitQ sendq; // list of send waiters + Lock; +}; + +// Buffer follows Hchan immediately in memory. +// chanbuf(c, i) is pointer to the i'th slot in the buffer. +#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i)) + +enum +{ + // Scase.kind + CaseRecv, + CaseSend, + CaseDefault, +}; + +struct Scase +{ + SudoG sg; // must be first member (cast to Scase) + Hchan* chan; // chan + uint16 kind; + uint16 index; // index to return + bool* receivedp; // pointer to received bool (recv2) +}; + +struct Select +{ + uint16 tcase; // total count of scase[] + uint16 ncase; // currently filled scase[] + uint16* pollorder; // case poll order + Hchan** lockorder; // channel lock order + Scase scase[1]; // one per case (in order of appearance) +}; + +static void dequeueg(WaitQ*); +static SudoG* dequeue(WaitQ*); +static void enqueue(WaitQ*, SudoG*); + +Hchan* +runtime_makechan_c(ChanType *t, int64 hint) +{ + Hchan *c; + int32 n; + const Type *elem; + + elem = t->__element_type; + + if(hint < 0 || (int32)hint != hint || (elem->__size > 0 && (uintptr)hint > ((uintptr)-1) / elem->__size)) + runtime_panicstring("makechan: size out of range"); + + n = sizeof(*c); + + // allocate memory in one call + c = (Hchan*)runtime_mal(n + hint*elem->__size); + c->elemsize = elem->__size; + c->elemalign = elem->__align; + c->dataqsiz = hint; + + if(debug) + runtime_printf("makechan: chan=%p; elemsize=%lld; elemalign=%d; dataqsiz=%d\n", + c, (long long)elem->__size, elem->__align, c->dataqsiz); + + return c; +} + +// For reflect +// func makechan(typ *ChanType, size uint32) (chan) +uintptr reflect_makechan(ChanType *, uint32) + asm ("libgo_reflect.reflect.makechan"); + +uintptr +reflect_makechan(ChanType *t, uint32 size) +{ + void *ret; + Hchan *c; + + c = runtime_makechan_c(t, size); + ret = runtime_mal(sizeof(void*)); + __builtin_memcpy(ret, &c, sizeof(void*)); + return (uintptr)ret; +} + +// makechan(t *ChanType, hint int64) (hchan *chan any); +Hchan* +__go_new_channel(ChanType *t, uintptr hint) +{ + return runtime_makechan_c(t, hint); +} + +/* + * generic single channel send/recv + * if the bool pointer is nil, + * then the full exchange will + * occur. if pres is not nil, + * then the protocol will not + * sleep but return if it could + * not complete. + * + * sleep can wake up with g->param == nil + * when a channel involved in the sleep has + * been closed. it is easiest to loop and re-run + * the operation; we'll see that it's now closed. + */ +void +runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres) +{ + SudoG *sg; + SudoG mysg; + G* gp; + G* g; + + g = runtime_g(); + + if(c == nil) { + USED(t); + if(pres != nil) { + *pres = false; + return; + } + g->status = Gwaiting; + g->waitreason = "chan send (nil chan)"; + runtime_gosched(); + return; // not reached + } + + if(runtime_gcwaiting) + runtime_gosched(); + + if(debug) { + runtime_printf("chansend: chan=%p\n", c); + } + + runtime_lock(c); + if(c->closed) + goto closed; + + if(c->dataqsiz > 0) + goto asynch; + + sg = dequeue(&c->recvq); + if(sg != nil) { + runtime_unlock(c); + + gp = sg->g; + gp->param = sg; + if(sg->elem != nil) + runtime_memmove(sg->elem, ep, c->elemsize); + runtime_ready(gp); + + if(pres != nil) + *pres = true; + return; + } + + if(pres != nil) { + runtime_unlock(c); + *pres = false; + return; + } + + mysg.elem = ep; + mysg.g = g; + mysg.selgen = NOSELGEN; + g->param = nil; + g->status = Gwaiting; + g->waitreason = "chan send"; + enqueue(&c->sendq, &mysg); + runtime_unlock(c); + runtime_gosched(); + + if(g->param == nil) { + runtime_lock(c); + if(!c->closed) + runtime_throw("chansend: spurious wakeup"); + goto closed; + } + + return; + +asynch: + if(c->closed) + goto closed; + + if(c->qcount >= c->dataqsiz) { + if(pres != nil) { + runtime_unlock(c); + *pres = false; + return; + } + mysg.g = g; + mysg.elem = nil; + mysg.selgen = NOSELGEN; + g->status = Gwaiting; + g->waitreason = "chan send"; + enqueue(&c->sendq, &mysg); + runtime_unlock(c); + runtime_gosched(); + + runtime_lock(c); + goto asynch; + } + runtime_memmove(chanbuf(c, c->sendx), ep, c->elemsize); + if(++c->sendx == c->dataqsiz) + c->sendx = 0; + c->qcount++; + + sg = dequeue(&c->recvq); + if(sg != nil) { + gp = sg->g; + runtime_unlock(c); + runtime_ready(gp); + } else + runtime_unlock(c); + if(pres != nil) + *pres = true; + return; + +closed: + runtime_unlock(c); + runtime_panicstring("send on closed channel"); +} + + +void +runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received) +{ + SudoG *sg; + SudoG mysg; + G *gp; + G *g; + + if(runtime_gcwaiting) + runtime_gosched(); + + if(debug) + runtime_printf("chanrecv: chan=%p\n", c); + + g = runtime_g(); + + if(c == nil) { + USED(t); + if(selected != nil) { + *selected = false; + return; + } + g->status = Gwaiting; + g->waitreason = "chan receive (nil chan)"; + runtime_gosched(); + return; // not reached + } + + runtime_lock(c); + if(c->dataqsiz > 0) + goto asynch; + + if(c->closed) + goto closed; + + sg = dequeue(&c->sendq); + if(sg != nil) { + runtime_unlock(c); + + if(ep != nil) + runtime_memmove(ep, sg->elem, c->elemsize); + gp = sg->g; + gp->param = sg; + runtime_ready(gp); + + if(selected != nil) + *selected = true; + if(received != nil) + *received = true; + return; + } + + if(selected != nil) { + runtime_unlock(c); + *selected = false; + return; + } + + mysg.elem = ep; + mysg.g = g; + mysg.selgen = NOSELGEN; + g->param = nil; + g->status = Gwaiting; + g->waitreason = "chan receive"; + enqueue(&c->recvq, &mysg); + runtime_unlock(c); + runtime_gosched(); + + if(g->param == nil) { + runtime_lock(c); + if(!c->closed) + runtime_throw("chanrecv: spurious wakeup"); + goto closed; + } + + if(received != nil) + *received = true; + return; + +asynch: + if(c->qcount <= 0) { + if(c->closed) + goto closed; + + if(selected != nil) { + runtime_unlock(c); + *selected = false; + if(received != nil) + *received = false; + return; + } + mysg.g = g; + mysg.elem = nil; + mysg.selgen = NOSELGEN; + g->status = Gwaiting; + g->waitreason = "chan receive"; + enqueue(&c->recvq, &mysg); + runtime_unlock(c); + runtime_gosched(); + + runtime_lock(c); + goto asynch; + } + if(ep != nil) + runtime_memmove(ep, chanbuf(c, c->recvx), c->elemsize); + runtime_memclr(chanbuf(c, c->recvx), c->elemsize); + if(++c->recvx == c->dataqsiz) + c->recvx = 0; + c->qcount--; + + sg = dequeue(&c->sendq); + if(sg != nil) { + gp = sg->g; + runtime_unlock(c); + runtime_ready(gp); + } else + runtime_unlock(c); + + if(selected != nil) + *selected = true; + if(received != nil) + *received = true; + return; + +closed: + if(ep != nil) + runtime_memclr(ep, c->elemsize); + if(selected != nil) + *selected = true; + if(received != nil) + *received = false; + runtime_unlock(c); +} + +// The compiler generates a call to __go_send_small to send a value 8 +// bytes or smaller. +void +__go_send_small(ChanType *t, Hchan* c, uint64 val) +{ + byte b[sizeof(uint64)]; + + runtime_memclr(b, sizeof(uint64)); + __builtin_memcpy(b, &val, t->__element_type->__size); + runtime_chansend(t, c, b, nil); +} + +// The compiler generates a call to __go_send_big to send a value +// larger than 8 bytes or smaller. +void +__go_send_big(ChanType *t, Hchan* c, byte* p) +{ + runtime_chansend(t, c, p, nil); +} + +// The compiler generates a call to __go_receive_small to receive a +// value 8 bytes or smaller. +uint64 +__go_receive_small(ChanType *t, Hchan* c) +{ + union { + byte b[sizeof(uint64)]; + uint64 v; + } u; + + u.v = 0; + runtime_chanrecv(t, c, u.b, nil, nil); + return u.v; +} + +// The compiler generates a call to __go_receive_big to receive a +// value larger than 8 bytes. +void +__go_receive_big(ChanType *t, Hchan* c, byte* p) +{ + runtime_chanrecv(t, c, p, nil, nil); +} + +_Bool runtime_chanrecv2(ChanType *t, Hchan* c, byte* p) + __asm__("runtime.chanrecv2"); + +_Bool +runtime_chanrecv2(ChanType *t, Hchan* c, byte* p) +{ + bool received; + + runtime_chanrecv(t, c, p, nil, &received); + return received; +} + +// func selectnbsend(c chan any, elem any) bool +// +// compiler implements +// +// select { +// case c <- v: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if selectnbsend(c, v) { +// ... foo +// } else { +// ... bar +// } +// +_Bool +runtime_selectnbsend(ChanType *t, Hchan *c, byte *p) +{ + bool res; + + runtime_chansend(t, c, p, &res); + return res; +} + +// func selectnbrecv(elem *any, c chan any) bool +// +// compiler implements +// +// select { +// case v = <-c: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if selectnbrecv(&v, c) { +// ... foo +// } else { +// ... bar +// } +// +_Bool +runtime_selectnbrecv(ChanType *t, byte *v, Hchan *c) +{ + bool selected; + + runtime_chanrecv(t, c, v, &selected, nil); + return selected; +} + +// func selectnbrecv2(elem *any, ok *bool, c chan any) bool +// +// compiler implements +// +// select { +// case v, ok = <-c: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if c != nil && selectnbrecv2(&v, &ok, c) { +// ... foo +// } else { +// ... bar +// } +// +_Bool +runtime_selectnbrecv2(ChanType *t, byte *v, _Bool *received, Hchan *c) +{ + bool selected; + bool r; + + r = false; + runtime_chanrecv(t, c, v, &selected, received == nil ? nil : &r); + if(received != nil) + *received = r; + return selected; +} + +// For reflect: +// func chansend(c chan, val iword, nb bool) (selected bool) +// where an iword is the same word an interface value would use: +// the actual data if it fits, or else a pointer to the data. + +_Bool reflect_chansend(ChanType *, Hchan *, uintptr, _Bool) + __asm__("libgo_reflect.reflect.chansend"); + +_Bool +reflect_chansend(ChanType *t, Hchan *c, uintptr val, _Bool nb) +{ + bool selected; + bool *sp; + byte *vp; + + if(nb) { + selected = false; + sp = (bool*)&selected; + } else { + selected = true; + sp = nil; + } + if(__go_is_pointer_type(t->__element_type)) + vp = (byte*)&val; + else + vp = (byte*)val; + runtime_chansend(t, c, vp, sp); + return selected; +} + +// For reflect: +// func chanrecv(c chan, nb bool) (val iword, selected, received bool) +// where an iword is the same word an interface value would use: +// the actual data if it fits, or else a pointer to the data. + +struct chanrecv_ret +{ + uintptr val; + _Bool selected; + _Bool received; +}; + +struct chanrecv_ret reflect_chanrecv(ChanType *, Hchan *, _Bool) + __asm__("libgo_reflect.reflect.chanrecv"); + +struct chanrecv_ret +reflect_chanrecv(ChanType *t, Hchan *c, _Bool nb) +{ + struct chanrecv_ret ret; + byte *vp; + bool *sp; + bool selected; + bool received; + + if(nb) { + selected = false; + sp = &selected; + } else { + ret.selected = true; + sp = nil; + } + received = false; + if(__go_is_pointer_type(t->__element_type)) { + vp = (byte*)&ret.val; + } else { + vp = runtime_mal(t->__element_type->__size); + ret.val = (uintptr)vp; + } + runtime_chanrecv(t, c, vp, sp, &received); + if(nb) + ret.selected = selected; + ret.received = received; + return ret; +} + +static void newselect(int32, Select**); + +// newselect(size uint32) (sel *byte); + +void* runtime_newselect(int) __asm__("runtime.newselect"); + +void* +runtime_newselect(int size) +{ + Select *sel; + + newselect(size, &sel); + return (void*)sel; +} + +static void +newselect(int32 size, Select **selp) +{ + int32 n; + Select *sel; + + n = 0; + if(size > 1) + n = size-1; + + sel = runtime_mal(sizeof(*sel) + + n*sizeof(sel->scase[0]) + + size*sizeof(sel->lockorder[0]) + + size*sizeof(sel->pollorder[0])); + + sel->tcase = size; + sel->ncase = 0; + sel->pollorder = (void*)(sel->scase + size); + sel->lockorder = (void*)(sel->pollorder + size); + *selp = sel; + + if(debug) + runtime_printf("newselect s=%p size=%d\n", sel, size); +} + +// cut in half to give stack a chance to split +static void selectsend(Select *sel, Hchan *c, int index, void *elem); + +// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool); + +void runtime_selectsend(Select *, Hchan *, void *, int) + __asm__("runtime.selectsend"); + +void +runtime_selectsend(Select *sel, Hchan *c, void *elem, int index) +{ + // nil cases do not compete + if(c == nil) + return; + + selectsend(sel, c, index, elem); +} + +static void +selectsend(Select *sel, Hchan *c, int index, void *elem) +{ + int32 i; + Scase *cas; + + i = sel->ncase; + if(i >= sel->tcase) + runtime_throw("selectsend: too many cases"); + sel->ncase = i+1; + cas = &sel->scase[i]; + + cas->index = index; + cas->chan = c; + cas->kind = CaseSend; + cas->sg.elem = elem; + + if(debug) + runtime_printf("selectsend s=%p index=%d chan=%p\n", + sel, cas->index, cas->chan); +} + +// cut in half to give stack a chance to split +static void selectrecv(Select *sel, Hchan *c, int index, void *elem, bool*); + +// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); + +void runtime_selectrecv(Select *, Hchan *, void *, int) + __asm__("runtime.selectrecv"); + +void +runtime_selectrecv(Select *sel, Hchan *c, void *elem, int index) +{ + // nil cases do not compete + if(c == nil) + return; + + selectrecv(sel, c, index, elem, nil); +} + +// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool); + +void runtime_selectrecv2(Select *, Hchan *, void *, bool *, int) + __asm__("runtime.selectrecv2"); + +void +runtime_selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, int index) +{ + // nil cases do not compete + if(c == nil) + return; + + selectrecv(sel, c, index, elem, received); +} + +static void +selectrecv(Select *sel, Hchan *c, int index, void *elem, bool *received) +{ + int32 i; + Scase *cas; + + i = sel->ncase; + if(i >= sel->tcase) + runtime_throw("selectrecv: too many cases"); + sel->ncase = i+1; + cas = &sel->scase[i]; + cas->index = index; + cas->chan = c; + + cas->kind = CaseRecv; + cas->sg.elem = elem; + cas->receivedp = received; + + if(debug) + runtime_printf("selectrecv s=%p index=%d chan=%p\n", + sel, cas->index, cas->chan); +} + +// cut in half to give stack a chance to split +static void selectdefault(Select*, int); + +// selectdefault(sel *byte) (selected bool); + +void runtime_selectdefault(Select *, int) __asm__("runtime.selectdefault"); + +void +runtime_selectdefault(Select *sel, int index) +{ + selectdefault(sel, index); +} + +static void +selectdefault(Select *sel, int index) +{ + int32 i; + Scase *cas; + + i = sel->ncase; + if(i >= sel->tcase) + runtime_throw("selectdefault: too many cases"); + sel->ncase = i+1; + cas = &sel->scase[i]; + cas->index = index; + cas->chan = nil; + + cas->kind = CaseDefault; + + if(debug) + runtime_printf("selectdefault s=%p index=%d\n", + sel, cas->index); +} + +static void +sellock(Select *sel) +{ + uint32 i; + Hchan *c, *c0; + + c = nil; + for(i=0; i<sel->ncase; i++) { + c0 = sel->lockorder[i]; + if(c0 && c0 != c) { + c = sel->lockorder[i]; + runtime_lock(c); + } + } +} + +static void +selunlock(Select *sel) +{ + uint32 i; + Hchan *c, *c0; + + c = nil; + for(i=sel->ncase; i-->0;) { + c0 = sel->lockorder[i]; + if(c0 && c0 != c) { + c = c0; + runtime_unlock(c); + } + } +} + +void +runtime_block(void) +{ + G *g; + + g = runtime_g(); + g->status = Gwaiting; // forever + g->waitreason = "select (no cases)"; + runtime_gosched(); +} + +static int selectgo(Select**); + +// selectgo(sel *byte); + +int runtime_selectgo(Select *) __asm__("runtime.selectgo"); + +int +runtime_selectgo(Select *sel) +{ + return selectgo(&sel); +} + +static int +selectgo(Select **selp) +{ + Select *sel; + uint32 o, i, j; + Scase *cas, *dfl; + Hchan *c; + SudoG *sg; + G *gp; + int index; + G *g; + + sel = *selp; + if(runtime_gcwaiting) + runtime_gosched(); + + if(debug) + runtime_printf("select: sel=%p\n", sel); + + g = runtime_g(); + + // The compiler rewrites selects that statically have + // only 0 or 1 cases plus default into simpler constructs. + // The only way we can end up with such small sel->ncase + // values here is for a larger select in which most channels + // have been nilled out. The general code handles those + // cases correctly, and they are rare enough not to bother + // optimizing (and needing to test). + + // generate permuted order + for(i=0; i<sel->ncase; i++) + sel->pollorder[i] = i; + for(i=1; i<sel->ncase; i++) { + o = sel->pollorder[i]; + j = runtime_fastrand1()%(i+1); + sel->pollorder[i] = sel->pollorder[j]; + sel->pollorder[j] = o; + } + + // sort the cases by Hchan address to get the locking order. + for(i=0; i<sel->ncase; i++) { + c = sel->scase[i].chan; + for(j=i; j>0 && sel->lockorder[j-1] >= c; j--) + sel->lockorder[j] = sel->lockorder[j-1]; + sel->lockorder[j] = c; + } + sellock(sel); + +loop: + // pass 1 - look for something already waiting + dfl = nil; + for(i=0; i<sel->ncase; i++) { + o = sel->pollorder[i]; + cas = &sel->scase[o]; + c = cas->chan; + + switch(cas->kind) { + case CaseRecv: + if(c->dataqsiz > 0) { + if(c->qcount > 0) + goto asyncrecv; + } else { + sg = dequeue(&c->sendq); + if(sg != nil) + goto syncrecv; + } + if(c->closed) + goto rclose; + break; + + case CaseSend: + if(c->closed) + goto sclose; + if(c->dataqsiz > 0) { + if(c->qcount < c->dataqsiz) + goto asyncsend; + } else { + sg = dequeue(&c->recvq); + if(sg != nil) + goto syncsend; + } + break; + + case CaseDefault: + dfl = cas; + break; + } + } + + if(dfl != nil) { + selunlock(sel); + cas = dfl; + goto retc; + } + + + // pass 2 - enqueue on all chans + for(i=0; i<sel->ncase; i++) { + o = sel->pollorder[i]; + cas = &sel->scase[o]; + c = cas->chan; + sg = &cas->sg; + sg->g = g; + sg->selgen = g->selgen; + + switch(cas->kind) { + case CaseRecv: + enqueue(&c->recvq, sg); + break; + + case CaseSend: + enqueue(&c->sendq, sg); + break; + } + } + + g->param = nil; + g->status = Gwaiting; + g->waitreason = "select"; + selunlock(sel); + runtime_gosched(); + + sellock(sel); + sg = g->param; + + // pass 3 - dequeue from unsuccessful chans + // otherwise they stack up on quiet channels + for(i=0; i<sel->ncase; i++) { + cas = &sel->scase[i]; + if(cas != (Scase*)sg) { + c = cas->chan; + if(cas->kind == CaseSend) + dequeueg(&c->sendq); + else + dequeueg(&c->recvq); + } + } + + if(sg == nil) + goto loop; + + cas = (Scase*)sg; + c = cas->chan; + + if(c->dataqsiz > 0) + runtime_throw("selectgo: shouldnt happen"); + + if(debug) + runtime_printf("wait-return: sel=%p c=%p cas=%p kind=%d\n", + sel, c, cas, cas->kind); + + if(cas->kind == CaseRecv) { + if(cas->receivedp != nil) + *cas->receivedp = true; + } + + selunlock(sel); + goto retc; + +asyncrecv: + // can receive from buffer + if(cas->receivedp != nil) + *cas->receivedp = true; + if(cas->sg.elem != nil) + runtime_memmove(cas->sg.elem, chanbuf(c, c->recvx), c->elemsize); + runtime_memclr(chanbuf(c, c->recvx), c->elemsize); + if(++c->recvx == c->dataqsiz) + c->recvx = 0; + c->qcount--; + sg = dequeue(&c->sendq); + if(sg != nil) { + gp = sg->g; + selunlock(sel); + runtime_ready(gp); + } else { + selunlock(sel); + } + goto retc; + +asyncsend: + // can send to buffer + runtime_memmove(chanbuf(c, c->sendx), cas->sg.elem, c->elemsize); + if(++c->sendx == c->dataqsiz) + c->sendx = 0; + c->qcount++; + sg = dequeue(&c->recvq); + if(sg != nil) { + gp = sg->g; + selunlock(sel); + runtime_ready(gp); + } else { + selunlock(sel); + } + goto retc; + +syncrecv: + // can receive from sleeping sender (sg) + selunlock(sel); + if(debug) + runtime_printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o); + if(cas->receivedp != nil) + *cas->receivedp = true; + if(cas->sg.elem != nil) + runtime_memmove(cas->sg.elem, sg->elem, c->elemsize); + gp = sg->g; + gp->param = sg; + runtime_ready(gp); + goto retc; + +rclose: + // read at end of closed channel + selunlock(sel); + if(cas->receivedp != nil) + *cas->receivedp = false; + if(cas->sg.elem != nil) + runtime_memclr(cas->sg.elem, c->elemsize); + goto retc; + +syncsend: + // can send to sleeping receiver (sg) + selunlock(sel); + if(debug) + runtime_printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o); + if(sg->elem != nil) + runtime_memmove(sg->elem, cas->sg.elem, c->elemsize); + gp = sg->g; + gp->param = sg; + runtime_ready(gp); + +retc: + // return index corresponding to chosen case + index = cas->index; + runtime_free(sel); + return index; + +sclose: + // send on closed channel + selunlock(sel); + runtime_panicstring("send on closed channel"); + return 0; // not reached +} + +// closechan(sel *byte); +void +runtime_closechan(Hchan *c) +{ + SudoG *sg; + G* gp; + + if(c == nil) + runtime_panicstring("close of nil channel"); + + if(runtime_gcwaiting) + runtime_gosched(); + + runtime_lock(c); + if(c->closed) { + runtime_unlock(c); + runtime_panicstring("close of closed channel"); + } + + c->closed = true; + + // release all readers + for(;;) { + sg = dequeue(&c->recvq); + if(sg == nil) + break; + gp = sg->g; + gp->param = nil; + runtime_ready(gp); + } + + // release all writers + for(;;) { + sg = dequeue(&c->sendq); + if(sg == nil) + break; + gp = sg->g; + gp->param = nil; + runtime_ready(gp); + } + + runtime_unlock(c); +} + +void +__go_builtin_close(Hchan *c) +{ + runtime_closechan(c); +} + +// For reflect +// func chanclose(c chan) + +void reflect_chanclose(uintptr) __asm__("libgo_reflect.reflect.chanclose"); + +void +reflect_chanclose(uintptr c) +{ + runtime_closechan((Hchan*)c); +} + +// For reflect +// func chanlen(c chan) (len int32) + +int32 reflect_chanlen(uintptr) __asm__("libgo_reflect.reflect.chanlen"); + +int32 +reflect_chanlen(uintptr ca) +{ + Hchan *c; + int32 len; + + c = (Hchan*)ca; + if(c == nil) + len = 0; + else + len = c->qcount; + return len; +} + +int +__go_chan_len(Hchan *c) +{ + return reflect_chanlen((uintptr)c); +} + +// For reflect +// func chancap(c chan) (cap int32) + +int32 reflect_chancap(uintptr) __asm__("libgo_reflect.reflect.chancap"); + +int32 +reflect_chancap(uintptr ca) +{ + Hchan *c; + int32 cap; + + c = (Hchan*)ca; + if(c == nil) + cap = 0; + else + cap = c->dataqsiz; + return cap; +} + +int +__go_chan_cap(Hchan *c) +{ + return reflect_chancap((uintptr)c); +} + +static SudoG* +dequeue(WaitQ *q) +{ + SudoG *sgp; + +loop: + sgp = q->first; + if(sgp == nil) + return nil; + q->first = sgp->link; + + // if sgp is stale, ignore it + if(sgp->selgen != NOSELGEN && + (sgp->selgen != sgp->g->selgen || + !runtime_cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) { + //prints("INVALID PSEUDOG POINTER\n"); + goto loop; + } + + return sgp; +} + +static void +dequeueg(WaitQ *q) +{ + SudoG **l, *sgp, *prevsgp; + G *g; + + g = runtime_g(); + prevsgp = nil; + for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) { + if(sgp->g == g) { + *l = sgp->link; + if(q->last == sgp) + q->last = prevsgp; + break; + } + } +} + +static void +enqueue(WaitQ *q, SudoG *sgp) +{ + sgp->link = nil; + if(q->first == nil) { + q->first = sgp; + q->last = sgp; + return; + } + q->last->link = sgp; + q->last = sgp; +} diff --git a/libgo/runtime/chan.goc b/libgo/runtime/chan.goc deleted file mode 100644 index c3cc3e39879..00000000000 --- a/libgo/runtime/chan.goc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime -#include "config.h" -#include "channel.h" - -#define nil NULL - -typedef _Bool bool; -typedef unsigned char byte; -typedef struct __go_channel chan; - -/* Do a channel receive with closed status. */ - -func chanrecv2(c *chan, val *byte) (received bool) { - uintptr_t element_size = c == nil ? 0 : c->element_type->__size; - if (element_size > 8) { - return __go_receive_big(c, val, 0); - } else { - union { - char b[8]; - uint64_t v; - } u; - - u.v = __go_receive_small_closed(c, 0, &received); -#ifndef WORDS_BIGENDIAN - __builtin_memcpy(val, u.b, element_size); -#else - __builtin_memcpy(val, u.b + 8 - element_size, element_size); -#endif - return received; - } -} - -/* Do a channel receive with closed status for a select statement. */ - -func chanrecv3(c *chan, val *byte) (received bool) { - uintptr_t element_size = c->element_type->__size; - if (element_size > 8) { - return __go_receive_big(c, val, 1); - } else { - union { - char b[8]; - uint64_t v; - } u; - - u.v = __go_receive_small_closed(c, 1, &received); -#ifndef WORDS_BIGENDIAN - __builtin_memcpy(val, u.b, element_size); -#else - __builtin_memcpy(val, u.b + 8 - element_size, element_size); -#endif - return received; - } -} diff --git a/libgo/runtime/channel.h b/libgo/runtime/channel.h deleted file mode 100644 index 9176c68f692..00000000000 --- a/libgo/runtime/channel.h +++ /dev/null @@ -1,152 +0,0 @@ -/* channel.h -- the channel type for Go. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> -#include <pthread.h> - -#include "go-type.h" - -/* This structure is used when a select is waiting for a synchronous - channel. */ - -struct __go_channel_select -{ - /* A pointer to the next select waiting for this channel. */ - struct __go_channel_select *next; - /* A pointer to the channel which this select will use. This starts - out as NULL and is set to the first channel which synchs up with - this one. This variable to which this points may only be - accessed when __go_select_data_mutex is held. */ - struct __go_channel **selected; - /* A pointer to a variable which must be set to true if the - goroutine which sets *SELECTED wants to read from the channel, - false if it wants to write to it. */ - _Bool *is_read; -}; - -/* A channel is a pointer to this structure. */ - -struct __go_channel -{ - /* A mutex to control access to the channel. */ - pthread_mutex_t lock; - /* A condition variable. This is signalled when data is added to - the channel and when data is removed from the channel. */ - pthread_cond_t cond; - /* The type of elements on this channel. */ - const struct __go_type_descriptor *element_type; - /* True if a goroutine is waiting to send on a synchronous - channel. */ - _Bool waiting_to_send; - /* True if a goroutine is waiting to receive on a synchronous - channel. */ - _Bool waiting_to_receive; - /* True if this channel was selected for send in a select statement. - This looks out all other sends. */ - _Bool selected_for_send; - /* True if this channel was selected for receive in a select - statement. This locks out all other receives. */ - _Bool selected_for_receive; - /* True if this channel has been closed. */ - _Bool is_closed; - /* The list of select statements waiting to send on a synchronous - channel. */ - struct __go_channel_select *select_send_queue; - /* The list of select statements waiting to receive on a synchronous - channel. */ - struct __go_channel_select *select_receive_queue; - /* If a select statement is waiting for this channel, it sets these - pointers. When something happens on the channel, the channel - locks the mutex, signals the condition, and unlocks the - mutex. */ - pthread_mutex_t *select_mutex; - pthread_cond_t *select_cond; - /* The number of entries in the circular buffer. */ - unsigned int num_entries; - /* Where to store the next value. */ - unsigned int next_store; - /* Where to fetch the next value. If next_fetch == next_store, the - buffer is empty. If next_store + 1 == next_fetch, the buffer is - full. */ - unsigned int next_fetch; - /* The circular buffer. */ - uint64_t data[]; -}; - -/* Try to link up with the structure generated by the frontend. */ -typedef struct __go_channel __go_channel; - -/* The mutex used to control access to the value pointed to by the - __go_channel_select selected field. No additional mutexes may be - acquired while this mutex is held. */ -extern pthread_mutex_t __go_select_data_mutex; - -extern struct __go_channel * -__go_new_channel (const struct __go_type_descriptor *, uintptr_t); - -extern _Bool __go_synch_with_select (struct __go_channel *, _Bool); - -extern void __go_broadcast_to_select (struct __go_channel *); - -extern void __go_send_acquire (struct __go_channel *, _Bool); - -extern _Bool __go_send_nonblocking_acquire (struct __go_channel *); - -extern void __go_send_release (struct __go_channel *); - -extern void __go_send_small (struct __go_channel *, uint64_t, _Bool); - -extern _Bool __go_send_nonblocking_small (struct __go_channel *, uint64_t); - -extern void __go_send_big (struct __go_channel *, const void *, _Bool); - -extern _Bool __go_send_nonblocking_big (struct __go_channel *, const void *); - -extern _Bool __go_receive_acquire (struct __go_channel *, _Bool); - -#define RECEIVE_NONBLOCKING_ACQUIRE_DATA 0 -#define RECEIVE_NONBLOCKING_ACQUIRE_NODATA 1 -#define RECEIVE_NONBLOCKING_ACQUIRE_CLOSED 2 - -extern int __go_receive_nonblocking_acquire (struct __go_channel *); - -extern uint64_t __go_receive_small (struct __go_channel *, _Bool); - -extern uint64_t __go_receive_small_closed (struct __go_channel *, _Bool, - _Bool *); - -extern void __go_receive_release (struct __go_channel *); - -struct __go_receive_nonblocking_small -{ - /* Value read from channel, or 0. */ - uint64_t __val; - /* True if value was read from channel. */ - _Bool __success; - /* True if channel is closed. */ - _Bool __closed; -}; - -extern struct __go_receive_nonblocking_small -__go_receive_nonblocking_small (struct __go_channel *); - -extern _Bool __go_receive_big (struct __go_channel *, void *, _Bool); - -extern _Bool __go_receive_nonblocking_big (struct __go_channel *, void *, - _Bool *); - -extern void __go_unlock_and_notify_selects (struct __go_channel *); - -extern _Bool __go_builtin_closed (struct __go_channel *); - -extern void __go_builtin_close (struct __go_channel *); - -extern int __go_chan_len (struct __go_channel *); - -extern int __go_chan_cap (struct __go_channel *); - -extern uintptr_t __go_select (uintptr_t, _Bool, struct __go_channel **, - _Bool *); diff --git a/libgo/runtime/go-chan-cap.c b/libgo/runtime/go-chan-cap.c deleted file mode 100644 index 2c7958dd9fc..00000000000 --- a/libgo/runtime/go-chan-cap.c +++ /dev/null @@ -1,41 +0,0 @@ -/* go-chan-cap.c -- the cap function applied to a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stddef.h> - -#include "go-assert.h" -#include "channel.h" - -/* Return the cap function applied to a channel--the size of the - buffer. This could be done inline but I'm doing it as a function - for now to make it easy to change the channel structure. */ - -int -__go_chan_cap (struct __go_channel *channel) -{ - int i; - int ret; - - if (channel == NULL) - return 0; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - if (channel->num_entries == 0) - ret = 0; - else - { - /* One slot is always unused. We added 1 when we created the - channel. */ - ret = channel->num_entries - 1; - } - - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - return ret; -} diff --git a/libgo/runtime/go-chan-len.c b/libgo/runtime/go-chan-len.c deleted file mode 100644 index b3ced98aa05..00000000000 --- a/libgo/runtime/go-chan-len.c +++ /dev/null @@ -1,41 +0,0 @@ -/* go-chan-len.c -- the len function applied to a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stddef.h> - -#include "go-assert.h" -#include "channel.h" - -/* Return the len function applied to a channel--the number of - elements in the buffer. This could be done inline but I'm doing it - as a function for now to make it easy to change the channel - structure. */ - -int -__go_chan_len (struct __go_channel *channel) -{ - int i; - int ret; - - if (channel == NULL) - return 0; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - if (channel->num_entries == 0) - ret = 0; - else if (channel->next_fetch == channel->next_store) - ret = 0; - else - ret = ((channel->next_store + channel->num_entries - channel->next_fetch) - % channel->num_entries); - - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - return ret; -} diff --git a/libgo/runtime/go-close.c b/libgo/runtime/go-close.c deleted file mode 100644 index 7e32286dae0..00000000000 --- a/libgo/runtime/go-close.c +++ /dev/null @@ -1,42 +0,0 @@ -/* go-close.c -- the builtin close function. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* Close a channel. After a channel is closed, sends are no longer - permitted. Receives always return zero. */ - -void -__go_builtin_close (struct __go_channel *channel) -{ - int i; - - if (channel == NULL) - runtime_panicstring ("close of nil channel"); - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (channel->selected_for_send) - runtime_cond_wait (&channel->cond, &channel->lock); - - if (channel->is_closed) - { - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - runtime_panicstring ("close of closed channel"); - } - - channel->is_closed = 1; - - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - - __go_unlock_and_notify_selects (channel); -} diff --git a/libgo/runtime/go-new-channel.c b/libgo/runtime/go-new-channel.c deleted file mode 100644 index fe13c5efab6..00000000000 --- a/libgo/runtime/go-new-channel.c +++ /dev/null @@ -1,70 +0,0 @@ -/* go-new-channel.c -- allocate a new channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stddef.h> -#include <stdint.h> - -#include "runtime.h" -#include "go-alloc.h" -#include "go-assert.h" -#include "channel.h" - -struct __go_channel* -__go_new_channel (const struct __go_type_descriptor *channel_type, - uintptr_t entries) -{ - const struct __go_channel_type *ctd; - const struct __go_type_descriptor *element_type; - uintptr_t element_size; - int ientries; - struct __go_channel* ret; - size_t alloc_size; - int i; - - __go_assert (channel_type->__code == GO_CHAN); - ctd = (const struct __go_channel_type *) channel_type; - element_type = ctd->__element_type; - - element_size = element_type->__size; - - ientries = (int) entries; - if (ientries < 0 - || (uintptr_t) ientries != entries - || (element_size > 0 && entries > (uintptr_t) -1 / element_size)) - runtime_panicstring ("chan size out of range"); - - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - /* We use a circular buffer which means that when next_fetch == - next_store we don't know whether the buffer is empty or full. So - we allocate an extra space, and always leave a space open. - FIXME. */ - if (entries != 0) - ++entries; - - ret = (struct __go_channel*) __go_alloc (sizeof (struct __go_channel) - + ((entries == 0 ? 1 : entries) - * alloc_size - * sizeof (uint64_t))); - i = pthread_mutex_init (&ret->lock, NULL); - __go_assert (i == 0); - i = pthread_cond_init (&ret->cond, NULL); - __go_assert (i == 0); - ret->element_type = element_type; - ret->waiting_to_send = 0; - ret->waiting_to_receive = 0; - ret->selected_for_send = 0; - ret->selected_for_receive = 0; - ret->is_closed = 0; - ret->select_send_queue = NULL; - ret->select_receive_queue = NULL; - ret->select_mutex = NULL; - ret->select_cond = NULL; - ret->num_entries = entries; - ret->next_store = 0; - ret->next_fetch = 0; - return ret; -} diff --git a/libgo/runtime/go-rec-big.c b/libgo/runtime/go-rec-big.c deleted file mode 100644 index d45e90af476..00000000000 --- a/libgo/runtime/go-rec-big.c +++ /dev/null @@ -1,43 +0,0 @@ -/* go-rec-big.c -- receive something larger than 64 bits on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "go-panic.h" -#include "channel.h" - -/* Returns true if a value was received, false if the channel is - closed. */ - -_Bool -__go_receive_big (struct __go_channel *channel, void *val, _Bool for_select) -{ - uintptr_t element_size; - size_t alloc_size; - size_t offset; - - if (channel == NULL) - { - /* Block forever. */ - __go_select (0, 0, NULL, NULL); - } - - element_size = channel->element_type->__size; - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - if (!__go_receive_acquire (channel, for_select)) - { - __builtin_memset (val, 0, element_size); - return 0; - } - - offset = channel->next_fetch * alloc_size; - __builtin_memcpy (val, &channel->data[offset], element_size); - - __go_receive_release (channel); - - return 1; -} diff --git a/libgo/runtime/go-rec-nb-big.c b/libgo/runtime/go-rec-nb-big.c deleted file mode 100644 index 659ea1dc33d..00000000000 --- a/libgo/runtime/go-rec-nb-big.c +++ /dev/null @@ -1,46 +0,0 @@ -/* go-rec-nb-big.c -- nonblocking receive of something big on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "channel.h" - -/* Return true if a value was received, false if not. */ - -_Bool -__go_receive_nonblocking_big (struct __go_channel* channel, void *val, - _Bool *closed) -{ - uintptr_t element_size; - size_t alloc_size; - size_t offset; - - if (channel == NULL) - { - if (closed != NULL) - *closed = 0; - return 0; - } - - element_size = channel->element_type->__size; - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - int data = __go_receive_nonblocking_acquire (channel); - if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA) - { - __builtin_memset (val, 0, element_size); - if (closed != NULL) - *closed = data == RECEIVE_NONBLOCKING_ACQUIRE_CLOSED; - return 0; - } - - offset = channel->next_fetch * alloc_size; - __builtin_memcpy (val, &channel->data[offset], element_size); - - __go_receive_release (channel); - - return 1; -} diff --git a/libgo/runtime/go-rec-nb-small.c b/libgo/runtime/go-rec-nb-small.c deleted file mode 100644 index c21878ce131..00000000000 --- a/libgo/runtime/go-rec-nb-small.c +++ /dev/null @@ -1,123 +0,0 @@ -/* go-rec-nb-small.c -- nonblocking receive of something smal on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* Prepare to receive something on a nonblocking channel. */ - -int -__go_receive_nonblocking_acquire (struct __go_channel *channel) -{ - int i; - _Bool has_data; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (channel->selected_for_receive) - runtime_cond_wait (&channel->cond, &channel->lock); - - if (channel->is_closed - && (channel->num_entries == 0 - ? channel->next_store == 0 - : channel->next_fetch == channel->next_store)) - { - __go_unlock_and_notify_selects (channel); - return RECEIVE_NONBLOCKING_ACQUIRE_CLOSED; - } - - if (channel->num_entries > 0) - has_data = channel->next_fetch != channel->next_store; - else - { - if (channel->waiting_to_receive) - { - /* Some other goroutine is already waiting for data on this - channel, so we can't pick it up. */ - has_data = 0; - } - else if (channel->next_store > 0) - { - /* There is data on the channel. */ - has_data = 1; - } - else if (__go_synch_with_select (channel, 0)) - { - /* We synched up with a select sending data, so there will - be data for us shortly. Tell the select to go, and then - wait for the data. */ - __go_broadcast_to_select (channel); - - while (channel->next_store == 0) - runtime_cond_wait (&channel->cond, &channel->lock); - - has_data = 1; - } - else - { - /* Otherwise there is no data. */ - has_data = 0; - } - - if (has_data) - { - channel->waiting_to_receive = 1; - __go_assert (channel->next_store == 1); - } - } - - if (!has_data) - { - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - return RECEIVE_NONBLOCKING_ACQUIRE_NODATA; - } - - return RECEIVE_NONBLOCKING_ACQUIRE_DATA; -} - -/* Receive something 64 bits or smaller on a nonblocking channel. */ - -struct __go_receive_nonblocking_small -__go_receive_nonblocking_small (struct __go_channel *channel) -{ - uintptr_t element_size; - struct __go_receive_nonblocking_small ret; - - if (channel == NULL) - { - ret.__val = 0; - ret.__success = 0; - ret.__closed = 0; - return ret; - } - - element_size = channel->element_type->__size; - __go_assert (element_size <= sizeof (uint64_t)); - - int data = __go_receive_nonblocking_acquire (channel); - if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA) - { - ret.__val = 0; - ret.__success = 0; - ret.__closed = data == RECEIVE_NONBLOCKING_ACQUIRE_CLOSED; - return ret; - } - - ret.__val = channel->data[channel->next_fetch]; - - __go_receive_release (channel); - - ret.__success = 1; - ret.__closed = 0; - - return ret; -} diff --git a/libgo/runtime/go-rec-small.c b/libgo/runtime/go-rec-small.c deleted file mode 100644 index f26dbcdd993..00000000000 --- a/libgo/runtime/go-rec-small.c +++ /dev/null @@ -1,304 +0,0 @@ -/* go-rec-small.c -- receive something smaller than 64 bits on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* This mutex controls access to the selected field of struct - __go_channel_select. While this mutex is held, no other mutexes - may be acquired. */ - -pthread_mutex_t __go_select_data_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* Try to synchronize with a select waiting on a sychronized channel. - This is used by a send or receive. The channel is locked. This - returns true if it was able to synch. */ - -_Bool -__go_synch_with_select (struct __go_channel *channel, _Bool is_send) -{ - struct __go_channel_select *p; - int i; - - __go_assert (channel->num_entries == 0); - - i = pthread_mutex_lock (&__go_select_data_mutex); - __go_assert (i == 0); - - for (p = (is_send - ? channel->select_receive_queue - : channel->select_send_queue); - p != NULL; - p = p->next) - { - if (*p->selected == NULL) - { - *p->selected = channel; - *p->is_read = !is_send; - if (is_send) - channel->selected_for_receive = 1; - else - channel->selected_for_send = 1; - break; - } - } - - i = pthread_mutex_unlock (&__go_select_data_mutex); - __go_assert (i == 0); - - /* The caller is responsible for signalling the select condition - variable so that the other select knows that something has - changed. We can't signal it here because we can't acquire the - select mutex while we hold a channel lock. */ - - return p != NULL; -} - -/* If we synch with a select, then we need to signal the select that - something has changed. This requires grabbing the select mutex, - which can only be done when the channel is unlocked. This routine - does the signalling. It is called with the channel locked. It - unlocks the channel, broadcasts the signal and relocks the - channel. */ - -void -__go_broadcast_to_select (struct __go_channel *channel) -{ - pthread_mutex_t *select_mutex; - pthread_cond_t *select_cond; - int i; - - select_mutex = channel->select_mutex; - select_cond = channel->select_cond; - - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - __go_assert (select_mutex != NULL && select_cond != NULL); - - i = pthread_mutex_lock (select_mutex); - __go_assert (i == 0); - - i = pthread_cond_broadcast (select_cond); - __go_assert (i == 0); - - i = pthread_mutex_unlock (select_mutex); - __go_assert (i == 0); - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); -} - -/* Prepare to receive something on a channel. Return true if the - channel is acquired (which implies that there is data available), - false if it is closed. */ - -_Bool -__go_receive_acquire (struct __go_channel *channel, _Bool for_select) -{ - int i; - _Bool my_wait_lock; - _Bool synched_with_select; - - my_wait_lock = 0; - synched_with_select = 0; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (1) - { - _Bool need_broadcast; - - need_broadcast = 0; - - /* Check whether the channel is closed. */ - if (channel->is_closed - && (channel->num_entries == 0 - ? channel->next_store == 0 - : channel->next_fetch == channel->next_store)) - { - channel->selected_for_receive = 0; - __go_unlock_and_notify_selects (channel); - return 0; - } - - /* If somebody else has the channel locked for receiving, we - have to wait. If FOR_SELECT is true, then we are the one - with the lock. */ - if (!channel->selected_for_receive || for_select) - { - if (channel->num_entries == 0) - { - /* If somebody else is waiting to receive, we have to - wait. */ - if (!channel->waiting_to_receive || my_wait_lock) - { - _Bool was_marked; - - /* Lock the channel so that we get to receive - next. */ - was_marked = channel->waiting_to_receive; - channel->waiting_to_receive = 1; - my_wait_lock = 1; - - /* See if there is a value to receive. */ - if (channel->next_store > 0) - return 1; - - /* If we haven't already done so, try to synch with - a select waiting to send on this channel. If we - have already synched with a select, we are just - looping until the select eventually causes - something to be sent. */ - if (!synched_with_select && !for_select) - { - if (__go_synch_with_select (channel, 0)) - { - synched_with_select = 1; - need_broadcast = 1; - } - } - - /* If we marked the channel as waiting, we need to - signal, because something changed. It needs to - be a broadcast since there might be other - receivers waiting. */ - if (!was_marked) - { - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - } - } - } - else - { - /* If there is a value on the channel, we are OK. */ - if (channel->next_fetch != channel->next_store) - return 1; - } - } - - /* If we just synched with a select, then we need to signal the - select condition variable. We can only do that if we unlock - the channel. So we need to unlock, signal, lock, and go - around the loop again without waiting. */ - if (need_broadcast) - { - __go_broadcast_to_select (channel); - continue; - } - - /* Wait for something to change, then loop around and try - again. */ - - runtime_cond_wait (&channel->cond, &channel->lock); - } -} - -/* Finished receiving something on a channel. */ - -void -__go_receive_release (struct __go_channel *channel) -{ - int i; - - if (channel->num_entries != 0) - channel->next_fetch = (channel->next_fetch + 1) % channel->num_entries; - else - { - /* For a synchronous receiver, we tell the sender that we picked - up the value by setting the next_store field back to 0. - Using the mutexes should implement a memory barrier. */ - __go_assert (channel->next_store == 1); - channel->next_store = 0; - - channel->waiting_to_receive = 0; - } - - channel->selected_for_receive = 0; - - /* This is a broadcast to make sure that a synchronous sender sees - it. */ - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - - __go_unlock_and_notify_selects (channel); -} - -/* Unlock a channel and notify any waiting selects that something - happened. */ - -void -__go_unlock_and_notify_selects (struct __go_channel *channel) -{ - pthread_mutex_t* select_mutex; - pthread_cond_t* select_cond; - int i; - - select_mutex = channel->select_mutex; - select_cond = channel->select_cond; - - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - if (select_mutex != NULL) - { - i = pthread_mutex_lock (select_mutex); - __go_assert (i == 0); - i = pthread_cond_broadcast (select_cond); - __go_assert (i == 0); - i = pthread_mutex_unlock (select_mutex); - __go_assert (i == 0); - } -} - -/* Receive something 64 bits or smaller on a channel. */ - -uint64_t -__go_receive_small_closed (struct __go_channel *channel, _Bool for_select, - _Bool *received) -{ - uintptr_t element_size; - uint64_t ret; - - if (channel == NULL) - { - /* Block forever. */ - __go_select (0, 0, NULL, NULL); - } - - element_size = channel->element_type->__size; - __go_assert (element_size <= sizeof (uint64_t)); - - if (!__go_receive_acquire (channel, for_select)) - { - if (received != NULL) - *received = 0; - return 0; - } - - ret = channel->data[channel->next_fetch]; - - __go_receive_release (channel); - - if (received != NULL) - *received = 1; - - return ret; -} - -/* Called by the compiler. */ - -uint64_t -__go_receive_small (struct __go_channel *channel, _Bool for_select) -{ - return __go_receive_small_closed (channel, for_select, NULL); -} diff --git a/libgo/runtime/go-reflect-chan.c b/libgo/runtime/go-reflect-chan.c deleted file mode 100644 index 6f6693b6b54..00000000000 --- a/libgo/runtime/go-reflect-chan.c +++ /dev/null @@ -1,200 +0,0 @@ -/* go-reflect-chan.c -- channel reflection support for Go. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdlib.h> -#include <stdint.h> - -#include "config.h" -#include "go-alloc.h" -#include "go-assert.h" -#include "go-panic.h" -#include "go-type.h" -#include "channel.h" - -/* This file implements support for reflection on channels. These - functions are called from reflect/value.go. */ - -extern uintptr_t makechan (const struct __go_type_descriptor *, uint32_t) - asm ("libgo_reflect.reflect.makechan"); - -uintptr_t -makechan (const struct __go_type_descriptor *typ, uint32_t size) -{ - struct __go_channel *channel; - void *ret; - - channel = __go_new_channel (typ, size); - - ret = __go_alloc (sizeof (void *)); - __builtin_memcpy (ret, &channel, sizeof (void *)); - return (uintptr_t) ret; -} - -extern _Bool chansend (struct __go_channel_type *, uintptr_t, uintptr_t, _Bool) - asm ("libgo_reflect.reflect.chansend"); - -_Bool -chansend (struct __go_channel_type *ct, uintptr_t ch, uintptr_t val_i, - _Bool nb) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - uintptr_t element_size; - void *pv; - - __go_assert (ct->__common.__code == GO_CHAN); - - if (__go_is_pointer_type (ct->__element_type)) - pv = &val_i; - else - pv = (void *) val_i; - - element_size = ct->__element_type->__size; - if (element_size <= sizeof (uint64_t)) - { - union - { - char b[sizeof (uint64_t)]; - uint64_t v; - } u; - - __builtin_memset (u.b, 0, sizeof (uint64_t)); -#ifndef WORDS_BIGENDIAN - __builtin_memcpy (u.b, pv, element_size); -#else - __builtin_memcpy (u.b + sizeof (uint64_t) - element_size, pv, - element_size); -#endif - if (nb) - return __go_send_nonblocking_small (channel, u.v); - else - { - __go_send_small (channel, u.v, 0); - return 1; - } - } - else - { - if (nb) - return __go_send_nonblocking_big (channel, pv); - else - { - __go_send_big (channel, pv, 0); - return 1; - } - } -} - -struct chanrecv_ret -{ - uintptr_t val; - _Bool selected; - _Bool received; -}; - -extern struct chanrecv_ret chanrecv (struct __go_channel_type *, uintptr_t, - _Bool) - asm ("libgo_reflect.reflect.chanrecv"); - -struct chanrecv_ret -chanrecv (struct __go_channel_type *ct, uintptr_t ch, _Bool nb) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - void *pv; - uintptr_t element_size; - struct chanrecv_ret ret; - - __go_assert (ct->__common.__code == GO_CHAN); - - element_size = ct->__element_type->__size; - - if (__go_is_pointer_type (ct->__element_type)) - pv = &ret.val; - else - { - pv = __go_alloc (element_size); - ret.val = (uintptr_t) pv; - } - - if (element_size <= sizeof (uint64_t)) - { - union - { - char b[sizeof (uint64_t)]; - uint64_t v; - } u; - - if (!nb) - { - u.v = __go_receive_small_closed (channel, 0, &ret.received); - ret.selected = 1; - } - else - { - struct __go_receive_nonblocking_small s; - - s = __go_receive_nonblocking_small (channel); - ret.selected = s.__success || s.__closed; - ret.received = s.__success; - u.v = s.__val; - } - -#ifndef WORDS_BIGENDIAN - __builtin_memcpy (pv, u.b, element_size); -#else - __builtin_memcpy (pv, u.b + sizeof (uint64_t) - element_size, - element_size); -#endif - } - else - { - if (!nb) - { - ret.received = __go_receive_big (channel, pv, 0); - ret.selected = 1; - } - else - { - _Bool got; - _Bool closed; - - got = __go_receive_nonblocking_big (channel, pv, &closed); - ret.selected = got || closed; - ret.received = got; - } - } - - return ret; -} - -extern void chanclose (uintptr_t) asm ("libgo_reflect.reflect.chanclose"); - -void -chanclose (uintptr_t ch) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - - __go_builtin_close (channel); -} - -extern int32_t chanlen (uintptr_t) asm ("libgo_reflect.reflect.chanlen"); - -int32_t -chanlen (uintptr_t ch) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - - return (int32_t) __go_chan_len (channel); -} - -extern int32_t chancap (uintptr_t) asm ("libgo_reflect.reflect.chancap"); - -int32_t -chancap (uintptr_t ch) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - - return (int32_t) __go_chan_cap (channel); -} diff --git a/libgo/runtime/go-select.c b/libgo/runtime/go-select.c deleted file mode 100644 index 677c699b52c..00000000000 --- a/libgo/runtime/go-select.c +++ /dev/null @@ -1,758 +0,0 @@ -/* go-select.c -- implement select. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <pthread.h> -#include <stdarg.h> -#include <stddef.h> -#include <stdint.h> -#include <stdlib.h> -#include <unistd.h> - -#include "runtime.h" -#include "config.h" -#include "go-assert.h" -#include "channel.h" - -/* __go_select builds an array of these structures. */ - -struct select_channel -{ - /* The channel being selected. */ - struct __go_channel* channel; - /* If this channel is selected, the value to return. */ - uintptr_t retval; - /* If this channel is a duplicate of one which appears earlier in - the array, this is the array index of the earlier channel. This - is -1UL if this is not a dup. */ - uintptr_t dup_index; - /* An entry to put on the send or receive queue. */ - struct __go_channel_select queue_entry; - /* True if selected for send. */ - _Bool is_send; - /* True if channel is ready--it has data to receive or space to - send. */ - _Bool is_ready; -}; - -/* This mutex controls access to __go_select_cond. This mutex may not - be acquired if any channel locks are held. */ - -static pthread_mutex_t __go_select_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* When we have to wait for channels, we tell them to trigger this - condition variable when they send or receive something. */ - -static pthread_cond_t __go_select_cond = PTHREAD_COND_INITIALIZER; - -/* Sort the channels by address. This avoids deadlock when multiple - selects are running on overlapping sets of channels. */ - -static int -channel_sort (const void *p1, const void *p2) -{ - const struct select_channel *c1 = (const struct select_channel *) p1; - const struct select_channel *c2 = (const struct select_channel *) p2; - - if ((uintptr_t) c1->channel < (uintptr_t) c2->channel) - return -1; - else if ((uintptr_t) c1->channel > (uintptr_t) c2->channel) - return 1; - else - return 0; -} - -/* Return whether there is an entry on QUEUE which can be used for a - synchronous send or receive. */ - -static _Bool -is_queue_ready (struct __go_channel_select *queue) -{ - int x; - - if (queue == NULL) - return 0; - - x = pthread_mutex_lock (&__go_select_data_mutex); - __go_assert (x == 0); - - while (queue != NULL) - { - if (*queue->selected == NULL) - break; - queue = queue->next; - } - - x = pthread_mutex_unlock (&__go_select_data_mutex); - __go_assert (x == 0); - - return queue != NULL; -} - -/* Return whether CHAN is ready. If IS_SEND is true check whether it - has space to send, otherwise check whether it has a value to - receive. */ - -static _Bool -is_channel_ready (struct __go_channel* channel, _Bool is_send) -{ - if (is_send) - { - if (channel->selected_for_send) - return 0; - if (channel->is_closed) - return 1; - if (channel->num_entries > 0) - { - /* An asynchronous channel is ready for sending if there is - room in the buffer. */ - return ((channel->next_store + 1) % channel->num_entries - != channel->next_fetch); - } - else - { - if (channel->waiting_to_send) - { - /* Some other goroutine is waiting to send on this - channel, so we can't. */ - return 0; - } - if (channel->waiting_to_receive) - { - /* Some other goroutine is waiting to receive a value, - so we can send one. */ - return 1; - } - if (is_queue_ready (channel->select_receive_queue)) - { - /* There is a select statement waiting to synchronize - with this one. */ - return 1; - } - return 0; - } - } - else - { - if (channel->selected_for_receive) - return 0; - if (channel->is_closed) - return 1; - if (channel->num_entries > 0) - { - /* An asynchronous channel is ready for receiving if there - is a value in the buffer. */ - return channel->next_fetch != channel->next_store; - } - else - { - if (channel->waiting_to_receive) - { - /* Some other goroutine is waiting to receive from this - channel, so it is not ready for us to receive. */ - return 0; - } - if (channel->next_store > 0) - { - /* There is data on the channel. */ - return 1; - } - if (is_queue_ready (channel->select_send_queue)) - { - /* There is a select statement waiting to synchronize - with this one. */ - return 1; - } - return 0; - } - } -} - -/* Mark a channel as selected. The channel is locked. IS_SELECTED is - true if the channel was selected for us by another goroutine. We - set *NEEDS_BROADCAST if we need to broadcast on the select - condition variable. Return true if we got it. */ - -static _Bool -mark_channel_selected (struct __go_channel *channel, _Bool is_send, - _Bool is_selected, _Bool *needs_broadcast) -{ - if (channel->num_entries == 0) - { - /* This is a synchronous channel. If there is no goroutine - currently waiting, but there is another select waiting, then - we need to tell that select to use this channel. That may - fail--there may be no other goroutines currently waiting--as - a third goroutine may already have claimed the select. */ - if (!is_selected - && !channel->is_closed - && (is_send - ? !channel->waiting_to_receive - : channel->next_store == 0)) - { - int x; - struct __go_channel_select *queue; - - x = pthread_mutex_lock (&__go_select_data_mutex); - __go_assert (x == 0); - - queue = (is_send - ? channel->select_receive_queue - : channel->select_send_queue); - __go_assert (queue != NULL); - - while (queue != NULL) - { - if (*queue->selected == NULL) - { - *queue->selected = channel; - *queue->is_read = !is_send; - break; - } - queue = queue->next; - } - - x = pthread_mutex_unlock (&__go_select_data_mutex); - __go_assert (x == 0); - - if (queue == NULL) - return 0; - - if (is_send) - channel->selected_for_receive = 1; - else - channel->selected_for_send = 1; - - /* We are going to have to tell the other select that there - is something to do. */ - *needs_broadcast = 1; - } - } - - if (is_send) - channel->selected_for_send = 1; - else - channel->selected_for_receive = 1; - - return 1; -} - -/* Mark a channel to indicate that a select is waiting. The channel - is locked. */ - -static void -mark_select_waiting (struct select_channel *sc, - struct __go_channel **selected_pointer, - _Bool *selected_for_read_pointer) -{ - struct __go_channel *channel = sc->channel; - _Bool is_send = sc->is_send; - - if (channel->num_entries == 0) - { - struct __go_channel_select **pp; - - pp = (is_send - ? &channel->select_send_queue - : &channel->select_receive_queue); - - /* Add an entry to the queue of selects on this channel. */ - sc->queue_entry.next = *pp; - sc->queue_entry.selected = selected_pointer; - sc->queue_entry.is_read = selected_for_read_pointer; - - *pp = &sc->queue_entry; - } - - channel->select_mutex = &__go_select_mutex; - channel->select_cond = &__go_select_cond; - - /* We never actually clear the select_mutex and select_cond fields. - In order to clear them safely, we would need to have some way of - knowing when no select is waiting for the channel. Thus we - introduce a bit of inefficiency for every channel that select - needs to wait for. This is harmless other than the performance - cost. */ -} - -/* Remove the entry for this select waiting on this channel. The - channel is locked. We check both queues, because the channel may - be selected for both reading and writing. */ - -static void -clear_select_waiting (struct select_channel *sc, - struct __go_channel **selected_pointer) -{ - struct __go_channel *channel = sc->channel; - - if (channel->num_entries == 0) - { - _Bool found; - struct __go_channel_select **pp; - - found = 0; - - for (pp = &channel->select_send_queue; *pp != NULL; pp = &(*pp)->next) - { - if ((*pp)->selected == selected_pointer) - { - *pp = (*pp)->next; - found = 1; - break; - } - } - - for (pp = &channel->select_receive_queue; *pp != NULL; pp = &(*pp)->next) - { - if ((*pp)->selected == selected_pointer) - { - *pp = (*pp)->next; - found = 1; - break; - } - } - - __go_assert (found); - } -} - -/* Look through the list of channels to see which ones are ready. - Lock each channels, and set the is_ready flag. Return the number - of ready channels. */ - -static uintptr_t -lock_channels_find_ready (struct select_channel *channels, uintptr_t count) -{ - uintptr_t ready_count; - uintptr_t i; - - ready_count = 0; - for (i = 0; i < count; ++i) - { - struct __go_channel *channel = channels[i].channel; - _Bool is_send = channels[i].is_send; - uintptr_t dup_index = channels[i].dup_index; - int x; - - if (channel == NULL) - continue; - - if (dup_index != (uintptr_t) -1UL) - { - if (channels[dup_index].is_ready) - { - channels[i].is_ready = 1; - ++ready_count; - } - continue; - } - - x = pthread_mutex_lock (&channel->lock); - __go_assert (x == 0); - - if (is_channel_ready (channel, is_send)) - { - channels[i].is_ready = 1; - ++ready_count; - } - } - - return ready_count; -} - -/* The channel we are going to select has been forced by some other - goroutine. SELECTED_CHANNEL is the channel we will use, - SELECTED_FOR_READ is whether the other goroutine wants to read from - the channel. Note that the channel could be specified multiple - times in this select, so we must mark each appropriate entry for - this channel as ready. Every other channel is marked as not ready. - All the channels are locked before this routine is called. This - returns the number of ready channels. */ - -uintptr_t -force_selected_channel_ready (struct select_channel *channels, uintptr_t count, - struct __go_channel *selected_channel, - _Bool selected_for_read) -{ - uintptr_t ready_count; - uintptr_t i; - - ready_count = 0; - for (i = 0; i < count; ++i) - { - struct __go_channel *channel = channels[i].channel; - _Bool is_send = channels[i].is_send; - - if (channel == NULL) - continue; - - if (channel != selected_channel - || (is_send ? !selected_for_read : selected_for_read)) - channels[i].is_ready = 0; - else - { - channels[i].is_ready = 1; - ++ready_count; - } - } - __go_assert (ready_count > 0); - return ready_count; -} - -/* Unlock all the channels. */ - -static void -unlock_channels (struct select_channel *channels, uintptr_t count) -{ - uintptr_t i; - int x; - - for (i = 0; i < count; ++i) - { - struct __go_channel *channel = channels[i].channel; - - if (channel == NULL) - continue; - - if (channels[i].dup_index != (uintptr_t) -1UL) - continue; - - x = pthread_mutex_unlock (&channel->lock); - __go_assert (x == 0); - } -} - -/* At least one channel is ready. Randomly pick a channel to return. - Unlock all the channels. IS_SELECTED is true if the channel was - picked for us by some other goroutine. If SELECTED_POINTER is not - NULL, remove it from the queue for all the channels. Return the - retval field of the selected channel. This will return 0 if we - can't use the selected channel, because it relied on synchronizing - with some other select, and that select already synchronized with a - different channel. */ - -static uintptr_t -unlock_channels_and_select (struct select_channel *channels, - uintptr_t count, uintptr_t ready_count, - _Bool is_selected, - struct __go_channel **selected_pointer) -{ - uintptr_t selected; - uintptr_t ret; - _Bool needs_broadcast; - uintptr_t i; - int x; - - /* Pick which channel we are going to return. */ -#if defined(HAVE_RANDOM) - selected = (uintptr_t) random () % ready_count; -#else - selected = (uintptr_t) rand () % ready_count; -#endif - ret = 0; - needs_broadcast = 0; - - /* Look at the channels in reverse order so that we don't unlock a - duplicated channel until we have seen all its dups. */ - for (i = 0; i < count; ++i) - { - uintptr_t j = count - i - 1; - struct __go_channel *channel = channels[j].channel; - _Bool is_send = channels[j].is_send; - - if (channel == NULL) - continue; - - if (channels[j].is_ready) - { - if (selected == 0) - { - if (mark_channel_selected (channel, is_send, is_selected, - &needs_broadcast)) - ret = channels[j].retval; - } - - --selected; - } - - if (channels[j].dup_index == (uintptr_t) -1UL) - { - if (selected_pointer != NULL) - clear_select_waiting (&channels[j], selected_pointer); - - x = pthread_mutex_unlock (&channel->lock); - __go_assert (x == 0); - } - } - - /* The NEEDS_BROADCAST variable is set if we are synchronizing with - some other select statement. We can't do the actual broadcast - until we have unlocked all the channels. */ - - if (needs_broadcast) - { - x = pthread_mutex_lock (&__go_select_mutex); - __go_assert (x == 0); - - x = pthread_cond_broadcast (&__go_select_cond); - __go_assert (x == 0); - - x = pthread_mutex_unlock (&__go_select_mutex); - __go_assert (x == 0); - } - - return ret; -} - -/* Mark all channels to show that we are waiting for them. This is - called with the select mutex held, but none of the channels are - locked. This returns true if some channel was found to be - ready. */ - -static _Bool -mark_all_channels_waiting (struct select_channel* channels, uintptr_t count, - struct __go_channel **selected_pointer, - _Bool *selected_for_read_pointer) -{ - _Bool ret; - int x; - uintptr_t i; - - ret = 0; - for (i = 0; i < count; ++i) - { - struct __go_channel *channel = channels[i].channel; - _Bool is_send = channels[i].is_send; - - if (channel == NULL) - continue; - - if (channels[i].dup_index != (uintptr_t) -1UL) - { - uintptr_t j; - - /* A channel may be selected for both read and write. */ - if (channels[channels[i].dup_index].is_send == is_send) - continue; - else - { - for (j = channels[i].dup_index + 1; j < i; ++j) - { - if (channels[j].channel == channel - && channels[j].is_send == is_send) - break; - } - if (j < i) - continue; - } - } - - x = pthread_mutex_lock (&channel->lock); - __go_assert (x == 0); - - /* To avoid a race condition, we have to check again whether the - channel is ready. It may have become ready since we did the - first set of checks but before we acquired the select mutex. - If we don't check here, we could sleep forever on the select - condition variable. */ - if (is_channel_ready (channel, is_send)) - ret = 1; - - /* If SELECTED_POINTER is NULL, then we have already marked the - channel as waiting. */ - if (selected_pointer != NULL) - mark_select_waiting (&channels[i], selected_pointer, - selected_for_read_pointer); - - x = pthread_mutex_unlock (&channel->lock); - __go_assert (x == 0); - } - - return ret; -} - -/* Implement select. This is called by the compiler-generated code - with pairs of arguments: a pointer to a channel, and an int which - is non-zero for send, zero for receive. */ - -uintptr_t -__go_select (uintptr_t count, _Bool has_default, - struct __go_channel **channel_args, _Bool *is_send_args) -{ - struct select_channel stack_buffer[16]; - struct select_channel *allocated_buffer; - struct select_channel *channels; - uintptr_t i; - int x; - struct __go_channel *selected_channel; - _Bool selected_for_read; - _Bool is_queued; - - if (count < sizeof stack_buffer / sizeof stack_buffer[0]) - { - channels = &stack_buffer[0]; - allocated_buffer = NULL; - } - else - { - allocated_buffer = ((struct select_channel *) - malloc (count * sizeof (struct select_channel))); - channels = allocated_buffer; - } - - for (i = 0; i < count; ++i) - { - struct __go_channel *channel_arg = channel_args[i]; - _Bool is_send = is_send_args[i]; - - channels[i].channel = (struct __go_channel*) channel_arg; - channels[i].retval = i + 1; - channels[i].dup_index = (uintptr_t) -1UL; - channels[i].queue_entry.next = NULL; - channels[i].queue_entry.selected = NULL; - channels[i].is_send = is_send; - channels[i].is_ready = 0; - } - - qsort (channels, count, sizeof (struct select_channel), channel_sort); - - for (i = 0; i < count; ++i) - { - uintptr_t j; - - for (j = 0; j < i; ++j) - { - if (channels[j].channel == channels[i].channel) - { - channels[i].dup_index = j; - break; - } - } - } - - /* SELECT_CHANNEL is used to select synchronized channels. If no - channels are ready, we store a pointer to this variable on the - select queue for each synchronized channel. Because the variable - may be set by channel operations running in other goroutines, - SELECT_CHANNEL may only be accessed when all the channels are - locked and/or when the select_data_mutex is locked. */ - selected_channel = NULL; - - /* SELECTED_FOR_READ is set to true if SELECTED_CHANNEL was set by a - goroutine which wants to read from the channel. The access - restrictions for this are like those for SELECTED_CHANNEL. */ - selected_for_read = 0; - - /* IS_QUEUED is true if we have queued up this select on the queues - for any associated synchronous channels. We only do this if no - channels are ready the first time around the loop. */ - is_queued = 0; - - while (1) - { - int ready_count; - _Bool is_selected; - - /* Lock all channels, identify which ones are ready. */ - ready_count = lock_channels_find_ready (channels, count); - - /* All the channels are locked, so we can look at - SELECTED_CHANNEL. If it is not NULL, then our choice has - been forced by some other goroutine. This can only happen - after the first time through the loop. */ - is_selected = selected_channel != NULL; - if (is_selected) - ready_count = force_selected_channel_ready (channels, count, - selected_channel, - selected_for_read); - - if (ready_count > 0) - { - uintptr_t ret; - - ret = unlock_channels_and_select (channels, count, ready_count, - is_selected, - (is_queued - ? &selected_channel - : NULL)); - - /* If RET is zero, it means that the channel we picked - turned out not to be ready, because some other select - grabbed it during our traversal. Loop around and try - again. */ - if (ret == 0) - { - is_queued = 0; - /* We are no longer on any channel queues, so it is safe - to touch SELECTED_CHANNEL here. It must be NULL, - because otherwise that would somebody has promised to - synch up with us and then failed to do so. */ - __go_assert (selected_channel == NULL); - continue; - } - - if (allocated_buffer != NULL) - free (allocated_buffer); - - return ret; - } - - /* No channels were ready. */ - - unlock_channels (channels, count); - - if (has_default) - { - /* Use the default clause. */ - if (allocated_buffer != NULL) - free (allocated_buffer); - return 0; - } - - /* This is a blocking select. Grab the select lock, tell all - the channels to notify us when something happens, and wait - for something to happen. */ - - x = pthread_mutex_lock (&__go_select_mutex); - __go_assert (x == 0); - - /* Check whether CHANNEL_SELECTED was set while the channels - were unlocked. If it was set, then we can simply loop around - again. We need to check this while the select mutex is held. - It is possible that something will set CHANNEL_SELECTED while - we mark the channels as waiting. If this happens, that - goroutine is required to signal the select condition - variable, which means acquiring the select mutex. Since we - have the select mutex locked ourselves, we can not miss that - signal. */ - - x = pthread_mutex_lock (&__go_select_data_mutex); - __go_assert (x == 0); - - is_selected = selected_channel != NULL; - - x = pthread_mutex_unlock (&__go_select_data_mutex); - __go_assert (x == 0); - - if (!is_selected) - { - /* Mark the channels as waiting, and check whether they have - become ready. */ - if (!mark_all_channels_waiting (channels, count, - (is_queued - ? NULL - : &selected_channel), - (is_queued - ? NULL - : &selected_for_read))) - runtime_cond_wait (&__go_select_cond, &__go_select_mutex); - - is_queued = 1; - } - - x = pthread_mutex_unlock (&__go_select_mutex); - __go_assert (x == 0); - } -} diff --git a/libgo/runtime/go-send-big.c b/libgo/runtime/go-send-big.c deleted file mode 100644 index 61d4a0f13d9..00000000000 --- a/libgo/runtime/go-send-big.c +++ /dev/null @@ -1,34 +0,0 @@ -/* go-send-big.c -- send something bigger than uint64_t on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "go-panic.h" -#include "channel.h" - -void -__go_send_big (struct __go_channel* channel, const void *val, _Bool for_select) -{ - uintptr_t element_size; - size_t alloc_size; - size_t offset; - - if (channel == NULL) - { - // Block forever. - __go_select (0, 0, NULL, NULL); - } - - element_size = channel->element_type->__size; - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - __go_send_acquire (channel, for_select); - - offset = channel->next_store * alloc_size; - __builtin_memcpy (&channel->data[offset], val, element_size); - - __go_send_release (channel); -} diff --git a/libgo/runtime/go-send-nb-big.c b/libgo/runtime/go-send-nb-big.c deleted file mode 100644 index e039874ef9a..00000000000 --- a/libgo/runtime/go-send-nb-big.c +++ /dev/null @@ -1,33 +0,0 @@ -/* go-send-nb-big.c -- nonblocking send of something big on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "channel.h" - -_Bool -__go_send_nonblocking_big (struct __go_channel* channel, const void *val) -{ - uintptr_t element_size; - size_t alloc_size; - size_t offset; - - if (channel == NULL) - return 0; - - element_size = channel->element_type->__size; - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - if (!__go_send_nonblocking_acquire (channel)) - return 0; - - offset = channel->next_store * alloc_size; - __builtin_memcpy (&channel->data[offset], val, element_size); - - __go_send_release (channel); - - return 1; -} diff --git a/libgo/runtime/go-send-nb-small.c b/libgo/runtime/go-send-nb-small.c deleted file mode 100644 index c77ee9183e2..00000000000 --- a/libgo/runtime/go-send-nb-small.c +++ /dev/null @@ -1,107 +0,0 @@ -/* go-send-nb-small.c -- nonblocking send of something small on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* Prepare to send something on a nonblocking channel. Return true if - we acquired the channel, false if we did not acquire it because - there is no space to send a value. */ - -_Bool -__go_send_nonblocking_acquire (struct __go_channel *channel) -{ - int i; - _Bool has_space; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (channel->selected_for_send) - runtime_cond_wait (&channel->cond, &channel->lock); - - if (channel->is_closed) - { - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - runtime_panicstring ("send on closed channel"); - } - - if (channel->num_entries > 0) - has_space = ((channel->next_store + 1) % channel->num_entries - != channel->next_fetch); - else - { - /* This is a synchronous channel. If somebody is current - sending, then we can't send. Otherwise, see if somebody is - waiting to receive, or see if we can synch with a select. */ - if (channel->waiting_to_send) - { - /* Some other goroutine is currently sending on this - channel, which means that we can't. */ - has_space = 0; - } - else if (channel->waiting_to_receive) - { - /* Some other goroutine is waiting to receive a value, so we - can send directly to them. */ - has_space = 1; - } - else if (__go_synch_with_select (channel, 1)) - { - /* We found a select waiting to receive data, so we can send - to that. */ - __go_broadcast_to_select (channel); - has_space = 1; - } - else - { - /* Otherwise, we can't send, because nobody is waiting to - receive. */ - has_space = 0; - } - - if (has_space) - { - channel->waiting_to_send = 1; - __go_assert (channel->next_store == 0); - } - } - - if (!has_space) - { - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - return 0; - } - - return 1; -} - -/* Send something 64 bits or smaller on a channel. */ - -_Bool -__go_send_nonblocking_small (struct __go_channel *channel, uint64_t val) -{ - if (channel == NULL) - return 0; - - __go_assert (channel->element_type->__size <= sizeof (uint64_t)); - - if (!__go_send_nonblocking_acquire (channel)) - return 0; - - channel->data[channel->next_store] = val; - - __go_send_release (channel); - - return 1; -} diff --git a/libgo/runtime/go-send-small.c b/libgo/runtime/go-send-small.c deleted file mode 100644 index 06bcb41b9ad..00000000000 --- a/libgo/runtime/go-send-small.c +++ /dev/null @@ -1,159 +0,0 @@ -/* go-send-small.c -- send something 64 bits or smaller on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* Prepare to send something on a channel. FOR_SELECT is true if this - call is being made after a select statement returned with this - channel selected. */ - -void -__go_send_acquire (struct __go_channel *channel, _Bool for_select) -{ - int i; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (1) - { - if (channel->is_closed) - { - if (for_select) - channel->selected_for_send = 0; - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - runtime_panicstring ("send on closed channel"); - } - - /* If somebody else has the channel locked for sending, we have - to wait. If FOR_SELECT is true, then we are the one with the - lock. */ - if (!channel->selected_for_send || for_select) - { - if (channel->num_entries == 0) - { - /* This is a synchronous channel. If nobody else is - waiting to send, we grab the channel and tell the - caller to send the data. We will then wait for a - receiver. */ - if (!channel->waiting_to_send) - { - __go_assert (channel->next_store == 0); - return; - } - } - else - { - /* If there is room on the channel, we are OK. */ - if ((channel->next_store + 1) % channel->num_entries - != channel->next_fetch) - return; - } - } - - /* Wait for something to change, then loop around and try - again. */ - - runtime_cond_wait (&channel->cond, &channel->lock); - } -} - -/* Finished sending something on a channel. */ - -void -__go_send_release (struct __go_channel *channel) -{ - int i; - - if (channel->num_entries != 0) - { - /* This is a buffered channel. Bump the store count and signal - the condition variable. */ - channel->next_store = (channel->next_store + 1) % channel->num_entries; - - i = pthread_cond_signal (&channel->cond); - __go_assert (i == 0); - } - else - { - _Bool synched_with_select; - - /* This is a synchronous channel. Indicate that we have a value - waiting. */ - channel->next_store = 1; - channel->waiting_to_send = 1; - - /* Tell everybody else to do something. This has to be a - broadcast because we might have both senders and receivers - waiting on the condition, but senders won't send another - signal. */ - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - - /* Wait until the value is received. */ - synched_with_select = 0; - while (1) - { - if (channel->next_store == 0) - break; - - /* If nobody is currently waiting to receive, try to synch - up with a select. */ - if (!channel->waiting_to_receive && !synched_with_select) - { - if (__go_synch_with_select (channel, 1)) - { - synched_with_select = 1; - __go_broadcast_to_select (channel); - continue; - } - } - - runtime_cond_wait (&channel->cond, &channel->lock); - } - - channel->waiting_to_send = 0; - - /* Using the mutexes should implement a memory barrier. */ - - /* We have to signal again since we cleared the waiting_to_send - field. This has to be a broadcast because both senders and - receivers might be waiting, but only senders will be able to - act. */ - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - } - - channel->selected_for_send = 0; - - __go_unlock_and_notify_selects (channel); -} - -/* Send something 64 bits or smaller on a channel. */ - -void -__go_send_small (struct __go_channel *channel, uint64_t val, _Bool for_select) -{ - if (channel == NULL) - { - // Block forever. - __go_select (0, 0, NULL, NULL); - } - - __go_assert (channel->element_type->__size <= sizeof (uint64_t)); - - __go_send_acquire (channel, for_select); - - channel->data[channel->next_store] = val; - - __go_send_release (channel); -} diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c index 958b421c871..cd165f45112 100644 --- a/libgo/runtime/go-signal.c +++ b/libgo/runtime/go-signal.c @@ -218,7 +218,7 @@ sighandler (int sig) /* Ignore a signal. */ static void -sigignore (int sig __attribute__ ((unused))) +sig_ignore (int sig __attribute__ ((unused))) { } @@ -247,7 +247,7 @@ runtime_initsig (int32 queue) if (signals[i].catch || signals[i].queue) sa.sa_handler = sighandler; else - sa.sa_handler = sigignore; + sa.sa_handler = sig_ignore; sa.sa_flags = signals[i].restart ? SA_RESTART : 0; if (sigaction (signals[i].sig, &sa, NULL) != 0) __go_assert (0); diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 9455ae88c5a..e28bc82f8ab 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -55,14 +55,15 @@ typedef struct M M; typedef union Note Note; typedef struct MCache MCache; typedef struct FixAlloc FixAlloc; +typedef struct Hchan Hchan; -typedef struct __go_defer_stack Defer; +typedef struct __go_open_array Slice; +typedef struct __go_string String; typedef struct __go_interface Iface; typedef struct __go_empty_interface Eface; typedef struct __go_type_descriptor Type; +typedef struct __go_defer_stack Defer; typedef struct __go_panic_stack Panic; -typedef struct __go_open_array Slice; -typedef struct __go_string String; typedef struct __go_func_type FuncType; typedef struct __go_map_type MapType; @@ -131,6 +132,7 @@ struct G bool fromgogo; // reached from gogo int16 status; int32 goid; + uint32 selgen; // valid sudog pointer const char* waitreason; // if status==Gwaiting G* schedlink; bool readyonstop; @@ -335,6 +337,3 @@ void reflect_call(const struct __go_func_type *, const void *, _Bool, _Bool, #ifdef __rtems__ void __wrap_rtems_task_variable_add(void **); #endif - -/* Temporary. */ -void runtime_cond_wait(pthread_cond_t*, pthread_mutex_t*); diff --git a/libgo/runtime/thread.c b/libgo/runtime/thread.c index 459fc85c780..d43e224ffb2 100644 --- a/libgo/runtime/thread.c +++ b/libgo/runtime/thread.c @@ -90,27 +90,3 @@ runtime_minit(void) if(sigaltstack(&ss, nil) < 0) *(int *)0xf1 = 0xf1; } - -// Temporary functions, which will be removed when we stop using -// condition variables. - -void -runtime_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) -{ - int i; - - runtime_entersyscall(); - - i = pthread_cond_wait(cond, mutex); - if(i != 0) - runtime_throw("pthread_cond_wait"); - i = pthread_mutex_unlock(mutex); - if(i != 0) - runtime_throw("pthread_mutex_unlock"); - - runtime_exitsyscall(); - - i = pthread_mutex_lock(mutex); - if(i != 0) - runtime_throw("pthread_mutex_lock"); -} |