Example #1
0
int
ACE_RW_Token::acquire (ACE_TPQ_Entry *caller,
                       int ignore_deadlock,
                       int notify)
{
  ACE_TRACE ("ACE_RW_Token::acquire");
  // We need to acquire two locks. This one to ensure that only one
  // thread uses this token at a time.
  ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon1, this->lock_, -1);
  // This one to ensure an atomic transaction across all tokens.  Note
  // that this order is crucial too.  It's resource coloring for other
  // threads which may be calling this same token.
  ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon2, ACE_Token_Manager::instance ()->mutex (), -1);

  if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
    this->num_writers_++;

  // Does _anyone_ own the token?
  if (this->owner () == 0)
    {
      // There are no waiters, so queue as the first waiter (the owner).
      this->waiters_.enqueue (caller, -1);
      return 0;
    }

  // Check for recursive acquisition.
  if (this->is_owner (caller->client_id ()))
    {
      caller->nesting_level (1);
      return 0;  // Success.
    }

  // Reader.
  if (caller->proxy ()->type () == ACE_RW_Token::READER)
    {
      // Are there any writers?
      if (this->num_writers_ == 0)
        {
          // Queue the caller at the end of the queue.
          this->waiters_.enqueue (caller, -1);
          return 0;
        }
      // Else failure.
    }

  // Failure code.

  // Check for deadlock.
  if (!ignore_deadlock &&
      ACE_Token_Manager::instance ()->check_deadlock (caller->proxy ()) == 1)
    {
      if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
        this->num_writers_--;
      errno = EDEADLK;
      ACE_RETURN (-1);
    }

  // Queue the caller at the end of the queue.
  this->waiters_.enqueue (caller, -1);

  if (notify)
    {
      // If it's a writer, just notify it.
      if (this->owner ()->proxy ()->type () == ACE_RW_Token::WRITER)
        this->owner ()->call_sleep_hook ();
      else
        {
          // Call back all reader owners.
          ACE_TPQ_Entry *temp = this->owner ();
          do
            {
              temp->call_sleep_hook ();
              temp = temp->next_;
            }
          while (temp != 0 &&
                 temp->proxy ()->type () == ACE_RW_Token::READER);
        }
    }

  errno = EWOULDBLOCK;
  ACE_RETURN (-1);

  ACE_NOTREACHED (return -1);
}