summaryrefslogtreecommitdiff
path: root/ACE/ace/TSS_T.h
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/ace/TSS_T.h')
-rw-r--r--ACE/ace/TSS_T.h269
1 files changed, 269 insertions, 0 deletions
diff --git a/ACE/ace/TSS_T.h b/ACE/ace/TSS_T.h
new file mode 100644
index 00000000000..6b710bb69e7
--- /dev/null
+++ b/ACE/ace/TSS_T.h
@@ -0,0 +1,269 @@
+// -*- C++ -*-
+
+//==========================================================================
+/**
+ * @file TSS_T.h
+ *
+ * $Id$
+ *
+ * Moved from Synch.h.
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//==========================================================================
+
+#ifndef ACE_TSS_T_H
+#define ACE_TSS_T_H
+#include /**/ "ace/pre.h"
+
+#include "ace/Lock.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// This should probably go somewhere else, but it's only used here and
+// in Thread_Manager.
+// Note there is no ACE_TSS_SET because one would typicaly do
+// 'ACE_TSS_GET()->xyz_ = value', so the macro would have been too
+// complicated.
+# if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))
+# define ACE_TSS_TYPE(T) ACE_TSS< T >
+# define ACE_TSS_GET(I, T) ((I)->operator T * ())
+# else
+# define ACE_TSS_TYPE(T) T
+# define ACE_TSS_GET(I, T) (I)
+# endif /* ACE_HAS_THREADS && (ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION) */
+
+#include "ace/Thread_Mutex.h"
+#include "ace/Copy_Disabled.h"
+
+ACE_BEGIN_VERSIONED_NAMESPACE_DECL
+
+#if defined (ACE_HAS_THR_C_DEST)
+class ACE_TSS_Adapter;
+#endif
+
+/**
+ * @class ACE_TSS
+ *
+ * @brief Allows objects that are "physically" in thread specific
+ * storage (i.e., private to a thread) to be accessed as though
+ * they were "logically" global to a program.
+ *
+ * This class helps to maintain a separate copy of an object for each thread
+ * that needs access to it. All threads access a single instance of ACE_TSS
+ * to obtain a pointer to a thread-specific copy of a TYPE object. Using
+ * a pointer to TYPE in TSS instead of TYPE itself is useful because,
+ * in addition to avoiding copies on what may be a complex class, it allows
+ * assignment of objects to thread-specific data that have arbitrarily
+ * complex constructors.
+ *
+ * When the ACE_TSS object is destroyed, all threads's instances of the
+ * data are deleted.
+ *
+ * Modern compilers have no problem using a built-in type for @c TYPE.
+ * However, if you must use an older compiler that won't work with a built-in
+ * type, the ACE_TSS_Type_Adapter class template, below, can be used for
+ * adapting built-in types to work with ACE_TSS.
+ *
+ * @note Beware when creating static instances of this type
+ * (as with any other, btw). The unpredictable order of initialization
+ * across different platforms may cause a situation where one uses
+ * the instance before it is fully initialized. That's why typically
+ * instances of this type are dynamicaly allocated. On the stack it is
+ * typically allocated inside the ACE_Thread::svc() method which
+ * limits its lifetime appropriately.
+ *
+ */
+template <class TYPE>
+class ACE_TSS : private ACE_Copy_Disabled
+{
+public:
+ /**
+ * Default constructor. Can also initialize this ACE_TSS instance,
+ * readying it for use by the calling thread as well as all other
+ * threads in the process. If the constructor does not initialize this
+ * object, the first access to it will perform the initialization, which
+ * could possibly (under odd error conditions) fail.
+ *
+ * @param ts_obj If non-zero, this object is initialized for use by
+ * all threads and @a ts_obj is used to set the
+ * thread-specific value for the calling thread. Other
+ * threads use the ts_object (TYPE *) method to set
+ * a specific value.
+ */
+ ACE_TSS (TYPE *ts_obj = 0);
+
+ /// Deregister this object from thread-specific storage administration.
+ /// Will cause all threads' copies of TYPE to be destroyed.
+ virtual ~ACE_TSS (void);
+
+ /**
+ * Set the thread-specific object for the calling thread.
+ * If this object has not been initialized yet, this method performs the
+ * initialization.
+ *
+ * @param new_ts_obj The new value for the calling thread's copy of
+ * this object.
+ *
+ * @return The previous value of the calling thread's copy of this
+ * object; 0 if there was no previous value. This method also
+ * returns 0 on errors. To tell the difference between an error
+ * and a returned 0 pointer, it's recommended that one set errno
+ * to 0 prior to calling ts_object() and check for a new errno
+ * value if ts_object() returns 0.
+ */
+ TYPE *ts_object (TYPE *new_ts_obj);
+
+ /** @name Accessors
+ *
+ * All accessors return a pointer to the calling thread's copy of the
+ * TYPE data. The pointer may be 0 on error conditions or if the calling
+ * thread's copy of the data has not yet been set. See specific method
+ * descriptions for complete details.
+ */
+ //@{
+ /**
+ * Get the thread-specific object for this object.
+ *
+ * @return 0 if the object has never been initialized, otherwise returns
+ * the calling thread's copy of the data. The returned pointer
+ * may be 0 under odd error conditions; check errno for further
+ * information.
+ */
+ TYPE *ts_object (void) const;
+
+ /**
+ * Use a "smart pointer" to get the thread-specific data associated
+ * with this object.
+ * If this ACE_TSS object hasn't been initialized, this method
+ * will initialize it as a side-affect. If the calling thread has not
+ * set a value, a default-constructed instance of TYPE is allocated and it
+ * becomes the thread's instance.
+ *
+ * @return The calling thread's copy of the data. The returned pointer
+ * may be 0 under odd error conditions; check errno for further
+ * information.
+ */
+ TYPE *operator-> () const;
+
+ /**
+ * Obtain a pointer to the calling thread's TYPE object.
+ * If this ACE_TSS object hasn't been initialized, this method
+ * will initialize it as a side-affect. If the calling thread has not
+ * set a value, a default-constructed instance of TYPE is allocated and it
+ * becomes the thread's instance.
+ *
+ * @return The calling thread's copy of the data. The returned pointer
+ * may be 0 under odd error conditions; check errno for further
+ * information.
+ */
+ operator TYPE *(void) const;
+
+ //@}
+
+ /// Hook for construction parameters.
+ virtual TYPE *make_TSS_TYPE (void) const;
+
+ // = Utility methods.
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+
+protected:
+ /// Actually implements the code that retrieves the object from
+ /// thread-specific storage.
+ TYPE *ts_get (void) const;
+
+ /// Factors out common code for initializing TSS. This must NOT be
+ /// called with the lock held...
+ int ts_init (void);
+
+#if !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)))
+ /// This implementation only works for non-threading systems...
+ TYPE *type_;
+#else
+ /// Avoid race conditions during initialization.
+ ACE_Thread_Mutex keylock_;
+
+ /// "First time in" flag.
+ volatile bool once_;
+
+ /// Key for the thread-specific error data.
+ ACE_thread_key_t key_;
+
+ /// "Destructor" that deletes internal TYPE * when thread exits.
+ static void cleanup (void *ptr);
+
+ /// Obtains a plain value stored in the thread-specific storage.
+# if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *ts_value (void) const;
+# else
+ TYPE *ts_value (void) const;
+# endif /* ACE_HAS_THR_C_DEST */
+
+ /// Stores a new plain value in the thread-specific storage.
+# if defined (ACE_HAS_THR_C_DEST)
+ int ts_value (ACE_TSS_Adapter *new_tss_adapter) const;
+# else
+ int ts_value (TYPE *new_ts_obj) const;
+# endif /* ACE_HAS_THR_C_DEST */
+#endif /* defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) */
+};
+
+/**
+ * @class ACE_TSS_Type_Adapter
+ *
+ * @brief Adapter that allows built-in types to be used with ACE_TSS.
+ *
+ * Wraps a value of a built-in type, providing conversions to
+ * and from the type. Example use with ACE_TSS:
+ * ACE_TSS<ACE_TSS_Type_Adapter<int> > i;
+ * *i = 37;
+ * ACE_OS::fprintf (stderr, "%d\n", *i);
+ * Unfortunately, though, some compilers have trouble with the
+ * implicit type conversions. This seems to work better:
+ * ACE_TSS<ACE_TSS_Type_Adapter<int> > i;
+ * i->operator int & () = 37;
+ * ACE_OS::fprintf (stderr, "%d\n", i->operator int ());
+ */
+template <class TYPE>
+class ACE_TSS_Type_Adapter
+{
+public:
+ /// Constructor. Inlined here so that it should _always_ be inlined.
+ ACE_TSS_Type_Adapter (const TYPE value = 0): value_ (value) {}
+
+ /// TYPE conversion. Inlined here so that it should _always_ be
+ /// inlined.
+ operator TYPE () const { return value_; };
+
+ /// TYPE & conversion. Inlined here so that it should _always_ be
+ /// inlined.
+ operator TYPE &() { return value_; };
+
+private:
+ /// The wrapped value.
+ TYPE value_;
+};
+
+ACE_END_VERSIONED_NAMESPACE_DECL
+
+#if defined (__ACE_INLINE__)
+#include "ace/TSS_T.inl"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/TSS_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("TSS_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include /**/ "ace/post.h"
+#endif /* ACE_TSS_T_H */