From 3e68d6d75a599806335a90b73b8c0e404c1fc021 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 1 Dec 2011 08:06:16 +0000 Subject: [PATCH] compiler/runtime: Copy channel implementation from master library. From-SVN: r181874 --- gcc/go/gofrontend/expressions.cc | 9 +- gcc/go/gofrontend/expressions.h | 9 +- gcc/go/gofrontend/gogo-tree.cc | 27 +- gcc/go/gofrontend/gogo.h | 7 +- gcc/go/gofrontend/parse.cc | 2 - gcc/go/gofrontend/runtime.cc | 16 - gcc/go/gofrontend/runtime.def | 50 +- gcc/go/gofrontend/runtime.h | 5 - gcc/go/gofrontend/statements.cc | 544 ++++++------- gcc/go/gofrontend/statements.h | 83 +- libgo/Makefile.am | 16 +- libgo/Makefile.in | 182 +---- libgo/runtime/chan.c | 1248 ++++++++++++++++++++++++++++++ libgo/runtime/chan.goc | 57 -- libgo/runtime/channel.h | 152 ---- libgo/runtime/go-chan-cap.c | 41 - libgo/runtime/go-chan-len.c | 41 - libgo/runtime/go-close.c | 42 - libgo/runtime/go-new-channel.c | 70 -- libgo/runtime/go-rec-big.c | 43 - libgo/runtime/go-rec-nb-big.c | 46 -- libgo/runtime/go-rec-nb-small.c | 123 --- libgo/runtime/go-rec-small.c | 304 -------- libgo/runtime/go-reflect-chan.c | 200 ----- libgo/runtime/go-select.c | 758 ------------------ libgo/runtime/go-send-big.c | 34 - libgo/runtime/go-send-nb-big.c | 33 - libgo/runtime/go-send-nb-small.c | 107 --- libgo/runtime/go-send-small.c | 159 ---- libgo/runtime/runtime.h | 8 +- 30 files changed, 1621 insertions(+), 2795 deletions(-) create mode 100644 libgo/runtime/chan.c delete mode 100644 libgo/runtime/chan.goc delete mode 100644 libgo/runtime/channel.h delete mode 100644 libgo/runtime/go-chan-cap.c delete mode 100644 libgo/runtime/go-chan-len.c delete mode 100644 libgo/runtime/go-close.c delete mode 100644 libgo/runtime/go-new-channel.c delete mode 100644 libgo/runtime/go-rec-big.c delete mode 100644 libgo/runtime/go-rec-nb-big.c delete mode 100644 libgo/runtime/go-rec-nb-small.c delete mode 100644 libgo/runtime/go-rec-small.c delete mode 100644 libgo/runtime/go-reflect-chan.c delete mode 100644 libgo/runtime/go-select.c delete mode 100644 libgo/runtime/go-send-big.c delete mode 100644 libgo/runtime/go-send-nb-big.c delete mode 100644 libgo/runtime/go-send-nb-small.c delete mode 100644 libgo/runtime/go-send-small.c diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index a2cf33eb67b..a80c82375ce 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -13493,12 +13493,18 @@ Receive_expression::do_check_types(Gogo*) tree Receive_expression::do_get_tree(Translate_context* context) { + Location loc = this->location(); + Channel_type* channel_type = this->channel_->type()->channel_type(); if (channel_type == NULL) { go_assert(this->channel_->type()->is_error()); return error_mark_node; } + + Expression* td = Expression::make_type_descriptor(channel_type, loc); + tree td_tree = td->get_tree(context); + Type* element_type = channel_type->element_type(); Btype* element_type_btype = element_type->get_backend(context->gogo()); tree element_type_tree = type_to_tree(element_type_btype); @@ -13507,8 +13513,7 @@ Receive_expression::do_get_tree(Translate_context* context) if (element_type_tree == error_mark_node || channel == error_mark_node) return error_mark_node; - return Gogo::receive_from_channel(element_type_tree, channel, - this->for_select_, this->location()); + return Gogo::receive_from_channel(element_type_tree, td_tree, channel, loc); } // Dump ast representation for a receive expression. diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 74d1281e17c..6da507b57ca 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -1947,7 +1947,7 @@ class Receive_expression : public Expression public: Receive_expression(Expression* channel, Location location) : Expression(EXPRESSION_RECEIVE, location), - channel_(channel), for_select_(false) + channel_(channel) { } // Return the channel. @@ -1955,11 +1955,6 @@ class Receive_expression : public Expression channel() { return this->channel_; } - // Note that this is for a select statement. - void - set_for_select() - { this->for_select_ = true; } - protected: int do_traverse(Traverse* traverse) @@ -1998,8 +1993,6 @@ class Receive_expression : public Expression private: // The channel from which we are receiving. Expression* channel_; - // Whether this is for a select statement. - bool for_select_; }; #endif // !defined(GO_EXPRESSIONS_H) diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index 0e77f5dcd61..dd66a7f6832 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -2201,13 +2201,12 @@ Gogo::runtime_error(int code, Location location) } // Return a tree for receiving a value of type TYPE_TREE on CHANNEL. -// This does a blocking receive and returns the value read from the -// channel. If FOR_SELECT is true, this is being done because it was -// chosen in a select statement. +// TYPE_DESCRIPTOR_TREE is the channel's type descriptor. This does a +// blocking receive and returns the value read from the channel. tree -Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select, - Location location) +Gogo::receive_from_channel(tree type_tree, tree type_descriptor_tree, + tree channel, Location location) { if (type_tree == error_mark_node || channel == error_mark_node) return error_mark_node; @@ -2222,12 +2221,10 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select, "__go_receive_small", 2, uint64_type_node, + TREE_TYPE(type_descriptor_tree), + type_descriptor_tree, ptr_type_node, - channel, - boolean_type_node, - (for_select - ? boolean_true_node - : boolean_false_node)); + channel); if (call == error_mark_node) return error_mark_node; // This can panic if there are too many operations on a closed @@ -2253,15 +2250,13 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select, location, "__go_receive_big", 3, - boolean_type_node, + void_type_node, + TREE_TYPE(type_descriptor_tree), + type_descriptor_tree, ptr_type_node, channel, ptr_type_node, - tmpaddr, - boolean_type_node, - (for_select - ? boolean_true_node - : boolean_false_node)); + tmpaddr); if (call == error_mark_node) return error_mark_node; // This can panic if there are too many operations on a closed diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 9d3b37ae857..6efce18cfac 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -527,14 +527,9 @@ class Gogo // Receive a value from a channel. static tree - receive_from_channel(tree type_tree, tree channel, bool for_select, + receive_from_channel(tree type_tree, tree type_descriptor_tree, tree channel, Location); - // Return a tree for receiving an integer on a channel. - static tree - receive_as_64bit_integer(tree type, tree channel, bool blocking, - bool for_select); - // Make a trampoline which calls FNADDR passing CLOSURE. tree make_trampoline(tree fnaddr, tree closure, Location); diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 62288687662..37a97825bcd 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -1780,7 +1780,6 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type, Statement* s = Statement::make_tuple_receive_assignment(val_var, received_var, receive->channel(), - false, location); if (!this->gogo_->in_global_scope()) @@ -3769,7 +3768,6 @@ Parse::tuple_assignment(Expression_list* lhs, Range_clause* p_range_clause) Expression* channel = receive->channel(); Statement* s = Statement::make_tuple_receive_assignment(val, success, channel, - false, location); this->gogo_->add_statement(s); } diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc index 42f1e787a8f..bffefbb0513 100644 --- a/gcc/go/gofrontend/runtime.cc +++ b/gcc/go/gofrontend/runtime.cc @@ -54,8 +54,6 @@ enum Runtime_function_type RFT_MAPITER, // Go type chan any, C type struct __go_channel *. RFT_CHAN, - // Go type *chan any, C type struct __go_channel **. - RFT_CHANPTR, // Go type non-empty interface, C type struct __go_interface. RFT_IFACE, // Go type interface{}, C type struct __go_empty_interface. @@ -148,10 +146,6 @@ runtime_function_type(Runtime_function_type bft) t = Type::make_channel_type(true, true, Type::make_void_type()); break; - case RFT_CHANPTR: - t = Type::make_pointer_type(runtime_function_type(RFT_CHAN)); - break; - case RFT_IFACE: { Typed_identifier_list* methods = new Typed_identifier_list(); @@ -223,7 +217,6 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e, case RFT_SLICE: case RFT_MAP: case RFT_CHAN: - case RFT_CHANPTR: case RFT_IFACE: case RFT_EFACE: return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc); @@ -393,12 +386,3 @@ Runtime::map_iteration_type() return Type::make_array_type(runtime_function_type(RFT_POINTER), iexpr); } - -// Return the type used to pass a list of general channels to the -// select runtime function. - -Type* -Runtime::chanptr_type() -{ - return runtime_function_type(RFT_CHANPTR); -} diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index d742e5b0c79..fe842c93b9b 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -121,31 +121,44 @@ DEF_GO_RUNTIME(CHAN_LEN, "__go_chan_len", P1(CHAN), R1(INT)) DEF_GO_RUNTIME(CHAN_CAP, "__go_chan_cap", P1(CHAN), R1(INT)) // Send a small value on a channel. -DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(CHAN, UINT64, BOOL), R0()) - -// Send a small value on a channel without blocking. -DEF_GO_RUNTIME(SEND_NONBLOCKING_SMALL, "__go_send_nonblocking_small", - P2(CHAN, UINT64), R1(BOOL)) +DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(TYPE, CHAN, UINT64), R0()) // Send a big value on a channel. -DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(CHAN, POINTER, BOOL), R0()) - -// Send a big value on a channel without blocking. -DEF_GO_RUNTIME(SEND_NONBLOCKING_BIG, "__go_send_nonblocking_big", - P2(CHAN, POINTER), R1(BOOL)) +DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(TYPE, CHAN, POINTER), R0()) // Receive a small value from a channel. -DEF_GO_RUNTIME(RECEIVE_SMALL, "__go_receive_small", P2(CHAN, BOOL), R1(UINT64)) +DEF_GO_RUNTIME(RECEIVE_SMALL, "__go_receive_small", P2(TYPE, CHAN), R1(UINT64)) // Receive a big value from a channel. -DEF_GO_RUNTIME(RECEIVE_BIG, "__go_receive_big", P3(CHAN, POINTER, BOOL), - R1(BOOL)) +DEF_GO_RUNTIME(RECEIVE_BIG, "__go_receive_big", P3(TYPE, CHAN, POINTER), R0()) // Receive a value from a channel returning whether it is closed. -DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P2(CHAN, POINTER), R1(BOOL)) +DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P3(TYPE, CHAN, POINTER), + R1(BOOL)) + + +// Start building a select statement. +DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P1(INT), R1(POINTER)) -// Receive a value from a channel returning whether it is closed, for select. -DEF_GO_RUNTIME(CHANRECV3, "runtime.chanrecv3", P2(CHAN, POINTER), R1(BOOL)) +// Add a default clause to a select statement. +DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault", P2(POINTER, INT), R0()) + +// Add a send clause to a select statement. +DEF_GO_RUNTIME(SELECTSEND, "runtime.selectsend", + P4(POINTER, CHAN, POINTER, INT), R0()) + +// Add a receive clause to a select statement, for a clause which does +// not check whether the channel is closed. +DEF_GO_RUNTIME(SELECTRECV, "runtime.selectrecv", + P4(POINTER, CHAN, POINTER, INT), R0()) + +// Add a receive clause to a select statement, for a clause which does +// check whether the channel is closed. +DEF_GO_RUNTIME(SELECTRECV2, "runtime.selectrecv2", + P5(POINTER, CHAN, POINTER, BOOLPTR, INT), R0()) + +// Run a select, returning the index of the selected clause. +DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P1(POINTER), R1(INT)) // Panic. @@ -213,11 +226,6 @@ DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0()) DEF_GO_RUNTIME(DEFER, "__go_defer", P3(BOOLPTR, FUNC_PTR, POINTER), R0()) -// Run a select statement. -DEF_GO_RUNTIME(SELECT, "__go_select", P4(UINTPTR, BOOL, CHANPTR, BOOLPTR), - R1(UINTPTR)) - - // Convert an empty interface to an empty interface, returning ok. DEF_GO_RUNTIME(IFACEE2E2, "runtime.ifaceE2E2", P1(EFACE), R2(EFACE, BOOL)) diff --git a/gcc/go/gofrontend/runtime.h b/gcc/go/gofrontend/runtime.h index 3cd40348cbe..be5dcbe25d0 100644 --- a/gcc/go/gofrontend/runtime.h +++ b/gcc/go/gofrontend/runtime.h @@ -43,11 +43,6 @@ class Runtime static Type* map_iteration_type(); - // Return the type used to pass a list of general channels to the - // select runtime function. - static Type* - chanptr_type(); - private: static Named_object* runtime_declaration(Function); diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 835a0cca239..964b394c3bd 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -1329,10 +1329,9 @@ class Tuple_receive_assignment_statement : public Statement { public: Tuple_receive_assignment_statement(Expression* val, Expression* closed, - Expression* channel, bool for_select, - Location location) + Expression* channel, Location location) : Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location), - val_(val), closed_(closed), channel_(channel), for_select_(for_select) + val_(val), closed_(closed), channel_(channel) { } protected: @@ -1360,8 +1359,6 @@ class Tuple_receive_assignment_statement : public Statement Expression* closed_; // The channel on which we receive the value. Expression* channel_; - // Whether this is for a select statement. - bool for_select_; }; // Traversal. @@ -1414,14 +1411,14 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*, Statement::make_temporary(Type::lookup_bool_type(), NULL, loc); b->add_statement(closed_temp); - // closed_temp = chanrecv[23](channel, &val_temp) + // closed_temp = chanrecv2(type, channel, &val_temp) + Expression* td = Expression::make_type_descriptor(this->channel_->type(), + loc); Temporary_reference_expression* ref = Expression::make_temporary_reference(val_temp, loc); Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc); - Expression* call = Runtime::make_call((this->for_select_ - ? Runtime::CHANRECV3 - : Runtime::CHANRECV2), - loc, 2, this->channel_, p2); + Expression* call = Runtime::make_call(Runtime::CHANRECV2, + loc, 3, td, this->channel_, p2); ref = Expression::make_temporary_reference(closed_temp, loc); ref->set_is_lvalue(); Statement* s = Statement::make_assignment(ref, call, loc); @@ -1460,11 +1457,10 @@ Tuple_receive_assignment_statement::do_dump_statement( Statement* Statement::make_tuple_receive_assignment(Expression* val, Expression* closed, Expression* channel, - bool for_select, Location location) { return new Tuple_receive_assignment_statement(val, closed, channel, - for_select, location); + location); } // An assignment to a pair of values from a type guard. This is a @@ -4391,9 +4387,11 @@ Send_statement::do_get_backend(Translate_context* context) && val->temporary_reference_expression() == NULL) can_take_address = false; + Expression* td = Expression::make_type_descriptor(this->channel_->type(), + loc); + Runtime::Function code; Bstatement* btemp = NULL; - Expression* call; if (is_small) { // Type is small enough to handle as uint64. @@ -4421,8 +4419,7 @@ Send_statement::do_get_backend(Translate_context* context) btemp = temp->get_backend(context); } - call = Runtime::make_call(code, loc, 3, this->channel_, val, - Expression::make_boolean(this->for_select_, loc)); + Expression* call = Runtime::make_call(code, loc, 3, td, this->channel_, val); context->gogo()->lower_expression(context->function(), NULL, &call); Bexpression* bcall = tree_to_expr(call->get_tree(context)); @@ -4490,134 +4487,178 @@ Select_clauses::Select_clause::traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } -// Lowering. Here we pull out the channel and the send values, to -// enforce the order of evaluation. We also add explicit send and -// receive statements to the clauses. +// Lowering. We call a function to register this clause, and arrange +// to set any variables in any receive clause. void Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, - Block* b) + Block* b, Temporary_statement* sel) { + Location loc = this->location_; + + Expression* selref = Expression::make_temporary_reference(sel, loc); + + mpz_t ival; + mpz_init_set_ui(ival, this->index_); + Expression* index_expr = Expression::make_integer(&ival, NULL, loc); + mpz_clear(ival); + if (this->is_default_) { go_assert(this->channel_ == NULL && this->val_ == NULL); + this->lower_default(b, selref, index_expr); this->is_lowered_ = true; return; } - Location loc = this->location_; - // Evaluate the channel before the select statement. Temporary_statement* channel_temp = Statement::make_temporary(NULL, this->channel_, loc); b->add_statement(channel_temp); - this->channel_ = Expression::make_temporary_reference(channel_temp, loc); - - // If this is a send clause, evaluate the value to send before the - // select statement. - Temporary_statement* val_temp = NULL; - if (this->is_send_ && !this->val_->is_constant()) - { - val_temp = Statement::make_temporary(NULL, this->val_, loc); - b->add_statement(val_temp); - } + Expression* chanref = Expression::make_temporary_reference(channel_temp, + loc); - // Add the send or receive before the rest of the statements if any. - Block *init = new Block(b, loc); - Expression* ref = Expression::make_temporary_reference(channel_temp, loc); if (this->is_send_) - { - Expression* ref2; - if (val_temp == NULL) - ref2 = this->val_; - else - ref2 = Expression::make_temporary_reference(val_temp, loc); - Send_statement* send = Statement::make_send_statement(ref, ref2, loc); - send->set_for_select(); - init->add_statement(send); - } - else if (this->closed_ != NULL && !this->closed_->is_sink_expression()) - { - go_assert(this->var_ == NULL && this->closedvar_ == NULL); - if (this->val_ == NULL) - this->val_ = Expression::make_sink(loc); - Statement* s = Statement::make_tuple_receive_assignment(this->val_, - this->closed_, - ref, true, loc); - init->add_statement(s); - } - else if (this->closedvar_ != NULL) - { - go_assert(this->val_ == NULL); - Expression* val; - if (this->var_ == NULL) - val = Expression::make_sink(loc); - else - val = Expression::make_var_reference(this->var_, loc); - Expression* closed = Expression::make_var_reference(this->closedvar_, - loc); - Statement* s = Statement::make_tuple_receive_assignment(val, closed, ref, - true, loc); + this->lower_send(b, selref, chanref, index_expr); + else + this->lower_recv(gogo, function, b, selref, chanref, index_expr); - // We have to put S in STATEMENTS_, because that is where the - // variables are declared. + // Now all references should be handled through the statements, not + // through here. + this->is_lowered_ = true; + this->val_ = NULL; + this->var_ = NULL; +} - go_assert(this->statements_ != NULL); +// Lower a default clause in a select statement. - // Skip the variable declaration statements themselves. - size_t skip = 1; - if (this->var_ != NULL) - skip = 2; +void +Select_clauses::Select_clause::lower_default(Block* b, Expression* selref, + Expression* index_expr) +{ + Location loc = this->location_; + Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 2, selref, + index_expr); + b->add_statement(Statement::make_statement(call, true)); +} - // Verify that we are only skipping variable declarations. - size_t i = 0; - for (Block::iterator p = this->statements_->begin(); - i < skip && p != this->statements_->end(); - ++p, ++i) - go_assert((*p)->variable_declaration_statement() != NULL); +// Lower a send clause in a select statement. - this->statements_->insert_statement_before(skip, s); +void +Select_clauses::Select_clause::lower_send(Block* b, Expression* selref, + Expression* chanref, + Expression* index_expr) +{ + Location loc = this->location_; - // We have to lower STATEMENTS_ again, to lower the tuple - // receive assignment we just added. - gogo->lower_block(function, this->statements_); - } + Channel_type* ct = this->channel_->type()->channel_type(); + if (ct == NULL) + return; + + Type* valtype = ct->element_type(); + + // Note that copying the value to a temporary here means that we + // evaluate the send values in the required order. + Temporary_statement* val = Statement::make_temporary(valtype, this->val_, + loc); + b->add_statement(val); + + Expression* valref = Expression::make_temporary_reference(val, loc); + Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc); + + Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 4, selref, + chanref, valaddr, index_expr); + b->add_statement(Statement::make_statement(call, true)); +} + +// Lower a receive clause in a select statement. + +void +Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, + Block* b, Expression* selref, + Expression* chanref, + Expression* index_expr) +{ + Location loc = this->location_; + + Channel_type* ct = this->channel_->type()->channel_type(); + if (ct == NULL) + return; + + Type* valtype = ct->element_type(); + Temporary_statement* val = Statement::make_temporary(valtype, NULL, loc); + b->add_statement(val); + + Expression* valref = Expression::make_temporary_reference(val, loc); + Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc); + + Temporary_statement* closed_temp = NULL; + + Expression* call; + if (this->closed_ == NULL && this->closedvar_ == NULL) + call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref, chanref, + valaddr, index_expr); else { - Receive_expression* recv = Expression::make_receive(ref, loc); - recv->set_for_select(); - if (this->val_ != NULL) - { - go_assert(this->var_ == NULL); - init->add_statement(Statement::make_assignment(this->val_, recv, - loc)); - } - else if (this->var_ != NULL) - { - this->var_->var_value()->set_init(recv); - this->var_->var_value()->clear_type_from_chan_element(); - } - else - { - init->add_statement(Statement::make_statement(recv, true)); - } + closed_temp = Statement::make_temporary(Type::lookup_bool_type(), NULL, + loc); + b->add_statement(closed_temp); + Expression* cref = Expression::make_temporary_reference(closed_temp, + loc); + Expression* caddr = Expression::make_unary(OPERATOR_AND, cref, loc); + call = Runtime::make_call(Runtime::SELECTRECV2, loc, 5, selref, chanref, + valaddr, caddr, index_expr); } - // Lower any statements we just created. - gogo->lower_block(function, init); + b->add_statement(Statement::make_statement(call, true)); - if (this->statements_ != NULL) - init->add_statement(Statement::make_block_statement(this->statements_, - loc)); + // If the block of statements is executed, arrange for the received + // value to move from VAL to the place where the statements expect + // it. - this->statements_ = init; + Block* init = NULL; - // Now all references should be handled through the statements, not - // through here. - this->is_lowered_ = true; - this->val_ = NULL; - this->var_ = NULL; + if (this->var_ != NULL) + { + go_assert(this->val_ == NULL); + valref = Expression::make_temporary_reference(val, loc); + this->var_->var_value()->set_init(valref); + this->var_->var_value()->clear_type_from_chan_element(); + } + else if (this->val_ != NULL && !this->val_->is_sink_expression()) + { + init = new Block(b, loc); + valref = Expression::make_temporary_reference(val, loc); + init->add_statement(Statement::make_assignment(this->val_, valref, loc)); + } + + if (this->closedvar_ != NULL) + { + go_assert(this->closed_ == NULL); + Expression* cref = Expression::make_temporary_reference(closed_temp, + loc); + this->closedvar_->var_value()->set_init(cref); + } + else if (this->closed_ != NULL && !this->closed_->is_sink_expression()) + { + if (init == NULL) + init = new Block(b, loc); + Expression* cref = Expression::make_temporary_reference(closed_temp, + loc); + init->add_statement(Statement::make_assignment(this->closed_, cref, + loc)); + } + + if (init != NULL) + { + gogo->lower_block(function, init); + + if (this->statements_ != NULL) + init->add_statement(Statement::make_block_statement(this->statements_, + loc)); + this->statements_ = init; + } } // Determine types. @@ -4630,6 +4671,27 @@ Select_clauses::Select_clause::determine_types() this->statements_->determine_types(); } +// Check types. + +void +Select_clauses::Select_clause::check_types() +{ + if (this->is_default_) + return; + + Channel_type* ct = this->channel_->type()->channel_type(); + if (ct == NULL) + { + error_at(this->channel_->location(), "expected channel"); + return; + } + + if (this->is_send_ && !ct->may_send()) + error_at(this->location(), "invalid send on receive-only channel"); + else if (!this->is_send_ && !ct->may_receive()) + error_at(this->location(), "invalid receive on send-only channel"); +} + // Whether this clause may fall through to the statement which follows // the overall select statement. @@ -4717,12 +4779,13 @@ Select_clauses::traverse(Traverse* traverse) // receive statements to the clauses. void -Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b) +Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b, + Temporary_statement* sel) { for (Clauses::iterator p = this->clauses_.begin(); p != this->clauses_.end(); ++p) - p->lower(gogo, function, b); + p->lower(gogo, function, b, sel); } // Determine types. @@ -4736,6 +4799,17 @@ Select_clauses::determine_types() p->determine_types(); } +// Check types. + +void +Select_clauses::check_types() +{ + for (Clauses::iterator p = this->clauses_.begin(); + p != this->clauses_.end(); + ++p) + p->check_types(); +} + // Return whether these select clauses fall through to the statement // following the overall select statement. @@ -4750,179 +4824,55 @@ Select_clauses::may_fall_through() const return false; } -// Convert to the backend representation. We build a call to -// size_t __go_select(size_t count, _Bool has_default, -// channel* channels, _Bool* is_send) -// -// There are COUNT entries in the CHANNELS and IS_SEND arrays. The -// value in the IS_SEND array is true for send, false for receive. -// __go_select returns an integer from 0 to COUNT, inclusive. A -// return of 0 means that the default case should be run; this only -// happens if HAS_DEFAULT is non-zero. Otherwise the number indicates -// the case to run. - -// FIXME: This doesn't handle channels which send interface types -// where the receiver has a static type which matches that interface. +// Convert to the backend representation. We have already accumulated +// all the select information. Now we call selectgo, which will +// return the index of the clause to execute. Bstatement* Select_clauses::get_backend(Translate_context* context, + Temporary_statement* sel, Unnamed_label *break_label, Location location) { size_t count = this->clauses_.size(); + std::vector > cases(count); + std::vector clauses(count); - Expression_list* chan_init = new Expression_list(); - chan_init->reserve(count); - - Expression_list* is_send_init = new Expression_list(); - is_send_init->reserve(count); - - Select_clause *default_clause = NULL; - - Type* runtime_chanptr_type = Runtime::chanptr_type(); - Type* runtime_chan_type = runtime_chanptr_type->points_to(); - + int i = 0; for (Clauses::iterator p = this->clauses_.begin(); p != this->clauses_.end(); - ++p) + ++p, ++i) { - if (p->is_default()) - { - default_clause = &*p; - --count; - continue; - } - - if (p->channel()->type()->channel_type() == NULL) - { - // We should have given an error in the send or receive - // statement we created via lowering. - go_assert(saw_errors()); - return context->backend()->error_statement(); - } - - Expression* c = p->channel(); - c = Expression::make_unsafe_cast(runtime_chan_type, c, p->location()); - chan_init->push_back(c); + int index = p->index(); + mpz_t ival; + mpz_init_set_ui(ival, index); + Expression* index_expr = Expression::make_integer(&ival, NULL, location); + mpz_clear(ival); + cases[i].push_back(tree_to_expr(index_expr->get_tree(context))); - is_send_init->push_back(Expression::make_boolean(p->is_send(), - p->location())); - } + Bstatement* s = p->get_statements_backend(context); + Location gloc = (p->statements() == NULL + ? p->location() + : p->statements()->end_location()); + Bstatement* g = break_label->get_goto(context, gloc); - if (chan_init->empty()) - { - go_assert(count == 0); - Bstatement* s; - Bstatement* ldef = break_label->get_definition(context); - if (default_clause != NULL) - { - // There is a default clause and no cases. Just execute the - // default clause. - s = default_clause->get_statements_backend(context); - } - else - { - // There isn't even a default clause. In this case select - // pauses forever. Call the runtime function with nils. - mpz_t zval; - mpz_init_set_ui(zval, 0); - Expression* zero = Expression::make_integer(&zval, NULL, location); - mpz_clear(zval); - Expression* default_arg = Expression::make_boolean(false, location); - Expression* nil1 = Expression::make_nil(location); - Expression* nil2 = nil1->copy(); - Expression* call = Runtime::make_call(Runtime::SELECT, location, 4, - zero, default_arg, nil1, nil2); - context->gogo()->lower_expression(context->function(), NULL, &call); - Bexpression* bcall = tree_to_expr(call->get_tree(context)); - s = context->backend()->expression_statement(bcall); - } if (s == NULL) - return ldef; - return context->backend()->compound_statement(s, ldef); + clauses[i] = g; + else + clauses[i] = context->backend()->compound_statement(s, g); } - go_assert(count > 0); - - std::vector 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 > cases; - std::vector 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 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 > *cases, - std::vector* clauses) -{ - mpz_t ival; - mpz_init_set_ui(ival, case_value); - Expression* e = Expression::make_integer(&ival, NULL, location); - mpz_clear(ival); - (*cases)[index].push_back(tree_to_expr(e->get_tree(context))); - - Bstatement* s = clause->get_statements_backend(context); - - Location gloc = (clause->statements() == NULL - ? clause->location() - : clause->statements()->end_location()); - Bstatement* g = bottom_label->get_goto(context, gloc); - - if (s == NULL) - (*clauses)[index] = g; - else - (*clauses)[index] = context->backend()->compound_statement(s, g); -} - // Dump the AST representation for select clauses. void @@ -5003,11 +4920,28 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, { if (this->is_lowered_) return this; - Block* b = new Block(enclosing, this->location()); - this->clauses_->lower(gogo, function, b); + + Location loc = this->location(); + + Block* b = new Block(enclosing, loc); + + go_assert(this->sel_ == NULL); + + mpz_t ival; + mpz_init_set_ui(ival, this->clauses_->size()); + Expression* size_expr = Expression::make_integer(&ival, NULL, loc); + mpz_clear(ival); + + Expression* call = Runtime::make_call(Runtime::NEWSELECT, loc, 1, size_expr); + + this->sel_ = Statement::make_temporary(NULL, call, loc); + b->add_statement(this->sel_); + + this->clauses_->lower(gogo, function, b, this->sel_); this->is_lowered_ = true; b->add_statement(this); - return Statement::make_block_statement(b, this->location()); + + return Statement::make_block_statement(b, loc); } // Return the backend representation for a select statement. @@ -5015,7 +4949,7 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, Bstatement* Select_statement::do_get_backend(Translate_context* context) { - return this->clauses_->get_backend(context, this->break_label(), + return this->clauses_->get_backend(context, this->sel_, this->break_label(), this->location()); } @@ -5790,7 +5724,7 @@ For_range_statement::lower_range_channel(Gogo*, Expression::make_temporary_reference(ok_temp, loc); oref->set_is_lvalue(); Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref, - false, loc); + loc); iter_init->add_statement(s); Block* then_block = new Block(iter_init, loc); diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 16914f16c37..4548ba6f56c 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -165,12 +165,10 @@ class Statement Expression* should_set, Location); // Make an assignment from a nonblocking receive to a pair of - // variables. FOR_SELECT is true is this is being created for a - // case x, ok := <-c in a select statement. + // variables. static Statement* make_tuple_receive_assignment(Expression* val, Expression* closed, - Expression* channel, bool for_select, - Location); + Expression* channel, Location); // Make an assignment from a type guard to a pair of variables. static Statement* @@ -634,14 +632,9 @@ class Send_statement : public Statement Send_statement(Expression* channel, Expression* val, Location location) : Statement(STATEMENT_SEND, location), - channel_(channel), val_(val), for_select_(false) + channel_(channel), val_(val) { } - // Note that this is for a select statement. - void - set_for_select() - { this->for_select_ = true; } - protected: int do_traverse(Traverse* traverse); @@ -663,8 +656,6 @@ class Send_statement : public Statement Expression* channel_; // The value to send. Expression* val_; - // Whether this is for a select statement. - bool for_select_; }; // Select_clauses holds the clauses of a select statement. This is @@ -693,23 +684,32 @@ class Select_clauses Named_object* var, Named_object* closedvar, bool is_default, Block* statements, Location location) { - this->clauses_.push_back(Select_clause(is_send, channel, val, closed, var, - closedvar, is_default, statements, - location)); + int index = static_cast(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 >* cases, - std::vector* clauses); - typedef std::vector Clauses; Clauses clauses_; @@ -840,7 +857,7 @@ class Select_statement : public Statement public: Select_statement(Location location) : Statement(STATEMENT_SELECT, location), - clauses_(NULL), break_label_(NULL), is_lowered_(false) + clauses_(NULL), sel_(NULL), break_label_(NULL), is_lowered_(false) { } // Add the clauses. @@ -867,6 +884,10 @@ class Select_statement : public Statement do_determine_types() { this->clauses_->determine_types(); } + void + do_check_types(Gogo*) + { this->clauses_->check_types(); } + bool do_may_fall_through() const { return this->clauses_->may_fall_through(); } @@ -880,6 +901,8 @@ class Select_statement : public Statement private: // The select clauses. Select_clauses* clauses_; + // A temporary which holds the select structure we build up at runtime. + Temporary_statement* sel_; // The break label. Unnamed_label* break_label_; // Whether this statement has been lowered. diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 5ab10a61f3d..19ce7152cf1 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -409,10 +409,7 @@ runtime_files = \ runtime/go-caller.c \ runtime/go-can-convert-interface.c \ runtime/go-cgo.c \ - runtime/go-chan-cap.c \ - runtime/go-chan-len.c \ runtime/go-check-interface.c \ - runtime/go-close.c \ runtime/go-construct-map.c \ runtime/go-convert-interface.c \ runtime/go-copy.c \ @@ -432,27 +429,16 @@ runtime_files = \ runtime/go-map-len.c \ runtime/go-map-range.c \ runtime/go-nanotime.c \ - runtime/go-new-channel.c \ runtime/go-new-map.c \ runtime/go-new.c \ runtime/go-panic.c \ runtime/go-print.c \ - runtime/go-rec-big.c \ - runtime/go-rec-nb-big.c \ - runtime/go-rec-nb-small.c \ - runtime/go-rec-small.c \ runtime/go-recover.c \ runtime/go-reflect.c \ runtime/go-reflect-call.c \ - runtime/go-reflect-chan.c \ runtime/go-reflect-map.c \ runtime/go-rune.c \ runtime/go-runtime-error.c \ - runtime/go-select.c \ - runtime/go-send-big.c \ - runtime/go-send-nb-big.c \ - runtime/go-send-nb-small.c \ - runtime/go-send-small.c \ runtime/go-setenv.c \ runtime/go-signal.c \ runtime/go-strcmp.c \ @@ -473,6 +459,7 @@ runtime_files = \ runtime/go-unsafe-newarray.c \ runtime/go-unsafe-pointer.c \ runtime/go-unwind.c \ + runtime/chan.c \ runtime/cpuprof.c \ $(runtime_lock_files) \ runtime/mcache.c \ @@ -488,7 +475,6 @@ runtime_files = \ runtime/thread.c \ runtime/yield.c \ $(rtems_task_variable_add_file) \ - chan.c \ iface.c \ malloc.c \ map.c \ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index f7c293a66cc..1a76f0b5a20 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -183,8 +183,7 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ runtime/go-assert-interface.c \ runtime/go-byte-array-to-string.c runtime/go-breakpoint.c \ runtime/go-caller.c runtime/go-can-convert-interface.c \ - runtime/go-cgo.c runtime/go-chan-cap.c runtime/go-chan-len.c \ - runtime/go-check-interface.c runtime/go-close.c \ + runtime/go-cgo.c runtime/go-check-interface.c \ runtime/go-construct-map.c runtime/go-convert-interface.c \ runtime/go-copy.c runtime/go-defer.c \ runtime/go-deferred-recover.c runtime/go-eface-compare.c \ @@ -195,17 +194,11 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ runtime/go-interface-val-compare.c runtime/go-make-slice.c \ runtime/go-map-delete.c runtime/go-map-index.c \ runtime/go-map-len.c runtime/go-map-range.c \ - runtime/go-nanotime.c runtime/go-new-channel.c \ - runtime/go-new-map.c runtime/go-new.c runtime/go-panic.c \ - runtime/go-print.c runtime/go-rec-big.c \ - runtime/go-rec-nb-big.c runtime/go-rec-nb-small.c \ - runtime/go-rec-small.c runtime/go-recover.c \ + runtime/go-nanotime.c runtime/go-new-map.c runtime/go-new.c \ + runtime/go-panic.c runtime/go-print.c runtime/go-recover.c \ runtime/go-reflect.c runtime/go-reflect-call.c \ - runtime/go-reflect-chan.c runtime/go-reflect-map.c \ - runtime/go-rune.c runtime/go-runtime-error.c \ - runtime/go-select.c runtime/go-send-big.c \ - runtime/go-send-nb-big.c runtime/go-send-nb-small.c \ - runtime/go-send-small.c runtime/go-setenv.c \ + runtime/go-reflect-map.c runtime/go-rune.c \ + runtime/go-runtime-error.c runtime/go-setenv.c \ runtime/go-signal.c runtime/go-strcmp.c \ runtime/go-string-to-byte-array.c \ runtime/go-string-to-int-array.c runtime/go-strplus.c \ @@ -215,15 +208,15 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ runtime/go-type-string.c runtime/go-typedesc-equal.c \ runtime/go-typestring.c runtime/go-unreflect.c \ runtime/go-unsafe-new.c runtime/go-unsafe-newarray.c \ - runtime/go-unsafe-pointer.c runtime/go-unwind.c \ + runtime/go-unsafe-pointer.c runtime/go-unwind.c runtime/chan.c \ runtime/cpuprof.c runtime/lock_sema.c runtime/thread-sema.c \ runtime/lock_futex.c runtime/thread-linux.c runtime/mcache.c \ runtime/mcentral.c runtime/mem_posix_memalign.c runtime/mem.c \ runtime/mfinal.c runtime/mfixalloc.c runtime/mgc0.c \ runtime/mheap.c runtime/msize.c runtime/proc.c \ runtime/runtime.c runtime/thread.c runtime/yield.c \ - runtime/rtems-task-variable-add.c chan.c iface.c malloc.c \ - map.c mprof.c reflect.c runtime1.c sema.c sigqueue.c string.c + runtime/rtems-task-variable-add.c iface.c malloc.c map.c \ + mprof.c reflect.c runtime1.c sema.c sigqueue.c string.c @LIBGO_IS_LINUX_FALSE@am__objects_1 = lock_sema.lo thread-sema.lo @LIBGO_IS_LINUX_TRUE@am__objects_1 = lock_futex.lo thread-linux.lo @HAVE_SYS_MMAN_H_FALSE@am__objects_2 = mem_posix_memalign.lo @@ -231,8 +224,7 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ @LIBGO_IS_RTEMS_TRUE@am__objects_3 = rtems-task-variable-add.lo am__objects_4 = go-append.lo go-assert.lo go-assert-interface.lo \ go-byte-array-to-string.lo go-breakpoint.lo go-caller.lo \ - go-can-convert-interface.lo go-cgo.lo go-chan-cap.lo \ - go-chan-len.lo go-check-interface.lo go-close.lo \ + go-can-convert-interface.lo go-cgo.lo go-check-interface.lo \ go-construct-map.lo go-convert-interface.lo go-copy.lo \ go-defer.lo go-deferred-recover.lo go-eface-compare.lo \ go-eface-val-compare.lo go-getgoroot.lo \ @@ -240,23 +232,20 @@ am__objects_4 = go-append.lo go-assert.lo go-assert-interface.lo \ go-interface-compare.lo go-interface-eface-compare.lo \ go-interface-val-compare.lo go-make-slice.lo go-map-delete.lo \ go-map-index.lo go-map-len.lo go-map-range.lo go-nanotime.lo \ - go-new-channel.lo go-new-map.lo go-new.lo go-panic.lo \ - go-print.lo go-rec-big.lo go-rec-nb-big.lo go-rec-nb-small.lo \ - go-rec-small.lo go-recover.lo go-reflect.lo go-reflect-call.lo \ - go-reflect-chan.lo go-reflect-map.lo go-rune.lo \ - go-runtime-error.lo go-select.lo go-send-big.lo \ - go-send-nb-big.lo go-send-nb-small.lo go-send-small.lo \ - go-setenv.lo go-signal.lo go-strcmp.lo \ + go-new-map.lo go-new.lo go-panic.lo go-print.lo go-recover.lo \ + go-reflect.lo go-reflect-call.lo go-reflect-map.lo go-rune.lo \ + go-runtime-error.lo go-setenv.lo go-signal.lo go-strcmp.lo \ go-string-to-byte-array.lo go-string-to-int-array.lo \ go-strplus.lo go-strslice.lo go-trampoline.lo go-type-eface.lo \ go-type-error.lo go-type-identity.lo go-type-interface.lo \ go-type-string.lo go-typedesc-equal.lo go-typestring.lo \ go-unreflect.lo go-unsafe-new.lo go-unsafe-newarray.lo \ - go-unsafe-pointer.lo go-unwind.lo cpuprof.lo $(am__objects_1) \ - mcache.lo mcentral.lo $(am__objects_2) mfinal.lo mfixalloc.lo \ - mgc0.lo mheap.lo msize.lo proc.lo runtime.lo thread.lo \ - yield.lo $(am__objects_3) chan.lo iface.lo malloc.lo map.lo \ - mprof.lo reflect.lo runtime1.lo sema.lo sigqueue.lo string.lo + go-unsafe-pointer.lo go-unwind.lo chan.lo cpuprof.lo \ + $(am__objects_1) mcache.lo mcentral.lo $(am__objects_2) \ + mfinal.lo mfixalloc.lo mgc0.lo mheap.lo msize.lo proc.lo \ + runtime.lo thread.lo yield.lo $(am__objects_3) iface.lo \ + malloc.lo map.lo mprof.lo reflect.lo runtime1.lo sema.lo \ + sigqueue.lo string.lo am_libgo_la_OBJECTS = $(am__objects_4) libgo_la_OBJECTS = $(am_libgo_la_OBJECTS) libgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ @@ -836,10 +825,7 @@ runtime_files = \ runtime/go-caller.c \ runtime/go-can-convert-interface.c \ runtime/go-cgo.c \ - runtime/go-chan-cap.c \ - runtime/go-chan-len.c \ runtime/go-check-interface.c \ - runtime/go-close.c \ runtime/go-construct-map.c \ runtime/go-convert-interface.c \ runtime/go-copy.c \ @@ -859,27 +845,16 @@ runtime_files = \ runtime/go-map-len.c \ runtime/go-map-range.c \ runtime/go-nanotime.c \ - runtime/go-new-channel.c \ runtime/go-new-map.c \ runtime/go-new.c \ runtime/go-panic.c \ runtime/go-print.c \ - runtime/go-rec-big.c \ - runtime/go-rec-nb-big.c \ - runtime/go-rec-nb-small.c \ - runtime/go-rec-small.c \ runtime/go-recover.c \ runtime/go-reflect.c \ runtime/go-reflect-call.c \ - runtime/go-reflect-chan.c \ runtime/go-reflect-map.c \ runtime/go-rune.c \ runtime/go-runtime-error.c \ - runtime/go-select.c \ - runtime/go-send-big.c \ - runtime/go-send-nb-big.c \ - runtime/go-send-nb-small.c \ - runtime/go-send-small.c \ runtime/go-setenv.c \ runtime/go-signal.c \ runtime/go-strcmp.c \ @@ -900,6 +875,7 @@ runtime_files = \ runtime/go-unsafe-newarray.c \ runtime/go-unsafe-pointer.c \ runtime/go-unwind.c \ + runtime/chan.c \ runtime/cpuprof.c \ $(runtime_lock_files) \ runtime/mcache.c \ @@ -915,7 +891,6 @@ runtime_files = \ runtime/thread.c \ runtime/yield.c \ $(rtems_task_variable_add_file) \ - chan.c \ iface.c \ malloc.c \ map.c \ @@ -2461,10 +2436,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-caller.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-can-convert-interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-cgo.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-chan-cap.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-chan-len.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-check-interface.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-close.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-construct-map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-convert-interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-copy.Plo@am__quote@ @@ -2485,27 +2457,16 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-len.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-range.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-nanotime.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-channel.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-panic.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-print.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-big.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-nb-big.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-nb-small.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-small.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-recover.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-call.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-chan.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rune.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-runtime-error.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-select.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-big.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-nb-big.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-nb-small.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-small.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-setenv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-signal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strcmp.Plo@am__quote@ @@ -2645,20 +2606,6 @@ go-cgo.lo: runtime/go-cgo.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-cgo.lo `test -f 'runtime/go-cgo.c' || echo '$(srcdir)/'`runtime/go-cgo.c -go-chan-cap.lo: runtime/go-chan-cap.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-chan-cap.lo -MD -MP -MF $(DEPDIR)/go-chan-cap.Tpo -c -o go-chan-cap.lo `test -f 'runtime/go-chan-cap.c' || echo '$(srcdir)/'`runtime/go-chan-cap.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-chan-cap.Tpo $(DEPDIR)/go-chan-cap.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-chan-cap.c' object='go-chan-cap.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-chan-cap.lo `test -f 'runtime/go-chan-cap.c' || echo '$(srcdir)/'`runtime/go-chan-cap.c - -go-chan-len.lo: runtime/go-chan-len.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-chan-len.lo -MD -MP -MF $(DEPDIR)/go-chan-len.Tpo -c -o go-chan-len.lo `test -f 'runtime/go-chan-len.c' || echo '$(srcdir)/'`runtime/go-chan-len.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-chan-len.Tpo $(DEPDIR)/go-chan-len.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-chan-len.c' object='go-chan-len.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-chan-len.lo `test -f 'runtime/go-chan-len.c' || echo '$(srcdir)/'`runtime/go-chan-len.c - go-check-interface.lo: runtime/go-check-interface.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-check-interface.lo -MD -MP -MF $(DEPDIR)/go-check-interface.Tpo -c -o go-check-interface.lo `test -f 'runtime/go-check-interface.c' || echo '$(srcdir)/'`runtime/go-check-interface.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-check-interface.Tpo $(DEPDIR)/go-check-interface.Plo @@ -2666,13 +2613,6 @@ go-check-interface.lo: runtime/go-check-interface.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-check-interface.lo `test -f 'runtime/go-check-interface.c' || echo '$(srcdir)/'`runtime/go-check-interface.c -go-close.lo: runtime/go-close.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-close.lo -MD -MP -MF $(DEPDIR)/go-close.Tpo -c -o go-close.lo `test -f 'runtime/go-close.c' || echo '$(srcdir)/'`runtime/go-close.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-close.Tpo $(DEPDIR)/go-close.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-close.c' object='go-close.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-close.lo `test -f 'runtime/go-close.c' || echo '$(srcdir)/'`runtime/go-close.c - go-construct-map.lo: runtime/go-construct-map.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-construct-map.lo -MD -MP -MF $(DEPDIR)/go-construct-map.Tpo -c -o go-construct-map.lo `test -f 'runtime/go-construct-map.c' || echo '$(srcdir)/'`runtime/go-construct-map.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-construct-map.Tpo $(DEPDIR)/go-construct-map.Plo @@ -2806,13 +2746,6 @@ go-nanotime.lo: runtime/go-nanotime.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-nanotime.lo `test -f 'runtime/go-nanotime.c' || echo '$(srcdir)/'`runtime/go-nanotime.c -go-new-channel.lo: runtime/go-new-channel.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-channel.lo -MD -MP -MF $(DEPDIR)/go-new-channel.Tpo -c -o go-new-channel.lo `test -f 'runtime/go-new-channel.c' || echo '$(srcdir)/'`runtime/go-new-channel.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new-channel.Tpo $(DEPDIR)/go-new-channel.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-new-channel.c' object='go-new-channel.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-new-channel.lo `test -f 'runtime/go-new-channel.c' || echo '$(srcdir)/'`runtime/go-new-channel.c - go-new-map.lo: runtime/go-new-map.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-map.lo -MD -MP -MF $(DEPDIR)/go-new-map.Tpo -c -o go-new-map.lo `test -f 'runtime/go-new-map.c' || echo '$(srcdir)/'`runtime/go-new-map.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new-map.Tpo $(DEPDIR)/go-new-map.Plo @@ -2841,34 +2774,6 @@ go-print.lo: runtime/go-print.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-print.lo `test -f 'runtime/go-print.c' || echo '$(srcdir)/'`runtime/go-print.c -go-rec-big.lo: runtime/go-rec-big.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-big.lo -MD -MP -MF $(DEPDIR)/go-rec-big.Tpo -c -o go-rec-big.lo `test -f 'runtime/go-rec-big.c' || echo '$(srcdir)/'`runtime/go-rec-big.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-big.Tpo $(DEPDIR)/go-rec-big.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-big.c' object='go-rec-big.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-big.lo `test -f 'runtime/go-rec-big.c' || echo '$(srcdir)/'`runtime/go-rec-big.c - -go-rec-nb-big.lo: runtime/go-rec-nb-big.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-nb-big.lo -MD -MP -MF $(DEPDIR)/go-rec-nb-big.Tpo -c -o go-rec-nb-big.lo `test -f 'runtime/go-rec-nb-big.c' || echo '$(srcdir)/'`runtime/go-rec-nb-big.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-nb-big.Tpo $(DEPDIR)/go-rec-nb-big.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-nb-big.c' object='go-rec-nb-big.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-nb-big.lo `test -f 'runtime/go-rec-nb-big.c' || echo '$(srcdir)/'`runtime/go-rec-nb-big.c - -go-rec-nb-small.lo: runtime/go-rec-nb-small.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-nb-small.lo -MD -MP -MF $(DEPDIR)/go-rec-nb-small.Tpo -c -o go-rec-nb-small.lo `test -f 'runtime/go-rec-nb-small.c' || echo '$(srcdir)/'`runtime/go-rec-nb-small.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-nb-small.Tpo $(DEPDIR)/go-rec-nb-small.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-nb-small.c' object='go-rec-nb-small.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-nb-small.lo `test -f 'runtime/go-rec-nb-small.c' || echo '$(srcdir)/'`runtime/go-rec-nb-small.c - -go-rec-small.lo: runtime/go-rec-small.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-small.lo -MD -MP -MF $(DEPDIR)/go-rec-small.Tpo -c -o go-rec-small.lo `test -f 'runtime/go-rec-small.c' || echo '$(srcdir)/'`runtime/go-rec-small.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-small.Tpo $(DEPDIR)/go-rec-small.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-small.c' object='go-rec-small.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-small.lo `test -f 'runtime/go-rec-small.c' || echo '$(srcdir)/'`runtime/go-rec-small.c - go-recover.lo: runtime/go-recover.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-recover.lo -MD -MP -MF $(DEPDIR)/go-recover.Tpo -c -o go-recover.lo `test -f 'runtime/go-recover.c' || echo '$(srcdir)/'`runtime/go-recover.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-recover.Tpo $(DEPDIR)/go-recover.Plo @@ -2890,13 +2795,6 @@ go-reflect-call.lo: runtime/go-reflect-call.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect-call.lo `test -f 'runtime/go-reflect-call.c' || echo '$(srcdir)/'`runtime/go-reflect-call.c -go-reflect-chan.lo: runtime/go-reflect-chan.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-chan.lo -MD -MP -MF $(DEPDIR)/go-reflect-chan.Tpo -c -o go-reflect-chan.lo `test -f 'runtime/go-reflect-chan.c' || echo '$(srcdir)/'`runtime/go-reflect-chan.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-reflect-chan.Tpo $(DEPDIR)/go-reflect-chan.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-reflect-chan.c' object='go-reflect-chan.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect-chan.lo `test -f 'runtime/go-reflect-chan.c' || echo '$(srcdir)/'`runtime/go-reflect-chan.c - go-reflect-map.lo: runtime/go-reflect-map.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-map.lo -MD -MP -MF $(DEPDIR)/go-reflect-map.Tpo -c -o go-reflect-map.lo `test -f 'runtime/go-reflect-map.c' || echo '$(srcdir)/'`runtime/go-reflect-map.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-reflect-map.Tpo $(DEPDIR)/go-reflect-map.Plo @@ -2918,41 +2816,6 @@ go-runtime-error.lo: runtime/go-runtime-error.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-runtime-error.lo `test -f 'runtime/go-runtime-error.c' || echo '$(srcdir)/'`runtime/go-runtime-error.c -go-select.lo: runtime/go-select.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-select.lo -MD -MP -MF $(DEPDIR)/go-select.Tpo -c -o go-select.lo `test -f 'runtime/go-select.c' || echo '$(srcdir)/'`runtime/go-select.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-select.Tpo $(DEPDIR)/go-select.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-select.c' object='go-select.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-select.lo `test -f 'runtime/go-select.c' || echo '$(srcdir)/'`runtime/go-select.c - -go-send-big.lo: runtime/go-send-big.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-big.lo -MD -MP -MF $(DEPDIR)/go-send-big.Tpo -c -o go-send-big.lo `test -f 'runtime/go-send-big.c' || echo '$(srcdir)/'`runtime/go-send-big.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-big.Tpo $(DEPDIR)/go-send-big.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-big.c' object='go-send-big.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-big.lo `test -f 'runtime/go-send-big.c' || echo '$(srcdir)/'`runtime/go-send-big.c - -go-send-nb-big.lo: runtime/go-send-nb-big.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-nb-big.lo -MD -MP -MF $(DEPDIR)/go-send-nb-big.Tpo -c -o go-send-nb-big.lo `test -f 'runtime/go-send-nb-big.c' || echo '$(srcdir)/'`runtime/go-send-nb-big.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-nb-big.Tpo $(DEPDIR)/go-send-nb-big.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-nb-big.c' object='go-send-nb-big.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-nb-big.lo `test -f 'runtime/go-send-nb-big.c' || echo '$(srcdir)/'`runtime/go-send-nb-big.c - -go-send-nb-small.lo: runtime/go-send-nb-small.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-nb-small.lo -MD -MP -MF $(DEPDIR)/go-send-nb-small.Tpo -c -o go-send-nb-small.lo `test -f 'runtime/go-send-nb-small.c' || echo '$(srcdir)/'`runtime/go-send-nb-small.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-nb-small.Tpo $(DEPDIR)/go-send-nb-small.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-nb-small.c' object='go-send-nb-small.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-nb-small.lo `test -f 'runtime/go-send-nb-small.c' || echo '$(srcdir)/'`runtime/go-send-nb-small.c - -go-send-small.lo: runtime/go-send-small.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-small.lo -MD -MP -MF $(DEPDIR)/go-send-small.Tpo -c -o go-send-small.lo `test -f 'runtime/go-send-small.c' || echo '$(srcdir)/'`runtime/go-send-small.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-small.Tpo $(DEPDIR)/go-send-small.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-small.c' object='go-send-small.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-small.lo `test -f 'runtime/go-send-small.c' || echo '$(srcdir)/'`runtime/go-send-small.c - go-setenv.lo: runtime/go-setenv.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-setenv.lo -MD -MP -MF $(DEPDIR)/go-setenv.Tpo -c -o go-setenv.lo `test -f 'runtime/go-setenv.c' || echo '$(srcdir)/'`runtime/go-setenv.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-setenv.Tpo $(DEPDIR)/go-setenv.Plo @@ -3093,6 +2956,13 @@ go-unwind.lo: runtime/go-unwind.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unwind.lo `test -f 'runtime/go-unwind.c' || echo '$(srcdir)/'`runtime/go-unwind.c +chan.lo: runtime/chan.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT chan.lo -MD -MP -MF $(DEPDIR)/chan.Tpo -c -o chan.lo `test -f 'runtime/chan.c' || echo '$(srcdir)/'`runtime/chan.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/chan.Tpo $(DEPDIR)/chan.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/chan.c' object='chan.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o chan.lo `test -f 'runtime/chan.c' || echo '$(srcdir)/'`runtime/chan.c + cpuprof.lo: runtime/cpuprof.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cpuprof.lo -MD -MP -MF $(DEPDIR)/cpuprof.Tpo -c -o cpuprof.lo `test -f 'runtime/cpuprof.c' || echo '$(srcdir)/'`runtime/cpuprof.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cpuprof.Tpo $(DEPDIR)/cpuprof.Plo diff --git a/libgo/runtime/chan.c b/libgo/runtime/chan.c new file mode 100644 index 00000000000..a246992c60b --- /dev/null +++ b/libgo/runtime/chan.c @@ -0,0 +1,1248 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" +#include "go-type.h" + +#define NOSELGEN 1 + +static int32 debug = 0; + +typedef struct WaitQ WaitQ; +typedef struct SudoG SudoG; +typedef struct Select Select; +typedef struct Scase Scase; + +typedef struct __go_type_descriptor Type; +typedef struct __go_channel_type ChanType; + +struct SudoG +{ + G* g; // g and selgen constitute + uint32 selgen; // a weak pointer to g + SudoG* link; + byte* elem; // data element +}; + +struct WaitQ +{ + SudoG* first; + SudoG* last; +}; + +struct Hchan +{ + uint32 qcount; // total data in the q + uint32 dataqsiz; // size of the circular q + uint16 elemsize; + bool closed; + uint8 elemalign; + uint32 sendx; // send index + uint32 recvx; // receive index + WaitQ recvq; // list of recv waiters + WaitQ sendq; // list of send waiters + Lock; +}; + +// Buffer follows Hchan immediately in memory. +// chanbuf(c, i) is pointer to the i'th slot in the buffer. +#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i)) + +enum +{ + // Scase.kind + CaseRecv, + CaseSend, + CaseDefault, +}; + +struct Scase +{ + SudoG sg; // must be first member (cast to Scase) + Hchan* chan; // chan + uint16 kind; + uint16 index; // index to return + bool* receivedp; // pointer to received bool (recv2) +}; + +struct Select +{ + uint16 tcase; // total count of scase[] + uint16 ncase; // currently filled scase[] + uint16* pollorder; // case poll order + Hchan** lockorder; // channel lock order + Scase scase[1]; // one per case (in order of appearance) +}; + +static void dequeueg(WaitQ*); +static SudoG* dequeue(WaitQ*); +static void enqueue(WaitQ*, SudoG*); + +Hchan* +runtime_makechan_c(ChanType *t, int64 hint) +{ + Hchan *c; + int32 n; + const Type *elem; + + elem = t->__element_type; + + if(hint < 0 || (int32)hint != hint || (elem->__size > 0 && (uintptr)hint > ((uintptr)-1) / elem->__size)) + runtime_panicstring("makechan: size out of range"); + + n = sizeof(*c); + + // allocate memory in one call + c = (Hchan*)runtime_mal(n + hint*elem->__size); + c->elemsize = elem->__size; + c->elemalign = elem->__align; + c->dataqsiz = hint; + + if(debug) + runtime_printf("makechan: chan=%p; elemsize=%lld; elemalign=%d; dataqsiz=%d\n", + c, (long long)elem->__size, elem->__align, c->dataqsiz); + + return c; +} + +// For reflect +// func makechan(typ *ChanType, size uint32) (chan) +uintptr reflect_makechan(ChanType *, uint32) + asm ("libgo_reflect.reflect.makechan"); + +uintptr +reflect_makechan(ChanType *t, uint32 size) +{ + void *ret; + Hchan *c; + + c = runtime_makechan_c(t, size); + ret = runtime_mal(sizeof(void*)); + __builtin_memcpy(ret, &c, sizeof(void*)); + return (uintptr)ret; +} + +// makechan(t *ChanType, hint int64) (hchan *chan any); +Hchan* +__go_new_channel(ChanType *t, uintptr hint) +{ + return runtime_makechan_c(t, hint); +} + +/* + * generic single channel send/recv + * if the bool pointer is nil, + * then the full exchange will + * occur. if pres is not nil, + * then the protocol will not + * sleep but return if it could + * not complete. + * + * sleep can wake up with g->param == nil + * when a channel involved in the sleep has + * been closed. it is easiest to loop and re-run + * the operation; we'll see that it's now closed. + */ +void +runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres) +{ + SudoG *sg; + SudoG mysg; + G* gp; + G* g; + + g = runtime_g(); + + if(c == nil) { + USED(t); + if(pres != nil) { + *pres = false; + return; + } + g->status = Gwaiting; + g->waitreason = "chan send (nil chan)"; + runtime_gosched(); + return; // not reached + } + + if(runtime_gcwaiting) + runtime_gosched(); + + if(debug) { + runtime_printf("chansend: chan=%p\n", c); + } + + runtime_lock(c); + if(c->closed) + goto closed; + + if(c->dataqsiz > 0) + goto asynch; + + sg = dequeue(&c->recvq); + if(sg != nil) { + runtime_unlock(c); + + gp = sg->g; + gp->param = sg; + if(sg->elem != nil) + runtime_memmove(sg->elem, ep, c->elemsize); + runtime_ready(gp); + + if(pres != nil) + *pres = true; + return; + } + + if(pres != nil) { + runtime_unlock(c); + *pres = false; + return; + } + + mysg.elem = ep; + mysg.g = g; + mysg.selgen = NOSELGEN; + g->param = nil; + g->status = Gwaiting; + g->waitreason = "chan send"; + enqueue(&c->sendq, &mysg); + runtime_unlock(c); + runtime_gosched(); + + if(g->param == nil) { + runtime_lock(c); + if(!c->closed) + runtime_throw("chansend: spurious wakeup"); + goto closed; + } + + return; + +asynch: + if(c->closed) + goto closed; + + if(c->qcount >= c->dataqsiz) { + if(pres != nil) { + runtime_unlock(c); + *pres = false; + return; + } + mysg.g = g; + mysg.elem = nil; + mysg.selgen = NOSELGEN; + g->status = Gwaiting; + g->waitreason = "chan send"; + enqueue(&c->sendq, &mysg); + runtime_unlock(c); + runtime_gosched(); + + runtime_lock(c); + goto asynch; + } + runtime_memmove(chanbuf(c, c->sendx), ep, c->elemsize); + if(++c->sendx == c->dataqsiz) + c->sendx = 0; + c->qcount++; + + sg = dequeue(&c->recvq); + if(sg != nil) { + gp = sg->g; + runtime_unlock(c); + runtime_ready(gp); + } else + runtime_unlock(c); + if(pres != nil) + *pres = true; + return; + +closed: + runtime_unlock(c); + runtime_panicstring("send on closed channel"); +} + + +void +runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received) +{ + SudoG *sg; + SudoG mysg; + G *gp; + G *g; + + if(runtime_gcwaiting) + runtime_gosched(); + + if(debug) + runtime_printf("chanrecv: chan=%p\n", c); + + g = runtime_g(); + + if(c == nil) { + USED(t); + if(selected != nil) { + *selected = false; + return; + } + g->status = Gwaiting; + g->waitreason = "chan receive (nil chan)"; + runtime_gosched(); + return; // not reached + } + + runtime_lock(c); + if(c->dataqsiz > 0) + goto asynch; + + if(c->closed) + goto closed; + + sg = dequeue(&c->sendq); + if(sg != nil) { + runtime_unlock(c); + + if(ep != nil) + runtime_memmove(ep, sg->elem, c->elemsize); + gp = sg->g; + gp->param = sg; + runtime_ready(gp); + + if(selected != nil) + *selected = true; + if(received != nil) + *received = true; + return; + } + + if(selected != nil) { + runtime_unlock(c); + *selected = false; + return; + } + + mysg.elem = ep; + mysg.g = g; + mysg.selgen = NOSELGEN; + g->param = nil; + g->status = Gwaiting; + g->waitreason = "chan receive"; + enqueue(&c->recvq, &mysg); + runtime_unlock(c); + runtime_gosched(); + + if(g->param == nil) { + runtime_lock(c); + if(!c->closed) + runtime_throw("chanrecv: spurious wakeup"); + goto closed; + } + + if(received != nil) + *received = true; + return; + +asynch: + if(c->qcount <= 0) { + if(c->closed) + goto closed; + + if(selected != nil) { + runtime_unlock(c); + *selected = false; + if(received != nil) + *received = false; + return; + } + mysg.g = g; + mysg.elem = nil; + mysg.selgen = NOSELGEN; + g->status = Gwaiting; + g->waitreason = "chan receive"; + enqueue(&c->recvq, &mysg); + runtime_unlock(c); + runtime_gosched(); + + runtime_lock(c); + goto asynch; + } + if(ep != nil) + runtime_memmove(ep, chanbuf(c, c->recvx), c->elemsize); + runtime_memclr(chanbuf(c, c->recvx), c->elemsize); + if(++c->recvx == c->dataqsiz) + c->recvx = 0; + c->qcount--; + + sg = dequeue(&c->sendq); + if(sg != nil) { + gp = sg->g; + runtime_unlock(c); + runtime_ready(gp); + } else + runtime_unlock(c); + + if(selected != nil) + *selected = true; + if(received != nil) + *received = true; + return; + +closed: + if(ep != nil) + runtime_memclr(ep, c->elemsize); + if(selected != nil) + *selected = true; + if(received != nil) + *received = false; + runtime_unlock(c); +} + +// The compiler generates a call to __go_send_small to send a value 8 +// bytes or smaller. +void +__go_send_small(ChanType *t, Hchan* c, uint64 val) +{ + byte b[sizeof(uint64)]; + + runtime_memclr(b, sizeof(uint64)); + __builtin_memcpy(b, &val, t->__element_type->__size); + runtime_chansend(t, c, b, nil); +} + +// The compiler generates a call to __go_send_big to send a value +// larger than 8 bytes or smaller. +void +__go_send_big(ChanType *t, Hchan* c, byte* p) +{ + runtime_chansend(t, c, p, nil); +} + +// The compiler generates a call to __go_receive_small to receive a +// value 8 bytes or smaller. +uint64 +__go_receive_small(ChanType *t, Hchan* c) +{ + union { + byte b[sizeof(uint64)]; + uint64 v; + } u; + + u.v = 0; + runtime_chanrecv(t, c, u.b, nil, nil); + return u.v; +} + +// The compiler generates a call to __go_receive_big to receive a +// value larger than 8 bytes. +void +__go_receive_big(ChanType *t, Hchan* c, byte* p) +{ + runtime_chanrecv(t, c, p, nil, nil); +} + +_Bool runtime_chanrecv2(ChanType *t, Hchan* c, byte* p) + __asm__("runtime.chanrecv2"); + +_Bool +runtime_chanrecv2(ChanType *t, Hchan* c, byte* p) +{ + bool received; + + runtime_chanrecv(t, c, p, nil, &received); + return received; +} + +// func selectnbsend(c chan any, elem any) bool +// +// compiler implements +// +// select { +// case c <- v: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if selectnbsend(c, v) { +// ... foo +// } else { +// ... bar +// } +// +_Bool +runtime_selectnbsend(ChanType *t, Hchan *c, byte *p) +{ + bool res; + + runtime_chansend(t, c, p, &res); + return res; +} + +// func selectnbrecv(elem *any, c chan any) bool +// +// compiler implements +// +// select { +// case v = <-c: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if selectnbrecv(&v, c) { +// ... foo +// } else { +// ... bar +// } +// +_Bool +runtime_selectnbrecv(ChanType *t, byte *v, Hchan *c) +{ + bool selected; + + runtime_chanrecv(t, c, v, &selected, nil); + return selected; +} + +// func selectnbrecv2(elem *any, ok *bool, c chan any) bool +// +// compiler implements +// +// select { +// case v, ok = <-c: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if c != nil && selectnbrecv2(&v, &ok, c) { +// ... foo +// } else { +// ... bar +// } +// +_Bool +runtime_selectnbrecv2(ChanType *t, byte *v, _Bool *received, Hchan *c) +{ + bool selected; + bool r; + + r = false; + runtime_chanrecv(t, c, v, &selected, received == nil ? nil : &r); + if(received != nil) + *received = r; + return selected; +} + +// For reflect: +// func chansend(c chan, val iword, nb bool) (selected bool) +// where an iword is the same word an interface value would use: +// the actual data if it fits, or else a pointer to the data. + +_Bool reflect_chansend(ChanType *, Hchan *, uintptr, _Bool) + __asm__("libgo_reflect.reflect.chansend"); + +_Bool +reflect_chansend(ChanType *t, Hchan *c, uintptr val, _Bool nb) +{ + bool selected; + bool *sp; + byte *vp; + + if(nb) { + selected = false; + sp = (bool*)&selected; + } else { + selected = true; + sp = nil; + } + if(__go_is_pointer_type(t->__element_type)) + vp = (byte*)&val; + else + vp = (byte*)val; + runtime_chansend(t, c, vp, sp); + return selected; +} + +// For reflect: +// func chanrecv(c chan, nb bool) (val iword, selected, received bool) +// where an iword is the same word an interface value would use: +// the actual data if it fits, or else a pointer to the data. + +struct chanrecv_ret +{ + uintptr val; + _Bool selected; + _Bool received; +}; + +struct chanrecv_ret reflect_chanrecv(ChanType *, Hchan *, _Bool) + __asm__("libgo_reflect.reflect.chanrecv"); + +struct chanrecv_ret +reflect_chanrecv(ChanType *t, Hchan *c, _Bool nb) +{ + struct chanrecv_ret ret; + byte *vp; + bool *sp; + bool selected; + bool received; + + if(nb) { + selected = false; + sp = &selected; + } else { + ret.selected = true; + sp = nil; + } + received = false; + if(__go_is_pointer_type(t->__element_type)) { + vp = (byte*)&ret.val; + } else { + vp = runtime_mal(t->__element_type->__size); + ret.val = (uintptr)vp; + } + runtime_chanrecv(t, c, vp, sp, &received); + if(nb) + ret.selected = selected; + ret.received = received; + return ret; +} + +static void newselect(int32, Select**); + +// newselect(size uint32) (sel *byte); + +void* runtime_newselect(int) __asm__("runtime.newselect"); + +void* +runtime_newselect(int size) +{ + Select *sel; + + newselect(size, &sel); + return (void*)sel; +} + +static void +newselect(int32 size, Select **selp) +{ + int32 n; + Select *sel; + + n = 0; + if(size > 1) + n = size-1; + + sel = runtime_mal(sizeof(*sel) + + n*sizeof(sel->scase[0]) + + size*sizeof(sel->lockorder[0]) + + size*sizeof(sel->pollorder[0])); + + sel->tcase = size; + sel->ncase = 0; + sel->pollorder = (void*)(sel->scase + size); + sel->lockorder = (void*)(sel->pollorder + size); + *selp = sel; + + if(debug) + runtime_printf("newselect s=%p size=%d\n", sel, size); +} + +// cut in half to give stack a chance to split +static void selectsend(Select *sel, Hchan *c, int index, void *elem); + +// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool); + +void runtime_selectsend(Select *, Hchan *, void *, int) + __asm__("runtime.selectsend"); + +void +runtime_selectsend(Select *sel, Hchan *c, void *elem, int index) +{ + // nil cases do not compete + if(c == nil) + return; + + selectsend(sel, c, index, elem); +} + +static void +selectsend(Select *sel, Hchan *c, int index, void *elem) +{ + int32 i; + Scase *cas; + + i = sel->ncase; + if(i >= sel->tcase) + runtime_throw("selectsend: too many cases"); + sel->ncase = i+1; + cas = &sel->scase[i]; + + cas->index = index; + cas->chan = c; + cas->kind = CaseSend; + cas->sg.elem = elem; + + if(debug) + runtime_printf("selectsend s=%p index=%d chan=%p\n", + sel, cas->index, cas->chan); +} + +// cut in half to give stack a chance to split +static void selectrecv(Select *sel, Hchan *c, int index, void *elem, bool*); + +// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); + +void runtime_selectrecv(Select *, Hchan *, void *, int) + __asm__("runtime.selectrecv"); + +void +runtime_selectrecv(Select *sel, Hchan *c, void *elem, int index) +{ + // nil cases do not compete + if(c == nil) + return; + + selectrecv(sel, c, index, elem, nil); +} + +// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool); + +void runtime_selectrecv2(Select *, Hchan *, void *, bool *, int) + __asm__("runtime.selectrecv2"); + +void +runtime_selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, int index) +{ + // nil cases do not compete + if(c == nil) + return; + + selectrecv(sel, c, index, elem, received); +} + +static void +selectrecv(Select *sel, Hchan *c, int index, void *elem, bool *received) +{ + int32 i; + Scase *cas; + + i = sel->ncase; + if(i >= sel->tcase) + runtime_throw("selectrecv: too many cases"); + sel->ncase = i+1; + cas = &sel->scase[i]; + cas->index = index; + cas->chan = c; + + cas->kind = CaseRecv; + cas->sg.elem = elem; + cas->receivedp = received; + + if(debug) + runtime_printf("selectrecv s=%p index=%d chan=%p\n", + sel, cas->index, cas->chan); +} + +// cut in half to give stack a chance to split +static void selectdefault(Select*, int); + +// selectdefault(sel *byte) (selected bool); + +void runtime_selectdefault(Select *, int) __asm__("runtime.selectdefault"); + +void +runtime_selectdefault(Select *sel, int index) +{ + selectdefault(sel, index); +} + +static void +selectdefault(Select *sel, int index) +{ + int32 i; + Scase *cas; + + i = sel->ncase; + if(i >= sel->tcase) + runtime_throw("selectdefault: too many cases"); + sel->ncase = i+1; + cas = &sel->scase[i]; + cas->index = index; + cas->chan = nil; + + cas->kind = CaseDefault; + + if(debug) + runtime_printf("selectdefault s=%p index=%d\n", + sel, cas->index); +} + +static void +sellock(Select *sel) +{ + uint32 i; + Hchan *c, *c0; + + c = nil; + for(i=0; incase; i++) { + c0 = sel->lockorder[i]; + if(c0 && c0 != c) { + c = sel->lockorder[i]; + runtime_lock(c); + } + } +} + +static void +selunlock(Select *sel) +{ + uint32 i; + Hchan *c, *c0; + + c = nil; + for(i=sel->ncase; i-->0;) { + c0 = sel->lockorder[i]; + if(c0 && c0 != c) { + c = c0; + runtime_unlock(c); + } + } +} + +void +runtime_block(void) +{ + G *g; + + g = runtime_g(); + g->status = Gwaiting; // forever + g->waitreason = "select (no cases)"; + runtime_gosched(); +} + +static int selectgo(Select**); + +// selectgo(sel *byte); + +int runtime_selectgo(Select *) __asm__("runtime.selectgo"); + +int +runtime_selectgo(Select *sel) +{ + return selectgo(&sel); +} + +static int +selectgo(Select **selp) +{ + Select *sel; + uint32 o, i, j; + Scase *cas, *dfl; + Hchan *c; + SudoG *sg; + G *gp; + int index; + G *g; + + sel = *selp; + if(runtime_gcwaiting) + runtime_gosched(); + + if(debug) + runtime_printf("select: sel=%p\n", sel); + + g = runtime_g(); + + // The compiler rewrites selects that statically have + // only 0 or 1 cases plus default into simpler constructs. + // The only way we can end up with such small sel->ncase + // values here is for a larger select in which most channels + // have been nilled out. The general code handles those + // cases correctly, and they are rare enough not to bother + // optimizing (and needing to test). + + // generate permuted order + for(i=0; incase; i++) + sel->pollorder[i] = i; + for(i=1; incase; i++) { + o = sel->pollorder[i]; + j = runtime_fastrand1()%(i+1); + sel->pollorder[i] = sel->pollorder[j]; + sel->pollorder[j] = o; + } + + // sort the cases by Hchan address to get the locking order. + for(i=0; incase; i++) { + c = sel->scase[i].chan; + for(j=i; j>0 && sel->lockorder[j-1] >= c; j--) + sel->lockorder[j] = sel->lockorder[j-1]; + sel->lockorder[j] = c; + } + sellock(sel); + +loop: + // pass 1 - look for something already waiting + dfl = nil; + for(i=0; incase; i++) { + o = sel->pollorder[i]; + cas = &sel->scase[o]; + c = cas->chan; + + switch(cas->kind) { + case CaseRecv: + if(c->dataqsiz > 0) { + if(c->qcount > 0) + goto asyncrecv; + } else { + sg = dequeue(&c->sendq); + if(sg != nil) + goto syncrecv; + } + if(c->closed) + goto rclose; + break; + + case CaseSend: + if(c->closed) + goto sclose; + if(c->dataqsiz > 0) { + if(c->qcount < c->dataqsiz) + goto asyncsend; + } else { + sg = dequeue(&c->recvq); + if(sg != nil) + goto syncsend; + } + break; + + case CaseDefault: + dfl = cas; + break; + } + } + + if(dfl != nil) { + selunlock(sel); + cas = dfl; + goto retc; + } + + + // pass 2 - enqueue on all chans + for(i=0; incase; i++) { + o = sel->pollorder[i]; + cas = &sel->scase[o]; + c = cas->chan; + sg = &cas->sg; + sg->g = g; + sg->selgen = g->selgen; + + switch(cas->kind) { + case CaseRecv: + enqueue(&c->recvq, sg); + break; + + case CaseSend: + enqueue(&c->sendq, sg); + break; + } + } + + g->param = nil; + g->status = Gwaiting; + g->waitreason = "select"; + selunlock(sel); + runtime_gosched(); + + sellock(sel); + sg = g->param; + + // pass 3 - dequeue from unsuccessful chans + // otherwise they stack up on quiet channels + for(i=0; incase; i++) { + cas = &sel->scase[i]; + if(cas != (Scase*)sg) { + c = cas->chan; + if(cas->kind == CaseSend) + dequeueg(&c->sendq); + else + dequeueg(&c->recvq); + } + } + + if(sg == nil) + goto loop; + + cas = (Scase*)sg; + c = cas->chan; + + if(c->dataqsiz > 0) + runtime_throw("selectgo: shouldnt happen"); + + if(debug) + runtime_printf("wait-return: sel=%p c=%p cas=%p kind=%d\n", + sel, c, cas, cas->kind); + + if(cas->kind == CaseRecv) { + if(cas->receivedp != nil) + *cas->receivedp = true; + } + + selunlock(sel); + goto retc; + +asyncrecv: + // can receive from buffer + if(cas->receivedp != nil) + *cas->receivedp = true; + if(cas->sg.elem != nil) + runtime_memmove(cas->sg.elem, chanbuf(c, c->recvx), c->elemsize); + runtime_memclr(chanbuf(c, c->recvx), c->elemsize); + if(++c->recvx == c->dataqsiz) + c->recvx = 0; + c->qcount--; + sg = dequeue(&c->sendq); + if(sg != nil) { + gp = sg->g; + selunlock(sel); + runtime_ready(gp); + } else { + selunlock(sel); + } + goto retc; + +asyncsend: + // can send to buffer + runtime_memmove(chanbuf(c, c->sendx), cas->sg.elem, c->elemsize); + if(++c->sendx == c->dataqsiz) + c->sendx = 0; + c->qcount++; + sg = dequeue(&c->recvq); + if(sg != nil) { + gp = sg->g; + selunlock(sel); + runtime_ready(gp); + } else { + selunlock(sel); + } + goto retc; + +syncrecv: + // can receive from sleeping sender (sg) + selunlock(sel); + if(debug) + runtime_printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o); + if(cas->receivedp != nil) + *cas->receivedp = true; + if(cas->sg.elem != nil) + runtime_memmove(cas->sg.elem, sg->elem, c->elemsize); + gp = sg->g; + gp->param = sg; + runtime_ready(gp); + goto retc; + +rclose: + // read at end of closed channel + selunlock(sel); + if(cas->receivedp != nil) + *cas->receivedp = false; + if(cas->sg.elem != nil) + runtime_memclr(cas->sg.elem, c->elemsize); + goto retc; + +syncsend: + // can send to sleeping receiver (sg) + selunlock(sel); + if(debug) + runtime_printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o); + if(sg->elem != nil) + runtime_memmove(sg->elem, cas->sg.elem, c->elemsize); + gp = sg->g; + gp->param = sg; + runtime_ready(gp); + +retc: + // return index corresponding to chosen case + index = cas->index; + runtime_free(sel); + return index; + +sclose: + // send on closed channel + selunlock(sel); + runtime_panicstring("send on closed channel"); + return 0; // not reached +} + +// closechan(sel *byte); +void +runtime_closechan(Hchan *c) +{ + SudoG *sg; + G* gp; + + if(c == nil) + runtime_panicstring("close of nil channel"); + + if(runtime_gcwaiting) + runtime_gosched(); + + runtime_lock(c); + if(c->closed) { + runtime_unlock(c); + runtime_panicstring("close of closed channel"); + } + + c->closed = true; + + // release all readers + for(;;) { + sg = dequeue(&c->recvq); + if(sg == nil) + break; + gp = sg->g; + gp->param = nil; + runtime_ready(gp); + } + + // release all writers + for(;;) { + sg = dequeue(&c->sendq); + if(sg == nil) + break; + gp = sg->g; + gp->param = nil; + runtime_ready(gp); + } + + runtime_unlock(c); +} + +void +__go_builtin_close(Hchan *c) +{ + runtime_closechan(c); +} + +// For reflect +// func chanclose(c chan) + +void reflect_chanclose(uintptr) __asm__("libgo_reflect.reflect.chanclose"); + +void +reflect_chanclose(uintptr c) +{ + runtime_closechan((Hchan*)c); +} + +// For reflect +// func chanlen(c chan) (len int32) + +int32 reflect_chanlen(uintptr) __asm__("libgo_reflect.reflect.chanlen"); + +int32 +reflect_chanlen(uintptr ca) +{ + Hchan *c; + int32 len; + + c = (Hchan*)ca; + if(c == nil) + len = 0; + else + len = c->qcount; + return len; +} + +int +__go_chan_len(Hchan *c) +{ + return reflect_chanlen((uintptr)c); +} + +// For reflect +// func chancap(c chan) (cap int32) + +int32 reflect_chancap(uintptr) __asm__("libgo_reflect.reflect.chancap"); + +int32 +reflect_chancap(uintptr ca) +{ + Hchan *c; + int32 cap; + + c = (Hchan*)ca; + if(c == nil) + cap = 0; + else + cap = c->dataqsiz; + return cap; +} + +int +__go_chan_cap(Hchan *c) +{ + return reflect_chancap((uintptr)c); +} + +static SudoG* +dequeue(WaitQ *q) +{ + SudoG *sgp; + +loop: + sgp = q->first; + if(sgp == nil) + return nil; + q->first = sgp->link; + + // if sgp is stale, ignore it + if(sgp->selgen != NOSELGEN && + (sgp->selgen != sgp->g->selgen || + !runtime_cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) { + //prints("INVALID PSEUDOG POINTER\n"); + goto loop; + } + + return sgp; +} + +static void +dequeueg(WaitQ *q) +{ + SudoG **l, *sgp, *prevsgp; + G *g; + + g = runtime_g(); + prevsgp = nil; + for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) { + if(sgp->g == g) { + *l = sgp->link; + if(q->last == sgp) + q->last = prevsgp; + break; + } + } +} + +static void +enqueue(WaitQ *q, SudoG *sgp) +{ + sgp->link = nil; + if(q->first == nil) { + q->first = sgp; + q->last = sgp; + return; + } + q->last->link = sgp; + q->last = sgp; +} diff --git a/libgo/runtime/chan.goc b/libgo/runtime/chan.goc deleted file mode 100644 index c3cc3e39879..00000000000 --- a/libgo/runtime/chan.goc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime -#include "config.h" -#include "channel.h" - -#define nil NULL - -typedef _Bool bool; -typedef unsigned char byte; -typedef struct __go_channel chan; - -/* Do a channel receive with closed status. */ - -func chanrecv2(c *chan, val *byte) (received bool) { - uintptr_t element_size = c == nil ? 0 : c->element_type->__size; - if (element_size > 8) { - return __go_receive_big(c, val, 0); - } else { - union { - char b[8]; - uint64_t v; - } u; - - u.v = __go_receive_small_closed(c, 0, &received); -#ifndef WORDS_BIGENDIAN - __builtin_memcpy(val, u.b, element_size); -#else - __builtin_memcpy(val, u.b + 8 - element_size, element_size); -#endif - return received; - } -} - -/* Do a channel receive with closed status for a select statement. */ - -func chanrecv3(c *chan, val *byte) (received bool) { - uintptr_t element_size = c->element_type->__size; - if (element_size > 8) { - return __go_receive_big(c, val, 1); - } else { - union { - char b[8]; - uint64_t v; - } u; - - u.v = __go_receive_small_closed(c, 1, &received); -#ifndef WORDS_BIGENDIAN - __builtin_memcpy(val, u.b, element_size); -#else - __builtin_memcpy(val, u.b + 8 - element_size, element_size); -#endif - return received; - } -} diff --git a/libgo/runtime/channel.h b/libgo/runtime/channel.h deleted file mode 100644 index 9176c68f692..00000000000 --- a/libgo/runtime/channel.h +++ /dev/null @@ -1,152 +0,0 @@ -/* channel.h -- the channel type for Go. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include -#include - -#include "go-type.h" - -/* This structure is used when a select is waiting for a synchronous - channel. */ - -struct __go_channel_select -{ - /* A pointer to the next select waiting for this channel. */ - struct __go_channel_select *next; - /* A pointer to the channel which this select will use. This starts - out as NULL and is set to the first channel which synchs up with - this one. This variable to which this points may only be - accessed when __go_select_data_mutex is held. */ - struct __go_channel **selected; - /* A pointer to a variable which must be set to true if the - goroutine which sets *SELECTED wants to read from the channel, - false if it wants to write to it. */ - _Bool *is_read; -}; - -/* A channel is a pointer to this structure. */ - -struct __go_channel -{ - /* A mutex to control access to the channel. */ - pthread_mutex_t lock; - /* A condition variable. This is signalled when data is added to - the channel and when data is removed from the channel. */ - pthread_cond_t cond; - /* The type of elements on this channel. */ - const struct __go_type_descriptor *element_type; - /* True if a goroutine is waiting to send on a synchronous - channel. */ - _Bool waiting_to_send; - /* True if a goroutine is waiting to receive on a synchronous - channel. */ - _Bool waiting_to_receive; - /* True if this channel was selected for send in a select statement. - This looks out all other sends. */ - _Bool selected_for_send; - /* True if this channel was selected for receive in a select - statement. This locks out all other receives. */ - _Bool selected_for_receive; - /* True if this channel has been closed. */ - _Bool is_closed; - /* The list of select statements waiting to send on a synchronous - channel. */ - struct __go_channel_select *select_send_queue; - /* The list of select statements waiting to receive on a synchronous - channel. */ - struct __go_channel_select *select_receive_queue; - /* If a select statement is waiting for this channel, it sets these - pointers. When something happens on the channel, the channel - locks the mutex, signals the condition, and unlocks the - mutex. */ - pthread_mutex_t *select_mutex; - pthread_cond_t *select_cond; - /* The number of entries in the circular buffer. */ - unsigned int num_entries; - /* Where to store the next value. */ - unsigned int next_store; - /* Where to fetch the next value. If next_fetch == next_store, the - buffer is empty. If next_store + 1 == next_fetch, the buffer is - full. */ - unsigned int next_fetch; - /* The circular buffer. */ - uint64_t data[]; -}; - -/* Try to link up with the structure generated by the frontend. */ -typedef struct __go_channel __go_channel; - -/* The mutex used to control access to the value pointed to by the - __go_channel_select selected field. No additional mutexes may be - acquired while this mutex is held. */ -extern pthread_mutex_t __go_select_data_mutex; - -extern struct __go_channel * -__go_new_channel (const struct __go_type_descriptor *, uintptr_t); - -extern _Bool __go_synch_with_select (struct __go_channel *, _Bool); - -extern void __go_broadcast_to_select (struct __go_channel *); - -extern void __go_send_acquire (struct __go_channel *, _Bool); - -extern _Bool __go_send_nonblocking_acquire (struct __go_channel *); - -extern void __go_send_release (struct __go_channel *); - -extern void __go_send_small (struct __go_channel *, uint64_t, _Bool); - -extern _Bool __go_send_nonblocking_small (struct __go_channel *, uint64_t); - -extern void __go_send_big (struct __go_channel *, const void *, _Bool); - -extern _Bool __go_send_nonblocking_big (struct __go_channel *, const void *); - -extern _Bool __go_receive_acquire (struct __go_channel *, _Bool); - -#define RECEIVE_NONBLOCKING_ACQUIRE_DATA 0 -#define RECEIVE_NONBLOCKING_ACQUIRE_NODATA 1 -#define RECEIVE_NONBLOCKING_ACQUIRE_CLOSED 2 - -extern int __go_receive_nonblocking_acquire (struct __go_channel *); - -extern uint64_t __go_receive_small (struct __go_channel *, _Bool); - -extern uint64_t __go_receive_small_closed (struct __go_channel *, _Bool, - _Bool *); - -extern void __go_receive_release (struct __go_channel *); - -struct __go_receive_nonblocking_small -{ - /* Value read from channel, or 0. */ - uint64_t __val; - /* True if value was read from channel. */ - _Bool __success; - /* True if channel is closed. */ - _Bool __closed; -}; - -extern struct __go_receive_nonblocking_small -__go_receive_nonblocking_small (struct __go_channel *); - -extern _Bool __go_receive_big (struct __go_channel *, void *, _Bool); - -extern _Bool __go_receive_nonblocking_big (struct __go_channel *, void *, - _Bool *); - -extern void __go_unlock_and_notify_selects (struct __go_channel *); - -extern _Bool __go_builtin_closed (struct __go_channel *); - -extern void __go_builtin_close (struct __go_channel *); - -extern int __go_chan_len (struct __go_channel *); - -extern int __go_chan_cap (struct __go_channel *); - -extern uintptr_t __go_select (uintptr_t, _Bool, struct __go_channel **, - _Bool *); diff --git a/libgo/runtime/go-chan-cap.c b/libgo/runtime/go-chan-cap.c deleted file mode 100644 index 2c7958dd9fc..00000000000 --- a/libgo/runtime/go-chan-cap.c +++ /dev/null @@ -1,41 +0,0 @@ -/* go-chan-cap.c -- the cap function applied to a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include - -#include "go-assert.h" -#include "channel.h" - -/* Return the cap function applied to a channel--the size of the - buffer. This could be done inline but I'm doing it as a function - for now to make it easy to change the channel structure. */ - -int -__go_chan_cap (struct __go_channel *channel) -{ - int i; - int ret; - - if (channel == NULL) - return 0; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - if (channel->num_entries == 0) - ret = 0; - else - { - /* One slot is always unused. We added 1 when we created the - channel. */ - ret = channel->num_entries - 1; - } - - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - return ret; -} diff --git a/libgo/runtime/go-chan-len.c b/libgo/runtime/go-chan-len.c deleted file mode 100644 index b3ced98aa05..00000000000 --- a/libgo/runtime/go-chan-len.c +++ /dev/null @@ -1,41 +0,0 @@ -/* go-chan-len.c -- the len function applied to a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include - -#include "go-assert.h" -#include "channel.h" - -/* Return the len function applied to a channel--the number of - elements in the buffer. This could be done inline but I'm doing it - as a function for now to make it easy to change the channel - structure. */ - -int -__go_chan_len (struct __go_channel *channel) -{ - int i; - int ret; - - if (channel == NULL) - return 0; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - if (channel->num_entries == 0) - ret = 0; - else if (channel->next_fetch == channel->next_store) - ret = 0; - else - ret = ((channel->next_store + channel->num_entries - channel->next_fetch) - % channel->num_entries); - - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - return ret; -} diff --git a/libgo/runtime/go-close.c b/libgo/runtime/go-close.c deleted file mode 100644 index 7e32286dae0..00000000000 --- a/libgo/runtime/go-close.c +++ /dev/null @@ -1,42 +0,0 @@ -/* go-close.c -- the builtin close function. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* Close a channel. After a channel is closed, sends are no longer - permitted. Receives always return zero. */ - -void -__go_builtin_close (struct __go_channel *channel) -{ - int i; - - if (channel == NULL) - runtime_panicstring ("close of nil channel"); - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (channel->selected_for_send) - runtime_cond_wait (&channel->cond, &channel->lock); - - if (channel->is_closed) - { - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - runtime_panicstring ("close of closed channel"); - } - - channel->is_closed = 1; - - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - - __go_unlock_and_notify_selects (channel); -} diff --git a/libgo/runtime/go-new-channel.c b/libgo/runtime/go-new-channel.c deleted file mode 100644 index fe13c5efab6..00000000000 --- a/libgo/runtime/go-new-channel.c +++ /dev/null @@ -1,70 +0,0 @@ -/* go-new-channel.c -- allocate a new channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include -#include - -#include "runtime.h" -#include "go-alloc.h" -#include "go-assert.h" -#include "channel.h" - -struct __go_channel* -__go_new_channel (const struct __go_type_descriptor *channel_type, - uintptr_t entries) -{ - const struct __go_channel_type *ctd; - const struct __go_type_descriptor *element_type; - uintptr_t element_size; - int ientries; - struct __go_channel* ret; - size_t alloc_size; - int i; - - __go_assert (channel_type->__code == GO_CHAN); - ctd = (const struct __go_channel_type *) channel_type; - element_type = ctd->__element_type; - - element_size = element_type->__size; - - ientries = (int) entries; - if (ientries < 0 - || (uintptr_t) ientries != entries - || (element_size > 0 && entries > (uintptr_t) -1 / element_size)) - runtime_panicstring ("chan size out of range"); - - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - /* We use a circular buffer which means that when next_fetch == - next_store we don't know whether the buffer is empty or full. So - we allocate an extra space, and always leave a space open. - FIXME. */ - if (entries != 0) - ++entries; - - ret = (struct __go_channel*) __go_alloc (sizeof (struct __go_channel) - + ((entries == 0 ? 1 : entries) - * alloc_size - * sizeof (uint64_t))); - i = pthread_mutex_init (&ret->lock, NULL); - __go_assert (i == 0); - i = pthread_cond_init (&ret->cond, NULL); - __go_assert (i == 0); - ret->element_type = element_type; - ret->waiting_to_send = 0; - ret->waiting_to_receive = 0; - ret->selected_for_send = 0; - ret->selected_for_receive = 0; - ret->is_closed = 0; - ret->select_send_queue = NULL; - ret->select_receive_queue = NULL; - ret->select_mutex = NULL; - ret->select_cond = NULL; - ret->num_entries = entries; - ret->next_store = 0; - ret->next_fetch = 0; - return ret; -} diff --git a/libgo/runtime/go-rec-big.c b/libgo/runtime/go-rec-big.c deleted file mode 100644 index d45e90af476..00000000000 --- a/libgo/runtime/go-rec-big.c +++ /dev/null @@ -1,43 +0,0 @@ -/* go-rec-big.c -- receive something larger than 64 bits on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include - -#include "go-panic.h" -#include "channel.h" - -/* Returns true if a value was received, false if the channel is - closed. */ - -_Bool -__go_receive_big (struct __go_channel *channel, void *val, _Bool for_select) -{ - uintptr_t element_size; - size_t alloc_size; - size_t offset; - - if (channel == NULL) - { - /* Block forever. */ - __go_select (0, 0, NULL, NULL); - } - - element_size = channel->element_type->__size; - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - if (!__go_receive_acquire (channel, for_select)) - { - __builtin_memset (val, 0, element_size); - return 0; - } - - offset = channel->next_fetch * alloc_size; - __builtin_memcpy (val, &channel->data[offset], element_size); - - __go_receive_release (channel); - - return 1; -} diff --git a/libgo/runtime/go-rec-nb-big.c b/libgo/runtime/go-rec-nb-big.c deleted file mode 100644 index 659ea1dc33d..00000000000 --- a/libgo/runtime/go-rec-nb-big.c +++ /dev/null @@ -1,46 +0,0 @@ -/* go-rec-nb-big.c -- nonblocking receive of something big on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include - -#include "channel.h" - -/* Return true if a value was received, false if not. */ - -_Bool -__go_receive_nonblocking_big (struct __go_channel* channel, void *val, - _Bool *closed) -{ - uintptr_t element_size; - size_t alloc_size; - size_t offset; - - if (channel == NULL) - { - if (closed != NULL) - *closed = 0; - return 0; - } - - element_size = channel->element_type->__size; - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - int data = __go_receive_nonblocking_acquire (channel); - if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA) - { - __builtin_memset (val, 0, element_size); - if (closed != NULL) - *closed = data == RECEIVE_NONBLOCKING_ACQUIRE_CLOSED; - return 0; - } - - offset = channel->next_fetch * alloc_size; - __builtin_memcpy (val, &channel->data[offset], element_size); - - __go_receive_release (channel); - - return 1; -} diff --git a/libgo/runtime/go-rec-nb-small.c b/libgo/runtime/go-rec-nb-small.c deleted file mode 100644 index c21878ce131..00000000000 --- a/libgo/runtime/go-rec-nb-small.c +++ /dev/null @@ -1,123 +0,0 @@ -/* go-rec-nb-small.c -- nonblocking receive of something smal on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* Prepare to receive something on a nonblocking channel. */ - -int -__go_receive_nonblocking_acquire (struct __go_channel *channel) -{ - int i; - _Bool has_data; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (channel->selected_for_receive) - runtime_cond_wait (&channel->cond, &channel->lock); - - if (channel->is_closed - && (channel->num_entries == 0 - ? channel->next_store == 0 - : channel->next_fetch == channel->next_store)) - { - __go_unlock_and_notify_selects (channel); - return RECEIVE_NONBLOCKING_ACQUIRE_CLOSED; - } - - if (channel->num_entries > 0) - has_data = channel->next_fetch != channel->next_store; - else - { - if (channel->waiting_to_receive) - { - /* Some other goroutine is already waiting for data on this - channel, so we can't pick it up. */ - has_data = 0; - } - else if (channel->next_store > 0) - { - /* There is data on the channel. */ - has_data = 1; - } - else if (__go_synch_with_select (channel, 0)) - { - /* We synched up with a select sending data, so there will - be data for us shortly. Tell the select to go, and then - wait for the data. */ - __go_broadcast_to_select (channel); - - while (channel->next_store == 0) - runtime_cond_wait (&channel->cond, &channel->lock); - - has_data = 1; - } - else - { - /* Otherwise there is no data. */ - has_data = 0; - } - - if (has_data) - { - channel->waiting_to_receive = 1; - __go_assert (channel->next_store == 1); - } - } - - if (!has_data) - { - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - return RECEIVE_NONBLOCKING_ACQUIRE_NODATA; - } - - return RECEIVE_NONBLOCKING_ACQUIRE_DATA; -} - -/* Receive something 64 bits or smaller on a nonblocking channel. */ - -struct __go_receive_nonblocking_small -__go_receive_nonblocking_small (struct __go_channel *channel) -{ - uintptr_t element_size; - struct __go_receive_nonblocking_small ret; - - if (channel == NULL) - { - ret.__val = 0; - ret.__success = 0; - ret.__closed = 0; - return ret; - } - - element_size = channel->element_type->__size; - __go_assert (element_size <= sizeof (uint64_t)); - - int data = __go_receive_nonblocking_acquire (channel); - if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA) - { - ret.__val = 0; - ret.__success = 0; - ret.__closed = data == RECEIVE_NONBLOCKING_ACQUIRE_CLOSED; - return ret; - } - - ret.__val = channel->data[channel->next_fetch]; - - __go_receive_release (channel); - - ret.__success = 1; - ret.__closed = 0; - - return ret; -} diff --git a/libgo/runtime/go-rec-small.c b/libgo/runtime/go-rec-small.c deleted file mode 100644 index f26dbcdd993..00000000000 --- a/libgo/runtime/go-rec-small.c +++ /dev/null @@ -1,304 +0,0 @@ -/* go-rec-small.c -- receive something smaller than 64 bits on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* This mutex controls access to the selected field of struct - __go_channel_select. While this mutex is held, no other mutexes - may be acquired. */ - -pthread_mutex_t __go_select_data_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* Try to synchronize with a select waiting on a sychronized channel. - This is used by a send or receive. The channel is locked. This - returns true if it was able to synch. */ - -_Bool -__go_synch_with_select (struct __go_channel *channel, _Bool is_send) -{ - struct __go_channel_select *p; - int i; - - __go_assert (channel->num_entries == 0); - - i = pthread_mutex_lock (&__go_select_data_mutex); - __go_assert (i == 0); - - for (p = (is_send - ? channel->select_receive_queue - : channel->select_send_queue); - p != NULL; - p = p->next) - { - if (*p->selected == NULL) - { - *p->selected = channel; - *p->is_read = !is_send; - if (is_send) - channel->selected_for_receive = 1; - else - channel->selected_for_send = 1; - break; - } - } - - i = pthread_mutex_unlock (&__go_select_data_mutex); - __go_assert (i == 0); - - /* The caller is responsible for signalling the select condition - variable so that the other select knows that something has - changed. We can't signal it here because we can't acquire the - select mutex while we hold a channel lock. */ - - return p != NULL; -} - -/* If we synch with a select, then we need to signal the select that - something has changed. This requires grabbing the select mutex, - which can only be done when the channel is unlocked. This routine - does the signalling. It is called with the channel locked. It - unlocks the channel, broadcasts the signal and relocks the - channel. */ - -void -__go_broadcast_to_select (struct __go_channel *channel) -{ - pthread_mutex_t *select_mutex; - pthread_cond_t *select_cond; - int i; - - select_mutex = channel->select_mutex; - select_cond = channel->select_cond; - - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - __go_assert (select_mutex != NULL && select_cond != NULL); - - i = pthread_mutex_lock (select_mutex); - __go_assert (i == 0); - - i = pthread_cond_broadcast (select_cond); - __go_assert (i == 0); - - i = pthread_mutex_unlock (select_mutex); - __go_assert (i == 0); - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); -} - -/* Prepare to receive something on a channel. Return true if the - channel is acquired (which implies that there is data available), - false if it is closed. */ - -_Bool -__go_receive_acquire (struct __go_channel *channel, _Bool for_select) -{ - int i; - _Bool my_wait_lock; - _Bool synched_with_select; - - my_wait_lock = 0; - synched_with_select = 0; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (1) - { - _Bool need_broadcast; - - need_broadcast = 0; - - /* Check whether the channel is closed. */ - if (channel->is_closed - && (channel->num_entries == 0 - ? channel->next_store == 0 - : channel->next_fetch == channel->next_store)) - { - channel->selected_for_receive = 0; - __go_unlock_and_notify_selects (channel); - return 0; - } - - /* If somebody else has the channel locked for receiving, we - have to wait. If FOR_SELECT is true, then we are the one - with the lock. */ - if (!channel->selected_for_receive || for_select) - { - if (channel->num_entries == 0) - { - /* If somebody else is waiting to receive, we have to - wait. */ - if (!channel->waiting_to_receive || my_wait_lock) - { - _Bool was_marked; - - /* Lock the channel so that we get to receive - next. */ - was_marked = channel->waiting_to_receive; - channel->waiting_to_receive = 1; - my_wait_lock = 1; - - /* See if there is a value to receive. */ - if (channel->next_store > 0) - return 1; - - /* If we haven't already done so, try to synch with - a select waiting to send on this channel. If we - have already synched with a select, we are just - looping until the select eventually causes - something to be sent. */ - if (!synched_with_select && !for_select) - { - if (__go_synch_with_select (channel, 0)) - { - synched_with_select = 1; - need_broadcast = 1; - } - } - - /* If we marked the channel as waiting, we need to - signal, because something changed. It needs to - be a broadcast since there might be other - receivers waiting. */ - if (!was_marked) - { - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - } - } - } - else - { - /* If there is a value on the channel, we are OK. */ - if (channel->next_fetch != channel->next_store) - return 1; - } - } - - /* If we just synched with a select, then we need to signal the - select condition variable. We can only do that if we unlock - the channel. So we need to unlock, signal, lock, and go - around the loop again without waiting. */ - if (need_broadcast) - { - __go_broadcast_to_select (channel); - continue; - } - - /* Wait for something to change, then loop around and try - again. */ - - runtime_cond_wait (&channel->cond, &channel->lock); - } -} - -/* Finished receiving something on a channel. */ - -void -__go_receive_release (struct __go_channel *channel) -{ - int i; - - if (channel->num_entries != 0) - channel->next_fetch = (channel->next_fetch + 1) % channel->num_entries; - else - { - /* For a synchronous receiver, we tell the sender that we picked - up the value by setting the next_store field back to 0. - Using the mutexes should implement a memory barrier. */ - __go_assert (channel->next_store == 1); - channel->next_store = 0; - - channel->waiting_to_receive = 0; - } - - channel->selected_for_receive = 0; - - /* This is a broadcast to make sure that a synchronous sender sees - it. */ - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - - __go_unlock_and_notify_selects (channel); -} - -/* Unlock a channel and notify any waiting selects that something - happened. */ - -void -__go_unlock_and_notify_selects (struct __go_channel *channel) -{ - pthread_mutex_t* select_mutex; - pthread_cond_t* select_cond; - int i; - - select_mutex = channel->select_mutex; - select_cond = channel->select_cond; - - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - if (select_mutex != NULL) - { - i = pthread_mutex_lock (select_mutex); - __go_assert (i == 0); - i = pthread_cond_broadcast (select_cond); - __go_assert (i == 0); - i = pthread_mutex_unlock (select_mutex); - __go_assert (i == 0); - } -} - -/* Receive something 64 bits or smaller on a channel. */ - -uint64_t -__go_receive_small_closed (struct __go_channel *channel, _Bool for_select, - _Bool *received) -{ - uintptr_t element_size; - uint64_t ret; - - if (channel == NULL) - { - /* Block forever. */ - __go_select (0, 0, NULL, NULL); - } - - element_size = channel->element_type->__size; - __go_assert (element_size <= sizeof (uint64_t)); - - if (!__go_receive_acquire (channel, for_select)) - { - if (received != NULL) - *received = 0; - return 0; - } - - ret = channel->data[channel->next_fetch]; - - __go_receive_release (channel); - - if (received != NULL) - *received = 1; - - return ret; -} - -/* Called by the compiler. */ - -uint64_t -__go_receive_small (struct __go_channel *channel, _Bool for_select) -{ - return __go_receive_small_closed (channel, for_select, NULL); -} diff --git a/libgo/runtime/go-reflect-chan.c b/libgo/runtime/go-reflect-chan.c deleted file mode 100644 index 6f6693b6b54..00000000000 --- a/libgo/runtime/go-reflect-chan.c +++ /dev/null @@ -1,200 +0,0 @@ -/* go-reflect-chan.c -- channel reflection support for Go. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include -#include - -#include "config.h" -#include "go-alloc.h" -#include "go-assert.h" -#include "go-panic.h" -#include "go-type.h" -#include "channel.h" - -/* This file implements support for reflection on channels. These - functions are called from reflect/value.go. */ - -extern uintptr_t makechan (const struct __go_type_descriptor *, uint32_t) - asm ("libgo_reflect.reflect.makechan"); - -uintptr_t -makechan (const struct __go_type_descriptor *typ, uint32_t size) -{ - struct __go_channel *channel; - void *ret; - - channel = __go_new_channel (typ, size); - - ret = __go_alloc (sizeof (void *)); - __builtin_memcpy (ret, &channel, sizeof (void *)); - return (uintptr_t) ret; -} - -extern _Bool chansend (struct __go_channel_type *, uintptr_t, uintptr_t, _Bool) - asm ("libgo_reflect.reflect.chansend"); - -_Bool -chansend (struct __go_channel_type *ct, uintptr_t ch, uintptr_t val_i, - _Bool nb) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - uintptr_t element_size; - void *pv; - - __go_assert (ct->__common.__code == GO_CHAN); - - if (__go_is_pointer_type (ct->__element_type)) - pv = &val_i; - else - pv = (void *) val_i; - - element_size = ct->__element_type->__size; - if (element_size <= sizeof (uint64_t)) - { - union - { - char b[sizeof (uint64_t)]; - uint64_t v; - } u; - - __builtin_memset (u.b, 0, sizeof (uint64_t)); -#ifndef WORDS_BIGENDIAN - __builtin_memcpy (u.b, pv, element_size); -#else - __builtin_memcpy (u.b + sizeof (uint64_t) - element_size, pv, - element_size); -#endif - if (nb) - return __go_send_nonblocking_small (channel, u.v); - else - { - __go_send_small (channel, u.v, 0); - return 1; - } - } - else - { - if (nb) - return __go_send_nonblocking_big (channel, pv); - else - { - __go_send_big (channel, pv, 0); - return 1; - } - } -} - -struct chanrecv_ret -{ - uintptr_t val; - _Bool selected; - _Bool received; -}; - -extern struct chanrecv_ret chanrecv (struct __go_channel_type *, uintptr_t, - _Bool) - asm ("libgo_reflect.reflect.chanrecv"); - -struct chanrecv_ret -chanrecv (struct __go_channel_type *ct, uintptr_t ch, _Bool nb) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - void *pv; - uintptr_t element_size; - struct chanrecv_ret ret; - - __go_assert (ct->__common.__code == GO_CHAN); - - element_size = ct->__element_type->__size; - - if (__go_is_pointer_type (ct->__element_type)) - pv = &ret.val; - else - { - pv = __go_alloc (element_size); - ret.val = (uintptr_t) pv; - } - - if (element_size <= sizeof (uint64_t)) - { - union - { - char b[sizeof (uint64_t)]; - uint64_t v; - } u; - - if (!nb) - { - u.v = __go_receive_small_closed (channel, 0, &ret.received); - ret.selected = 1; - } - else - { - struct __go_receive_nonblocking_small s; - - s = __go_receive_nonblocking_small (channel); - ret.selected = s.__success || s.__closed; - ret.received = s.__success; - u.v = s.__val; - } - -#ifndef WORDS_BIGENDIAN - __builtin_memcpy (pv, u.b, element_size); -#else - __builtin_memcpy (pv, u.b + sizeof (uint64_t) - element_size, - element_size); -#endif - } - else - { - if (!nb) - { - ret.received = __go_receive_big (channel, pv, 0); - ret.selected = 1; - } - else - { - _Bool got; - _Bool closed; - - got = __go_receive_nonblocking_big (channel, pv, &closed); - ret.selected = got || closed; - ret.received = got; - } - } - - return ret; -} - -extern void chanclose (uintptr_t) asm ("libgo_reflect.reflect.chanclose"); - -void -chanclose (uintptr_t ch) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - - __go_builtin_close (channel); -} - -extern int32_t chanlen (uintptr_t) asm ("libgo_reflect.reflect.chanlen"); - -int32_t -chanlen (uintptr_t ch) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - - return (int32_t) __go_chan_len (channel); -} - -extern int32_t chancap (uintptr_t) asm ("libgo_reflect.reflect.chancap"); - -int32_t -chancap (uintptr_t ch) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - - return (int32_t) __go_chan_cap (channel); -} diff --git a/libgo/runtime/go-select.c b/libgo/runtime/go-select.c deleted file mode 100644 index 677c699b52c..00000000000 --- a/libgo/runtime/go-select.c +++ /dev/null @@ -1,758 +0,0 @@ -/* go-select.c -- implement select. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include -#include -#include -#include -#include -#include - -#include "runtime.h" -#include "config.h" -#include "go-assert.h" -#include "channel.h" - -/* __go_select builds an array of these structures. */ - -struct select_channel -{ - /* The channel being selected. */ - struct __go_channel* channel; - /* If this channel is selected, the value to return. */ - uintptr_t retval; - /* If this channel is a duplicate of one which appears earlier in - the array, this is the array index of the earlier channel. This - is -1UL if this is not a dup. */ - uintptr_t dup_index; - /* An entry to put on the send or receive queue. */ - struct __go_channel_select queue_entry; - /* True if selected for send. */ - _Bool is_send; - /* True if channel is ready--it has data to receive or space to - send. */ - _Bool is_ready; -}; - -/* This mutex controls access to __go_select_cond. This mutex may not - be acquired if any channel locks are held. */ - -static pthread_mutex_t __go_select_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* When we have to wait for channels, we tell them to trigger this - condition variable when they send or receive something. */ - -static pthread_cond_t __go_select_cond = PTHREAD_COND_INITIALIZER; - -/* Sort the channels by address. This avoids deadlock when multiple - selects are running on overlapping sets of channels. */ - -static int -channel_sort (const void *p1, const void *p2) -{ - const struct select_channel *c1 = (const struct select_channel *) p1; - const struct select_channel *c2 = (const struct select_channel *) p2; - - if ((uintptr_t) c1->channel < (uintptr_t) c2->channel) - return -1; - else if ((uintptr_t) c1->channel > (uintptr_t) c2->channel) - return 1; - else - return 0; -} - -/* Return whether there is an entry on QUEUE which can be used for a - synchronous send or receive. */ - -static _Bool -is_queue_ready (struct __go_channel_select *queue) -{ - int x; - - if (queue == NULL) - return 0; - - x = pthread_mutex_lock (&__go_select_data_mutex); - __go_assert (x == 0); - - while (queue != NULL) - { - if (*queue->selected == NULL) - break; - queue = queue->next; - } - - x = pthread_mutex_unlock (&__go_select_data_mutex); - __go_assert (x == 0); - - return queue != NULL; -} - -/* Return whether CHAN is ready. If IS_SEND is true check whether it - has space to send, otherwise check whether it has a value to - receive. */ - -static _Bool -is_channel_ready (struct __go_channel* channel, _Bool is_send) -{ - if (is_send) - { - if (channel->selected_for_send) - return 0; - if (channel->is_closed) - return 1; - if (channel->num_entries > 0) - { - /* An asynchronous channel is ready for sending if there is - room in the buffer. */ - return ((channel->next_store + 1) % channel->num_entries - != channel->next_fetch); - } - else - { - if (channel->waiting_to_send) - { - /* Some other goroutine is waiting to send on this - channel, so we can't. */ - return 0; - } - if (channel->waiting_to_receive) - { - /* Some other goroutine is waiting to receive a value, - so we can send one. */ - return 1; - } - if (is_queue_ready (channel->select_receive_queue)) - { - /* There is a select statement waiting to synchronize - with this one. */ - return 1; - } - return 0; - } - } - else - { - if (channel->selected_for_receive) - return 0; - if (channel->is_closed) - return 1; - if (channel->num_entries > 0) - { - /* An asynchronous channel is ready for receiving if there - is a value in the buffer. */ - return channel->next_fetch != channel->next_store; - } - else - { - if (channel->waiting_to_receive) - { - /* Some other goroutine is waiting to receive from this - channel, so it is not ready for us to receive. */ - return 0; - } - if (channel->next_store > 0) - { - /* There is data on the channel. */ - return 1; - } - if (is_queue_ready (channel->select_send_queue)) - { - /* There is a select statement waiting to synchronize - with this one. */ - return 1; - } - return 0; - } - } -} - -/* Mark a channel as selected. The channel is locked. IS_SELECTED is - true if the channel was selected for us by another goroutine. We - set *NEEDS_BROADCAST if we need to broadcast on the select - condition variable. Return true if we got it. */ - -static _Bool -mark_channel_selected (struct __go_channel *channel, _Bool is_send, - _Bool is_selected, _Bool *needs_broadcast) -{ - if (channel->num_entries == 0) - { - /* This is a synchronous channel. If there is no goroutine - currently waiting, but there is another select waiting, then - we need to tell that select to use this channel. That may - fail--there may be no other goroutines currently waiting--as - a third goroutine may already have claimed the select. */ - if (!is_selected - && !channel->is_closed - && (is_send - ? !channel->waiting_to_receive - : channel->next_store == 0)) - { - int x; - struct __go_channel_select *queue; - - x = pthread_mutex_lock (&__go_select_data_mutex); - __go_assert (x == 0); - - queue = (is_send - ? channel->select_receive_queue - : channel->select_send_queue); - __go_assert (queue != NULL); - - while (queue != NULL) - { - if (*queue->selected == NULL) - { - *queue->selected = channel; - *queue->is_read = !is_send; - break; - } - queue = queue->next; - } - - x = pthread_mutex_unlock (&__go_select_data_mutex); - __go_assert (x == 0); - - if (queue == NULL) - return 0; - - if (is_send) - channel->selected_for_receive = 1; - else - channel->selected_for_send = 1; - - /* We are going to have to tell the other select that there - is something to do. */ - *needs_broadcast = 1; - } - } - - if (is_send) - channel->selected_for_send = 1; - else - channel->selected_for_receive = 1; - - return 1; -} - -/* Mark a channel to indicate that a select is waiting. The channel - is locked. */ - -static void -mark_select_waiting (struct select_channel *sc, - struct __go_channel **selected_pointer, - _Bool *selected_for_read_pointer) -{ - struct __go_channel *channel = sc->channel; - _Bool is_send = sc->is_send; - - if (channel->num_entries == 0) - { - struct __go_channel_select **pp; - - pp = (is_send - ? &channel->select_send_queue - : &channel->select_receive_queue); - - /* Add an entry to the queue of selects on this channel. */ - sc->queue_entry.next = *pp; - sc->queue_entry.selected = selected_pointer; - sc->queue_entry.is_read = selected_for_read_pointer; - - *pp = &sc->queue_entry; - } - - channel->select_mutex = &__go_select_mutex; - channel->select_cond = &__go_select_cond; - - /* We never actually clear the select_mutex and select_cond fields. - In order to clear them safely, we would need to have some way of - knowing when no select is waiting for the channel. Thus we - introduce a bit of inefficiency for every channel that select - needs to wait for. This is harmless other than the performance - cost. */ -} - -/* Remove the entry for this select waiting on this channel. The - channel is locked. We check both queues, because the channel may - be selected for both reading and writing. */ - -static void -clear_select_waiting (struct select_channel *sc, - struct __go_channel **selected_pointer) -{ - struct __go_channel *channel = sc->channel; - - if (channel->num_entries == 0) - { - _Bool found; - struct __go_channel_select **pp; - - found = 0; - - for (pp = &channel->select_send_queue; *pp != NULL; pp = &(*pp)->next) - { - if ((*pp)->selected == selected_pointer) - { - *pp = (*pp)->next; - found = 1; - break; - } - } - - for (pp = &channel->select_receive_queue; *pp != NULL; pp = &(*pp)->next) - { - if ((*pp)->selected == selected_pointer) - { - *pp = (*pp)->next; - found = 1; - break; - } - } - - __go_assert (found); - } -} - -/* Look through the list of channels to see which ones are ready. - Lock each channels, and set the is_ready flag. Return the number - of ready channels. */ - -static uintptr_t -lock_channels_find_ready (struct select_channel *channels, uintptr_t count) -{ - uintptr_t ready_count; - uintptr_t i; - - ready_count = 0; - for (i = 0; i < count; ++i) - { - struct __go_channel *channel = channels[i].channel; - _Bool is_send = channels[i].is_send; - uintptr_t dup_index = channels[i].dup_index; - int x; - - if (channel == NULL) - continue; - - if (dup_index != (uintptr_t) -1UL) - { - if (channels[dup_index].is_ready) - { - channels[i].is_ready = 1; - ++ready_count; - } - continue; - } - - x = pthread_mutex_lock (&channel->lock); - __go_assert (x == 0); - - if (is_channel_ready (channel, is_send)) - { - channels[i].is_ready = 1; - ++ready_count; - } - } - - return ready_count; -} - -/* The channel we are going to select has been forced by some other - goroutine. SELECTED_CHANNEL is the channel we will use, - SELECTED_FOR_READ is whether the other goroutine wants to read from - the channel. Note that the channel could be specified multiple - times in this select, so we must mark each appropriate entry for - this channel as ready. Every other channel is marked as not ready. - All the channels are locked before this routine is called. This - returns the number of ready channels. */ - -uintptr_t -force_selected_channel_ready (struct select_channel *channels, uintptr_t count, - struct __go_channel *selected_channel, - _Bool selected_for_read) -{ - uintptr_t ready_count; - uintptr_t i; - - ready_count = 0; - for (i = 0; i < count; ++i) - { - struct __go_channel *channel = channels[i].channel; - _Bool is_send = channels[i].is_send; - - if (channel == NULL) - continue; - - if (channel != selected_channel - || (is_send ? !selected_for_read : selected_for_read)) - channels[i].is_ready = 0; - else - { - channels[i].is_ready = 1; - ++ready_count; - } - } - __go_assert (ready_count > 0); - return ready_count; -} - -/* Unlock all the channels. */ - -static void -unlock_channels (struct select_channel *channels, uintptr_t count) -{ - uintptr_t i; - int x; - - for (i = 0; i < count; ++i) - { - struct __go_channel *channel = channels[i].channel; - - if (channel == NULL) - continue; - - if (channels[i].dup_index != (uintptr_t) -1UL) - continue; - - x = pthread_mutex_unlock (&channel->lock); - __go_assert (x == 0); - } -} - -/* At least one channel is ready. Randomly pick a channel to return. - Unlock all the channels. IS_SELECTED is true if the channel was - picked for us by some other goroutine. If SELECTED_POINTER is not - NULL, remove it from the queue for all the channels. Return the - retval field of the selected channel. This will return 0 if we - can't use the selected channel, because it relied on synchronizing - with some other select, and that select already synchronized with a - different channel. */ - -static uintptr_t -unlock_channels_and_select (struct select_channel *channels, - uintptr_t count, uintptr_t ready_count, - _Bool is_selected, - struct __go_channel **selected_pointer) -{ - uintptr_t selected; - uintptr_t ret; - _Bool needs_broadcast; - uintptr_t i; - int x; - - /* Pick which channel we are going to return. */ -#if defined(HAVE_RANDOM) - selected = (uintptr_t) random () % ready_count; -#else - selected = (uintptr_t) rand () % ready_count; -#endif - ret = 0; - needs_broadcast = 0; - - /* Look at the channels in reverse order so that we don't unlock a - duplicated channel until we have seen all its dups. */ - for (i = 0; i < count; ++i) - { - uintptr_t j = count - i - 1; - struct __go_channel *channel = channels[j].channel; - _Bool is_send = channels[j].is_send; - - if (channel == NULL) - continue; - - if (channels[j].is_ready) - { - if (selected == 0) - { - if (mark_channel_selected (channel, is_send, is_selected, - &needs_broadcast)) - ret = channels[j].retval; - } - - --selected; - } - - if (channels[j].dup_index == (uintptr_t) -1UL) - { - if (selected_pointer != NULL) - clear_select_waiting (&channels[j], selected_pointer); - - x = pthread_mutex_unlock (&channel->lock); - __go_assert (x == 0); - } - } - - /* The NEEDS_BROADCAST variable is set if we are synchronizing with - some other select statement. We can't do the actual broadcast - until we have unlocked all the channels. */ - - if (needs_broadcast) - { - x = pthread_mutex_lock (&__go_select_mutex); - __go_assert (x == 0); - - x = pthread_cond_broadcast (&__go_select_cond); - __go_assert (x == 0); - - x = pthread_mutex_unlock (&__go_select_mutex); - __go_assert (x == 0); - } - - return ret; -} - -/* Mark all channels to show that we are waiting for them. This is - called with the select mutex held, but none of the channels are - locked. This returns true if some channel was found to be - ready. */ - -static _Bool -mark_all_channels_waiting (struct select_channel* channels, uintptr_t count, - struct __go_channel **selected_pointer, - _Bool *selected_for_read_pointer) -{ - _Bool ret; - int x; - uintptr_t i; - - ret = 0; - for (i = 0; i < count; ++i) - { - struct __go_channel *channel = channels[i].channel; - _Bool is_send = channels[i].is_send; - - if (channel == NULL) - continue; - - if (channels[i].dup_index != (uintptr_t) -1UL) - { - uintptr_t j; - - /* A channel may be selected for both read and write. */ - if (channels[channels[i].dup_index].is_send == is_send) - continue; - else - { - for (j = channels[i].dup_index + 1; j < i; ++j) - { - if (channels[j].channel == channel - && channels[j].is_send == is_send) - break; - } - if (j < i) - continue; - } - } - - x = pthread_mutex_lock (&channel->lock); - __go_assert (x == 0); - - /* To avoid a race condition, we have to check again whether the - channel is ready. It may have become ready since we did the - first set of checks but before we acquired the select mutex. - If we don't check here, we could sleep forever on the select - condition variable. */ - if (is_channel_ready (channel, is_send)) - ret = 1; - - /* If SELECTED_POINTER is NULL, then we have already marked the - channel as waiting. */ - if (selected_pointer != NULL) - mark_select_waiting (&channels[i], selected_pointer, - selected_for_read_pointer); - - x = pthread_mutex_unlock (&channel->lock); - __go_assert (x == 0); - } - - return ret; -} - -/* Implement select. This is called by the compiler-generated code - with pairs of arguments: a pointer to a channel, and an int which - is non-zero for send, zero for receive. */ - -uintptr_t -__go_select (uintptr_t count, _Bool has_default, - struct __go_channel **channel_args, _Bool *is_send_args) -{ - struct select_channel stack_buffer[16]; - struct select_channel *allocated_buffer; - struct select_channel *channels; - uintptr_t i; - int x; - struct __go_channel *selected_channel; - _Bool selected_for_read; - _Bool is_queued; - - if (count < sizeof stack_buffer / sizeof stack_buffer[0]) - { - channels = &stack_buffer[0]; - allocated_buffer = NULL; - } - else - { - allocated_buffer = ((struct select_channel *) - malloc (count * sizeof (struct select_channel))); - channels = allocated_buffer; - } - - for (i = 0; i < count; ++i) - { - struct __go_channel *channel_arg = channel_args[i]; - _Bool is_send = is_send_args[i]; - - channels[i].channel = (struct __go_channel*) channel_arg; - channels[i].retval = i + 1; - channels[i].dup_index = (uintptr_t) -1UL; - channels[i].queue_entry.next = NULL; - channels[i].queue_entry.selected = NULL; - channels[i].is_send = is_send; - channels[i].is_ready = 0; - } - - qsort (channels, count, sizeof (struct select_channel), channel_sort); - - for (i = 0; i < count; ++i) - { - uintptr_t j; - - for (j = 0; j < i; ++j) - { - if (channels[j].channel == channels[i].channel) - { - channels[i].dup_index = j; - break; - } - } - } - - /* SELECT_CHANNEL is used to select synchronized channels. If no - channels are ready, we store a pointer to this variable on the - select queue for each synchronized channel. Because the variable - may be set by channel operations running in other goroutines, - SELECT_CHANNEL may only be accessed when all the channels are - locked and/or when the select_data_mutex is locked. */ - selected_channel = NULL; - - /* SELECTED_FOR_READ is set to true if SELECTED_CHANNEL was set by a - goroutine which wants to read from the channel. The access - restrictions for this are like those for SELECTED_CHANNEL. */ - selected_for_read = 0; - - /* IS_QUEUED is true if we have queued up this select on the queues - for any associated synchronous channels. We only do this if no - channels are ready the first time around the loop. */ - is_queued = 0; - - while (1) - { - int ready_count; - _Bool is_selected; - - /* Lock all channels, identify which ones are ready. */ - ready_count = lock_channels_find_ready (channels, count); - - /* All the channels are locked, so we can look at - SELECTED_CHANNEL. If it is not NULL, then our choice has - been forced by some other goroutine. This can only happen - after the first time through the loop. */ - is_selected = selected_channel != NULL; - if (is_selected) - ready_count = force_selected_channel_ready (channels, count, - selected_channel, - selected_for_read); - - if (ready_count > 0) - { - uintptr_t ret; - - ret = unlock_channels_and_select (channels, count, ready_count, - is_selected, - (is_queued - ? &selected_channel - : NULL)); - - /* If RET is zero, it means that the channel we picked - turned out not to be ready, because some other select - grabbed it during our traversal. Loop around and try - again. */ - if (ret == 0) - { - is_queued = 0; - /* We are no longer on any channel queues, so it is safe - to touch SELECTED_CHANNEL here. It must be NULL, - because otherwise that would somebody has promised to - synch up with us and then failed to do so. */ - __go_assert (selected_channel == NULL); - continue; - } - - if (allocated_buffer != NULL) - free (allocated_buffer); - - return ret; - } - - /* No channels were ready. */ - - unlock_channels (channels, count); - - if (has_default) - { - /* Use the default clause. */ - if (allocated_buffer != NULL) - free (allocated_buffer); - return 0; - } - - /* This is a blocking select. Grab the select lock, tell all - the channels to notify us when something happens, and wait - for something to happen. */ - - x = pthread_mutex_lock (&__go_select_mutex); - __go_assert (x == 0); - - /* Check whether CHANNEL_SELECTED was set while the channels - were unlocked. If it was set, then we can simply loop around - again. We need to check this while the select mutex is held. - It is possible that something will set CHANNEL_SELECTED while - we mark the channels as waiting. If this happens, that - goroutine is required to signal the select condition - variable, which means acquiring the select mutex. Since we - have the select mutex locked ourselves, we can not miss that - signal. */ - - x = pthread_mutex_lock (&__go_select_data_mutex); - __go_assert (x == 0); - - is_selected = selected_channel != NULL; - - x = pthread_mutex_unlock (&__go_select_data_mutex); - __go_assert (x == 0); - - if (!is_selected) - { - /* Mark the channels as waiting, and check whether they have - become ready. */ - if (!mark_all_channels_waiting (channels, count, - (is_queued - ? NULL - : &selected_channel), - (is_queued - ? NULL - : &selected_for_read))) - runtime_cond_wait (&__go_select_cond, &__go_select_mutex); - - is_queued = 1; - } - - x = pthread_mutex_unlock (&__go_select_mutex); - __go_assert (x == 0); - } -} diff --git a/libgo/runtime/go-send-big.c b/libgo/runtime/go-send-big.c deleted file mode 100644 index 61d4a0f13d9..00000000000 --- a/libgo/runtime/go-send-big.c +++ /dev/null @@ -1,34 +0,0 @@ -/* go-send-big.c -- send something bigger than uint64_t on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include - -#include "go-panic.h" -#include "channel.h" - -void -__go_send_big (struct __go_channel* channel, const void *val, _Bool for_select) -{ - uintptr_t element_size; - size_t alloc_size; - size_t offset; - - if (channel == NULL) - { - // Block forever. - __go_select (0, 0, NULL, NULL); - } - - element_size = channel->element_type->__size; - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - __go_send_acquire (channel, for_select); - - offset = channel->next_store * alloc_size; - __builtin_memcpy (&channel->data[offset], val, element_size); - - __go_send_release (channel); -} diff --git a/libgo/runtime/go-send-nb-big.c b/libgo/runtime/go-send-nb-big.c deleted file mode 100644 index e039874ef9a..00000000000 --- a/libgo/runtime/go-send-nb-big.c +++ /dev/null @@ -1,33 +0,0 @@ -/* go-send-nb-big.c -- nonblocking send of something big on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include - -#include "channel.h" - -_Bool -__go_send_nonblocking_big (struct __go_channel* channel, const void *val) -{ - uintptr_t element_size; - size_t alloc_size; - size_t offset; - - if (channel == NULL) - return 0; - - element_size = channel->element_type->__size; - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - if (!__go_send_nonblocking_acquire (channel)) - return 0; - - offset = channel->next_store * alloc_size; - __builtin_memcpy (&channel->data[offset], val, element_size); - - __go_send_release (channel); - - return 1; -} diff --git a/libgo/runtime/go-send-nb-small.c b/libgo/runtime/go-send-nb-small.c deleted file mode 100644 index c77ee9183e2..00000000000 --- a/libgo/runtime/go-send-nb-small.c +++ /dev/null @@ -1,107 +0,0 @@ -/* go-send-nb-small.c -- nonblocking send of something small on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* Prepare to send something on a nonblocking channel. Return true if - we acquired the channel, false if we did not acquire it because - there is no space to send a value. */ - -_Bool -__go_send_nonblocking_acquire (struct __go_channel *channel) -{ - int i; - _Bool has_space; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (channel->selected_for_send) - runtime_cond_wait (&channel->cond, &channel->lock); - - if (channel->is_closed) - { - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - runtime_panicstring ("send on closed channel"); - } - - if (channel->num_entries > 0) - has_space = ((channel->next_store + 1) % channel->num_entries - != channel->next_fetch); - else - { - /* This is a synchronous channel. If somebody is current - sending, then we can't send. Otherwise, see if somebody is - waiting to receive, or see if we can synch with a select. */ - if (channel->waiting_to_send) - { - /* Some other goroutine is currently sending on this - channel, which means that we can't. */ - has_space = 0; - } - else if (channel->waiting_to_receive) - { - /* Some other goroutine is waiting to receive a value, so we - can send directly to them. */ - has_space = 1; - } - else if (__go_synch_with_select (channel, 1)) - { - /* We found a select waiting to receive data, so we can send - to that. */ - __go_broadcast_to_select (channel); - has_space = 1; - } - else - { - /* Otherwise, we can't send, because nobody is waiting to - receive. */ - has_space = 0; - } - - if (has_space) - { - channel->waiting_to_send = 1; - __go_assert (channel->next_store == 0); - } - } - - if (!has_space) - { - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - return 0; - } - - return 1; -} - -/* Send something 64 bits or smaller on a channel. */ - -_Bool -__go_send_nonblocking_small (struct __go_channel *channel, uint64_t val) -{ - if (channel == NULL) - return 0; - - __go_assert (channel->element_type->__size <= sizeof (uint64_t)); - - if (!__go_send_nonblocking_acquire (channel)) - return 0; - - channel->data[channel->next_store] = val; - - __go_send_release (channel); - - return 1; -} diff --git a/libgo/runtime/go-send-small.c b/libgo/runtime/go-send-small.c deleted file mode 100644 index 06bcb41b9ad..00000000000 --- a/libgo/runtime/go-send-small.c +++ /dev/null @@ -1,159 +0,0 @@ -/* go-send-small.c -- send something 64 bits or smaller on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* Prepare to send something on a channel. FOR_SELECT is true if this - call is being made after a select statement returned with this - channel selected. */ - -void -__go_send_acquire (struct __go_channel *channel, _Bool for_select) -{ - int i; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (1) - { - if (channel->is_closed) - { - if (for_select) - channel->selected_for_send = 0; - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - runtime_panicstring ("send on closed channel"); - } - - /* If somebody else has the channel locked for sending, we have - to wait. If FOR_SELECT is true, then we are the one with the - lock. */ - if (!channel->selected_for_send || for_select) - { - if (channel->num_entries == 0) - { - /* This is a synchronous channel. If nobody else is - waiting to send, we grab the channel and tell the - caller to send the data. We will then wait for a - receiver. */ - if (!channel->waiting_to_send) - { - __go_assert (channel->next_store == 0); - return; - } - } - else - { - /* If there is room on the channel, we are OK. */ - if ((channel->next_store + 1) % channel->num_entries - != channel->next_fetch) - return; - } - } - - /* Wait for something to change, then loop around and try - again. */ - - runtime_cond_wait (&channel->cond, &channel->lock); - } -} - -/* Finished sending something on a channel. */ - -void -__go_send_release (struct __go_channel *channel) -{ - int i; - - if (channel->num_entries != 0) - { - /* This is a buffered channel. Bump the store count and signal - the condition variable. */ - channel->next_store = (channel->next_store + 1) % channel->num_entries; - - i = pthread_cond_signal (&channel->cond); - __go_assert (i == 0); - } - else - { - _Bool synched_with_select; - - /* This is a synchronous channel. Indicate that we have a value - waiting. */ - channel->next_store = 1; - channel->waiting_to_send = 1; - - /* Tell everybody else to do something. This has to be a - broadcast because we might have both senders and receivers - waiting on the condition, but senders won't send another - signal. */ - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - - /* Wait until the value is received. */ - synched_with_select = 0; - while (1) - { - if (channel->next_store == 0) - break; - - /* If nobody is currently waiting to receive, try to synch - up with a select. */ - if (!channel->waiting_to_receive && !synched_with_select) - { - if (__go_synch_with_select (channel, 1)) - { - synched_with_select = 1; - __go_broadcast_to_select (channel); - continue; - } - } - - runtime_cond_wait (&channel->cond, &channel->lock); - } - - channel->waiting_to_send = 0; - - /* Using the mutexes should implement a memory barrier. */ - - /* We have to signal again since we cleared the waiting_to_send - field. This has to be a broadcast because both senders and - receivers might be waiting, but only senders will be able to - act. */ - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - } - - channel->selected_for_send = 0; - - __go_unlock_and_notify_selects (channel); -} - -/* Send something 64 bits or smaller on a channel. */ - -void -__go_send_small (struct __go_channel *channel, uint64_t val, _Bool for_select) -{ - if (channel == NULL) - { - // Block forever. - __go_select (0, 0, NULL, NULL); - } - - __go_assert (channel->element_type->__size <= sizeof (uint64_t)); - - __go_send_acquire (channel, for_select); - - channel->data[channel->next_store] = val; - - __go_send_release (channel); -} diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 9455ae88c5a..db59be5d062 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -55,14 +55,15 @@ typedef struct M M; typedef union Note Note; typedef struct MCache MCache; typedef struct FixAlloc FixAlloc; +typedef struct Hchan Hchan; -typedef struct __go_defer_stack Defer; +typedef struct __go_open_array Slice; +typedef struct __go_string String; typedef struct __go_interface Iface; typedef struct __go_empty_interface Eface; typedef struct __go_type_descriptor Type; +typedef struct __go_defer_stack Defer; typedef struct __go_panic_stack Panic; -typedef struct __go_open_array Slice; -typedef struct __go_string String; typedef struct __go_func_type FuncType; typedef struct __go_map_type MapType; @@ -131,6 +132,7 @@ struct G bool fromgogo; // reached from gogo int16 status; int32 goid; + uint32 selgen; // valid sudog pointer const char* waitreason; // if status==Gwaiting G* schedlink; bool readyonstop; -- 2.30.2