// -*- C++ -*- //============================================================================= /** * @file Local_Tokens.h * * @author Karl-Heinz Dorn * @author Douglas C. Schmidt * @author Tim Harrison * * This file contains definitions for the following classes: * * public: * 7. ACE_Token_Proxy * 8. ACE_Null_Token : public ACE_Token_Proxy * 9. ACE_Local_Mutex : public ACE_Token_Proxy * *. ACE_Local_RLock : public ACE_Local_Mutex * &. ACE_Local_WLock : public ACE_Local_Mutex * private: * 1. ACE_TOKEN_CONST * 3. ACE_TPQ_Entry * b. ACE_TSS_TPQ_Entry * c. ACE_TPQ_Iterator * 4. ACE_Token_Proxy_Queue * 5. ACE_Tokens * 6. ACE_Mutex_Token : public ACE_Tokens * 12. ACE_RW_Token : public ACE_Tokens * a. ACE_Token_Name * * Note that the locking classes defined in this file are *not* * intended to be used as general-purpose synchronization * mechanisms, such as mutexes or semaphores. Instead, you should * use the ACE_Recursive_Thread_Mutex, ACE_Thread_Mutex, * ACE_Thread_Semaphore, etc., that are defined in * $ACE_ROOT/ace/Synch.h or the * ACE_Token that's defined in $ACE_ROOT/ace/Token.h. */ //============================================================================= #ifndef ACE_LOCAL_MUTEX_H #define ACE_LOCAL_MUTEX_H #include /**/ "ace/pre.h" #include /**/ "ace/config-all.h" #if !defined (ACE_LACKS_PRAGMA_ONCE) # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ #if defined (ACE_HAS_TOKENS_LIBRARY) #include "ace/Synch_Traits.h" #include "ace/Condition_Thread_Mutex.h" #include "ace/TSS_T.h" #include "ace/Containers.h" #include "ace/Synch_Options.h" #include "ace/Map_Manager.h" #include "ace/Log_Category.h" #include "ace/OS_NS_string.h" #include "ace/os_include/os_netdb.h" #if !(defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREAD_SPECIFIC_STORAGE)) # define ACE_NO_TSS_TOKENS 1 #endif /* !(defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREAD_SPECIFIC_STORAGE)) */ ACE_BEGIN_VERSIONED_NAMESPACE_DECL // 1. /** * @class ACE_TOKEN_CONST * * @brief Not a public interface. * * Constant definitions and typedefs for Token library. Mostly, * this class is necessary to fight the compiler with order of * declaration errors. */ // FUZZ: disable check_for_ACE_Guard namespace ACE_TOKEN_CONST { #if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) // ACE platform supports some form of threading. typedef ACE_Condition_Thread_Mutex COND_VAR; typedef ACE_Thread_Mutex MUTEX; typedef ACE_Guard GUARD; #else typedef ACE_Null_Condition COND_VAR; typedef ACE_Null_Mutex MUTEX; typedef ACE_Guard GUARD; #endif /* ACE_HAS_THREADS */ } // FUZZ: enable check_for_ACE_Guard // Forward decl. class ACE_Token_Proxy; // 3.. /** * @class ACE_TPQ_Entry * * @brief Token Proxy Queue entry. Used in the ACE_Token_Proxy_Queue * * Not a public interface. */ class ACE_Export ACE_TPQ_Entry { friend class ACE_Token_Manager; public: typedef void (*PTVF) (void *); /// Null constructor. ACE_TPQ_Entry (void); /// Constructor. ACE_TPQ_Entry (const ACE_Token_Proxy *proxy, const ACE_TCHAR *client_id); /// Copy constructor. ACE_TPQ_Entry (const ACE_TPQ_Entry &rhs); /// Destructor. ~ACE_TPQ_Entry (void); /// Copy operator use by the queue. void operator= (const ACE_TPQ_Entry &rhs); /// Get top of the queue. ACE_Token_Proxy *proxy () const; /// Set top of the queue. void proxy (ACE_Token_Proxy *); /// Get nesting level of the entry. int nesting_level () const; /// Delta nesting level of the entry. void nesting_level (int delta); /// Get client_id of the entry. const ACE_TCHAR *client_id () const; /// Set client_id of the entry. void client_id (const ACE_TCHAR *); /// Returns 1 if @a id == client id. Does not check for @a id == 0. int equal_client_id (const ACE_TCHAR *id); /// One method for arg and sleep_hook. void set (void (*sleep_hook)(void *)); /// Set sleep hook of the entry. void sleep_hook (void (*sh)(void *)); /// Get sleep hook of the entry. PTVF sleep_hook () const; /// Call the sleep hook function or method passing arg. void call_sleep_hook (void); /// Dump the state of the class. void dump () const; // = Used to block the thread if an acquire fails with EWOULDBLOCK. ACE_TOKEN_CONST::COND_VAR cond_var_; ACE_TOKEN_CONST::MUTEX lock_; /// Pointer to next in list. ACE_TPQ_Entry *next_; /// Get whether this client is blocked waiting for a token. int waiting () const; /// Set whether this client is blocked waiting for a token. void waiting (int w); private: /// This client is waiting for a token. int waiting_; /// Proxy. ACE_Token_Proxy *proxy_; /// Nesting level. int nesting_level_; /// Arg. void *arg_; /// Client id. ACE_TCHAR client_id_[ACE_MAXCLIENTIDLEN]; /// Sleep hook. void (*sleep_hook_)(void *); }; // b.. #if defined (ACE_NO_TSS_TOKENS) typedef ACE_TPQ_Entry ACE_TPQ_ENTRY; #else typedef ACE_TSS ACE_TPQ_ENTRY; #endif /* ACE_NO_TSS_TOKENS */ /** * @class ACE_TSS_TPQ_Entry * * @brief ACE_TSS_TPQ_Entry * * Not a public interface. */ class ACE_Export ACE_TSS_TPQ_Entry : public ACE_TPQ_ENTRY { public: /// These are passed to the constructor of ACE_TPQ_Entry in /// make_TSS_TYPE ACE_TSS_TPQ_Entry (const ACE_Token_Proxy *proxy, const ACE_TCHAR *client_id); /// Destructor. virtual ~ACE_TSS_TPQ_Entry (void); /// Allows us to pass args to the construction of the TSS object. virtual ACE_TPQ_Entry *make_TSS_TYPE () const; /// Operator overloading and inheritance don't mix. operator ACE_TPQ_Entry *(void); /// Dump the state of the class. void dump () const; #if defined (ACE_NO_TSS_TOKENS) ACE_TPQ_Entry *operator-> (void) { return (ACE_TPQ_Entry *) this; } #endif /* ACE_NO_TSS_TOKENS */ private: /// Private: should not be used ACE_TSS_TPQ_Entry (const ACE_TSS_TPQ_Entry &); void operator= (const ACE_TSS_TPQ_Entry &); // = These are passed to the constructor of ACE_TPQ_Entry in // make_TSS_TYPE /// Proxy. const ACE_Token_Proxy *proxy_; /// Client_id. const ACE_TCHAR *client_id_; }; class ACE_Token_Proxy_Queue; // c.. /** * @class ACE_TPQ_Iterator * * @brief Iterates through ACE_Token_Proxy_Queues. * * Not a public interface. */ class ACE_Export ACE_TPQ_Iterator { public: /// Constructor. ACE_TPQ_Iterator (ACE_Token_Proxy_Queue &q); /// Destructor. ~ACE_TPQ_Iterator () = default; /// Pass back the @a next_item. int next (ACE_TPQ_Entry *&next_item); /// Returns 1 when all items have been seen, else 0. int done () const; /// Move forward by one element in the queue. void advance (void); /// Dump the state of an object. void dump () const; private: ACE_TPQ_Entry *current_; }; // 4.. /** * @class ACE_Token_Proxy_Queue * * @brief Token waiter list. * * Not a public interface. * This queue holds all the token proxies waiting for ownership * of a token. Along with the proxy reference, it also stores * the nesting level, client id, and a magic cookie from the * proxy. This queue stores the ACE_TPQ_Entries by pointer * values. It DOES NOT make copies. Thus, the user is * responsible to ensure that the TPQ's stick around. This is * motivated by the need to reduce dynamic memory allocation. */ class ACE_Export ACE_Token_Proxy_Queue { public: friend class ACE_TPQ_Iterator; /// Constructor. ACE_Token_Proxy_Queue (void); /// Destructor. ~ACE_Token_Proxy_Queue () = default; /** * Enqueue a proxy, nesting level, client_id, and a magic cookie at * the given position in the list. If the position is -1, we * enqueue at the end of the list (I think). */ void enqueue (ACE_TPQ_Entry* new_entry, int position); /// Top of the queue. const ACE_TPQ_Entry* head (void); // int member (const ACE_TCHAR *id); // Is this id in the waiter list? /// Remove the top waiter. void dequeue (void); /// Remove the waiter whose proxy ref matches @a remove_me. void remove (const ACE_TPQ_Entry *remove_me); /// The number of waiters. int size (void); /// Dump the state of the class. void dump () const; protected: /// Head. ACE_TPQ_Entry *head_; /// Tail. ACE_TPQ_Entry *tail_; /// Size. int size_; }; // 5.. /** * @class ACE_Tokens * * @brief Abstract representation of ACE tokens. * * Not a public interface. * Currently, I don't see a reason for providing an abstract * interface at this level of the library. As of yet, no one * uses ACE_Tokens derivatives through this abstract interface * except for ACE_Token_Manager. It only uses the statistical * methods which are shared by all Tokens. For that reason, it * still makes since to have a common base class. However, * acquire, renew, and release do not need to have matching * interfaces throughout all Tokens. * To add a new type of token (e.g. semaphore), this class must * be subtyped to define the new semantics. See * ACE_Token_Manager for details. */ class ACE_Export ACE_Tokens { public: /// Null constructor. ACE_Tokens (); /// Destructor virtual ~ACE_Tokens () = default; /// No implementation. virtual int acquire (ACE_TPQ_Entry *caller, int ignore_deadlock, int notify) = 0; /// No implementation. virtual int tryacquire (ACE_TPQ_Entry *caller) = 0; /// No implementation. virtual int renew (ACE_TPQ_Entry *caller, int requeue_position) = 0; /// No implementation. virtual int release (ACE_TPQ_Entry *caller) = 0; /// Move the caller to the front of the waiter list. This is for use /// with remote mutexes and shadow mutexes. void make_owner (ACE_TPQ_Entry *caller); /// Remove the caller from the waiter list. void remove (ACE_TPQ_Entry *caller); // = Accessor methods. /// Stack of owners. typedef ACE_Unbounded_Stack OWNER_STACK; /// Returns a stack of the current owners. Returns -1 on error, 0 on /// success. If @a id is non-zero, returns 1 if id is an owner. virtual int owners (OWNER_STACK &o, const ACE_TCHAR *id) = 0; /// Returns 1 if @a id is waiting for this token. 0 otherwise. virtual int is_waiting_for (const ACE_TCHAR *id) = 0; /// Returns 1 if @a id is an owner of this token. 0 otherwise. virtual int is_owner (const ACE_TCHAR *id) = 0; /// Return the queue of waiters. virtual ACE_Token_Proxy_Queue *waiters (void); /// Return the number of proxies that are currently waiting to get /// the token. virtual int no_of_waiters (void); /// The current owner. const ACE_TCHAR *owner_id (void); /// Token name. const ACE_TCHAR* name (void); // = Reference counting. These are only called by the // Token_Manager. void inc_reference (void); int dec_reference (void); /// Dump the state of the class. void dump () const; /** * These are the Token types supported by the library at ship time. * There is no restriction on the number of Token types added by * "3rd parties." These are only necessary for the Token Server. */ enum TOKEN_TYPES { MUTEX, RWLOCK }; /** * Provides a manual RTTI mechanism. This method is used only by * ACE_Token_Request so that the type of a token can be sent to a * remote Token Server. */ virtual int type () const = 0; // = The following methods allow the deadlock detection algorithm to // check if this token has been visited. /// Mark or unmark the token as visited. void visit (int v); /// Check if the token has been visited. int visited (void); /// All the data of the current owner. ACE_TPQ_Entry *owner (void); protected: /// For the deadlock detection algorithm. int visited_; /// Reference count. int reference_count_; /// List of client's owning and waiting the token. ACE_Token_Proxy_Queue waiters_; /// Name of token. ACE_TCHAR token_name_[ACE_MAXTOKENNAMELEN]; }; class ACE_Local_Mutex; // 6.. /** * @class ACE_Mutex_Token * * @brief 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). */ class ACE_Export ACE_Mutex_Token : public ACE_Tokens { public: /// Constructor explicit ACE_Mutex_Token (const ACE_TCHAR* name); /// Destructor virtual ~ACE_Mutex_Token (void); // = Synchronization operations. // With acquire, renew, and release, the caller must be specified so // that multiple proxies (e.g. ACE_Local_Mutex) can use the same // token. /** * Returns 0 on success, -1 on failure with as * the reason. If errnum == EWOULDBLOCK, and notify == 1, * 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. */ virtual int acquire (ACE_TPQ_Entry *caller, int ignore_deadlock, int notify); /// Same as acquire, but fails if would block virtual int tryacquire (ACE_TPQ_Entry *caller); /** * 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 as the reason. * If errnum == EWOULDBLOCK, and notify == 1, * has been called on the current * owner of the token. */ virtual int renew (ACE_TPQ_Entry *caller, int requeue_position); /** * 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. */ virtual int release (ACE_TPQ_Entry *caller); /// Dump the state of the class. void dump () const; /// Returns ACE_Tokens::MUTEX. virtual int type () const; /// Returns a stack of the current owners. Returns -1 on error, 0 on /// success. If @a id is non-zero, returns 1 if id is an owner. virtual int owners (OWNER_STACK &o, const ACE_TCHAR *id); /// Returns 1 if @a id is waiting for this token. 0 otherwise. virtual int is_waiting_for (const ACE_TCHAR *id); /// Returns 1 if @a id is an owner of this token. 0 otherwise. virtual int is_owner (const ACE_TCHAR *id); private: /// ACE_Mutex_Token used to lock internal data structures. ACE_TOKEN_CONST::MUTEX lock_; }; // 12.. /** * @class ACE_RW_Token * * @brief 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). */ class ACE_Export ACE_RW_Token : public ACE_Tokens { public: /// Constructor. explicit ACE_RW_Token (const ACE_TCHAR* name); /// Destructor. virtual ~ACE_RW_Token (void); // = Synchronization operations. // With acquire, renew, and release, the caller must be specified so // that multiple proxies (e.g. ACE_Local_Mutex) can use the same // token. /** * Returns 0 on success, -1 on failure with as * the reason. If errnum == EWOULDBLOCK, and notify == 1, * has been called on the current * owner of the token. If @a ignore_deadlock is passed as 1 and errnum * == EDEADLK, then deadlock was detected via ACE_Token_Manager. */ virtual int acquire (ACE_TPQ_Entry *caller, int ignore_deadlock, int notify); /// Same as acquire except fails on would block virtual int tryacquire (ACE_TPQ_Entry *caller); /** * 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 as the reason. * If errnum == EWOULDBLOCK, and notify == 1, * has been called on the current * owner of the token. */ virtual int renew (ACE_TPQ_Entry *caller, int requeue_position); /** * 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. */ virtual int release (ACE_TPQ_Entry *caller); /// Dump the state of the class. void dump () const; /// These are the types that proxies can be. enum PROXY_TYPE { READER, WRITER }; /// Returns READER or WRITER. virtual int type () const; /// Returns a stack of the current owners. Returns -1 on error, 0 on /// success. If @a id is non-zero, returns 1 if id is an owner. virtual int owners (OWNER_STACK &o, const ACE_TCHAR *id); /// Returns 1 if @a id is waiting for this token. 0 otherwise. virtual int is_waiting_for (const ACE_TCHAR *id); /// Returns 1 if @a id is an owner of this token. 0 otherwise. virtual int is_owner (const ACE_TCHAR *id); protected: /// The number of waiting writers. int num_writers_; /// ACE_Mutex_Token used to lock internal data structures. ACE_TOKEN_CONST::MUTEX lock_; /// Sets the new owner. void notify_new_owner (ACE_TPQ_Entry *caller); }; // a.. /** * @class ACE_Token_Name * * @brief Allows Token_Manger to identify tokens. * * For now, this is just a string. We need a string class * anyway to use in ACE_Map_Manager. Having this class * (instead of ) allows us to easily change if * needed. For instance, we may choose to identify tokens by * name and *type* in the future. */ class ACE_Export ACE_Token_Name { public: /// Construction. ACE_Token_Name (const ACE_TCHAR *token_name = 0); /// Copy construction. ACE_Token_Name (const ACE_Token_Name &rhs); /// Destructor. virtual ~ACE_Token_Name (void); /// Copy. void operator= (const ACE_Token_Name &rhs); /// Comparison. bool operator== (const ACE_Token_Name &rhs) const; /// Get the token name. const ACE_TCHAR *name () const; /// Set the token name. void name (const ACE_TCHAR *new_name); /// Dump the state of the class. void dump () const; private: /// Name of the token. ACE_TCHAR token_name_[ACE_MAXTOKENNAMELEN]; }; // 7.. /** * @class ACE_Token_Proxy * * @brief Abstract representation of ACE tokens. * * Interface for all Tokens in ACE. This class implements the * synchronization needed for tokens (condition variables etc.) * The algorithms for the operations (acquire, release, etc.) * operate on the generic ACE_Tokens interface. Thus, the _type_ * of token (mutex, rwlock) can be set at construction of * ACE_Token_Proxy. You can use all Tokens in ACE through the * ACE_Token_Proxy by passing the proper values at construction. * Alternatively, there are class definitions which "know" how to * do this (ACE_Local_Mutex, ACE_Local_RLock, ACE_Local_WLock). * To add a new type of token (e.g. semaphore), this class is not * changed. See ACE_Token_Manager for details. * Tokens (e.g. ACE_Mutex_Token) assume that it can always call * on a new token owner. This * is not a problem for synchronous use of token proxies (that is, * when acquires block until successful.) However, for * implementations of the Token Server, which may use asynch * operations, the proxy can not go away after an acquire until * the token is acquired. This is not really a problem, but * should be understood. */ class ACE_Export ACE_Token_Proxy { public: friend class ACE_Token_Manager; friend class ACE_Token_Invariant_Manager; // For testing. // Initialization and termination methods. /// Construction. ACE_Token_Proxy (void); /// Destructor. virtual ~ACE_Token_Proxy (void); /** * Open the . * @param name The string uniquely identifying the token. * @param ignore_deadlock Can be 1 to disable deadlock notifications. * @param debug Prints debug messages. */ virtual int open (const ACE_TCHAR *name, int ignore_deadlock = 0, int debug = 0); // = The following methods have implementations which are // independent of the token semantics (mutex, rwlock, etc.) They // forward operations to the underlying token and perform the // necessary blocking semantics for operations (condition variables // etc.) This allows reuse of the blocking code as well as having // multiple proxies to the same token. /// Calls acquire on the token. Blocks the calling thread if would /// block. virtual int acquire (int notify = 0, void (*sleep_hook)(void *) = 0, ACE_Synch_Options &options = ACE_Synch_Options::defaults); /// Calls renew on the token. Blocks the calling thread if would block. virtual int renew (int requeue_position = -1, ACE_Synch_Options &options = ACE_Synch_Options::defaults); /// Calls renew on the token. virtual int tryacquire (void (*sleep_hook)(void *) = 0); /// Calls release on the token. virtual int release (ACE_Synch_Options &options = ACE_Synch_Options::defaults); /// Calls remove on the token. virtual int remove (ACE_Synch_Options &options = ACE_Synch_Options::defaults); /// Since the locking mechanism doesn't support read locks then this /// just calls . virtual int acquire_read (int notify = 0, void (*sleep_hook)(void *) = 0, ACE_Synch_Options &options = ACE_Synch_Options::defaults); /// Since the locking mechanism doesn't support write locks then this /// just calls . virtual int acquire_write (int notify = 0, void (*sleep_hook)(void *) = 0, ACE_Synch_Options &options = ACE_Synch_Options::defaults); /// Since the locking mechanism doesn't support read locks then this /// just calls . virtual int tryacquire_read (void (*sleep_hook)(void *) = 0); /// Since the locking mechanism doesn't support write locks then this /// just calls . virtual int tryacquire_write (void (*sleep_hook)(void *) = 0); // = Utility methods. /// Get the client id of the proxy. This is implemented as /// thread-specific data. virtual const ACE_TCHAR *client_id () const; /** * Set the client_id for the calling thread. I strongly recommend * that this not be used unless you really know what you're doing. * I use this in the Token Server, and it caused many headaches. */ virtual void client_id (const ACE_TCHAR *client_id); /** * Return the name of the token. This is important for use within * the token servers (local and remote) as well as with token * collections. So, all derivations of ACE_Token_Proxy must be able to * stringify some name. The name must uniquely identify a token. * So, for instance, the token within the reactor should probably be * called "Reactor Token." */ virtual const ACE_TCHAR *name () const; /** * This should really be called . This is called * by ACE_Token_xx's when another proxy enters the waiting list and * requests that the current token holder be notified. */ virtual void sleep_hook (void); /// This is called when a queued (waiting) proxy is removed from the /// waiters list and given the token. virtual void token_acquired (ACE_TPQ_Entry *); /// The client id of the current token holder virtual const ACE_TCHAR *owner_id (void); /// Return a dynamically allocated clone of the derived class. virtual ACE_Token_Proxy *clone () const = 0; /// Dump the state of the class. void dump () const; /** * This method can be used be Tokens (e.g. Readers/Writer Tokens) to * distinguish between Proxy types. For instance a Reader proxy * should return a different type value than a Writer proxy. The * default implementation returns 0. */ virtual int type () const; protected: /// Duplication. ACE_Token_Proxy (const ACE_Token_Proxy &); /// If this is set, we ignore deadlock. int ignore_deadlock_; /// Print a bunch of debug messages. int debug_; /// Reference to the actual logical token. Many ACE_Local_Mutex /// proxies can reference the same ACE_Mutex_Token. ACE_Tokens *token_; /// Handles cond_var waits. int handle_options (ACE_Synch_Options &options, ACE_TOKEN_CONST::COND_VAR &cv); /// Waiter info used for asynchronous transactions. ACE_TSS_TPQ_Entry waiter_; /// Make the correct type of ACE_Tokens. This is called by the Token /// Manager. virtual ACE_Tokens *create_token (const ACE_TCHAR *name) = 0; }; // 8.. /** * @class ACE_Null_Token * * @brief No op class for nonthreaded platform protocols. */ class ACE_Export ACE_Null_Token : public ACE_Token_Proxy { public: /// Construction. ACE_Null_Token () = default; /// Destructor. ~ACE_Null_Token () = default; /// Acquire. virtual int acquire (int /* notify */ = 0, void (* /* sleep_hook */ )(void *) = 0, ACE_Synch_Options & /* options */ = ACE_Synch_Options::defaults) { return 0; } /// Renew. virtual int renew (int /* requeue_position */ = -1, ACE_Synch_Options & /* options */ = ACE_Synch_Options::defaults) { return 0; } /// Try acquire. virtual int tryacquire (void (* /* sleep_hook */)(void *) = 0) { return 0; } /// Release. virtual int release (ACE_Synch_Options & /* options */ = ACE_Synch_Options::defaults) { return 0; } /// Remove. virtual int remove (ACE_Synch_Options & /* options */ = ACE_Synch_Options::defaults) { return 0; } /// Return a dynamically allocated clone of the derived class. virtual ACE_Token_Proxy *clone () const { return new ACE_Null_Token; } /// Dump the state of the class. void dump () const; /// Do not allow the Token Manager to create us. virtual ACE_Tokens *create_token (const ACE_TCHAR *) { return 0; } }; // 9.. /** * @class ACE_Local_Mutex * * @brief Class that acquires, renews, and releases a synchronization * token local to the process. * * 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). Lastly, * ACE_Local_Mutex performs deadlock detection on acquire calls. * The interfaces for acquire, tryacquire, renew, release, * etc. are defined in ACE_Token_Proxy. The semantics for * ACE_Local_Mutex are that of a mutex. */ class ACE_Export ACE_Local_Mutex : public ACE_Token_Proxy { public: /** * Constructor. * @param token_name Uniquely id's the token. * @param ignore_deadlock Will allow deadlock to occur (useful for testing). * @param debug Prints a bunch of messages. */ ACE_Local_Mutex (const ACE_TCHAR *token_name = 0, int ignore_deadlock = 0, int debug = 0); /// Destructor ~ACE_Local_Mutex (void); /// Dump the state of the class. void dump () const; /// Return deep copy. virtual ACE_Token_Proxy *clone () const; protected: /// Return a new ACE_Local_Mutex. virtual ACE_Tokens *create_token (const ACE_TCHAR *name); }; // *. /** * @class ACE_Local_RLock * * @brief Class that acquires, renews, and releases a readers lock that * is local to the process. * * This class implements the reader interface to canonical * readers/writer locks. Multiple readers can hold the lock * simultaneously when no writers have the lock. Alternatively, * when a writer holds the lock, no other participants (readers * or writers) may hold the lock. This class is a more * general-purpose synchronization mechanism than SunOS 5.x * RLocks. For example, it implements "recursive RLock" * 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 RLockes don't strictly * enforce an acquisition order). * The interfaces for acquire, tryacquire, renew, release, * etc. are defined in ACE_Token_Proxy. The semantics for * ACE_Local_RLock are that of a readers/writers lock. Acquire * for this class implies a reader acquisition. That is, * multiple clients may acquire a lock for read only. */ class ACE_Export ACE_Local_RLock : public ACE_Token_Proxy { public: /** * Constructor. * @param token_name Uniquely id's the token. * @param ignore_deadlock Will allow deadlock to occur (useful for testing). * @param debug Prints a bunch of messages. */ ACE_Local_RLock (const ACE_TCHAR *token_name = 0, int ignore_deadlock = 0, int debug = 0); /// Destructor ~ACE_Local_RLock (void); /// Dump the state of the class. void dump () const; /// Returns ACE_RW_Token::RLOCK. virtual int type () const; /// Return deep copy. virtual ACE_Token_Proxy *clone () const; protected: /// Return a new ACE_Local_Mutex. virtual ACE_Tokens *create_token (const ACE_TCHAR *name); }; // *. /** * @class ACE_Local_WLock * * @brief Class that acquires, renews, and releases a writer lock that * is local to the process. * * This class implements the writer interface to canonical * readers/writer locks. Multiple readers can hold the lock * simultaneously when no writers have the lock. Alternatively, * when a writer holds the lock, no other participants (readers * or writers) may hold the lock. This class is a more * general-purpose synchronization mechanism than SunOS 5.x * WLock. For example, it implements "recursive WLock" * 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 WLocks don't strictly * enforce an acquisition order). * The interfaces for acquire, tryacquire, renew, release, * etc. are defined in ACE_Token_Proxy. The semantics for * ACE_Local_WLock are that of a readers/writers lock. Acquire * for this class implies a writer acquisition. That is, only * one client may hold the lock for writing. */ class ACE_Export ACE_Local_WLock : public ACE_Token_Proxy { public: /** * Constructor. * @param token_name Uniquely id's the token. * @param ignore_deadlock Will allow deadlock to occur (useful for testing). * @param debug Prints a bunch of messages. */ ACE_Local_WLock (const ACE_TCHAR *token_name = 0, int ignore_deadlock = 0, int debug = 0); /// Destructor ~ACE_Local_WLock (); /// Dump the state of the class. void dump () const; /// Returns ACE_RW_Token::WLOCK. virtual int type () const; /// Return deep copy. virtual ACE_Token_Proxy *clone () const; protected: /// Return a new ACE_Local_Mutex. ACE_Tokens *create_token (const ACE_TCHAR *name); }; ACE_END_VERSIONED_NAMESPACE_DECL #endif /* ACE_HAS_TOKENS_LIBRARY */ #if defined (__ACE_INLINE__) #include "ace/Local_Tokens.inl" #endif /* __ACE_INLINE__ */ #include /**/ "ace/post.h" #endif /* ACE_LOCAL_MUTEX_H */