LCOV - code coverage report
Current view: top level - sal/osl/unx - thread.c (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 180 266 67.7 %
Date: 2014-04-14 Functions: 23 32 71.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      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
      36             : 
      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
      43             : 
      44             : /****************************************************************************
      45             :  * @@@ TODO @@@
      46             :  *
      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.
      62             :  *
      63             :  ****************************************************************************/
      64             : 
      65             : /*****************************************************************************/
      66             : /*  Internal data structures and functions */
      67             : /*****************************************************************************/
      68             : 
      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
      75             : 
      76             : typedef struct osl_thread_impl_st
      77             : {
      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;
      86             : 
      87             : struct osl_thread_priority_st
      88             : {
      89             :     int m_Highest;
      90             :     int m_Above_Normal;
      91             :     int m_Normal;
      92             :     int m_Below_Normal;
      93             :     int m_Lowest;
      94             : };
      95             : 
      96             : #define OSL_THREAD_PRIORITY_INITIALIZER { 127, 96, 64, 32, 0 }
      97             : static void osl_thread_priority_init_Impl (void);
      98             : 
      99             : struct osl_thread_textencoding_st
     100             : {
     101             :     pthread_key_t    m_key;     /* key to store thread local text encoding */
     102             :     rtl_TextEncoding m_default; /* the default text encoding */
     103             : };
     104             : 
     105             : #define OSL_THREAD_TEXTENCODING_INITIALIZER { 0, RTL_TEXTENCODING_DONTKNOW }
     106             : static void osl_thread_textencoding_init_Impl (void);
     107             : 
     108             : struct osl_thread_global_st
     109             : {
     110             :     pthread_once_t                    m_once;
     111             :     struct osl_thread_priority_st     m_priority;
     112             :     struct osl_thread_textencoding_st m_textencoding;
     113             : };
     114             : 
     115             : static struct osl_thread_global_st g_thread =
     116             : {
     117             :     PTHREAD_ONCE_INIT,
     118             :     OSL_THREAD_PRIORITY_INITIALIZER,
     119             :     OSL_THREAD_TEXTENCODING_INITIALIZER
     120             : };
     121             : 
     122             : static void osl_thread_init_Impl (void);
     123             : 
     124             : static Thread_Impl* osl_thread_construct_Impl (void);
     125             : static void         osl_thread_destruct_Impl (Thread_Impl ** ppImpl);
     126             : 
     127             : static void* osl_thread_start_Impl (void * pData);
     128             : static void  osl_thread_cleanup_Impl (Thread_Impl * pImpl);
     129             : 
     130             : static oslThread osl_thread_create_Impl (
     131             :     oslWorkerFunction pWorker, void * pThreadData, short nFlags);
     132             : 
     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);
     137             : 
     138       85011 : static void osl_thread_init_Impl (void)
     139             : {
     140       85011 :     osl_thread_priority_init_Impl();
     141       85011 :     osl_thread_textencoding_init_Impl();
     142       85011 : }
     143             : 
     144       85015 : Thread_Impl* osl_thread_construct_Impl (void)
     145             : {
     146       85015 :     Thread_Impl* pImpl = malloc (sizeof(Thread_Impl));
     147       85015 :     if (pImpl)
     148             :     {
     149       85015 :         memset (pImpl, 0, sizeof(Thread_Impl));
     150             : 
     151       85015 :         pthread_mutex_init (&(pImpl->m_Lock), PTHREAD_MUTEXATTR_DEFAULT);
     152       85015 :         pthread_cond_init  (&(pImpl->m_Cond), PTHREAD_CONDATTR_DEFAULT);
     153             :     }
     154       85015 :     return (pImpl);
     155             : }
     156             : 
     157       85000 : static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl)
     158             : {
     159             :     OSL_ASSERT(ppImpl);
     160       85000 :     if (*ppImpl)
     161             :     {
     162       85000 :         pthread_cond_destroy  (&((*ppImpl)->m_Cond));
     163       85000 :         pthread_mutex_destroy (&((*ppImpl)->m_Lock));
     164             : 
     165       85000 :         free (*ppImpl);
     166       85000 :         (*ppImpl) = 0;
     167             :     }
     168       85000 : }
     169             : 
     170       85003 : static void osl_thread_cleanup_Impl (Thread_Impl * pImpl)
     171             : {
     172             :     pthread_t thread;
     173             :     int attached;
     174             :     int destroyed;
     175             : 
     176       85003 :     pthread_mutex_lock (&(pImpl->m_Lock));
     177             : 
     178       85003 :     thread = pImpl->m_hThread;
     179       85003 :     attached = (pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) != 0;
     180       85003 :     destroyed = (pImpl->m_Flags & THREADIMPL_FLAGS_DESTROYED) != 0;
     181       85003 :     pImpl->m_Flags &= ~(THREADIMPL_FLAGS_ACTIVE | THREADIMPL_FLAGS_ATTACHED);
     182             : 
     183       85003 :     pthread_mutex_unlock (&(pImpl->m_Lock));
     184             : 
     185             :     /* release oslThreadIdentifier @@@ see TODO @@@ */
     186       85003 :     removeThreadId (thread);
     187             : 
     188       85001 :     if (attached)
     189             :     {
     190       85000 :         pthread_detach (thread);
     191             :     }
     192             : 
     193       85001 :     if (destroyed)
     194             :     {
     195       84999 :         osl_thread_destruct_Impl (&pImpl);
     196             :     }
     197       85000 : }
     198             : 
     199       85015 : static void* osl_thread_start_Impl (void* pData)
     200             : {
     201             :     int terminate;
     202       85015 :     Thread_Impl* pImpl= (Thread_Impl*)pData;
     203             : 
     204             :     OSL_ASSERT(pImpl);
     205             : 
     206       85015 :     pthread_mutex_lock (&(pImpl->m_Lock));
     207             : 
     208             :     /* request oslThreadIdentifier @@@ see TODO @@@ */
     209       85015 :     pImpl->m_Ident = insertThreadId (pImpl->m_hThread);
     210             : 
     211             :     /* signal change from STARTUP to ACTIVE state */
     212       85015 :     pImpl->m_Flags &= ~THREADIMPL_FLAGS_STARTUP;
     213       85015 :     pImpl->m_Flags |=  THREADIMPL_FLAGS_ACTIVE;
     214       85015 :     pthread_cond_signal (&(pImpl->m_Cond));
     215             : 
     216             :     /* Check if thread is started in SUSPENDED state */
     217      170033 :     while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
     218             :     {
     219             :         /* wait until SUSPENDED flag is cleared */
     220           3 :         pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
     221             :     }
     222             : 
     223             :     /* check for SUSPENDED to TERMINATE state change */
     224       85015 :     terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);
     225             : 
     226       85015 :     pthread_mutex_unlock (&(pImpl->m_Lock));
     227             : 
     228       85015 :     if (!terminate)
     229             :     {
     230             : #ifdef ANDROID
     231             :         JNIEnv* env = 0;
     232             :         int res = (*lo_get_javavm())->AttachCurrentThread(lo_get_javavm(), &env, NULL);
     233             :         __android_log_print(ANDROID_LOG_INFO, "LibreOffice", "New sal thread started and attached res=%d", res);
     234             : #endif
     235             :         /* call worker function */
     236       85015 :         pImpl->m_WorkerFunction(pImpl->m_pData);
     237             : 
     238             : #ifdef ANDROID
     239             :         res = (*lo_get_javavm())->DetachCurrentThread(lo_get_javavm());
     240             :         __android_log_print(ANDROID_LOG_INFO, "LibreOffice", "Detached finished sal thread res=%d", res);
     241             : #endif
     242             :     }
     243             : 
     244       85003 :     osl_thread_cleanup_Impl (pImpl);
     245       85000 :     return (0);
     246             : }
     247             : 
     248       85015 : static oslThread osl_thread_create_Impl (
     249             :     oslWorkerFunction pWorker,
     250             :     void*             pThreadData,
     251             :     short             nFlags)
     252             : {
     253             :     Thread_Impl* pImpl;
     254             : #if defined(OPENBSD)
     255             :     pthread_attr_t attr;
     256             : #endif
     257       85015 :     int nRet=0;
     258             : 
     259       85015 :     pImpl = osl_thread_construct_Impl();
     260       85015 :     if (!pImpl)
     261           0 :         return (0); /* ENOMEM */
     262             : 
     263       85015 :     pImpl->m_WorkerFunction = pWorker;
     264       85015 :     pImpl->m_pData = pThreadData;
     265       85015 :     pImpl->m_Flags = nFlags | THREADIMPL_FLAGS_STARTUP;
     266             : 
     267       85015 :     pthread_mutex_lock (&(pImpl->m_Lock));
     268             : 
     269             : #if defined(OPENBSD)
     270             :     if (pthread_attr_init(&attr) != 0)
     271             :         return (0);
     272             : 
     273             :     if (pthread_attr_setstacksize(&attr, 262144) != 0) {
     274             :         pthread_attr_destroy(&attr);
     275             :         return (0);
     276             :     }
     277             : #endif
     278             : 
     279      170030 :     if ((nRet = pthread_create (
     280       85015 :         &(pImpl->m_hThread),
     281             : #if defined(OPENBSD)
     282             :         &attr,
     283             : #else
     284             :         PTHREAD_ATTR_DEFAULT,
     285             : #endif
     286             :         osl_thread_start_Impl,
     287             :         (void*)(pImpl))) != 0)
     288             :     {
     289             :         OSL_TRACE("osl_thread_create_Impl(): errno: %d, %s\n",
     290             :                   nRet, strerror(nRet));
     291             : 
     292           0 :         pthread_mutex_unlock (&(pImpl->m_Lock));
     293           0 :         osl_thread_destruct_Impl (&pImpl);
     294             : 
     295           0 :         return (0);
     296             :     }
     297             : 
     298             : #if defined(OPENBSD)
     299             :     pthread_attr_destroy(&attr);
     300             : #endif
     301             : 
     302             :     /* wait for change from STARTUP to ACTIVE state */
     303      255045 :     while (pImpl->m_Flags & THREADIMPL_FLAGS_STARTUP)
     304             :     {
     305             :         /* wait until STARTUP flag is cleared */
     306       85015 :         pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
     307             :     }
     308             : 
     309       85015 :     pthread_mutex_unlock (&(pImpl->m_Lock));
     310             : 
     311       85015 :     return ((oslThread)(pImpl));
     312             : }
     313             : 
     314       85012 : oslThread osl_createThread (
     315             :     oslWorkerFunction pWorker,
     316             :     void *            pThreadData)
     317             : {
     318       85012 :     return osl_thread_create_Impl (
     319             :         pWorker,
     320             :         pThreadData,
     321             :         THREADIMPL_FLAGS_ATTACHED);
     322             : }
     323             : 
     324           3 : oslThread osl_createSuspendedThread (
     325             :     oslWorkerFunction pWorker,
     326             :     void *            pThreadData)
     327             : {
     328           3 :     return osl_thread_create_Impl (
     329             :         pWorker,
     330             :         pThreadData,
     331             :         THREADIMPL_FLAGS_ATTACHED |
     332             :         THREADIMPL_FLAGS_SUSPENDED );
     333             : }
     334             : 
     335       85016 : void SAL_CALL osl_destroyThread(oslThread Thread)
     336             : {
     337       85016 :     if (Thread != NULL) {
     338       85015 :         Thread_Impl * impl = (Thread_Impl *) Thread;
     339             :         int active;
     340       85015 :         pthread_mutex_lock(&impl->m_Lock);
     341       85015 :         active = (impl->m_Flags & THREADIMPL_FLAGS_ACTIVE) != 0;
     342       85015 :         impl->m_Flags |= THREADIMPL_FLAGS_DESTROYED;
     343       85015 :         pthread_mutex_unlock(&impl->m_Lock);
     344       85015 :         if (!active) {
     345           2 :             osl_thread_destruct_Impl(&impl);
     346             :         }
     347             :     }
     348       85016 : }
     349             : 
     350           3 : void SAL_CALL osl_resumeThread(oslThread Thread)
     351             : {
     352           3 :     Thread_Impl* pImpl= (Thread_Impl*)Thread;
     353             : 
     354             :     OSL_ASSERT(pImpl);
     355           3 :     if (!pImpl)
     356           3 :         return; /* EINVAL */
     357             : 
     358           3 :     pthread_mutex_lock (&(pImpl->m_Lock));
     359             : 
     360           3 :     if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
     361             :     {
     362             :         /* clear SUSPENDED flag */
     363           3 :         pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
     364           3 :         pthread_cond_signal (&(pImpl->m_Cond));
     365             :     }
     366             : 
     367           3 :     pthread_mutex_unlock (&(pImpl->m_Lock));
     368             : }
     369             : 
     370           0 : void SAL_CALL osl_suspendThread(oslThread Thread)
     371             : {
     372           0 :     Thread_Impl* pImpl= (Thread_Impl*)Thread;
     373             : 
     374             :     OSL_ASSERT(pImpl);
     375           0 :     if (!pImpl)
     376           0 :         return; /* EINVAL */
     377             : 
     378           0 :     pthread_mutex_lock (&(pImpl->m_Lock));
     379             : 
     380           0 :     pImpl->m_Flags |= THREADIMPL_FLAGS_SUSPENDED;
     381             : 
     382           0 :     if (pthread_equal (pthread_self(), pImpl->m_hThread))
     383             :     {
     384             :         /* self suspend */
     385           0 :         while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
     386             :         {
     387             :             /* wait until SUSPENDED flag is cleared */
     388           0 :             pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
     389             :         }
     390             :     }
     391             : 
     392           0 :     pthread_mutex_unlock (&(pImpl->m_Lock));
     393             : }
     394             : 
     395           0 : sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
     396             : {
     397             :     sal_Bool active;
     398           0 :     Thread_Impl* pImpl= (Thread_Impl*)Thread;
     399             : 
     400           0 :     if (!pImpl)
     401           0 :         return sal_False;
     402             : 
     403           0 :     pthread_mutex_lock (&(pImpl->m_Lock));
     404           0 :     active = ((pImpl->m_Flags & THREADIMPL_FLAGS_ACTIVE) > 0);
     405           0 :     pthread_mutex_unlock (&(pImpl->m_Lock));
     406             : 
     407           0 :     return (active);
     408             : }
     409             : 
     410           2 : void SAL_CALL osl_joinWithThread(oslThread Thread)
     411             : {
     412             :     pthread_t thread;
     413             :     int attached;
     414           2 :     Thread_Impl* pImpl= (Thread_Impl*)Thread;
     415             : 
     416           2 :     if (!pImpl)
     417           0 :         return;
     418             : 
     419           2 :     pthread_mutex_lock (&(pImpl->m_Lock));
     420             : 
     421           2 :     if (pthread_equal (pthread_self(), pImpl->m_hThread))
     422             :     {
     423             :         /* self join */
     424           0 :         pthread_mutex_unlock (&(pImpl->m_Lock));
     425           0 :         return; /* EDEADLK */
     426             :     }
     427             : 
     428           2 :     thread = pImpl->m_hThread;
     429           2 :     attached = ((pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) > 0);
     430           2 :     pImpl->m_Flags &= ~THREADIMPL_FLAGS_ATTACHED;
     431             : 
     432           2 :     pthread_mutex_unlock (&(pImpl->m_Lock));
     433             : 
     434           2 :     if (attached)
     435             :     {
     436           1 :         pthread_join (thread, NULL);
     437             :     }
     438             : }
     439             : 
     440           0 : void SAL_CALL osl_terminateThread(oslThread Thread)
     441             : {
     442           0 :     Thread_Impl* pImpl= (Thread_Impl*)Thread;
     443             : 
     444             :     OSL_ASSERT(pImpl);
     445           0 :     if (!pImpl)
     446           0 :         return; /* EINVAL */
     447             : 
     448           0 :     pthread_mutex_lock (&(pImpl->m_Lock));
     449             : 
     450           0 :     if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
     451             :     {
     452             :         /* clear SUSPENDED flag */
     453           0 :         pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
     454           0 :         pthread_cond_signal (&(pImpl->m_Cond));
     455             :     }
     456             : 
     457           0 :     pImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE;
     458             : 
     459           0 :     pthread_mutex_unlock (&(pImpl->m_Lock));
     460             : }
     461             : 
     462           0 : sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
     463             : {
     464             :     int terminate;
     465           0 :     Thread_Impl* pImpl= (Thread_Impl*)Thread;
     466             : 
     467             :     OSL_ASSERT(pImpl);
     468           0 :     if (!pImpl)
     469           0 :         return sal_False; /* EINVAL */
     470             : 
     471             :     OSL_ASSERT(pthread_equal (pthread_self(), pImpl->m_hThread));
     472           0 :     if (!(pthread_equal (pthread_self(), pImpl->m_hThread)))
     473           0 :         return sal_False; /* EINVAL */
     474             : 
     475           0 :     pthread_mutex_lock (&(pImpl->m_Lock));
     476             : 
     477           0 :     while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
     478             :     {
     479             :         /* wait until SUSPENDED flag is cleared */
     480           0 :         pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
     481             :     }
     482             : 
     483           0 :     terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);
     484             : 
     485           0 :     pthread_mutex_unlock(&(pImpl->m_Lock));
     486             : 
     487           0 :     return (terminate == 0);
     488             : }
     489             : 
     490           0 : void SAL_CALL osl_waitThread(const TimeValue* pDelay)
     491             : {
     492           0 :     if (pDelay)
     493             :     {
     494             :         struct timespec delay;
     495             : 
     496           0 :         SET_TIMESPEC(delay, pDelay->Seconds, pDelay->Nanosec);
     497             : 
     498           0 :         SLEEP_TIMESPEC(delay);
     499             :     }
     500           0 : }
     501             : 
     502             : /*****************************************************************************/
     503             : /* osl_yieldThread */
     504             : /*
     505             :     Note that POSIX scheduling _really_ requires threads to call this
     506             :     functions, since a thread only reschedules to other thread, when
     507             :     it blocks (sleep, blocking I/O) OR calls sched_yield().
     508             : */
     509             : /*****************************************************************************/
     510           0 : void SAL_CALL osl_yieldThread()
     511             : {
     512           0 :     sched_yield();
     513           0 : }
     514             : 
     515       85014 : void SAL_CALL osl_setThreadName(char const * name) {
     516             : #if defined LINUX && ! defined __FreeBSD_kernel__
     517       85014 :     if (prctl(PR_SET_NAME, (unsigned long) name, 0, 0, 0) != 0) {
     518             :         OSL_TRACE(
     519             :             "%s prctl(PR_SET_NAME) failed with errno %d", OSL_LOG_PREFIX,
     520             :             errno);
     521             :     }
     522             : #else
     523             :     (void) name;
     524             : #endif
     525       85014 : }
     526             : 
     527             : /*****************************************************************************/
     528             : /* osl_getThreadIdentifier @@@ see TODO @@@ */
     529             : /*****************************************************************************/
     530             : 
     531             : #define HASHID(x) ((unsigned int)PTHREAD_VALUE(x) % HashSize)
     532             : 
     533             : typedef struct _HashEntry
     534             : {
     535             :     pthread_t         Handle;
     536             :     sal_uInt16        Ident;
     537             :     struct _HashEntry *Next;
     538             : } HashEntry;
     539             : 
     540             : static HashEntry* HashTable[31];
     541             : static int HashSize = SAL_N_ELEMENTS(HashTable);
     542             : 
     543             : static pthread_mutex_t HashLock = PTHREAD_MUTEX_INITIALIZER;
     544             : 
     545             : static sal_uInt16 LastIdent = 0;
     546             : 
     547         138 : static sal_uInt16 lookupThreadId (pthread_t hThread)
     548             : {
     549             :     HashEntry *pEntry;
     550             : 
     551         138 :     pthread_mutex_lock(&HashLock);
     552             : 
     553         138 :         pEntry = HashTable[HASHID(hThread)];
     554         276 :         while (pEntry != NULL)
     555             :         {
     556         137 :             if (pthread_equal(pEntry->Handle, hThread))
     557             :             {
     558         137 :                 pthread_mutex_unlock(&HashLock);
     559         137 :                 return (pEntry->Ident);
     560             :             }
     561           0 :             pEntry = pEntry->Next;
     562             :         }
     563             : 
     564           1 :     pthread_mutex_unlock(&HashLock);
     565             : 
     566           1 :     return (0);
     567             : }
     568             : 
     569       85016 : static sal_uInt16 insertThreadId (pthread_t hThread)
     570             : {
     571       85016 :     HashEntry *pEntry, *pInsert = NULL;
     572             : 
     573       85016 :     pthread_mutex_lock(&HashLock);
     574             : 
     575       85016 :     pEntry = HashTable[HASHID(hThread)];
     576             : 
     577      170032 :     while (pEntry != NULL)
     578             :     {
     579           0 :         if (pthread_equal(pEntry->Handle, hThread))
     580           0 :             break;
     581             : 
     582           0 :         pInsert = pEntry;
     583           0 :         pEntry = pEntry->Next;
     584             :     }
     585             : 
     586       85016 :     if (pEntry == NULL)
     587             :     {
     588       85016 :         pEntry = (HashEntry*) calloc(sizeof(HashEntry), 1);
     589             : 
     590       85016 :         pEntry->Handle = hThread;
     591             : 
     592       85016 :         ++ LastIdent;
     593             : 
     594       85016 :         if ( LastIdent == 0 )
     595           0 :             LastIdent = 1;
     596             : 
     597       85016 :         pEntry->Ident  = LastIdent;
     598             : 
     599       85016 :         if (pInsert)
     600           0 :             pInsert->Next = pEntry;
     601             :         else
     602       85016 :             HashTable[HASHID(hThread)] = pEntry;
     603             :     }
     604             : 
     605       85016 :     pthread_mutex_unlock(&HashLock);
     606             : 
     607       85016 :     return (pEntry->Ident);
     608             : }
     609             : 
     610       85003 : static void removeThreadId (pthread_t hThread)
     611             : {
     612       85003 :     HashEntry *pEntry, *pRemove = NULL;
     613             : 
     614       85003 :     pthread_mutex_lock(&HashLock);
     615             : 
     616       85003 :     pEntry = HashTable[HASHID(hThread)];
     617      170006 :     while (pEntry != NULL)
     618             :     {
     619       85003 :         if (pthread_equal(pEntry->Handle, hThread))
     620       85002 :             break;
     621             : 
     622           0 :         pRemove = pEntry;
     623           0 :         pEntry = pEntry->Next;
     624             :     }
     625             : 
     626       85002 :     if (pEntry != NULL)
     627             :     {
     628       85001 :         if (pRemove)
     629           0 :             pRemove->Next = pEntry->Next;
     630             :         else
     631       85002 :             HashTable[HASHID(hThread)] = pEntry->Next;
     632             : 
     633       85001 :         free(pEntry);
     634             :     }
     635             : 
     636       85002 :     pthread_mutex_unlock(&HashLock);
     637       85001 : }
     638             : 
     639         138 : oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
     640             : {
     641         138 :     Thread_Impl* pImpl= (Thread_Impl*)Thread;
     642             :     sal_uInt16   Ident;
     643             : 
     644         138 :     if (pImpl)
     645           0 :         Ident = pImpl->m_Ident;
     646             :     else
     647             :     {
     648             :         /* current thread */
     649         138 :         pthread_t current = pthread_self();
     650             : 
     651         138 :         Ident = lookupThreadId (current);
     652         138 :         if (Ident == 0)
     653             :             /* @@@ see TODO: alien pthread_self() @@@ */
     654           1 :             Ident = insertThreadId (current);
     655             :     }
     656             : 
     657         138 :     return ((oslThreadIdentifier)(Ident));
     658             : }
     659             : 
     660             : /*****************************************************************************
     661             :     @@@ see TODO @@@
     662             :     osl_thread_priority_init_Impl
     663             : 
     664             :     set the base-priority of the main-thread to
     665             :     oslThreadPriorityNormal (64) since 0 (lowest) is
     666             :     the system default. This behaviour collides with
     667             :     our enum-priority definition (highest..normal..lowest).
     668             :     A  normaluser will expect the main-thread of an app.
     669             :     to have the "normal" priority.
     670             : 
     671             : *****************************************************************************/
     672       85011 : static void osl_thread_priority_init_Impl (void)
     673             : {
     674             : #ifndef NO_PTHREAD_PRIORITY
     675             :     struct sched_param param;
     676             :     int policy=0;
     677             :     int nRet=0;
     678             : 
     679             : /* @@@ see TODO: calling thread may not be main thread @@@ */
     680             : 
     681             :     if ((nRet = pthread_getschedparam(pthread_self(), &policy, &param)) != 0)
     682             :     {
     683             :         OSL_TRACE("failed to get priority of thread [%s]",strerror(nRet));
     684             :         return;
     685             :     }
     686             : 
     687             : #if defined (SOLARIS)
     688             :     if ( policy >= _SCHED_NEXT)
     689             :     {
     690             :         /* mfe: pthread_getschedparam on Solaris has a possible Bug */
     691             :         /*      one gets 959917873 as the policy                    */
     692             :         /*      so set the policy to a default one                  */
     693             :         policy=SCHED_OTHER;
     694             :     }
     695             : #endif /* SOLARIS */
     696             : 
     697             :     if ((nRet = sched_get_priority_min(policy) ) != -1)
     698             :     {
     699             :         OSL_TRACE("Min Prioriy for policy '%i' == '%i'",policy,nRet);
     700             :         g_thread.m_priority.m_Lowest=nRet;
     701             :     }
     702             : #if OSL_DEBUG_LEVEL > 1
     703             :     else
     704             :     {
     705             :         fprintf(stderr,"failed to get min sched param [%s]\n",strerror(errno));
     706             :     }
     707             : #endif /* OSL_DEBUG_LEVEL */
     708             : 
     709             :     if ((nRet = sched_get_priority_max(policy) ) != -1)
     710             :     {
     711             :         OSL_TRACE("Max Prioriy for policy '%i' == '%i'",policy,nRet);
     712             :         g_thread.m_priority.m_Highest=nRet;
     713             :     }
     714             : #if OSL_DEBUG_LEVEL > 1
     715             :     else
     716             :     {
     717             :         fprintf(stderr,"failed to get max sched param [%s]\n",strerror(errno));
     718             :     }
     719             : #endif /* OSL_DEBUG_LEVEL */
     720             : 
     721             :     g_thread.m_priority.m_Normal =
     722             :         (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Highest) / 2;
     723             :     g_thread.m_priority.m_Below_Normal =
     724             :         (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Normal)  / 2;
     725             :     g_thread.m_priority.m_Above_Normal =
     726             :         (g_thread.m_priority.m_Normal + g_thread.m_priority.m_Highest) / 2;
     727             : 
     728             : /* @@@ set prio of calling (not main) thread (?) @@@ */
     729             : 
     730             :     param.sched_priority= g_thread.m_priority.m_Normal;
     731             : 
     732             :     if ((nRet = pthread_setschedparam(pthread_self(), policy, &param)) != 0)
     733             :     {
     734             :         OSL_TRACE("failed to change base priority of thread [%s]",strerror(nRet));
     735             :         OSL_TRACE("Thread ID '%i', Policy '%i', Priority '%i'\n",pthread_self(),policy,param.sched_priority);
     736             :     }
     737             : 
     738             : #endif /* NO_PTHREAD_PRIORITY */
     739       85011 : }
     740             : 
     741             : /*****************************************************************************/
     742             : /* osl_setThreadPriority */
     743             : /*
     744             :     Impl-Notes: contrary to solaris-docu, which claims
     745             :     valid priority-levels from 0 .. INT_MAX, only the
     746             :     range 0..127 is accepted. (0 lowest, 127 highest)
     747             : */
     748             : /*****************************************************************************/
     749           0 : void SAL_CALL osl_setThreadPriority (
     750             :     oslThread         Thread,
     751             :     oslThreadPriority Priority)
     752             : {
     753             : #ifndef NO_PTHREAD_PRIORITY
     754             : 
     755             :     struct sched_param Param;
     756             :     int policy;
     757             :     int nRet;
     758             : 
     759             : #endif /* NO_PTHREAD_PRIORITY */
     760             : 
     761           0 :     Thread_Impl* pImpl= (Thread_Impl*)Thread;
     762             : 
     763             :     OSL_ASSERT(pImpl);
     764           0 :     if (!pImpl)
     765           0 :         return; /* EINVAL */
     766             : 
     767             : #ifdef NO_PTHREAD_PRIORITY
     768             :     (void) Priority; /* unused */
     769             : #else /* NO_PTHREAD_PRIORITY */
     770             : 
     771             :     if (pthread_getschedparam(pImpl->m_hThread, &policy, &Param) != 0)
     772             :         return; /* ESRCH */
     773             : 
     774             : #if defined (SOLARIS)
     775             :     if ( policy >= _SCHED_NEXT)
     776             :     {
     777             :         /* mfe: pthread_getschedparam on Solaris has a possible Bug */
     778             :         /*      one gets 959917873 as the policy                   */
     779             :         /*      so set the policy to a default one                 */
     780             :         policy=SCHED_OTHER;
     781             :     }
     782             : #endif /* SOLARIS */
     783             : 
     784             :     pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
     785             : 
     786             :     switch(Priority)
     787             :     {
     788             :         case osl_Thread_PriorityHighest:
     789             :             Param.sched_priority= g_thread.m_priority.m_Highest;
     790             :             break;
     791             : 
     792             :         case osl_Thread_PriorityAboveNormal:
     793             :             Param.sched_priority= g_thread.m_priority.m_Above_Normal;
     794             :             break;
     795             : 
     796             :         case osl_Thread_PriorityNormal:
     797             :             Param.sched_priority= g_thread.m_priority.m_Normal;
     798             :             break;
     799             : 
     800             :         case osl_Thread_PriorityBelowNormal:
     801             :             Param.sched_priority= g_thread.m_priority.m_Below_Normal;
     802             :             break;
     803             : 
     804             :         case osl_Thread_PriorityLowest:
     805             :             Param.sched_priority= g_thread.m_priority.m_Lowest;
     806             :             break;
     807             : 
     808             :         case osl_Thread_PriorityUnknown:
     809             :             OSL_ASSERT(sal_False);      /* only fools try this...*/
     810             : 
     811             :             /* let release-version behave friendly */
     812             :             return;
     813             : 
     814             :         default:
     815             :             /* enum expanded, but forgotten here...*/
     816             :             OSL_ENSURE(sal_False,"osl_setThreadPriority : unknown priority\n");
     817             : 
     818             :             /* let release-version behave friendly */
     819             :             return;
     820             :     }
     821             : 
     822             :     if ((nRet = pthread_setschedparam(pImpl->m_hThread, policy, &Param)) != 0)
     823             :     {
     824             :         OSL_TRACE("failed to change thread priority [%s]",strerror(nRet));
     825             :     }
     826             : 
     827             : #endif /* NO_PTHREAD_PRIORITY */
     828             : }
     829             : 
     830           0 : oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
     831             : {
     832             : #ifndef NO_PTHREAD_PRIORITY
     833             : 
     834             :     struct sched_param Param;
     835             :     int Policy;
     836             : 
     837             : #endif /* NO_PTHREAD_PRIORITY */
     838             : 
     839           0 :     oslThreadPriority Priority = osl_Thread_PriorityNormal;
     840           0 :     Thread_Impl* pImpl= (Thread_Impl*)Thread;
     841             : 
     842             :     OSL_ASSERT(pImpl);
     843           0 :     if (!pImpl)
     844           0 :         return osl_Thread_PriorityUnknown; /* EINVAL */
     845             : 
     846             : #ifndef NO_PTHREAD_PRIORITY
     847             : 
     848             :     if (pthread_getschedparam(pImpl->m_hThread, &Policy, &Param) != 0)
     849             :         return osl_Thread_PriorityUnknown; /* ESRCH */
     850             : 
     851             :     pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
     852             : 
     853             :     /* map pthread priority to enum */
     854             :     if (Param.sched_priority==g_thread.m_priority.m_Highest)
     855             :     {
     856             :         /* 127 - highest */
     857             :         Priority= osl_Thread_PriorityHighest;
     858             :     }
     859             :     else if (Param.sched_priority > g_thread.m_priority.m_Normal)
     860             :     {
     861             :         /* 65..126 - above normal */
     862             :         Priority= osl_Thread_PriorityAboveNormal;
     863             :     }
     864             :     else if (Param.sched_priority == g_thread.m_priority.m_Normal)
     865             :     {
     866             :         /* normal */
     867             :         Priority= osl_Thread_PriorityNormal;
     868             :     }
     869             :     else if (Param.sched_priority > g_thread.m_priority.m_Lowest)
     870             :     {
     871             :         /* 63..1 -below normal */
     872             :         Priority= osl_Thread_PriorityBelowNormal;
     873             :     }
     874             :     else if (Param.sched_priority == g_thread.m_priority.m_Lowest)
     875             :     {
     876             :         /* 0 - lowest */
     877             :         Priority= osl_Thread_PriorityLowest;
     878             :     }
     879             :     else
     880             :     {
     881             :         /* unknown */
     882             :         Priority= osl_Thread_PriorityUnknown;
     883             :     }
     884             : 
     885             : #endif /* NO_PTHREAD_PRIORITY */
     886             : 
     887           0 :     return Priority;
     888             : }
     889             : 
     890             : typedef struct _wrapper_pthread_key
     891             : {
     892             :     pthread_key_t m_key;
     893             :     oslThreadKeyCallbackFunction pfnCallback;
     894             : } wrapper_pthread_key;
     895             : 
     896           1 : oslThreadKey SAL_CALL osl_createThreadKey( oslThreadKeyCallbackFunction pCallback )
     897             : {
     898           1 :     wrapper_pthread_key *pKey = (wrapper_pthread_key*)rtl_allocateMemory(sizeof(wrapper_pthread_key));
     899             : 
     900           1 :     if (pKey)
     901             :     {
     902           1 :         pKey->pfnCallback = pCallback;
     903             : 
     904           1 :         if (pthread_key_create(&(pKey->m_key), pKey->pfnCallback) != 0)
     905             :         {
     906           0 :             rtl_freeMemory(pKey);
     907           0 :             pKey = 0;
     908             :         }
     909             :     }
     910             : 
     911           1 :     return ((oslThreadKey)pKey);
     912             : }
     913             : 
     914           1 : void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
     915             : {
     916           1 :     wrapper_pthread_key *pKey = (wrapper_pthread_key*)Key;
     917           1 :     if (pKey)
     918             :     {
     919           1 :         pthread_key_delete(pKey->m_key);
     920           1 :         rtl_freeMemory(pKey);
     921             :     }
     922           1 : }
     923             : 
     924           6 : void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
     925             : {
     926           6 :     wrapper_pthread_key *pKey = (wrapper_pthread_key*)Key;
     927           6 :     return pKey ? pthread_getspecific(pKey->m_key) : NULL;
     928             : }
     929             : 
     930           1 : sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
     931             : {
     932             :     sal_Bool bRet;
     933           1 :     void *pOldData = NULL;
     934           1 :     wrapper_pthread_key *pKey = (wrapper_pthread_key*)Key;
     935           1 :     if (!pKey)
     936           0 :         return sal_False;
     937             : 
     938           1 :     if (pKey->pfnCallback)
     939           1 :         pOldData = pthread_getspecific(pKey->m_key);
     940             : 
     941           1 :     bRet = (pthread_setspecific(pKey->m_key, pData) == 0);
     942             : 
     943           1 :     if (bRet && pKey->pfnCallback && pOldData)
     944           0 :         pKey->pfnCallback(pOldData);
     945             : 
     946           1 :     return bRet;
     947             : }
     948             : 
     949             : /*****************************************************************************/
     950             : /* Thread Local Text Encoding */
     951             : /*****************************************************************************/
     952       85011 : static void osl_thread_textencoding_init_Impl (void)
     953             : {
     954             :     rtl_TextEncoding defaultEncoding;
     955             : 
     956             :     /* create thread specific data key */
     957       85011 :     pthread_key_create (&(g_thread.m_textencoding.m_key), NULL);
     958             : 
     959             :     /* determine default text encoding */
     960       85011 :     defaultEncoding = osl_getTextEncodingFromLocale(NULL);
     961             :     OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW);
     962             : 
     963             :     /*
     964             :     Tools string functions call abort() on an unknown encoding so ASCII
     965             :     is a meaningfull fallback regardless whether the assertion makes sense.
     966             :     */
     967             : 
     968       85011 :     if ( RTL_TEXTENCODING_DONTKNOW == defaultEncoding )
     969           0 :         defaultEncoding = RTL_TEXTENCODING_ASCII_US;
     970             : 
     971       85011 :     g_thread.m_textencoding.m_default = defaultEncoding;
     972       85011 : }
     973             : 
     974     5017681 : rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding()
     975             : {
     976             :     rtl_TextEncoding threadEncoding;
     977             : 
     978     5017681 :     pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
     979             : 
     980             :     /* check for thread specific encoding, use default if not set */
     981     5017681 :     threadEncoding = SAL_INT_CAST(
     982             :         rtl_TextEncoding,
     983             :         (sal_uIntPtr) pthread_getspecific(g_thread.m_textencoding.m_key));
     984     5017681 :     if (0 == threadEncoding)
     985     5017681 :         threadEncoding = g_thread.m_textencoding.m_default;
     986             : 
     987     5017681 :     return threadEncoding;
     988             : }
     989             : 
     990           0 : rtl_TextEncoding osl_setThreadTextEncoding(rtl_TextEncoding Encoding)
     991             : {
     992           0 :     rtl_TextEncoding oldThreadEncoding = osl_getThreadTextEncoding();
     993             : 
     994             :     /* save encoding in thread local storage */
     995           0 :     pthread_setspecific (
     996             :         g_thread.m_textencoding.m_key,
     997           0 :         (void*) SAL_INT_CAST(sal_uIntPtr, Encoding));
     998             : 
     999           0 :     return oldThreadEncoding;
    1000             : }
    1001             : 
    1002             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10