BUILTIN_APPEND,
BUILTIN_CAP,
BUILTIN_CLOSE,
- BUILTIN_CLOSED,
BUILTIN_COMPLEX,
BUILTIN_COPY,
BUILTIN_IMAG,
this->code_ = BUILTIN_CAP;
else if (name == "close")
this->code_ = BUILTIN_CLOSE;
- else if (name == "closed")
- this->code_ = BUILTIN_CLOSED;
else if (name == "complex")
this->code_ = BUILTIN_COMPLEX;
else if (name == "copy")
case BUILTIN_PRINTLN:
return Type::make_void_type();
- case BUILTIN_CLOSED:
- return Type::lookup_bool_type();
-
case BUILTIN_RECOVER:
return Type::make_interface_type(NULL, BUILTINS_LOCATION);
break;
case BUILTIN_CLOSE:
- case BUILTIN_CLOSED:
if (this->check_one_arg())
{
if (this->one_arg()->type()->channel_type() == NULL)
}
case BUILTIN_CLOSE:
- case BUILTIN_CLOSED:
{
const Expression_list* args = this->args();
gcc_assert(args != NULL && args->size() == 1);
tree arg_tree = arg->get_tree(context);
if (arg_tree == error_mark_node)
return error_mark_node;
- if (this->code_ == BUILTIN_CLOSE)
- {
- static tree close_fndecl;
- return Gogo::call_builtin(&close_fndecl,
- location,
- "__go_builtin_close",
- 1,
- void_type_node,
- TREE_TYPE(arg_tree),
- arg_tree);
- }
- else
- {
- static tree closed_fndecl;
- return Gogo::call_builtin(&closed_fndecl,
- location,
- "__go_builtin_closed",
- 1,
- boolean_type_node,
- TREE_TYPE(arg_tree),
- arg_tree);
- }
+ static tree close_fndecl;
+ return Gogo::call_builtin(&close_fndecl,
+ location,
+ "__go_builtin_close",
+ 1,
+ void_type_node,
+ TREE_TYPE(arg_tree),
+ arg_tree);
}
case BUILTIN_SIZEOF:
close_type->set_is_builtin();
this->globals_->add_function_declaration("close", NULL, close_type, loc);
- Typed_identifier_list* closed_result = new Typed_identifier_list();
- closed_result->push_back(Typed_identifier("", Type::lookup_bool_type(),
- loc));
- Function_type* closed_type = Type::make_function_type(NULL, NULL,
- closed_result, loc);
- closed_type->set_is_varargs();
- closed_type->set_is_builtin();
- this->globals_->add_function_declaration("closed", NULL, closed_type, loc);
-
Typed_identifier_list* copy_result = new Typed_identifier_list();
copy_result->push_back(Typed_identifier("", int_type, loc));
Function_type* copy_type = Type::make_function_type(NULL, NULL,
true);
this->init_ = NULL;
}
+ else if (this->type_from_chan_element_)
+ {
+ Expression* init = this->init_;
+ init->determine_type_no_context();
+ this->type_ = this->type_from_chan_element(init, true);
+ this->init_ = NULL;
+ }
else
{
- // type_from_chan_element_ should have been cleared during
- // lowering.
- gcc_assert(!this->type_from_chan_element_);
-
Type_context context(this->type_, false);
this->init_->determine_type(&context);
if (this->type_ == NULL)
Statement* s = Statement::make_tuple_receive_assignment(val_var,
received_var,
receive->channel(),
+ false,
location);
if (!this->gogo_->in_global_scope())
Expression* channel = receive->channel();
Statement* s = Statement::make_tuple_receive_assignment(val, success,
channel,
+ false,
location);
this->gogo_->add_statement(s);
}
{
public:
Tuple_receive_assignment_statement(Expression* val, Expression* closed,
- Expression* channel,
+ Expression* channel, bool for_select,
source_location location)
: Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location),
- val_(val), closed_(closed), channel_(channel)
+ val_(val), closed_(closed), channel_(channel), for_select_(for_select)
{ }
protected:
Expression* closed_;
// The channel on which we receive the value.
Expression* channel_;
+ // Whether this is for a select statement.
+ bool for_select_;
};
// Traversal.
b->add_statement(closed_temp);
// func chanrecv2(c chan T, val *T) bool
+ // func chanrecv3(c chan T, val *T) bool (if for_select)
source_location bloc = BUILTINS_LOCATION;
Typed_identifier_list* param_types = new Typed_identifier_list();
param_types->push_back(Typed_identifier("c", channel_type, bloc));
Function_type* fntype = Type::make_function_type(NULL, param_types,
ret_types, bloc);
- Named_object* chanrecv2 =
- Named_object::make_function_declaration("chanrecv2", NULL, fntype, bloc);
- chanrecv2->func_declaration_value()->set_asm_name("runtime.chanrecv2");
+ Named_object* chanrecv;
+ if (!this->for_select_)
+ {
+ chanrecv = Named_object::make_function_declaration("chanrecv2", NULL,
+ fntype, bloc);
+ chanrecv->func_declaration_value()->set_asm_name("runtime.chanrecv2");
+ }
+ else
+ {
+ chanrecv = Named_object::make_function_declaration("chanrecv3", NULL,
+ fntype, bloc);
+ chanrecv->func_declaration_value()->set_asm_name("runtime.chanrecv3");
+ }
- // closed_temp = chanrecv2(channel, &val_temp)
- Expression* func = Expression::make_func_reference(chanrecv2, NULL, loc);
+ // closed_temp = chanrecv[23](channel, &val_temp)
+ Expression* func = Expression::make_func_reference(chanrecv, NULL, loc);
Expression_list* params = new Expression_list();
params->push_back(this->channel_);
Expression* ref = Expression::make_temporary_reference(val_temp, loc);
Statement*
Statement::make_tuple_receive_assignment(Expression* val, Expression* closed,
Expression* channel,
+ bool for_select,
source_location location)
{
return new Tuple_receive_assignment_statement(val, closed, channel,
- location);
+ for_select, location);
}
// An assignment to a pair of values from a type guard. This is a
this->val_ = Expression::make_sink(loc);
Statement* s = Statement::make_tuple_receive_assignment(this->val_,
this->closed_,
- ref, loc);
+ ref, true, loc);
init->add_statement(s);
}
else if (this->closedvar_ != NULL)
Expression* closed = Expression::make_var_reference(this->closedvar_,
loc);
Statement* s = Statement::make_tuple_receive_assignment(val, closed, ref,
- loc);
- init->add_statement(s);
+ true, loc);
+ // We have to put S in STATEMENTS_, because that is where the
+ // variables are declared.
+ gcc_assert(this->statements_ != NULL);
+ this->statements_->add_statement_at_front(s);
+ // We have to lower STATEMENTS_ again, to lower the tuple
+ // receive assignment we just added.
+ gogo->lower_block(function, this->statements_);
}
else
{
// Lower a for range over a channel.
void
-For_range_statement::lower_range_channel(Gogo* gogo,
+For_range_statement::lower_range_channel(Gogo*,
Block*,
Block* body_block,
Named_object* range_object,
// The loop we generate:
// for {
- // index_temp = <-range
- // if closed(range) {
+ // index_temp, ok_temp = <-range
+ // if !ok_temp {
// break
// }
// index = index_temp
- // value = value_temp
// original body
// }
*ppost = NULL;
// Set *PITER_INIT to
- // index_temp = <-range
- // if closed(range) {
+ // index_temp, ok_temp = <-range
+ // if !ok_temp {
// break
// }
Block* iter_init = new Block(body_block, loc);
- Expression* ref = this->make_range_ref(range_object, range_temp, loc);
- Expression* cond = this->call_builtin(gogo, "closed", ref, loc);
+ Temporary_statement* ok_temp =
+ Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
+ iter_init->add_statement(ok_temp);
- ref = this->make_range_ref(range_object, range_temp, loc);
- Expression* recv = Expression::make_receive(ref, loc);
- ref = Expression::make_temporary_reference(index_temp, loc);
- Statement* s = Statement::make_assignment(ref, recv, loc);
+ Expression* cref = this->make_range_ref(range_object, range_temp, loc);
+ Expression* iref = Expression::make_temporary_reference(index_temp, loc);
+ Expression* oref = Expression::make_temporary_reference(ok_temp, loc);
+ Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
+ false, loc);
iter_init->add_statement(s);
Block* then_block = new Block(iter_init, loc);
s = Statement::make_break_statement(this->break_label(), loc);
then_block->add_statement(s);
+ oref = Expression::make_temporary_reference(ok_temp, loc);
+ Expression* cond = Expression::make_unary(OPERATOR_NOT, oref, loc);
s = Statement::make_if_statement(cond, then_block, NULL, loc);
iter_init->add_statement(s);
Expression* should_set, source_location);
// Make an assignment from a nonblocking receive to a pair of
- // variables.
+ // variables. FOR_SELECT is true is this is being created for a
+ // case x, ok := <-c in a select statement.
static Statement*
make_tuple_receive_assignment(Expression* val, Expression* closed,
- Expression* channel, source_location);
+ Expression* channel, bool for_select,
+ source_location);
// Make an assignment from a type guard to a pair of variables.
static Statement*
func sender(n int, c1, c2, c3, c4 chan<- int) {
defer close(c1)
defer close(c2)
+ defer close(c3)
+ defer close(c4)
for i := 0; i < n; i++ {
select {
// mux receives the values from sender and forwards them onto another channel.
// It would be simplier to just have sender's four cases all be the same
// channel, but this doesn't actually trigger the bug.
-func mux(out chan<- int, in <-chan int) {
- for {
- v := <-in
- if closed(in) {
- close(out)
- break
- }
+func mux(out chan<- int, in <-chan int, done chan<- bool) {
+ for v := range in {
out <- v
}
+ done <- true
}
// recver gets a steam of values from the four mux's and checks for duplicates.
func recver(in <-chan int) {
seen := make(map[int]bool)
- for {
- v := <-in
- if closed(in) {
- break
- }
+ for v := range in {
if _, ok := seen[v]; ok {
println("got duplicate value: ", v)
panic("fail")
c2 := make(chan int)
c3 := make(chan int)
c4 := make(chan int)
+ done := make(chan bool)
cmux := make(chan int)
go sender(*iterations, c1, c2, c3, c4)
- go mux(cmux, c1)
- go mux(cmux, c2)
- go mux(cmux, c3)
- go mux(cmux, c4)
+ go mux(cmux, c1, done)
+ go mux(cmux, c2, done)
+ go mux(cmux, c3, done)
+ go mux(cmux, c4, done)
+ go func() {
+ <-done
+ <-done
+ <-done
+ <-done
+ close(cmux)
+ }()
// We keep the recver because it might catch more bugs in the future.
// However, the result of the bug linked to at the top is that we'll
- // end up panicing with: "throw: bad g->status in ready".
+ // end up panicking with: "throw: bad g->status in ready".
recver(cmux)
print("PASS\n")
}
c <- 0 // ok
<-c // ok
- //TODO(rsc): uncomment when this syntax is valid for receive+check closed
- // x, ok := <-c // ok
- // _, _ = x, ok
+ x, ok := <-c // ok
+ _, _ = x, ok
cr <- 0 // ERROR "send"
<-cr // ok
- //TODO(rsc): uncomment when this syntax is valid for receive+check closed
- // x, ok = <-cr // ok
- // _, _ = x, ok
+ x, ok = <-cr // ok
+ _, _ = x, ok
cs <- 0 // ok
<-cs // ERROR "receive"
- ////TODO(rsc): uncomment when this syntax is valid for receive+check closed
- //// x, ok = <-cs // ERROR "receive"
- //// _, _ = x, ok
+ x, ok = <-cs // ERROR "receive"
+ _, _ = x, ok
select {
case c <- 0: // ok
ch <- 7
})
- // receiving (a small number of times) from a closed channel never blocks
+ // receiving from a closed channel never blocks
testBlock(never, func() {
for i := 0; i < 10; i++ {
if <-closedch != 0 {
panic("expected zero value when reading from closed channel")
}
+ if x, ok := <-closedch; x != 0 || ok {
+ println("closedch:", x, ok)
+ panic("expected 0, false from closed channel")
+ }
}
})
case <-closedch:
}
})
+ testBlock(never, func() {
+ select {
+ case x := <-closedch:
+ _ = x
+ }
+ })
+ testBlock(never, func() {
+ select {
+ case x, ok := <-closedch:
+ _, _ = x, ok
+ }
+ })
testPanic(always, func() {
select {
case closedch <- 7:
}
})
+
+ // select should not get confused if it sees itself
+ testBlock(always, func() {
+ c := make(chan int)
+ select {
+ case c <- 1:
+ case <-c:
+ }
+ })
}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Test close(c), closed(c).
+// Test close(c), receive of closed channel.
//
// TODO(rsc): Doesn't check behavior of close(c) when there
// are blocked senders/receivers.
type Chan interface {
Send(int)
Nbsend(int) bool
- Recv() int
+ Recv() (int)
Nbrecv() (int, bool)
+ Recv2() (int, bool)
+ Nbrecv2() (int, bool, bool)
Close()
- Closed() bool
Impl() string
}
panic("nbrecv")
}
-func (c XChan) Close() {
- close(c)
+func (c XChan) Recv2() (int, bool) {
+ x, ok := <-c
+ return x, ok
+}
+
+func (c XChan) Nbrecv2() (int, bool, bool) {
+ select {
+ case x, ok := <-c:
+ return x, ok, true
+ default:
+ return 0, false, false
+ }
+ panic("nbrecv2")
}
-func (c XChan) Closed() bool {
- return closed(c)
+func (c XChan) Close() {
+ close(c)
}
func (c XChan) Impl() string {
panic("nbrecv")
}
-func (c SChan) Close() {
- close(c)
+func (c SChan) Recv2() (int, bool) {
+ select {
+ case x, ok := <-c:
+ return x, ok
+ }
+ panic("recv")
}
-func (c SChan) Closed() bool {
- return closed(c)
+func (c SChan) Nbrecv2() (int, bool, bool) {
+ select {
+ default:
+ return 0, false, false
+ case x, ok := <-c:
+ return x, ok, true
+ }
+ panic("nbrecv")
+}
+
+func (c SChan) Close() {
+ close(c)
}
func (c SChan) Impl() string {
panic("nbrecv")
}
-func (c SSChan) Close() {
- close(c)
+func (c SSChan) Recv2() (int, bool) {
+ select {
+ case <-dummy:
+ case x, ok := <-c:
+ return x, ok
+ }
+ panic("recv")
}
-func (c SSChan) Closed() bool {
- return closed(c)
+func (c SSChan) Nbrecv2() (int, bool, bool) {
+ select {
+ case <-dummy:
+ default:
+ return 0, false, false
+ case x, ok := <-c:
+ return x, ok, true
+ }
+ panic("nbrecv")
+}
+
+func (c SSChan) Close() {
+ close(c)
}
func (c SSChan) Impl() string {
}
func test1(c Chan) {
- // not closed until the close signal (a zero value) has been received.
- if c.Closed() {
- println("test1: Closed before Recv zero:", c.Impl())
- }
-
for i := 0; i < 3; i++ {
// recv a close signal (a zero value)
if x := c.Recv(); x != 0 {
- println("test1: recv on closed got non-zero:", x, c.Impl())
+ println("test1: recv on closed:", x, c.Impl())
}
-
- // should now be closed.
- if !c.Closed() {
- println("test1: not closed after recv zero", c.Impl())
+ if x, ok := c.Recv2(); x != 0 || ok {
+ println("test1: recv2 on closed:", x, ok, c.Impl())
}
- // should work with ,ok: received a value without blocking, so ok == true.
- x, ok := c.Nbrecv()
- if !ok {
- println("test1: recv on closed got not ok", c.Impl())
+ // should work with select: received a value without blocking, so selected == true.
+ x, selected := c.Nbrecv()
+ if x != 0 || !selected {
+ println("test1: recv on closed nb:", x, selected, c.Impl())
}
- if x != 0 {
- println("test1: recv ,ok on closed got non-zero:", x, c.Impl())
+ x, ok, selected := c.Nbrecv2()
+ if x != 0 || ok || !selected {
+ println("test1: recv2 on closed nb:", x, ok, selected, c.Impl())
}
}
}
func testasync1(c Chan) {
- // not closed until the close signal (a zero value) has been received.
- if c.Closed() {
- println("testasync1: Closed before Recv zero:", c.Impl())
- }
-
// should be able to get the last value via Recv
if x := c.Recv(); x != 1 {
println("testasync1: Recv did not get 1:", x, c.Impl())
}
func testasync2(c Chan) {
- // not closed until the close signal (a zero value) has been received.
- if c.Closed() {
- println("testasync2: Closed before Recv zero:", c.Impl())
+ // should be able to get the last value via Recv2
+ if x, ok := c.Recv2(); x != 1 || !ok {
+ println("testasync1: Recv did not get 1, true:", x, ok, c.Impl())
}
+ test1(c)
+}
+
+func testasync3(c Chan) {
// should be able to get the last value via Nbrecv
- if x, ok := c.Nbrecv(); !ok || x != 1 {
- println("testasync2: Nbrecv did not get 1, true:", x, ok, c.Impl())
+ if x, selected := c.Nbrecv(); x != 1 || !selected {
+ println("testasync2: Nbrecv did not get 1, true:", x, selected, c.Impl())
}
test1(c)
}
+func testasync4(c Chan) {
+ // should be able to get the last value via Nbrecv2
+ if x, ok, selected := c.Nbrecv2(); x != 1 || !ok || !selected {
+ println("testasync2: Nbrecv did not get 1, true, true:", x, ok, selected, c.Impl())
+ }
+ test1(c)
+}
+
func closedsync() chan int {
c := make(chan int)
close(c)
return c
}
+var mks = []func(chan int) Chan {
+ func(c chan int) Chan { return XChan(c) },
+ func(c chan int) Chan { return SChan(c) },
+ func(c chan int) Chan { return SSChan(c) },
+}
+
+var testcloseds = []func(Chan) {
+ testasync1,
+ testasync2,
+ testasync3,
+ testasync4,
+}
+
func main() {
- test1(XChan(closedsync()))
- test1(SChan(closedsync()))
- test1(SSChan(closedsync()))
-
- testasync1(XChan(closedasync()))
- testasync1(SChan(closedasync()))
- testasync1(SSChan(closedasync()))
- testasync2(XChan(closedasync()))
- testasync2(SChan(closedasync()))
- testasync2(SSChan(closedasync()))
+ for _, mk := range mks {
+ test1(mk(closedsync()))
+ }
+
+ for _, testclosed := range testcloseds {
+ for _, mk := range mks {
+ testclosed(mk(closedasync()))
+ }
+ }
}
_, b = m[2] // ERROR "cannot .* bool.*type Bool"
m[2] = 1, b // ERROR "cannot use.*type Bool.*as type bool"
- ////TODO(rsc): uncomment when this syntax is valid for receive+check closed
- //// _, b = <-c // ERROR "cannot .* bool.*type Bool"
- //// _ = b
-
var inter interface{}
_, b = inter.(Map) // ERROR "cannot .* bool.*type Bool"
_ = b
_, b = minter.(Map) // ERROR "cannot .* bool.*type Bool"
_ = b
- asBool(closed(c)) // ERROR "cannot use.*type bool.*as type Bool"
- b = closed(c) // ERROR "cannot use.*type bool.*type Bool"
+ _, bb := <-c
+ asBool(bb) // ERROR "cannot use.*type bool.*as type Bool"
+ _, b = <-c // ERROR "cannot .* bool.*type Bool"
_ = b
asString(String(slice)) // ERROR "cannot .*type Slice.*type String"
runtime/go-chan-len.c \
runtime/go-check-interface.c \
runtime/go-close.c \
- runtime/go-closed.c \
runtime/go-construct-map.c \
runtime/go-convert-interface.c \
runtime/go-copy.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-closed.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 runtime/go-eface-val-compare.c \
- runtime/go-getgoroot.c runtime/go-go.c runtime/go-gomaxprocs.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 \
+ runtime/go-eface-val-compare.c runtime/go-getgoroot.c \
+ runtime/go-go.c runtime/go-gomaxprocs.c \
runtime/go-int-array-to-string.c runtime/go-int-to-string.c \
runtime/go-interface-compare.c \
runtime/go-interface-eface-compare.c \
am__objects_3 = 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-closed.lo \
+ go-chan-len.lo go-check-interface.lo go-close.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 go-go.lo \
runtime/go-chan-len.c \
runtime/go-check-interface.c \
runtime/go-close.c \
- runtime/go-closed.c \
runtime/go-construct-map.c \
runtime/go-convert-interface.c \
runtime/go-copy.c \
@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-closed.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@
@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-closed.lo: runtime/go-closed.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-closed.lo -MD -MP -MF $(DEPDIR)/go-closed.Tpo -c -o go-closed.lo `test -f 'runtime/go-closed.c' || echo '$(srcdir)/'`runtime/go-closed.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-closed.Tpo $(DEPDIR)/go-closed.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-closed.c' object='go-closed.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-closed.lo `test -f 'runtime/go-closed.c' || echo '$(srcdir)/'`runtime/go-closed.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
typedef unsigned char byte;
typedef struct __go_channel chan;
-/* Do a nonblocking channel receive. */
+/* Do a channel receive with closed status. */
func chanrecv2(c *chan, val *byte) (received bool) {
if (c->element_size > 8) {
return received;
}
}
+
+/* Do a channel receive with closed status for a select statement. */
+
+func chanrecv3(c *chan, val *byte) (received bool) {
+ if (c->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, c->element_size);
+#else
+ __builtin_memcpy(val, u.b + 8 - c->element_size,
+ c->element_size);
+#endif
+ return received;
+ }
+}
_Bool selected_for_receive;
/* True if this channel has been closed. */
_Bool is_closed;
- /* True if at least one null value has been read from a closed
- channel. */
- _Bool saw_close;
/* The list of select statements waiting to send on a synchronous
channel. */
struct __go_channel_select *select_send_queue;
+++ /dev/null
-/* go-closed.c -- the builtin closed 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 "go-assert.h"
-#include "channel.h"
-
-/* Return whether a channel is closed. We only return true after at
- least one nil value has been read from the channel. */
-
-_Bool
-__go_builtin_closed (struct __go_channel *channel)
-{
- int i;
- _Bool ret;
-
- i = pthread_mutex_lock (&channel->lock);
- __go_assert (i == 0);
-
- while (channel->selected_for_receive)
- {
- i = pthread_cond_wait (&channel->cond, &channel->lock);
- __go_assert (i == 0);
- }
-
- ret = channel->saw_close;
-
- i = pthread_mutex_unlock (&channel->lock);
- __go_assert (i == 0);
-
- return ret;
-}
ret->selected_for_send = 0;
ret->selected_for_receive = 0;
ret->is_closed = 0;
- ret->saw_close = 0;
ret->select_send_queue = NULL;
ret->select_receive_queue = NULL;
ret->select_mutex = NULL;
? channel->next_store == 0
: channel->next_fetch == channel->next_store))
{
- channel->saw_close = 1;
__go_unlock_and_notify_selects (channel);
return RECEIVE_NONBLOCKING_ACQUIRE_CLOSED;
}
? channel->next_store == 0
: channel->next_fetch == channel->next_store))
{
- channel->saw_close = 1;
channel->selected_for_receive = 0;
__go_unlock_and_notify_selects (channel);
return 0;