Пример #1
0
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);
}
Пример #2
0
void
__go_builtin_close (struct __go_channel *channel)
{
  int i;

  i = pthread_mutex_lock (&channel->lock);
  __go_assert (i == 0);

  while (channel->selected_for_send)
    {
      i = pthread_cond_wait (&channel->cond, &channel->lock);
      __go_assert (i == 0);
    }

  if (channel->is_closed)
    {
      i = pthread_mutex_unlock (&channel->lock);
      __go_assert (i == 0);
      __go_panic_msg ("close of closed channel");
    }

  channel->is_closed = 1;

  i = pthread_cond_broadcast (&channel->cond);
  __go_assert (i == 0);

  __go_unlock_and_notify_selects (channel);
}
Пример #3
0
_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.  */

        i = pthread_cond_wait (&channel->cond, &channel->lock);
        __go_assert (i == 0);
    }
}
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;
		}
	    }

	  i = pthread_cond_wait (&channel->cond, &channel->lock);
	  __go_assert (i == 0);
	}

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