From patchwork Fri Sep 16 23:19:32 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 115064 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 0FF5EB70B1 for ; Sat, 17 Sep 2011 09:19:57 +1000 (EST) Received: (qmail 18288 invoked by alias); 16 Sep 2011 23:19:54 -0000 Received: (qmail 18279 invoked by uid 22791); 16 Sep 2011 23:19:53 -0000 X-SWARE-Spam-Status: No, hits=-2.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RP_MATCHES_RCVD, SARE_SUB_FOREVER, SPF_HELO_PASS, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (74.125.121.67) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 16 Sep 2011 23:19:38 +0000 Received: from hpaq13.eem.corp.google.com (hpaq13.eem.corp.google.com [172.25.149.13]) by smtp-out.google.com with ESMTP id p8GNJbZa019401 for ; Fri, 16 Sep 2011 16:19:37 -0700 Received: from pzd13 (pzd13.prod.google.com [10.243.17.205]) by hpaq13.eem.corp.google.com with ESMTP id p8GNGbJS031346 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for ; Fri, 16 Sep 2011 16:19:35 -0700 Received: by pzd13 with SMTP id 13so3237010pzd.2 for ; Fri, 16 Sep 2011 16:19:35 -0700 (PDT) Received: by 10.68.50.193 with SMTP id e1mr2592519pbo.450.1316215175140; Fri, 16 Sep 2011 16:19:35 -0700 (PDT) Received: by 10.68.50.193 with SMTP id e1mr2592515pbo.450.1316215175028; Fri, 16 Sep 2011 16:19:35 -0700 (PDT) Received: from coign.google.com ([2620:0:1000:2301:21c:25ff:fe14:8d86]) by mx.google.com with ESMTPS id i3sm37342249pbg.10.2011.09.16.16.19.33 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 16 Sep 2011 16:19:34 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: Go patch committed: send/recieve on nil channel blocks forever Date: Fri, 16 Sep 2011 16:19:32 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org 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 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: