xref: /trunk/main/sal/osl/unx/thread.c (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "system.h"
29 #include <string.h>
30 #include <osl/diagnose.h>
31 #include <osl/thread.h>
32 #include <osl/nlsupport.h>
33 #ifndef _RTL_TEXTENC_H_
34 #include <rtl/textenc.h>
35 #endif
36 
37 #if defined LINUX
38 #include <sys/prctl.h>
39 #endif
40 
41 /****************************************************************************
42  * @@@ TODO @@@
43  *
44  * (1) 'osl_thread_priority_init_Impl()'
45  *     - insane assumption that initializing caller is main thread
46  *     - use _POSIX_THREAD_PRIORITY_SCHEDULING, not NO_PTHREAD_PRIORITY (?)
47  *     - POSIX doesn't require defined prio's for SCHED_OTHER (!)
48  *     - use SCHED_RR instead of SCHED_OTHER for defined behaviour (?)
49  * (2) 'oslThreadIdentifier' and '{insert|remove|lookup}ThreadId()'
50  *     - cannot reliably be applied to 'alien' threads;
51  *     - memory leak for 'alien' thread 'HashEntry's;
52  *     - use 'PTHREAD_VALUE(pthread_t)' as identifier instead (?)
53  *     - if yes, change 'oslThreadIdentifier' to 'intptr_t' or similar
54  * (3) 'oslSigAlarmHandler()' (#71232#)
55  *     - [Under Solaris we get SIGALRM in e.g. pthread_join which terminates
56  *       the process. So we initialize our signal handling module and do
57  *       register a SIGALRM Handler which catches and ignores it]
58  *     - should this still happen, 'signal.c' needs to be fixed instead.
59  *
60  ****************************************************************************/
61 
62 /*****************************************************************************/
63 /*	Internal data structures and functions */
64 /*****************************************************************************/
65 
66 #define THREADIMPL_FLAGS_TERMINATE  0x00001
67 #define THREADIMPL_FLAGS_STARTUP	0x00002
68 #define THREADIMPL_FLAGS_SUSPENDED	0x00004
69 #define THREADIMPL_FLAGS_ACTIVE     0x00008
70 #define THREADIMPL_FLAGS_ATTACHED   0x00010
71 #define THREADIMPL_FLAGS_DESTROYED  0x00020
72 
73 typedef struct osl_thread_impl_st
74 {
75 	pthread_t			m_hThread;
76 	sal_uInt16			m_Ident; /* @@@ see TODO @@@ */
77 	short               m_Flags;
78     oslWorkerFunction	m_WorkerFunction;
79 	void*				m_pData;
80 	pthread_mutex_t		m_Lock;
81 	pthread_cond_t		m_Cond;
82 } Thread_Impl;
83 
84 struct osl_thread_priority_st
85 {
86 	int m_Highest;
87 	int m_Above_Normal;
88 	int m_Normal;
89 	int m_Below_Normal;
90 	int m_Lowest;
91 };
92 
93 #define OSL_THREAD_PRIORITY_INITIALIZER { 127, 96, 64, 32, 0 }
94 static void osl_thread_priority_init_Impl (void);
95 
96 struct osl_thread_textencoding_st
97 {
98 	pthread_key_t    m_key;     /* key to store thread local text encoding */
99 	rtl_TextEncoding m_default; /* the default text encoding */
100 };
101 
102 #define OSL_THREAD_TEXTENCODING_INITIALIZER { 0, RTL_TEXTENCODING_DONTKNOW }
103 static void osl_thread_textencoding_init_Impl (void);
104 
105 struct osl_thread_global_st
106 {
107 	pthread_once_t                    m_once;
108 	struct osl_thread_priority_st     m_priority;
109 	struct osl_thread_textencoding_st m_textencoding;
110 };
111 
112 static struct osl_thread_global_st g_thread =
113 {
114 	PTHREAD_ONCE_INIT,
115 	OSL_THREAD_PRIORITY_INITIALIZER,
116 	OSL_THREAD_TEXTENCODING_INITIALIZER
117 };
118 
119 static void osl_thread_init_Impl (void);
120 
121 static Thread_Impl* osl_thread_construct_Impl (void);
122 static void         osl_thread_destruct_Impl (Thread_Impl ** ppImpl);
123 
124 static void* osl_thread_start_Impl (void * pData);
125 static void  osl_thread_cleanup_Impl (void * pData);
126 
127 static oslThread osl_thread_create_Impl (
128 	oslWorkerFunction pWorker, void * pThreadData, short nFlags);
129 
130 static void osl_thread_join_cleanup_Impl (void * opaque);
131 static void osl_thread_wait_cleanup_Impl (void * opaque);
132 
133 /* @@@ see TODO @@@ */
134 static sal_uInt16 insertThreadId (pthread_t hThread);
135 static sal_uInt16 lookupThreadId (pthread_t hThread);
136 static void       removeThreadId (pthread_t hThread);
137 
138 /*****************************************************************************/
139 /* osl_thread_init_Impl */
140 /*****************************************************************************/
141 static void osl_thread_init_Impl (void)
142 {
143 	osl_thread_priority_init_Impl();
144 	osl_thread_textencoding_init_Impl();
145 }
146 
147 /*****************************************************************************/
148 /* osl_thread_join_cleanup_Impl */
149 /*****************************************************************************/
150 static void osl_thread_join_cleanup_Impl (void * opaque)
151 {
152 	pthread_t hThread = (pthread_t)(opaque);
153 	pthread_detach (hThread);
154 }
155 
156 /*****************************************************************************/
157 /* osl_thread_wait_cleanup_Impl */
158 /*****************************************************************************/
159 static void osl_thread_wait_cleanup_Impl (void * opaque)
160 {
161 	pthread_mutex_t * pMutex = (pthread_mutex_t*)(opaque);
162 	pthread_mutex_unlock (pMutex);
163 }
164 
165 /*****************************************************************************/
166 /* osl_thread_construct_Impl */
167 /*****************************************************************************/
168 Thread_Impl* osl_thread_construct_Impl (void)
169 {
170 	Thread_Impl* pImpl = malloc (sizeof(Thread_Impl));
171 	if (pImpl)
172 	{
173 		memset (pImpl, 0, sizeof(Thread_Impl));
174 
175 		pthread_mutex_init (&(pImpl->m_Lock), PTHREAD_MUTEXATTR_DEFAULT);
176 		pthread_cond_init  (&(pImpl->m_Cond), PTHREAD_CONDATTR_DEFAULT);
177 	}
178 	return (pImpl);
179 }
180 
181 /*****************************************************************************/
182 /* osl_thread_destruct_Impl */
183 /*****************************************************************************/
184 static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl)
185 {
186 	OSL_ASSERT(ppImpl);
187 	if (*ppImpl)
188 	{
189 		pthread_cond_destroy  (&((*ppImpl)->m_Cond));
190 		pthread_mutex_destroy (&((*ppImpl)->m_Lock));
191 
192 		free (*ppImpl);
193 		(*ppImpl) = 0;
194 	}
195 }
196 
197 /*****************************************************************************/
198 /* osl_thread_cleanup_Impl */
199 /*****************************************************************************/
200 static void osl_thread_cleanup_Impl (void* pData)
201 {
202     pthread_t thread;
203     int attached;
204     int destroyed;
205 	Thread_Impl* pImpl= (Thread_Impl*)pData;
206 
207 	pthread_mutex_lock (&(pImpl->m_Lock));
208 
209     thread = pImpl->m_hThread;
210     attached = (pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) != 0;
211     destroyed = (pImpl->m_Flags & THREADIMPL_FLAGS_DESTROYED) != 0;
212     pImpl->m_Flags &= ~(THREADIMPL_FLAGS_ACTIVE | THREADIMPL_FLAGS_ATTACHED);
213 
214 	pthread_mutex_unlock (&(pImpl->m_Lock));
215 
216     /* release oslThreadIdentifier @@@ see TODO @@@ */
217     removeThreadId (thread);
218 
219     if (attached)
220     {
221         pthread_detach (thread);
222     }
223 
224     if (destroyed)
225     {
226 		osl_thread_destruct_Impl (&pImpl);
227 	}
228 }
229 
230 /*****************************************************************************/
231 /* osl_thread_start_Impl */
232 /*****************************************************************************/
233 static void* osl_thread_start_Impl (void* pData)
234 {
235 	int terminate;
236 	Thread_Impl* pImpl= (Thread_Impl*)pData;
237 
238 	OSL_ASSERT(pImpl);
239 
240     pthread_mutex_lock (&(pImpl->m_Lock));
241 
242 	/* install cleanup handler */
243     pthread_cleanup_push (osl_thread_cleanup_Impl, pData);
244 
245 	/* request oslThreadIdentifier @@@ see TODO @@@ */
246 	pImpl->m_Ident = insertThreadId (pImpl->m_hThread);
247 
248 	/* signal change from STARTUP to ACTIVE state */
249 	pImpl->m_Flags &= ~THREADIMPL_FLAGS_STARTUP;
250 	pImpl->m_Flags |=  THREADIMPL_FLAGS_ACTIVE;
251     pthread_cond_signal (&(pImpl->m_Cond));
252 
253 	/* Check if thread is started in SUSPENDED state */
254     while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
255     {
256         /* wait until SUSPENDED flag is cleared */
257 		pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock));
258 		pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
259 		pthread_cleanup_pop (0);
260     }
261 
262 	/* check for SUSPENDED to TERMINATE state change */
263 	terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);
264 
265     pthread_mutex_unlock (&(pImpl->m_Lock));
266 
267 	if (!terminate)
268 	{
269 		/* call worker function */
270 		pImpl->m_WorkerFunction(pImpl->m_pData);
271 	}
272 
273 	/* call cleanup handler and leave */
274 	pthread_cleanup_pop (1);
275 	return (0);
276 }
277 
278 /*****************************************************************************/
279 /* osl_thread_create_Impl */
280 /*****************************************************************************/
281 static oslThread osl_thread_create_Impl (
282 	oslWorkerFunction pWorker,
283 	void*             pThreadData,
284 	short             nFlags)
285 {
286 	Thread_Impl* pImpl;
287     int nRet=0;
288 
289 	pImpl = osl_thread_construct_Impl();
290     if (!pImpl)
291         return (0); /* ENOMEM */
292 
293 	pImpl->m_WorkerFunction = pWorker;
294 	pImpl->m_pData = pThreadData;
295 	pImpl->m_Flags = nFlags | THREADIMPL_FLAGS_STARTUP;
296 
297     pthread_mutex_lock (&(pImpl->m_Lock));
298 
299 	if ((nRet = pthread_create (
300 		&(pImpl->m_hThread),
301 		PTHREAD_ATTR_DEFAULT,
302 		osl_thread_start_Impl,
303 		(void*)(pImpl))) != 0)
304 	{
305 	    OSL_TRACE("osl_thread_create_Impl(): errno: %d, %s\n",
306 			      nRet, strerror(nRet));
307 
308 		pthread_mutex_unlock (&(pImpl->m_Lock));
309 		osl_thread_destruct_Impl (&pImpl);
310 
311 		return (0);
312 	}
313 
314 	/* wait for change from STARTUP to ACTIVE state */
315 	while (pImpl->m_Flags & THREADIMPL_FLAGS_STARTUP)
316 	{
317 		/* wait until STARTUP flag is cleared */
318 		pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock));
319         pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
320 		pthread_cleanup_pop (0);
321     }
322 
323     pthread_mutex_unlock (&(pImpl->m_Lock));
324 
325 	return ((oslThread)(pImpl));
326 }
327 
328 /*****************************************************************************/
329 /* osl_createThread */
330 /*****************************************************************************/
331 oslThread osl_createThread (
332 	oslWorkerFunction pWorker,
333 	void *            pThreadData)
334 {
335     return osl_thread_create_Impl (
336 		pWorker,
337 		pThreadData,
338 		THREADIMPL_FLAGS_ATTACHED);
339 }
340 
341 /*****************************************************************************/
342 /* osl_createSuspendedThread */
343 /*****************************************************************************/
344 oslThread osl_createSuspendedThread (
345 	oslWorkerFunction pWorker,
346 	void *            pThreadData)
347 {
348     return osl_thread_create_Impl (
349 		pWorker,
350 		pThreadData,
351 		THREADIMPL_FLAGS_ATTACHED |
352 		THREADIMPL_FLAGS_SUSPENDED );
353 }
354 
355 /*****************************************************************************/
356 /* osl_destroyThread */
357 /*****************************************************************************/
358 void SAL_CALL osl_destroyThread(oslThread Thread)
359 {
360     if (Thread != NULL) {
361         Thread_Impl * impl = (Thread_Impl *) Thread;
362         int active;
363         pthread_mutex_lock(&impl->m_Lock);
364         active = (impl->m_Flags & THREADIMPL_FLAGS_ACTIVE) != 0;
365         impl->m_Flags |= THREADIMPL_FLAGS_DESTROYED;
366         pthread_mutex_unlock(&impl->m_Lock);
367         if (!active) {
368             osl_thread_destruct_Impl(&impl);
369         }
370     }
371 }
372 
373 /*****************************************************************************/
374 /* osl_resumeThread */
375 /*****************************************************************************/
376 void SAL_CALL osl_resumeThread(oslThread Thread)
377 {
378 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
379 
380 	OSL_ASSERT(pImpl);
381 	if (!pImpl)
382 		return; /* EINVAL */
383 
384 	pthread_mutex_lock (&(pImpl->m_Lock));
385 
386 	if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
387     {
388 		/* clear SUSPENDED flag */
389 		pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
390 		pthread_cond_signal (&(pImpl->m_Cond));
391     }
392 
393 	pthread_mutex_unlock (&(pImpl->m_Lock));
394 }
395 
396 /*****************************************************************************/
397 /* osl_suspendThread */
398 /*****************************************************************************/
399 void SAL_CALL osl_suspendThread(oslThread Thread)
400 {
401     Thread_Impl* pImpl= (Thread_Impl*)Thread;
402 
403 	OSL_ASSERT(pImpl);
404 	if (!pImpl)
405 		return; /* EINVAL */
406 
407 	pthread_mutex_lock (&(pImpl->m_Lock));
408 
409 	pImpl->m_Flags |= THREADIMPL_FLAGS_SUSPENDED;
410 
411 	if (pthread_equal (pthread_self(), pImpl->m_hThread))
412     {
413 		/* self suspend */
414         while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
415         {
416             /* wait until SUSPENDED flag is cleared */
417 			pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock));
418 			pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
419 			pthread_cleanup_pop (0);
420         }
421     }
422 
423 	pthread_mutex_unlock (&(pImpl->m_Lock));
424 }
425 
426 /*****************************************************************************/
427 /* osl_isThreadRunning */
428 /*****************************************************************************/
429 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
430 {
431 	sal_Bool active;
432 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
433 
434 	if (!pImpl)
435 		return sal_False;
436 
437 	pthread_mutex_lock (&(pImpl->m_Lock));
438 	active = ((pImpl->m_Flags & THREADIMPL_FLAGS_ACTIVE) > 0);
439 	pthread_mutex_unlock (&(pImpl->m_Lock));
440 
441 	return (active);
442 }
443 
444 /*****************************************************************************/
445 /* osl_joinWithThread */
446 /*****************************************************************************/
447 void SAL_CALL osl_joinWithThread(oslThread Thread)
448 {
449     pthread_t thread;
450 	int attached;
451 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
452 
453 	if (!pImpl)
454 		return;
455 
456 	pthread_mutex_lock (&(pImpl->m_Lock));
457 
458 	if (pthread_equal (pthread_self(), pImpl->m_hThread))
459 	{
460 		/* self join */
461 		pthread_mutex_unlock (&(pImpl->m_Lock));
462 		return; /* EDEADLK */
463 	}
464 
465     thread = pImpl->m_hThread;
466 	attached = ((pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) > 0);
467 	pImpl->m_Flags &= ~THREADIMPL_FLAGS_ATTACHED;
468 
469 	pthread_mutex_unlock (&(pImpl->m_Lock));
470 
471 	if (attached)
472 	{
473 		/* install cleanup handler to ensure consistent flags and state */
474 		pthread_cleanup_push (
475 			osl_thread_join_cleanup_Impl, (void*)thread);
476 
477 		/* join */
478 		pthread_join (thread, NULL);
479 
480 		/* remove cleanup handler */
481 		pthread_cleanup_pop (0);
482 	}
483 }
484 
485 /*****************************************************************************/
486 /* osl_terminateThread */
487 /*****************************************************************************/
488 void SAL_CALL osl_terminateThread(oslThread Thread)
489 {
490 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
491 
492 	OSL_ASSERT(pImpl);
493 	if (!pImpl)
494 		return; /* EINVAL */
495 
496 	pthread_mutex_lock (&(pImpl->m_Lock));
497 
498 	if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
499     {
500 		/* clear SUSPENDED flag */
501 		pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
502 		pthread_cond_signal (&(pImpl->m_Cond));
503     }
504 
505 	pImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE;
506 
507 	pthread_mutex_unlock (&(pImpl->m_Lock));
508 }
509 
510 /*****************************************************************************/
511 /* osl_scheduleThread */
512 /*****************************************************************************/
513 sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
514 {
515 	int terminate;
516 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
517 
518 	OSL_ASSERT(pImpl);
519 	if (!pImpl)
520 		return sal_False; /* EINVAL */
521 
522 	OSL_ASSERT(pthread_equal (pthread_self(), pImpl->m_hThread));
523 	if (!(pthread_equal (pthread_self(), pImpl->m_hThread)))
524 		return sal_False; /* EINVAL */
525 
526 	pthread_testcancel();
527 	pthread_mutex_lock (&(pImpl->m_Lock));
528 
529 	while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
530     {
531 		/* wait until SUSPENDED flag is cleared */
532 		pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock));
533 		pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
534 		pthread_cleanup_pop (0);
535     }
536 
537 	terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);
538 
539 	pthread_mutex_unlock(&(pImpl->m_Lock));
540 	pthread_testcancel();
541 
542 	return (terminate == 0);
543 }
544 
545 /*****************************************************************************/
546 /* osl_waitThread */
547 /*****************************************************************************/
548 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
549 {
550 	if (pDelay)
551 	{
552 		struct timespec delay;
553 
554 		SET_TIMESPEC(delay, pDelay->Seconds, pDelay->Nanosec);
555 
556 		SLEEP_TIMESPEC(delay);
557 	}
558 }
559 
560 /*****************************************************************************/
561 /* osl_yieldThread */
562 /*
563 	Note that POSIX scheduling _really_ requires threads to call this
564 	functions, since a thread only reschedules to other thread, when
565     it blocks (sleep, blocking I/O) OR calls sched_yield().
566 */
567 /*****************************************************************************/
568 void SAL_CALL osl_yieldThread()
569 {
570     sched_yield();
571 }
572 
573 void SAL_CALL osl_setThreadName(char const * name) {
574 #if defined LINUX
575     if (prctl(PR_SET_NAME, (unsigned long) name, 0, 0, 0) != 0) {
576         OSL_TRACE(
577             "%s prctl(PR_SET_NAME) failed with errno %d", OSL_LOG_PREFIX,
578             errno);
579     }
580 #else
581     (void) name;
582 #endif
583 }
584 
585 /*****************************************************************************/
586 /* osl_getThreadIdentifier @@@ see TODO @@@ */
587 /*****************************************************************************/
588 
589 #define HASHID(x) ((unsigned int)PTHREAD_VALUE(x) % HashSize)
590 
591 typedef struct _HashEntry
592 {
593 	pthread_t         Handle;
594 	sal_uInt16	      Ident;
595 	struct _HashEntry *Next;
596 } HashEntry;
597 
598 static HashEntry* HashTable[31];
599 static int HashSize = sizeof(HashTable) / sizeof(HashTable[0]);
600 
601 static pthread_mutex_t HashLock = PTHREAD_MUTEX_INITIALIZER;
602 
603 static sal_uInt16 LastIdent = 0;
604 
605 static sal_uInt16 lookupThreadId (pthread_t hThread)
606 {
607 	HashEntry *pEntry;
608 
609 	pthread_mutex_lock(&HashLock);
610 
611 		pEntry = HashTable[HASHID(hThread)];
612 		while (pEntry != NULL)
613 		{
614 			if (pthread_equal(pEntry->Handle, hThread))
615 			{
616 				pthread_mutex_unlock(&HashLock);
617 				return (pEntry->Ident);
618 			}
619 			pEntry = pEntry->Next;
620 		}
621 
622 	pthread_mutex_unlock(&HashLock);
623 
624 	return (0);
625 }
626 
627 static sal_uInt16 insertThreadId (pthread_t hThread)
628 {
629 	HashEntry *pEntry, *pInsert = NULL;
630 
631 	pthread_mutex_lock(&HashLock);
632 
633 	pEntry = HashTable[HASHID(hThread)];
634 
635 	while (pEntry != NULL)
636 	{
637 		if (pthread_equal(pEntry->Handle, hThread))
638 			break;
639 
640 		pInsert = pEntry;
641 		pEntry = pEntry->Next;
642 	}
643 
644 	if (pEntry == NULL)
645 	{
646 		pEntry = (HashEntry*) calloc(sizeof(HashEntry), 1);
647 
648 		pEntry->Handle = hThread;
649 
650 		++ LastIdent;
651 
652         if ( LastIdent == 0 )
653             LastIdent = 1;
654 
655         pEntry->Ident  = LastIdent;
656 
657 		if (pInsert)
658 			pInsert->Next = pEntry;
659 		else
660 			HashTable[HASHID(hThread)] = pEntry;
661 	}
662 
663 	pthread_mutex_unlock(&HashLock);
664 
665 	return (pEntry->Ident);
666 }
667 
668 static void removeThreadId (pthread_t hThread)
669 {
670 	HashEntry *pEntry, *pRemove = NULL;
671 
672 	pthread_mutex_lock(&HashLock);
673 
674 	pEntry = HashTable[HASHID(hThread)];
675 	while (pEntry != NULL)
676 	{
677 		if (pthread_equal(pEntry->Handle, hThread))
678 			break;
679 
680 		pRemove = pEntry;
681 		pEntry = pEntry->Next;
682 	}
683 
684 	if (pEntry != NULL)
685 	{
686 		if (pRemove)
687 			pRemove->Next = pEntry->Next;
688 		else
689 			HashTable[HASHID(hThread)] = pEntry->Next;
690 
691 		free(pEntry);
692 	}
693 
694 	pthread_mutex_unlock(&HashLock);
695 }
696 
697 oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
698 {
699 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
700 	sal_uInt16   Ident;
701 
702 	if (pImpl)
703 		Ident = pImpl->m_Ident;
704 	else
705 	{
706 		/* current thread */
707 		pthread_t current = pthread_self();
708 
709 		Ident = lookupThreadId (current);
710 		if (Ident == 0)
711 			/* @@@ see TODO: alien pthread_self() @@@ */
712 			Ident = insertThreadId (current);
713 	}
714 
715 	return ((oslThreadIdentifier)(Ident));
716 }
717 
718 /*****************************************************************************
719     @@@ see TODO @@@
720 	osl_thread_priority_init_Impl
721 
722 	set the base-priority of the main-thread to
723 	oslThreadPriorityNormal (64) since 0 (lowest) is
724 	the system default. This behaviour collides with
725 	our enum-priority definition (highest..normal..lowest).
726 	A  normaluser will expect the main-thread of an app.
727 	to have the "normal" priority.
728 
729 *****************************************************************************/
730 static void osl_thread_priority_init_Impl (void)
731 {
732 #ifndef NO_PTHREAD_PRIORITY
733     struct sched_param param;
734     int policy=0;
735     int nRet=0;
736 
737 /* @@@ see TODO: calling thread may not be main thread @@@ */
738 
739     if ((nRet = pthread_getschedparam(pthread_self(), &policy, &param)) != 0)
740     {
741         OSL_TRACE("failed to get priority of thread [%s]\n",strerror(nRet));
742         return;
743     }
744 
745 #if defined (SOLARIS)
746     if ( policy >= _SCHED_NEXT)
747     {
748         /* mfe: pthread_getschedparam on Solaris has a possible Bug */
749         /*      one gets 959917873 as the policy                    */
750         /*      so set the policy to a default one                  */
751         policy=SCHED_OTHER;
752     }
753 #endif /* SOLARIS */
754 
755     if ((nRet = sched_get_priority_min(policy) ) != -1)
756     {
757         OSL_TRACE("Min Prioriy for policy '%i' == '%i'\n",policy,nRet);
758         g_thread.m_priority.m_Lowest=nRet;
759     }
760 #if OSL_DEBUG_LEVEL > 1
761     else
762     {
763         fprintf(stderr,"failed to get min sched param [%s]\n",strerror(errno));
764     }
765 #endif /* OSL_DEBUG_LEVEL */
766 
767     if ((nRet = sched_get_priority_max(policy) ) != -1)
768     {
769         OSL_TRACE("Max Prioriy for policy '%i' == '%i'\n",policy,nRet);
770         g_thread.m_priority.m_Highest=nRet;
771     }
772 #if OSL_DEBUG_LEVEL > 1
773     else
774     {
775         fprintf(stderr,"failed to get max sched param [%s]\n",strerror(errno));
776     }
777 #endif /* OSL_DEBUG_LEVEL */
778 
779     g_thread.m_priority.m_Normal =
780 		(g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Highest) / 2;
781     g_thread.m_priority.m_Below_Normal =
782 		(g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Normal)  / 2;
783     g_thread.m_priority.m_Above_Normal =
784 		(g_thread.m_priority.m_Normal + g_thread.m_priority.m_Highest) / 2;
785 
786 /* @@@ set prio of calling (not main) thread (?) @@@ */
787 
788     param.sched_priority= g_thread.m_priority.m_Normal;
789 
790     if ((nRet = pthread_setschedparam(pthread_self(), policy, &param)) != 0)
791     {
792         OSL_TRACE("failed to change base priority of thread [%s]\n",strerror(nRet));
793         OSL_TRACE("Thread ID '%i', Policy '%i', Priority '%i'\n",pthread_self(),policy,param.sched_priority);
794     }
795 
796 #endif /* NO_PTHREAD_PRIORITY */
797 }
798 
799 /*****************************************************************************/
800 /* osl_setThreadPriority */
801 /*
802 	Impl-Notes: contrary to solaris-docu, which claims
803 	valid priority-levels from 0 .. INT_MAX, only the
804 	range 0..127 is accepted. (0 lowest, 127 highest)
805 */
806 /*****************************************************************************/
807 void SAL_CALL osl_setThreadPriority (
808 	oslThread         Thread,
809 	oslThreadPriority Priority)
810 {
811 #ifndef NO_PTHREAD_PRIORITY
812 
813 	struct sched_param Param;
814 	int policy;
815     int nRet;
816 
817 #endif /* NO_PTHREAD_PRIORITY */
818 
819 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
820 
821 	OSL_ASSERT(pImpl);
822 	if (!pImpl)
823 		return; /* EINVAL */
824 
825 #ifdef NO_PTHREAD_PRIORITY
826     (void) Priority; /* unused */
827 #else /* NO_PTHREAD_PRIORITY */
828 
829     if (pthread_getschedparam(pImpl->m_hThread, &policy, &Param) != 0)
830 		return; /* ESRCH */
831 
832 #if defined (SOLARIS)
833     if ( policy >= _SCHED_NEXT)
834     {
835         /* mfe: pthread_getschedparam on Solaris has a possible Bug */
836         /*      one gets 959917873 as the policy                   */
837         /*      so set the policy to a default one                 */
838         policy=SCHED_OTHER;
839     }
840 #endif /* SOLARIS */
841 
842 	pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
843 
844     switch(Priority)
845     {
846         case osl_Thread_PriorityHighest:
847             Param.sched_priority= g_thread.m_priority.m_Highest;
848             break;
849 
850         case osl_Thread_PriorityAboveNormal:
851             Param.sched_priority= g_thread.m_priority.m_Above_Normal;
852             break;
853 
854         case osl_Thread_PriorityNormal:
855             Param.sched_priority= g_thread.m_priority.m_Normal;
856             break;
857 
858         case osl_Thread_PriorityBelowNormal:
859             Param.sched_priority= g_thread.m_priority.m_Below_Normal;
860             break;
861 
862         case osl_Thread_PriorityLowest:
863             Param.sched_priority= g_thread.m_priority.m_Lowest;
864             break;
865 
866         case osl_Thread_PriorityUnknown:
867             OSL_ASSERT(sal_False);		/* only fools try this...*/
868 
869             /* let release-version behave friendly */
870             return;
871 
872         default:
873             /* enum expanded, but forgotten here...*/
874             OSL_ENSURE(sal_False,"osl_setThreadPriority : unknown priority\n");
875 
876             /* let release-version behave friendly */
877             return;
878     }
879 
880     if ((nRet = pthread_setschedparam(pImpl->m_hThread, policy, &Param)) != 0)
881     {
882         OSL_TRACE("failed to change thread priority [%s]\n",strerror(nRet));
883     }
884 
885 #endif /* NO_PTHREAD_PRIORITY */
886 }
887 
888 /*****************************************************************************/
889 /* osl_getThreadPriority */
890 /*****************************************************************************/
891 oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
892 {
893 #ifndef NO_PTHREAD_PRIORITY
894 
895 	struct sched_param Param;
896 	int Policy;
897 
898 #endif /* NO_PTHREAD_PRIORITY */
899 
900 	oslThreadPriority Priority = osl_Thread_PriorityNormal;
901 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
902 
903 	OSL_ASSERT(pImpl);
904 	if (!pImpl)
905 		return osl_Thread_PriorityUnknown; /* EINVAL */
906 
907 #ifndef NO_PTHREAD_PRIORITY
908 
909 	if (pthread_getschedparam(pImpl->m_hThread, &Policy, &Param) != 0)
910 		return osl_Thread_PriorityUnknown; /* ESRCH */
911 
912 	pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
913 
914 	/* map pthread priority to enum */
915 	if (Param.sched_priority==g_thread.m_priority.m_Highest)
916 	{
917 		/* 127 - highest */
918 		Priority= osl_Thread_PriorityHighest;
919 	}
920 	else if (Param.sched_priority > g_thread.m_priority.m_Normal)
921 	{
922 		/* 65..126 - above normal */
923 		Priority= osl_Thread_PriorityAboveNormal;
924 	}
925 	else if (Param.sched_priority == g_thread.m_priority.m_Normal)
926 	{
927 		/* normal */
928 		Priority= osl_Thread_PriorityNormal;
929 	}
930 	else if (Param.sched_priority > g_thread.m_priority.m_Lowest)
931 	{
932 		/* 63..1 -below normal */
933 		Priority= osl_Thread_PriorityBelowNormal;
934 	}
935 	else if (Param.sched_priority == g_thread.m_priority.m_Lowest)
936 	{
937 		/* 0 - lowest */
938 		Priority= osl_Thread_PriorityLowest;
939 	}
940 	else
941 	{
942 		/* unknown */
943 		Priority= osl_Thread_PriorityUnknown;
944 	}
945 
946 #endif /* NO_PTHREAD_PRIORITY */
947 
948 	return Priority;
949 }
950 
951 /*****************************************************************************/
952 /* osl_createThreadKey */
953 /*****************************************************************************/
954 oslThreadKey SAL_CALL osl_createThreadKey( oslThreadKeyCallbackFunction pCallback )
955 {
956 	pthread_key_t key;
957 
958 	if (pthread_key_create(&key, pCallback) != 0)
959 		key = 0;
960 
961 	return ((oslThreadKey)key);
962 }
963 
964 /*****************************************************************************/
965 /* osl_destroyThreadKey */
966 /*****************************************************************************/
967 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
968 {
969 	pthread_key_delete((pthread_key_t)Key);
970 }
971 
972 /*****************************************************************************/
973 /* osl_getThreadKeyData */
974 /*****************************************************************************/
975 void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
976 {
977 	return (pthread_getspecific((pthread_key_t)Key));
978 }
979 
980 /*****************************************************************************/
981 /* osl_setThreadKeyData */
982 /*****************************************************************************/
983 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
984 {
985 	return (pthread_setspecific((pthread_key_t)Key, pData) == 0);
986 }
987 
988 /*****************************************************************************/
989 /* Thread Local Text Encoding */
990 /*****************************************************************************/
991 static void osl_thread_textencoding_init_Impl (void)
992 {
993 	rtl_TextEncoding defaultEncoding;
994 	const char *     pszEncoding;
995 
996 	/* create thread specific data key */
997 	pthread_key_create (&(g_thread.m_textencoding.m_key), NULL);
998 
999 	/* determine default text encoding */
1000 	pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING");
1001 	if (pszEncoding)
1002 		defaultEncoding = atoi(pszEncoding);
1003 	else
1004 		defaultEncoding = osl_getTextEncodingFromLocale(NULL);
1005 
1006 	OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW);
1007 
1008 	/*
1009 	Tools string functions call abort() on an unknown encoding so ASCII
1010 	is a meaningfull fallback regardless wether the assertion makes sense.
1011 	*/
1012 
1013 	if ( RTL_TEXTENCODING_DONTKNOW == defaultEncoding )
1014 		defaultEncoding = RTL_TEXTENCODING_ASCII_US;
1015 
1016 	g_thread.m_textencoding.m_default = defaultEncoding;
1017 }
1018 
1019 /*****************************************************************************/
1020 /* osl_getThreadTextEncoding */
1021 /*****************************************************************************/
1022 rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding()
1023 {
1024     rtl_TextEncoding threadEncoding;
1025 
1026 	pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
1027 
1028     /* check for thread specific encoding, use default if not set */
1029 	threadEncoding = SAL_INT_CAST(
1030         rtl_TextEncoding,
1031         (sal_uIntPtr) pthread_getspecific(g_thread.m_textencoding.m_key));
1032 	if (0 == threadEncoding)
1033 		threadEncoding = g_thread.m_textencoding.m_default;
1034 
1035     return threadEncoding;
1036 }
1037 
1038 /*****************************************************************************/
1039 /* osl_setThreadTextEncoding */
1040 /*****************************************************************************/
1041 rtl_TextEncoding osl_setThreadTextEncoding(rtl_TextEncoding Encoding)
1042 {
1043     rtl_TextEncoding oldThreadEncoding = osl_getThreadTextEncoding();
1044 
1045     /* save encoding in thread local storage */
1046     pthread_setspecific (
1047         g_thread.m_textencoding.m_key,
1048         (void*) SAL_INT_CAST(sal_uIntPtr, Encoding));
1049 
1050     return oldThreadEncoding;
1051 }
1052