ACE_RW_Token Class Reference

Class that acquires, renews, and releases a process-local synchronization token. More...

#include <Local_Tokens.h>

Inheritance diagram for ACE_RW_Token:

Inheritance graph
[legend]
Collaboration diagram for ACE_RW_Token:

Collaboration graph
[legend]
List of all members.

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.


Detailed Description

Class that acquires, renews, and releases a process-local synchronization token.

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.


Member Enumeration Documentation

enum ACE_RW_Token::PROXY_TYPE
 

These are the types that proxies can be.

Enumeration values:
READER 
WRITER 

Definition at line 655 of file Local_Tokens.h.

00655 { READER, WRITER };


Constructor & Destructor Documentation

ACE_RW_Token::ACE_RW_Token const ACE_TCHAR name  )  [explicit]
 

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 }

ACE_RW_Token::~ACE_RW_Token void   )  [virtual]
 

Destructor.

Definition at line 732 of file Local_Tokens.cpp.

References ACE_TRACE.

00733 {
00734   ACE_TRACE ("ACE_RW_Token::~ACE_RW_Token");
00735 }


Member Function Documentation

int ACE_RW_Token::acquire ACE_TPQ_Entry caller,
int  ignore_deadlock,
int  notify
[virtual]
 

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 }

void ACE_RW_Token::dump void   )  const
 

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 }

int ACE_RW_Token::is_owner const ACE_TCHAR id  )  [virtual]
 

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 }

int ACE_RW_Token::is_waiting_for const ACE_TCHAR id  )  [virtual]
 

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 }

void ACE_RW_Token::notify_new_owner ACE_TPQ_Entry caller  )  [protected]
 

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 }

int ACE_RW_Token::owners OWNER_STACK o,
const ACE_TCHAR id
[virtual]
 

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 }

int ACE_RW_Token::release ACE_TPQ_Entry caller  )  [virtual]
 

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 }

int ACE_RW_Token::renew ACE_TPQ_Entry caller,
int  requeue_position
[virtual]
 

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 }

int ACE_RW_Token::tryacquire ACE_TPQ_Entry caller  )  [virtual]
 

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 }

int ACE_RW_Token::type void   )  const [virtual]
 

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 }


Member Data Documentation

ACE_TOKEN_CONST::MUTEX ACE_RW_Token::lock_ [protected]
 

ACE_Mutex_Token used to lock internal data structures.

Definition at line 675 of file Local_Tokens.h.

int ACE_RW_Token::num_writers_ [protected]
 

The number of waiting writers.

Definition at line 672 of file Local_Tokens.h.

Referenced by acquire(), dump(), release(), and tryacquire().


The documentation for this class was generated from the following files:
Generated on Thu Nov 9 11:28:24 2006 for ACE by doxygen 1.3.6