int ACE_Mutex_Token::renew (ACE_TPQ_Entry *caller, int requeue_position) { ACE_TRACE ("ACE_Mutex_Token::renew"); ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1); // Verify that the caller is the owner. if (this->is_owner (caller->client_id ()) == 0) { errno = EACCES; ACE_RETURN (-1); } // The caller is the owner, so check to see if there are any // waiters. If not, we just keep the token. == 1 means that there // is only the owner. if (this->waiters_.size () == 1 || requeue_position == 0) return 0; // Requeue the caller. this->waiters_.dequeue (); this->waiters_.enqueue (caller, requeue_position); // Notify new owner. if (this->owner () != 0) this->owner ()->proxy ()->token_acquired (this->owner ()); // Tell the caller that the operation would block. errno = EWOULDBLOCK; ACE_RETURN (-1); ACE_NOTREACHED (return -1); }
int ACE_Mutex_Token::acquire (ACE_TPQ_Entry *caller, int ignore_deadlock, int notify) { ACE_TRACE ("ACE_Mutex_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); // 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; // success } // Does the caller already own it? if (this->is_owner (caller->client_id ())) { // Recursive acquisition. caller->nesting_level (1); return 0; // success } // Check for deadlock. if (!ignore_deadlock && ACE_Token_Manager::instance ()->check_deadlock (caller->proxy ()) == 1) { errno = EDEADLK; ACE_RETURN (-1); } // Someone owns it. Sorry, you're getting queued up at the end of // the waiter queue. this->waiters_.enqueue (caller, -1); if (notify) this->owner ()->call_sleep_hook (); errno = EWOULDBLOCK; ACE_RETURN (-1); ACE_NOTREACHED (return -1); }
int ACE_Token_Collection::acquire (int notify, void (*sleep_hook)(void *), ACE_Synch_Options &options) { ACE_TRACE ("ACE_Token_Collection::acquire"); COLLECTION::ITERATOR iterator (collection_); for (COLLECTION::ENTRY *temp = 0; iterator.next (temp) != 0; iterator.advance ()) { if (debug_) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("collection acquiring %s\n"), temp->int_id_->name ())); if (temp->int_id_->acquire (notify, sleep_hook, options) == -1) { // Save/restore errno. ACE_Errno_Guard error (errno); this->release (); ACE_RETURN (-1); } } return 0; }
int ACE_RW_Token::release (ACE_TPQ_Entry *caller) { ACE_TRACE ("ACE_RW_Token::release"); ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1); // Check for errors. if ((this->owner () == 0) || (this->is_owner (caller->client_id ()) == 0)) { errno = EACCES; ACE_RETURN (-1); } if (caller->proxy ()->type () == ACE_RW_Token::WRITER) num_writers_--; // Recursive release. if (caller->nesting_level () > 0) { caller->nesting_level (-1); return 0; } // Remove the caller and notify the new owner(s). this->remove (caller); this->notify_new_owner (caller); return 0; }
int ACE_Mutex_Token::release (ACE_TPQ_Entry *caller) { ACE_TRACE ("ACE_Mutex_Token::release"); ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1); // Does anyone own the token? if (this->owner () == 0) { errno = EACCES; ACE_RETURN (-1); } // Is the caller the owner. if (this->is_owner (caller->client_id ())) { // Check the nesting level. if (caller->nesting_level () > 0) caller->nesting_level (-1); else { this->waiters_.dequeue (); // Notify new owner. if (this->owner () != 0) this->owner ()->proxy ()->token_acquired (this->owner ()); } } else this->remove (caller); return 0; }
int ACE_Mutex_Token::tryacquire (ACE_TPQ_Entry *caller) { ACE_TRACE ("ACE_Mutex_Token::tryacquire"); // 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); // Does _anyone_ own the token? if (this->owner () == 0) { this->waiters_.enqueue (caller, -1); return 0; // success } // Does the caller already own it? if (this->is_owner (caller->client_id ())) { // recursive acquisition caller->nesting_level (1); return 0; // success } else // Someone owns it. Fail. { errno = EWOULDBLOCK; ACE_RETURN (-1); } ACE_NOTREACHED (return -1); }
int ACE_Token_Proxy::release (ACE_Synch_Options &) { ACE_TRACE ("ACE_Token_Proxy::release"); if (this->token_ == 0) { errno = ENOENT; if (debug_) ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("Must open before releasing.\n"))); ACE_RETURN (-1); } if (this->token_->release (waiter_) != 0) { // Release failed. this->token_->remove (this->waiter_); if (debug_) ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) %p.\n"), ACE_TEXT ("release failed"))); return -1; } else { if (this->debug_) ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) released %s, owner is %s\n"), this->name (), token_->owner_id ())); return 0; } }
int ACE_RW_Token::renew (ACE_TPQ_Entry *caller, int requeue_position) { ACE_TRACE ("ACE_RW_Token::renew"); ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1); // Werify that the caller is the owner if (this->is_owner (caller->client_id ()) == 0) { errno = EACCES; ACE_RETURN (-1); } // The caller is the owner, so check to see if there are any // waiters. If not, we just keep the token. if (this->waiters_.size () == 1 || requeue_position == 0) return 0; // There are waiters, so remove the caller. this->remove (caller); // Requeue the caller. this->waiters_.enqueue (caller, requeue_position); if (caller->proxy ()->type () == ACE_RW_Token::READER) { // If the caller got queued before any writers, the caller is // still the owner. if (this->is_owner (caller->client_id ())) return 0; // success // else fallthrough and return would block. } // Writers will always have to block since waiters_.size () == 1 or // requeue_position == 0. // Get a new owner. this->notify_new_owner (caller); // Tell the caller that the operation would block. errno = EWOULDBLOCK; ACE_RETURN (-1); ACE_NOTREACHED (return -1); }
int ACE_RW_Token::tryacquire (ACE_TPQ_Entry *caller) { ACE_TRACE ("ACE_RW_Token::tryacquire"); // 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, fail. } else // Writer. // We're going to fail, so decrement the num_writers. { this->num_writers_--; } errno = EWOULDBLOCK; ACE_RETURN (-1); ACE_NOTREACHED (return -1); }
int ACE_Token_Proxy::handle_options (ACE_Synch_Options &options, ACE_TOKEN_CONST::COND_VAR &cv) { // Some operation failed with EWOULDBLOCK. ACE_TRACE ("ACE_Token_Proxy::handle_options"); if (options[ACE_Synch_Options::USE_REACTOR] == 1) // Asynchronous. { // Save/restore errno. ACE_Errno_Guard error (errno); cv.mutex ().release (); ACE_RETURN (-1); } else // Synchronous. { // Block on condition variable. while (cv.wait ((ACE_Time_Value *) options.time_value ()) == -1) { // Note, this should obey whatever thread-specific // interrupt policy is currently in place... if (errno == EINTR) continue; // We come here if a timeout occurs or some serious // ACE_Condition object error. cv.mutex ().release (); ACELIB_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("condition variable wait") ACE_TEXT (" bombed.")), -1); } if (this->debug_) ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) unblocking %s.\n"), this->client_id ())); cv.mutex ().release (); return 0; // operation succeeded } }
int ACE_Remote_Token_Proxy::acquire (int notify, void (*sleep_hook)(void *), ACE_Synch_Options &options) { ACE_TRACE ("ACE_Remote_Token_Proxy::acquire"); // First grab the local shadow mutex. if (ACE_Token_Proxy::acquire (notify, sleep_hook, ACE_Synch_Options::asynch) == -1) { // Acquire failed, deal with it... switch (errno) { case EWOULDBLOCK : // Whoah, we detected wouldblock via the shadow mutex! if (debug_) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) shadow: acquire will block, owner is %s\n"), this->token_->owner_id ())); // No error, but would block, break; case EDEADLK : if (debug_) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) shadow: deadlock detected\n"))); if (ignore_shadow_deadlock_) break; else { errno = EDEADLK; ACE_RETURN (-1); } default : ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%t) %p shadow acquire failed\n"), ACE_TEXT ("ACE_Remote_Token_Proxy")), -1); } } ACE_Token_Request request (token_->type (), this->type (), ACE_Token_Request::ACQUIRE, this->name (), this->client_id (), options); request.notify (notify); int result = this->request_reply (request, options); if (result == -1) { // Update the local shadow copy. ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("error on remote acquire, releasing shadow mutex.\n"))); ACE_Token_Proxy::release (); } else { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) acquired %s remotely.\n"), this->name ())); // Our shadow call may have failed. However, it's still a race // to the remote server. If we beat the client which holds the // local token, we need to fix things locally to reflect the // actual ownership. All that should happen is that our waiter // is moved to the front of the waiter list. token_->make_owner (waiter_); } return result; }
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); }
int ACE_Token_Proxy::acquire (int notify, void (*sleep_hook)(void *), ACE_Synch_Options &options) { ACE_TRACE ("ACE_Token_Proxy::acquire"); if (this->token_ == 0) { errno = ENOENT; ACELIB_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Not open.\n")), -1); } // Make sure no one calls our token_acquired until we have a chance // to sleep first! If after we call an EWOULDBLOCK // mutex_->acquire() below, but before we enter handle_options to // wait on the cond_var, a thread tries to give take us off the // waiter queue and signal us, IT WILL FIRST HAVE TO ACQUIRE THIS // cond_var.mutex (). _This_ is why we acquire it. this->waiter_->cond_var_.mutex ().acquire (); this->waiter_->sleep_hook (sleep_hook); if (this->token_->acquire (this->waiter_, this->ignore_deadlock_, notify) == -1) // acquire failed { switch (errno) { case EDEADLK : if (!ignore_deadlock_) { waiter_->cond_var_.mutex ().release (); errno = EDEADLK; ACE_RETURN (-1); } // Else, fallthrough and block! case EWOULDBLOCK : if (this->debug_) ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) waiting for %s, owner is %s, ") ACE_TEXT ("total waiters == %d\n"), this->name (), this->token_->owner_id (), token_->no_of_waiters ())); // no error, but would block, if error, return error (-1), // otherwise, return whether we called the holder or not. int return_value; if (this->handle_options (options, waiter_->cond_var_) == -1) return_value = -1; else return_value = notify == 1; errno = EWOULDBLOCK; ACE_RETURN (return_value); default : waiter_->cond_var_.mutex ().release (); ACELIB_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("Token Proxy acquire.")), -1); } } else // we have the token { if (debug_) ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) acquired %s\n"), this->name ())); waiter_->cond_var_.mutex ().release (); } return 0; }