#include <Local_Tokens.h>
Inheritance diagram for ACE_RW_Token:


Public Types | |
| enum | PROXY_TYPE { READER, WRITER } |
| These are the types that proxies can be. More... | |
Public Member Functions | |
| ACE_RW_Token (const ACE_TCHAR *name) | |
| Constructor. | |
| virtual | ~ACE_RW_Token (void) |
| Destructor. | |
| virtual int | acquire (ACE_TPQ_Entry *caller, int ignore_deadlock, int notify) |
| virtual int | tryacquire (ACE_TPQ_Entry *caller) |
| Same as acquire except fails on would block. | |
| virtual int | renew (ACE_TPQ_Entry *caller, int requeue_position) |
| virtual int | release (ACE_TPQ_Entry *caller) |
| void | dump (void) const |
| Dump the state of the class. | |
| virtual int | type (void) const |
| Returns READER or WRITER. | |
| virtual int | owners (OWNER_STACK &o, const ACE_TCHAR *id) |
| virtual int | is_waiting_for (const ACE_TCHAR *id) |
| Returns 1 if is waiting for this token. 0 otherwise. | |
| virtual int | is_owner (const ACE_TCHAR *id) |
| Returns 1 if is an owner of this token. 0 otherwise. | |
Protected Member Functions | |
| void | notify_new_owner (ACE_TPQ_Entry *caller) |
| Sets the new owner. | |
Protected Attributes | |
| int | num_writers_ |
| The number of waiting writers. | |
| ACE_TOKEN_CONST::MUTEX | lock_ |
| ACE_Mutex_Token used to lock internal data structures. | |
Not a public interface. This class is a more general-purpose synchronization mechanism than SunOS 5.x mutexes. For example, it implements "recursive mutex" semantics, where a thread that owns the token can reacquire it without deadlocking. In addition, threads that are blocked awaiting the token are serviced in strict FIFO order as other threads release the token (SunOS 5.x mutexes don't strictly enforce an acquisition order).
Definition at line 593 of file Local_Tokens.h.
|
|
These are the types that proxies can be.
Definition at line 655 of file Local_Tokens.h.
|
|
|
Constructor.
Definition at line 722 of file Local_Tokens.cpp. References ACE_MAXTOKENNAMELEN, ACE_TCHAR, ACE_TRACE, and ACE_OS::strsncpy().
00723 : num_writers_ (0) 00724 { 00725 ACE_TRACE ("ACE_RW_Token::ACE_RW_Token"); 00726 00727 ACE_OS::strsncpy (this->token_name_, 00728 name, 00729 ACE_MAXTOKENNAMELEN); 00730 } |
|
|
Destructor.
Definition at line 732 of file Local_Tokens.cpp. References ACE_TRACE.
00733 {
00734 ACE_TRACE ("ACE_RW_Token::~ACE_RW_Token");
00735 }
|
|
||||||||||||||||
|
Returns 0 on success, -1 on failure with <ACE_Log_Msg::errnum> as the reason. If errnum == EWOULDBLOCK, and notify == 1, <ACE_Token_Proxy::sleep_hook> has been called on the current owner of the token. If ignore_deadlock is passed as 1 and errnum == EDEADLK, then deadlock was detected via ACE_Token_Manager. Implements ACE_Tokens. Definition at line 738 of file Local_Tokens.cpp. References ACE_GUARD_RETURN, ACE_RETURN, ACE_TRACE, ACE_TPQ_Entry::call_sleep_hook(), ACE_Token_Manager::check_deadlock(), ACE_TPQ_Entry::client_id(), EDEADLK, ACE_Token_Proxy_Queue::enqueue(), EWOULDBLOCK, ACE_Token_Manager::instance(), is_owner(), ACE_TOKEN_CONST::MUTEX, ACE_TPQ_Entry::nesting_level(), ACE_TPQ_Entry::next_, num_writers_, ACE_Tokens::owner(), ACE_TPQ_Entry::proxy(), READER, ACE_Token_Proxy::type(), and WRITER.
00741 {
00742 ACE_TRACE ("ACE_RW_Token::acquire");
00743 // We need to acquire two locks. This one to ensure that only one
00744 // thread uses this token at a time.
00745 ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon1, this->lock_, -1);
00746 // This one to ensure an atomic transaction across all tokens. Note
00747 // that this order is crucial too. It's resource coloring for other
00748 // threads which may be calling this same token.
00749 ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon2, ACE_Token_Manager::instance ()->mutex (), -1);
00750
00751 if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
00752 this->num_writers_++;
00753
00754 // Does _anyone_ own the token?
00755 if (this->owner () == 0)
00756 {
00757 // There are no waiters, so queue as the first waiter (the owner).
00758 this->waiters_.enqueue (caller, -1);
00759 return 0;
00760 }
00761
00762 // Check for recursive acquisition.
00763 if (this->is_owner (caller->client_id ()))
00764 {
00765 caller->nesting_level (1);
00766 return 0; // Success.
00767 }
00768
00769 // Reader.
00770 if (caller->proxy ()->type () == ACE_RW_Token::READER)
00771 {
00772 // Are there any writers?
00773 if (this->num_writers_ == 0)
00774 {
00775 // Queue the caller at the end of the queue.
00776 this->waiters_.enqueue (caller, -1);
00777 return 0;
00778 }
00779 // Else failure.
00780 }
00781
00782 // Failure code.
00783
00784 // Check for deadlock.
00785 if (!ignore_deadlock &&
00786 ACE_Token_Manager::instance ()->check_deadlock (caller->proxy ()) == 1)
00787 {
00788 if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
00789 this->num_writers_--;
00790 errno = EDEADLK;
00791 ACE_RETURN (-1);
00792 }
00793
00794 // Queue the caller at the end of the queue.
00795 this->waiters_.enqueue (caller, -1);
00796
00797 if (notify)
00798 {
00799 // If it's a writer, just notify it.
00800 if (this->owner ()->proxy ()->type () == ACE_RW_Token::WRITER)
00801 this->owner ()->call_sleep_hook ();
00802 else
00803 {
00804 // Call back all reader owners.
00805 ACE_TPQ_Entry *temp = this->owner ();
00806 do
00807 {
00808 temp->call_sleep_hook ();
00809 temp = temp->next_;
00810 }
00811 while (temp != 0 &&
00812 temp->proxy ()->type () == ACE_RW_Token::READER);
00813 }
00814 }
00815
00816 errno = EWOULDBLOCK;
00817 ACE_RETURN (-1);
00818
00819 ACE_NOTREACHED (return -1);
00820 }
|
|
|
Dump the state of the class.
Reimplemented from ACE_Tokens. Definition at line 706 of file Local_Tokens.cpp. References ACE_BEGIN_DUMP, ACE_DEBUG, ACE_END_DUMP, ACE_LIB_TEXT, ACE_TRACE, ACE_Tokens::dump(), ACE_Null_Mutex::dump(), LM_DEBUG, and num_writers_.
00707 {
00708 #if defined (ACE_HAS_DUMP)
00709 ACE_TRACE ("ACE_RW_Token::dump");
00710 ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00711 ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_RW_Token::dump:\n")
00712 ACE_LIB_TEXT ("num_writers_ = %d\n"), num_writers_));
00713 ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("lock_\n")));
00714 this->lock_.dump ();
00715 ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("base:\n")));
00716 ACE_Tokens::dump ();
00717 ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_RW_Token::dump end.\n")));
00718 ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00719 #endif /* ACE_HAS_DUMP */
00720 }
|
|
|
Returns 1 if is an owner of this token. 0 otherwise.
Implements ACE_Tokens. Definition at line 1059 of file Local_Tokens.cpp. References ACE_TCHAR, ACE_TRACE, ACE_TPQ_Iterator::advance(), ACE_TPQ_Entry::equal_client_id(), ACE_TPQ_Iterator::next(), ACE_Tokens::owner(), ACE_TPQ_Entry::proxy(), READER, ACE_Token_Proxy::type(), and WRITER. Referenced by acquire(), is_waiting_for(), release(), renew(), and tryacquire().
01060 {
01061 ACE_TRACE ("ACE_RW_Token::is_owner");
01062 // If there is no owner, return false.
01063 if (this->owner () == 0)
01064 return 0;
01065
01066 // A writer owns us.
01067 if (this->owner ()->proxy ()->type () == ACE_RW_Token::WRITER)
01068 return this->owner ()->equal_client_id (id);
01069
01070 // Readers own us.
01071 // Step through each owning reader looking for <id>.
01072 ACE_TPQ_Iterator iterator (waiters_);
01073 for (ACE_TPQ_Entry *temp = 0;
01074 iterator.next (temp) != 0;
01075 iterator.advance ())
01076 {
01077 if (temp->proxy ()->type () != ACE_RW_Token::READER)
01078 break;
01079
01080 if (temp->equal_client_id (id))
01081 return 1;
01082 }
01083
01084 return 0;
01085 }
|
|
|
Returns 1 if is waiting for this token. 0 otherwise.
Implements ACE_Tokens. Definition at line 1036 of file Local_Tokens.cpp. References ACE_TCHAR, ACE_TRACE, ACE_TPQ_Iterator::advance(), ACE_TPQ_Entry::equal_client_id(), is_owner(), ACE_TPQ_Iterator::next(), and ACE_Tokens::owner().
01037 {
01038 ACE_TRACE ("ACE_RW_Token::is_waiting_for");
01039 // If there is no owner, or <id> is the owner, return false.
01040 if ((this->owner () == 0) ||
01041 this->is_owner (id))
01042 return 0;
01043
01044 // Step through each waiter looking for <id>.
01045 ACE_TPQ_Iterator iterator (waiters_);
01046 iterator.advance ();
01047 for (ACE_TPQ_Entry *temp = 0;
01048 iterator.next (temp) != 0;
01049 iterator.advance ())
01050 {
01051 if (temp->equal_client_id (id))
01052 return 1;
01053 }
01054
01055 return 0;
01056 }
|
|
|
Sets the new owner.
Definition at line 957 of file Local_Tokens.cpp. References ACE_TRACE, ACE_TPQ_Iterator::advance(), ACE_TPQ_Iterator::next(), ACE_Tokens::owner(), ACE_TPQ_Entry::proxy(), READER, ACE_Token_Proxy::token_acquired(), ACE_Token_Proxy::type(), and WRITER. Referenced by release(), and renew().
00958 {
00959 ACE_TRACE ("ACE_RW_Token::notify_new_owner");
00960
00961 if (this->owner () == 0)
00962 return;
00963
00964 if (this->owner ()->proxy ()->type () == ACE_RW_Token::READER)
00965 {
00966 if (old_owner->proxy ()->type () == ACE_RW_Token::READER)
00967 // the owners already know that they're owners
00968 return;
00969
00970 // The current owner is a reader and the previous owner was a
00971 // writer, so notify all waiting readers up to the first writer.
00972 // call back all reader owners.
00973 ACE_TPQ_Iterator iterator (waiters_);
00974 for (ACE_TPQ_Entry *temp = 0;
00975 iterator.next (temp) != 0;
00976 iterator.advance ())
00977 {
00978 if (temp->proxy ()->type () == WRITER)
00979 // We've gone through all the readers.
00980 break;
00981
00982 temp->proxy ()->token_acquired (temp);
00983 }
00984 }
00985 else // writer
00986 this->owner ()->proxy ()->token_acquired (this->owner ());
00987 }
|
|
||||||||||||
|
Returns a stack of the current owners. Returns -1 on error, 0 on success. If is non-zero, returns 1 if id is an owner. Implements ACE_Tokens. Definition at line 991 of file Local_Tokens.cpp. References ACE_TCHAR, ACE_TRACE, ACE_TPQ_Iterator::advance(), ACE_TPQ_Entry::client_id(), ACE_TPQ_Iterator::next(), ACE_Tokens::owner(), ACE_TPQ_Entry::proxy(), ACE_OS::strcmp(), ACE_Token_Proxy::type(), and WRITER.
00993 {
00994 ACE_TRACE ("ACE_RW_Token::owners");
00995
00996 if (this->owner () == 0)
00997 return 0;
00998
00999 int id_is_owner = 0;
01000
01001 // The first waiter is a writer, so there is only one owner.
01002 if (this->owner ()->proxy ()->type () == WRITER)
01003 {
01004 stack.push (this->owner ());
01005 // If an <id> is specified, return whether it is the owner being
01006 // returned.
01007 if ((id != 0) &&
01008 (ACE_OS::strcmp (id, this->owner ()->client_id ()) == 0))
01009 id_is_owner = 1;
01010 }
01011 // The first waiter is a reader, so there can be multiple owning
01012 // readers.
01013 else
01014 {
01015 ACE_TPQ_Iterator iterator (waiters_);
01016 for (ACE_TPQ_Entry *temp = 0;
01017 iterator.next (temp) != 0;
01018 iterator.advance ())
01019 {
01020 if (temp->proxy ()->type () == WRITER)
01021 // We've gone through all the readers.
01022 break;
01023
01024 stack.push (temp);
01025
01026 if (!id_is_owner && (id != 0) &&
01027 (ACE_OS::strcmp (id, temp->client_id ()) == 0))
01028 id_is_owner = 1;
01029 }
01030 }
01031
01032 return id_is_owner;
01033 }
|
|
|
Relinquish the token. If there are any waiters then the next one in line gets it. If the caller is not the owner, caller is removed from the waiter list. Implements ACE_Tokens. Definition at line 926 of file Local_Tokens.cpp. References ACE_GUARD_RETURN, ACE_RETURN, ACE_TRACE, ACE_TPQ_Entry::client_id(), is_owner(), ACE_TOKEN_CONST::MUTEX, ACE_TPQ_Entry::nesting_level(), notify_new_owner(), num_writers_, ACE_Tokens::owner(), ACE_TPQ_Entry::proxy(), ACE_Tokens::remove(), ACE_Token_Proxy::type(), and WRITER.
00927 {
00928 ACE_TRACE ("ACE_RW_Token::release");
00929 ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1);
00930
00931 // Check for errors.
00932 if ((this->owner () == 0) ||
00933 (this->is_owner (caller->client_id ()) == 0))
00934 {
00935 errno = EACCES;
00936 ACE_RETURN (-1);
00937 }
00938
00939 if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
00940 num_writers_--;
00941
00942 // Recursive release.
00943 if (caller->nesting_level () > 0)
00944 {
00945 caller->nesting_level (-1);
00946 return 0;
00947 }
00948
00949 // Remove the caller and notify the new owner(s).
00950 this->remove (caller);
00951 this->notify_new_owner (caller);
00952
00953 return 0;
00954 }
|
|
||||||||||||
|
An optimized method that efficiently reacquires the token if no other threads are waiting. This is useful for situations where you don't want to degrade the quality of service if there are other threads waiting to get the token. If == -1 and there are other threads waiting to obtain the token we are queued at the end of the list of waiters. If > -1 then it indicates how many entries to skip over before inserting our thread into the list of waiters (e.g., == 0 means "insert at front of the queue"). Renew has the rather odd semantics such that if there are other waiting threads it will give up the token even if the nesting_level_ > 1. I'm not sure if this is really the right thing to do (since it makes it possible for shared data to be changed unexpectedly) so use with caution... Returns 0 on success, -1 on failure with <ACE_Log_Msg::errnum> as the reason. If errnum == EWOULDBLOCK, and notify == 1, <ACE_Token_Proxy::sleep_hook> has been called on the current owner of the token. Implements ACE_Tokens. Definition at line 880 of file Local_Tokens.cpp. References ACE_GUARD_RETURN, ACE_RETURN, ACE_TRACE, ACE_TPQ_Entry::client_id(), ACE_Token_Proxy_Queue::enqueue(), EWOULDBLOCK, is_owner(), ACE_TOKEN_CONST::MUTEX, notify_new_owner(), ACE_TPQ_Entry::proxy(), READER, ACE_Tokens::remove(), ACE_Token_Proxy_Queue::size(), and ACE_Token_Proxy::type().
00882 {
00883 ACE_TRACE ("ACE_RW_Token::renew");
00884 ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1);
00885
00886 // Werify that the caller is the owner
00887 if (this->is_owner (caller->client_id ()) == 0)
00888 {
00889 errno = EACCES;
00890 ACE_RETURN (-1);
00891 }
00892
00893 // The caller is the owner, so check to see if there are any
00894 // waiters. If not, we just keep the token.
00895 if (this->waiters_.size () == 1 || requeue_position == 0)
00896 return 0;
00897
00898 // There are waiters, so remove the caller.
00899 this->remove (caller);
00900
00901 // Requeue the caller.
00902 this->waiters_.enqueue (caller, requeue_position);
00903
00904 if (caller->proxy ()->type () == ACE_RW_Token::READER)
00905 {
00906 // If the caller got queued before any writers, the caller is
00907 // still the owner.
00908 if (this->is_owner (caller->client_id ()))
00909 return 0; // success
00910 // else fallthrough and return would block.
00911 }
00912 // Writers will always have to block since waiters_.size () == 1 or
00913 // requeue_position == 0.
00914
00915 // Get a new owner.
00916 this->notify_new_owner (caller);
00917
00918 // Tell the caller that the operation would block.
00919 errno = EWOULDBLOCK;
00920 ACE_RETURN (-1);
00921
00922 ACE_NOTREACHED (return -1);
00923 }
|
|
|
Same as acquire except fails on would block.
Implements ACE_Tokens. Definition at line 823 of file Local_Tokens.cpp. References ACE_GUARD_RETURN, ACE_RETURN, ACE_TRACE, ACE_TPQ_Entry::client_id(), ACE_Token_Proxy_Queue::enqueue(), EWOULDBLOCK, is_owner(), ACE_TOKEN_CONST::MUTEX, ACE_TPQ_Entry::nesting_level(), num_writers_, ACE_Tokens::owner(), ACE_TPQ_Entry::proxy(), READER, ACE_Token_Proxy::type(), and WRITER.
00824 {
00825 ACE_TRACE ("ACE_RW_Token::tryacquire");
00826 // We need to acquire two locks. This one to ensure that only one
00827 // thread uses this token at a time.
00828 ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon1, this->lock_, -1);
00829 // This one to ensure an atomic transaction across all tokens. Note
00830 // that this order is crucial too. It's resource coloring for other
00831 // threads which may be calling this same token.
00832 ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon2, ACE_Token_Manager::instance ()->mutex (), -1);
00833
00834 if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
00835 {
00836 this->num_writers_++;
00837 }
00838
00839 // Does _anyone_ own the token?
00840 if (this->owner () == 0)
00841 {
00842 // There are no waiters, so queue as the first waiter (the owner).
00843 this->waiters_.enqueue (caller, -1);
00844 return 0;
00845 }
00846
00847 // Check for recursive acquisition.
00848 if (this->is_owner (caller->client_id ()))
00849 {
00850 caller->nesting_level (1);
00851 return 0; // Success.
00852 }
00853
00854 // Reader.
00855 if (caller->proxy ()->type () == ACE_RW_Token::READER)
00856 {
00857 // Are there any writers?
00858 if (this->num_writers_ == 0)
00859 {
00860 // queue the caller at the end of the queue.
00861 this->waiters_.enqueue (caller, -1);
00862 return 0;
00863 }
00864 // Else, fail.
00865 }
00866 else // Writer.
00867 // We're going to fail, so decrement the num_writers.
00868 {
00869 this->num_writers_--;
00870 }
00871
00872
00873 errno = EWOULDBLOCK;
00874 ACE_RETURN (-1);
00875
00876 ACE_NOTREACHED (return -1);
00877 }
|
|
|
Returns READER or WRITER.
Implements ACE_Tokens. Definition at line 699 of file Local_Tokens.cpp. References ACE_TRACE.
00700 {
00701 ACE_TRACE ("ACE_RW_Token::type");
00702 return (int) ACE_Tokens::RWLOCK;
00703 }
|
|
|
ACE_Mutex_Token used to lock internal data structures.
Definition at line 675 of file Local_Tokens.h. |
|
|
The number of waiting writers.
Definition at line 672 of file Local_Tokens.h. Referenced by acquire(), dump(), release(), and tryacquire(). |
1.3.6