diff mbox

Go patch committed: send/recieve on nil channel blocks forever

Message ID mcrfwjwvzwb.fsf@coign.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor Sept. 16, 2011, 11:19 p.m. UTC
The Go language was clarified so that a send/receive on a nil channel
blocks forever, which makes nil channels not very useful but consistent
with select.  This patch implements that.  Bootstrapped and ran Go
testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

Index: libgo/runtime/go-reflect-chan.c
===================================================================
--- libgo/runtime/go-reflect-chan.c	(revision 178910)
+++ libgo/runtime/go-reflect-chan.c	(working copy)
@@ -45,18 +45,13 @@  chansend (struct __go_channel_type *ct, 
   void *pv;
 
   __go_assert (ct->__common.__code == GO_CHAN);
-  __go_assert (__go_type_descriptors_equal (ct->__element_type,
-					    channel->element_type));
 
-  if (channel == NULL)
-    __go_panic_msg ("send to nil channel");
-
-  if (__go_is_pointer_type (channel->element_type))
+  if (__go_is_pointer_type (ct->__element_type))
     pv = &val_i;
   else
     pv = (void *) val_i;
 
-  element_size = channel->element_type->__size;
+  element_size = ct->__element_type->__size;
   if (element_size <= sizeof (uint64_t))
     {
       union
@@ -112,12 +107,10 @@  chanrecv (struct __go_channel_type *ct, 
   struct chanrecv_ret ret;
 
   __go_assert (ct->__common.__code == GO_CHAN);
-  __go_assert (__go_type_descriptors_equal (ct->__element_type,
-					    channel->element_type));
 
-  element_size = channel->element_type->__size;
+  element_size = ct->__element_type->__size;
 
-  if (__go_is_pointer_type (channel->element_type))
+  if (__go_is_pointer_type (ct->__element_type))
     pv = &ret.val;
   else
     {
Index: libgo/runtime/channel.h
===================================================================
--- libgo/runtime/channel.h	(revision 178784)
+++ libgo/runtime/channel.h	(working copy)
@@ -147,3 +147,6 @@  extern void __go_builtin_close (struct _
 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 *);
Index: libgo/runtime/go-send-big.c
===================================================================
--- libgo/runtime/go-send-big.c	(revision 178784)
+++ libgo/runtime/go-send-big.c	(working copy)
@@ -17,7 +17,10 @@  __go_send_big (struct __go_channel* chan
   size_t offset;
 
   if (channel == NULL)
-    __go_panic_msg ("send to nil channel");
+    {
+      // 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);
Index: libgo/runtime/go-send-nb-small.c
===================================================================
--- libgo/runtime/go-send-nb-small.c	(revision 178784)
+++ libgo/runtime/go-send-nb-small.c	(working copy)
@@ -93,6 +93,9 @@  __go_send_nonblocking_acquire (struct __
 _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))
Index: libgo/runtime/chan.goc
===================================================================
--- libgo/runtime/chan.goc	(revision 178784)
+++ libgo/runtime/chan.goc	(working copy)
@@ -6,6 +6,8 @@  package runtime
 #include "config.h"
 #include "channel.h"
 
+#define nil NULL
+
 typedef _Bool bool;
 typedef unsigned char byte;
 typedef struct __go_channel chan;
@@ -13,7 +15,7 @@  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->element_type->__size;
+	uintptr_t element_size = c == nil ? 0 : c->element_type->__size;
 	if (element_size > 8) {
 		return __go_receive_big(c, val, 0);
 	} else {
Index: libgo/runtime/go-send-nb-big.c
===================================================================
--- libgo/runtime/go-send-nb-big.c	(revision 178784)
+++ libgo/runtime/go-send-nb-big.c	(working copy)
@@ -15,6 +15,9 @@  __go_send_nonblocking_big (struct __go_c
   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);
 
Index: libgo/runtime/go-send-small.c
===================================================================
--- libgo/runtime/go-send-small.c	(revision 178784)
+++ libgo/runtime/go-send-small.c	(working copy)
@@ -145,7 +145,10 @@  void
 __go_send_small (struct __go_channel *channel, uint64_t val, _Bool for_select)
 {
   if (channel == NULL)
-    __go_panic_msg ("send to nil channel");
+    {
+      // Block forever.
+      __go_select (0, 0, NULL, NULL);
+    }
 
   __go_assert (channel->element_type->__size <= sizeof (uint64_t));
 
Index: libgo/runtime/go-rec-big.c
===================================================================
--- libgo/runtime/go-rec-big.c	(revision 178784)
+++ libgo/runtime/go-rec-big.c	(working copy)
@@ -20,7 +20,10 @@  __go_receive_big (struct __go_channel *c
   size_t offset;
 
   if (channel == NULL)
-    __go_panic_msg ("receive from nil channel");
+    {
+      /* 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);
Index: libgo/runtime/go-rec-nb-small.c
===================================================================
--- libgo/runtime/go-rec-nb-small.c	(revision 178784)
+++ libgo/runtime/go-rec-nb-small.c	(working copy)
@@ -97,6 +97,14 @@  __go_receive_nonblocking_small (struct _
   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));
 
Index: libgo/runtime/go-rec-nb-big.c
===================================================================
--- libgo/runtime/go-rec-nb-big.c	(revision 178784)
+++ libgo/runtime/go-rec-nb-big.c	(working copy)
@@ -18,6 +18,13 @@  __go_receive_nonblocking_big (struct __g
   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);
 
Index: libgo/runtime/go-rec-small.c
===================================================================
--- libgo/runtime/go-rec-small.c	(revision 178784)
+++ libgo/runtime/go-rec-small.c	(working copy)
@@ -270,7 +270,10 @@  __go_receive_small_closed (struct __go_c
   uint64_t ret;
 
   if (channel == NULL)
-    __go_panic_msg ("receive from nil channel");
+    {
+      /* Block forever.  */
+      __go_select (0, 0, NULL, NULL);
+    }
 
   element_size = channel->element_type->__size;
   __go_assert (element_size <= sizeof (uint64_t));
Index: gcc/testsuite/go.test/test/chan/select3.go
===================================================================
--- gcc/testsuite/go.test/test/chan/select3.go	(revision 178784)
+++ gcc/testsuite/go.test/test/chan/select3.go	(working copy)
@@ -58,15 +58,15 @@  func main() {
 	closedch := make(chan int)
 	close(closedch)
 
-	// sending/receiving from a nil channel outside a select panics
-	testPanic(always, func() {
+	// sending/receiving from a nil channel blocks
+	testBlock(always, func() {
 		nilch <- 7
 	})
-	testPanic(always, func() {
+	testBlock(always, func() {
 		<-nilch
 	})
 
-	// sending/receiving from a nil channel inside a select never panics
+	// sending/receiving from a nil channel inside a select is never selected
 	testPanic(never, func() {
 		select {
 		case nilch <- 7: