void ACE_RW_Token::notify_new_owner (ACE_TPQ_Entry *old_owner) { ACE_TRACE ("ACE_RW_Token::notify_new_owner"); if (this->owner () == 0) return; if (this->owner ()->proxy ()->type () == ACE_RW_Token::READER) { if (old_owner->proxy ()->type () == ACE_RW_Token::READER) // the owners already know that they're owners return; // The current owner is a reader and the previous owner was a // writer, so notify all waiting readers up to the first writer. // call back all reader owners. ACE_TPQ_Iterator iterator (waiters_); for (ACE_TPQ_Entry *temp = 0; iterator.next (temp) != 0; iterator.advance ()) { if (temp->proxy ()->type () == WRITER) // We've gone through all the readers. break; temp->proxy ()->token_acquired (temp); } } else // writer this->owner ()->proxy ()->token_acquired (this->owner ()); }
int ACE_Token_Manager::check_deadlock (ACE_Tokens *token, ACE_Token_Proxy *proxy) { ACE_TRACE ("ACE_Token_Manager::check_deadlock"); if (token->visited ()) return 0; token->visit (1); ACE_Tokens::OWNER_STACK owners; int is_owner = token->owners (owners, proxy->client_id ()); switch (is_owner) { case -1: // Error. return -1; case 1: // The caller is an owner, so we have a deadlock situation. if (debug_) { ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) Deadlock detected.\n"))); ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("%s owns %s and is waiting for %s.\n"), proxy->client_id (), token->name (), proxy->token_->name ())); } return 1; case 0: default: // Recurse on each owner. while (!owners.is_empty ()) { ACE_TPQ_Entry *e; owners.pop (e); // If the owner is waiting on another token, recurse. ACE_Tokens *twf = this->token_waiting_for (e->client_id ()); if ((twf != 0) && (this->check_deadlock (twf, proxy) == 1)) { if (debug_) { ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("%s owns %s and is waiting for %s.\n"), e->client_id (), token->name (), twf->name ())); } return 1; } // else, check the next owner. } // We've checked all the owners and found no deadlock. return 0; } }
int ACE_RW_Token::is_owner (const ACE_TCHAR *id) { ACE_TRACE ("ACE_RW_Token::is_owner"); // If there is no owner, return false. if (this->owner () == 0) return 0; // A writer owns us. if (this->owner ()->proxy ()->type () == ACE_RW_Token::WRITER) return this->owner ()->equal_client_id (id); // Readers own us. // Step through each owning reader looking for <id>. ACE_TPQ_Iterator iterator (waiters_); for (ACE_TPQ_Entry *temp = 0; iterator.next (temp) != 0; iterator.advance ()) { if (temp->proxy ()->type () != ACE_RW_Token::READER) break; if (temp->equal_client_id (id)) return 1; } return 0; }
void ACE_TPQ_Entry::operator= (const ACE_TPQ_Entry& rhs) { ACE_TRACE ("ACE_TPQ_Entry::operator="); if (&rhs == this) return; this->proxy_ = rhs.proxy (); this->nesting_level_ = rhs.nesting_level (); this->client_id (rhs.client_id ()); this->sleep_hook_ = rhs.sleep_hook (); }
int ACE_RW_Token::owners (OWNER_STACK &stack, const ACE_TCHAR *id) { ACE_TRACE ("ACE_RW_Token::owners"); if (this->owner () == 0) return 0; int id_is_owner = 0; // The first waiter is a writer, so there is only one owner. if (this->owner ()->proxy ()->type () == WRITER) { stack.push (this->owner ()); // If an <id> is specified, return whether it is the owner being // returned. if ((id != 0) && (ACE_OS::strcmp (id, this->owner ()->client_id ()) == 0)) id_is_owner = 1; } // The first waiter is a reader, so there can be multiple owning // readers. else { ACE_TPQ_Iterator iterator (waiters_); for (ACE_TPQ_Entry *temp = 0; iterator.next (temp) != 0; iterator.advance ()) { if (temp->proxy ()->type () == WRITER) // We've gone through all the readers. break; stack.push (temp); if (!id_is_owner && (id != 0) && (ACE_OS::strcmp (id, temp->client_id ()) == 0)) id_is_owner = 1; } } return id_is_owner; }
int ACE_Mutex_Token::is_waiting_for (const ACE_TCHAR *id) { ACE_TRACE ("ACE_Mutex_Token::is_waiting_for"); // If there is no owner, or <id> is the owner, return false. if ((this->owner () == 0) || this->is_owner (id)) return 0; // Step through each waiter looking for <id>. ACE_TPQ_Iterator iterator (waiters_); iterator.advance (); for (ACE_TPQ_Entry *temp = 0; iterator.next (temp) != 0; iterator.advance ()) { if (temp->equal_client_id (id)) return 1; } return 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); }