1 martin 1.110 //%LICENSE////////////////////////////////////////////////////////////////
|
2 martin 1.111 //
|
3 martin 1.110 // 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 martin 1.111 //
|
10 martin 1.110 // 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 martin 1.111 //
|
17 martin 1.110 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
|
19 martin 1.111 //
|
20 martin 1.110 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
21 martin 1.111 // 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 martin 1.111 //
|
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 kumpf 1.112 _start(start),
268 _cleanup(),
269 _thread_parm(parameter),
|
270 mike 1.109 _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 dl.meetei 1.113 {
|
335 mike 1.91 cu->execute();
|
336 dl.meetei 1.113 }
|
337 mike 1.91 }
|
338 kumpf 1.81
339
|
340 mike 1.91 void Thread::exit_self(ThreadReturnType exit_code)
341 {
|
342 ouyang.jian 1.100 #if !defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) \
343 && !defined(PEGASUS_PLATFORM_PASE_ISERIES_IBMCXX)
|
344 marek 1.97 Threads::exit(exit_code);
|
345 mike 1.91 #else
346 // execute the cleanup stack and then return
347 while (_cleanup.size())
348 {
|
349 kumpf 1.81 try
350 {
|
351 mike 1.91 cleanup_pop(true);
|
352 kumpf 1.81 }
|
353 kumpf 1.107 catch (...)
|
354 kumpf 1.81 {
|
355 mike 1.91 PEGASUS_ASSERT(0);
|
356 kumpf 1.81 break;
357 }
|
358 mike 1.91 }
359 _exit_code = exit_code;
360 Threads::exit(exit_code);
361 Threads::clear(_handle.thid);
362 #endif
363 }
|
364 kumpf 1.81
|
365 mike 1.91 Sint8 Thread::initializeKey()
366 {
367 PEG_METHOD_ENTER(TRC_THREAD, "Thread::initializeKey");
368 if (!Thread::_key_initialized)
369 {
370 if (Thread::_key_error)
371 {
|
372 marek 1.106 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL1,
|
373 mike 1.91 "Thread: ERROR - thread key error");
374 return -1;
375 }
|
376 kumpf 1.81
|
377 mike 1.91 if (TSDKey::create(&Thread::_platform_thread_key) == 0)
|
378 kumpf 1.81 {
|
379 marek 1.99 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL4,
|
380 mike 1.91 "Thread: able to create a thread key");
381 Thread::_key_initialized = true;
|
382 kumpf 1.81 }
383 else
384 {
|
385 marek 1.106 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL1,
|
386 mike 1.91 "Thread: ERROR - unable to create a thread key");
387 Thread::_key_error = true;
388 return -1;
|
389 kumpf 1.81 }
|
390 konrad.r 1.67 }
|
391 kumpf 1.81
392 PEG_METHOD_EXIT();
|
393 mike 1.91 return 0;
|
394 konrad.r 1.67 }
|
395 mday 1.19
|
396 mike 1.91 Thread *Thread::getCurrent()
|
397 mday 1.19 {
|
398 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::getCurrent");
399 if (Thread::initializeKey() != 0)
400 {
401 return NULL;
402 }
|
403 kumpf 1.81 PEG_METHOD_EXIT();
|
404 mike 1.91 return (Thread *) TSDKey::get_thread_specific(_platform_thread_key);
|
405 mday 1.19 }
406
|
407 mike 1.91 void Thread::setCurrent(Thread * thrd)
|
408 mday 1.19 {
|
409 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::setCurrent");
410 if (Thread::initializeKey() == 0)
|
411 kumpf 1.81 {
|
412 mike 1.91 if (TSDKey::
413 set_thread_specific(Thread::_platform_thread_key,
414 (void *) thrd) == 0)
415 {
|
416 marek 1.99 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL4,
|
417 mike 1.91 "Successful set Thread * into thread specific storage");
418 }
419 else
420 {
|
421 marek 1.106 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL1,
|
422 mike 1.91 "ERROR: error setting Thread * into thread specific storage");
423 }
|
424 kumpf 1.81 }
|
425 mike 1.91 PEG_METHOD_EXIT();
|
426 mday 1.19 }
427
|
428 mike 1.91 AcceptLanguageList *Thread::getLanguages()
|
429 mday 1.19 {
|
430 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::getLanguages");
431
432 Thread *curThrd = Thread::getCurrent();
433 if (curThrd == NULL)
434 return NULL;
435 AcceptLanguageList *acceptLangs =
|
436 mike 1.109 (AcceptLanguageList *) curThrd->reference_tsd(TSD_ACCEPT_LANGUAGES);
|
437 mike 1.91 curThrd->dereference_tsd();
438 PEG_METHOD_EXIT();
439 return acceptLangs;
|
440 mday 1.19 }
441
|
442 kumpf 1.102 void Thread::setLanguages(const AcceptLanguageList& langs)
|
443 mday 1.19 {
|
444 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::setLanguages");
|
445 kumpf 1.81
|
446 mike 1.91 Thread *currentThrd = Thread::getCurrent();
447 if (currentThrd != NULL)
|
448 kumpf 1.81 {
|
449 kumpf 1.102 AutoPtr<AcceptLanguageList> langsCopy(new AcceptLanguageList(langs));
450
|
451 mike 1.91 // deletes the old tsd and creates a new one
|
452 kumpf 1.102 currentThrd->put_tsd(
|
453 mike 1.109 TSD_ACCEPT_LANGUAGES,
|
454 kumpf 1.102 language_delete,
455 sizeof (AcceptLanguageList *),
456 langsCopy.get());
457
458 langsCopy.release();
|
459 kumpf 1.81 }
460
461 PEG_METHOD_EXIT();
|
462 mday 1.19 }
|
463 mike 1.2
|
464 kumpf 1.98 void Thread::clearLanguages()
|
465 kumpf 1.81 {
|
466 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::clearLanguages");
467
468 Thread *currentThrd = Thread::getCurrent();
469 if (currentThrd != NULL)
|
470 kumpf 1.81 {
|
471 mike 1.91 // deletes the old tsd
|
472 mike 1.109 currentThrd->delete_tsd(TSD_ACCEPT_LANGUAGES);
|
473 kumpf 1.81 }
474
|
475 mike 1.91 PEG_METHOD_EXIT();
|
476 kumpf 1.81 }
|
477 mike 1.2
|
478 mike 1.91 // ATTN: not sure where to put this!
479 #ifdef PEGASUS_ZOS_SECURITY
480 bool isEnhancedSecurity = 99;
481 #endif
482
|
483 mike 1.2 PEGASUS_NAMESPACE_END
|