diff options
Diffstat (limited to 'sal/osl/unx/thread.cxx')
-rw-r--r-- | sal/osl/unx/thread.cxx | 1010 |
1 files changed, 1010 insertions, 0 deletions
diff --git a/sal/osl/unx/thread.cxx b/sal/osl/unx/thread.cxx new file mode 100644 index 000000000000..fc0ff87255a5 --- /dev/null +++ b/sal/osl/unx/thread.cxx @@ -0,0 +1,1010 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include <assert.h> +#include "system.h" +#include <string.h> +#if defined(OPENBSD) +#include <sched.h> +#endif +#include <config_options.h> +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <osl/nlsupport.h> +#include <rtl/textenc.h> +#include <rtl/alloc.h> +#include <sal/macros.h> +#ifdef ANDROID +#include <jni.h> +#include <android/log.h> +#include <osl/detail/android-bootstrap.h> +#endif + +#if defined LINUX && ! defined __FreeBSD_kernel__ +#include <sys/prctl.h> +#ifndef PR_SET_NAME +#define PR_SET_NAME 15 +#endif +#endif + +/**************************************************************************** + * @@@ TODO @@@ + * + * (1) 'osl_thread_priority_init_Impl()' + * - insane assumption that initializing caller is main thread + * - use _POSIX_THREAD_PRIORITY_SCHEDULING, not NO_PTHREAD_PRIORITY (?) + * - POSIX doesn't require defined prio's for SCHED_OTHER (!) + * - use SCHED_RR instead of SCHED_OTHER for defined behaviour (?) + * (2) 'oslThreadIdentifier' and '{insert|remove|lookup}ThreadId()' + * - cannot reliably be applied to 'alien' threads; + * - memory leak for 'alien' thread 'HashEntry's; + * - use 'PTHREAD_VALUE(pthread_t)' as identifier instead (?) + * - if yes, change 'oslThreadIdentifier' to 'intptr_t' or similar + * (3) 'oslSigAlarmHandler()' (#71232#) + * - [Under Solaris we get SIGALRM in e.g. pthread_join which terminates + * the process. So we initialize our signal handling module and do + * register a SIGALRM Handler which catches and ignores it] + * - should this still happen, 'signal.c' needs to be fixed instead. + * + ****************************************************************************/ + +/*****************************************************************************/ +/* Internal data structures and functions */ +/*****************************************************************************/ + +#define THREADIMPL_FLAGS_TERMINATE 0x00001 +#define THREADIMPL_FLAGS_STARTUP 0x00002 +#define THREADIMPL_FLAGS_SUSPENDED 0x00004 +#define THREADIMPL_FLAGS_ACTIVE 0x00008 +#define THREADIMPL_FLAGS_ATTACHED 0x00010 +#define THREADIMPL_FLAGS_DESTROYED 0x00020 + +typedef struct osl_thread_impl_st +{ + pthread_t m_hThread; + sal_uInt16 m_Ident; /* @@@ see TODO @@@ */ + short m_Flags; + oslWorkerFunction m_WorkerFunction; + void* m_pData; + pthread_mutex_t m_Lock; + pthread_cond_t m_Cond; +} Thread_Impl; + +struct osl_thread_priority_st +{ + int m_Highest; + int m_Above_Normal; + int m_Normal; + int m_Below_Normal; + int m_Lowest; +}; + +#define OSL_THREAD_PRIORITY_INITIALIZER { 127, 96, 64, 32, 0 } +static void osl_thread_priority_init_Impl (void); + +struct osl_thread_textencoding_st +{ + pthread_key_t m_key; /* key to store thread local text encoding */ + rtl_TextEncoding m_default; /* the default text encoding */ +}; + +#define OSL_THREAD_TEXTENCODING_INITIALIZER { 0, RTL_TEXTENCODING_DONTKNOW } +static void osl_thread_textencoding_init_Impl (void); + +struct osl_thread_global_st +{ + pthread_once_t m_once; + struct osl_thread_priority_st m_priority; + struct osl_thread_textencoding_st m_textencoding; +}; + +static struct osl_thread_global_st g_thread = +{ + PTHREAD_ONCE_INIT, + OSL_THREAD_PRIORITY_INITIALIZER, + OSL_THREAD_TEXTENCODING_INITIALIZER +}; + +static void osl_thread_init_Impl (void); + +static Thread_Impl* osl_thread_construct_Impl (void); +static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl); + +static void* osl_thread_start_Impl (void * pData); +static void osl_thread_cleanup_Impl (Thread_Impl * pImpl); + +static oslThread osl_thread_create_Impl ( + oslWorkerFunction pWorker, void * pThreadData, short nFlags); + +/* @@@ see TODO @@@ */ +static sal_uInt16 insertThreadId (pthread_t hThread); +static sal_uInt16 lookupThreadId (pthread_t hThread); +static void removeThreadId (pthread_t hThread); + +static void osl_thread_init_Impl (void) +{ + osl_thread_priority_init_Impl(); + osl_thread_textencoding_init_Impl(); +} + +Thread_Impl* osl_thread_construct_Impl (void) +{ + Thread_Impl* pImpl = new Thread_Impl; + if (pImpl) + { + memset (pImpl, 0, sizeof(Thread_Impl)); + + pthread_mutex_init (&(pImpl->m_Lock), PTHREAD_MUTEXATTR_DEFAULT); + pthread_cond_init (&(pImpl->m_Cond), PTHREAD_CONDATTR_DEFAULT); + } + return (pImpl); +} + +static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl) +{ + OSL_ASSERT(ppImpl); + if (*ppImpl) + { + pthread_cond_destroy (&((*ppImpl)->m_Cond)); + pthread_mutex_destroy (&((*ppImpl)->m_Lock)); + + free (*ppImpl); + (*ppImpl) = 0; + } +} + +static void osl_thread_cleanup_Impl (Thread_Impl * pImpl) +{ + pthread_t thread; + bool attached; + bool destroyed; + + pthread_mutex_lock (&(pImpl->m_Lock)); + + thread = pImpl->m_hThread; + attached = (pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) != 0; + destroyed = (pImpl->m_Flags & THREADIMPL_FLAGS_DESTROYED) != 0; + pImpl->m_Flags &= ~(THREADIMPL_FLAGS_ACTIVE | THREADIMPL_FLAGS_ATTACHED); + + pthread_mutex_unlock (&(pImpl->m_Lock)); + + /* release oslThreadIdentifier @@@ see TODO @@@ */ + removeThreadId (thread); + + if (attached) + { + pthread_detach (thread); + } + + if (destroyed) + { + osl_thread_destruct_Impl (&pImpl); + } +} + +static void* osl_thread_start_Impl (void* pData) +{ + bool terminate; + Thread_Impl* pImpl= (Thread_Impl*)pData; + + assert(pImpl); + + pthread_mutex_lock (&(pImpl->m_Lock)); + + /* request oslThreadIdentifier @@@ see TODO @@@ */ + pImpl->m_Ident = insertThreadId (pImpl->m_hThread); + + /* signal change from STARTUP to ACTIVE state */ + pImpl->m_Flags &= ~THREADIMPL_FLAGS_STARTUP; + pImpl->m_Flags |= THREADIMPL_FLAGS_ACTIVE; + pthread_cond_signal (&(pImpl->m_Cond)); + + /* Check if thread is started in SUSPENDED state */ + while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* wait until SUSPENDED flag is cleared */ + pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); + } + + /* check for SUSPENDED to TERMINATE state change */ + terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0); + + pthread_mutex_unlock (&(pImpl->m_Lock)); + + if (!terminate) + { +#ifdef ANDROID + JNIEnv* env = 0; + int res = (*lo_get_javavm())->AttachCurrentThread(lo_get_javavm(), &env, NULL); + __android_log_print(ANDROID_LOG_INFO, "LibreOffice", "New sal thread started and attached res=%d", res); +#endif + /* call worker function */ + pImpl->m_WorkerFunction(pImpl->m_pData); + +#ifdef ANDROID + res = (*lo_get_javavm())->DetachCurrentThread(lo_get_javavm()); + __android_log_print(ANDROID_LOG_INFO, "LibreOffice", "Detached finished sal thread res=%d", res); +#endif + } + + osl_thread_cleanup_Impl (pImpl); + return (0); +} + +static oslThread osl_thread_create_Impl ( + oslWorkerFunction pWorker, + void* pThreadData, + short nFlags) +{ + Thread_Impl* pImpl; +#if defined OPENBSD || ((defined MACOSX || defined LINUX) && !ENABLE_RUNTIME_OPTIMIZATIONS) + pthread_attr_t attr; + size_t stacksize; +#endif + int nRet=0; + + pImpl = osl_thread_construct_Impl(); + if (!pImpl) + return (0); /* ENOMEM */ + + pImpl->m_WorkerFunction = pWorker; + pImpl->m_pData = pThreadData; + pImpl->m_Flags = nFlags | THREADIMPL_FLAGS_STARTUP; + + pthread_mutex_lock (&(pImpl->m_Lock)); + +#if defined OPENBSD || ((defined MACOSX || defined LINUX) && !ENABLE_RUNTIME_OPTIMIZATIONS) + if (pthread_attr_init(&attr) != 0) + return (0); + +#if defined OPENBSD + stacksize = 262144; +#elif defined LINUX + stacksize = 12 * 1024 * 1024; // 8MB is not enough for ASAN on x86-64 +#else + stacksize = 100 * PTHREAD_STACK_MIN; +#endif + if (pthread_attr_setstacksize(&attr, stacksize) != 0) { + pthread_attr_destroy(&attr); + return (0); + } +#endif + + if ((nRet = pthread_create ( + &(pImpl->m_hThread), +#if defined OPENBSD || ((defined MACOSX || defined LINUX) && !ENABLE_RUNTIME_OPTIMIZATIONS) + &attr, +#else + PTHREAD_ATTR_DEFAULT, +#endif + osl_thread_start_Impl, + (void*)(pImpl))) != 0) + { + OSL_TRACE("osl_thread_create_Impl(): errno: %d, %s\n", + nRet, strerror(nRet)); + + pthread_mutex_unlock (&(pImpl->m_Lock)); + osl_thread_destruct_Impl (&pImpl); + + return (0); + } + +#if defined OPENBSD || ((defined MACOSX || defined LINUX) && !ENABLE_RUNTIME_OPTIMIZATIONS) + pthread_attr_destroy(&attr); +#endif + + /* wait for change from STARTUP to ACTIVE state */ + while (pImpl->m_Flags & THREADIMPL_FLAGS_STARTUP) + { + /* wait until STARTUP flag is cleared */ + pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); + } + + pthread_mutex_unlock (&(pImpl->m_Lock)); + + return ((oslThread)(pImpl)); +} + +oslThread osl_createThread ( + oslWorkerFunction pWorker, + void * pThreadData) +{ + return osl_thread_create_Impl ( + pWorker, + pThreadData, + THREADIMPL_FLAGS_ATTACHED); +} + +oslThread osl_createSuspendedThread ( + oslWorkerFunction pWorker, + void * pThreadData) +{ + return osl_thread_create_Impl ( + pWorker, + pThreadData, + THREADIMPL_FLAGS_ATTACHED | + THREADIMPL_FLAGS_SUSPENDED ); +} + +void SAL_CALL osl_destroyThread(oslThread Thread) +{ + if (Thread != NULL) { + Thread_Impl * impl = (Thread_Impl *) Thread; + bool active; + pthread_mutex_lock(&impl->m_Lock); + active = (impl->m_Flags & THREADIMPL_FLAGS_ACTIVE) != 0; + impl->m_Flags |= THREADIMPL_FLAGS_DESTROYED; + pthread_mutex_unlock(&impl->m_Lock); + if (!active) { + osl_thread_destruct_Impl(&impl); + } + } +} + +void SAL_CALL osl_resumeThread(oslThread Thread) +{ + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return; /* EINVAL */ + + pthread_mutex_lock (&(pImpl->m_Lock)); + + if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* clear SUSPENDED flag */ + pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED; + pthread_cond_signal (&(pImpl->m_Cond)); + } + + pthread_mutex_unlock (&(pImpl->m_Lock)); +} + +void SAL_CALL osl_suspendThread(oslThread Thread) +{ + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return; /* EINVAL */ + + pthread_mutex_lock (&(pImpl->m_Lock)); + + pImpl->m_Flags |= THREADIMPL_FLAGS_SUSPENDED; + + if (pthread_equal (pthread_self(), pImpl->m_hThread)) + { + /* self suspend */ + while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* wait until SUSPENDED flag is cleared */ + pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); + } + } + + pthread_mutex_unlock (&(pImpl->m_Lock)); +} + +sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread) +{ + bool active; + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + if (!pImpl) + return sal_False; + + pthread_mutex_lock (&(pImpl->m_Lock)); + active = ((pImpl->m_Flags & THREADIMPL_FLAGS_ACTIVE) > 0); + pthread_mutex_unlock (&(pImpl->m_Lock)); + + return (active); +} + +void SAL_CALL osl_joinWithThread(oslThread Thread) +{ + pthread_t thread; + bool attached; + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + if (!pImpl) + return; + + pthread_mutex_lock (&(pImpl->m_Lock)); + + if (pthread_equal (pthread_self(), pImpl->m_hThread)) + { + /* self join */ + pthread_mutex_unlock (&(pImpl->m_Lock)); + return; /* EDEADLK */ + } + + thread = pImpl->m_hThread; + attached = ((pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) > 0); + pImpl->m_Flags &= ~THREADIMPL_FLAGS_ATTACHED; + + pthread_mutex_unlock (&(pImpl->m_Lock)); + + if (attached) + { + pthread_join (thread, NULL); + } +} + +void SAL_CALL osl_terminateThread(oslThread Thread) +{ + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return; /* EINVAL */ + + pthread_mutex_lock (&(pImpl->m_Lock)); + + if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* clear SUSPENDED flag */ + pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED; + pthread_cond_signal (&(pImpl->m_Cond)); + } + + pImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE; + + pthread_mutex_unlock (&(pImpl->m_Lock)); +} + +sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread) +{ + bool terminate; + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return sal_False; /* EINVAL */ + + OSL_ASSERT(pthread_equal (pthread_self(), pImpl->m_hThread)); + if (!(pthread_equal (pthread_self(), pImpl->m_hThread))) + return sal_False; /* EINVAL */ + + pthread_mutex_lock (&(pImpl->m_Lock)); + + while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) + { + /* wait until SUSPENDED flag is cleared */ + pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); + } + + terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0); + + pthread_mutex_unlock(&(pImpl->m_Lock)); + + return !terminate; +} + +void SAL_CALL osl_waitThread(const TimeValue* pDelay) +{ + if (pDelay) + { + struct timespec delay; + + SET_TIMESPEC(delay, pDelay->Seconds, pDelay->Nanosec); + + SLEEP_TIMESPEC(delay); + } +} + +/*****************************************************************************/ +/* osl_yieldThread */ +/* + Note that POSIX scheduling _really_ requires threads to call this + functions, since a thread only reschedules to other thread, when + it blocks (sleep, blocking I/O) OR calls sched_yield(). +*/ +/*****************************************************************************/ +void SAL_CALL osl_yieldThread() +{ + sched_yield(); +} + +void SAL_CALL osl_setThreadName(char const * name) { +#if defined LINUX && ! defined __FreeBSD_kernel__ + if (prctl(PR_SET_NAME, (unsigned long) name, 0, 0, 0) != 0) { + OSL_TRACE( + "%s prctl(PR_SET_NAME) failed with errno %d", OSL_LOG_PREFIX, + errno); + } +#else + (void) name; +#endif +} + +/*****************************************************************************/ +/* osl_getThreadIdentifier @@@ see TODO @@@ */ +/*****************************************************************************/ + +#define HASHID(x) ((unsigned int)PTHREAD_VALUE(x) % HashSize) + +typedef struct _HashEntry +{ + pthread_t Handle; + sal_uInt16 Ident; + struct _HashEntry *Next; +} HashEntry; + +static HashEntry* HashTable[31]; +static int HashSize = SAL_N_ELEMENTS(HashTable); + +static pthread_mutex_t HashLock = PTHREAD_MUTEX_INITIALIZER; + +static sal_uInt16 LastIdent = 0; + +static sal_uInt16 lookupThreadId (pthread_t hThread) +{ + HashEntry *pEntry; + + pthread_mutex_lock(&HashLock); + + pEntry = HashTable[HASHID(hThread)]; + while (pEntry != NULL) + { + if (pthread_equal(pEntry->Handle, hThread)) + { + pthread_mutex_unlock(&HashLock); + return (pEntry->Ident); + } + pEntry = pEntry->Next; + } + + pthread_mutex_unlock(&HashLock); + + return (0); +} + +static sal_uInt16 insertThreadId (pthread_t hThread) +{ + HashEntry *pEntry, *pInsert = NULL; + + pthread_mutex_lock(&HashLock); + + pEntry = HashTable[HASHID(hThread)]; + + while (pEntry != NULL) + { + if (pthread_equal(pEntry->Handle, hThread)) + break; + + pInsert = pEntry; + pEntry = pEntry->Next; + } + + if (pEntry == NULL) + { + pEntry = (HashEntry*) calloc(sizeof(HashEntry), 1); + + pEntry->Handle = hThread; + + ++ LastIdent; + + if ( LastIdent == 0 ) + LastIdent = 1; + + pEntry->Ident = LastIdent; + + if (pInsert) + pInsert->Next = pEntry; + else + HashTable[HASHID(hThread)] = pEntry; + } + + pthread_mutex_unlock(&HashLock); + + return (pEntry->Ident); +} + +static void removeThreadId (pthread_t hThread) +{ + HashEntry *pEntry, *pRemove = NULL; + + pthread_mutex_lock(&HashLock); + + pEntry = HashTable[HASHID(hThread)]; + while (pEntry != NULL) + { + if (pthread_equal(pEntry->Handle, hThread)) + break; + + pRemove = pEntry; + pEntry = pEntry->Next; + } + + if (pEntry != NULL) + { + if (pRemove) + pRemove->Next = pEntry->Next; + else + HashTable[HASHID(hThread)] = pEntry->Next; + + free(pEntry); + } + + pthread_mutex_unlock(&HashLock); +} + +oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread) +{ + Thread_Impl* pImpl= (Thread_Impl*)Thread; + sal_uInt16 Ident; + + if (pImpl) + Ident = pImpl->m_Ident; + else + { + /* current thread */ + pthread_t current = pthread_self(); + + Ident = lookupThreadId (current); + if (Ident == 0) + /* @@@ see TODO: alien pthread_self() @@@ */ + Ident = insertThreadId (current); + } + + return ((oslThreadIdentifier)(Ident)); +} + +/***************************************************************************** + @@@ see TODO @@@ + osl_thread_priority_init_Impl + + set the base-priority of the main-thread to + oslThreadPriorityNormal (64) since 0 (lowest) is + the system default. This behaviour collides with + our enum-priority definition (highest..normal..lowest). + A normaluser will expect the main-thread of an app. + to have the "normal" priority. + +*****************************************************************************/ +static void osl_thread_priority_init_Impl (void) +{ +#ifndef NO_PTHREAD_PRIORITY + struct sched_param param; + int policy=0; + int nRet=0; + +/* @@@ see TODO: calling thread may not be main thread @@@ */ + + if ((nRet = pthread_getschedparam(pthread_self(), &policy, ¶m)) != 0) + { + OSL_TRACE("failed to get priority of thread [%s]",strerror(nRet)); + return; + } + +#if defined (SOLARIS) + if ( policy >= _SCHED_NEXT) + { + /* mfe: pthread_getschedparam on Solaris has a possible Bug */ + /* one gets 959917873 as the policy */ + /* so set the policy to a default one */ + policy=SCHED_OTHER; + } +#endif /* SOLARIS */ + + if ((nRet = sched_get_priority_min(policy) ) != -1) + { + OSL_TRACE("Min Prioriy for policy '%i' == '%i'",policy,nRet); + g_thread.m_priority.m_Lowest=nRet; + } +#if OSL_DEBUG_LEVEL > 1 + else + { + fprintf(stderr,"failed to get min sched param [%s]\n",strerror(errno)); + } +#endif /* OSL_DEBUG_LEVEL */ + + if ((nRet = sched_get_priority_max(policy) ) != -1) + { + OSL_TRACE("Max Prioriy for policy '%i' == '%i'",policy,nRet); + g_thread.m_priority.m_Highest=nRet; + } +#if OSL_DEBUG_LEVEL > 1 + else + { + fprintf(stderr,"failed to get max sched param [%s]\n",strerror(errno)); + } +#endif /* OSL_DEBUG_LEVEL */ + + g_thread.m_priority.m_Normal = + (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Highest) / 2; + g_thread.m_priority.m_Below_Normal = + (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Normal) / 2; + g_thread.m_priority.m_Above_Normal = + (g_thread.m_priority.m_Normal + g_thread.m_priority.m_Highest) / 2; + +/* @@@ set prio of calling (not main) thread (?) @@@ */ + + param.sched_priority= g_thread.m_priority.m_Normal; + + if ((nRet = pthread_setschedparam(pthread_self(), policy, ¶m)) != 0) + { + OSL_TRACE("failed to change base priority of thread [%s]",strerror(nRet)); + OSL_TRACE("Thread ID '%i', Policy '%i', Priority '%i'\n",pthread_self(),policy,param.sched_priority); + } + +#endif /* NO_PTHREAD_PRIORITY */ +} + +/*****************************************************************************/ +/* osl_setThreadPriority */ +/* + Impl-Notes: contrary to solaris-docu, which claims + valid priority-levels from 0 .. INT_MAX, only the + range 0..127 is accepted. (0 lowest, 127 highest) +*/ +/*****************************************************************************/ +void SAL_CALL osl_setThreadPriority ( + oslThread Thread, + oslThreadPriority Priority) +{ +#ifndef NO_PTHREAD_PRIORITY + + struct sched_param Param; + int policy; + int nRet; + +#endif /* NO_PTHREAD_PRIORITY */ + + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return; /* EINVAL */ + +#ifdef NO_PTHREAD_PRIORITY + (void) Priority; /* unused */ +#else /* NO_PTHREAD_PRIORITY */ + + if (pthread_getschedparam(pImpl->m_hThread, &policy, &Param) != 0) + return; /* ESRCH */ + +#if defined (SOLARIS) + if ( policy >= _SCHED_NEXT) + { + /* mfe: pthread_getschedparam on Solaris has a possible Bug */ + /* one gets 959917873 as the policy */ + /* so set the policy to a default one */ + policy=SCHED_OTHER; + } +#endif /* SOLARIS */ + + pthread_once (&(g_thread.m_once), osl_thread_init_Impl); + + switch(Priority) + { + case osl_Thread_PriorityHighest: + Param.sched_priority= g_thread.m_priority.m_Highest; + break; + + case osl_Thread_PriorityAboveNormal: + Param.sched_priority= g_thread.m_priority.m_Above_Normal; + break; + + case osl_Thread_PriorityNormal: + Param.sched_priority= g_thread.m_priority.m_Normal; + break; + + case osl_Thread_PriorityBelowNormal: + Param.sched_priority= g_thread.m_priority.m_Below_Normal; + break; + + case osl_Thread_PriorityLowest: + Param.sched_priority= g_thread.m_priority.m_Lowest; + break; + + case osl_Thread_PriorityUnknown: + OSL_ASSERT(sal_False); /* only fools try this...*/ + + /* let release-version behave friendly */ + return; + + default: + /* enum expanded, but forgotten here...*/ + OSL_ENSURE(sal_False,"osl_setThreadPriority : unknown priority\n"); + + /* let release-version behave friendly */ + return; + } + + if ((nRet = pthread_setschedparam(pImpl->m_hThread, policy, &Param)) != 0) + { + OSL_TRACE("failed to change thread priority [%s]",strerror(nRet)); + } + +#endif /* NO_PTHREAD_PRIORITY */ +} + +oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread) +{ +#ifndef NO_PTHREAD_PRIORITY + + struct sched_param Param; + int Policy; + +#endif /* NO_PTHREAD_PRIORITY */ + + oslThreadPriority Priority = osl_Thread_PriorityNormal; + Thread_Impl* pImpl= (Thread_Impl*)Thread; + + OSL_ASSERT(pImpl); + if (!pImpl) + return osl_Thread_PriorityUnknown; /* EINVAL */ + +#ifndef NO_PTHREAD_PRIORITY + + if (pthread_getschedparam(pImpl->m_hThread, &Policy, &Param) != 0) + return osl_Thread_PriorityUnknown; /* ESRCH */ + + pthread_once (&(g_thread.m_once), osl_thread_init_Impl); + + /* map pthread priority to enum */ + if (Param.sched_priority==g_thread.m_priority.m_Highest) + { + /* 127 - highest */ + Priority= osl_Thread_PriorityHighest; + } + else if (Param.sched_priority > g_thread.m_priority.m_Normal) + { + /* 65..126 - above normal */ + Priority= osl_Thread_PriorityAboveNormal; + } + else if (Param.sched_priority == g_thread.m_priority.m_Normal) + { + /* normal */ + Priority= osl_Thread_PriorityNormal; + } + else if (Param.sched_priority > g_thread.m_priority.m_Lowest) + { + /* 63..1 -below normal */ + Priority= osl_Thread_PriorityBelowNormal; + } + else if (Param.sched_priority == g_thread.m_priority.m_Lowest) + { + /* 0 - lowest */ + Priority= osl_Thread_PriorityLowest; + } + else + { + /* unknown */ + Priority= osl_Thread_PriorityUnknown; + } + +#endif /* NO_PTHREAD_PRIORITY */ + + return Priority; +} + +typedef struct _wrapper_pthread_key +{ + pthread_key_t m_key; + oslThreadKeyCallbackFunction pfnCallback; +} wrapper_pthread_key; + +oslThreadKey SAL_CALL osl_createThreadKey( oslThreadKeyCallbackFunction pCallback ) +{ + wrapper_pthread_key *pKey = (wrapper_pthread_key*)rtl_allocateMemory(sizeof(wrapper_pthread_key)); + + if (pKey) + { + pKey->pfnCallback = pCallback; + + if (pthread_key_create(&(pKey->m_key), pKey->pfnCallback) != 0) + { + rtl_freeMemory(pKey); + pKey = 0; + } + } + + return ((oslThreadKey)pKey); +} + +void SAL_CALL osl_destroyThreadKey(oslThreadKey Key) +{ + wrapper_pthread_key *pKey = (wrapper_pthread_key*)Key; + if (pKey) + { + pthread_key_delete(pKey->m_key); + rtl_freeMemory(pKey); + } +} + +void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key) +{ + wrapper_pthread_key *pKey = (wrapper_pthread_key*)Key; + return pKey ? pthread_getspecific(pKey->m_key) : NULL; +} + +sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData) +{ + bool bRet; + void *pOldData = NULL; + wrapper_pthread_key *pKey = (wrapper_pthread_key*)Key; + if (!pKey) + return sal_False; + + if (pKey->pfnCallback) + pOldData = pthread_getspecific(pKey->m_key); + + bRet = (pthread_setspecific(pKey->m_key, pData) == 0); + + if (bRet && pKey->pfnCallback && pOldData) + pKey->pfnCallback(pOldData); + + return bRet; +} + +/*****************************************************************************/ +/* Thread Local Text Encoding */ +/*****************************************************************************/ +static void osl_thread_textencoding_init_Impl (void) +{ + rtl_TextEncoding defaultEncoding; + + /* create thread specific data key */ + pthread_key_create (&(g_thread.m_textencoding.m_key), NULL); + + /* determine default text encoding */ + defaultEncoding = osl_getTextEncodingFromLocale(NULL); + OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW); + + /* + Tools string functions call abort() on an unknown encoding so ASCII + is a meaningfull fallback regardless whether the assertion makes sense. + */ + + if ( RTL_TEXTENCODING_DONTKNOW == defaultEncoding ) + defaultEncoding = RTL_TEXTENCODING_ASCII_US; + + g_thread.m_textencoding.m_default = defaultEncoding; +} + +rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding() +{ + rtl_TextEncoding threadEncoding; + + pthread_once (&(g_thread.m_once), osl_thread_init_Impl); + + /* check for thread specific encoding, use default if not set */ + threadEncoding = static_cast<rtl_TextEncoding>( + (sal_uIntPtr) pthread_getspecific(g_thread.m_textencoding.m_key)); + if (0 == threadEncoding) + threadEncoding = g_thread.m_textencoding.m_default; + + return threadEncoding; +} + +rtl_TextEncoding osl_setThreadTextEncoding(rtl_TextEncoding Encoding) +{ + rtl_TextEncoding oldThreadEncoding = osl_getThreadTextEncoding(); + + /* save encoding in thread local storage */ + pthread_setspecific ( + g_thread.m_textencoding.m_key, + (void*) static_cast<sal_uIntPtr>(Encoding)); + + return oldThreadEncoding; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |