aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/go/gofrontend/expressions.cc9
-rw-r--r--gcc/go/gofrontend/expressions.h9
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc27
-rw-r--r--gcc/go/gofrontend/gogo.h7
-rw-r--r--gcc/go/gofrontend/parse.cc2
-rw-r--r--gcc/go/gofrontend/runtime.cc16
-rw-r--r--gcc/go/gofrontend/runtime.def50
-rw-r--r--gcc/go/gofrontend/runtime.h5
-rw-r--r--gcc/go/gofrontend/statements.cc544
-rw-r--r--gcc/go/gofrontend/statements.h83
-rw-r--r--libgo/Makefile.am16
-rw-r--r--libgo/Makefile.in182
-rw-r--r--libgo/runtime/chan.c1248
-rw-r--r--libgo/runtime/chan.goc57
-rw-r--r--libgo/runtime/channel.h152
-rw-r--r--libgo/runtime/go-chan-cap.c41
-rw-r--r--libgo/runtime/go-chan-len.c41
-rw-r--r--libgo/runtime/go-close.c42
-rw-r--r--libgo/runtime/go-new-channel.c70
-rw-r--r--libgo/runtime/go-rec-big.c43
-rw-r--r--libgo/runtime/go-rec-nb-big.c46
-rw-r--r--libgo/runtime/go-rec-nb-small.c123
-rw-r--r--libgo/runtime/go-rec-small.c304
-rw-r--r--libgo/runtime/go-reflect-chan.c200
-rw-r--r--libgo/runtime/go-select.c758
-rw-r--r--libgo/runtime/go-send-big.c34
-rw-r--r--libgo/runtime/go-send-nb-big.c33
-rw-r--r--libgo/runtime/go-send-nb-small.c107
-rw-r--r--libgo/runtime/go-send-small.c159
-rw-r--r--libgo/runtime/runtime.h8
30 files changed, 1621 insertions, 2795 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index a2cf33e..a80c823 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -13493,12 +13493,18 @@ Receive_expression::do_check_types(Gogo*)
tree
Receive_expression::do_get_tree(Translate_context* context)
{
+ Location loc = this->location();
+
Channel_type* channel_type = this->channel_->type()->channel_type();
if (channel_type == NULL)
{
go_assert(this->channel_->type()->is_error());
return error_mark_node;
}
+
+ Expression* td = Expression::make_type_descriptor(channel_type, loc);
+ tree td_tree = td->get_tree(context);
+
Type* element_type = channel_type->element_type();
Btype* element_type_btype = element_type->get_backend(context->gogo());
tree element_type_tree = type_to_tree(element_type_btype);
@@ -13507,8 +13513,7 @@ Receive_expression::do_get_tree(Translate_context* context)
if (element_type_tree == error_mark_node || channel == error_mark_node)
return error_mark_node;
- return Gogo::receive_from_channel(element_type_tree, channel,
- this->for_select_, this->location());
+ return Gogo::receive_from_channel(element_type_tree, td_tree, channel, loc);
}
// Dump ast representation for a receive expression.
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 74d1281..6da507b 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -1947,7 +1947,7 @@ class Receive_expression : public Expression
public:
Receive_expression(Expression* channel, Location location)
: Expression(EXPRESSION_RECEIVE, location),
- channel_(channel), for_select_(false)
+ channel_(channel)
{ }
// Return the channel.
@@ -1955,11 +1955,6 @@ class Receive_expression : public Expression
channel()
{ return this->channel_; }
- // Note that this is for a select statement.
- void
- set_for_select()
- { this->for_select_ = true; }
-
protected:
int
do_traverse(Traverse* traverse)
@@ -1998,8 +1993,6 @@ class Receive_expression : public Expression
private:
// The channel from which we are receiving.
Expression* channel_;
- // Whether this is for a select statement.
- bool for_select_;
};
#endif // !defined(GO_EXPRESSIONS_H)
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
index 0e77f5d..dd66a7f 100644
--- a/gcc/go/gofrontend/gogo-tree.cc
+++ b/gcc/go/gofrontend/gogo-tree.cc
@@ -2201,13 +2201,12 @@ Gogo::runtime_error(int code, Location location)
}
// Return a tree for receiving a value of type TYPE_TREE on CHANNEL.
-// This does a blocking receive and returns the value read from the
-// channel. If FOR_SELECT is true, this is being done because it was
-// chosen in a select statement.
+// TYPE_DESCRIPTOR_TREE is the channel's type descriptor. This does a
+// blocking receive and returns the value read from the channel.
tree
-Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select,
- Location location)
+Gogo::receive_from_channel(tree type_tree, tree type_descriptor_tree,
+ tree channel, Location location)
{
if (type_tree == error_mark_node || channel == error_mark_node)
return error_mark_node;
@@ -2222,12 +2221,10 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select,
"__go_receive_small",
2,
uint64_type_node,
+ TREE_TYPE(type_descriptor_tree),
+ type_descriptor_tree,
ptr_type_node,
- channel,
- boolean_type_node,
- (for_select
- ? boolean_true_node
- : boolean_false_node));
+ channel);
if (call == error_mark_node)
return error_mark_node;
// This can panic if there are too many operations on a closed
@@ -2253,15 +2250,13 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select,
location,
"__go_receive_big",
3,
- boolean_type_node,
+ void_type_node,
+ TREE_TYPE(type_descriptor_tree),
+ type_descriptor_tree,
ptr_type_node,
channel,
ptr_type_node,
- tmpaddr,
- boolean_type_node,
- (for_select
- ? boolean_true_node
- : boolean_false_node));
+ tmpaddr);
if (call == error_mark_node)
return error_mark_node;
// This can panic if there are too many operations on a closed
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 9d3b37a..6efce18 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -527,14 +527,9 @@ class Gogo
// Receive a value from a channel.
static tree
- receive_from_channel(tree type_tree, tree channel, bool for_select,
+ receive_from_channel(tree type_tree, tree type_descriptor_tree, tree channel,
Location);
- // Return a tree for receiving an integer on a channel.
- static tree
- receive_as_64bit_integer(tree type, tree channel, bool blocking,
- bool for_select);
-
// Make a trampoline which calls FNADDR passing CLOSURE.
tree
make_trampoline(tree fnaddr, tree closure, Location);
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index 6228868..37a9782 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -1780,7 +1780,6 @@ 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())
@@ -3769,7 +3768,6 @@ 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);
}
diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc
index 42f1e78..bffefbb 100644
--- a/gcc/go/gofrontend/runtime.cc
+++ b/gcc/go/gofrontend/runtime.cc
@@ -54,8 +54,6 @@ enum Runtime_function_type
RFT_MAPITER,
// Go type chan any, C type struct __go_channel *.
RFT_CHAN,
- // Go type *chan any, C type struct __go_channel **.
- RFT_CHANPTR,
// Go type non-empty interface, C type struct __go_interface.
RFT_IFACE,
// Go type interface{}, C type struct __go_empty_interface.
@@ -148,10 +146,6 @@ runtime_function_type(Runtime_function_type bft)
t = Type::make_channel_type(true, true, Type::make_void_type());
break;
- case RFT_CHANPTR:
- t = Type::make_pointer_type(runtime_function_type(RFT_CHAN));
- break;
-
case RFT_IFACE:
{
Typed_identifier_list* methods = new Typed_identifier_list();
@@ -223,7 +217,6 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
case RFT_SLICE:
case RFT_MAP:
case RFT_CHAN:
- case RFT_CHANPTR:
case RFT_IFACE:
case RFT_EFACE:
return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc);
@@ -393,12 +386,3 @@ Runtime::map_iteration_type()
return Type::make_array_type(runtime_function_type(RFT_POINTER), iexpr);
}
-
-// Return the type used to pass a list of general channels to the
-// select runtime function.
-
-Type*
-Runtime::chanptr_type()
-{
- return runtime_function_type(RFT_CHANPTR);
-}
diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def
index d742e5b..fe842c9 100644
--- a/gcc/go/gofrontend/runtime.def
+++ b/gcc/go/gofrontend/runtime.def
@@ -121,31 +121,44 @@ DEF_GO_RUNTIME(CHAN_LEN, "__go_chan_len", P1(CHAN), R1(INT))
DEF_GO_RUNTIME(CHAN_CAP, "__go_chan_cap", P1(CHAN), R1(INT))
// Send a small value on a channel.
-DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(CHAN, UINT64, BOOL), R0())
-
-// Send a small value on a channel without blocking.
-DEF_GO_RUNTIME(SEND_NONBLOCKING_SMALL, "__go_send_nonblocking_small",
- P2(CHAN, UINT64), R1(BOOL))
+DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(TYPE, CHAN, UINT64), R0())
// Send a big value on a channel.
-DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(CHAN, POINTER, BOOL), R0())
-
-// Send a big value on a channel without blocking.
-DEF_GO_RUNTIME(SEND_NONBLOCKING_BIG, "__go_send_nonblocking_big",
- P2(CHAN, POINTER), R1(BOOL))
+DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(TYPE, CHAN, POINTER), R0())
// Receive a small value from a channel.
-DEF_GO_RUNTIME(RECEIVE_SMALL, "__go_receive_small", P2(CHAN, BOOL), R1(UINT64))
+DEF_GO_RUNTIME(RECEIVE_SMALL, "__go_receive_small", P2(TYPE, CHAN), R1(UINT64))
// Receive a big value from a channel.
-DEF_GO_RUNTIME(RECEIVE_BIG, "__go_receive_big", P3(CHAN, POINTER, BOOL),
- R1(BOOL))
+DEF_GO_RUNTIME(RECEIVE_BIG, "__go_receive_big", P3(TYPE, CHAN, POINTER), R0())
// Receive a value from a channel returning whether it is closed.
-DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P2(CHAN, POINTER), R1(BOOL))
+DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P3(TYPE, CHAN, POINTER),
+ R1(BOOL))
+
+
+// Start building a select statement.
+DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P1(INT), R1(POINTER))
-// Receive a value from a channel returning whether it is closed, for select.
-DEF_GO_RUNTIME(CHANRECV3, "runtime.chanrecv3", P2(CHAN, POINTER), R1(BOOL))
+// Add a default clause to a select statement.
+DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault", P2(POINTER, INT), R0())
+
+// Add a send clause to a select statement.
+DEF_GO_RUNTIME(SELECTSEND, "runtime.selectsend",
+ P4(POINTER, CHAN, POINTER, INT), R0())
+
+// Add a receive clause to a select statement, for a clause which does
+// not check whether the channel is closed.
+DEF_GO_RUNTIME(SELECTRECV, "runtime.selectrecv",
+ P4(POINTER, CHAN, POINTER, INT), R0())
+
+// Add a receive clause to a select statement, for a clause which does
+// check whether the channel is closed.
+DEF_GO_RUNTIME(SELECTRECV2, "runtime.selectrecv2",
+ P5(POINTER, CHAN, POINTER, BOOLPTR, INT), R0())
+
+// Run a select, returning the index of the selected clause.
+DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P1(POINTER), R1(INT))
// Panic.
@@ -213,11 +226,6 @@ DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0())
DEF_GO_RUNTIME(DEFER, "__go_defer", P3(BOOLPTR, FUNC_PTR, POINTER), R0())
-// Run a select statement.
-DEF_GO_RUNTIME(SELECT, "__go_select", P4(UINTPTR, BOOL, CHANPTR, BOOLPTR),
- R1(UINTPTR))
-
-
// Convert an empty interface to an empty interface, returning ok.
DEF_GO_RUNTIME(IFACEE2E2, "runtime.ifaceE2E2", P1(EFACE), R2(EFACE, BOOL))
diff --git a/gcc/go/gofrontend/runtime.h b/gcc/go/gofrontend/runtime.h
index 3cd4034..be5dcbe 100644
--- a/gcc/go/gofrontend/runtime.h
+++ b/gcc/go/gofrontend/runtime.h
@@ -43,11 +43,6 @@ class Runtime
static Type*
map_iteration_type();
- // Return the type used to pass a list of general channels to the
- // select runtime function.
- static Type*
- chanptr_type();
-
private:
static Named_object*
runtime_declaration(Function);
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 835a0cc..964b394 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -1329,10 +1329,9 @@ class Tuple_receive_assignment_statement : public Statement
{
public:
Tuple_receive_assignment_statement(Expression* val, Expression* closed,
- Expression* channel, bool for_select,
- Location location)
+ Expression* channel, Location location)
: Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location),
- val_(val), closed_(closed), channel_(channel), for_select_(for_select)
+ val_(val), closed_(closed), channel_(channel)
{ }
protected:
@@ -1360,8 +1359,6 @@ 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.
@@ -1414,14 +1411,14 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
b->add_statement(closed_temp);
- // closed_temp = chanrecv[23](channel, &val_temp)
+ // closed_temp = chanrecv2(type, channel, &val_temp)
+ Expression* td = Expression::make_type_descriptor(this->channel_->type(),
+ loc);
Temporary_reference_expression* ref =
Expression::make_temporary_reference(val_temp, loc);
Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
- Expression* call = Runtime::make_call((this->for_select_
- ? Runtime::CHANRECV3
- : Runtime::CHANRECV2),
- loc, 2, this->channel_, p2);
+ Expression* call = Runtime::make_call(Runtime::CHANRECV2,
+ loc, 3, td, this->channel_, p2);
ref = Expression::make_temporary_reference(closed_temp, loc);
ref->set_is_lvalue();
Statement* s = Statement::make_assignment(ref, call, loc);
@@ -1460,11 +1457,10 @@ Tuple_receive_assignment_statement::do_dump_statement(
Statement*
Statement::make_tuple_receive_assignment(Expression* val, Expression* closed,
Expression* channel,
- bool for_select,
Location location)
{
return new Tuple_receive_assignment_statement(val, closed, channel,
- for_select, location);
+ location);
}
// An assignment to a pair of values from a type guard. This is a
@@ -4391,9 +4387,11 @@ Send_statement::do_get_backend(Translate_context* context)
&& val->temporary_reference_expression() == NULL)
can_take_address = false;
+ Expression* td = Expression::make_type_descriptor(this->channel_->type(),
+ loc);
+
Runtime::Function code;
Bstatement* btemp = NULL;
- Expression* call;
if (is_small)
{
// Type is small enough to handle as uint64.
@@ -4421,8 +4419,7 @@ Send_statement::do_get_backend(Translate_context* context)
btemp = temp->get_backend(context);
}
- call = Runtime::make_call(code, loc, 3, this->channel_, val,
- Expression::make_boolean(this->for_select_, loc));
+ Expression* call = Runtime::make_call(code, loc, 3, td, this->channel_, val);
context->gogo()->lower_expression(context->function(), NULL, &call);
Bexpression* bcall = tree_to_expr(call->get_tree(context));
@@ -4490,134 +4487,178 @@ Select_clauses::Select_clause::traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
-// Lowering. Here we pull out the channel and the send values, to
-// enforce the order of evaluation. We also add explicit send and
-// receive statements to the clauses.
+// Lowering. We call a function to register this clause, and arrange
+// to set any variables in any receive clause.
void
Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
- Block* b)
+ Block* b, Temporary_statement* sel)
{
+ Location loc = this->location_;
+
+ Expression* selref = Expression::make_temporary_reference(sel, loc);
+
+ mpz_t ival;
+ mpz_init_set_ui(ival, this->index_);
+ Expression* index_expr = Expression::make_integer(&ival, NULL, loc);
+ mpz_clear(ival);
+
if (this->is_default_)
{
go_assert(this->channel_ == NULL && this->val_ == NULL);
+ this->lower_default(b, selref, index_expr);
this->is_lowered_ = true;
return;
}
- Location loc = this->location_;
-
// Evaluate the channel before the select statement.
Temporary_statement* channel_temp = Statement::make_temporary(NULL,
this->channel_,
loc);
b->add_statement(channel_temp);
- this->channel_ = Expression::make_temporary_reference(channel_temp, loc);
-
- // If this is a send clause, evaluate the value to send before the
- // select statement.
- Temporary_statement* val_temp = NULL;
- if (this->is_send_ && !this->val_->is_constant())
- {
- val_temp = Statement::make_temporary(NULL, this->val_, loc);
- b->add_statement(val_temp);
- }
+ Expression* chanref = Expression::make_temporary_reference(channel_temp,
+ loc);
- // Add the send or receive before the rest of the statements if any.
- Block *init = new Block(b, loc);
- Expression* ref = Expression::make_temporary_reference(channel_temp, loc);
if (this->is_send_)
- {
- Expression* ref2;
- if (val_temp == NULL)
- ref2 = this->val_;
- else
- ref2 = Expression::make_temporary_reference(val_temp, loc);
- Send_statement* send = Statement::make_send_statement(ref, ref2, loc);
- send->set_for_select();
- init->add_statement(send);
- }
- else if (this->closed_ != NULL && !this->closed_->is_sink_expression())
- {
- go_assert(this->var_ == NULL && this->closedvar_ == NULL);
- if (this->val_ == NULL)
- this->val_ = Expression::make_sink(loc);
- Statement* s = Statement::make_tuple_receive_assignment(this->val_,
- this->closed_,
- ref, true, loc);
- init->add_statement(s);
- }
- else if (this->closedvar_ != NULL)
- {
- go_assert(this->val_ == NULL);
- Expression* val;
- if (this->var_ == NULL)
- val = Expression::make_sink(loc);
- else
- val = Expression::make_var_reference(this->var_, loc);
- Expression* closed = Expression::make_var_reference(this->closedvar_,
- loc);
- Statement* s = Statement::make_tuple_receive_assignment(val, closed, ref,
- true, loc);
+ this->lower_send(b, selref, chanref, index_expr);
+ else
+ this->lower_recv(gogo, function, b, selref, chanref, index_expr);
- // We have to put S in STATEMENTS_, because that is where the
- // variables are declared.
+ // Now all references should be handled through the statements, not
+ // through here.
+ this->is_lowered_ = true;
+ this->val_ = NULL;
+ this->var_ = NULL;
+}
- go_assert(this->statements_ != NULL);
+// Lower a default clause in a select statement.
- // Skip the variable declaration statements themselves.
- size_t skip = 1;
- if (this->var_ != NULL)
- skip = 2;
+void
+Select_clauses::Select_clause::lower_default(Block* b, Expression* selref,
+ Expression* index_expr)
+{
+ Location loc = this->location_;
+ Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 2, selref,
+ index_expr);
+ b->add_statement(Statement::make_statement(call, true));
+}
- // Verify that we are only skipping variable declarations.
- size_t i = 0;
- for (Block::iterator p = this->statements_->begin();
- i < skip && p != this->statements_->end();
- ++p, ++i)
- go_assert((*p)->variable_declaration_statement() != NULL);
+// Lower a send clause in a select statement.
- this->statements_->insert_statement_before(skip, s);
+void
+Select_clauses::Select_clause::lower_send(Block* b, Expression* selref,
+ Expression* chanref,
+ Expression* index_expr)
+{
+ Location loc = this->location_;
- // We have to lower STATEMENTS_ again, to lower the tuple
- // receive assignment we just added.
- gogo->lower_block(function, this->statements_);
- }
+ Channel_type* ct = this->channel_->type()->channel_type();
+ if (ct == NULL)
+ return;
+
+ Type* valtype = ct->element_type();
+
+ // Note that copying the value to a temporary here means that we
+ // evaluate the send values in the required order.
+ Temporary_statement* val = Statement::make_temporary(valtype, this->val_,
+ loc);
+ b->add_statement(val);
+
+ Expression* valref = Expression::make_temporary_reference(val, loc);
+ Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
+
+ Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 4, selref,
+ chanref, valaddr, index_expr);
+ b->add_statement(Statement::make_statement(call, true));
+}
+
+// Lower a receive clause in a select statement.
+
+void
+Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
+ Block* b, Expression* selref,
+ Expression* chanref,
+ Expression* index_expr)
+{
+ Location loc = this->location_;
+
+ Channel_type* ct = this->channel_->type()->channel_type();
+ if (ct == NULL)
+ return;
+
+ Type* valtype = ct->element_type();
+ Temporary_statement* val = Statement::make_temporary(valtype, NULL, loc);
+ b->add_statement(val);
+
+ Expression* valref = Expression::make_temporary_reference(val, loc);
+ Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
+
+ Temporary_statement* closed_temp = NULL;
+
+ Expression* call;
+ if (this->closed_ == NULL && this->closedvar_ == NULL)
+ call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref, chanref,
+ valaddr, index_expr);
else
{
- Receive_expression* recv = Expression::make_receive(ref, loc);
- recv->set_for_select();
- if (this->val_ != NULL)
- {
- go_assert(this->var_ == NULL);
- init->add_statement(Statement::make_assignment(this->val_, recv,
- loc));
- }
- else if (this->var_ != NULL)
- {
- this->var_->var_value()->set_init(recv);
- this->var_->var_value()->clear_type_from_chan_element();
- }
- else
- {
- init->add_statement(Statement::make_statement(recv, true));
- }
+ closed_temp = Statement::make_temporary(Type::lookup_bool_type(), NULL,
+ loc);
+ b->add_statement(closed_temp);
+ Expression* cref = Expression::make_temporary_reference(closed_temp,
+ loc);
+ Expression* caddr = Expression::make_unary(OPERATOR_AND, cref, loc);
+ call = Runtime::make_call(Runtime::SELECTRECV2, loc, 5, selref, chanref,
+ valaddr, caddr, index_expr);
}
- // Lower any statements we just created.
- gogo->lower_block(function, init);
+ b->add_statement(Statement::make_statement(call, true));
- if (this->statements_ != NULL)
- init->add_statement(Statement::make_block_statement(this->statements_,
- loc));
+ // If the block of statements is executed, arrange for the received
+ // value to move from VAL to the place where the statements expect
+ // it.
- this->statements_ = init;
+ Block* init = NULL;
- // Now all references should be handled through the statements, not
- // through here.
- this->is_lowered_ = true;
- this->val_ = NULL;
- this->var_ = NULL;
+ if (this->var_ != NULL)
+ {
+ go_assert(this->val_ == NULL);
+ valref = Expression::make_temporary_reference(val, loc);
+ this->var_->var_value()->set_init(valref);
+ this->var_->var_value()->clear_type_from_chan_element();
+ }
+ else if (this->val_ != NULL && !this->val_->is_sink_expression())
+ {
+ init = new Block(b, loc);
+ valref = Expression::make_temporary_reference(val, loc);
+ init->add_statement(Statement::make_assignment(this->val_, valref, loc));
+ }
+
+ if (this->closedvar_ != NULL)
+ {
+ go_assert(this->closed_ == NULL);
+ Expression* cref = Expression::make_temporary_reference(closed_temp,
+ loc);
+ this->closedvar_->var_value()->set_init(cref);
+ }
+ else if (this->closed_ != NULL && !this->closed_->is_sink_expression())
+ {
+ if (init == NULL)
+ init = new Block(b, loc);
+ Expression* cref = Expression::make_temporary_reference(closed_temp,
+ loc);
+ init->add_statement(Statement::make_assignment(this->closed_, cref,
+ loc));
+ }
+
+ if (init != NULL)
+ {
+ gogo->lower_block(function, init);
+
+ if (this->statements_ != NULL)
+ init->add_statement(Statement::make_block_statement(this->statements_,
+ loc));
+ this->statements_ = init;
+ }
}
// Determine types.
@@ -4630,6 +4671,27 @@ Select_clauses::Select_clause::determine_types()
this->statements_->determine_types();
}
+// Check types.
+
+void
+Select_clauses::Select_clause::check_types()
+{
+ if (this->is_default_)
+ return;
+
+ Channel_type* ct = this->channel_->type()->channel_type();
+ if (ct == NULL)
+ {
+ error_at(this->channel_->location(), "expected channel");
+ return;
+ }
+
+ if (this->is_send_ && !ct->may_send())
+ error_at(this->location(), "invalid send on receive-only channel");
+ else if (!this->is_send_ && !ct->may_receive())
+ error_at(this->location(), "invalid receive on send-only channel");
+}
+
// Whether this clause may fall through to the statement which follows
// the overall select statement.
@@ -4717,12 +4779,13 @@ Select_clauses::traverse(Traverse* traverse)
// receive statements to the clauses.
void
-Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b)
+Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b,
+ Temporary_statement* sel)
{
for (Clauses::iterator p = this->clauses_.begin();
p != this->clauses_.end();
++p)
- p->lower(gogo, function, b);
+ p->lower(gogo, function, b, sel);
}
// Determine types.
@@ -4736,6 +4799,17 @@ Select_clauses::determine_types()
p->determine_types();
}
+// Check types.
+
+void
+Select_clauses::check_types()
+{
+ for (Clauses::iterator p = this->clauses_.begin();
+ p != this->clauses_.end();
+ ++p)
+ p->check_types();
+}
+
// Return whether these select clauses fall through to the statement
// following the overall select statement.
@@ -4750,179 +4824,55 @@ Select_clauses::may_fall_through() const
return false;
}
-// Convert to the backend representation. We build a call to
-// size_t __go_select(size_t count, _Bool has_default,
-// channel* channels, _Bool* is_send)
-//
-// There are COUNT entries in the CHANNELS and IS_SEND arrays. The
-// value in the IS_SEND array is true for send, false for receive.
-// __go_select returns an integer from 0 to COUNT, inclusive. A
-// return of 0 means that the default case should be run; this only
-// happens if HAS_DEFAULT is non-zero. Otherwise the number indicates
-// the case to run.
-
-// FIXME: This doesn't handle channels which send interface types
-// where the receiver has a static type which matches that interface.
+// Convert to the backend representation. We have already accumulated
+// all the select information. Now we call selectgo, which will
+// return the index of the clause to execute.
Bstatement*
Select_clauses::get_backend(Translate_context* context,
+ Temporary_statement* sel,
Unnamed_label *break_label,
Location location)
{
size_t count = this->clauses_.size();
+ std::vector<std::vector<Bexpression*> > cases(count);
+ std::vector<Bstatement*> clauses(count);
- Expression_list* chan_init = new Expression_list();
- chan_init->reserve(count);
-
- Expression_list* is_send_init = new Expression_list();
- is_send_init->reserve(count);
-
- Select_clause *default_clause = NULL;
-
- Type* runtime_chanptr_type = Runtime::chanptr_type();
- Type* runtime_chan_type = runtime_chanptr_type->points_to();
-
+ int i = 0;
for (Clauses::iterator p = this->clauses_.begin();
p != this->clauses_.end();
- ++p)
+ ++p, ++i)
{
- if (p->is_default())
- {
- default_clause = &*p;
- --count;
- continue;
- }
-
- if (p->channel()->type()->channel_type() == NULL)
- {
- // We should have given an error in the send or receive
- // statement we created via lowering.
- go_assert(saw_errors());
- return context->backend()->error_statement();
- }
-
- Expression* c = p->channel();
- c = Expression::make_unsafe_cast(runtime_chan_type, c, p->location());
- chan_init->push_back(c);
+ int index = p->index();
+ mpz_t ival;
+ mpz_init_set_ui(ival, index);
+ Expression* index_expr = Expression::make_integer(&ival, NULL, location);
+ mpz_clear(ival);
+ cases[i].push_back(tree_to_expr(index_expr->get_tree(context)));
- is_send_init->push_back(Expression::make_boolean(p->is_send(),
- p->location()));
- }
+ Bstatement* s = p->get_statements_backend(context);
+ Location gloc = (p->statements() == NULL
+ ? p->location()
+ : p->statements()->end_location());
+ Bstatement* g = break_label->get_goto(context, gloc);
- if (chan_init->empty())
- {
- go_assert(count == 0);
- Bstatement* s;
- Bstatement* ldef = break_label->get_definition(context);
- if (default_clause != NULL)
- {
- // There is a default clause and no cases. Just execute the
- // default clause.
- s = default_clause->get_statements_backend(context);
- }
- else
- {
- // There isn't even a default clause. In this case select
- // pauses forever. Call the runtime function with nils.
- mpz_t zval;
- mpz_init_set_ui(zval, 0);
- Expression* zero = Expression::make_integer(&zval, NULL, location);
- mpz_clear(zval);
- Expression* default_arg = Expression::make_boolean(false, location);
- Expression* nil1 = Expression::make_nil(location);
- Expression* nil2 = nil1->copy();
- Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
- zero, default_arg, nil1, nil2);
- context->gogo()->lower_expression(context->function(), NULL, &call);
- Bexpression* bcall = tree_to_expr(call->get_tree(context));
- s = context->backend()->expression_statement(bcall);
- }
if (s == NULL)
- return ldef;
- return context->backend()->compound_statement(s, ldef);
+ clauses[i] = g;
+ else
+ clauses[i] = context->backend()->compound_statement(s, g);
}
- go_assert(count > 0);
-
- std::vector<Bstatement*> statements;
- mpz_t ival;
- mpz_init_set_ui(ival, count);
- Expression* ecount = Expression::make_integer(&ival, NULL, location);
- mpz_clear(ival);
-
- Type* chan_array_type = Type::make_array_type(runtime_chan_type, ecount);
- Expression* chans = Expression::make_composite_literal(chan_array_type, 0,
- false, chan_init,
- location);
- context->gogo()->lower_expression(context->function(), NULL, &chans);
- Temporary_statement* chan_temp = Statement::make_temporary(chan_array_type,
- chans,
- location);
- statements.push_back(chan_temp->get_backend(context));
-
- Type* is_send_array_type = Type::make_array_type(Type::lookup_bool_type(),
- ecount->copy());
- Expression* is_sends = Expression::make_composite_literal(is_send_array_type,
- 0, false,
- is_send_init,
- location);
- context->gogo()->lower_expression(context->function(), NULL, &is_sends);
- Temporary_statement* is_send_temp =
- Statement::make_temporary(is_send_array_type, is_sends, location);
- statements.push_back(is_send_temp->get_backend(context));
-
- mpz_init_set_ui(ival, 0);
- Expression* zero = Expression::make_integer(&ival, NULL, location);
- mpz_clear(ival);
-
- Expression* ref = Expression::make_temporary_reference(chan_temp, location);
- Expression* chan_arg = Expression::make_array_index(ref, zero, NULL,
- location);
- chan_arg = Expression::make_unary(OPERATOR_AND, chan_arg, location);
- chan_arg = Expression::make_unsafe_cast(runtime_chanptr_type, chan_arg,
- location);
-
- ref = Expression::make_temporary_reference(is_send_temp, location);
- Expression* is_send_arg = Expression::make_array_index(ref, zero->copy(),
- NULL, location);
- is_send_arg = Expression::make_unary(OPERATOR_AND, is_send_arg, location);
-
- Expression* default_arg = Expression::make_boolean(default_clause != NULL,
- location);
- Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
- ecount->copy(), default_arg,
- chan_arg, is_send_arg);
+ Expression* selref = Expression::make_temporary_reference(sel, location);
+ Expression* call = Runtime::make_call(Runtime::SELECTGO, location, 1,
+ selref);
context->gogo()->lower_expression(context->function(), NULL, &call);
Bexpression* bcall = tree_to_expr(call->get_tree(context));
- std::vector<std::vector<Bexpression*> > cases;
- std::vector<Bstatement*> clauses;
+ if (count == 0)
+ return context->backend()->expression_statement(bcall);
- cases.resize(count + (default_clause != NULL ? 1 : 0));
- clauses.resize(count + (default_clause != NULL ? 1 : 0));
-
- int index = 0;
-
- if (default_clause != NULL)
- {
- this->add_clause_backend(context, location, index, 0, default_clause,
- break_label, &cases, &clauses);
- ++index;
- }
-
- int i = 1;
- for (Clauses::iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- {
- if (!p->is_default())
- {
- this->add_clause_backend(context, location, index, i, &*p,
- break_label, &cases, &clauses);
- ++i;
- ++index;
- }
- }
+ std::vector<Bstatement*> statements;
+ statements.reserve(2);
Bstatement* switch_stmt = context->backend()->switch_statement(bcall,
cases,
@@ -4935,39 +4885,6 @@ Select_clauses::get_backend(Translate_context* context,
return context->backend()->statement_list(statements);
}
-
-// Add CLAUSE to CASES/CLAUSES at INDEX.
-
-void
-Select_clauses::add_clause_backend(
- Translate_context* context,
- Location location,
- int index,
- int case_value,
- Select_clause* clause,
- Unnamed_label* bottom_label,
- std::vector<std::vector<Bexpression*> > *cases,
- std::vector<Bstatement*>* clauses)
-{
- mpz_t ival;
- mpz_init_set_ui(ival, case_value);
- Expression* e = Expression::make_integer(&ival, NULL, location);
- mpz_clear(ival);
- (*cases)[index].push_back(tree_to_expr(e->get_tree(context)));
-
- Bstatement* s = clause->get_statements_backend(context);
-
- Location gloc = (clause->statements() == NULL
- ? clause->location()
- : clause->statements()->end_location());
- Bstatement* g = bottom_label->get_goto(context, gloc);
-
- if (s == NULL)
- (*clauses)[index] = g;
- else
- (*clauses)[index] = context->backend()->compound_statement(s, g);
-}
-
// Dump the AST representation for select clauses.
void
@@ -5003,11 +4920,28 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
{
if (this->is_lowered_)
return this;
- Block* b = new Block(enclosing, this->location());
- this->clauses_->lower(gogo, function, b);
+
+ Location loc = this->location();
+
+ Block* b = new Block(enclosing, loc);
+
+ go_assert(this->sel_ == NULL);
+
+ mpz_t ival;
+ mpz_init_set_ui(ival, this->clauses_->size());
+ Expression* size_expr = Expression::make_integer(&ival, NULL, loc);
+ mpz_clear(ival);
+
+ Expression* call = Runtime::make_call(Runtime::NEWSELECT, loc, 1, size_expr);
+
+ this->sel_ = Statement::make_temporary(NULL, call, loc);
+ b->add_statement(this->sel_);
+
+ this->clauses_->lower(gogo, function, b, this->sel_);
this->is_lowered_ = true;
b->add_statement(this);
- return Statement::make_block_statement(b, this->location());
+
+ return Statement::make_block_statement(b, loc);
}
// Return the backend representation for a select statement.
@@ -5015,7 +4949,7 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function,
Bstatement*
Select_statement::do_get_backend(Translate_context* context)
{
- return this->clauses_->get_backend(context, this->break_label(),
+ return this->clauses_->get_backend(context, this->sel_, this->break_label(),
this->location());
}
@@ -5790,7 +5724,7 @@ For_range_statement::lower_range_channel(Gogo*,
Expression::make_temporary_reference(ok_temp, loc);
oref->set_is_lvalue();
Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
- false, loc);
+ loc);
iter_init->add_statement(s);
Block* then_block = new Block(iter_init, loc);
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index 16914f1..4548ba6 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -165,12 +165,10 @@ class Statement
Expression* should_set, Location);
// Make an assignment from a nonblocking receive to a pair of
- // variables. FOR_SELECT is true is this is being created for a
- // case x, ok := <-c in a select statement.
+ // variables.
static Statement*
make_tuple_receive_assignment(Expression* val, Expression* closed,
- Expression* channel, bool for_select,
- Location);
+ Expression* channel, Location);
// Make an assignment from a type guard to a pair of variables.
static Statement*
@@ -634,14 +632,9 @@ class Send_statement : public Statement
Send_statement(Expression* channel, Expression* val,
Location location)
: Statement(STATEMENT_SEND, location),
- channel_(channel), val_(val), for_select_(false)
+ channel_(channel), val_(val)
{ }
- // Note that this is for a select statement.
- void
- set_for_select()
- { this->for_select_ = true; }
-
protected:
int
do_traverse(Traverse* traverse);
@@ -663,8 +656,6 @@ class Send_statement : public Statement
Expression* channel_;
// The value to send.
Expression* val_;
- // Whether this is for a select statement.
- bool for_select_;
};
// Select_clauses holds the clauses of a select statement. This is
@@ -693,23 +684,32 @@ class Select_clauses
Named_object* var, Named_object* closedvar, bool is_default,
Block* statements, Location location)
{
- this->clauses_.push_back(Select_clause(is_send, channel, val, closed, var,
- closedvar, is_default, statements,
- location));
+ int index = static_cast<int>(this->clauses_.size());
+ this->clauses_.push_back(Select_clause(index, is_send, channel, val,
+ closed, var, closedvar, is_default,
+ statements, location));
}
+ size_t
+ size() const
+ { return this->clauses_.size(); }
+
// Traverse the select clauses.
int
traverse(Traverse*);
// Lower statements.
void
- lower(Gogo*, Named_object*, Block*);
+ lower(Gogo*, Named_object*, Block*, Temporary_statement*);
// Determine types.
void
determine_types();
+ // Check types.
+ void
+ check_types();
+
// Whether the select clauses may fall through to the statement
// which follows the overall select statement.
bool
@@ -717,7 +717,8 @@ class Select_clauses
// Convert to the backend representation.
Bstatement*
- get_backend(Translate_context*, Unnamed_label* break_label, Location);
+ get_backend(Translate_context*, Temporary_statement* sel,
+ Unnamed_label* break_label, Location);
// Dump AST representation.
void
@@ -734,27 +735,37 @@ class Select_clauses
is_default_(false)
{ }
- Select_clause(bool is_send, Expression* channel, Expression* val,
- Expression* closed, Named_object* var,
+ Select_clause(int index, bool is_send, Expression* channel,
+ Expression* val, Expression* closed, Named_object* var,
Named_object* closedvar, bool is_default, Block* statements,
Location location)
- : channel_(channel), val_(val), closed_(closed), var_(var),
- closedvar_(closedvar), statements_(statements), location_(location),
- is_send_(is_send), is_default_(is_default), is_lowered_(false)
+ : index_(index), channel_(channel), val_(val), closed_(closed),
+ var_(var), closedvar_(closedvar), statements_(statements),
+ location_(location), is_send_(is_send), is_default_(is_default),
+ is_lowered_(false)
{ go_assert(is_default ? channel == NULL : channel != NULL); }
+ // Return the index of this clause.
+ int
+ index() const
+ { return this->index_; }
+
// Traverse the select clause.
int
traverse(Traverse*);
// Lower statements.
void
- lower(Gogo*, Named_object*, Block*);
+ lower(Gogo*, Named_object*, Block*, Temporary_statement*);
// Determine types.
void
determine_types();
+ // Check types.
+ void
+ check_types();
+
// Return true if this is the default clause.
bool
is_default() const
@@ -798,6 +809,18 @@ class Select_clauses
dump_clause(Ast_dump_context*) const;
private:
+ void
+ lower_default(Block*, Expression*, Expression*);
+
+ void
+ lower_send(Block*, Expression*, Expression*, Expression*);
+
+ void
+ lower_recv(Gogo*, Named_object*, Block*, Expression*, Expression*,
+ Expression*);
+
+ // The index of this case in the generated switch statement.
+ int index_;
// The channel.
Expression* channel_;
// The value to send or the lvalue to receive into.
@@ -822,12 +845,6 @@ class Select_clauses
bool is_lowered_;
};
- void
- add_clause_backend(Translate_context*, Location, int index,
- int case_value, Select_clause*, Unnamed_label*,
- std::vector<std::vector<Bexpression*> >* cases,
- std::vector<Bstatement*>* clauses);
-
typedef std::vector<Select_clause> Clauses;
Clauses clauses_;
@@ -840,7 +857,7 @@ class Select_statement : public Statement
public:
Select_statement(Location location)
: Statement(STATEMENT_SELECT, location),
- clauses_(NULL), break_label_(NULL), is_lowered_(false)
+ clauses_(NULL), sel_(NULL), break_label_(NULL), is_lowered_(false)
{ }
// Add the clauses.
@@ -867,6 +884,10 @@ class Select_statement : public Statement
do_determine_types()
{ this->clauses_->determine_types(); }
+ void
+ do_check_types(Gogo*)
+ { this->clauses_->check_types(); }
+
bool
do_may_fall_through() const
{ return this->clauses_->may_fall_through(); }
@@ -880,6 +901,8 @@ class Select_statement : public Statement
private:
// The select clauses.
Select_clauses* clauses_;
+ // A temporary which holds the select structure we build up at runtime.
+ Temporary_statement* sel_;
// The break label.
Unnamed_label* break_label_;
// Whether this statement has been lowered.
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index 5ab10a6..19ce715 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 f7c293a..1a76f0b 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 0000000..a246992
--- /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 c3cc3e3..0000000
--- 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 9176c68..0000000
--- 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 2c7958d..0000000
--- 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 b3ced98..0000000
--- 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 7e32286..0000000
--- 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 fe13c5e..0000000
--- 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 d45e90a..0000000
--- 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 659ea1d..0000000
--- 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 c21878c..0000000
--- 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 f26dbcd..0000000
--- 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 6f6693b..0000000
--- 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 677c699..0000000
--- 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 61d4a0f..0000000
--- 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 e039874..0000000
--- 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 c77ee91..0000000
--- 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 06bcb41..0000000
--- 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/runtime.h b/libgo/runtime/runtime.h
index 9455ae8..db59be5 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;