update credits
[LibreOffice.git] / sal / osl / unx / thread.c
blob0e1ebbab7f02dffe04135f58a60904feffb59399
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "system.h"
21 #include <string.h>
22 #if defined(OPENBSD)
23 #include <sched.h>
24 #endif
25 #include <osl/diagnose.h>
26 #include <osl/thread.h>
27 #include <osl/nlsupport.h>
28 #include <rtl/textenc.h>
29 #include <rtl/alloc.h>
30 #include <sal/macros.h>
31 #ifdef ANDROID
32 #include <jni.h>
33 #include <android/log.h>
34 #include <osl/detail/android-bootstrap.h>
35 #endif
37 #if defined LINUX && ! defined __FreeBSD_kernel__
38 #include <sys/prctl.h>
39 #ifndef PR_SET_NAME
40 #define PR_SET_NAME 15
41 #endif
42 #endif
44 /****************************************************************************
45 * @@@ TODO @@@
47 * (1) 'osl_thread_priority_init_Impl()'
48 * - insane assumption that initializing caller is main thread
49 * - use _POSIX_THREAD_PRIORITY_SCHEDULING, not NO_PTHREAD_PRIORITY (?)
50 * - POSIX doesn't require defined prio's for SCHED_OTHER (!)
51 * - use SCHED_RR instead of SCHED_OTHER for defined behaviour (?)
52 * (2) 'oslThreadIdentifier' and '{insert|remove|lookup}ThreadId()'
53 * - cannot reliably be applied to 'alien' threads;
54 * - memory leak for 'alien' thread 'HashEntry's;
55 * - use 'PTHREAD_VALUE(pthread_t)' as identifier instead (?)
56 * - if yes, change 'oslThreadIdentifier' to 'intptr_t' or similar
57 * (3) 'oslSigAlarmHandler()' (#71232#)
58 * - [Under Solaris we get SIGALRM in e.g. pthread_join which terminates
59 * the process. So we initialize our signal handling module and do
60 * register a SIGALRM Handler which catches and ignores it]
61 * - should this still happen, 'signal.c' needs to be fixed instead.
63 ****************************************************************************/
65 /*****************************************************************************/
66 /* Internal data structures and functions */
67 /*****************************************************************************/
69 #define THREADIMPL_FLAGS_TERMINATE 0x00001
70 #define THREADIMPL_FLAGS_STARTUP 0x00002
71 #define THREADIMPL_FLAGS_SUSPENDED 0x00004
72 #define THREADIMPL_FLAGS_ACTIVE 0x00008
73 #define THREADIMPL_FLAGS_ATTACHED 0x00010
74 #define THREADIMPL_FLAGS_DESTROYED 0x00020
76 typedef struct osl_thread_impl_st
78 pthread_t m_hThread;
79 sal_uInt16 m_Ident; /* @@@ see TODO @@@ */
80 short m_Flags;
81 oslWorkerFunction m_WorkerFunction;
82 void* m_pData;
83 pthread_mutex_t m_Lock;
84 pthread_cond_t m_Cond;
85 } Thread_Impl;
87 struct osl_thread_priority_st
89 int m_Highest;
90 int m_Above_Normal;
91 int m_Normal;
92 int m_Below_Normal;
93 int m_Lowest;
96 #define OSL_THREAD_PRIORITY_INITIALIZER { 127, 96, 64, 32, 0 }
97 static void osl_thread_priority_init_Impl (void);
99 struct osl_thread_textencoding_st
101 pthread_key_t m_key; /* key to store thread local text encoding */
102 rtl_TextEncoding m_default; /* the default text encoding */
105 #define OSL_THREAD_TEXTENCODING_INITIALIZER { 0, RTL_TEXTENCODING_DONTKNOW }
106 static void osl_thread_textencoding_init_Impl (void);
108 struct osl_thread_global_st
110 pthread_once_t m_once;
111 struct osl_thread_priority_st m_priority;
112 struct osl_thread_textencoding_st m_textencoding;
115 static struct osl_thread_global_st g_thread =
117 PTHREAD_ONCE_INIT,
118 OSL_THREAD_PRIORITY_INITIALIZER,
119 OSL_THREAD_TEXTENCODING_INITIALIZER
122 static void osl_thread_init_Impl (void);
124 static Thread_Impl* osl_thread_construct_Impl (void);
125 static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl);
127 static void* osl_thread_start_Impl (void * pData);
128 static void osl_thread_cleanup_Impl (Thread_Impl * pImpl);
130 static oslThread osl_thread_create_Impl (
131 oslWorkerFunction pWorker, void * pThreadData, short nFlags);
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);
138 /*****************************************************************************/
139 /* osl_thread_init_Impl */
140 /*****************************************************************************/
141 static void osl_thread_init_Impl (void)
143 osl_thread_priority_init_Impl();
144 osl_thread_textencoding_init_Impl();
147 /*****************************************************************************/
148 /* osl_thread_construct_Impl */
149 /*****************************************************************************/
150 Thread_Impl* osl_thread_construct_Impl (void)
152 Thread_Impl* pImpl = malloc (sizeof(Thread_Impl));
153 if (pImpl)
155 memset (pImpl, 0, sizeof(Thread_Impl));
157 pthread_mutex_init (&(pImpl->m_Lock), PTHREAD_MUTEXATTR_DEFAULT);
158 pthread_cond_init (&(pImpl->m_Cond), PTHREAD_CONDATTR_DEFAULT);
160 return (pImpl);
163 /*****************************************************************************/
164 /* osl_thread_destruct_Impl */
165 /*****************************************************************************/
166 static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl)
168 OSL_ASSERT(ppImpl);
169 if (*ppImpl)
171 pthread_cond_destroy (&((*ppImpl)->m_Cond));
172 pthread_mutex_destroy (&((*ppImpl)->m_Lock));
174 free (*ppImpl);
175 (*ppImpl) = 0;
179 /*****************************************************************************/
180 /* osl_thread_cleanup_Impl */
181 /*****************************************************************************/
182 static void osl_thread_cleanup_Impl (Thread_Impl * pImpl)
184 pthread_t thread;
185 int attached;
186 int destroyed;
188 pthread_mutex_lock (&(pImpl->m_Lock));
190 thread = pImpl->m_hThread;
191 attached = (pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) != 0;
192 destroyed = (pImpl->m_Flags & THREADIMPL_FLAGS_DESTROYED) != 0;
193 pImpl->m_Flags &= ~(THREADIMPL_FLAGS_ACTIVE | THREADIMPL_FLAGS_ATTACHED);
195 pthread_mutex_unlock (&(pImpl->m_Lock));
197 /* release oslThreadIdentifier @@@ see TODO @@@ */
198 removeThreadId (thread);
200 if (attached)
202 pthread_detach (thread);
205 if (destroyed)
207 osl_thread_destruct_Impl (&pImpl);
211 /*****************************************************************************/
212 /* osl_thread_start_Impl */
213 /*****************************************************************************/
214 static void* osl_thread_start_Impl (void* pData)
216 int terminate;
217 Thread_Impl* pImpl= (Thread_Impl*)pData;
219 OSL_ASSERT(pImpl);
221 pthread_mutex_lock (&(pImpl->m_Lock));
223 /* request oslThreadIdentifier @@@ see TODO @@@ */
224 pImpl->m_Ident = insertThreadId (pImpl->m_hThread);
226 /* signal change from STARTUP to ACTIVE state */
227 pImpl->m_Flags &= ~THREADIMPL_FLAGS_STARTUP;
228 pImpl->m_Flags |= THREADIMPL_FLAGS_ACTIVE;
229 pthread_cond_signal (&(pImpl->m_Cond));
231 /* Check if thread is started in SUSPENDED state */
232 while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
234 /* wait until SUSPENDED flag is cleared */
235 pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
238 /* check for SUSPENDED to TERMINATE state change */
239 terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);
241 pthread_mutex_unlock (&(pImpl->m_Lock));
243 if (!terminate)
245 #ifdef ANDROID
246 JNIEnv* env = 0;
247 int res = (*lo_get_javavm())->AttachCurrentThread(lo_get_javavm(), &env, NULL);
248 __android_log_print(ANDROID_LOG_INFO, "LibreOffice", "New sal thread started and attached res=%d", res);
249 #endif
250 /* call worker function */
251 pImpl->m_WorkerFunction(pImpl->m_pData);
253 #ifdef ANDROID
254 res = (*lo_get_javavm())->DetachCurrentThread(lo_get_javavm());
255 __android_log_print(ANDROID_LOG_INFO, "LibreOffice", "Detached finished sal thread res=%d", res);
256 #endif
259 osl_thread_cleanup_Impl (pImpl);
260 return (0);
263 /*****************************************************************************/
264 /* osl_thread_create_Impl */
265 /*****************************************************************************/
266 static oslThread osl_thread_create_Impl (
267 oslWorkerFunction pWorker,
268 void* pThreadData,
269 short nFlags)
271 Thread_Impl* pImpl;
272 #if defined(OPENBSD)
273 pthread_attr_t attr;
274 #endif
275 int nRet=0;
277 pImpl = osl_thread_construct_Impl();
278 if (!pImpl)
279 return (0); /* ENOMEM */
281 pImpl->m_WorkerFunction = pWorker;
282 pImpl->m_pData = pThreadData;
283 pImpl->m_Flags = nFlags | THREADIMPL_FLAGS_STARTUP;
285 pthread_mutex_lock (&(pImpl->m_Lock));
287 #if defined(OPENBSD)
288 if (pthread_attr_init(&attr) != 0)
289 return (0);
291 if (pthread_attr_setstacksize(&attr, 262144) != 0) {
292 pthread_attr_destroy(&attr);
293 return (0);
295 #endif
297 if ((nRet = pthread_create (
298 &(pImpl->m_hThread),
299 #if defined(OPENBSD)
300 &attr,
301 #else
302 PTHREAD_ATTR_DEFAULT,
303 #endif
304 osl_thread_start_Impl,
305 (void*)(pImpl))) != 0)
307 OSL_TRACE("osl_thread_create_Impl(): errno: %d, %s\n",
308 nRet, strerror(nRet));
310 pthread_mutex_unlock (&(pImpl->m_Lock));
311 osl_thread_destruct_Impl (&pImpl);
313 return (0);
316 #if defined(OPENBSD)
317 pthread_attr_destroy(&attr);
318 #endif
320 /* wait for change from STARTUP to ACTIVE state */
321 while (pImpl->m_Flags & THREADIMPL_FLAGS_STARTUP)
323 /* wait until STARTUP flag is cleared */
324 pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
327 pthread_mutex_unlock (&(pImpl->m_Lock));
329 return ((oslThread)(pImpl));
332 /*****************************************************************************/
333 /* osl_createThread */
334 /*****************************************************************************/
335 oslThread osl_createThread (
336 oslWorkerFunction pWorker,
337 void * pThreadData)
339 return osl_thread_create_Impl (
340 pWorker,
341 pThreadData,
342 THREADIMPL_FLAGS_ATTACHED);
345 /*****************************************************************************/
346 /* osl_createSuspendedThread */
347 /*****************************************************************************/
348 oslThread osl_createSuspendedThread (
349 oslWorkerFunction pWorker,
350 void * pThreadData)
352 return osl_thread_create_Impl (
353 pWorker,
354 pThreadData,
355 THREADIMPL_FLAGS_ATTACHED |
356 THREADIMPL_FLAGS_SUSPENDED );
359 /*****************************************************************************/
360 /* osl_destroyThread */
361 /*****************************************************************************/
362 void SAL_CALL osl_destroyThread(oslThread Thread)
364 if (Thread != NULL) {
365 Thread_Impl * impl = (Thread_Impl *) Thread;
366 int active;
367 pthread_mutex_lock(&impl->m_Lock);
368 active = (impl->m_Flags & THREADIMPL_FLAGS_ACTIVE) != 0;
369 impl->m_Flags |= THREADIMPL_FLAGS_DESTROYED;
370 pthread_mutex_unlock(&impl->m_Lock);
371 if (!active) {
372 osl_thread_destruct_Impl(&impl);
377 /*****************************************************************************/
378 /* osl_resumeThread */
379 /*****************************************************************************/
380 void SAL_CALL osl_resumeThread(oslThread Thread)
382 Thread_Impl* pImpl= (Thread_Impl*)Thread;
384 OSL_ASSERT(pImpl);
385 if (!pImpl)
386 return; /* EINVAL */
388 pthread_mutex_lock (&(pImpl->m_Lock));
390 if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
392 /* clear SUSPENDED flag */
393 pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
394 pthread_cond_signal (&(pImpl->m_Cond));
397 pthread_mutex_unlock (&(pImpl->m_Lock));
400 /*****************************************************************************/
401 /* osl_suspendThread */
402 /*****************************************************************************/
403 void SAL_CALL osl_suspendThread(oslThread Thread)
405 Thread_Impl* pImpl= (Thread_Impl*)Thread;
407 OSL_ASSERT(pImpl);
408 if (!pImpl)
409 return; /* EINVAL */
411 pthread_mutex_lock (&(pImpl->m_Lock));
413 pImpl->m_Flags |= THREADIMPL_FLAGS_SUSPENDED;
415 if (pthread_equal (pthread_self(), pImpl->m_hThread))
417 /* self suspend */
418 while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
420 /* wait until SUSPENDED flag is cleared */
421 pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
425 pthread_mutex_unlock (&(pImpl->m_Lock));
428 /*****************************************************************************/
429 /* osl_isThreadRunning */
430 /*****************************************************************************/
431 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
433 sal_Bool active;
434 Thread_Impl* pImpl= (Thread_Impl*)Thread;
436 if (!pImpl)
437 return sal_False;
439 pthread_mutex_lock (&(pImpl->m_Lock));
440 active = ((pImpl->m_Flags & THREADIMPL_FLAGS_ACTIVE) > 0);
441 pthread_mutex_unlock (&(pImpl->m_Lock));
443 return (active);
446 /*****************************************************************************/
447 /* osl_joinWithThread */
448 /*****************************************************************************/
449 void SAL_CALL osl_joinWithThread(oslThread Thread)
451 pthread_t thread;
452 int attached;
453 Thread_Impl* pImpl= (Thread_Impl*)Thread;
455 if (!pImpl)
456 return;
458 pthread_mutex_lock (&(pImpl->m_Lock));
460 if (pthread_equal (pthread_self(), pImpl->m_hThread))
462 /* self join */
463 pthread_mutex_unlock (&(pImpl->m_Lock));
464 return; /* EDEADLK */
467 thread = pImpl->m_hThread;
468 attached = ((pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) > 0);
469 pImpl->m_Flags &= ~THREADIMPL_FLAGS_ATTACHED;
471 pthread_mutex_unlock (&(pImpl->m_Lock));
473 if (attached)
475 pthread_join (thread, NULL);
479 /*****************************************************************************/
480 /* osl_terminateThread */
481 /*****************************************************************************/
482 void SAL_CALL osl_terminateThread(oslThread Thread)
484 Thread_Impl* pImpl= (Thread_Impl*)Thread;
486 OSL_ASSERT(pImpl);
487 if (!pImpl)
488 return; /* EINVAL */
490 pthread_mutex_lock (&(pImpl->m_Lock));
492 if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
494 /* clear SUSPENDED flag */
495 pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
496 pthread_cond_signal (&(pImpl->m_Cond));
499 pImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE;
501 pthread_mutex_unlock (&(pImpl->m_Lock));
504 /*****************************************************************************/
505 /* osl_scheduleThread */
506 /*****************************************************************************/
507 sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
509 int terminate;
510 Thread_Impl* pImpl= (Thread_Impl*)Thread;
512 OSL_ASSERT(pImpl);
513 if (!pImpl)
514 return sal_False; /* EINVAL */
516 OSL_ASSERT(pthread_equal (pthread_self(), pImpl->m_hThread));
517 if (!(pthread_equal (pthread_self(), pImpl->m_hThread)))
518 return sal_False; /* EINVAL */
520 pthread_mutex_lock (&(pImpl->m_Lock));
522 while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
524 /* wait until SUSPENDED flag is cleared */
525 pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
528 terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);
530 pthread_mutex_unlock(&(pImpl->m_Lock));
532 return (terminate == 0);
535 /*****************************************************************************/
536 /* osl_waitThread */
537 /*****************************************************************************/
538 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
540 if (pDelay)
542 struct timespec delay;
544 SET_TIMESPEC(delay, pDelay->Seconds, pDelay->Nanosec);
546 SLEEP_TIMESPEC(delay);
550 /*****************************************************************************/
551 /* osl_yieldThread */
553 Note that POSIX scheduling _really_ requires threads to call this
554 functions, since a thread only reschedules to other thread, when
555 it blocks (sleep, blocking I/O) OR calls sched_yield().
557 /*****************************************************************************/
558 void SAL_CALL osl_yieldThread()
560 sched_yield();
563 void SAL_CALL osl_setThreadName(char const * name) {
564 #if defined LINUX && ! defined __FreeBSD_kernel__
565 if (prctl(PR_SET_NAME, (unsigned long) name, 0, 0, 0) != 0) {
566 OSL_TRACE(
567 "%s prctl(PR_SET_NAME) failed with errno %d", OSL_LOG_PREFIX,
568 errno);
570 #else
571 (void) name;
572 #endif
575 /*****************************************************************************/
576 /* osl_getThreadIdentifier @@@ see TODO @@@ */
577 /*****************************************************************************/
579 #define HASHID(x) ((unsigned int)PTHREAD_VALUE(x) % HashSize)
581 typedef struct _HashEntry
583 pthread_t Handle;
584 sal_uInt16 Ident;
585 struct _HashEntry *Next;
586 } HashEntry;
588 static HashEntry* HashTable[31];
589 static int HashSize = SAL_N_ELEMENTS(HashTable);
591 static pthread_mutex_t HashLock = PTHREAD_MUTEX_INITIALIZER;
593 static sal_uInt16 LastIdent = 0;
595 static sal_uInt16 lookupThreadId (pthread_t hThread)
597 HashEntry *pEntry;
599 pthread_mutex_lock(&HashLock);
601 pEntry = HashTable[HASHID(hThread)];
602 while (pEntry != NULL)
604 if (pthread_equal(pEntry->Handle, hThread))
606 pthread_mutex_unlock(&HashLock);
607 return (pEntry->Ident);
609 pEntry = pEntry->Next;
612 pthread_mutex_unlock(&HashLock);
614 return (0);
617 static sal_uInt16 insertThreadId (pthread_t hThread)
619 HashEntry *pEntry, *pInsert = NULL;
621 pthread_mutex_lock(&HashLock);
623 pEntry = HashTable[HASHID(hThread)];
625 while (pEntry != NULL)
627 if (pthread_equal(pEntry->Handle, hThread))
628 break;
630 pInsert = pEntry;
631 pEntry = pEntry->Next;
634 if (pEntry == NULL)
636 pEntry = (HashEntry*) calloc(sizeof(HashEntry), 1);
638 pEntry->Handle = hThread;
640 ++ LastIdent;
642 if ( LastIdent == 0 )
643 LastIdent = 1;
645 pEntry->Ident = LastIdent;
647 if (pInsert)
648 pInsert->Next = pEntry;
649 else
650 HashTable[HASHID(hThread)] = pEntry;
653 pthread_mutex_unlock(&HashLock);
655 return (pEntry->Ident);
658 static void removeThreadId (pthread_t hThread)
660 HashEntry *pEntry, *pRemove = NULL;
662 pthread_mutex_lock(&HashLock);
664 pEntry = HashTable[HASHID(hThread)];
665 while (pEntry != NULL)
667 if (pthread_equal(pEntry->Handle, hThread))
668 break;
670 pRemove = pEntry;
671 pEntry = pEntry->Next;
674 if (pEntry != NULL)
676 if (pRemove)
677 pRemove->Next = pEntry->Next;
678 else
679 HashTable[HASHID(hThread)] = pEntry->Next;
681 free(pEntry);
684 pthread_mutex_unlock(&HashLock);
687 oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
689 Thread_Impl* pImpl= (Thread_Impl*)Thread;
690 sal_uInt16 Ident;
692 if (pImpl)
693 Ident = pImpl->m_Ident;
694 else
696 /* current thread */
697 pthread_t current = pthread_self();
699 Ident = lookupThreadId (current);
700 if (Ident == 0)
701 /* @@@ see TODO: alien pthread_self() @@@ */
702 Ident = insertThreadId (current);
705 return ((oslThreadIdentifier)(Ident));
708 /*****************************************************************************
709 @@@ see TODO @@@
710 osl_thread_priority_init_Impl
712 set the base-priority of the main-thread to
713 oslThreadPriorityNormal (64) since 0 (lowest) is
714 the system default. This behaviour collides with
715 our enum-priority definition (highest..normal..lowest).
716 A normaluser will expect the main-thread of an app.
717 to have the "normal" priority.
719 *****************************************************************************/
720 static void osl_thread_priority_init_Impl (void)
722 #ifndef NO_PTHREAD_PRIORITY
723 struct sched_param param;
724 int policy=0;
725 int nRet=0;
727 /* @@@ see TODO: calling thread may not be main thread @@@ */
729 if ((nRet = pthread_getschedparam(pthread_self(), &policy, &param)) != 0)
731 OSL_TRACE("failed to get priority of thread [%s]",strerror(nRet));
732 return;
735 #if defined (SOLARIS)
736 if ( policy >= _SCHED_NEXT)
738 /* mfe: pthread_getschedparam on Solaris has a possible Bug */
739 /* one gets 959917873 as the policy */
740 /* so set the policy to a default one */
741 policy=SCHED_OTHER;
743 #endif /* SOLARIS */
745 if ((nRet = sched_get_priority_min(policy) ) != -1)
747 OSL_TRACE("Min Prioriy for policy '%i' == '%i'",policy,nRet);
748 g_thread.m_priority.m_Lowest=nRet;
750 #if OSL_DEBUG_LEVEL > 1
751 else
753 fprintf(stderr,"failed to get min sched param [%s]\n",strerror(errno));
755 #endif /* OSL_DEBUG_LEVEL */
757 if ((nRet = sched_get_priority_max(policy) ) != -1)
759 OSL_TRACE("Max Prioriy for policy '%i' == '%i'",policy,nRet);
760 g_thread.m_priority.m_Highest=nRet;
762 #if OSL_DEBUG_LEVEL > 1
763 else
765 fprintf(stderr,"failed to get max sched param [%s]\n",strerror(errno));
767 #endif /* OSL_DEBUG_LEVEL */
769 g_thread.m_priority.m_Normal =
770 (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Highest) / 2;
771 g_thread.m_priority.m_Below_Normal =
772 (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Normal) / 2;
773 g_thread.m_priority.m_Above_Normal =
774 (g_thread.m_priority.m_Normal + g_thread.m_priority.m_Highest) / 2;
776 /* @@@ set prio of calling (not main) thread (?) @@@ */
778 param.sched_priority= g_thread.m_priority.m_Normal;
780 if ((nRet = pthread_setschedparam(pthread_self(), policy, &param)) != 0)
782 OSL_TRACE("failed to change base priority of thread [%s]",strerror(nRet));
783 OSL_TRACE("Thread ID '%i', Policy '%i', Priority '%i'\n",pthread_self(),policy,param.sched_priority);
786 #endif /* NO_PTHREAD_PRIORITY */
789 /*****************************************************************************/
790 /* osl_setThreadPriority */
792 Impl-Notes: contrary to solaris-docu, which claims
793 valid priority-levels from 0 .. INT_MAX, only the
794 range 0..127 is accepted. (0 lowest, 127 highest)
796 /*****************************************************************************/
797 void SAL_CALL osl_setThreadPriority (
798 oslThread Thread,
799 oslThreadPriority Priority)
801 #ifndef NO_PTHREAD_PRIORITY
803 struct sched_param Param;
804 int policy;
805 int nRet;
807 #endif /* NO_PTHREAD_PRIORITY */
809 Thread_Impl* pImpl= (Thread_Impl*)Thread;
811 OSL_ASSERT(pImpl);
812 if (!pImpl)
813 return; /* EINVAL */
815 #ifdef NO_PTHREAD_PRIORITY
816 (void) Priority; /* unused */
817 #else /* NO_PTHREAD_PRIORITY */
819 if (pthread_getschedparam(pImpl->m_hThread, &policy, &Param) != 0)
820 return; /* ESRCH */
822 #if defined (SOLARIS)
823 if ( policy >= _SCHED_NEXT)
825 /* mfe: pthread_getschedparam on Solaris has a possible Bug */
826 /* one gets 959917873 as the policy */
827 /* so set the policy to a default one */
828 policy=SCHED_OTHER;
830 #endif /* SOLARIS */
832 pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
834 switch(Priority)
836 case osl_Thread_PriorityHighest:
837 Param.sched_priority= g_thread.m_priority.m_Highest;
838 break;
840 case osl_Thread_PriorityAboveNormal:
841 Param.sched_priority= g_thread.m_priority.m_Above_Normal;
842 break;
844 case osl_Thread_PriorityNormal:
845 Param.sched_priority= g_thread.m_priority.m_Normal;
846 break;
848 case osl_Thread_PriorityBelowNormal:
849 Param.sched_priority= g_thread.m_priority.m_Below_Normal;
850 break;
852 case osl_Thread_PriorityLowest:
853 Param.sched_priority= g_thread.m_priority.m_Lowest;
854 break;
856 case osl_Thread_PriorityUnknown:
857 OSL_ASSERT(sal_False); /* only fools try this...*/
859 /* let release-version behave friendly */
860 return;
862 default:
863 /* enum expanded, but forgotten here...*/
864 OSL_ENSURE(sal_False,"osl_setThreadPriority : unknown priority\n");
866 /* let release-version behave friendly */
867 return;
870 if ((nRet = pthread_setschedparam(pImpl->m_hThread, policy, &Param)) != 0)
872 OSL_TRACE("failed to change thread priority [%s]",strerror(nRet));
875 #endif /* NO_PTHREAD_PRIORITY */
878 /*****************************************************************************/
879 /* osl_getThreadPriority */
880 /*****************************************************************************/
881 oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
883 #ifndef NO_PTHREAD_PRIORITY
885 struct sched_param Param;
886 int Policy;
888 #endif /* NO_PTHREAD_PRIORITY */
890 oslThreadPriority Priority = osl_Thread_PriorityNormal;
891 Thread_Impl* pImpl= (Thread_Impl*)Thread;
893 OSL_ASSERT(pImpl);
894 if (!pImpl)
895 return osl_Thread_PriorityUnknown; /* EINVAL */
897 #ifndef NO_PTHREAD_PRIORITY
899 if (pthread_getschedparam(pImpl->m_hThread, &Policy, &Param) != 0)
900 return osl_Thread_PriorityUnknown; /* ESRCH */
902 pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
904 /* map pthread priority to enum */
905 if (Param.sched_priority==g_thread.m_priority.m_Highest)
907 /* 127 - highest */
908 Priority= osl_Thread_PriorityHighest;
910 else if (Param.sched_priority > g_thread.m_priority.m_Normal)
912 /* 65..126 - above normal */
913 Priority= osl_Thread_PriorityAboveNormal;
915 else if (Param.sched_priority == g_thread.m_priority.m_Normal)
917 /* normal */
918 Priority= osl_Thread_PriorityNormal;
920 else if (Param.sched_priority > g_thread.m_priority.m_Lowest)
922 /* 63..1 -below normal */
923 Priority= osl_Thread_PriorityBelowNormal;
925 else if (Param.sched_priority == g_thread.m_priority.m_Lowest)
927 /* 0 - lowest */
928 Priority= osl_Thread_PriorityLowest;
930 else
932 /* unknown */
933 Priority= osl_Thread_PriorityUnknown;
936 #endif /* NO_PTHREAD_PRIORITY */
938 return Priority;
941 typedef struct _wrapper_pthread_key
943 pthread_key_t m_key;
944 oslThreadKeyCallbackFunction pfnCallback;
945 } wrapper_pthread_key;
947 /*****************************************************************************/
948 /* osl_createThreadKey */
949 /*****************************************************************************/
950 oslThreadKey SAL_CALL osl_createThreadKey( oslThreadKeyCallbackFunction pCallback )
952 wrapper_pthread_key *pKey = (wrapper_pthread_key*)rtl_allocateMemory(sizeof(wrapper_pthread_key));
954 if (pKey)
956 pKey->pfnCallback = pCallback;
958 if (pthread_key_create(&(pKey->m_key), pKey->pfnCallback) != 0)
960 rtl_freeMemory(pKey);
961 pKey = 0;
965 return ((oslThreadKey)pKey);
968 /*****************************************************************************/
969 /* osl_destroyThreadKey */
970 /*****************************************************************************/
971 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
973 wrapper_pthread_key *pKey = (wrapper_pthread_key*)Key;
974 if (pKey)
976 pthread_key_delete(pKey->m_key);
977 rtl_freeMemory(pKey);
981 /*****************************************************************************/
982 /* osl_getThreadKeyData */
983 /*****************************************************************************/
984 void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
986 wrapper_pthread_key *pKey = (wrapper_pthread_key*)Key;
987 return pKey ? pthread_getspecific(pKey->m_key) : NULL;
990 /*****************************************************************************/
991 /* osl_setThreadKeyData */
992 /*****************************************************************************/
993 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
995 sal_Bool bRet;
996 void *pOldData = NULL;
997 wrapper_pthread_key *pKey = (wrapper_pthread_key*)Key;
998 if (!pKey)
999 return sal_False;
1001 if (pKey->pfnCallback)
1002 pOldData = pthread_getspecific(pKey->m_key);
1004 bRet = (pthread_setspecific(pKey->m_key, pData) == 0);
1006 if (bRet && pKey->pfnCallback && pOldData)
1007 pKey->pfnCallback(pOldData);
1009 return bRet;
1012 /*****************************************************************************/
1013 /* Thread Local Text Encoding */
1014 /*****************************************************************************/
1015 static void osl_thread_textencoding_init_Impl (void)
1017 rtl_TextEncoding defaultEncoding;
1018 const char * pszEncoding;
1020 /* create thread specific data key */
1021 pthread_key_create (&(g_thread.m_textencoding.m_key), NULL);
1023 /* determine default text encoding */
1024 pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING");
1025 if (pszEncoding)
1026 defaultEncoding = atoi(pszEncoding);
1027 else
1028 defaultEncoding = osl_getTextEncodingFromLocale(NULL);
1030 OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW);
1033 Tools string functions call abort() on an unknown encoding so ASCII
1034 is a meaningfull fallback regardless wether the assertion makes sense.
1037 if ( RTL_TEXTENCODING_DONTKNOW == defaultEncoding )
1038 defaultEncoding = RTL_TEXTENCODING_ASCII_US;
1040 g_thread.m_textencoding.m_default = defaultEncoding;
1043 /*****************************************************************************/
1044 /* osl_getThreadTextEncoding */
1045 /*****************************************************************************/
1046 rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding()
1048 rtl_TextEncoding threadEncoding;
1050 pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
1052 /* check for thread specific encoding, use default if not set */
1053 threadEncoding = SAL_INT_CAST(
1054 rtl_TextEncoding,
1055 (sal_uIntPtr) pthread_getspecific(g_thread.m_textencoding.m_key));
1056 if (0 == threadEncoding)
1057 threadEncoding = g_thread.m_textencoding.m_default;
1059 return threadEncoding;
1062 /*****************************************************************************/
1063 /* osl_setThreadTextEncoding */
1064 /*****************************************************************************/
1065 rtl_TextEncoding osl_setThreadTextEncoding(rtl_TextEncoding Encoding)
1067 rtl_TextEncoding oldThreadEncoding = osl_getThreadTextEncoding();
1069 /* save encoding in thread local storage */
1070 pthread_setspecific (
1071 g_thread.m_textencoding.m_key,
1072 (void*) SAL_INT_CAST(sal_uIntPtr, Encoding));
1074 return oldThreadEncoding;
1077 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */