2 //=============================================================================
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
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
38 : (ACE_DEFAULT_THREAD_KEYS
- ACE_MAX_THREADS
) / (2 * ACE_MAX_THREADS
);
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 */
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
;
63 static ACE_Thread_Mutex output_lock
;
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);
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.
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
;
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")));
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")));
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"),
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.
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 */
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
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
,
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 ()));
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")));
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"),
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.
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 */
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
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
254 ACE_THR_FUNC (worker
),
257 ACE_ERROR_RETURN ((LM_ERROR
,
258 ACE_TEXT ("%p\n"), ACE_TEXT ("spawn_n")), 1);
260 ACE_Thread_Manager::instance ()->wait ();
265 Errno::deallocate_lock ();
268 if (Errno::created () != Errno::deleted ())
270 //@@TODO: this should probably be promoted to an error rather than just a
272 ACE_ERROR ((LM_DEBUG
,
273 ACE_TEXT ("(%P|%t) Warning: Number created (%d) != number deleted (%d)\n"),
279 #else /* ACE_HAS_THREADS */
281 ACE_TEXT ("threads are not supported on this platform\n")));
282 #endif /* ACE_HAS_THREADS */
285 return errors
? -1 : 0;