Slightly more informative logging
[LibreOffice.git] / sal / osl / unx / thread.cxx
blob3d51f4ab2a3322e86c6cb2d2bc5e5cdeaebc985b
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 <sal/config.h>
22 #include <cassert>
23 #include <functional>
24 #include <mutex>
25 #include <unistd.h>
27 #include "system.hxx"
28 #include "unixerrnostring.hxx"
29 #include <thread_internal.hxx>
31 #include <string.h>
32 #if defined(OPENBSD)
33 #include <sched.h>
34 #endif
35 #ifdef __FreeBSD__
36 #if __FreeBSD_version <= 1201517
37 #include <pthread_np.h>
38 #define pthread_setname_np pthread_set_name_np
39 #endif
40 #endif
41 #include <config_options.h>
42 #include <o3tl/safeint.hxx>
43 #include <osl/thread.h>
44 #include <osl/nlsupport.h>
45 #include <rtl/textenc.h>
46 #include <sal/log.hxx>
47 #include <sal/macros.h>
48 #ifdef ANDROID
49 #include <jni.h>
50 #include <android/log.h>
51 #include <osl/detail/android-bootstrap.h>
52 #endif
54 #if defined LINUX && ! defined __FreeBSD_kernel__
55 #include <sys/syscall.h>
56 #endif
58 /****************************************************************************
59 * @@@ TODO @@@
61 * (1) 'osl_thread_priority_init_Impl()'
62 * - insane assumption that initializing caller is main thread
63 * - use _POSIX_THREAD_PRIORITY_SCHEDULING, not NO_PTHREAD_PRIORITY (?)
64 * - POSIX doesn't require defined prio's for SCHED_OTHER (!)
65 * - use SCHED_RR instead of SCHED_OTHER for defined behaviour (?)
66 * (2) 'oslThreadIdentifier' and '{insert|remove|lookup}ThreadId()'
67 * - cannot reliably be applied to 'alien' threads;
68 * - memory leak for 'alien' thread 'HashEntry's;
69 * - use 'reinterpret_cast<unsigned long>(pthread_t)' as identifier
70 * instead (?)
71 * - if yes, change 'oslThreadIdentifier' to 'intptr_t' or similar
72 * (3) 'oslSigAlarmHandler()' (#71232#)
73 * - [Under Solaris we get SIGALRM in e.g. pthread_join which terminates
74 * the process. So we initialize our signal handling module and do
75 * register a SIGALRM Handler which catches and ignores it]
76 * - should this still happen, 'signal.c' needs to be fixed instead.
78 ****************************************************************************/
80 #define THREADIMPL_FLAGS_TERMINATE 0x00001
81 #define THREADIMPL_FLAGS_STARTUP 0x00002
82 #define THREADIMPL_FLAGS_SUSPENDED 0x00004
83 #define THREADIMPL_FLAGS_ACTIVE 0x00008
84 #define THREADIMPL_FLAGS_ATTACHED 0x00010
85 #define THREADIMPL_FLAGS_DESTROYED 0x00020
87 namespace {
89 typedef struct osl_thread_impl_st
91 pthread_t m_hThread;
92 oslThreadIdentifier m_Ident; /* @@@ see TODO @@@ */
93 short m_Flags;
94 oslWorkerFunction m_WorkerFunction;
95 void* m_pData;
96 pthread_mutex_t m_Lock;
97 pthread_cond_t m_Cond;
98 } Thread_Impl;
100 #if !defined NO_PTHREAD_PRIORITY
101 struct osl_thread_priority_st
103 int m_Highest;
104 int m_Above_Normal;
105 int m_Normal;
106 int m_Below_Normal;
107 int m_Lowest;
109 #define OSL_THREAD_PRIORITY_INITIALIZER { 127, 96, 64, 32, 0 }
110 #endif
114 #if !defined NO_PTHREAD_PRIORITY
116 namespace {
118 struct osl_thread_global_st
120 pthread_once_t m_once;
121 struct osl_thread_priority_st m_priority;
126 static struct osl_thread_global_st g_thread =
128 PTHREAD_ONCE_INIT,
129 OSL_THREAD_PRIORITY_INITIALIZER
132 #endif // !defined NO_PTHREAD_PRIORITY
134 static Thread_Impl* osl_thread_construct_Impl();
135 static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl);
137 static void* osl_thread_start_Impl (void * pData);
138 static void osl_thread_cleanup_Impl (Thread_Impl * pImpl);
140 static oslThread osl_thread_create_Impl (
141 oslWorkerFunction pWorker, void * pThreadData, short nFlags);
143 /* @@@ see TODO @@@ */
144 static oslThreadIdentifier insertThreadId (pthread_t hThread);
145 static oslThreadIdentifier lookupThreadId (pthread_t hThread);
146 static void removeThreadId (pthread_t hThread);
148 Thread_Impl* osl_thread_construct_Impl()
150 Thread_Impl* pImpl = new Thread_Impl;
151 memset (pImpl, 0, sizeof(Thread_Impl));
153 pthread_mutex_init (&(pImpl->m_Lock), PTHREAD_MUTEXATTR_DEFAULT);
154 pthread_cond_init (&(pImpl->m_Cond), PTHREAD_CONDATTR_DEFAULT);
155 return pImpl;
158 static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl)
160 assert(ppImpl);
161 if (*ppImpl)
163 pthread_cond_destroy (&((*ppImpl)->m_Cond));
164 pthread_mutex_destroy (&((*ppImpl)->m_Lock));
166 delete *ppImpl;
167 (*ppImpl) = nullptr;
171 static void osl_thread_cleanup_Impl (Thread_Impl * pImpl)
173 pthread_t thread;
174 bool attached;
175 bool destroyed;
177 pthread_mutex_lock (&(pImpl->m_Lock));
179 thread = pImpl->m_hThread;
180 attached = (pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) != 0;
181 destroyed = (pImpl->m_Flags & THREADIMPL_FLAGS_DESTROYED) != 0;
182 pImpl->m_Flags &= ~(THREADIMPL_FLAGS_ACTIVE | THREADIMPL_FLAGS_ATTACHED);
184 pthread_mutex_unlock (&(pImpl->m_Lock));
186 /* release oslThreadIdentifier @@@ see TODO @@@ */
187 removeThreadId (thread);
189 if (attached)
191 pthread_detach (thread);
194 if (destroyed)
196 osl_thread_destruct_Impl (&pImpl);
200 static void* osl_thread_start_Impl (void* pData)
202 bool terminate;
203 Thread_Impl* pImpl= static_cast<Thread_Impl*>(pData);
205 assert(pImpl);
207 pthread_mutex_lock (&(pImpl->m_Lock));
209 /* request oslThreadIdentifier @@@ see TODO @@@ */
210 pImpl->m_Ident = insertThreadId (pImpl->m_hThread);
212 /* signal change from STARTUP to ACTIVE state */
213 pImpl->m_Flags &= ~THREADIMPL_FLAGS_STARTUP;
214 pImpl->m_Flags |= THREADIMPL_FLAGS_ACTIVE;
215 pthread_cond_signal (&(pImpl->m_Cond));
217 /* Check if thread is started in SUSPENDED state */
218 while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
220 /* wait until SUSPENDED flag is cleared */
221 pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
224 /* check for SUSPENDED to TERMINATE state change */
225 terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);
227 pthread_mutex_unlock (&(pImpl->m_Lock));
229 if (!terminate)
231 #ifdef ANDROID
232 JNIEnv* env = 0;
233 int res = (*lo_get_javavm()).AttachCurrentThread(&env, NULL);
234 __android_log_print(ANDROID_LOG_INFO, "LibreOffice", "New sal thread started and attached res=%d", res);
235 #endif
236 /* call worker function */
237 pImpl->m_WorkerFunction(pImpl->m_pData);
239 #ifdef ANDROID
240 res = (*lo_get_javavm()).DetachCurrentThread();
241 __android_log_print(ANDROID_LOG_INFO, "LibreOffice", "Detached finished sal thread res=%d", res);
242 #endif
245 osl_thread_cleanup_Impl (pImpl);
246 return nullptr;
249 static oslThread osl_thread_create_Impl (
250 oslWorkerFunction pWorker,
251 void* pThreadData,
252 short nFlags)
254 Thread_Impl* pImpl;
255 #if defined OPENBSD || defined MACOSX || (defined LINUX && !ENABLE_RUNTIME_OPTIMIZATIONS)
256 pthread_attr_t attr;
257 size_t stacksize;
258 #endif
259 int nRet=0;
261 pImpl = osl_thread_construct_Impl();
262 if (!pImpl)
263 return nullptr; /* ENOMEM */
265 pImpl->m_WorkerFunction = pWorker;
266 pImpl->m_pData = pThreadData;
267 pImpl->m_Flags = nFlags | THREADIMPL_FLAGS_STARTUP;
269 pthread_mutex_lock (&(pImpl->m_Lock));
271 #if defined OPENBSD || defined MACOSX || (defined LINUX && !ENABLE_RUNTIME_OPTIMIZATIONS)
272 if (pthread_attr_init(&attr) != 0)
273 return nullptr;
275 #if defined OPENBSD
276 stacksize = 262144;
277 #elif !ENABLE_RUNTIME_OPTIMIZATIONS
278 stacksize = 12 * 1024 * 1024; // 8MB is not enough for ASAN on x86-64
279 #else
280 stacksize = 1 * 1024 * 1024; // macOS default for non-main threads (512kB) is not enough...
281 #endif
282 if (pthread_attr_setstacksize(&attr, stacksize) != 0) {
283 pthread_attr_destroy(&attr);
284 return nullptr;
286 #endif
288 if ((nRet = pthread_create (
289 &(pImpl->m_hThread),
290 #if defined OPENBSD || defined MACOSX || (defined LINUX && !ENABLE_RUNTIME_OPTIMIZATIONS)
291 &attr,
292 #else
293 PTHREAD_ATTR_DEFAULT,
294 #endif
295 osl_thread_start_Impl,
296 static_cast<void*>(pImpl))) != 0)
298 SAL_WARN(
299 "sal.osl",
300 "pthread_create failed: " << UnixErrnoString(nRet));
302 pthread_mutex_unlock (&(pImpl->m_Lock));
303 osl_thread_destruct_Impl (&pImpl);
305 return nullptr;
308 #if defined OPENBSD || defined MACOSX || (defined LINUX && !ENABLE_RUNTIME_OPTIMIZATIONS)
309 pthread_attr_destroy(&attr);
310 #endif
312 /* wait for change from STARTUP to ACTIVE state */
313 while (pImpl->m_Flags & THREADIMPL_FLAGS_STARTUP)
315 /* wait until STARTUP flag is cleared */
316 pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
319 pthread_mutex_unlock (&(pImpl->m_Lock));
321 return static_cast<oslThread>(pImpl);
324 oslThread osl_createThread (
325 oslWorkerFunction pWorker,
326 void * pThreadData)
328 return osl_thread_create_Impl (
329 pWorker,
330 pThreadData,
331 THREADIMPL_FLAGS_ATTACHED);
334 oslThread osl_createSuspendedThread (
335 oslWorkerFunction pWorker,
336 void * pThreadData)
338 return osl_thread_create_Impl (
339 pWorker,
340 pThreadData,
341 THREADIMPL_FLAGS_ATTACHED |
342 THREADIMPL_FLAGS_SUSPENDED );
345 void SAL_CALL osl_destroyThread(oslThread Thread)
347 if (Thread != nullptr) {
348 Thread_Impl * impl = static_cast<Thread_Impl *>(Thread);
349 bool active;
350 pthread_mutex_lock(&impl->m_Lock);
351 active = (impl->m_Flags & THREADIMPL_FLAGS_ACTIVE) != 0;
352 impl->m_Flags |= THREADIMPL_FLAGS_DESTROYED;
353 pthread_mutex_unlock(&impl->m_Lock);
354 if (!active) {
355 osl_thread_destruct_Impl(&impl);
360 void SAL_CALL osl_resumeThread(oslThread Thread)
362 Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
364 if (!pImpl)
366 SAL_WARN("sal.osl", "invalid osl_resumeThread(nullptr) call");
367 return; /* EINVAL */
370 pthread_mutex_lock (&(pImpl->m_Lock));
372 if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
374 /* clear SUSPENDED flag */
375 pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
376 pthread_cond_signal (&(pImpl->m_Cond));
379 pthread_mutex_unlock (&(pImpl->m_Lock));
382 void SAL_CALL osl_suspendThread(oslThread Thread)
384 Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
386 if (!pImpl)
388 SAL_WARN("sal.osl", "invalid osl_suspendThread(nullptr) call");
389 return; /* EINVAL */
392 pthread_mutex_lock (&(pImpl->m_Lock));
394 pImpl->m_Flags |= THREADIMPL_FLAGS_SUSPENDED;
396 if (pthread_equal (pthread_self(), pImpl->m_hThread))
398 /* self suspend */
399 while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
401 /* wait until SUSPENDED flag is cleared */
402 pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
406 pthread_mutex_unlock (&(pImpl->m_Lock));
409 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
411 bool active;
412 Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
414 if (!pImpl)
415 return false;
417 pthread_mutex_lock (&(pImpl->m_Lock));
418 active = ((pImpl->m_Flags & THREADIMPL_FLAGS_ACTIVE) > 0);
419 pthread_mutex_unlock (&(pImpl->m_Lock));
421 return active;
424 void SAL_CALL osl_joinWithThread(oslThread Thread)
426 Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
428 if (!pImpl)
429 return;
431 pthread_mutex_lock (&(pImpl->m_Lock));
433 pthread_t const thread = pImpl->m_hThread;
434 bool const attached = ((pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) > 0);
436 /* check this only if *this* thread is still attached - if it's not,
437 then it could have terminated and another newly created thread could
438 have recycled the same id as m_hThread! */
439 if (attached && pthread_equal(pthread_self(), pImpl->m_hThread))
441 assert(false); /* Win32 implementation would deadlock here! */
442 /* self join */
443 pthread_mutex_unlock (&(pImpl->m_Lock));
444 return; /* EDEADLK */
447 pImpl->m_Flags &= ~THREADIMPL_FLAGS_ATTACHED;
449 pthread_mutex_unlock (&(pImpl->m_Lock));
451 if (attached)
453 pthread_join (thread, nullptr);
457 void SAL_CALL osl_terminateThread(oslThread Thread)
459 Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
461 if (!pImpl)
463 SAL_WARN("sal.osl", "invalid osl_terminateThread(nullptr) call");
464 return; /* EINVAL */
467 pthread_mutex_lock (&(pImpl->m_Lock));
469 if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
471 /* clear SUSPENDED flag */
472 pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
473 pthread_cond_signal (&(pImpl->m_Cond));
476 pImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE;
478 pthread_mutex_unlock (&(pImpl->m_Lock));
481 sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
483 bool terminate;
484 Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
486 if (!pImpl)
488 SAL_WARN("sal.osl", "invalid osl_scheduleThread(nullptr) call");
489 return false; /* EINVAL */
492 if (!(pthread_equal (pthread_self(), pImpl->m_hThread)))
494 SAL_WARN("sal.osl", "invalid osl_scheduleThread(non-self) call");
495 return false; /* EINVAL */
498 pthread_mutex_lock (&(pImpl->m_Lock));
500 while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
502 /* wait until SUSPENDED flag is cleared */
503 pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
506 terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);
508 pthread_mutex_unlock(&(pImpl->m_Lock));
510 return !terminate;
513 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
515 if (pDelay)
517 struct timespec delay;
519 SET_TIMESPEC(delay, pDelay->Seconds, pDelay->Nanosec);
521 SLEEP_TIMESPEC(delay);
525 /** Yields thread
527 @attention Note that POSIX scheduling @em really requires threads to call this
528 function, since a thread only reschedules to other thread, when
529 it blocks (sleep, blocking I/O) OR calls sched_yield().
531 void SAL_CALL osl_yieldThread()
533 sched_yield();
536 void SAL_CALL osl_setThreadName(char const * name)
538 assert( name );
539 #if defined LINUX && ! defined __FreeBSD_kernel__
540 const int LINUX_THREAD_NAME_MAXLEN = 15;
541 if ( strlen( name ) > LINUX_THREAD_NAME_MAXLEN )
542 SAL_INFO( "sal.osl", "osl_setThreadName truncated thread name to "
543 << LINUX_THREAD_NAME_MAXLEN << " chars from name '"
544 << name << "'" );
545 char shortname[ LINUX_THREAD_NAME_MAXLEN + 1 ];
546 shortname[ LINUX_THREAD_NAME_MAXLEN ] = '\0';
547 strncpy( shortname, name, LINUX_THREAD_NAME_MAXLEN );
548 int err = pthread_setname_np( pthread_self(), shortname );
549 if ( 0 != err )
550 SAL_WARN("sal.osl", "pthread_setname_np failed with errno " << err);
551 #elif defined __FreeBSD__
552 pthread_setname_np( pthread_self(), name );
553 #elif defined MACOSX || defined IOS
554 pthread_setname_np( name );
555 #else
556 (void) name;
557 #endif
560 /* osl_getThreadIdentifier @@@ see TODO @@@ */
562 namespace {
564 struct HashEntry
566 pthread_t Handle;
567 oslThreadIdentifier Ident;
568 HashEntry * Next;
573 static HashEntry* HashTable[31];
574 const int HashSize = SAL_N_ELEMENTS(HashTable);
576 static std::mutex HashLock;
578 #if ! ((defined LINUX && !defined __FreeBSD_kernel__) || defined MACOSX || defined IOS)
579 static oslThreadIdentifier LastIdent = 0;
580 #endif
582 namespace {
584 std::size_t HASHID(pthread_t x)
585 { return std::hash<pthread_t>()(x) % HashSize; }
589 static oslThreadIdentifier lookupThreadId (pthread_t hThread)
591 HashEntry *pEntry;
593 std::unique_lock aGuard(HashLock);
595 pEntry = HashTable[HASHID(hThread)];
596 while (pEntry != nullptr)
598 if (pthread_equal(pEntry->Handle, hThread))
600 return pEntry->Ident;
602 pEntry = pEntry->Next;
605 return 0;
608 static oslThreadIdentifier insertThreadId (pthread_t hThread)
610 HashEntry *pEntry, *pInsert = nullptr;
612 std::unique_lock aGuard(HashLock);
614 pEntry = HashTable[HASHID(hThread)];
616 while (pEntry != nullptr)
618 if (pthread_equal(pEntry->Handle, hThread))
619 break;
621 pInsert = pEntry;
622 pEntry = pEntry->Next;
625 if (pEntry == nullptr)
627 pEntry = static_cast<HashEntry*>(calloc(1, sizeof(HashEntry)));
629 pEntry->Handle = hThread;
631 #if defined LINUX && ! defined __FreeBSD_kernel__
632 #if defined __GLIBC__ && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 30))
633 // gettid returns a pid_t, which POSIX defines to be a signed integer type; assume that all
634 // valid pid_t values on Linux are positive (zero is filtered out in the generic code
635 // below):
636 pid_t const tid = gettid();
637 assert(tid >= 0);
638 #else
639 long const tid = syscall(SYS_gettid);
640 if (tid < 0 || o3tl::make_unsigned(tid) > std::numeric_limits<sal_uInt32>::max()) {
641 std::abort();
643 #endif
644 pEntry->Ident = tid;
645 #elif defined MACOSX || defined IOS
646 // currently the value of pthread_threadid_np is the same then
647 // syscall(SYS_thread_selfid), which returns an int as the TID.
648 // may change, as the syscall interface was deprecated.
649 uint64_t mac_tid;
650 pthread_threadid_np(nullptr, &mac_tid);
651 if (mac_tid > SAL_MAX_UINT32)
652 std::abort();
653 pEntry->Ident = mac_tid;
654 #else
655 ++LastIdent;
656 if (0 == LastIdent)
657 LastIdent = 1;
658 pEntry->Ident = LastIdent;
659 #endif
660 if (0 == pEntry->Ident)
661 std::abort();
663 if (pInsert)
664 pInsert->Next = pEntry;
665 else
666 HashTable[HASHID(hThread)] = pEntry;
669 return pEntry->Ident;
672 static void removeThreadId (pthread_t hThread)
674 HashEntry *pEntry, *pRemove = nullptr;
676 std::unique_lock aGuard(HashLock);
678 pEntry = HashTable[HASHID(hThread)];
679 while (pEntry != nullptr)
681 if (pthread_equal(pEntry->Handle, hThread))
682 break;
684 pRemove = pEntry;
685 pEntry = pEntry->Next;
688 if (pEntry != nullptr)
690 if (pRemove)
691 pRemove->Next = pEntry->Next;
692 else
693 HashTable[HASHID(hThread)] = pEntry->Next;
695 free(pEntry);
699 oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
701 Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
702 oslThreadIdentifier Ident;
704 if (pImpl)
705 Ident = pImpl->m_Ident;
706 else
708 /* current thread */
709 pthread_t current = pthread_self();
711 Ident = lookupThreadId (current);
712 if (Ident == 0)
713 /* @@@ see TODO: alien pthread_self() @@@ */
714 Ident = insertThreadId (current);
717 return Ident;
720 #ifndef NO_PTHREAD_PRIORITY
721 /*****************************************************************************
722 @@@ see TODO @@@
723 osl_thread_priority_init_Impl
725 set the base-priority of the main-thread to
726 oslThreadPriorityNormal (64) since 0 (lowest) is
727 the system default. This behaviour collides with
728 our enum-priority definition (highest..normal..lowest).
729 A normaluser will expect the main-thread of an app.
730 to have the "normal" priority.
732 *****************************************************************************/
733 static void osl_thread_priority_init_Impl()
735 struct sched_param param;
736 int policy=0;
737 int nRet=0;
739 /* @@@ see TODO: calling thread may not be main thread @@@ */
741 if ((nRet = pthread_getschedparam(pthread_self(), &policy, &param)) != 0)
743 SAL_WARN(
744 "sal.osl",
745 "pthread_getschedparam failed: " << UnixErrnoString(nRet));
746 return;
749 #if defined (__sun)
750 if ( policy >= _SCHED_NEXT)
752 /* mfe: pthread_getschedparam on Solaris has a possible Bug */
753 /* one gets 959917873 as the policy */
754 /* so set the policy to a default one */
755 policy=SCHED_OTHER;
757 #endif /* __sun */
759 if ((nRet = sched_get_priority_min(policy) ) != -1)
761 SAL_INFO(
762 "sal.osl", "Min Prioriy for policy " << policy << " == " << nRet);
763 g_thread.m_priority.m_Lowest=nRet;
765 else
767 int e = errno;
768 SAL_WARN(
769 "sal.osl",
770 "sched_get_priority_min failed: " << UnixErrnoString(e));
773 if ((nRet = sched_get_priority_max(policy) ) != -1)
775 SAL_INFO(
776 "sal.osl", "Max Prioriy for policy " << policy << " == " << nRet);
777 g_thread.m_priority.m_Highest=nRet;
779 else
781 int e = errno;
782 SAL_WARN(
783 "sal.osl",
784 "sched_get_priority_max failed: " << UnixErrnoString(e));
787 g_thread.m_priority.m_Normal =
788 (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Highest) / 2;
789 g_thread.m_priority.m_Below_Normal =
790 (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Normal) / 2;
791 g_thread.m_priority.m_Above_Normal =
792 (g_thread.m_priority.m_Normal + g_thread.m_priority.m_Highest) / 2;
794 /* @@@ set prio of calling (not main) thread (?) @@@ */
796 param.sched_priority= g_thread.m_priority.m_Normal;
798 if ((nRet = pthread_setschedparam(pthread_self(), policy, &param)) != 0)
800 SAL_WARN(
801 "sal.osl",
802 "pthread_setschedparam failed: " << UnixErrnoString(nRet));
803 SAL_INFO(
804 "sal.osl",
805 "Thread ID " << pthread_self() << ", Policy " << policy
806 << ", Priority " << param.sched_priority);
810 #endif /* NO_PTHREAD_PRIORITY */
813 Impl-Notes: contrary to solaris-docu, which claims
814 valid priority-levels from 0 .. INT_MAX, only the
815 range 0..127 is accepted. (0 lowest, 127 highest)
817 void SAL_CALL osl_setThreadPriority (
818 oslThread Thread,
819 oslThreadPriority Priority)
821 #ifndef NO_PTHREAD_PRIORITY
823 struct sched_param Param;
824 int policy;
825 int nRet;
827 #endif /* NO_PTHREAD_PRIORITY */
829 Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
831 if (!pImpl)
833 SAL_WARN("sal.osl", "invalid osl_setThreadPriority(nullptr, ...) call");
834 return; /* EINVAL */
837 #ifdef NO_PTHREAD_PRIORITY
838 (void) Priority; /* unused */
839 #else /* NO_PTHREAD_PRIORITY */
841 if (pthread_getschedparam(pImpl->m_hThread, &policy, &Param) != 0)
842 return; /* ESRCH */
844 #if defined (__sun)
845 if ( policy >= _SCHED_NEXT)
847 /* mfe: pthread_getschedparam on Solaris has a possible Bug */
848 /* one gets 959917873 as the policy */
849 /* so set the policy to a default one */
850 policy=SCHED_OTHER;
852 #endif /* __sun */
854 pthread_once (&(g_thread.m_once), osl_thread_priority_init_Impl);
856 switch(Priority)
858 case osl_Thread_PriorityHighest:
859 Param.sched_priority= g_thread.m_priority.m_Highest;
860 break;
862 case osl_Thread_PriorityAboveNormal:
863 Param.sched_priority= g_thread.m_priority.m_Above_Normal;
864 break;
866 case osl_Thread_PriorityNormal:
867 Param.sched_priority= g_thread.m_priority.m_Normal;
868 break;
870 case osl_Thread_PriorityBelowNormal:
871 Param.sched_priority= g_thread.m_priority.m_Below_Normal;
872 break;
874 case osl_Thread_PriorityLowest:
875 Param.sched_priority= g_thread.m_priority.m_Lowest;
876 break;
878 case osl_Thread_PriorityUnknown:
879 SAL_WARN(
880 "sal.osl",
881 "invalid osl_setThreadPriority(..., osl_Thread_PriorityUnknown)"
882 " call");
883 return;
885 default:
886 SAL_WARN(
887 "sal.osl",
888 "invalid osl_setThreadPriority(..., " << Priority << ") call");
889 return;
892 if ((nRet = pthread_setschedparam(pImpl->m_hThread, policy, &Param)) != 0)
894 SAL_WARN(
895 "sal.osl",
896 "pthread_setschedparam failed: " << UnixErrnoString(nRet));
899 #endif /* NO_PTHREAD_PRIORITY */
902 oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
904 #ifndef NO_PTHREAD_PRIORITY
906 struct sched_param Param;
907 int Policy;
909 #endif /* NO_PTHREAD_PRIORITY */
911 oslThreadPriority Priority = osl_Thread_PriorityNormal;
912 Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
914 if (!pImpl)
916 SAL_WARN("sal.osl", "invalid osl_getThreadPriority(nullptr) call");
917 return osl_Thread_PriorityUnknown; /* EINVAL */
920 #ifndef NO_PTHREAD_PRIORITY
922 if (pthread_getschedparam(pImpl->m_hThread, &Policy, &Param) != 0)
923 return osl_Thread_PriorityUnknown; /* ESRCH */
925 pthread_once (&(g_thread.m_once), osl_thread_priority_init_Impl);
927 /* map pthread priority to enum */
928 if (Param.sched_priority==g_thread.m_priority.m_Highest)
930 /* 127 - highest */
931 Priority= osl_Thread_PriorityHighest;
933 else if (Param.sched_priority > g_thread.m_priority.m_Normal)
935 /* 65..126 - above normal */
936 Priority= osl_Thread_PriorityAboveNormal;
938 else if (Param.sched_priority == g_thread.m_priority.m_Normal)
940 /* normal */
941 Priority= osl_Thread_PriorityNormal;
943 else if (Param.sched_priority > g_thread.m_priority.m_Lowest)
945 /* 63..1 -below normal */
946 Priority= osl_Thread_PriorityBelowNormal;
948 else if (Param.sched_priority == g_thread.m_priority.m_Lowest)
950 /* 0 - lowest */
951 Priority= osl_Thread_PriorityLowest;
953 else
955 /* unknown */
956 Priority= osl_Thread_PriorityUnknown;
959 #endif /* NO_PTHREAD_PRIORITY */
961 return Priority;
964 namespace {
966 struct wrapper_pthread_key
968 pthread_key_t m_key;
969 oslThreadKeyCallbackFunction pfnCallback;
974 oslThreadKey SAL_CALL osl_createThreadKey( oslThreadKeyCallbackFunction pCallback )
976 wrapper_pthread_key *pKey = static_cast<wrapper_pthread_key*>(malloc(sizeof(wrapper_pthread_key)));
978 if (pKey)
980 pKey->pfnCallback = pCallback;
982 if (pthread_key_create(&(pKey->m_key), pKey->pfnCallback) != 0)
984 free(pKey);
985 pKey = nullptr;
989 return static_cast<oslThreadKey>(pKey);
992 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
994 wrapper_pthread_key *pKey = static_cast<wrapper_pthread_key*>(Key);
995 if (pKey)
997 pthread_key_delete(pKey->m_key);
998 free(pKey);
1002 void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
1004 wrapper_pthread_key *pKey = static_cast<wrapper_pthread_key*>(Key);
1005 return pKey ? pthread_getspecific(pKey->m_key) : nullptr;
1008 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
1010 bool bRet;
1011 void *pOldData = nullptr;
1012 wrapper_pthread_key *pKey = static_cast<wrapper_pthread_key*>(Key);
1013 if (!pKey)
1014 return false;
1016 if (pKey->pfnCallback)
1017 pOldData = pthread_getspecific(pKey->m_key);
1019 bRet = (pthread_setspecific(pKey->m_key, pData) == 0);
1021 if (bRet && pKey->pfnCallback && pOldData)
1022 pKey->pfnCallback(pOldData);
1024 return bRet;
1027 rtl_TextEncoding getThreadTextEncodingForInitialization()
1029 /* determine default text encoding */
1030 rtl_TextEncoding defaultEncoding = osl_getTextEncodingFromLocale(nullptr);
1031 // Tools string functions call abort() on an unknown encoding so ASCII is a
1032 // meaningful fallback:
1033 if ( RTL_TEXTENCODING_DONTKNOW == defaultEncoding )
1035 SAL_WARN("sal.osl", "RTL_TEXTENCODING_DONTKNOW -> _ASCII_US");
1036 defaultEncoding = RTL_TEXTENCODING_ASCII_US;
1039 return defaultEncoding;
1042 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */