1 martin 1.110 //%LICENSE////////////////////////////////////////////////////////////////
2 //
3 // Licensed to The Open Group (TOG) under one or more contributor license
4 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
5 // this work for additional information regarding copyright ownership.
6 // Each contributor licenses this file to you under the OpenPegasus Open
7 // Source License; you may not use this file except in compliance with the
8 // License.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 martin 1.110 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27 karl 1.89 //
|
28 martin 1.110 //////////////////////////////////////////////////////////////////////////
|
29 mike 1.2 //
30 //%/////////////////////////////////////////////////////////////////////////////
31
32 #include "Thread.h"
|
33 mike 1.96 #include <errno.h>
|
34 kumpf 1.68 #include <exception>
|
35 kumpf 1.14 #include <Pegasus/Common/Tracer.h>
|
36 kumpf 1.103 #include <Pegasus/Common/AutoPtr.h>
|
37 mike 1.91 #include "Time.h"
|
38 mike 1.2
|
39 mike 1.91 PEGASUS_USING_STD;
|
40 mike 1.2
41 PEGASUS_NAMESPACE_BEGIN
42
|
43 mike 1.91 //==============================================================================
44 //
45 // POSIX Threads Implementation:
46 //
47 //==============================================================================
|
48 mday 1.42
|
49 mike 1.91 #if defined(PEGASUS_HAVE_PTHREADS)
50
51 struct StartWrapperArg
|
52 chip 1.11 {
|
53 mike 1.91 void *(PEGASUS_THREAD_CDECL * start) (void *);
54 void *arg;
55 };
|
56 mike 1.2
|
57 mike 1.91 extern "C" void *_start_wrapper(void *arg_)
|
58 chuck 1.43 {
|
59 kumpf 1.104 // Clean up dynamic memory now to prevent a leak if the thread is canceled.
60 StartWrapperArg arg;
61 arg.start = ((StartWrapperArg *) arg_)->start;
62 arg.arg = ((StartWrapperArg *) arg_)->arg;
63 delete (StartWrapperArg *) arg_;
|
64 chuck 1.43
|
65 marek 1.105 // establish cancelability of the thread
66 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
67 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
68
|
69 kumpf 1.104 void *return_value = (*arg.start) (arg.arg);
|
70 chuck 1.37
|
71 mike 1.91 return return_value;
72 }
|
73 mike 1.2
|
74 mike 1.91 void Thread::cancel()
|
75 mike 1.2 {
|
76 mike 1.94 pthread_cancel(_handle.thid.thread);
|
77 mike 1.2 }
|
78 kumpf 1.81
|
79 mike 1.91 void Thread::thread_switch()
80 {
|
81 r.kieninger 1.108 #if defined(PEGASUS_OS_ZOS)
|
82 mike 1.91 pthread_yield(NULL);
83 #else
84 sched_yield();
|
85 mike 1.2 #endif
|
86 mike 1.91 }
|
87 mike 1.2
|
88 mike 1.91 void Thread::sleep(Uint32 msec)
|
89 chuck 1.39 {
|
90 mike 1.91 Threads::sleep(msec);
|
91 chuck 1.37 }
92
|
93 kumpf 1.98 void Thread::join()
|
94 chuck 1.37 {
|
95 mike 1.94 if (!_is_detached && !Threads::null(_handle.thid))
96 pthread_join(_handle.thid.thread, &_exit_code);
|
97 kumpf 1.81
|
98 mike 1.91 Threads::clear(_handle.thid);
|
99 chuck 1.37 }
100
|
101 kumpf 1.98 void Thread::detach()
|
102 chuck 1.37 {
|
103 mike 1.91 _is_detached = true;
|
104 r.kieninger 1.108 #if defined(PEGASUS_OS_ZOS)
|
105 mike 1.94 pthread_t thread_id=_handle.thid.thread;
|
106 mike 1.91 pthread_detach(&thread_id);
107 #else
|
108 mike 1.94 pthread_detach(_handle.thid.thread);
|
109 mike 1.91 #endif
|
110 chuck 1.37 }
111
|
112 mike 1.91 ThreadStatus Thread::run()
113 {
114 StartWrapperArg *arg = new StartWrapperArg;
115 arg->start = _start;
116 arg->arg = this;
|
117 mday 1.52
|
118 mike 1.91 Threads::Type type = _is_detached ? Threads::DETACHED : Threads::JOINABLE;
119 int rc = Threads::create(_handle.thid, type, _start_wrapper, arg);
|
120 kumpf 1.81
|
121 kumpf 1.98 // On Linux distributions released prior 2005, the implementation of
|
122 mike 1.91 // Native POSIX Thread Library returns ENOMEM instead of EAGAIN when
|
123 kumpf 1.98 // there
|
124 mike 1.91 // are no insufficient memory. Hence we are checking for both. See bug
125 // 386.
|
126 mday 1.58
|
127 marek 1.93 if (rc == -1)
128 rc = errno;
|
129 mike 1.91 if ((rc == EAGAIN) || (rc == ENOMEM))
|
130 kumpf 1.81 {
|
131 mike 1.91 Threads::clear(_handle.thid);
132 delete arg;
133 return PEGASUS_THREAD_INSUFFICIENT_RESOURCES;
|
134 kumpf 1.81 }
|
135 mike 1.91 else if (rc != 0)
|
136 kumpf 1.81 {
|
137 mike 1.91 Threads::clear(_handle.thid);
138 delete arg;
139 return PEGASUS_THREAD_SETUP_FAILURE;
|
140 kumpf 1.81 }
|
141 mike 1.91 return PEGASUS_THREAD_OK;
142 }
|
143 mday 1.58
|
144 kumpf 1.98 Thread::Thread(
145 ThreadReturnType(PEGASUS_THREAD_CDECL* start) (void*),
146 void* parameter,
147 Boolean detached)
148 : _is_detached(detached),
149 _start(start),
150 _cleanup(),
151 _thread_parm(parameter),
152 _exit_code(0)
|
153 mike 1.91 {
154 Threads::clear(_handle.thid);
|
155 mike 1.109 memset(_tsd, 0, sizeof(_tsd));
|
156 kumpf 1.81 }
|
157 mday 1.20
|
158 mike 1.91 Thread::~Thread()
|
159 mday 1.20 {
|
160 kumpf 1.81 try
161 {
|
162 mike 1.91 join();
163 empty_tsd();
|
164 kumpf 1.81 }
|
165 kumpf 1.98 catch (...)
|
166 kumpf 1.81 {
|
167 mike 1.91 // Do not allow the destructor to throw an exception
|
168 kumpf 1.81 }
|
169 mday 1.20 }
170
|
171 mike 1.91 #endif /* PEGASUS_HAVE_PTHREADS */
172
173 //==============================================================================
174 //
175 // Windows Threads Implementation:
176 //
177 //==============================================================================
|
178 kumpf 1.81
|
179 mike 1.91 #if defined(PEGASUS_HAVE_WINDOWS_THREADS)
|
180 kumpf 1.81
|
181 kumpf 1.98 ThreadStatus Thread::run()
|
182 mike 1.91 {
183 // Note: A Win32 thread ID is not the same thing as a pthread ID.
184 // Win32 threads have both a thread ID and a handle. The handle
185 // is used in the wait functions, etc.
186 // So _handle.thid is actually the thread handle.
|
187 kumpf 1.81
|
188 mike 1.91 unsigned threadid = 0;
|
189 mike 1.2
|
190 mike 1.91 ThreadType tt;
191 tt.handle = (HANDLE) _beginthreadex(NULL, 0, _start, this, 0, &threadid);
192 _handle.thid = tt;
|
193 chuck 1.39
|
194 mike 1.95 if (Threads::null(_handle.thid))
|
195 mike 1.91 {
196 if (errno == EAGAIN)
|
197 kumpf 1.81 {
|
198 mike 1.91 return PEGASUS_THREAD_INSUFFICIENT_RESOURCES;
|
199 kumpf 1.81 }
|
200 mike 1.91 else
|
201 kumpf 1.81 {
|
202 mike 1.91 return PEGASUS_THREAD_SETUP_FAILURE;
|
203 kumpf 1.81 }
|
204 mike 1.91 }
205 return PEGASUS_THREAD_OK;
206 }
|
207 mday 1.52
|
208 kumpf 1.98 void Thread::cancel()
|
209 mike 1.91 {
210 _cancelled = true;
211 }
|
212 kumpf 1.82
|
213 kumpf 1.98 void Thread::thread_switch()
|
214 mike 1.91 {
215 Sleep(0);
216 }
|
217 kumpf 1.82
|
218 mike 1.91 void Thread::sleep(Uint32 milliseconds)
219 {
220 Sleep(milliseconds);
221 }
|
222 mike 1.2
|
223 kumpf 1.98 void Thread::join()
|
224 mike 1.91 {
|
225 mike 1.95 if (!Threads::null(_handle.thid))
|
226 mike 1.91 {
227 if (!_is_detached)
228 {
229 if (!_cancelled)
|
230 kumpf 1.82 {
|
231 mike 1.91 // Emulate the unix join api. Caller sleeps until thread is
232 // done.
233 WaitForSingleObject(_handle.thid.handle, INFINITE);
|
234 kumpf 1.82 }
|
235 mike 1.91 else
|
236 kumpf 1.82 {
|
237 mike 1.91 // Currently this is the only way to ensure this code does
|
238 kumpf 1.98 // not
|
239 mike 1.91 // hang forever.
240 if (WaitForSingleObject(_handle.thid.handle, 10000) ==
241 WAIT_TIMEOUT)
|
242 kumpf 1.82 {
|
243 mike 1.91 TerminateThread(_handle.thid.handle, 0);
|
244 kumpf 1.82 }
|
245 mike 1.91 }
|
246 s.hills 1.49
|
247 mike 1.91 DWORD exit_code = 0;
248 GetExitCodeThread(_handle.thid.handle, &exit_code);
249 _exit_code = (ThreadReturnType) exit_code;
|
250 kumpf 1.81 }
|
251 mike 1.91
252 CloseHandle(_handle.thid.handle);
253 Threads::clear(_handle.thid);
|
254 kumpf 1.82 }
|
255 mike 1.91 }
|
256 kumpf 1.14
|
257 kumpf 1.98 void Thread::detach()
|
258 mike 1.2 {
|
259 mike 1.91 _is_detached = true;
260 }
|
261 kumpf 1.81
|
262 mike 1.109 Thread::Thread(
263 ThreadReturnType(PEGASUS_THREAD_CDECL* start)(void*),
264 void *parameter,
265 Boolean detached) :_is_detached(detached),
266 _cancelled(false),
267 _start(start),
268 _cleanup(),
269 _thread_parm(parameter),
270 _exit_code(0)
|
271 mike 1.91 {
272 Threads::clear(_handle.thid);
|
273 mike 1.109 memset(_tsd, 0, sizeof(_tsd));
|
274 mike 1.91 }
|
275 kumpf 1.81
|
276 mike 1.91 Thread::~Thread()
277 {
|
278 kumpf 1.81 try
279 {
|
280 mike 1.91 join();
281 empty_tsd();
282 }
|
283 kumpf 1.98 catch (...)
|
284 mike 1.91 {
285 }
286 }
|
287 kumpf 1.81
|
288 mike 1.91 #endif /* PEGASUS_HAVE_WINDOWS_THREADS */
|
289 kumpf 1.57
|
290 mike 1.91 //==============================================================================
291 //
292 // Common implementation:
293 //
294 //==============================================================================
|
295 kumpf 1.81
|
296 mike 1.91 void language_delete(void *data)
297 {
298 if (data != NULL)
299 {
300 AutoPtr < AcceptLanguageList > al(static_cast <
301 AcceptLanguageList * >(data));
|
302 kumpf 1.57 }
|
303 mike 1.2 }
304
|
305 mike 1.91 Boolean Thread::_signals_blocked = false;
306 #ifndef PEGASUS_OS_ZOS
307 TSDKeyType Thread::_platform_thread_key = TSDKeyType(-1);
308 #else
309 TSDKeyType Thread::_platform_thread_key;
310 #endif
311 Boolean Thread::_key_initialized = false;
312 Boolean Thread::_key_error = false;
|
313 mday 1.12
|
314 mike 1.91 void Thread::cleanup_push(void (*routine) (void *), void *parm)
|
315 mike 1.2 {
|
316 mike 1.91 AutoPtr < cleanup_handler > cu(new cleanup_handler(routine, parm));
317 _cleanup.insert_front(cu.get());
318 cu.release();
319 return;
320 }
|
321 kumpf 1.81
|
322 mike 1.91 void Thread::cleanup_pop(Boolean execute)
323 {
324 AutoPtr < cleanup_handler > cu;
325 try
326 {
327 cu.reset(_cleanup.remove_front());
328 }
|
329 kumpf 1.107 catch (...)
|
330 mike 1.91 {
331 PEGASUS_ASSERT(0);
332 }
333 if (execute == true)
334 cu->execute();
335 }
|
336 kumpf 1.81
337
|
338 mike 1.91 void Thread::exit_self(ThreadReturnType exit_code)
339 {
|
340 ouyang.jian 1.100 #if !defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) \
341 && !defined(PEGASUS_PLATFORM_PASE_ISERIES_IBMCXX)
|
342 marek 1.97 Threads::exit(exit_code);
|
343 mike 1.91 #else
344 // execute the cleanup stack and then return
345 while (_cleanup.size())
346 {
|
347 kumpf 1.81 try
348 {
|
349 mike 1.91 cleanup_pop(true);
|
350 kumpf 1.81 }
|
351 kumpf 1.107 catch (...)
|
352 kumpf 1.81 {
|
353 mike 1.91 PEGASUS_ASSERT(0);
|
354 kumpf 1.81 break;
355 }
|
356 mike 1.91 }
357 _exit_code = exit_code;
358 Threads::exit(exit_code);
359 Threads::clear(_handle.thid);
360 #endif
361 }
|
362 kumpf 1.81
|
363 mike 1.91 Sint8 Thread::initializeKey()
364 {
365 PEG_METHOD_ENTER(TRC_THREAD, "Thread::initializeKey");
366 if (!Thread::_key_initialized)
367 {
368 if (Thread::_key_error)
369 {
|
370 marek 1.106 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL1,
|
371 mike 1.91 "Thread: ERROR - thread key error");
372 return -1;
373 }
|
374 kumpf 1.81
|
375 mike 1.91 if (TSDKey::create(&Thread::_platform_thread_key) == 0)
|
376 kumpf 1.81 {
|
377 marek 1.99 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL4,
|
378 mike 1.91 "Thread: able to create a thread key");
379 Thread::_key_initialized = true;
|
380 kumpf 1.81 }
381 else
382 {
|
383 marek 1.106 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL1,
|
384 mike 1.91 "Thread: ERROR - unable to create a thread key");
385 Thread::_key_error = true;
386 return -1;
|
387 kumpf 1.81 }
|
388 konrad.r 1.67 }
|
389 kumpf 1.81
390 PEG_METHOD_EXIT();
|
391 mike 1.91 return 0;
|
392 konrad.r 1.67 }
|
393 mday 1.19
|
394 mike 1.91 Thread *Thread::getCurrent()
|
395 mday 1.19 {
|
396 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::getCurrent");
397 if (Thread::initializeKey() != 0)
398 {
399 return NULL;
400 }
|
401 kumpf 1.81 PEG_METHOD_EXIT();
|
402 mike 1.91 return (Thread *) TSDKey::get_thread_specific(_platform_thread_key);
|
403 mday 1.19 }
404
|
405 mike 1.91 void Thread::setCurrent(Thread * thrd)
|
406 mday 1.19 {
|
407 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::setCurrent");
408 if (Thread::initializeKey() == 0)
|
409 kumpf 1.81 {
|
410 mike 1.91 if (TSDKey::
411 set_thread_specific(Thread::_platform_thread_key,
412 (void *) thrd) == 0)
413 {
|
414 marek 1.99 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL4,
|
415 mike 1.91 "Successful set Thread * into thread specific storage");
416 }
417 else
418 {
|
419 marek 1.106 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL1,
|
420 mike 1.91 "ERROR: error setting Thread * into thread specific storage");
421 }
|
422 kumpf 1.81 }
|
423 mike 1.91 PEG_METHOD_EXIT();
|
424 mday 1.19 }
425
|
426 mike 1.91 AcceptLanguageList *Thread::getLanguages()
|
427 mday 1.19 {
|
428 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::getLanguages");
429
430 Thread *curThrd = Thread::getCurrent();
431 if (curThrd == NULL)
432 return NULL;
433 AcceptLanguageList *acceptLangs =
|
434 mike 1.109 (AcceptLanguageList *) curThrd->reference_tsd(TSD_ACCEPT_LANGUAGES);
|
435 mike 1.91 curThrd->dereference_tsd();
436 PEG_METHOD_EXIT();
437 return acceptLangs;
|
438 mday 1.19 }
439
|
440 kumpf 1.102 void Thread::setLanguages(const AcceptLanguageList& langs)
|
441 mday 1.19 {
|
442 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::setLanguages");
|
443 kumpf 1.81
|
444 mike 1.91 Thread *currentThrd = Thread::getCurrent();
445 if (currentThrd != NULL)
|
446 kumpf 1.81 {
|
447 kumpf 1.102 AutoPtr<AcceptLanguageList> langsCopy(new AcceptLanguageList(langs));
448
|
449 mike 1.91 // deletes the old tsd and creates a new one
|
450 kumpf 1.102 currentThrd->put_tsd(
|
451 mike 1.109 TSD_ACCEPT_LANGUAGES,
|
452 kumpf 1.102 language_delete,
453 sizeof (AcceptLanguageList *),
454 langsCopy.get());
455
456 langsCopy.release();
|
457 kumpf 1.81 }
458
459 PEG_METHOD_EXIT();
|
460 mday 1.19 }
|
461 mike 1.2
|
462 kumpf 1.98 void Thread::clearLanguages()
|
463 kumpf 1.81 {
|
464 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::clearLanguages");
465
466 Thread *currentThrd = Thread::getCurrent();
467 if (currentThrd != NULL)
|
468 kumpf 1.81 {
|
469 mike 1.91 // deletes the old tsd
|
470 mike 1.109 currentThrd->delete_tsd(TSD_ACCEPT_LANGUAGES);
|
471 kumpf 1.81 }
472
|
473 mike 1.91 PEG_METHOD_EXIT();
|
474 kumpf 1.81 }
|
475 mike 1.2
|
476 mike 1.91 // ATTN: not sure where to put this!
477 #ifdef PEGASUS_ZOS_SECURITY
478 bool isEnhancedSecurity = 99;
479 #endif
480
|
481 mike 1.2 PEGASUS_NAMESPACE_END
|