Remove closed function. Fix tuple receive in select.
From-SVN: r171440
This commit is contained in:
parent
e533b2a4c9
commit
fe052134f6
@ -6530,7 +6530,6 @@ class Builtin_call_expression : public Call_expression
|
||||
BUILTIN_APPEND,
|
||||
BUILTIN_CAP,
|
||||
BUILTIN_CLOSE,
|
||||
BUILTIN_CLOSED,
|
||||
BUILTIN_COMPLEX,
|
||||
BUILTIN_COPY,
|
||||
BUILTIN_IMAG,
|
||||
@ -6588,8 +6587,6 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
|
||||
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")
|
||||
@ -7185,9 +7182,6 @@ Builtin_call_expression::do_type()
|
||||
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);
|
||||
|
||||
@ -7451,7 +7445,6 @@ Builtin_call_expression::do_check_types(Gogo*)
|
||||
break;
|
||||
|
||||
case BUILTIN_CLOSE:
|
||||
case BUILTIN_CLOSED:
|
||||
if (this->check_one_arg())
|
||||
{
|
||||
if (this->one_arg()->type()->channel_type() == NULL)
|
||||
@ -7936,7 +7929,6 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
|
||||
}
|
||||
|
||||
case BUILTIN_CLOSE:
|
||||
case BUILTIN_CLOSED:
|
||||
{
|
||||
const Expression_list* args = this->args();
|
||||
gcc_assert(args != NULL && args->size() == 1);
|
||||
@ -7944,8 +7936,6 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
|
||||
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,
|
||||
@ -7955,18 +7945,6 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
case BUILTIN_SIZEOF:
|
||||
case BUILTIN_OFFSETOF:
|
||||
|
@ -173,15 +173,6 @@ Gogo::Gogo(int int_type_size, int pointer_size)
|
||||
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,
|
||||
@ -3506,12 +3497,15 @@ Variable::determine_type()
|
||||
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)
|
||||
|
@ -1717,6 +1717,7 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
|
||||
Statement* s = Statement::make_tuple_receive_assignment(val_var,
|
||||
received_var,
|
||||
receive->channel(),
|
||||
false,
|
||||
location);
|
||||
|
||||
if (!this->gogo_->in_global_scope())
|
||||
@ -3629,6 +3630,7 @@ Parse::tuple_assignment(Expression_list* lhs, Range_clause* p_range_clause)
|
||||
Expression* channel = receive->channel();
|
||||
Statement* s = Statement::make_tuple_receive_assignment(val, success,
|
||||
channel,
|
||||
false,
|
||||
location);
|
||||
this->gogo_->add_statement(s);
|
||||
}
|
||||
|
@ -1148,10 +1148,10 @@ class Tuple_receive_assignment_statement : public Statement
|
||||
{
|
||||
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:
|
||||
@ -1176,6 +1176,8 @@ class Tuple_receive_assignment_statement : public Statement
|
||||
Expression* closed_;
|
||||
// The channel on which we receive the value.
|
||||
Expression* channel_;
|
||||
// Whether this is for a select statement.
|
||||
bool for_select_;
|
||||
};
|
||||
|
||||
// Traversal.
|
||||
@ -1228,6 +1230,7 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
|
||||
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));
|
||||
@ -1239,12 +1242,22 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
|
||||
|
||||
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);
|
||||
@ -1272,10 +1285,11 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
|
||||
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
|
||||
@ -4151,7 +4165,7 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
|
||||
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)
|
||||
@ -4165,8 +4179,14 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
|
||||
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
|
||||
{
|
||||
@ -5281,7 +5301,7 @@ For_range_statement::lower_range_map(Gogo* gogo,
|
||||
// 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,
|
||||
@ -5299,12 +5319,11 @@ For_range_statement::lower_range_channel(Gogo* gogo,
|
||||
|
||||
// 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
|
||||
// }
|
||||
|
||||
@ -5315,26 +5334,30 @@ For_range_statement::lower_range_channel(Gogo* gogo,
|
||||
*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);
|
||||
|
||||
|
@ -160,10 +160,12 @@ class Statement
|
||||
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*
|
||||
|
@ -21,6 +21,8 @@ var iterations *int = flag.Int("n", 100000, "number of iterations")
|
||||
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 {
|
||||
@ -35,26 +37,18 @@ func sender(n int, c1, c2, c3, c4 chan<- int) {
|
||||
// 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")
|
||||
@ -70,15 +64,23 @@ func main() {
|
||||
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")
|
||||
}
|
||||
|
@ -22,21 +22,18 @@ func main() {
|
||||
|
||||
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
|
||||
|
@ -88,12 +88,16 @@ func main() {
|
||||
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")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -191,9 +195,30 @@ func main() {
|
||||
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:
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
// 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.
|
||||
@ -14,10 +14,11 @@ package main
|
||||
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
|
||||
}
|
||||
|
||||
@ -52,12 +53,23 @@ func (c XChan) Nbrecv() (int, bool) {
|
||||
panic("nbrecv")
|
||||
}
|
||||
|
||||
func (c XChan) Close() {
|
||||
close(c)
|
||||
func (c XChan) Recv2() (int, bool) {
|
||||
x, ok := <-c
|
||||
return x, ok
|
||||
}
|
||||
|
||||
func (c XChan) Closed() bool {
|
||||
return closed(c)
|
||||
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) Close() {
|
||||
close(c)
|
||||
}
|
||||
|
||||
func (c XChan) Impl() string {
|
||||
@ -101,12 +113,26 @@ func (c SChan) Nbrecv() (int, bool) {
|
||||
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 {
|
||||
@ -156,12 +182,28 @@ func (c SSChan) Nbrecv() (int, bool) {
|
||||
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 {
|
||||
@ -179,29 +221,23 @@ func shouldPanic(f func()) {
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
if x, ok := c.Recv2(); x != 0 || ok {
|
||||
println("test1: recv2 on closed:", x, ok, c.Impl())
|
||||
}
|
||||
|
||||
// should now be closed.
|
||||
if !c.Closed() {
|
||||
println("test1: not closed after recv zero", 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())
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,11 +257,6 @@ func test1(c Chan) {
|
||||
}
|
||||
|
||||
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())
|
||||
@ -235,19 +266,31 @@ func testasync1(c Chan) {
|
||||
}
|
||||
|
||||
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)
|
||||
@ -261,15 +304,27 @@ func closedasync() chan int {
|
||||
return c
|
||||
}
|
||||
|
||||
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()))
|
||||
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() {
|
||||
for _, mk := range mks {
|
||||
test1(mk(closedsync()))
|
||||
}
|
||||
|
||||
for _, testclosed := range testcloseds {
|
||||
for _, mk := range mks {
|
||||
testclosed(mk(closedasync()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,10 +43,6 @@ func main() {
|
||||
_, 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
|
||||
@ -57,8 +53,9 @@ func main() {
|
||||
_, 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"
|
||||
|
@ -358,7 +358,6 @@ runtime_files = \
|
||||
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 \
|
||||
|
@ -174,11 +174,11 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.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 \
|
||||
@ -219,7 +219,7 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.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 \
|
||||
@ -771,7 +771,6 @@ runtime_files = \
|
||||
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 \
|
||||
@ -2177,7 +2176,6 @@ distclean-compile:
|
||||
@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@
|
||||
@ -2383,13 +2381,6 @@ go-close.lo: runtime/go-close.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-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
|
||||
|
@ -10,7 +10,7 @@ typedef _Bool bool;
|
||||
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) {
|
||||
@ -31,3 +31,25 @@ func chanrecv2(c *chan, val *byte) (received bool) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -50,9 +50,6 @@ struct __go_channel
|
||||
_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;
|
||||
|
@ -1,34 +0,0 @@
|
||||
/* 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;
|
||||
}
|
@ -44,7 +44,6 @@ __go_new_channel (size_t element_size, size_t entries)
|
||||
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;
|
||||
|
@ -32,7 +32,6 @@ __go_receive_nonblocking_acquire (struct __go_channel *channel)
|
||||
? 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;
|
||||
}
|
||||
|
@ -124,7 +124,6 @@ __go_receive_acquire (struct __go_channel *channel, _Bool for_select)
|
||||
? 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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user