Use =default for skeleton copy constructor
[ACE_TAO.git] / ACE / tests / TSS_Test.cpp
blob62feb2045194b26a2c9e20685f0def2487b802b2
2 //=============================================================================
3 /**
4 * @file TSS_Test.cpp
6 * This program tests thread specific storage of data. The ACE_TSS
7 * wrapper transparently ensures that the objects of this class
8 * will be placed in thread-specific storage. All calls on
9 * ACE_TSS::operator->() are delegated to the appropriate method
10 * in the Errno class.
12 * @author Prashant Jain <pjain@cs.wustl.edu> and Doug Schmidt <d.schmidt@vanderbilt.edu>
14 //=============================================================================
17 #include "test_config.h"
18 #include "ace/OS_NS_unistd.h"
19 #include "ace/Guard_T.h"
20 #include "ace/Thread_Manager.h"
21 #include "ace/Thread_Mutex.h"
22 #include "ace/Signal.h"
23 #include "TSS_Test_Errno.h"
26 static u_int errors = 0;
28 #if defined (ACE_HAS_THREADS)
30 #if defined (ACE_DEFAULT_THREAD_KEYS)
31 // If ACE_DEFAULT_THREAD_KEYS is defined, it is probably
32 // set to a small value. So that the test doesn't run out
33 // of keys quickly in the first thread, set the number of
34 // ITERATIONS to be small as well.
35 static const int ITERATIONS =
36 (ACE_DEFAULT_THREAD_KEYS - ACE_MAX_THREADS) / (2 * ACE_MAX_THREADS) < 2
37 ? 1
38 : (ACE_DEFAULT_THREAD_KEYS - ACE_MAX_THREADS) / (2 * ACE_MAX_THREADS);
39 #else
40 // POSIX requires at least _POSIX_THREAD_KEYS_MAX (128) keys. 25
41 // iterations with 4 worker threads should be sufficient to check
42 // the TSS wrappers without exceeding the minimum requirements.
44 static const int ITERATIONS = 25;
45 #endif /* ACE_DEFAULT_THREAD_KEYS */
47 // Static variables.
48 int Errno::flags_;
49 int Errno::created_;
50 int Errno::deleted_;
52 ACE_Thread_Mutex *Errno::lock_ = 0;
54 // This is our thread-specific error handler . . .
55 // See comment below about why it's dynamically allocated.
56 static ACE_TSS<Errno> *tss_error;
58 // This is for testing/demonstrating ACE_TSS_Type_Adapter. It's
59 // dynamically allocated to avoid static objects, also.
60 static ACE_TSS<ACE_TSS_Type_Adapter<u_int> > *u;
62 // Serializes output.
63 static ACE_Thread_Mutex output_lock;
65 extern "C" void
66 cleanup (void *ptr)
68 // Don't do this: ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) in cleanup, ptr = %x\n"), ptr));
69 // The Log_Msg buffer is a TSS object, too, and it may be gone!
70 // if you must say something here try:
71 // ACE_OS::fprintf (stderr, ACE_TEXT("(%d) in cleanup, ptr = %x\n"), ACE_Thread::self(), ptr);
72 // and this:
73 // operator delete (ptr);
74 // is nonsense when applied to a void *! (even tho the compilers accept it????
75 delete static_cast <int *> (ptr);
78 // This worker function is the entry point for each thread.
80 static void *
81 worker (void *c)
83 int count = *(static_cast<int*> (c));
85 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) worker, iterations = %d\n"), count));
87 ACE_thread_key_t key = ACE_OS::NULL_key;
88 int *ip = 0;
90 // Make one key that will be available when the thread exits so that
91 // we'll have something to cleanup!
93 if (ACE_Thread::keycreate (&key, cleanup) == -1)
95 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p (no keys available)\n"),
96 ACE_TEXT ("ACE_Thread::keycreate")));
97 return (void *) -1;
100 ACE_NEW_RETURN (ip, int, 0);
102 if (ACE_Thread::setspecific (key, (void *) ip) == -1)
103 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
104 ACE_TEXT ("ACE_Thread::setspecific")));
106 for (int i = 0; i < count; i++)
108 if (ACE_Thread::keycreate (&key, cleanup) == -1)
110 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p (no more keys)\n"),
111 ACE_TEXT ("ACE_Thread::keycreate")));
112 break;
115 ACE_NEW_RETURN (ip, int, 0);
117 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) in worker at location 1, ")
118 ACE_TEXT ("key = %d, ip = %x\n"),
119 key, ip));
121 // Needed to work around (possibly broken?) strict aliasing warning in GCC.
122 void *v_ip (reinterpret_cast <void *> (ip));
124 if (ACE_Thread::setspecific (key, v_ip) == -1)
125 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
126 ACE_TEXT ("ACE_Thread::setspecific")));
128 if (ACE_Thread::getspecific (key, &v_ip) == -1)
129 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
130 ACE_TEXT ("ACE_Thread::getspecific")));
132 if (ACE_Thread::setspecific (key, (void *) 0) == -1)
133 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
134 ACE_TEXT ("ACE_Thread::setspecific")));
136 // See comment in cleanup () above.
137 delete ip;
139 #if defined (ACE_HAS_TSS_EMULATION)
140 if (ACE_Thread::keyfree (key) == -1)
141 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
142 ACE_TEXT ("ACE_Thread::keyfree")));
143 #endif /* ACE_HAS_TSS_EMULATION */
145 // Cause an error.
146 ACE_OS::read (ACE_INVALID_HANDLE, 0, 0);
148 // The following two lines set the thread-specific state.
149 (*tss_error)->error (errno);
150 (*tss_error)->line (__LINE__);
152 // This sets the static state (note how C++ makes it easy to do
153 // both).
154 (*tss_error)->flags (count);
157 // Use the guard to serialize access
158 ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, output_lock, 0));
159 ACE_TEST_ASSERT ((*tss_error)->flags () == ITERATIONS);
162 // Demonstrate use of ACE_TSS_Type_Adapter to wrap built-in
163 // types when used with ACE_TSS. See DESCRIPTION of template
164 // class ACE_TSS_Type_Adapter for what this
165 // should look like. Unfortunately, some compilers have trouble
166 // with the implicit type conversions. Others have problems with
167 // the *explicit* type conversions.
168 #if !defined (ACE_HAS_BROKEN_EXPLICIT_TYPECAST_OPERATOR_INVOCATION)
169 (*u)->operator u_int & () = 37;
170 if ((*u)->operator u_int () != 37)
172 // Use the guard to serialize access to errors.
173 ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, output_lock,
174 0));
175 ACE_DEBUG ((LM_ERROR,
176 ACE_TEXT ("use of ACE_TSS_Type_Adapter failed, value ")
177 ACE_TEXT ("is %u, it should be 37!\n"),
178 (*u)->operator u_int ()));
179 ++errors;
181 #endif /* !defined (ACE_HAS_BROKEN_EXPLICIT_TYPECAST_OPERATOR_INVOCATION) */
183 #if defined (ACE_HAS_TSS_EMULATION)
184 key = ACE_OS::NULL_key;
186 if (ACE_Thread::keycreate (&key, cleanup) == -1)
188 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p (no more keys)\n"),
189 ACE_TEXT ("ACE_Thread::keycreate")));
190 break;
193 ACE_NEW_RETURN (ip, int, 0);
195 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) in worker at location 2, ")
196 ACE_TEXT ("key = %d, ip = %x\n"),
197 key, ip));
199 // Needed to work around (possibly broken?) strict aliasing warning in GCC.
200 void *v_ip2 (reinterpret_cast <void *> (ip));
202 if (ACE_Thread::setspecific (key, v_ip2) == -1)
203 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
204 ACE_TEXT ("ACE_Thread::setspecific")));
206 if (ACE_Thread::getspecific (key, &v_ip2) == -1)
207 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
208 ACE_TEXT ("ACE_Thread::getspecific")));
210 if (ACE_Thread::setspecific (key, (void *) 0) == -1)
211 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
212 ACE_TEXT ("ACE_Thread::setspecific")));
214 // See comment in cleanup () above.
215 delete ip;
217 // ACE_HAS_TSS_EMULATION is turned on, then it should work.
218 # if defined (ACE_HAS_TSS_EMULATION)
219 if (ACE_Thread::keyfree (key) == -1)
220 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
221 ACE_TEXT ("ACE_Thread::keyfree")));
222 # endif /* defined (ACE_HAS_TSS_EMULATION) */
223 #endif /* ACE_HAS_TSS_EMULATION */
225 return 0;
228 #endif /* ACE_HAS_THREADS */
231 run_main (int, ACE_TCHAR *[])
233 ACE_START_TEST (ACE_TEXT ("TSS_Test"));
235 #if defined (ACE_HAS_THREADS)
236 Errno::allocate_lock ();
238 const u_int threads = ACE_MAX_THREADS;
240 // Dynamically allocate TSS_Error so that we can control when it
241 // gets deleted. Specifically, we need to delete it before the
242 // ACE_Object_Manager destroys the ACE_Allocator. That's because
243 // deletion of TSS_Error causes the internal structures of
244 // ACE_TSS_Cleanup to be modified, and which in turn uses
245 // ACE_Allocator.
246 ACE_NEW_RETURN (tss_error, ACE_TSS<Errno>, 1);
248 // Similarly, dynamically allocate u.
249 ACE_NEW_RETURN (u, ACE_TSS<ACE_TSS_Type_Adapter<u_int> >, 1);
251 int iterations = ITERATIONS;
252 if (ACE_Thread_Manager::instance ()->spawn_n
253 (threads,
254 ACE_THR_FUNC (worker),
255 &iterations,
256 THR_BOUND) == -1)
257 ACE_ERROR_RETURN ((LM_ERROR,
258 ACE_TEXT ("%p\n"), ACE_TEXT ("spawn_n")), 1);
260 ACE_Thread_Manager::instance ()->wait ();
262 delete u;
263 delete tss_error;
265 Errno::deallocate_lock ();
268 if (Errno::created () != Errno::deleted ())
270 //@@TODO: this should probably be promoted to an error rather than just a
271 // warning.
272 ACE_ERROR ((LM_DEBUG,
273 ACE_TEXT ("(%P|%t) Warning: Number created (%d) != number deleted (%d)\n"),
274 Errno::created (),
275 Errno::deleted ()
279 #else /* ACE_HAS_THREADS */
280 ACE_ERROR ((LM_INFO,
281 ACE_TEXT ("threads are not supported on this platform\n")));
282 #endif /* ACE_HAS_THREADS */
284 ACE_END_TEST;
285 return errors ? -1 : 0;