summaryrefslogtreecommitdiff
path: root/ACE/ace/TSS_T.h
blob: 203a7ad1ded2e899dc4263e886937ef035e80cff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
// -*- C++ -*-

//==========================================================================
/**
 *  @file    TSS_T.h
 *
 *   Moved from Synch.h.
 *
 *  @author Douglas C. Schmidt <d.schmidt@vanderbilt.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 typically 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;

  /// Declare the dynamic allocation hooks.
  ACE_ALLOC_HOOK_DECLARE;

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 */