compiler/runtime: Copy channel implementation from master library.
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 1 Dec 2011 08:06:16 +0000 (08:06 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 1 Dec 2011 08:06:16 +0000 (08:06 +0000)
From-SVN: r181874

30 files changed:
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/gogo-tree.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/runtime.cc
gcc/go/gofrontend/runtime.def
gcc/go/gofrontend/runtime.h
gcc/go/gofrontend/statements.cc
gcc/go/gofrontend/statements.h
libgo/Makefile.am
libgo/Makefile.in
libgo/runtime/chan.c [new file with mode: 0644]
libgo/runtime/chan.goc [deleted file]
libgo/runtime/channel.h [deleted file]
libgo/runtime/go-chan-cap.c [deleted file]
libgo/runtime/go-chan-len.c [deleted file]
libgo/runtime/go-close.c [deleted file]
libgo/runtime/go-new-channel.c [deleted file]
libgo/runtime/go-rec-big.c [deleted file]
libgo/runtime/go-rec-nb-big.c [deleted file]
libgo/runtime/go-rec-nb-small.c [deleted file]
libgo/runtime/go-rec-small.c [deleted file]
libgo/runtime/go-reflect-chan.c [deleted file]
libgo/runtime/go-select.c [deleted file]
libgo/runtime/go-send-big.c [deleted file]
libgo/runtime/go-send-nb-big.c [deleted file]
libgo/runtime/go-send-nb-small.c [deleted file]
libgo/runtime/go-send-small.c [deleted file]
libgo/runtime/runtime.h

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