compiler/runtime: Copy channel implementation from master library.

From-SVN: r181874
This commit is contained in:
Ian Lance Taylor 2011-12-01 08:06:16 +00:00
parent 04f7a48edd
commit 3e68d6d75a
30 changed files with 1627 additions and 2801 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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))
// Receive a value from a channel returning whether it is closed, for select.
DEF_GO_RUNTIME(CHANRECV3, "runtime.chanrecv3", P2(CHAN, POINTER), R1(BOOL))
// Start building a select statement.
DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P1(INT), R1(POINTER))
// 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))

View File

@ -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);

View File

@ -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,128 +4487,42 @@ 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);
Expression* chanref = 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);
}
// 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);
// We have to put S in STATEMENTS_, because that is where the
// variables are declared.
go_assert(this->statements_ != NULL);
// Skip the variable declaration statements themselves.
size_t skip = 1;
if (this->var_ != NULL)
skip = 2;
// 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);
this->statements_->insert_statement_before(skip, s);
// We have to lower STATEMENTS_ again, to lower the tuple
// receive assignment we just added.
gogo->lower_block(function, this->statements_);
}
this->lower_send(b, selref, chanref, 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));
}
}
// Lower any statements we just created.
gogo->lower_block(function, init);
if (this->statements_ != NULL)
init->add_statement(Statement::make_block_statement(this->statements_,
loc));
this->statements_ = init;
this->lower_recv(gogo, function, b, selref, chanref, index_expr);
// Now all references should be handled through the statements, not
// through here.
@ -4620,6 +4531,136 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
this->var_ = NULL;
}
// Lower a default clause in a select statement.
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));
}
// Lower a send clause in a select statement.
void
Select_clauses::Select_clause::lower_send(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();
// 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
{
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);
}
b->add_statement(Statement::make_statement(call, true));
// If the block of statements is executed, arrange for the received
// value to move from VAL to the place where the statements expect
// it.
Block* init = 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.
void
@ -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;
}
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)));
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();
}
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);
Expression* c = p->channel();
c = Expression::make_unsafe_cast(runtime_chan_type, c, p->location());
chan_init->push_back(c);
is_send_init->push_back(Expression::make_boolean(p->is_send(),
p->location()));
}
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);

View File

@ -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.

View File

@ -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 \

View File

@ -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

1248
libgo/runtime/chan.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
}

View File

@ -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 *);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;