1 martin 1.66 //%LICENSE////////////////////////////////////////////////////////////////
|
2 martin 1.67 //
|
3 martin 1.66 // 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.67 //
|
10 martin 1.66 // 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.67 //
|
17 martin 1.66 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
|
19 martin 1.67 //
|
20 martin 1.66 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
21 martin 1.67 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
22 martin 1.66 // 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.67 //
|
28 martin 1.66 //////////////////////////////////////////////////////////////////////////
|
29 mike 1.2 //
30 //%/////////////////////////////////////////////////////////////////////////////
31
32 #ifndef Pegasus_Thread_h
33 #define Pegasus_Thread_h
|
34 kumpf 1.26
35 #include <cstring>
|
36 mike 1.2 #include <Pegasus/Common/Config.h>
|
37 mike 1.58 #include <Pegasus/Common/AtomicInt.h>
|
38 kumpf 1.23 #include <Pegasus/Common/InternalException.h>
|
39 kumpf 1.54 #include <Pegasus/Common/AcceptLanguageList.h>
|
40 kumpf 1.22 #include <Pegasus/Common/Linkage.h>
|
41 a.arora 1.37 #include <Pegasus/Common/AutoPtr.h>
|
42 mike 1.56 #include <Pegasus/Common/List.h>
|
43 mike 1.58 #include <Pegasus/Common/Mutex.h>
44 #include <Pegasus/Common/Semaphore.h>
45 #include <Pegasus/Common/TSDKey.h>
46 #include <Pegasus/Common/Threads.h>
|
47 mike 1.2
|
48 mike 1.58 #if defined(PEGASUS_HAVE_PTHREADS)
49 # include <signal.h>
50 #endif
51
|
52 kumpf 1.59 PEGASUS_NAMESPACE_BEGIN
|
53 mike 1.2
|
54 mike 1.56 class PEGASUS_COMMON_LINKAGE cleanup_handler : public Linkable
|
55 mike 1.2 {
|
56 mike 1.58 public:
57 cleanup_handler(void (*routine) (void *), void *arg):_routine(routine),
58 _arg(arg)
59 {
60 }
61 ~cleanup_handler()
62 {;
63 }
64
65 private:
66
67 void execute()
68 {
69 _routine(_arg);
70 }
71
|
72 kumpf 1.59 cleanup_handler();
73
|
74 mike 1.58 void (*_routine)(void*);
75 void *_arg;
|
76 mike 1.2
|
77 mike 1.58 friend class Thread;
|
78 mike 1.2 };
79
80 ///////////////////////////////////////////////////////////////////////////////
81
|
82 mike 1.64 enum TSD_Key
|
83 mike 1.58 {
|
84 mike 1.64 TSD_ACCEPT_LANGUAGES,
85 TSD_SLEEP_SEM,
86 TSD_LAST_ACTIVITY_TIME,
87 TSD_WORK_FUNC,
88 TSD_WORK_PARM,
89 TSD_BLOCKING_SEM,
90 TSD_CIMOM_HANDLE_CONTENT_LANGUAGES,
91 TSD_RESERVED_1,
92 TSD_RESERVED_2,
93 TSD_RESERVED_3,
94 TSD_RESERVED_4,
95 TSD_RESERVED_5,
96 TSD_RESERVED_6,
97 TSD_RESERVED_7,
98 TSD_RESERVED_8,
99 // Add new TSD keys before this line.
|
100 kumpf 1.65 TSD_COUNT
|
101 mike 1.64 };
102
103 class thread_data
104 {
105 /**
106 * This class is NOT build thread-safe.
107 * The Caller(user) of this class has to ensure there is no collision
108 * taking place.
|
109 kumpf 1.68 *
|
110 mike 1.64 * There is no mechanism in place to protect threads from manipulating
111 * the same thread-specific storage at one time.
112 * Make sure the possibility for a parallel access to the same
113 * threads-specific data from multiple threads cannot arise.
|
114 kumpf 1.68 *
|
115 mike 1.64 * In OpenPegasus this class is used in the ThreadPool
116 * - on initialisation and creation of threads owned by ThreadPool
117 * - on threads that are idle inside the ThreadPool
118 * - on the ThreadPools main thread (the thread which the ThreadPool
119 * runs in)
|
120 kumpf 1.68 * In OpenPegasus this class is used in the
|
121 mike 1.64 * ClientCIMOMHandleRep and InternalCIMOMHandleRep
122 * - on the current active Thread which belongs to that CIMOMHandle
|
123 kumpf 1.68 *
|
124 mike 1.64 */
|
125 mike 1.58 public:
126
|
127 mike 1.64 static void default_delete(void *data)
128 {
129 if (data)
130 ::operator delete(data);
131 }
|
132 mike 1.58
|
133 mike 1.64 thread_data(TSD_Key key) : _delete_func(0), _data(0), _size(0), _key(key)
|
134 mike 1.58 {
135 }
|
136 mike 1.2
|
137 mike 1.64 thread_data(TSD_Key key, size_t size) :
138 _delete_func(default_delete), _size(size), _key(key)
|
139 mike 1.58 {
|
140 mike 1.64 _data = ::operator new(_size);
|
141 mike 1.58 }
|
142 mike 1.2
|
143 mike 1.64 thread_data(TSD_Key key, size_t size, void* data)
144 : _delete_func(default_delete), _size(size), _key(key)
|
145 mike 1.58 {
|
146 mike 1.64 _data = ::operator new(_size);
|
147 mike 1.58 memcpy(_data, data, size);
148 }
|
149 kumpf 1.48
|
150 mike 1.58 ~thread_data()
151 {
|
152 mike 1.64 if (_data && _delete_func)
153 (*_delete_func)(_data);
|
154 mike 1.58 }
|
155 mike 1.2
|
156 mike 1.58 /**
157 * This function is used to put data in thread space.
158 *
159 * Be aware that there is NOTHING in place to stop
160 * other users of the thread to remove this data.
161 * Or change the data.
162 *
163 * You, the developer has to make sure that there are
164 * no situations in which this can arise (ie, have a
165 * lock for the function which manipulates the TSD.
166 *
167 * @exception NullPointer
168 */
|
169 mike 1.64 void put_data(void (*del)(void *), size_t size, void* data)
|
170 mike 1.58 {
|
171 mike 1.64 if (_data && _delete_func)
172 (*_delete_func)(_data);
|
173 mike 1.58
174 _delete_func = del;
175 _data = data;
176 _size = size;
177 }
|
178 mike 1.2
|
179 mike 1.58 size_t get_size()
180 {
181 return _size;
182 }
|
183 mike 1.2
|
184 mike 1.64 void* get_data()
185 {
186 return _data;
187 }
188
|
189 kumpf 1.59 /**
190 This function is used to retrieve data from the
191 TSD, the thread specific data.
192
193 Be aware that there is NOTHING in place to stop
194 other users of the thread to change the data you
195 get from this function.
196
197 You, the developer has to make sure that there are
198 no situations in which this can arise (ie, have a
199 lock for the function which manipulates the TSD.
200 */
201 void get_data(void** data, size_t* size)
|
202 mike 1.58 {
|
203 mike 1.64 if (data == 0 || size == 0)
|
204 kumpf 1.48 throw NullPointer();
205
|
206 mike 1.58 *data = _data;
207 *size = _size;
208 }
209
210 // @exception NullPointer
|
211 kumpf 1.59 void copy_data(void** buf, size_t* size)
|
212 mike 1.58 {
|
213 mike 1.64 if ((buf == 0) || (size == 0))
|
214 david.dillard 1.50 throw NullPointer();
|
215 mike 1.64
216 *buf = ::operator new(_size);
|
217 mike 1.58 *size = _size;
218 memcpy(*buf, _data, _size);
219 }
|
220 mike 1.2
|
221 mike 1.58
|
222 mike 1.64 private:
|
223 mike 1.58
|
224 mike 1.64 thread_data();
225 thread_data(const thread_data& x);
226 thread_data& operator=(const thread_data& x);
|
227 mike 1.58
|
228 mike 1.64 void (*_delete_func)(void*);
|
229 kumpf 1.59 void* _data;
|
230 mike 1.58 size_t _size;
|
231 mike 1.64 TSD_Key _key;
|
232 mike 1.2 };
233
234
|
235 mike 1.58 enum ThreadStatus
236 {
237 PEGASUS_THREAD_OK = 1, /* No problems */
238 PEGASUS_THREAD_INSUFFICIENT_RESOURCES, /* Can't allocate a thread.
239 Not enough memory. Try
240 again later */
|
241 kumpf 1.59 PEGASUS_THREAD_SETUP_FAILURE, /* Could not allocate into the thread
|
242 mike 1.58 specific data storage. */
243 PEGASUS_THREAD_UNAVAILABLE /* Service is being destroyed and no new
244 threads can be provided. */
|
245 konrad.r 1.53 };
246
|
247 mike 1.2 ///////////////////////////////////////////////////////////////////////////
248
|
249 kumpf 1.59 class PEGASUS_COMMON_LINKAGE Thread : public Linkable
|
250 mike 1.2 {
|
251 kumpf 1.59 public:
|
252 mike 1.2
|
253 kumpf 1.59 Thread(
254 ThreadReturnType(PEGASUS_THREAD_CDECL* start) (void*),
255 void* parameter,
256 Boolean detached);
|
257 mike 1.2
|
258 mike 1.58 ~Thread();
|
259 mike 1.2
|
260 mike 1.58 /** Start the thread.
|
261 kumpf 1.59 @return PEGASUS_THREAD_OK if the thread is started successfully,
262 PEGASUS_THREAD_INSUFFICIENT_RESOURCES if the resources necessary
263 to start the thread are not currently available.
264 PEGASUS_THREAD_SETUP_FAILURE if the thread could not
|
265 mike 1.58 be create properly - check the 'errno' value for specific operating
266 system return code.
|
267 kumpf 1.36 */
|
268 mike 1.58 ThreadStatus run();
|
269 mike 1.2
|
270 mike 1.58 // get the user parameter
|
271 mike 1.64 void *get_parm()
|
272 mike 1.58 {
273 return _thread_parm;
274 }
|
275 mike 1.2
|
276 mike 1.58 // cancellation must be deferred (not asynchronous)
277 // for user-level threads the thread itself can decide
278 // when it should die.
279 void cancel();
280
281 // for user-level threads - put the calling thread
282 // to sleep and jump to the thread scheduler.
283 // platforms with preemptive scheduling and native threads
284 // can define this to be a no-op.
285 // platforms without preemptive scheduling like NetWare
286 // or gnu portable threads will have an existing
287 // routine that can be mapped to this method
|
288 mike 1.2
|
289 mike 1.58 void thread_switch();
|
290 mike 1.2
|
291 mike 1.58 static void sleep(Uint32 msec);
|
292 mike 1.2
|
293 mike 1.58 // block the calling thread until this thread terminates
294 void join();
295
296 // thread routine needs to call this function when
297 // it is ready to exit
298 void exit_self(ThreadReturnType return_code);
299
300 // stack of functions to be called when thread terminates
301 // will be called last in first out (LIFO)
|
302 kumpf 1.59 void cleanup_push(void (*routine) (void *), void* parm);
|
303 mike 1.58
304 void cleanup_pop(Boolean execute = true);
305
306 // get the buffer associated with the key
307 // NOTE: this call leaves the tsd LOCKED !!!!
|
308 mike 1.64 void* reference_tsd(TSD_Key key)
|
309 mike 1.58 {
|
310 mike 1.64 if (_tsd[key])
311 return _tsd[key]->get_data();
312 else
313 return 0;
|
314 mike 1.58 }
|
315 mike 1.2
|
316 mike 1.58 // release the lock held on the tsd
317 // NOTE: assumes a corresponding and prior call to reference_tsd() !!!
|
318 mike 1.64 void dereference_tsd()
|
319 mike 1.58 {
320 }
|
321 kumpf 1.48
|
322 mike 1.58 // delete the tsd associated with the key
|
323 mike 1.64 void delete_tsd(TSD_Key key)
|
324 kumpf 1.48 {
|
325 mike 1.64 thread_data* tsd;
326
327 tsd = _tsd[key];
328 _tsd[key] = 0;
329
330 if (tsd)
331 delete tsd;
|
332 kumpf 1.48 }
333
|
334 mike 1.64 void empty_tsd()
|
335 kumpf 1.48 {
|
336 mike 1.64 thread_data* data[TSD_COUNT];
337
338 memcpy(data, _tsd, sizeof(_tsd));
339 memset(_tsd, 0, sizeof(_tsd));
340
341 for (size_t i = 0; i < TSD_COUNT; i++)
342 {
343 if (data[i])
344 delete data[i];
345 }
|
346 kumpf 1.48 }
347
|
348 mike 1.58 // create or re-initialize tsd associated with the key
349 // if the tsd already exists, delete the existing buffer
|
350 kumpf 1.59 void put_tsd(
|
351 mike 1.64 TSD_Key key,
352 void (*delete_func)(void*),
|
353 kumpf 1.59 Uint32 size,
354 void* value)
|
355 kumpf 1.48 {
|
356 mike 1.64 thread_data* tsd = new thread_data(key);
357 tsd->put_data(delete_func, size, value);
358
359 thread_data* old;
360
361 old = _tsd[key];
362 _tsd[key] = tsd;
363
364 if (old)
365 delete old;
|
366 kumpf 1.48 }
|
367 kumpf 1.59
|
368 mike 1.64 ThreadReturnType get_exit()
|
369 kumpf 1.48 {
|
370 mike 1.58 return _exit_code;
|
371 kumpf 1.48 }
|
372 mike 1.64
373 ThreadType self()
|
374 kumpf 1.48 {
|
375 mike 1.58 return Threads::self();
|
376 kumpf 1.48 }
377
|
378 mike 1.58 ThreadHandle getThreadHandle()
|
379 kumpf 1.48 {
|
380 mike 1.58 return _handle;
|
381 kumpf 1.48 }
382
|
383 venkat.puvvada 1.68.2.1 Boolean isDetached()
384 {
385 return _is_detached;
386 }
387
|
388 mike 1.58 void detach();
389
|
390 kumpf 1.59 //
|
391 mike 1.58 // Gets the Thread object associated with the caller's thread.
392 // Note: this may return NULL if no Thread object is associated
393 // with the caller's thread.
|
394 kumpf 1.59 //
395 static Thread *getCurrent();
|
396 mike 1.58
|
397 kumpf 1.59 //
|
398 mike 1.58 // Sets the Thread object associated with the caller's thread.
399 // Note: the Thread object must be placed on the heap.
|
400 kumpf 1.59 //
401 static void setCurrent(Thread* thrd);
|
402 mike 1.58
|
403 kumpf 1.59 //
|
404 mike 1.58 // Gets the AcceptLanguageList object associated with the caller's
405 // Thread.
406 // Note: this may return NULL if no Thread object, or no
407 // AcceptLanguageList object, is associated with the caller's thread.
|
408 kumpf 1.59 //
409 static AcceptLanguageList* getLanguages();
|
410 mike 1.58
|
411 kumpf 1.59 //
|
412 mike 1.58 // Sets the AcceptLanguageList object associated with the caller's
413 // Thread.
414 // Note: a Thread object must have been previously associated with
415 // the caller's thread.
|
416 kumpf 1.59 //
|
417 kumpf 1.60 static void setLanguages(const AcceptLanguageList& langs);
|
418 mike 1.58
|
419 kumpf 1.59 //
|
420 mike 1.58 // Removes the AcceptLanguageList object associated with the caller's
421 // Thread.
|
422 kumpf 1.59 //
423 static void clearLanguages();
|
424 kumpf 1.48
|
425 kumpf 1.59 private:
|
426 mike 1.58 Thread();
|
427 mike 1.2
|
428 kumpf 1.59 static Sint8 initializeKey();
|
429 mike 1.2
|
430 mike 1.58 ThreadHandle _handle;
431 Boolean _is_detached;
432 Boolean _cancelled;
433
434 // always pass this * as the void * parameter to the thread
435 // store the user parameter in _thread_parm
436
|
437 kumpf 1.59 ThreadReturnType(PEGASUS_THREAD_CDECL* _start) (void *);
438 List<cleanup_handler, Mutex> _cleanup;
|
439 mike 1.64 thread_data* _tsd[TSD_COUNT];
|
440 mike 1.58
|
441 kumpf 1.59 void* _thread_parm;
|
442 mike 1.58 ThreadReturnType _exit_code;
443 static Boolean _signals_blocked;
|
444 kumpf 1.59 static TSDKeyType _platform_thread_key;
445 static Boolean _key_initialized;
446 static Boolean _key_error;
|
447 mike 1.58 };
|
448 mike 1.2
449 PEGASUS_NAMESPACE_END
450
451 #endif // Pegasus_Thread_h
|