Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sal/osl/unx/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 27 kB image not shown  

Quelle  thread.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <sal/config.h>

#include <cassert>
#include <functional>
#include <mutex>
#include <unistd.h>

#include "system.hxx"
#include "unixerrnostring.hxx"
#include <thread_internal.hxx>

#include <string.h>
#if defined(OPENBSD)
#include <sched.h>
#endif
#ifdef __FreeBSD__
#if __FreeBSD_version <= 1201517
#include <pthread_np.h>
#define pthread_setname_np pthread_set_name_np
#endif
#endif
#include <config_options.h>
#include <o3tl/safeint.hxx>
#include <osl/thread.h>
#include <osl/nlsupport.h>
#include <rtl/textenc.h>
#include <sal/log.hxx>
#include <sal/macros.h>
#ifdef ANDROID
#include <jni.h>
#include <android/log.h>
#include <osl/detail/android-bootstrap.h>
#endif

#if defined LINUX && ! defined __FreeBSD_kernel__
#include <sys/syscall.h>
#endif

/****************************************************************************
 * @@@ TODO @@@
 *
 * (1) 'osl_thread_priority_init_Impl()'
 *     - insane assumption that initializing caller is main thread
 *     - use _POSIX_THREAD_PRIORITY_SCHEDULING, not NO_PTHREAD_PRIORITY (?)
 *     - POSIX doesn't require defined prio's for SCHED_OTHER (!)
 *     - use SCHED_RR instead of SCHED_OTHER for defined behaviour (?)
 * (2) 'oslThreadIdentifier' and '{insert|remove|lookup}ThreadId()'
 *     - cannot reliably be applied to 'alien' threads;
 *     - memory leak for 'alien' thread 'HashEntry's;
 *     - use 'reinterpret_cast<unsigned long>(pthread_t)' as identifier
 *       instead (?)
 *     - if yes, change 'oslThreadIdentifier' to 'intptr_t' or similar
 * (3) 'oslSigAlarmHandler()' (#71232#)
 *     - [Under Solaris we get SIGALRM in e.g. pthread_join which terminates
 *       the process. So we initialize our signal handling module and do
 *       register a SIGALRM Handler which catches and ignores it]
 *     - should this still happen, 'signal.c' needs to be fixed instead.
 *
 ****************************************************************************/


#define THREADIMPL_FLAGS_TERMINATE  0x00001
#define THREADIMPL_FLAGS_STARTUP    0x00002
#define THREADIMPL_FLAGS_SUSPENDED  0x00004
#define THREADIMPL_FLAGS_ACTIVE     0x00008
#define THREADIMPL_FLAGS_ATTACHED   0x00010
#define THREADIMPL_FLAGS_DESTROYED  0x00020

namespace {

typedef struct osl_thread_impl_st
{
    pthread_t           m_hThread;
    oslThreadIdentifier m_Ident; /* @@@ see TODO @@@ */
    short               m_Flags;
    oslWorkerFunction   m_WorkerFunction;
    void*               m_pData;
    pthread_mutex_t     m_Lock;
    pthread_cond_t      m_Cond;
} Thread_Impl;

#if !defined NO_PTHREAD_PRIORITY
struct osl_thread_priority_st
{
    int m_Highest;
    int m_Above_Normal;
    int m_Normal;
    int m_Below_Normal;
    int m_Lowest;
};
#define OSL_THREAD_PRIORITY_INITIALIZER { 127, 96, 64, 32, 0 }
#endif

}

#if !defined NO_PTHREAD_PRIORITY

namespace {

struct osl_thread_global_st
{
    pthread_once_t                    m_once;
    struct osl_thread_priority_st     m_priority;
};

}

static struct osl_thread_global_st g_thread =
{
    PTHREAD_ONCE_INIT,
    OSL_THREAD_PRIORITY_INITIALIZER
};

#endif // !defined NO_PTHREAD_PRIORITY

static Thread_Impl* osl_thread_construct_Impl();
static void         osl_thread_destruct_Impl (Thread_Impl ** ppImpl);

static void* osl_thread_start_Impl (void * pData);
static void  osl_thread_cleanup_Impl (Thread_Impl * pImpl);

static oslThread osl_thread_create_Impl (
    oslWorkerFunction pWorker, void * pThreadData, short nFlags);

/* @@@ see TODO @@@ */
static oslThreadIdentifier insertThreadId (pthread_t hThread);
static oslThreadIdentifier lookupThreadId (pthread_t hThread);
static void                removeThreadId (pthread_t hThread);

Thread_Impl* osl_thread_construct_Impl()
{
    Thread_Impl* pImpl = new Thread_Impl;
    memset (pImpl, 0, sizeof(Thread_Impl));

    pthread_mutex_init (&(pImpl->m_Lock), PTHREAD_MUTEXATTR_DEFAULT);
    pthread_cond_init  (&(pImpl->m_Cond), PTHREAD_CONDATTR_DEFAULT);
    return pImpl;
}

static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl)
{
    assert(ppImpl);
    if (*ppImpl)
    {
        pthread_cond_destroy  (&((*ppImpl)->m_Cond));
        pthread_mutex_destroy (&((*ppImpl)->m_Lock));

        delete *ppImpl;
        (*ppImpl) = nullptr;
    }
}

static void osl_thread_cleanup_Impl (Thread_Impl * pImpl)
{
    pthread_t thread;
    bool attached;
    bool destroyed;

    pthread_mutex_lock (&(pImpl->m_Lock));

    thread = pImpl->m_hThread;
    attached = (pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) != 0;
    destroyed = (pImpl->m_Flags & THREADIMPL_FLAGS_DESTROYED) != 0;
    pImpl->m_Flags &= ~(THREADIMPL_FLAGS_ACTIVE | THREADIMPL_FLAGS_ATTACHED);

    pthread_mutex_unlock (&(pImpl->m_Lock));

    /* release oslThreadIdentifier @@@ see TODO @@@ */
    removeThreadId (thread);

    if (attached)
    {
        pthread_detach (thread);
    }

    if (destroyed)
    {
        osl_thread_destruct_Impl (&pImpl);
    }
}

static void* osl_thread_start_Impl (void* pData)
{
    bool terminate;
    Thread_Impl* pImpl= static_cast<Thread_Impl*>(pData);

    assert(pImpl);

    pthread_mutex_lock (&(pImpl->m_Lock));

    /* request oslThreadIdentifier @@@ see TODO @@@ */
    pImpl->m_Ident = insertThreadId (pImpl->m_hThread);

    /* signal change from STARTUP to ACTIVE state */
    pImpl->m_Flags &= ~THREADIMPL_FLAGS_STARTUP;
    pImpl->m_Flags |=  THREADIMPL_FLAGS_ACTIVE;
    pthread_cond_signal (&(pImpl->m_Cond));

    /* Check if thread is started in SUSPENDED state */
    while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
    {
        /* wait until SUSPENDED flag is cleared */
        pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
    }

    /* check for SUSPENDED to TERMINATE state change */
    terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);

    pthread_mutex_unlock (&(pImpl->m_Lock));

    if (!terminate)
    {
#ifdef ANDROID
        JNIEnv* env = 0;
        int res = (*lo_get_javavm()).AttachCurrentThread(&env, NULL);
        __android_log_print(ANDROID_LOG_INFO, "LibreOffice""New sal thread started and attached res=%d", res);
#endif
        /* call worker function */
        pImpl->m_WorkerFunction(pImpl->m_pData);

#ifdef ANDROID
        res = (*lo_get_javavm()).DetachCurrentThread();
        __android_log_print(ANDROID_LOG_INFO, "LibreOffice""Detached finished sal thread res=%d", res);
#endif
    }

    osl_thread_cleanup_Impl (pImpl);
    return nullptr;
}

static oslThread osl_thread_create_Impl (
    oslWorkerFunction pWorker,
    void*             pThreadData,
    short             nFlags)
{
    Thread_Impl* pImpl;
#if defined OPENBSD || defined MACOSX || (defined LINUX && !ENABLE_RUNTIME_OPTIMIZATIONS)
    pthread_attr_t attr;
    size_t stacksize;
#endif
    int nRet=0;

    pImpl = osl_thread_construct_Impl();
    if (!pImpl)
        return nullptr; /* ENOMEM */

    pImpl->m_WorkerFunction = pWorker;
    pImpl->m_pData = pThreadData;
    pImpl->m_Flags = nFlags | THREADIMPL_FLAGS_STARTUP;

    pthread_mutex_lock (&(pImpl->m_Lock));

#if defined OPENBSD || defined MACOSX || (defined LINUX && !ENABLE_RUNTIME_OPTIMIZATIONS)
    if (pthread_attr_init(&attr) != 0)
        return nullptr;

#if defined OPENBSD
    stacksize = 262144;
#elif !ENABLE_RUNTIME_OPTIMIZATIONS
    stacksize = 12 * 1024 * 1024; // 8MB is not enough for ASAN on x86-64
#else
    stacksize = 1 * 1024 * 1024; // macOS default for non-main threads (512kB) is not enough...
#endif
    if (pthread_attr_setstacksize(&attr, stacksize) != 0) {
        pthread_attr_destroy(&attr);
        return nullptr;
    }
#endif

    if ((nRet = pthread_create (
        &(pImpl->m_hThread),
#if defined OPENBSD || defined MACOSX || (defined LINUX && !ENABLE_RUNTIME_OPTIMIZATIONS)
        &attr,
#else
        PTHREAD_ATTR_DEFAULT,
#endif
        osl_thread_start_Impl,
        static_cast<void*>(pImpl))) != 0)
    {
        SAL_WARN(
            "sal.osl",
            "pthread_create failed: " << UnixErrnoString(nRet));

        pthread_mutex_unlock (&(pImpl->m_Lock));
        osl_thread_destruct_Impl (&pImpl);

        return nullptr;
    }

#if defined OPENBSD || defined MACOSX || (defined LINUX && !ENABLE_RUNTIME_OPTIMIZATIONS)
    pthread_attr_destroy(&attr);
#endif

    /* wait for change from STARTUP to ACTIVE state */
    while (pImpl->m_Flags & THREADIMPL_FLAGS_STARTUP)
    {
        /* wait until STARTUP flag is cleared */
        pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
    }

    pthread_mutex_unlock (&(pImpl->m_Lock));

    return static_cast<oslThread>(pImpl);
}

oslThread osl_createThread (
    oslWorkerFunction pWorker,
    void *            pThreadData)
{
    return osl_thread_create_Impl (
        pWorker,
        pThreadData,
        THREADIMPL_FLAGS_ATTACHED);
}

oslThread osl_createSuspendedThread (
    oslWorkerFunction pWorker,
    void *            pThreadData)
{
    return osl_thread_create_Impl (
        pWorker,
        pThreadData,
        THREADIMPL_FLAGS_ATTACHED |
        THREADIMPL_FLAGS_SUSPENDED );
}

void SAL_CALL osl_destroyThread(oslThread Thread)
{
    if (Thread != nullptr) {
        Thread_Impl * impl = static_cast<Thread_Impl *>(Thread);
        bool active;
        pthread_mutex_lock(&impl->m_Lock);
        active = (impl->m_Flags & THREADIMPL_FLAGS_ACTIVE) != 0;
        impl->m_Flags |= THREADIMPL_FLAGS_DESTROYED;
        pthread_mutex_unlock(&impl->m_Lock);
        if (!active) {
            osl_thread_destruct_Impl(&impl);
        }
    }
}

void SAL_CALL osl_resumeThread(oslThread Thread)
{
    Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);

    if (!pImpl)
    {
        SAL_WARN("sal.osl""invalid osl_resumeThread(nullptr) call");
        return/* EINVAL */
    }

    pthread_mutex_lock (&(pImpl->m_Lock));

    if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
    {
        /* clear SUSPENDED flag */
        pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
        pthread_cond_signal (&(pImpl->m_Cond));
    }

    pthread_mutex_unlock (&(pImpl->m_Lock));
}

void SAL_CALL osl_suspendThread(oslThread Thread)
{
    Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);

    if (!pImpl)
    {
        SAL_WARN("sal.osl""invalid osl_suspendThread(nullptr) call");
        return/* EINVAL */
    }

    pthread_mutex_lock (&(pImpl->m_Lock));

    pImpl->m_Flags |= THREADIMPL_FLAGS_SUSPENDED;

    if (pthread_equal (pthread_self(), pImpl->m_hThread))
    {
        /* self suspend */
        while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
        {
            /* wait until SUSPENDED flag is cleared */
            pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
        }
    }

    pthread_mutex_unlock (&(pImpl->m_Lock));
}

sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
{
    bool active;
    Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);

    if (!pImpl)
        return false;

    pthread_mutex_lock (&(pImpl->m_Lock));
    active = ((pImpl->m_Flags & THREADIMPL_FLAGS_ACTIVE) > 0);
    pthread_mutex_unlock (&(pImpl->m_Lock));

    return active;
}

void SAL_CALL osl_joinWithThread(oslThread Thread)
{
    Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);

    if (!pImpl)
        return;

    pthread_mutex_lock (&(pImpl->m_Lock));

    pthread_t const thread = pImpl->m_hThread;
    bool const attached = ((pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) > 0);

    /* check this only if *this* thread is still attached - if it's not,
       then it could have terminated and another newly created thread could
       have recycled the same id as m_hThread! */

    if (attached && pthread_equal(pthread_self(), pImpl->m_hThread))
    {
        assert(false); /* Win32 implementation would deadlock here! */
        /* self join */
        pthread_mutex_unlock (&(pImpl->m_Lock));
        return/* EDEADLK */
    }

    pImpl->m_Flags &= ~THREADIMPL_FLAGS_ATTACHED;

    pthread_mutex_unlock (&(pImpl->m_Lock));

    if (attached)
    {
        pthread_join (thread, nullptr);
    }
}

void SAL_CALL osl_terminateThread(oslThread Thread)
{
    Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);

    if (!pImpl)
    {
        SAL_WARN("sal.osl""invalid osl_terminateThread(nullptr) call");
        return/* EINVAL */
    }

    pthread_mutex_lock (&(pImpl->m_Lock));

    if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
    {
        /* clear SUSPENDED flag */
        pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
        pthread_cond_signal (&(pImpl->m_Cond));
    }

    pImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE;

    pthread_mutex_unlock (&(pImpl->m_Lock));
}

sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
{
    bool terminate;
    Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);

    if (!pImpl)
    {
        SAL_WARN("sal.osl""invalid osl_scheduleThread(nullptr) call");
        return false/* EINVAL */
    }

    if (!(pthread_equal (pthread_self(), pImpl->m_hThread)))
    {
        SAL_WARN("sal.osl""invalid osl_scheduleThread(non-self) call");
        return false/* EINVAL */
    }

    pthread_mutex_lock (&(pImpl->m_Lock));

    while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
    {
        /* wait until SUSPENDED flag is cleared */
        pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
    }

    terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);

    pthread_mutex_unlock(&(pImpl->m_Lock));

    return !terminate;
}

void SAL_CALL osl_waitThread(const TimeValue* pDelay)
{
    if (pDelay)
    {
        struct timespec delay;

        SET_TIMESPEC(delay, pDelay->Seconds, pDelay->Nanosec);

        SLEEP_TIMESPEC(delay);
    }
}

/** Yields thread

    @attention Note that POSIX scheduling @em really requires threads to call this
    function, since a thread only reschedules to other thread, when
    it blocks (sleep, blocking I/O) OR calls sched_yield().
*/

void SAL_CALL osl_yieldThread()
{
    sched_yield();
}

void SAL_CALL osl_setThreadName(char const * name)
{
    assert( name );
#if defined LINUX && ! defined __FreeBSD_kernel__
    const int LINUX_THREAD_NAME_MAXLEN = 15;
    if ( strlen( name ) > LINUX_THREAD_NAME_MAXLEN )
        SAL_INFO( "sal.osl""osl_setThreadName truncated thread name to "
                  << LINUX_THREAD_NAME_MAXLEN << " chars from name '"
                  << name << "'" );
    char shortname[ LINUX_THREAD_NAME_MAXLEN + 1 ];
    shortname[ LINUX_THREAD_NAME_MAXLEN ] = '\0';
    strncpy( shortname, name, LINUX_THREAD_NAME_MAXLEN );
    int err = pthread_setname_np( pthread_self(), shortname );
    if ( 0 != err )
        SAL_WARN("sal.osl""pthread_setname_np failed with errno " << err);
#elif defined __FreeBSD__
    pthread_setname_np( pthread_self(), name );
#elif defined MACOSX || defined IOS
    pthread_setname_np( name );
#else
    (void) name;
#endif
}

/* osl_getThreadIdentifier @@@ see TODO @@@ */

namespace {

struct HashEntry
{
    pthread_t            Handle;
    oslThreadIdentifier  Ident;
    HashEntry *          Next;
};

}

static HashEntry* HashTable[31];
const int HashSize = SAL_N_ELEMENTS(HashTable);

static std::mutex HashLock;

#if ! ((defined LINUX && !defined __FreeBSD_kernel__) || defined MACOSX || defined IOS)
static oslThreadIdentifier LastIdent = 0;
#endif

namespace {

std::size_t HASHID(pthread_t x)
return std::hash<pthread_t>()(x) % HashSize; }

}

static oslThreadIdentifier lookupThreadId (pthread_t hThread)
{
    HashEntry *pEntry;

    std::unique_lock aGuard(HashLock);

    pEntry = HashTable[HASHID(hThread)];
    while (pEntry != nullptr)
    {
        if (pthread_equal(pEntry->Handle, hThread))
        {
            return pEntry->Ident;
        }
        pEntry = pEntry->Next;
    }

    return 0;
}

static oslThreadIdentifier insertThreadId (pthread_t hThread)
{
    HashEntry *pEntry, *pInsert = nullptr;

    std::unique_lock aGuard(HashLock);

    pEntry = HashTable[HASHID(hThread)];

    while (pEntry != nullptr)
    {
        if (pthread_equal(pEntry->Handle, hThread))
            break;

        pInsert = pEntry;
        pEntry = pEntry->Next;
    }

    if (pEntry == nullptr)
    {
        pEntry = static_cast<HashEntry*>(calloc(1, sizeof(HashEntry)));

        pEntry->Handle = hThread;

#if defined LINUX && ! defined __FreeBSD_kernel__
#if defined __GLIBC__ && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 30))
        // gettid returns a pid_t, which POSIX defines to be a signed integer type; assume that all
        // valid pid_t values on Linux are positive (zero is filtered out in the generic code
        // below):
        pid_t const tid = gettid();
        assert(tid >= 0);
#else
        long const tid = syscall(SYS_gettid);
        if (tid < 0 || o3tl::make_unsigned(tid) > std::numeric_limits<sal_uInt32>::max()) {
            std::abort();
        }
#endif
        pEntry->Ident = tid;
#elif defined MACOSX || defined IOS
        // currently the value of pthread_threadid_np is the same then
        // syscall(SYS_thread_selfid), which returns an int as the TID.
        // may change, as the syscall interface was deprecated.
        uint64_t mac_tid;
        pthread_threadid_np(nullptr, &mac_tid);
        if (mac_tid > SAL_MAX_UINT32)
            std::abort();
        pEntry->Ident = mac_tid;
#else
        ++LastIdent;
        if (0 == LastIdent)
            LastIdent = 1;
        pEntry->Ident = LastIdent;
#endif
        if (0 == pEntry->Ident)
            std::abort();

        if (pInsert)
            pInsert->Next = pEntry;
        else
            HashTable[HASHID(hThread)] = pEntry;
    }

    return pEntry->Ident;
}

static void removeThreadId (pthread_t hThread)
{
    HashEntry *pEntry, *pRemove = nullptr;

    std::unique_lock aGuard(HashLock);

    pEntry = HashTable[HASHID(hThread)];
    while (pEntry != nullptr)
    {
        if (pthread_equal(pEntry->Handle, hThread))
            break;

        pRemove = pEntry;
        pEntry = pEntry->Next;
    }

    if (pEntry != nullptr)
    {
        if (pRemove)
            pRemove->Next = pEntry->Next;
        else
            HashTable[HASHID(hThread)] = pEntry->Next;

        free(pEntry);
    }
}

oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
{
    Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
    oslThreadIdentifier Ident;

    if (pImpl)
        Ident = pImpl->m_Ident;
    else
    {
        /* current thread */
        pthread_t current = pthread_self();

        Ident = lookupThreadId (current);
        if (Ident == 0)
            /* @@@ see TODO: alien pthread_self() @@@ */
            Ident = insertThreadId (current);
    }

    return Ident;
}

#ifndef NO_PTHREAD_PRIORITY
/*****************************************************************************
    @@@ see TODO @@@
    osl_thread_priority_init_Impl

    set the base-priority of the main-thread to
    oslThreadPriorityNormal (64) since 0 (lowest) is
    the system default. This behaviour collides with
    our enum-priority definition (highest..normal..lowest).
    A  normaluser will expect the main-thread of an app.
    to have the "normal" priority.

*****************************************************************************/

static void osl_thread_priority_init_Impl()
{
    struct sched_param param;
    int policy=0;
    int nRet=0;

/* @@@ see TODO: calling thread may not be main thread @@@ */

    if ((nRet = pthread_getschedparam(pthread_self(), &policy, ¶m)) != 0)
    {
        SAL_WARN(
            "sal.osl",
            "pthread_getschedparam failed: " << UnixErrnoString(nRet));
        return;
    }

#if defined (__sun)
    if ( policy >= _SCHED_NEXT)
    {
        /* mfe: pthread_getschedparam on Solaris has a possible Bug */
        /*      one gets 959917873 as the policy                    */
        /*      so set the policy to a default one                  */
        policy=SCHED_OTHER;
    }
#endif /* __sun */

    if ((nRet = sched_get_priority_min(policy) ) != -1)
    {
        SAL_INFO(
            "sal.osl""Min Prioriy for policy " << policy << " == " << nRet);
        g_thread.m_priority.m_Lowest=nRet;
    }
    else
    {
        int e = errno;
        SAL_WARN(
            "sal.osl",
            "sched_get_priority_min failed: " << UnixErrnoString(e));
    }

    if ((nRet = sched_get_priority_max(policy) ) != -1)
    {
        SAL_INFO(
            "sal.osl""Max Prioriy for policy " << policy << " == " << nRet);
        g_thread.m_priority.m_Highest=nRet;
    }
    else
    {
        int e = errno;
        SAL_WARN(
            "sal.osl",
            "sched_get_priority_max failed: " << UnixErrnoString(e));
    }

    g_thread.m_priority.m_Normal =
        (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Highest) / 2;
    g_thread.m_priority.m_Below_Normal =
        (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Normal)  / 2;
    g_thread.m_priority.m_Above_Normal =
        (g_thread.m_priority.m_Normal + g_thread.m_priority.m_Highest) / 2;

/* @@@ set prio of calling (not main) thread (?) @@@ */

    param.sched_priority= g_thread.m_priority.m_Normal;

    if ((nRet = pthread_setschedparam(pthread_self(), policy, ¶m)) != 0)
    {
        SAL_WARN(
            "sal.osl",
            "pthread_setschedparam failed: " << UnixErrnoString(nRet));
        SAL_INFO(
            "sal.osl",
            "Thread ID " << pthread_self() << ", Policy " << policy
                << ", Priority " << param.sched_priority);
    }

}
#endif /* NO_PTHREAD_PRIORITY */

/**
    Impl-Notes: contrary to solaris-docu, which claims
    valid priority-levels from 0 .. INT_MAX, only the
    range 0..127 is accepted. (0 lowest, 127 highest)
*/

void SAL_CALL osl_setThreadPriority (
    oslThread         Thread,
    oslThreadPriority Priority)
{
#ifndef NO_PTHREAD_PRIORITY

    struct sched_param Param;
    int policy;
    int nRet;

#endif /* NO_PTHREAD_PRIORITY */

    Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);

    if (!pImpl)
    {
        SAL_WARN("sal.osl""invalid osl_setThreadPriority(nullptr, ...) call");
        return/* EINVAL */
    }

#ifdef NO_PTHREAD_PRIORITY
    (void) Priority; /* unused */
#else /* NO_PTHREAD_PRIORITY */

    if (pthread_getschedparam(pImpl->m_hThread, &policy, &Param) != 0)
        return/* ESRCH */

#if defined (__sun)
    if ( policy >= _SCHED_NEXT)
    {
        /* mfe: pthread_getschedparam on Solaris has a possible Bug */
        /*      one gets 959917873 as the policy                   */
        /*      so set the policy to a default one                 */
        policy=SCHED_OTHER;
    }
#endif /* __sun */

    pthread_once (&(g_thread.m_once), osl_thread_priority_init_Impl);

    switch(Priority)
    {
        case osl_Thread_PriorityHighest:
            Param.sched_priority= g_thread.m_priority.m_Highest;
            break;

        case osl_Thread_PriorityAboveNormal:
            Param.sched_priority= g_thread.m_priority.m_Above_Normal;
            break;

        case osl_Thread_PriorityNormal:
            Param.sched_priority= g_thread.m_priority.m_Normal;
            break;

        case osl_Thread_PriorityBelowNormal:
            Param.sched_priority= g_thread.m_priority.m_Below_Normal;
            break;

        case osl_Thread_PriorityLowest:
            Param.sched_priority= g_thread.m_priority.m_Lowest;
            break;

        case osl_Thread_PriorityUnknown:
            SAL_WARN(
                "sal.osl",
                "invalid osl_setThreadPriority(..., osl_Thread_PriorityUnknown)"
                    " call");
            return;

        default:
            SAL_WARN(
                "sal.osl",
                "invalid osl_setThreadPriority(..., " << Priority << ") call");
            return;
    }

    if ((nRet = pthread_setschedparam(pImpl->m_hThread, policy, &Param)) != 0)
    {
        SAL_WARN(
            "sal.osl",
            "pthread_setschedparam failed: " << UnixErrnoString(nRet));
    }

#endif /* NO_PTHREAD_PRIORITY */
}

oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
{
#ifndef NO_PTHREAD_PRIORITY

    struct sched_param Param;
    int Policy;

#endif /* NO_PTHREAD_PRIORITY */

    oslThreadPriority Priority = osl_Thread_PriorityNormal;
    Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);

    if (!pImpl)
    {
        SAL_WARN("sal.osl""invalid osl_getThreadPriority(nullptr) call");
        return osl_Thread_PriorityUnknown; /* EINVAL */
    }

#ifndef NO_PTHREAD_PRIORITY

    if (pthread_getschedparam(pImpl->m_hThread, &Policy, &Param) != 0)
        return osl_Thread_PriorityUnknown; /* ESRCH */

    pthread_once (&(g_thread.m_once), osl_thread_priority_init_Impl);

    /* map pthread priority to enum */
    if (Param.sched_priority==g_thread.m_priority.m_Highest)
    {
        /* 127 - highest */
        Priority= osl_Thread_PriorityHighest;
    }
    else if (Param.sched_priority > g_thread.m_priority.m_Normal)
    {
        /* 65..126 - above normal */
        Priority= osl_Thread_PriorityAboveNormal;
    }
    else if (Param.sched_priority == g_thread.m_priority.m_Normal)
    {
        /* normal */
        Priority= osl_Thread_PriorityNormal;
    }
    else if (Param.sched_priority > g_thread.m_priority.m_Lowest)
    {
        /* 63..1 -below normal */
        Priority= osl_Thread_PriorityBelowNormal;
    }
    else if (Param.sched_priority == g_thread.m_priority.m_Lowest)
    {
        /* 0 - lowest */
        Priority= osl_Thread_PriorityLowest;
    }
    else
    {
        /* unknown */
        Priority= osl_Thread_PriorityUnknown;
    }

#endif /* NO_PTHREAD_PRIORITY */

    return Priority;
}

namespace {

struct wrapper_pthread_key
{
    pthread_key_t m_key;
    oslThreadKeyCallbackFunction pfnCallback;
};

}

oslThreadKey SAL_CALL osl_createThreadKey( oslThreadKeyCallbackFunction pCallback )
{
    wrapper_pthread_key *pKey = static_cast<wrapper_pthread_key*>(malloc(sizeof(wrapper_pthread_key)));

    if (pKey)
    {
        pKey->pfnCallback = pCallback;

        if (pthread_key_create(&(pKey->m_key), pKey->pfnCallback) != 0)
        {
            free(pKey);
            pKey = nullptr;
        }
    }

    return static_cast<oslThreadKey>(pKey);
}

void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
{
    wrapper_pthread_key *pKey = static_cast<wrapper_pthread_key*>(Key);
    if (pKey)
    {
        pthread_key_delete(pKey->m_key);
        free(pKey);
    }
}

void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
{
    wrapper_pthread_key *pKey = static_cast<wrapper_pthread_key*>(Key);
    return pKey ? pthread_getspecific(pKey->m_key) : nullptr;
}

sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
{
    bool bRet;
    void *pOldData = nullptr;
    wrapper_pthread_key *pKey = static_cast<wrapper_pthread_key*>(Key);
    if (!pKey)
        return false;

    if (pKey->pfnCallback)
        pOldData = pthread_getspecific(pKey->m_key);

    bRet = (pthread_setspecific(pKey->m_key, pData) == 0);

    if (bRet && pKey->pfnCallback && pOldData)
        pKey->pfnCallback(pOldData);

    return bRet;
}

rtl_TextEncoding getThreadTextEncodingForInitialization()
{
    /* determine default text encoding */
    rtl_TextEncoding defaultEncoding = osl_getTextEncodingFromLocale(nullptr);
    // Tools string functions call abort() on an unknown encoding so ASCII is a
    // meaningful fallback:
    if ( RTL_TEXTENCODING_DONTKNOW == defaultEncoding )
    {
        SAL_WARN("sal.osl""RTL_TEXTENCODING_DONTKNOW -> _ASCII_US");
        defaultEncoding = RTL_TEXTENCODING_ASCII_US;
    }

    return defaultEncoding;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=94 H=89 G=91

¤ Dauer der Verarbeitung: 0.7 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.