aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rusak <lorusak@gmail.com>2022-03-26 10:34:32 -0700
committerGitHub <noreply@github.com>2022-03-26 10:34:32 -0700
commitf0125d68a9ff0332dd61ae6eb764cb76b9476d7a (patch)
treea18a1747c2e534e7df06f1e6706e3bf1e1338c48
parent1858297881e105f04bf975aa4e901105662791bc (diff)
parentec7ed895f87a292e9dbc2b006890c1867c0ea076 (diff)
Merge pull request #21153 from lrusak/threading-cleanup-PR-4
threads: split CThreadImplPosix into CThreadImplLinux
-rw-r--r--cmake/treedata/android/subdirs.txt1
-rw-r--r--cmake/treedata/linux/subdirs.txt1
-rw-r--r--xbmc/platform/linux/threads/CMakeLists.txt4
-rw-r--r--xbmc/platform/linux/threads/ThreadImplLinux.cpp152
-rw-r--r--xbmc/platform/linux/threads/ThreadImplLinux.h26
-rw-r--r--xbmc/platform/posix/threads/CMakeLists.txt11
-rw-r--r--xbmc/platform/posix/threads/ThreadImplPosix.cpp152
-rw-r--r--xbmc/platform/posix/threads/ThreadImplPosix.h6
8 files changed, 195 insertions, 158 deletions
diff --git a/cmake/treedata/android/subdirs.txt b/cmake/treedata/android/subdirs.txt
index 506b9a5607..d3be3bf246 100644
--- a/cmake/treedata/android/subdirs.txt
+++ b/cmake/treedata/android/subdirs.txt
@@ -15,6 +15,7 @@ xbmc/platform/android/powermanagement platform/android/powermanagement
xbmc/platform/android/storage platform/android/storage
xbmc/platform/android/utils platform/android/utils
xbmc/platform/linux/peripherals platform/linux/peripherals
+xbmc/platform/linux/threads platform/linux/threads
xbmc/platform/posix platform/posix
xbmc/platform/posix/filesystem platform/posix/filesystem
xbmc/platform/posix/threads platform/posix/threads
diff --git a/cmake/treedata/linux/subdirs.txt b/cmake/treedata/linux/subdirs.txt
index 440bea9afd..d25c36de51 100644
--- a/cmake/treedata/linux/subdirs.txt
+++ b/cmake/treedata/linux/subdirs.txt
@@ -7,6 +7,7 @@ xbmc/platform/linux/peripherals platform/linux/peripherals
xbmc/platform/linux/powermanagement platform/linux/powermanagement
xbmc/platform/linux/sse4 platform/linux/sse4
xbmc/platform/linux/storage platform/linux/storage
+xbmc/platform/linux/threads platform/linux/threads
xbmc/platform/posix platform/posix
xbmc/platform/posix/filesystem platform/posix/filesystem
xbmc/platform/posix/network platform/posix/network
diff --git a/xbmc/platform/linux/threads/CMakeLists.txt b/xbmc/platform/linux/threads/CMakeLists.txt
new file mode 100644
index 0000000000..b90d55ee36
--- /dev/null
+++ b/xbmc/platform/linux/threads/CMakeLists.txt
@@ -0,0 +1,4 @@
+set(SOURCES ThreadImplLinux.cpp)
+set(HEADERS ThreadImplLinux.h)
+
+core_add_library(platform_linux_threads)
diff --git a/xbmc/platform/linux/threads/ThreadImplLinux.cpp b/xbmc/platform/linux/threads/ThreadImplLinux.cpp
new file mode 100644
index 0000000000..1617e50941
--- /dev/null
+++ b/xbmc/platform/linux/threads/ThreadImplLinux.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "ThreadImplLinux.h"
+
+#include "utils/log.h"
+
+#include <algorithm>
+#include <array>
+#include <limits.h>
+
+#include <sys/resource.h>
+#include <unistd.h>
+
+namespace
+{
+
+constexpr std::array<ThreadPriorityStruct, 5> nativeThreadPriorityMap = {{
+ {ThreadPriority::LOWEST, -1},
+ {ThreadPriority::BELOW_NORMAL, -1},
+ {ThreadPriority::NORMAL, 0},
+ {ThreadPriority::ABOVE_NORMAL, 1},
+ {ThreadPriority::HIGHEST, 1},
+}};
+
+//! @todo: c++20 has constexpr std::find_if
+int ThreadPriorityToNativePriority(const ThreadPriority& priority)
+{
+ auto it = std::find_if(nativeThreadPriorityMap.cbegin(), nativeThreadPriorityMap.cend(),
+ [&priority](const auto& map) { return map.priority == priority; });
+
+ if (it != nativeThreadPriorityMap.cend())
+ {
+ return it->nativePriority;
+ }
+
+ throw std::runtime_error("priority not implemented");
+}
+
+} // namespace
+
+static int s_maxPriority;
+static bool s_maxPriorityIsSet{false};
+
+// We need to return what the best number than can be passed
+// to SetPriority is. It will basically be relative to the
+// the main thread's nice level, inverted (since "higher" priority
+// nice levels are actually lower numbers).
+static int GetUserMaxPriority(int maxPriority)
+{
+ if (s_maxPriorityIsSet)
+ return s_maxPriority;
+
+ // if we're root, then we can do anything. So we'll allow
+ // max priority.
+ if (geteuid() == 0)
+ return maxPriority;
+
+ // get user max prio
+ struct rlimit limit;
+ if (getrlimit(RLIMIT_NICE, &limit) != 0)
+ {
+ // If we fail getting the limit for nice we just assume we can't raise the priority
+ return 0;
+ }
+
+ const int appNice = getpriority(PRIO_PROCESS, getpid());
+ const int rlimVal = limit.rlim_cur;
+
+ // according to the docs, limit.rlim_cur shouldn't be zero, yet, here we are.
+ // if a user has no entry in limits.conf rlim_cur is zero. In this case the best
+ // nice value we can hope to achieve is '0' as a regular user
+ const int userBestNiceValue = (rlimVal == 0) ? 0 : (20 - rlimVal);
+
+ // running the app with nice -n 10 ->
+ // e.g. +10 10 - 0 // default non-root user.
+ // e.g. +30 10 - -20 // if root with rlimits set.
+ // running the app default ->
+ // e.g. 0 0 - 0 // default non-root user.
+ // e.g. +20 0 - -20 // if root with rlimits set.
+ const int bestUserSetPriority = appNice - userBestNiceValue; // nice is inverted from prio.
+
+ // static because we only need to check this once.
+ // we shouldn't expect a user to change RLIMIT_NICE while running
+ // and it won't work anyway for threads that already set their priority.
+ s_maxPriority = std::min(maxPriority, bestUserSetPriority);
+ s_maxPriorityIsSet = true;
+
+ return s_maxPriority;
+}
+
+std::unique_ptr<IThreadImpl> IThreadImpl::CreateThreadImpl(std::thread::native_handle_type handle)
+{
+ return std::make_unique<CThreadImplLinux>(handle);
+}
+
+CThreadImplLinux::CThreadImplLinux(std::thread::native_handle_type handle)
+ : IThreadImpl(handle), m_threadID(gettid())
+{
+}
+
+void CThreadImplLinux::SetThreadInfo(const std::string& name)
+{
+#if defined(__GLIBC__)
+ pthread_setname_np(m_handle, name.c_str());
+#endif
+
+ // get user max prio
+ const int maxPrio = ThreadPriorityToNativePriority(ThreadPriority::HIGHEST);
+ const int userMaxPrio = GetUserMaxPriority(maxPrio);
+
+ // if the user does not have an entry in limits.conf the following
+ // call will fail
+ if (userMaxPrio > 0)
+ {
+ // start thread with nice level of application
+ const int appNice = getpriority(PRIO_PROCESS, getpid());
+ if (setpriority(PRIO_PROCESS, m_threadID, appNice) != 0)
+ CLog::Log(LOGERROR, "[threads] failed to set priority: {}", strerror(errno));
+ }
+}
+
+bool CThreadImplLinux::SetPriority(const ThreadPriority& priority)
+{
+ // keep priority in bounds
+ const int prio = ThreadPriorityToNativePriority(priority);
+ const int maxPrio = ThreadPriorityToNativePriority(ThreadPriority::HIGHEST);
+ const int minPrio = ThreadPriorityToNativePriority(ThreadPriority::LOWEST);
+
+ // get user max prio given max prio (will take the min)
+ const int userMaxPrio = GetUserMaxPriority(maxPrio);
+
+ // clamp to min and max priorities
+ const int adjustedPrio = std::clamp(prio, minPrio, userMaxPrio);
+
+ // nice level of application
+ const int appNice = getpriority(PRIO_PROCESS, getpid());
+ const int newNice = appNice - adjustedPrio;
+
+ if (setpriority(PRIO_PROCESS, m_threadID, newNice) != 0)
+ {
+ CLog::Log(LOGERROR, "[threads] failed to set priority: {}", strerror(errno));
+ return false;
+ }
+
+ return true;
+}
diff --git a/xbmc/platform/linux/threads/ThreadImplLinux.h b/xbmc/platform/linux/threads/ThreadImplLinux.h
new file mode 100644
index 0000000000..986ffe5ef3
--- /dev/null
+++ b/xbmc/platform/linux/threads/ThreadImplLinux.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "threads/IThreadImpl.h"
+
+class CThreadImplLinux : public IThreadImpl
+{
+public:
+ CThreadImplLinux(std::thread::native_handle_type handle);
+
+ ~CThreadImplLinux() override = default;
+
+ void SetThreadInfo(const std::string& name) override;
+
+ bool SetPriority(const ThreadPriority& priority) override;
+
+private:
+ pid_t m_threadID;
+};
diff --git a/xbmc/platform/posix/threads/CMakeLists.txt b/xbmc/platform/posix/threads/CMakeLists.txt
index dd9498a3a2..251a7e1ac7 100644
--- a/xbmc/platform/posix/threads/CMakeLists.txt
+++ b/xbmc/platform/posix/threads/CMakeLists.txt
@@ -1,6 +1,9 @@
-set(SOURCES RecursiveMutex.cpp
- ThreadImplPosix.cpp)
-set(HEADERS RecursiveMutex.h
- ThreadImplPosix.h)
+set(SOURCES RecursiveMutex.cpp)
+set(HEADERS RecursiveMutex.h)
+
+if(NOT CORE_SYSTEM_NAME STREQUAL linux AND NOT CORE_SYSTEM_NAME STREQUAL android)
+ list(APPEND SOURCES ThreadImplPosix.cpp)
+ list(APPEND HEADERS ThreadImplPosix.h)
+endif()
core_add_library(platform_posix_threads)
diff --git a/xbmc/platform/posix/threads/ThreadImplPosix.cpp b/xbmc/platform/posix/threads/ThreadImplPosix.cpp
index 022c6b8fb8..ae5b849f36 100644
--- a/xbmc/platform/posix/threads/ThreadImplPosix.cpp
+++ b/xbmc/platform/posix/threads/ThreadImplPosix.cpp
@@ -8,113 +8,16 @@
#include "ThreadImplPosix.h"
-#include <limits.h>
-#include <mutex>
-#if defined(TARGET_ANDROID)
-#include <unistd.h>
-#else
-#include <sys/syscall.h>
-#endif
-#include <sys/resource.h>
-#include <string.h>
-#ifdef TARGET_FREEBSD
-#include <sys/param.h>
-#include <pthread_np.h>
-#endif
-
#include "utils/log.h"
-#include <array>
-#include <signal.h>
-
-#if defined(RLIMIT_NICE)
-namespace
-{
-
-constexpr std::array<ThreadPriorityStruct, 5> nativeThreadPriorityMap = {{
- {ThreadPriority::LOWEST, -1},
- {ThreadPriority::BELOW_NORMAL, -1},
- {ThreadPriority::NORMAL, 0},
- {ThreadPriority::ABOVE_NORMAL, 1},
- {ThreadPriority::HIGHEST, 1},
-}};
-
-//! @todo: c++20 has constexpr std::find_if
-int ThreadPriorityToNativePriority(const ThreadPriority& priority)
-{
- auto it = std::find_if(nativeThreadPriorityMap.cbegin(), nativeThreadPriorityMap.cend(),
- [&priority](const auto& map) { return map.priority == priority; });
-
- if (it != nativeThreadPriorityMap.cend())
- {
- return it->nativePriority;
- }
-
- throw std::runtime_error("priority not implemented");
-}
-
-} // namespace
-#endif
-
-static pid_t GetCurrentThreadPid_()
-{
-#ifdef TARGET_FREEBSD
- return pthread_getthreadid_np();
-#elif defined(TARGET_ANDROID)
- return gettid();
-#elif TARGET_DARWIN
- return pthread_mach_thread_np(pthread_self());
-#else
- return syscall(SYS_gettid);
-#endif
-}
-
-#ifdef RLIMIT_NICE
-// We need to return what the best number than can be passed
-// to SetPriority is. It will basically be relative to the
-// the main thread's nice level, inverted (since "higher" priority
-// nice levels are actually lower numbers).
-static int GetUserMaxPriority(int maxPriority)
-{
- // if we're root, then we can do anything. So we'll allow
- // max priority.
- if (geteuid() == 0)
- return maxPriority;
-
- // get user max prio
- struct rlimit limit;
- if (getrlimit(RLIMIT_NICE, &limit) == 0)
- {
- const int appNice = getpriority(PRIO_PROCESS, getpid());
- const int rlimVal = limit.rlim_cur;
-
- // according to the docs, limit.rlim_cur shouldn't be zero, yet, here we are.
- // if a user has no entry in limits.conf rlim_cur is zero. In this case the best
- // nice value we can hope to achieve is '0' as a regular user
- const int userBestNiceValue = (rlimVal == 0) ? 0 : (20 - rlimVal);
-
- // running the app with nice -n 10 ->
- // e.g. +10 10 - 0 // default non-root user.
- // e.g. +30 10 - -20 // if root with rlimits set.
- // running the app default ->
- // e.g. 0 0 - 0 // default non-root user.
- // e.g. +20 0 - -20 // if root with rlimits set.
- const int bestUserSetPriority = appNice - userBestNiceValue; // nice is inverted from prio.
- return std::min(maxPriority, bestUserSetPriority); //
- }
- else
- // If we fail getting the limit for nice we just assume we can't raise the priority
- return 0;
-}
-#endif
+#include <pthread.h>
std::unique_ptr<IThreadImpl> IThreadImpl::CreateThreadImpl(std::thread::native_handle_type handle)
{
return std::make_unique<CThreadImplPosix>(handle);
}
-CThreadImplPosix::CThreadImplPosix(std::thread::native_handle_type handle)
- : IThreadImpl(handle), m_threadID(GetCurrentThreadPid_())
+CThreadImplPosix::CThreadImplPosix(std::thread::native_handle_type handle) : IThreadImpl(handle)
{
}
@@ -122,58 +25,11 @@ void CThreadImplPosix::SetThreadInfo(const std::string& name)
{
#if defined(TARGET_DARWIN)
pthread_setname_np(name.c_str());
-#elif defined(TARGET_LINUX) && defined(__GLIBC__)
- // mthread must be set by here.
- pthread_setname_np(m_handle, name.c_str());
-#endif
-
-#ifdef RLIMIT_NICE
- // get user max prio
- int userMaxPrio = GetUserMaxPriority(ThreadPriorityToNativePriority(ThreadPriority::HIGHEST));
-
- // if the user does not have an entry in limits.conf the following
- // call will fail
- if (userMaxPrio > 0)
- {
- // start thread with nice level of application
- int appNice = getpriority(PRIO_PROCESS, getpid());
- if (setpriority(PRIO_PROCESS, m_threadID, appNice) != 0)
- CLog::Log(LOGERROR, "{}: error {}", __FUNCTION__, strerror(errno));
- }
#endif
}
bool CThreadImplPosix::SetPriority(const ThreadPriority& priority)
{
- bool bReturn = false;
-
- std::unique_lock<CCriticalSection> lockIt(m_criticalSection);
-
- if (!m_handle)
- bReturn = false;
-#ifdef RLIMIT_NICE
- else
- {
- // get user max prio given max prio (will take the min)
- int userMaxPrio = GetUserMaxPriority(ThreadPriorityToNativePriority(ThreadPriority::HIGHEST));
-
- // keep priority in bounds
- int prio = ThreadPriorityToNativePriority(priority);
- if (prio >= ThreadPriorityToNativePriority(ThreadPriority::HIGHEST))
- prio = userMaxPrio; // this is already the min of GetMaxPriority and what the user can set.
- if (prio < ThreadPriorityToNativePriority(ThreadPriority::LOWEST))
- prio = ThreadPriorityToNativePriority(ThreadPriority::LOWEST);
-
- // nice level of application
- const int appNice = getpriority(PRIO_PROCESS, getpid());
- const int newNice = appNice - prio;
-
- if (setpriority(PRIO_PROCESS, m_threadID, newNice) == 0)
- bReturn = true;
- else
- CLog::Log(LOGERROR, "{}: error {}", __FUNCTION__, strerror(errno));
- }
-#endif
-
- return bReturn;
+ CLog::Log(LOGDEBUG, "[threads] setting priority is not supported on this platform");
+ return false;
}
diff --git a/xbmc/platform/posix/threads/ThreadImplPosix.h b/xbmc/platform/posix/threads/ThreadImplPosix.h
index 6e2a98de42..7bba5e141e 100644
--- a/xbmc/platform/posix/threads/ThreadImplPosix.h
+++ b/xbmc/platform/posix/threads/ThreadImplPosix.h
@@ -9,7 +9,6 @@
#pragma once
#include "threads/IThreadImpl.h"
-#include "threads/SingleLock.h"
class CThreadImplPosix : public IThreadImpl
{
@@ -21,9 +20,4 @@ public:
void SetThreadInfo(const std::string& name) override;
bool SetPriority(const ThreadPriority& priority) override;
-
-private:
- CCriticalSection m_criticalSection;
-
- pid_t m_threadID;
};