/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include "system.h" #include #include #include #include #ifndef _RTL_TEXTENC_H_ #include #endif #if defined LINUX #include #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 (void * pData); static oslThread osl_thread_create_Impl ( oslWorkerFunction pWorker, void * pThreadData, short nFlags); static void osl_thread_join_cleanup_Impl (void * opaque); static void osl_thread_wait_cleanup_Impl (void * opaque); /* @@@ see TODO @@@ */ static sal_uInt16 insertThreadId (pthread_t hThread); static sal_uInt16 lookupThreadId (pthread_t hThread); static void removeThreadId (pthread_t hThread); /*****************************************************************************/ /* osl_thread_init_Impl */ /*****************************************************************************/ static void osl_thread_init_Impl (void) { osl_thread_priority_init_Impl(); osl_thread_textencoding_init_Impl(); } /*****************************************************************************/ /* osl_thread_join_cleanup_Impl */ /*****************************************************************************/ static void osl_thread_join_cleanup_Impl (void * opaque) { pthread_t hThread = (pthread_t)(opaque); pthread_detach (hThread); } /*****************************************************************************/ /* osl_thread_wait_cleanup_Impl */ /*****************************************************************************/ static void osl_thread_wait_cleanup_Impl (void * opaque) { pthread_mutex_t * pMutex = (pthread_mutex_t*)(opaque); pthread_mutex_unlock (pMutex); } /*****************************************************************************/ /* osl_thread_construct_Impl */ /*****************************************************************************/ Thread_Impl* osl_thread_construct_Impl (void) { Thread_Impl* pImpl = malloc (sizeof(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); } /*****************************************************************************/ /* osl_thread_destruct_Impl */ /*****************************************************************************/ 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) = NULL; } } /*****************************************************************************/ /* osl_thread_cleanup_Impl */ /*****************************************************************************/ static void osl_thread_cleanup_Impl (void* pData) { pthread_t thread; int attached; int destroyed; Thread_Impl* pImpl= (Thread_Impl*)pData; 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); } } /*****************************************************************************/ /* osl_thread_start_Impl */ /*****************************************************************************/ static void* osl_thread_start_Impl (void* pData) { int terminate; Thread_Impl* pImpl= (Thread_Impl*)pData; OSL_ASSERT(pImpl); pthread_mutex_lock (&(pImpl->m_Lock)); /* install cleanup handler */ pthread_cleanup_push (osl_thread_cleanup_Impl, pData); /* 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_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock)); pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); pthread_cleanup_pop (0); } /* check for SUSPENDED to TERMINATE state change */ terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0); pthread_mutex_unlock (&(pImpl->m_Lock)); if (!terminate) { /* call worker function */ pImpl->m_WorkerFunction(pImpl->m_pData); } /* call cleanup handler and leave */ pthread_cleanup_pop (1); return (0); } /*****************************************************************************/ /* osl_thread_create_Impl */ /*****************************************************************************/ static oslThread osl_thread_create_Impl ( oslWorkerFunction pWorker, void* pThreadData, short nFlags) { Thread_Impl* pImpl; 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 ((nRet = pthread_create ( &(pImpl->m_hThread), PTHREAD_ATTR_DEFAULT, 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); } /* wait for change from STARTUP to ACTIVE state */ while (pImpl->m_Flags & THREADIMPL_FLAGS_STARTUP) { /* wait until STARTUP flag is cleared */ pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock)); pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); pthread_cleanup_pop (0); } pthread_mutex_unlock (&(pImpl->m_Lock)); return ((oslThread)(pImpl)); } /*****************************************************************************/ /* osl_createThread */ /*****************************************************************************/ oslThread osl_createThread ( oslWorkerFunction pWorker, void * pThreadData) { return osl_thread_create_Impl ( pWorker, pThreadData, THREADIMPL_FLAGS_ATTACHED); } /*****************************************************************************/ /* osl_createSuspendedThread */ /*****************************************************************************/ oslThread osl_createSuspendedThread ( oslWorkerFunction pWorker, void * pThreadData) { return osl_thread_create_Impl ( pWorker, pThreadData, THREADIMPL_FLAGS_ATTACHED | THREADIMPL_FLAGS_SUSPENDED ); } /*****************************************************************************/ /* osl_destroyThread */ /*****************************************************************************/ void SAL_CALL osl_destroyThread(oslThread Thread) { if (Thread != NULL) { Thread_Impl * impl = (Thread_Impl *) Thread; int 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); } } } /*****************************************************************************/ /* osl_resumeThread */ /*****************************************************************************/ 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)); } /*****************************************************************************/ /* osl_suspendThread */ /*****************************************************************************/ 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_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock)); pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); pthread_cleanup_pop (0); } } pthread_mutex_unlock (&(pImpl->m_Lock)); } /*****************************************************************************/ /* osl_isThreadRunning */ /*****************************************************************************/ sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread) { sal_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); } /*****************************************************************************/ /* osl_joinWithThread */ /*****************************************************************************/ void SAL_CALL osl_joinWithThread(oslThread Thread) { pthread_t thread; int 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) { /* install cleanup handler to ensure consistent flags and state */ pthread_cleanup_push ( osl_thread_join_cleanup_Impl, (void*)thread); /* join */ pthread_join (thread, NULL); /* remove cleanup handler */ pthread_cleanup_pop (0); } } /*****************************************************************************/ /* osl_terminateThread */ /*****************************************************************************/ 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)); } /*****************************************************************************/ /* osl_scheduleThread */ /*****************************************************************************/ sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread) { int 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_testcancel(); pthread_mutex_lock (&(pImpl->m_Lock)); while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED) { /* wait until SUSPENDED flag is cleared */ pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock)); pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock)); pthread_cleanup_pop (0); } terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0); pthread_mutex_unlock(&(pImpl->m_Lock)); pthread_testcancel(); return (terminate == 0); } /*****************************************************************************/ /* osl_waitThread */ /*****************************************************************************/ 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 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 = sizeof(HashTable) / sizeof(HashTable[0]); 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 normal user 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]\n",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'\n",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'\n",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]\n",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]\n",strerror(nRet)); } #endif /* NO_PTHREAD_PRIORITY */ } /*****************************************************************************/ /* osl_getThreadPriority */ /*****************************************************************************/ 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; } /*****************************************************************************/ /* osl_createThreadKey */ /*****************************************************************************/ oslThreadKey SAL_CALL osl_createThreadKey( oslThreadKeyCallbackFunction pCallback ) { pthread_key_t key; if (pthread_key_create(&key, pCallback) != 0) key = 0; return ((oslThreadKey)key); } /*****************************************************************************/ /* osl_destroyThreadKey */ /*****************************************************************************/ void SAL_CALL osl_destroyThreadKey(oslThreadKey Key) { pthread_key_delete((pthread_key_t)Key); } /*****************************************************************************/ /* osl_getThreadKeyData */ /*****************************************************************************/ void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key) { return (pthread_getspecific((pthread_key_t)Key)); } /*****************************************************************************/ /* osl_setThreadKeyData */ /*****************************************************************************/ sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData) { return (pthread_setspecific((pthread_key_t)Key, pData) == 0); } /*****************************************************************************/ /* Thread Local Text Encoding */ /*****************************************************************************/ static void osl_thread_textencoding_init_Impl (void) { rtl_TextEncoding defaultEncoding; const char * pszEncoding; /* create thread specific data key */ pthread_key_create (&(g_thread.m_textencoding.m_key), NULL); /* determine default text encoding */ pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING"); if (pszEncoding) defaultEncoding = atoi(pszEncoding); else defaultEncoding = osl_getTextEncodingFromLocale(NULL); OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW); /* Tools string functions call abort() on an unknown encoding so ASCII is a meaningful fallback regardless whether the assertion makes sense. */ if ( RTL_TEXTENCODING_DONTKNOW == defaultEncoding ) defaultEncoding = RTL_TEXTENCODING_ASCII_US; g_thread.m_textencoding.m_default = defaultEncoding; } /*****************************************************************************/ /* osl_getThreadTextEncoding */ /*****************************************************************************/ 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 = SAL_INT_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; } /*****************************************************************************/ /* osl_setThreadTextEncoding */ /*****************************************************************************/ 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*) SAL_INT_CAST(sal_uIntPtr, Encoding)); return oldThreadEncoding; }