#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(). |