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