summaryrefslogtreecommitdiff
path: root/ACE/ace/Token_Manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/ace/Token_Manager.cpp')
-rw-r--r--ACE/ace/Token_Manager.cpp273
1 files changed, 273 insertions, 0 deletions
diff --git a/ACE/ace/Token_Manager.cpp b/ACE/ace/Token_Manager.cpp
new file mode 100644
index 00000000000..a68ac717ebf
--- /dev/null
+++ b/ACE/ace/Token_Manager.cpp
@@ -0,0 +1,273 @@
+#include "ace/Token_Manager.h"
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+#include "ace/Object_Manager.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Token_Manager.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID (ace,
+ Token_Manager,
+ "$Id$")
+
+ACE_BEGIN_VERSIONED_NAMESPACE_DECL
+
+// singleton token manager
+ACE_Token_Manager *ACE_Token_Manager::token_manager_ = 0;
+
+ACE_Token_Manager::ACE_Token_Manager ()
+{
+ ACE_TRACE ("ACE_Token_Manager::ACE_Token_Manager");
+}
+
+ACE_Token_Manager::~ACE_Token_Manager ()
+{
+ ACE_TRACE ("ACE_Token_Manager::~ACE_Token_Manager");
+
+ COLLECTION::ITERATOR iterator (collection_);
+
+ for (COLLECTION::ENTRY *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ // @ should I be doing an unbind here?
+ delete temp->int_id_;
+ // The ext_id_'s delete themselves when the array of
+ // COLLECTION::ENTRYs goes away.
+ }
+}
+
+ACE_Token_Manager *
+ACE_Token_Manager::instance (void)
+{
+ ACE_TRACE ("ACE_Token_Manager::instance");
+
+ // This first check is to avoid acquiring the mutex in the common
+ // case. Double-Check pattern rules.
+ if (token_manager_ == 0)
+ {
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ ACE_TOKEN_CONST::MUTEX *lock =
+ ACE_Managed_Object<ACE_TOKEN_CONST::MUTEX>::get_preallocated_object
+ (ACE_Object_Manager::ACE_TOKEN_MANAGER_CREATION_LOCK);
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, *lock, 0);
+#endif /* ACE_MT_SAFE */
+
+ if (token_manager_ == 0)
+ {
+ ACE_NEW_RETURN (token_manager_,
+ ACE_Token_Manager,
+ 0);
+ // Register for destruction with ACE_Object_Manager.
+ ACE_Object_Manager::at_exit (token_manager_);
+ }
+ }
+
+ return token_manager_;
+}
+
+void
+ACE_Token_Manager::get_token (ACE_Token_Proxy *proxy,
+ const ACE_TCHAR *token_name)
+{
+ ACE_TRACE ("ACE_Token_Manager::get_token");
+ // Hmm. I think this makes sense. We perform our own locking here
+ // (see safe_acquire.) We have to make sure that only one thread
+ // uses the collection at a time.
+
+ ACE_GUARD (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_);
+
+ TOKEN_NAME name (token_name);
+
+ if (collection_.find (name, proxy->token_) == -1)
+ // We did not find one in the collection.
+ {
+ // Make one.
+ proxy->token_ = proxy->create_token (token_name);
+
+ // Put it in the collection.
+ if (collection_.bind (name, proxy->token_) == -1)
+ {
+ delete proxy->token_;
+ proxy->token_ = 0;
+ }
+ }
+
+ if (proxy->token_ != 0)
+ proxy->token_->inc_reference ();
+
+ // We may be returning proxy->token_ == 0 if new failed, caller must
+ // check.
+}
+
+// 0. check_deadlock (TOKEN)
+// 1. if TOKEN->visited (), return 0.
+// 2. mark TOKEN visited.
+// 3. get ALL_OWNERS
+// 4. if CLIENT in ALL_OWNERS, return *DEADLOCK*.
+// 5. for each OWNER in ALL_OWNERS,
+// 6. if OWNER is not waiting for a NEW_TOKEN, continue.
+// 7. else, if check_deadlock (NEW_TOKEN) == 1, return *DEADLOCK*
+// 8. return 0.
+
+int
+ACE_Token_Manager::check_deadlock (ACE_Token_Proxy *proxy)
+{
+ ACE_TRACE ("ACE_Token_Manager::check_deadlock");
+
+ // Start the recursive deadlock detection algorithm.
+ int result = this->check_deadlock (proxy->token_, proxy);
+
+ // Whether or not we detect deadlock, we have to unmark all tokens
+ // for the next time.
+ COLLECTION::ITERATOR iterator (collection_);
+ for (COLLECTION::ENTRY *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ temp->int_id_->visit (0);
+
+ return result;
+}
+
+int
+ACE_Token_Manager::check_deadlock (ACE_Tokens *token, ACE_Token_Proxy *proxy)
+{
+ ACE_TRACE ("ACE_Token_Manager::check_deadlock");
+
+ if (token->visited ())
+ return 0;
+
+ token->visit (1);
+
+ ACE_Tokens::OWNER_STACK owners;
+
+ int is_owner = token->owners (owners, proxy->client_id ());
+
+ switch (is_owner)
+ {
+ case -1:
+ // Error.
+ return -1;
+ case 1:
+ // The caller is an owner, so we have a deadlock situation.
+ if (debug_)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) Deadlock detected.\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("%s owns %s and is waiting for %s.\n"),
+ proxy->client_id (),
+ token->name (),
+ proxy->token_->name ()));
+ }
+
+ return 1;
+ case 0:
+ default:
+ // Recurse on each owner.
+ while (!owners.is_empty ())
+ {
+ ACE_TPQ_Entry *e;
+ owners.pop (e);
+ // If the owner is waiting on another token, recurse.
+ ACE_Tokens *twf = this->token_waiting_for (e->client_id ());
+ if ((twf != 0) &&
+ (this->check_deadlock (twf, proxy) == 1))
+ {
+ if (debug_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("%s owns %s and is waiting for %s.\n"),
+ e->client_id (),
+ token->name (),
+ twf->name ()));
+ }
+ return 1;
+ }
+ // else, check the next owner.
+ }
+
+ // We've checked all the owners and found no deadlock.
+ return 0;
+ }
+}
+
+
+ACE_Tokens *
+ACE_Token_Manager::token_waiting_for (const ACE_TCHAR *client_id)
+{
+ COLLECTION::ITERATOR iterator (collection_);
+ for (COLLECTION::ENTRY *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ if (temp->int_id_->is_waiting_for (client_id))
+ return temp->int_id_;
+ }
+
+ // nothing was found, return NULL.
+ return 0;
+}
+
+// Notify the token manager that a token is has been released. If
+// as a result, there is no owner of the token, the token is
+// deleted.
+void
+ACE_Token_Manager::release_token (ACE_Tokens *&token)
+{
+ ACE_TRACE ("ACE_Token_Manager::release_token");
+ // again, let's perform our own locking here.
+
+ ACE_GUARD (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_);
+
+ if (token->dec_reference () == 0)
+ {
+ // No one has the token, so we can delete it and remove it from
+ // our collection. First, let's get it from the collection.
+ TOKEN_NAME token_name (token->name ());
+
+ ACE_Tokens *temp;
+
+ if (collection_.unbind (token_name, temp) == -1)
+ // we did not find one in the collection
+ {
+ errno = ENOENT;
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("Token Manager could not release %s:%d\n"),
+ token->name (), token->type ()));
+ // @@ bad
+ }
+ else
+ // we found it
+ {
+ // sanity pointer comparison. The token referenced by the
+ // proxy better be the one we found in the list.
+ ACE_ASSERT (token == temp);
+ delete token; // or delete temp
+ // we set their token to zero. if the calling proxy is
+ // still going to be used, it had better check it's token
+ // value before calling a method on it!
+ token = 0;
+ }
+ }
+ // else
+ // someone is still interested in the token, so keep it around.
+}
+
+void
+ACE_Token_Manager::dump (void) const
+{
+#if defined (ACE_HAS_DUMP)
+ ACE_TRACE ("ACE_Token_Manager::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Token_Manager::dump:\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("lock_\n")));
+ lock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("collection_\n")));
+ collection_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+#endif /* ACE_HAS_DUMP */
+}
+
+ACE_END_VERSIONED_NAMESPACE_DECL
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */