Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

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 Methods

ACE_EXPLICIT ACE_RW_Token (const ACE_TCHAR *name)
 Constructor. More...

virtual ~ACE_RW_Token (void)
 Destructor. More...

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. More...

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. More...

virtual int type (void) const
 Returns READER or WRITER. More...

virtual int owners (OWNER_STACK &o, const ACE_TCHAR *id)
 Returns a stack of the current owners. Returns -1 on error, 0 on success. If <id> is non-zero, returns 1 if id is an owner. More...

virtual int is_waiting_for (const ACE_TCHAR *id)
 Returns 1 if <id> is waiting for this token. 0 otherwise. More...

virtual int is_owner (const ACE_TCHAR *id)
 Returns 1 if <id> is an owner of this token. 0 otherwise. More...


Protected Methods

void notify_new_owner (ACE_TPQ_Entry *caller)
 Sets the new owner. More...


Protected Attributes

int num_writers_
 The number of waiting writers. More...

ACE_TOKEN_CONST::MUTEX lock_
 ACE_Mutex_Token used to lock internal data structures. More...


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 588 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 650 of file Local_Tokens.h.

00650 { READER, WRITER };


Constructor & Destructor Documentation

ACE_RW_Token::ACE_RW_Token const ACE_TCHAR   name
 

Constructor.

Definition at line 672 of file Local_Tokens.cpp.

References ACE_MAXTOKENNAMELEN, ACE_TCHAR, ACE_TRACE, ACE_Tokens::name, and ACE_OS_String::strsncpy.

00673 : num_writers_ (0)
00674 {
00675   ACE_TRACE ("ACE_RW_Token::ACE_RW_Token");
00676 
00677   ACE_OS::strsncpy (this->token_name_,
00678                     name,
00679                     ACE_MAXTOKENNAMELEN);
00680 }

ACE_RW_Token::~ACE_RW_Token void    [virtual]
 

Destructor.

Definition at line 682 of file Local_Tokens.cpp.

References ACE_TRACE.

00683 {
00684   ACE_TRACE ("ACE_RW_Token::~ACE_RW_Token");
00685 }


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 688 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_Null_Mutex::lock_, 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, ACE_Tokens::waiters_, and WRITER.

00691 {
00692   ACE_TRACE ("ACE_RW_Token::acquire");
00693   // We need to acquire two locks. This one to ensure that only one
00694   // thread uses this token at a time.
00695   ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon1, this->lock_, -1);
00696   // This one to ensure an atomic transaction across all tokens.  Note
00697   // that this order is crucial too.  It's resource coloring for other
00698   // threads which may be calling this same token.
00699   ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon2, ACE_Token_Manager::instance ()->mutex (), -1);
00700 
00701   if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
00702     this->num_writers_++;
00703 
00704   // Does _anyone_ own the token?
00705   if (this->owner () == 0)
00706     {
00707       // There are no waiters, so queue as the first waiter (the owner).
00708       this->waiters_.enqueue (caller, -1);
00709       return 0;
00710     }
00711 
00712   // Check for recursive acquisition.
00713   if (this->is_owner (caller->client_id ()))
00714     {
00715       caller->nesting_level (1);
00716       return 0;  // Success.
00717     }
00718 
00719   // Reader.
00720   if (caller->proxy ()->type () == ACE_RW_Token::READER)
00721     {
00722       // Are there any writers?
00723       if (this->num_writers_ == 0)
00724         {
00725           // Queue the caller at the end of the queue.
00726           this->waiters_.enqueue (caller, -1);
00727           return 0;
00728         }
00729       // Else failure.
00730     }
00731 
00732   // Failure code.
00733 
00734   // Check for deadlock.
00735   if (!ignore_deadlock &&
00736       ACE_Token_Manager::instance ()->check_deadlock (caller->proxy ()) == 1)
00737     {
00738       if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
00739         this->num_writers_--;
00740       errno = EDEADLK;
00741       ACE_RETURN (-1);
00742     }
00743 
00744   // Queue the caller at the end of the queue.
00745   this->waiters_.enqueue (caller, -1);
00746 
00747   if (notify)
00748     {
00749       // If it's a writer, just notify it.
00750       if (this->owner ()->proxy ()->type () == ACE_RW_Token::WRITER)
00751         this->owner ()->call_sleep_hook ();
00752       else
00753         {
00754           // Call back all reader owners.
00755           ACE_TPQ_Entry *temp = this->owner ();
00756           do
00757             {
00758               temp->call_sleep_hook ();
00759               temp = temp->next_;
00760             }
00761           while (temp != 0 &&
00762                  temp->proxy ()->type () == ACE_RW_Token::READER);
00763         }
00764     }
00765 
00766   errno = EWOULDBLOCK;
00767   ACE_RETURN (-1);
00768 
00769   ACE_NOTREACHED (return -1);
00770 }

void ACE_RW_Token::dump void    const
 

Dump the state of the class.

Reimplemented from ACE_Tokens.

Definition at line 658 of file Local_Tokens.cpp.

References ACE_BEGIN_DUMP, ACE_DEBUG, ACE_END_DUMP, ACE_LIB_TEXT, ACE_TRACE, ACE_Tokens::dump, LM_DEBUG, lock_, and num_writers_.

00659 {
00660   ACE_TRACE ("ACE_RW_Token::dump");
00661   ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00662   ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("ACE_RW_Token::dump:\n")
00663                         ACE_LIB_TEXT ("num_writers_ = %d\n"), num_writers_));
00664   ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("lock_\n")));
00665   this->lock_.dump ();
00666   ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("base:\n")));
00667   ACE_Tokens::dump ();
00668   ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("ACE_RW_Token::dump end.\n")));
00669   ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00670 }

int ACE_RW_Token::is_owner const ACE_TCHAR   id [virtual]
 

Returns 1 if <id> is an owner of this token. 0 otherwise.

Implements ACE_Tokens.

Definition at line 1009 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, ACE_Tokens::waiters_, and WRITER.

Referenced by acquire, is_waiting_for, release, renew, and tryacquire.

01010 {
01011   ACE_TRACE ("ACE_RW_Token::is_owner");
01012   // If there is no owner, return false.
01013   if (this->owner () == 0)
01014     return 0;
01015 
01016   // A writer owns us.
01017   if (this->owner ()->proxy ()->type () == ACE_RW_Token::WRITER)
01018     return this->owner ()->equal_client_id (id);
01019 
01020   // Readers own us.
01021   // Step through each owning reader looking for <id>.
01022   ACE_TPQ_Iterator iterator (waiters_);
01023   for (ACE_TPQ_Entry *temp = 0;
01024        iterator.next (temp) != 0;
01025        iterator.advance ())
01026     {
01027       if (temp->proxy ()->type () != ACE_RW_Token::READER)
01028         break;
01029 
01030       if (temp->equal_client_id (id))
01031         return 1;
01032     }
01033 
01034   return 0;
01035 }

int ACE_RW_Token::is_waiting_for const ACE_TCHAR   id [virtual]
 

Returns 1 if <id> is waiting for this token. 0 otherwise.

Implements ACE_Tokens.

Definition at line 986 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, ACE_Tokens::owner, and ACE_Tokens::waiters_.

00987 {
00988   ACE_TRACE ("ACE_RW_Token::is_waiting_for");
00989   // If there is no owner, or <id> is the owner, return false.
00990   if ((this->owner () == 0) ||
00991       this->is_owner (id))
00992     return 0;
00993 
00994   // Step through each waiter looking for <id>.
00995   ACE_TPQ_Iterator iterator (waiters_);
00996   iterator.advance ();
00997   for (ACE_TPQ_Entry *temp = 0;
00998        iterator.next (temp) != 0;
00999        iterator.advance ())
01000     {
01001       if (temp->equal_client_id (id))
01002         return 1;
01003     }
01004 
01005   return 0;
01006 }

void ACE_RW_Token::notify_new_owner ACE_TPQ_Entry   caller [protected]
 

Sets the new owner.

Definition at line 907 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, ACE_Tokens::waiters_, and WRITER.

Referenced by release, and renew.

00908 {
00909   ACE_TRACE ("ACE_RW_Token::notify_new_owner");
00910 
00911   if (this->owner () == 0)
00912     return;
00913 
00914   if (this->owner ()->proxy ()->type () == ACE_RW_Token::READER)
00915     {
00916       if (old_owner->proxy ()->type () == ACE_RW_Token::READER)
00917         // the owners already know that they're owners
00918         return;
00919 
00920       // The current owner is a reader and the previous owner was a
00921       // writer, so notify all waiting readers up to the first writer.
00922       // call back all reader owners.
00923       ACE_TPQ_Iterator iterator (waiters_);
00924       for (ACE_TPQ_Entry *temp = 0;
00925            iterator.next (temp) != 0;
00926            iterator.advance ())
00927         {
00928           if (temp->proxy ()->type () == WRITER)
00929             // We've gone through all the readers.
00930             break;
00931 
00932           temp->proxy ()->token_acquired (temp);
00933         }
00934     }
00935   else // writer
00936     this->owner ()->proxy ()->token_acquired (this->owner ());
00937 }

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 <id> is non-zero, returns 1 if id is an owner.

Implements ACE_Tokens.

Definition at line 941 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_String::strcmp, ACE_Token_Proxy::type, ACE_Tokens::waiters_, and WRITER.

00943 {
00944   ACE_TRACE ("ACE_RW_Token::owners");
00945 
00946   if (this->owner () == 0)
00947     return 0;
00948 
00949   int id_is_owner = 0;
00950 
00951   // The first waiter is a writer, so there is only one owner.
00952   if (this->owner ()->proxy ()->type () == WRITER)
00953     {
00954       stack.push (this->owner ());
00955       // If an <id> is specified, return whether it is the owner being
00956       // returned.
00957       if ((id != 0) &&
00958           (ACE_OS::strcmp (id, this->owner ()->client_id ()) == 0))
00959         id_is_owner = 1;
00960     }
00961   // The first waiter is a reader, so there can be multiple owning
00962   // readers.
00963   else
00964     {
00965       ACE_TPQ_Iterator iterator (waiters_);
00966       for (ACE_TPQ_Entry *temp = 0;
00967            iterator.next (temp) != 0;
00968            iterator.advance ())
00969         {
00970           if (temp->proxy ()->type () == WRITER)
00971             // We've gone through all the readers.
00972             break;
00973 
00974           stack.push (temp);
00975 
00976           if (!id_is_owner && (id != 0) &&
00977               (ACE_OS::strcmp (id, temp->client_id ()) == 0))
00978             id_is_owner = 1;
00979         }
00980     }
00981 
00982   return id_is_owner;
00983 }

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 876 of file Local_Tokens.cpp.

References ACE_GUARD_RETURN, ACE_RETURN, ACE_TRACE, ACE_TPQ_Entry::client_id, is_owner, ACE_Null_Mutex::lock_, 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.

00877 {
00878   ACE_TRACE ("ACE_RW_Token::release");
00879   ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1);
00880 
00881   // Check for errors.
00882   if ((this->owner () == 0) ||
00883       (this->is_owner (caller->client_id ()) == 0))
00884     {
00885       errno = EACCES;
00886       ACE_RETURN (-1);
00887     }
00888 
00889   if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
00890     num_writers_--;
00891 
00892   // Recursive release.
00893   if (caller->nesting_level () > 0)
00894     {
00895       caller->nesting_level (-1);
00896       return 0;
00897     }
00898 
00899   // Remove the caller and notify the new owner(s).
00900   this->remove (caller);
00901   this->notify_new_owner (caller);
00902 
00903   return 0;
00904 }

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 <requeue_position> == -1 and there are other threads waiting to obtain the token we are queued at the end of the list of waiters. If <requeue_position> > -1 then it indicates how many entries to skip over before inserting our thread into the list of waiters (e.g., <requeue_position> == 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 830 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_Null_Mutex::lock_, ACE_TOKEN_CONST::MUTEX, notify_new_owner, ACE_TPQ_Entry::proxy, READER, ACE_Tokens::remove, ACE_Token_Proxy_Queue::size, ACE_Token_Proxy::type, and ACE_Tokens::waiters_.

00832 {
00833   ACE_TRACE ("ACE_RW_Token::renew");
00834   ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1);
00835 
00836   // Werify that the caller is the owner
00837   if (this->is_owner (caller->client_id ()) == 0)
00838     {
00839       errno = EACCES;
00840       ACE_RETURN (-1);
00841     }
00842 
00843   // The caller is the owner, so check to see if there are any
00844   // waiters.  If not, we just keep the token.
00845   if (this->waiters_.size () == 1 || requeue_position == 0)
00846     return 0;
00847 
00848   // There are waiters, so remove the caller.
00849   this->remove (caller);
00850 
00851   // Requeue the caller.
00852   this->waiters_.enqueue (caller, requeue_position);
00853 
00854   if (caller->proxy ()->type () == ACE_RW_Token::READER)
00855     {
00856       // If the caller got queued before any writers, the caller is
00857       // still the owner.
00858       if (this->is_owner (caller->client_id ()))
00859         return 0; // success
00860       // else fallthrough and return would block.
00861     }
00862   // Writers will always have to block since waiters_.size () == 1 or
00863   // requeue_position == 0.
00864 
00865   // Get a new owner.
00866   this->notify_new_owner (caller);
00867 
00868   // Tell the caller that the operation would block.
00869   errno = EWOULDBLOCK;
00870   ACE_RETURN (-1);
00871 
00872   ACE_NOTREACHED (return -1);
00873 }

int ACE_RW_Token::tryacquire ACE_TPQ_Entry   caller [virtual]
 

Same as acquire except fails on would block.

Implements ACE_Tokens.

Definition at line 773 of file Local_Tokens.cpp.

References ACE_GUARD_RETURN, ACE_RETURN, ACE_TRACE, ACE_TPQ_Entry::client_id, ACE_Token_Proxy_Queue::enqueue, EWOULDBLOCK, ACE_Token_Manager::instance, is_owner, ACE_Null_Mutex::lock_, ACE_TOKEN_CONST::MUTEX, ACE_TPQ_Entry::nesting_level, num_writers_, ACE_Tokens::owner, ACE_TPQ_Entry::proxy, READER, ACE_Token_Proxy::type, ACE_Tokens::waiters_, and WRITER.

00774 {
00775   ACE_TRACE ("ACE_RW_Token::tryacquire");
00776   // We need to acquire two locks. This one to ensure that only one
00777   // thread uses this token at a time.
00778   ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon1, this->lock_, -1);
00779   // This one to ensure an atomic transaction across all tokens.  Note
00780   // that this order is crucial too.  It's resource coloring for other
00781   // threads which may be calling this same token.
00782   ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon2, ACE_Token_Manager::instance ()->mutex (), -1);
00783 
00784   if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
00785     {
00786       this->num_writers_++;
00787     }
00788 
00789   // Does _anyone_ own the token?
00790   if (this->owner () == 0)
00791     {
00792       // There are no waiters, so queue as the first waiter (the owner).
00793       this->waiters_.enqueue (caller, -1);
00794       return 0;
00795     }
00796 
00797   // Check for recursive acquisition.
00798   if (this->is_owner (caller->client_id ()))
00799     {
00800       caller->nesting_level (1);
00801       return 0;  // Success.
00802     }
00803 
00804   // Reader.
00805   if (caller->proxy ()->type () == ACE_RW_Token::READER)
00806     {
00807       // Are there any writers?
00808       if (this->num_writers_ == 0)
00809         {
00810           // queue the caller at the end of the queue.
00811           this->waiters_.enqueue (caller, -1);
00812           return 0;
00813         }
00814       // Else, fail.
00815     }
00816   else // Writer.
00817     // We're going to fail, so decrement the num_writers.
00818     {
00819       this->num_writers_--;
00820     }
00821 
00822 
00823   errno = EWOULDBLOCK;
00824   ACE_RETURN (-1);
00825 
00826   ACE_NOTREACHED (return -1);
00827 }

virtual int ACE_RW_Token::type void    const [virtual]
 

Returns READER or WRITER.

Implements ACE_Tokens.


Member Data Documentation

ACE_TOKEN_CONST::MUTEX ACE_RW_Token::lock_ [protected]
 

ACE_Mutex_Token used to lock internal data structures.

Definition at line 670 of file Local_Tokens.h.

Referenced by dump.

int ACE_RW_Token::num_writers_ [protected]
 

The number of waiting writers.

Definition at line 667 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 Mon Jun 16 12:55:30 2003 for ACE by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002