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

Generated by: LCOV version 1.10