Commit 3137991d by Ian Lance Taylor

Tuple receives indicate whether channel is closed.

From-SVN: r171380
parent 4908b0bf
...@@ -3057,7 +3057,7 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select, ...@@ -3057,7 +3057,7 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select,
location, location,
"__go_receive_big", "__go_receive_big",
3, 3,
void_type_node, boolean_type_node,
ptr_type_node, ptr_type_node,
channel, channel,
ptr_type_node, ptr_type_node,
......
...@@ -1257,7 +1257,7 @@ Lower_parse_tree::statement(Block* block, size_t* pindex, Statement* sorig) ...@@ -1257,7 +1257,7 @@ Lower_parse_tree::statement(Block* block, size_t* pindex, Statement* sorig)
Statement* s = sorig; Statement* s = sorig;
while (true) while (true)
{ {
Statement* snew = s->lower(this->gogo_, block); Statement* snew = s->lower(this->gogo_, this->function_, block);
if (snew == s) if (snew == s)
break; break;
s = snew; s = snew;
...@@ -1305,6 +1305,15 @@ Gogo::lower_parse_tree() ...@@ -1305,6 +1305,15 @@ Gogo::lower_parse_tree()
this->traverse(&lower_parse_tree); this->traverse(&lower_parse_tree);
} }
// Lower a block.
void
Gogo::lower_block(Named_object* function, Block* block)
{
Lower_parse_tree lower_parse_tree(this, function);
block->traverse(&lower_parse_tree);
}
// Lower an expression. // Lower an expression.
void void
......
...@@ -348,6 +348,10 @@ class Gogo ...@@ -348,6 +348,10 @@ class Gogo
void void
lower_parse_tree(); lower_parse_tree();
// Lower all the statements in a block.
void
lower_block(Named_object* function, Block*);
// Lower an expression. // Lower an expression.
void void
lower_expression(Named_object* function, Expression**); lower_expression(Named_object* function, Expression**);
......
...@@ -4179,10 +4179,12 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) ...@@ -4179,10 +4179,12 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
bool is_send = false; bool is_send = false;
Expression* channel = NULL; Expression* channel = NULL;
Expression* val = NULL; Expression* val = NULL;
Expression* closed = NULL;
std::string varname; std::string varname;
std::string closedname;
bool is_default = false; bool is_default = false;
bool got_case = this->comm_case(&is_send, &channel, &val, &varname, bool got_case = this->comm_case(&is_send, &channel, &val, &closed,
&is_default); &varname, &closedname, &is_default);
if (this->peek_token()->is_op(OPERATOR_COLON)) if (this->peek_token()->is_op(OPERATOR_COLON))
this->advance_token(); this->advance_token();
...@@ -4191,6 +4193,7 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) ...@@ -4191,6 +4193,7 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
Block* statements = NULL; Block* statements = NULL;
Named_object* var = NULL; Named_object* var = NULL;
Named_object* closedvar = NULL;
if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
this->advance_token(); this->advance_token();
else if (this->statement_list_may_start_here()) else if (this->statement_list_may_start_here())
...@@ -4206,6 +4209,14 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) ...@@ -4206,6 +4209,14 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
var = this->gogo_->add_variable(varname, v); var = this->gogo_->add_variable(varname, v);
} }
if (!closedname.empty())
{
// FIXME: LOCATION is slightly wrong here.
Variable* v = new Variable(Type::lookup_bool_type(), NULL,
false, false, false, location);
closedvar = this->gogo_->add_variable(closedname, v);
}
this->statement_list(); this->statement_list();
statements = this->gogo_->finish_block(this->location()); statements = this->gogo_->finish_block(this->location());
} }
...@@ -4221,7 +4232,8 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) ...@@ -4221,7 +4232,8 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
} }
if (got_case) if (got_case)
clauses->add(is_send, channel, val, var, is_default, statements, location); clauses->add(is_send, channel, val, closed, var, closedvar, is_default,
statements, location);
else if (statements != NULL) else if (statements != NULL)
{ {
// Add the statements to make sure that any names they define // Add the statements to make sure that any names they define
...@@ -4234,7 +4246,8 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) ...@@ -4234,7 +4246,8 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
bool bool
Parse::comm_case(bool* is_send, Expression** channel, Expression** val, Parse::comm_case(bool* is_send, Expression** channel, Expression** val,
std::string* varname, bool* is_default) Expression** closed, std::string* varname,
std::string* closedname, bool* is_default)
{ {
const Token* token = this->peek_token(); const Token* token = this->peek_token();
if (token->is_keyword(KEYWORD_DEFAULT)) if (token->is_keyword(KEYWORD_DEFAULT))
...@@ -4245,7 +4258,8 @@ Parse::comm_case(bool* is_send, Expression** channel, Expression** val, ...@@ -4245,7 +4258,8 @@ Parse::comm_case(bool* is_send, Expression** channel, Expression** val,
else if (token->is_keyword(KEYWORD_CASE)) else if (token->is_keyword(KEYWORD_CASE))
{ {
this->advance_token(); this->advance_token();
if (!this->send_or_recv_expr(is_send, channel, val, varname)) if (!this->send_or_recv_stmt(is_send, channel, val, closed, varname,
closedname))
return false; return false;
} }
else else
...@@ -4259,46 +4273,112 @@ Parse::comm_case(bool* is_send, Expression** channel, Expression** val, ...@@ -4259,46 +4273,112 @@ Parse::comm_case(bool* is_send, Expression** channel, Expression** val,
return true; return true;
} }
// RecvExpr = [ Expression ( "=" | ":=" ) ] "<-" Expression . // RecvStmt = [ Expression [ "," Expression ] ( "=" | ":=" ) ] RecvExpr .
// RecvExpr = Expression .
bool bool
Parse::send_or_recv_expr(bool* is_send, Expression** channel, Expression** val, Parse::send_or_recv_stmt(bool* is_send, Expression** channel, Expression** val,
std::string* varname) Expression** closed, std::string* varname,
std::string* closedname)
{ {
const Token* token = this->peek_token(); const Token* token = this->peek_token();
source_location location = token->location(); bool saw_comma = false;
bool closed_is_id = false;
if (token->is_identifier()) if (token->is_identifier())
{ {
Gogo* gogo = this->gogo_;
std::string recv_var = token->identifier(); std::string recv_var = token->identifier();
bool is_var_exported = token->is_identifier_exported(); bool is_rv_exported = token->is_identifier_exported();
if (!this->advance_token()->is_op(OPERATOR_COLONEQ)) source_location recv_var_loc = token->location();
this->unget_token(Token::make_identifier_token(recv_var, token = this->advance_token();
is_var_exported, if (token->is_op(OPERATOR_COLONEQ))
location));
else
{ {
// case rv := <-c:
if (!this->advance_token()->is_op(OPERATOR_CHANOP)) if (!this->advance_token()->is_op(OPERATOR_CHANOP))
{ {
error_at(this->location(), "expected %<<-%>"); error_at(this->location(), "expected %<<-%>");
return false; return false;
} }
if (recv_var == "_")
{
error_at(recv_var_loc,
"no new variables on left side of %<:=%>");
recv_var = "blank";
}
*is_send = false; *is_send = false;
*varname = this->gogo_->pack_hidden_name(recv_var, is_var_exported); *varname = gogo->pack_hidden_name(recv_var, is_rv_exported);
this->advance_token(); this->advance_token();
*channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL); *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
return true; return true;
} }
else if (token->is_op(OPERATOR_COMMA))
{
token = this->advance_token();
if (token->is_identifier())
{
std::string recv_closed = token->identifier();
bool is_rc_exported = token->is_identifier_exported();
source_location recv_closed_loc = token->location();
closed_is_id = true;
token = this->advance_token();
if (token->is_op(OPERATOR_COLONEQ))
{
// case rv, rc := <-c:
if (!this->advance_token()->is_op(OPERATOR_CHANOP))
{
error_at(this->location(), "expected %<<-%>");
return false;
}
if (recv_var == "_" && recv_closed == "_")
{
error_at(recv_var_loc,
"no new variables on left side of %<:=%>");
recv_var = "blank";
}
*is_send = false;
if (recv_var != "_")
*varname = gogo->pack_hidden_name(recv_var,
is_rv_exported);
if (recv_closed != "_")
*closedname = gogo->pack_hidden_name(recv_closed,
is_rc_exported);
this->advance_token();
*channel = this->expression(PRECEDENCE_NORMAL, false, true,
NULL);
return true;
} }
if (this->peek_token()->is_op(OPERATOR_CHANOP)) this->unget_token(Token::make_identifier_token(recv_closed,
is_rc_exported,
recv_closed_loc));
}
*val = this->id_to_expression(gogo->pack_hidden_name(recv_var,
is_rv_exported),
recv_var_loc);
saw_comma = true;
}
else
this->unget_token(Token::make_identifier_token(recv_var,
is_rv_exported,
recv_var_loc));
}
// If SAW_COMMA is false, then we are looking at the start of the
// send or receive expression. If SAW_COMMA is true, then *VAL is
// set and we just read a comma.
if (!saw_comma && this->peek_token()->is_op(OPERATOR_CHANOP))
{ {
// case <-c:
*is_send = false; *is_send = false;
this->advance_token(); this->advance_token();
*channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL); *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
return true;
} }
else
{ Expression* e = this->expression(PRECEDENCE_NORMAL, true, true, NULL);
Expression* left = this->expression(PRECEDENCE_NORMAL, true, true, NULL);
if (this->peek_token()->is_op(OPERATOR_EQ)) if (this->peek_token()->is_op(OPERATOR_EQ))
{ {
...@@ -4308,25 +4388,45 @@ Parse::send_or_recv_expr(bool* is_send, Expression** channel, Expression** val, ...@@ -4308,25 +4388,45 @@ Parse::send_or_recv_expr(bool* is_send, Expression** channel, Expression** val,
return false; return false;
} }
*is_send = false; *is_send = false;
*val = left;
this->advance_token(); this->advance_token();
*channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL); *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
} if (saw_comma)
else if (this->peek_token()->is_op(OPERATOR_CHANOP))
{ {
*is_send = true; // case v, e = <-c:
*channel = this->verify_not_sink(left); // *VAL is already set.
this->advance_token(); if (!e->is_sink_expression())
*val = this->expression(PRECEDENCE_NORMAL, false, true, NULL); *closed = e;
} }
else else
{ {
error_at(this->location(), "expected %<<-%> or %<=%>"); // case v = <-c:
return false; if (!e->is_sink_expression())
*val = e;
} }
return true;
}
if (saw_comma)
{
if (closed_is_id)
error_at(this->location(), "expected %<=%> or %<:=%>");
else
error_at(this->location(), "expected %<=%>");
return false;
} }
if (this->peek_token()->is_op(OPERATOR_CHANOP))
{
// case c <- v:
*is_send = true;
*channel = this->verify_not_sink(e);
this->advance_token();
*val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
return true; return true;
}
error_at(this->location(), "expected %<<-%> or %<=%>");
return false;
} }
// ForStat = "for" [ Condition | ForClause | RangeClause ] Block . // ForStat = "for" [ Condition | ForClause | RangeClause ] Block .
......
...@@ -246,8 +246,10 @@ class Parse ...@@ -246,8 +246,10 @@ class Parse
void type_switch_case(std::vector<Type*>*, bool*); void type_switch_case(std::vector<Type*>*, bool*);
void select_stat(const Label*); void select_stat(const Label*);
void comm_clause(Select_clauses*, bool* saw_default); void comm_clause(Select_clauses*, bool* saw_default);
bool comm_case(bool*, Expression**, Expression**, std::string*, bool*); bool comm_case(bool*, Expression**, Expression**, Expression**,
bool send_or_recv_expr(bool*, Expression**, Expression**, std::string*); std::string*, std::string*, bool*);
bool send_or_recv_stmt(bool*, Expression**, Expression**, Expression**,
std::string*, std::string*);
void for_stat(const Label*); void for_stat(const Label*);
void for_clause(Expression**, Block**); void for_clause(Expression**, Block**);
void range_clause_decl(const Typed_identifier_list*, Range_clause*); void range_clause_decl(const Typed_identifier_list*, Range_clause*);
......
...@@ -162,7 +162,7 @@ class Statement ...@@ -162,7 +162,7 @@ class Statement
// Make an assignment from a nonblocking receive to a pair of // Make an assignment from a nonblocking receive to a pair of
// variables. // variables.
static Statement* static Statement*
make_tuple_receive_assignment(Expression* val, Expression* success, make_tuple_receive_assignment(Expression* val, Expression* closed,
Expression* channel, source_location); Expression* channel, source_location);
// Make an assignment from a type guard to a pair of variables. // Make an assignment from a type guard to a pair of variables.
...@@ -284,11 +284,11 @@ class Statement ...@@ -284,11 +284,11 @@ class Statement
// Lower a statement. This is called immediately after parsing to // Lower a statement. This is called immediately after parsing to
// simplify statements for further processing. It returns the same // simplify statements for further processing. It returns the same
// Statement or a new one. BLOCK is the block containing this // Statement or a new one. FUNCTION is the function containing this
// statement. // statement. BLOCK is the block containing this statement.
Statement* Statement*
lower(Gogo* gogo, Block* block) lower(Gogo* gogo, Named_object* function, Block* block)
{ return this->do_lower(gogo, block); } { return this->do_lower(gogo, function, block); }
// Set type information for unnamed constants. // Set type information for unnamed constants.
void void
...@@ -381,7 +381,7 @@ class Statement ...@@ -381,7 +381,7 @@ class Statement
// Implemented by the child class: lower this statement to a simpler // Implemented by the child class: lower this statement to a simpler
// one. // one.
virtual Statement* virtual Statement*
do_lower(Gogo*, Block*) do_lower(Gogo*, Named_object*, Block*)
{ return this; } { return this; }
// Implemented by child class: set type information for unnamed // Implemented by child class: set type information for unnamed
...@@ -574,7 +574,7 @@ class Return_statement : public Statement ...@@ -574,7 +574,7 @@ class Return_statement : public Statement
do_traverse_assignments(Traverse_assignments*); do_traverse_assignments(Traverse_assignments*);
Statement* Statement*
do_lower(Gogo*, Block*); do_lower(Gogo*, Named_object*, Block*);
void void
do_determine_types(); do_determine_types();
...@@ -649,17 +649,22 @@ class Select_clauses ...@@ -649,17 +649,22 @@ class Select_clauses
// Add a new clause. IS_SEND is true if this is a send clause, // Add a new clause. IS_SEND is true if this is a send clause,
// false for a receive clause. For a send clause CHANNEL is the // false for a receive clause. For a send clause CHANNEL is the
// channel and VAL is the value to send. For a receive clause // channel and VAL is the value to send. For a receive clause
// CHANNEL is the channel and VAL is either NULL or a Var_expression // CHANNEL is the channel, VAL is either NULL or a Var_expression
// for the variable to set; if VAL is NULL, VAR may be a variable // for the variable to set, and CLOSED is either NULL or a
// which is initialized with the received value. IS_DEFAULT is true // Var_expression to set to whether the channel is closed. If VAL
// if this is the default clause. STATEMENTS is the list of // is NULL, VAR may be a variable to be initialized with the
// statements to execute. // received value, and CLOSEDVAR ma be a variable to be initialized
// with whether the channel is closed. IS_DEFAULT is true if this
// is the default clause. STATEMENTS is the list of statements to
// execute.
void void
add(bool is_send, Expression* channel, Expression* val, Named_object* var, add(bool is_send, Expression* channel, Expression* val, Expression* closed,
bool is_default, Block* statements, source_location location) Named_object* var, Named_object* closedvar, bool is_default,
Block* statements, source_location location)
{ {
this->clauses_.push_back(Select_clause(is_send, channel, val, var, this->clauses_.push_back(Select_clause(is_send, channel, val, closed, var,
is_default, statements, location)); closedvar, is_default, statements,
location));
} }
// Traverse the select clauses. // Traverse the select clauses.
...@@ -668,7 +673,7 @@ class Select_clauses ...@@ -668,7 +673,7 @@ class Select_clauses
// Lower statements. // Lower statements.
void void
lower(Block*); lower(Gogo*, Named_object*, Block*);
// Determine types. // Determine types.
void void
...@@ -689,16 +694,18 @@ class Select_clauses ...@@ -689,16 +694,18 @@ class Select_clauses
{ {
public: public:
Select_clause() Select_clause()
: channel_(NULL), val_(NULL), var_(NULL), statements_(NULL), : channel_(NULL), val_(NULL), closed_(NULL), var_(NULL),
is_send_(false), is_default_(false) closedvar_(NULL), statements_(NULL), is_send_(false),
is_default_(false)
{ } { }
Select_clause(bool is_send, Expression* channel, Expression* val, Select_clause(bool is_send, Expression* channel, Expression* val,
Named_object* var, bool is_default, Block* statements, Expression* closed, Named_object* var,
Named_object* closedvar, bool is_default, Block* statements,
source_location location) source_location location)
: channel_(channel), val_(val), var_(var), statements_(statements), : channel_(channel), val_(val), closed_(closed), var_(var),
location_(location), is_send_(is_send), is_default_(is_default), closedvar_(closedvar), statements_(statements), location_(location),
is_lowered_(false) is_send_(is_send), is_default_(is_default), is_lowered_(false)
{ gcc_assert(is_default ? channel == NULL : channel != NULL); } { gcc_assert(is_default ? channel == NULL : channel != NULL); }
// Traverse the select clause. // Traverse the select clause.
...@@ -707,7 +714,7 @@ class Select_clauses ...@@ -707,7 +714,7 @@ class Select_clauses
// Lower statements. // Lower statements.
void void
lower(Block*); lower(Gogo*, Named_object*, Block*);
// Determine types. // Determine types.
void void
...@@ -724,20 +731,6 @@ class Select_clauses ...@@ -724,20 +731,6 @@ class Select_clauses
channel() const channel() const
{ return this->channel_; } { return this->channel_; }
// Return the value. This will return NULL for the default
// clause, or for a receive clause for which no value was given.
Expression*
val() const
{ return this->val_; }
// Return the variable to set when a receive clause is also a
// variable definition (v := <- ch). This will return NULL for
// the default case, or for a send clause, or for a receive clause
// which does not define a variable.
Named_object*
var() const
{ return this->var_; }
// Return true for a send, false for a receive. // Return true for a send, false for a receive.
bool bool
is_send() const is_send() const
...@@ -768,10 +761,16 @@ class Select_clauses ...@@ -768,10 +761,16 @@ class Select_clauses
private: private:
// The channel. // The channel.
Expression* channel_; Expression* channel_;
// The value to send or the variable to set. // The value to send or the lvalue to receive into.
Expression* val_; Expression* val_;
// The variable to initialize, for "case a := <- ch". // The lvalue to set to whether the channel is closed on a
// receive.
Expression* closed_;
// The variable to initialize, for "case a := <-ch".
Named_object* var_; Named_object* var_;
// The variable to initialize to whether the channel is closed,
// for "case a, c := <-ch".
Named_object* closedvar_;
// The statements to execute. // The statements to execute.
Block* statements_; Block* statements_;
// The location of this clause. // The location of this clause.
...@@ -821,7 +820,7 @@ class Select_statement : public Statement ...@@ -821,7 +820,7 @@ class Select_statement : public Statement
{ return this->clauses_->traverse(traverse); } { return this->clauses_->traverse(traverse); }
Statement* Statement*
do_lower(Gogo*, Block*); do_lower(Gogo*, Named_object*, Block*);
void void
do_determine_types() do_determine_types()
...@@ -1008,7 +1007,7 @@ class For_statement : public Statement ...@@ -1008,7 +1007,7 @@ class For_statement : public Statement
{ gcc_unreachable(); } { gcc_unreachable(); }
Statement* Statement*
do_lower(Gogo*, Block*); do_lower(Gogo*, Named_object*, Block*);
tree tree
do_get_tree(Translate_context*) do_get_tree(Translate_context*)
...@@ -1066,7 +1065,7 @@ class For_range_statement : public Statement ...@@ -1066,7 +1065,7 @@ class For_range_statement : public Statement
{ gcc_unreachable(); } { gcc_unreachable(); }
Statement* Statement*
do_lower(Gogo*, Block*); do_lower(Gogo*, Named_object*, Block*);
tree tree
do_get_tree(Translate_context*) do_get_tree(Translate_context*)
...@@ -1290,7 +1289,7 @@ class Switch_statement : public Statement ...@@ -1290,7 +1289,7 @@ class Switch_statement : public Statement
do_traverse(Traverse*); do_traverse(Traverse*);
Statement* Statement*
do_lower(Gogo*, Block*); do_lower(Gogo*, Named_object*, Block*);
tree tree
do_get_tree(Translate_context*) do_get_tree(Translate_context*)
...@@ -1436,7 +1435,7 @@ class Type_switch_statement : public Statement ...@@ -1436,7 +1435,7 @@ class Type_switch_statement : public Statement
do_traverse(Traverse*); do_traverse(Traverse*);
Statement* Statement*
do_lower(Gogo*, Block*); do_lower(Gogo*, Named_object*, Block*);
tree tree
do_get_tree(Translate_context*) do_get_tree(Translate_context*)
......
...@@ -12,28 +12,22 @@ typedef struct __go_channel chan; ...@@ -12,28 +12,22 @@ typedef struct __go_channel chan;
/* Do a nonblocking channel receive. */ /* Do a nonblocking channel receive. */
func chanrecv2(c *chan, val *byte) (pres bool) { func chanrecv2(c *chan, val *byte) (received bool) {
if (c->element_size > 8) { if (c->element_size > 8) {
return __go_receive_nonblocking_big(c, val); return __go_receive_big(c, val, 0);
} else { } else {
struct __go_receive_nonblocking_small rs;
union { union {
char b[8]; char b[8];
uint64_t v; uint64_t v;
} u; } u;
rs = __go_receive_nonblocking_small (c); u.v = __go_receive_small_closed(c, 0, &received);
if (!rs.__success) {
__builtin_memset(val, 0, c->element_size);
return 0;
}
u.v = rs.__val;
#ifndef WORDS_BIGENDIAN #ifndef WORDS_BIGENDIAN
__builtin_memcpy(val, u.b, c->element_size); __builtin_memcpy(val, u.b, c->element_size);
#else #else
__builtin_memcpy(val, u.b + 8 - c->element_size, __builtin_memcpy(val, u.b + 8 - c->element_size,
c->element_size); c->element_size);
#endif #endif
return 1; return received;
} }
} }
...@@ -112,6 +112,9 @@ extern int __go_receive_nonblocking_acquire (struct __go_channel *); ...@@ -112,6 +112,9 @@ 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 (struct __go_channel *, _Bool);
extern uint64_t __go_receive_small_closed (struct __go_channel *, _Bool,
_Bool *);
extern void __go_receive_release (struct __go_channel *); extern void __go_receive_release (struct __go_channel *);
struct __go_receive_nonblocking_small struct __go_receive_nonblocking_small
...@@ -123,7 +126,7 @@ struct __go_receive_nonblocking_small ...@@ -123,7 +126,7 @@ struct __go_receive_nonblocking_small
extern struct __go_receive_nonblocking_small extern struct __go_receive_nonblocking_small
__go_receive_nonblocking_small (struct __go_channel *); __go_receive_nonblocking_small (struct __go_channel *);
extern void __go_receive_big (struct __go_channel *, void *, _Bool); extern _Bool __go_receive_big (struct __go_channel *, void *, _Bool);
extern _Bool __go_receive_nonblocking_big (struct __go_channel *, void *); extern _Bool __go_receive_nonblocking_big (struct __go_channel *, void *);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include "go-panic.h" #include "go-panic.h"
#include "channel.h" #include "channel.h"
void _Bool
__go_receive_big (struct __go_channel *channel, void *val, _Bool for_select) __go_receive_big (struct __go_channel *channel, void *val, _Bool for_select)
{ {
size_t alloc_size; size_t alloc_size;
...@@ -24,11 +24,13 @@ __go_receive_big (struct __go_channel *channel, void *val, _Bool for_select) ...@@ -24,11 +24,13 @@ __go_receive_big (struct __go_channel *channel, void *val, _Bool for_select)
if (!__go_receive_acquire (channel, for_select)) if (!__go_receive_acquire (channel, for_select))
{ {
__builtin_memset (val, 0, channel->element_size); __builtin_memset (val, 0, channel->element_size);
return; return 0;
} }
offset = channel->next_fetch * alloc_size; offset = channel->next_fetch * alloc_size;
__builtin_memcpy (val, &channel->data[offset], channel->element_size); __builtin_memcpy (val, &channel->data[offset], channel->element_size);
__go_receive_release (channel); __go_receive_release (channel);
return 1;
} }
...@@ -263,7 +263,8 @@ __go_unlock_and_notify_selects (struct __go_channel *channel) ...@@ -263,7 +263,8 @@ __go_unlock_and_notify_selects (struct __go_channel *channel)
/* Receive something 64 bits or smaller on a channel. */ /* Receive something 64 bits or smaller on a channel. */
uint64_t uint64_t
__go_receive_small (struct __go_channel *channel, _Bool for_select) __go_receive_small_closed (struct __go_channel *channel, _Bool for_select,
_Bool *received)
{ {
uint64_t ret; uint64_t ret;
...@@ -273,11 +274,26 @@ __go_receive_small (struct __go_channel *channel, _Bool for_select) ...@@ -273,11 +274,26 @@ __go_receive_small (struct __go_channel *channel, _Bool for_select)
__go_assert (channel->element_size <= sizeof (uint64_t)); __go_assert (channel->element_size <= sizeof (uint64_t));
if (!__go_receive_acquire (channel, for_select)) if (!__go_receive_acquire (channel, for_select))
{
if (received != NULL)
*received = 0;
return 0; return 0;
}
ret = channel->data[channel->next_fetch]; ret = channel->data[channel->next_fetch];
__go_receive_release (channel); __go_receive_release (channel);
if (received != NULL)
*received = 1;
return ret; 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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment