xref: /aoo4110/main/sal/osl/unx/thread.c (revision b1cdbd2c)
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) = 0;
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",
302 			      nRet, strerror(nRet));
303 
304 		pthread_mutex_unlock (&(pImpl->m_Lock));
305 		osl_thread_destruct_Impl (&pImpl);
306 
307 		return (0);
308 	}
309 
310 	/* wait for change from STARTUP to ACTIVE state */
311 	while (pImpl->m_Flags & THREADIMPL_FLAGS_STARTUP)
312 	{
313 		/* wait until STARTUP flag is cleared */
314 		pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock));
315         pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
316 		pthread_cleanup_pop (0);
317     }
318 
319     pthread_mutex_unlock (&(pImpl->m_Lock));
320 
321 	return ((oslThread)(pImpl));
322 }
323 
324 /*****************************************************************************/
325 /* osl_createThread */
326 /*****************************************************************************/
osl_createThread(oslWorkerFunction pWorker,void * pThreadData)327 oslThread osl_createThread (
328 	oslWorkerFunction pWorker,
329 	void *            pThreadData)
330 {
331     return osl_thread_create_Impl (
332 		pWorker,
333 		pThreadData,
334 		THREADIMPL_FLAGS_ATTACHED);
335 }
336 
337 /*****************************************************************************/
338 /* osl_createSuspendedThread */
339 /*****************************************************************************/
osl_createSuspendedThread(oslWorkerFunction pWorker,void * pThreadData)340 oslThread osl_createSuspendedThread (
341 	oslWorkerFunction pWorker,
342 	void *            pThreadData)
343 {
344     return osl_thread_create_Impl (
345 		pWorker,
346 		pThreadData,
347 		THREADIMPL_FLAGS_ATTACHED |
348 		THREADIMPL_FLAGS_SUSPENDED );
349 }
350 
351 /*****************************************************************************/
352 /* osl_destroyThread */
353 /*****************************************************************************/
osl_destroyThread(oslThread Thread)354 void SAL_CALL osl_destroyThread(oslThread Thread)
355 {
356     if (Thread != NULL) {
357         Thread_Impl * impl = (Thread_Impl *) Thread;
358         int active;
359         pthread_mutex_lock(&impl->m_Lock);
360         active = (impl->m_Flags & THREADIMPL_FLAGS_ACTIVE) != 0;
361         impl->m_Flags |= THREADIMPL_FLAGS_DESTROYED;
362         pthread_mutex_unlock(&impl->m_Lock);
363         if (!active) {
364             osl_thread_destruct_Impl(&impl);
365         }
366     }
367 }
368 
369 /*****************************************************************************/
370 /* osl_resumeThread */
371 /*****************************************************************************/
osl_resumeThread(oslThread Thread)372 void SAL_CALL osl_resumeThread(oslThread Thread)
373 {
374 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
375 
376 	OSL_ASSERT(pImpl);
377 	if (!pImpl)
378 		return; /* EINVAL */
379 
380 	pthread_mutex_lock (&(pImpl->m_Lock));
381 
382 	if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
383     {
384 		/* clear SUSPENDED flag */
385 		pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
386 		pthread_cond_signal (&(pImpl->m_Cond));
387     }
388 
389 	pthread_mutex_unlock (&(pImpl->m_Lock));
390 }
391 
392 /*****************************************************************************/
393 /* osl_suspendThread */
394 /*****************************************************************************/
osl_suspendThread(oslThread Thread)395 void SAL_CALL osl_suspendThread(oslThread Thread)
396 {
397     Thread_Impl* pImpl= (Thread_Impl*)Thread;
398 
399 	OSL_ASSERT(pImpl);
400 	if (!pImpl)
401 		return; /* EINVAL */
402 
403 	pthread_mutex_lock (&(pImpl->m_Lock));
404 
405 	pImpl->m_Flags |= THREADIMPL_FLAGS_SUSPENDED;
406 
407 	if (pthread_equal (pthread_self(), pImpl->m_hThread))
408     {
409 		/* self suspend */
410         while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
411         {
412             /* wait until SUSPENDED flag is cleared */
413 			pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock));
414 			pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
415 			pthread_cleanup_pop (0);
416         }
417     }
418 
419 	pthread_mutex_unlock (&(pImpl->m_Lock));
420 }
421 
422 /*****************************************************************************/
423 /* osl_isThreadRunning */
424 /*****************************************************************************/
osl_isThreadRunning(const oslThread Thread)425 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
426 {
427 	sal_Bool active;
428 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
429 
430 	if (!pImpl)
431 		return sal_False;
432 
433 	pthread_mutex_lock (&(pImpl->m_Lock));
434 	active = ((pImpl->m_Flags & THREADIMPL_FLAGS_ACTIVE) > 0);
435 	pthread_mutex_unlock (&(pImpl->m_Lock));
436 
437 	return (active);
438 }
439 
440 /*****************************************************************************/
441 /* osl_joinWithThread */
442 /*****************************************************************************/
osl_joinWithThread(oslThread Thread)443 void SAL_CALL osl_joinWithThread(oslThread Thread)
444 {
445     pthread_t thread;
446 	int attached;
447 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
448 
449 	if (!pImpl)
450 		return;
451 
452 	pthread_mutex_lock (&(pImpl->m_Lock));
453 
454 	if (pthread_equal (pthread_self(), pImpl->m_hThread))
455 	{
456 		/* self join */
457 		pthread_mutex_unlock (&(pImpl->m_Lock));
458 		return; /* EDEADLK */
459 	}
460 
461     thread = pImpl->m_hThread;
462 	attached = ((pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) > 0);
463 	pImpl->m_Flags &= ~THREADIMPL_FLAGS_ATTACHED;
464 
465 	pthread_mutex_unlock (&(pImpl->m_Lock));
466 
467 	if (attached)
468 	{
469 		/* install cleanup handler to ensure consistent flags and state */
470 		pthread_cleanup_push (
471 			osl_thread_join_cleanup_Impl, (void*)thread);
472 
473 		/* join */
474 		pthread_join (thread, NULL);
475 
476 		/* remove cleanup handler */
477 		pthread_cleanup_pop (0);
478 	}
479 }
480 
481 /*****************************************************************************/
482 /* osl_terminateThread */
483 /*****************************************************************************/
osl_terminateThread(oslThread Thread)484 void SAL_CALL osl_terminateThread(oslThread Thread)
485 {
486 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
487 
488 	OSL_ASSERT(pImpl);
489 	if (!pImpl)
490 		return; /* EINVAL */
491 
492 	pthread_mutex_lock (&(pImpl->m_Lock));
493 
494 	if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
495     {
496 		/* clear SUSPENDED flag */
497 		pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
498 		pthread_cond_signal (&(pImpl->m_Cond));
499     }
500 
501 	pImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE;
502 
503 	pthread_mutex_unlock (&(pImpl->m_Lock));
504 }
505 
506 /*****************************************************************************/
507 /* osl_scheduleThread */
508 /*****************************************************************************/
osl_scheduleThread(oslThread Thread)509 sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
510 {
511 	int terminate;
512 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
513 
514 	OSL_ASSERT(pImpl);
515 	if (!pImpl)
516 		return sal_False; /* EINVAL */
517 
518 	OSL_ASSERT(pthread_equal (pthread_self(), pImpl->m_hThread));
519 	if (!(pthread_equal (pthread_self(), pImpl->m_hThread)))
520 		return sal_False; /* EINVAL */
521 
522 	pthread_testcancel();
523 	pthread_mutex_lock (&(pImpl->m_Lock));
524 
525 	while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
526     {
527 		/* wait until SUSPENDED flag is cleared */
528 		pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock));
529 		pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
530 		pthread_cleanup_pop (0);
531     }
532 
533 	terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);
534 
535 	pthread_mutex_unlock(&(pImpl->m_Lock));
536 	pthread_testcancel();
537 
538 	return (terminate == 0);
539 }
540 
541 /*****************************************************************************/
542 /* osl_waitThread */
543 /*****************************************************************************/
osl_waitThread(const TimeValue * pDelay)544 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
545 {
546 	if (pDelay)
547 	{
548 		struct timespec delay;
549 
550 		SET_TIMESPEC(delay, pDelay->Seconds, pDelay->Nanosec);
551 
552 		SLEEP_TIMESPEC(delay);
553 	}
554 }
555 
556 /*****************************************************************************/
557 /* osl_yieldThread */
558 /*
559 	Note that POSIX scheduling _really_ requires threads to call this
560 	functions, since a thread only reschedules to other thread, when
561     it blocks (sleep, blocking I/O) OR calls sched_yield().
562 */
563 /*****************************************************************************/
osl_yieldThread()564 void SAL_CALL osl_yieldThread()
565 {
566     sched_yield();
567 }
568 
osl_setThreadName(char const * name)569 void SAL_CALL osl_setThreadName(char const * name) {
570 #if defined LINUX
571     if (prctl(PR_SET_NAME, (unsigned long) name, 0, 0, 0) != 0) {
572         OSL_TRACE(
573             "%s prctl(PR_SET_NAME) failed with errno %d", OSL_LOG_PREFIX,
574             errno);
575     }
576 #else
577     (void) name;
578 #endif
579 }
580 
581 /*****************************************************************************/
582 /* osl_getThreadIdentifier @@@ see TODO @@@ */
583 /*****************************************************************************/
584 
585 #define HASHID(x) ((unsigned int)PTHREAD_VALUE(x) % HashSize)
586 
587 typedef struct _HashEntry
588 {
589 	pthread_t         Handle;
590 	sal_uInt16	      Ident;
591 	struct _HashEntry *Next;
592 } HashEntry;
593 
594 static HashEntry* HashTable[31];
595 static int HashSize = sizeof(HashTable) / sizeof(HashTable[0]);
596 
597 static pthread_mutex_t HashLock = PTHREAD_MUTEX_INITIALIZER;
598 
599 static sal_uInt16 LastIdent = 0;
600 
lookupThreadId(pthread_t hThread)601 static sal_uInt16 lookupThreadId (pthread_t hThread)
602 {
603 	HashEntry *pEntry;
604 
605 	pthread_mutex_lock(&HashLock);
606 
607 		pEntry = HashTable[HASHID(hThread)];
608 		while (pEntry != NULL)
609 		{
610 			if (pthread_equal(pEntry->Handle, hThread))
611 			{
612 				pthread_mutex_unlock(&HashLock);
613 				return (pEntry->Ident);
614 			}
615 			pEntry = pEntry->Next;
616 		}
617 
618 	pthread_mutex_unlock(&HashLock);
619 
620 	return (0);
621 }
622 
insertThreadId(pthread_t hThread)623 static sal_uInt16 insertThreadId (pthread_t hThread)
624 {
625 	HashEntry *pEntry, *pInsert = NULL;
626 
627 	pthread_mutex_lock(&HashLock);
628 
629 	pEntry = HashTable[HASHID(hThread)];
630 
631 	while (pEntry != NULL)
632 	{
633 		if (pthread_equal(pEntry->Handle, hThread))
634 			break;
635 
636 		pInsert = pEntry;
637 		pEntry = pEntry->Next;
638 	}
639 
640 	if (pEntry == NULL)
641 	{
642 		pEntry = (HashEntry*) calloc(sizeof(HashEntry), 1);
643 
644 		pEntry->Handle = hThread;
645 
646 		++ LastIdent;
647 
648         if ( LastIdent == 0 )
649             LastIdent = 1;
650 
651         pEntry->Ident  = LastIdent;
652 
653 		if (pInsert)
654 			pInsert->Next = pEntry;
655 		else
656 			HashTable[HASHID(hThread)] = pEntry;
657 	}
658 
659 	pthread_mutex_unlock(&HashLock);
660 
661 	return (pEntry->Ident);
662 }
663 
removeThreadId(pthread_t hThread)664 static void removeThreadId (pthread_t hThread)
665 {
666 	HashEntry *pEntry, *pRemove = NULL;
667 
668 	pthread_mutex_lock(&HashLock);
669 
670 	pEntry = HashTable[HASHID(hThread)];
671 	while (pEntry != NULL)
672 	{
673 		if (pthread_equal(pEntry->Handle, hThread))
674 			break;
675 
676 		pRemove = pEntry;
677 		pEntry = pEntry->Next;
678 	}
679 
680 	if (pEntry != NULL)
681 	{
682 		if (pRemove)
683 			pRemove->Next = pEntry->Next;
684 		else
685 			HashTable[HASHID(hThread)] = pEntry->Next;
686 
687 		free(pEntry);
688 	}
689 
690 	pthread_mutex_unlock(&HashLock);
691 }
692 
osl_getThreadIdentifier(oslThread Thread)693 oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
694 {
695 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
696 	sal_uInt16   Ident;
697 
698 	if (pImpl)
699 		Ident = pImpl->m_Ident;
700 	else
701 	{
702 		/* current thread */
703 		pthread_t current = pthread_self();
704 
705 		Ident = lookupThreadId (current);
706 		if (Ident == 0)
707 			/* @@@ see TODO: alien pthread_self() @@@ */
708 			Ident = insertThreadId (current);
709 	}
710 
711 	return ((oslThreadIdentifier)(Ident));
712 }
713 
714 /*****************************************************************************
715     @@@ see TODO @@@
716 	osl_thread_priority_init_Impl
717 
718 	set the base-priority of the main-thread to
719 	oslThreadPriorityNormal (64) since 0 (lowest) is
720 	the system default. This behaviour collides with
721 	our enum-priority definition (highest..normal..lowest).
722 	A  normaluser will expect the main-thread of an app.
723 	to have the "normal" priority.
724 
725 *****************************************************************************/
osl_thread_priority_init_Impl(void)726 static void osl_thread_priority_init_Impl (void)
727 {
728 #ifndef NO_PTHREAD_PRIORITY
729     struct sched_param param;
730     int policy=0;
731     int nRet=0;
732 
733 /* @@@ see TODO: calling thread may not be main thread @@@ */
734 
735     if ((nRet = pthread_getschedparam(pthread_self(), &policy, &param)) != 0)
736     {
737         OSL_TRACE("failed to get priority of thread [%s]\n",strerror(nRet));
738         return;
739     }
740 
741 #if defined (SOLARIS)
742     if ( policy >= _SCHED_NEXT)
743     {
744         /* mfe: pthread_getschedparam on Solaris has a possible Bug */
745         /*      one gets 959917873 as the policy                    */
746         /*      so set the policy to a default one                  */
747         policy=SCHED_OTHER;
748     }
749 #endif /* SOLARIS */
750 
751     if ((nRet = sched_get_priority_min(policy) ) != -1)
752     {
753         OSL_TRACE("Min Prioriy for policy '%i' == '%i'\n",policy,nRet);
754         g_thread.m_priority.m_Lowest=nRet;
755     }
756 #if OSL_DEBUG_LEVEL > 1
757     else
758     {
759         fprintf(stderr,"failed to get min sched param [%s]\n",strerror(errno));
760     }
761 #endif /* OSL_DEBUG_LEVEL */
762 
763     if ((nRet = sched_get_priority_max(policy) ) != -1)
764     {
765         OSL_TRACE("Max Prioriy for policy '%i' == '%i'\n",policy,nRet);
766         g_thread.m_priority.m_Highest=nRet;
767     }
768 #if OSL_DEBUG_LEVEL > 1
769     else
770     {
771         fprintf(stderr,"failed to get max sched param [%s]\n",strerror(errno));
772     }
773 #endif /* OSL_DEBUG_LEVEL */
774 
775     g_thread.m_priority.m_Normal =
776 		(g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Highest) / 2;
777     g_thread.m_priority.m_Below_Normal =
778 		(g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Normal)  / 2;
779     g_thread.m_priority.m_Above_Normal =
780 		(g_thread.m_priority.m_Normal + g_thread.m_priority.m_Highest) / 2;
781 
782 /* @@@ set prio of calling (not main) thread (?) @@@ */
783 
784     param.sched_priority= g_thread.m_priority.m_Normal;
785 
786     if ((nRet = pthread_setschedparam(pthread_self(), policy, &param)) != 0)
787     {
788         OSL_TRACE("failed to change base priority of thread [%s]\n",strerror(nRet));
789         OSL_TRACE("Thread ID '%i', Policy '%i', Priority '%i'\n",pthread_self(),policy,param.sched_priority);
790     }
791 
792 #endif /* NO_PTHREAD_PRIORITY */
793 }
794 
795 /*****************************************************************************/
796 /* osl_setThreadPriority */
797 /*
798 	Impl-Notes: contrary to solaris-docu, which claims
799 	valid priority-levels from 0 .. INT_MAX, only the
800 	range 0..127 is accepted. (0 lowest, 127 highest)
801 */
802 /*****************************************************************************/
osl_setThreadPriority(oslThread Thread,oslThreadPriority Priority)803 void SAL_CALL osl_setThreadPriority (
804 	oslThread         Thread,
805 	oslThreadPriority Priority)
806 {
807 #ifndef NO_PTHREAD_PRIORITY
808 
809 	struct sched_param Param;
810 	int policy;
811     int nRet;
812 
813 #endif /* NO_PTHREAD_PRIORITY */
814 
815 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
816 
817 	OSL_ASSERT(pImpl);
818 	if (!pImpl)
819 		return; /* EINVAL */
820 
821 #ifdef NO_PTHREAD_PRIORITY
822     (void) Priority; /* unused */
823 #else /* NO_PTHREAD_PRIORITY */
824 
825     if (pthread_getschedparam(pImpl->m_hThread, &policy, &Param) != 0)
826 		return; /* ESRCH */
827 
828 #if defined (SOLARIS)
829     if ( policy >= _SCHED_NEXT)
830     {
831         /* mfe: pthread_getschedparam on Solaris has a possible Bug */
832         /*      one gets 959917873 as the policy                   */
833         /*      so set the policy to a default one                 */
834         policy=SCHED_OTHER;
835     }
836 #endif /* SOLARIS */
837 
838 	pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
839 
840     switch(Priority)
841     {
842         case osl_Thread_PriorityHighest:
843             Param.sched_priority= g_thread.m_priority.m_Highest;
844             break;
845 
846         case osl_Thread_PriorityAboveNormal:
847             Param.sched_priority= g_thread.m_priority.m_Above_Normal;
848             break;
849 
850         case osl_Thread_PriorityNormal:
851             Param.sched_priority= g_thread.m_priority.m_Normal;
852             break;
853 
854         case osl_Thread_PriorityBelowNormal:
855             Param.sched_priority= g_thread.m_priority.m_Below_Normal;
856             break;
857 
858         case osl_Thread_PriorityLowest:
859             Param.sched_priority= g_thread.m_priority.m_Lowest;
860             break;
861 
862         case osl_Thread_PriorityUnknown:
863             OSL_ASSERT(sal_False);		/* only fools try this...*/
864 
865             /* let release-version behave friendly */
866             return;
867 
868         default:
869             /* enum expanded, but forgotten here...*/
870             OSL_ENSURE(sal_False,"osl_setThreadPriority : unknown priority\n");
871 
872             /* let release-version behave friendly */
873             return;
874     }
875 
876     if ((nRet = pthread_setschedparam(pImpl->m_hThread, policy, &Param)) != 0)
877     {
878         OSL_TRACE("failed to change thread priority [%s]\n",strerror(nRet));
879     }
880 
881 #endif /* NO_PTHREAD_PRIORITY */
882 }
883 
884 /*****************************************************************************/
885 /* osl_getThreadPriority */
886 /*****************************************************************************/
osl_getThreadPriority(const oslThread Thread)887 oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
888 {
889 #ifndef NO_PTHREAD_PRIORITY
890 
891 	struct sched_param Param;
892 	int Policy;
893 
894 #endif /* NO_PTHREAD_PRIORITY */
895 
896 	oslThreadPriority Priority = osl_Thread_PriorityNormal;
897 	Thread_Impl* pImpl= (Thread_Impl*)Thread;
898 
899 	OSL_ASSERT(pImpl);
900 	if (!pImpl)
901 		return osl_Thread_PriorityUnknown; /* EINVAL */
902 
903 #ifndef NO_PTHREAD_PRIORITY
904 
905 	if (pthread_getschedparam(pImpl->m_hThread, &Policy, &Param) != 0)
906 		return osl_Thread_PriorityUnknown; /* ESRCH */
907 
908 	pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
909 
910 	/* map pthread priority to enum */
911 	if (Param.sched_priority==g_thread.m_priority.m_Highest)
912 	{
913 		/* 127 - highest */
914 		Priority= osl_Thread_PriorityHighest;
915 	}
916 	else if (Param.sched_priority > g_thread.m_priority.m_Normal)
917 	{
918 		/* 65..126 - above normal */
919 		Priority= osl_Thread_PriorityAboveNormal;
920 	}
921 	else if (Param.sched_priority == g_thread.m_priority.m_Normal)
922 	{
923 		/* normal */
924 		Priority= osl_Thread_PriorityNormal;
925 	}
926 	else if (Param.sched_priority > g_thread.m_priority.m_Lowest)
927 	{
928 		/* 63..1 -below normal */
929 		Priority= osl_Thread_PriorityBelowNormal;
930 	}
931 	else if (Param.sched_priority == g_thread.m_priority.m_Lowest)
932 	{
933 		/* 0 - lowest */
934 		Priority= osl_Thread_PriorityLowest;
935 	}
936 	else
937 	{
938 		/* unknown */
939 		Priority= osl_Thread_PriorityUnknown;
940 	}
941 
942 #endif /* NO_PTHREAD_PRIORITY */
943 
944 	return Priority;
945 }
946 
947 /*****************************************************************************/
948 /* osl_createThreadKey */
949 /*****************************************************************************/
osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)950 oslThreadKey SAL_CALL osl_createThreadKey( oslThreadKeyCallbackFunction pCallback )
951 {
952 	pthread_key_t key;
953 
954 	if (pthread_key_create(&key, pCallback) != 0)
955 		key = 0;
956 
957 	return ((oslThreadKey)key);
958 }
959 
960 /*****************************************************************************/
961 /* osl_destroyThreadKey */
962 /*****************************************************************************/
osl_destroyThreadKey(oslThreadKey Key)963 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
964 {
965 	pthread_key_delete((pthread_key_t)Key);
966 }
967 
968 /*****************************************************************************/
969 /* osl_getThreadKeyData */
970 /*****************************************************************************/
osl_getThreadKeyData(oslThreadKey Key)971 void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
972 {
973 	return (pthread_getspecific((pthread_key_t)Key));
974 }
975 
976 /*****************************************************************************/
977 /* osl_setThreadKeyData */
978 /*****************************************************************************/
osl_setThreadKeyData(oslThreadKey Key,void * pData)979 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
980 {
981 	return (pthread_setspecific((pthread_key_t)Key, pData) == 0);
982 }
983 
984 /*****************************************************************************/
985 /* Thread Local Text Encoding */
986 /*****************************************************************************/
osl_thread_textencoding_init_Impl(void)987 static void osl_thread_textencoding_init_Impl (void)
988 {
989 	rtl_TextEncoding defaultEncoding;
990 	const char *     pszEncoding;
991 
992 	/* create thread specific data key */
993 	pthread_key_create (&(g_thread.m_textencoding.m_key), NULL);
994 
995 	/* determine default text encoding */
996 	pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING");
997 	if (pszEncoding)
998 		defaultEncoding = atoi(pszEncoding);
999 	else
1000 		defaultEncoding = osl_getTextEncodingFromLocale(NULL);
1001 
1002 	OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW);
1003 
1004 	/*
1005 	Tools string functions call abort() on an unknown encoding so ASCII
1006 	is a meaningfull fallback regardless wether the assertion makes sense.
1007 	*/
1008 
1009 	if ( RTL_TEXTENCODING_DONTKNOW == defaultEncoding )
1010 		defaultEncoding = RTL_TEXTENCODING_ASCII_US;
1011 
1012 	g_thread.m_textencoding.m_default = defaultEncoding;
1013 }
1014 
1015 /*****************************************************************************/
1016 /* osl_getThreadTextEncoding */
1017 /*****************************************************************************/
osl_getThreadTextEncoding()1018 rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding()
1019 {
1020     rtl_TextEncoding threadEncoding;
1021 
1022 	pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
1023 
1024     /* check for thread specific encoding, use default if not set */
1025 	threadEncoding = SAL_INT_CAST(
1026         rtl_TextEncoding,
1027         (sal_uIntPtr) pthread_getspecific(g_thread.m_textencoding.m_key));
1028 	if (0 == threadEncoding)
1029 		threadEncoding = g_thread.m_textencoding.m_default;
1030 
1031     return threadEncoding;
1032 }
1033 
1034 /*****************************************************************************/
1035 /* osl_setThreadTextEncoding */
1036 /*****************************************************************************/
osl_setThreadTextEncoding(rtl_TextEncoding Encoding)1037 rtl_TextEncoding osl_setThreadTextEncoding(rtl_TextEncoding Encoding)
1038 {
1039     rtl_TextEncoding oldThreadEncoding = osl_getThreadTextEncoding();
1040 
1041     /* save encoding in thread local storage */
1042     pthread_setspecific (
1043         g_thread.m_textencoding.m_key,
1044         (void*) SAL_INT_CAST(sal_uIntPtr, Encoding));
1045 
1046     return oldThreadEncoding;
1047 }
1048