[packages/mpd] bring back thread check in relaxed form; rel 3
atler
atler at pld-linux.org
Fri Mar 13 00:55:20 CET 2026
commit f6d29cbf3d149f1c1a86308d70d61568fed9bf4d
Author: Jan Palus <atler at pld-linux.org>
Date: Fri Mar 13 00:51:36 2026 +0100
bring back thread check in relaxed form; rel 3
validate if existing threads have all signals blocked and double check
if current sigmask is clean
see https://github.com/MusicPlayerDaemon/MPD/issues/2445
mpd.spec | 2 +-
thread-count-check.patch | 203 +++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 189 insertions(+), 16 deletions(-)
---
diff --git a/mpd.spec b/mpd.spec
index f83aa16..fa91280 100644
--- a/mpd.spec
+++ b/mpd.spec
@@ -10,7 +10,7 @@ Summary: Music Player Daemon
Summary(pl.UTF-8): Music Player Daemon - demon odtwarzający muzykę
Name: mpd
Version: 0.24.9
-Release: 2
+Release: 3
License: GPL v2+
Group: Applications/Multimedia
Source0: https://www.musicpd.org/download/mpd/0.24/%{name}-%{version}.tar.xz
diff --git a/thread-count-check.patch b/thread-count-check.patch
index 2c8e04a..58a96f3 100644
--- a/thread-count-check.patch
+++ b/thread-count-check.patch
@@ -1,18 +1,191 @@
---- mpd-0.24.9/src/Main.cxx.orig 2026-03-11 11:54:28.000000000 +0100
-+++ mpd-0.24.9/src/Main.cxx 2026-03-12 01:27:56.922373764 +0100
-@@ -695,15 +695,6 @@
- int
+--- mpd-0.24.9/meson.build.orig 2026-03-11 11:54:28.000000000 +0100
++++ mpd-0.24.9/meson.build 2026-03-12 23:33:53.445792279 +0100
+@@ -6,7 +6,7 @@
+ default_options: [
+ 'c_std=c11',
+ 'build.c_std=c11',
+- 'cpp_std=c++20',
++ 'cpp_std=c++23',
+ 'build.cpp_std=c++20',
+ 'warning_level=3',
+
+diff --git a/src/Main.cxx b/src/Main.cxx
+index 6d494aebb..b19e0f3cf 100644
+--- a/src/Main.cxx
++++ b/src/Main.cxx
+@@ -698,7 +698,7 @@ int
main(int argc, char *argv[]) noexcept
try {
--#ifdef __linux__
+ #ifdef __linux__
- if (ProcStatusThreads() > 1)
-- /* threads created by libraries before main() can
-- cause all sorts of bugs that are difficult to
-- analyze; bail out quickly and refuse to run if we
-- detect such a thing */
-- throw "Background threads were detected before MPD could initialize. This is likely caused by a misbehaving library. Aborting to prevent erroneous behavior. Please report.";
--#endif
--
- AtScopeExit() { log_deinit(); };
-
- #ifdef _WIN32
++ if (!ProcStatusThreadsCheck())
+ /* threads created by libraries before main() can
+ cause all sorts of bugs that are difficult to
+ analyze; bail out quickly and refuse to run if we
+diff --git a/src/io/linux/ProcStatus.cxx b/src/io/linux/ProcStatus.cxx
+index 3d8b9fc3f..fa7de315a 100644
+--- a/src/io/linux/ProcStatus.cxx
++++ b/src/io/linux/ProcStatus.cxx
+@@ -1,36 +1,143 @@
+ // SPDX-License-Identifier: BSD-2-Clause
+ // author: Max Kellermann <max.kellermann at gmail.com>
+
++#include <cstddef>
++#include <cstdint>
++#include <cinttypes>
++#include <cstdio>
++#include <cstring>
++#include <iostream>
++#include <ostream>
++#include <ranges>
++#include <signal.h>
++#include <string>
++#include <unistd.h>
++
+ #include "ProcStatus.hxx"
++#include "fs/AllocatedPath.hxx"
++#include "fs/DirectoryReader.hxx"
++#include "fs/Path.hxx"
+ #include "io/UniqueFileDescriptor.hxx"
+ #include "util/NumberParser.hxx"
+ #include "util/StringSplit.hxx"
+
+ using std::string_view_literals::operator""sv;
+
+-unsigned
+-ProcStatusThreads() noexcept
++// keep in sync
++typedef uint64_t mpd_sigmask_t;
++#define SCNMPDSIGMASK SCNx64
++
++static_assert(NSIG <= sizeof(mpd_sigmask_t) * 8 + 1, "mpd_sigmask_t is too small for all signals");
++
++bool
++ProcStatusThreadsCheck() noexcept
+ {
+ UniqueFileDescriptor fd;
+ if (!fd.OpenReadOnly("/proc/self/status"))
+- return 0;
++ return true;
+
+ char buffer[4096];
+ ssize_t nbytes = fd.Read(std::as_writable_bytes(std::span{buffer}));
+ if (nbytes <= 0)
+- return 0;
++ return true;
+
+ const std::string_view contents{buffer, static_cast<std::size_t>(nbytes)};
+
+ static constexpr std::string_view prefix = "\nThreads:\t"sv;
+ const auto position = contents.find(prefix);
+ if (position == contents.npos)
+- return 0;
++ return true;
+
+ const std::string_view value_string = Split(contents.substr(position + prefix.size()), '\n').first;
+ unsigned value;
+ if (!ParseIntegerTo(value_string, value))
+- return 0;
++ return true;
++
++ if (value == 1)
++ return true;
++
++ bool result = true;
++
++ sigset_t current_sigmask;
++ pthread_sigmask(SIG_SETMASK, NULL, ¤t_sigmask);
++
++ mpd_sigmask_t expected_blocked_mask = 0;
++ for (int sig = 1; sig < NSIG; sig++)
++ if (sig != SIGKILL && sig != SIGSTOP && (sig < 32 || sig >= SIGRTMIN)) {
++ expected_blocked_mask |= (((mpd_sigmask_t) 1) << (sig - 1));
++ int ret = sigismember(¤t_sigmask, sig);
++ if (ret < 0)
++ return false;
++ else if (result && ret) {
++ std::cerr << "Blocked signal mask is not clean" << std::endl;
++ result = false;
++ }
++
++ }
++
++ try {
++ auto task_path = Path::FromFS("/proc/self/task");
++ DirectoryReader task_dir(task_path);
++ pid_t pid = getpid();
++
++ while (task_dir.ReadEntry()) {
++ auto entry = task_dir.GetEntry();
++
++ if (strcmp(".", entry.c_str()) == 0 || strcmp("..", entry.c_str()) == 0)
++ continue;
++
++ pid_t task_id;
++
++ if (!ParseIntegerTo(entry.c_str(), task_id)) [[unlikely]]
++ return false;
++
++ if (task_id == pid)
++ continue;
++
++ UniqueFileDescriptor status_fd;
++ if (!status_fd.OpenReadOnly((task_path / entry / Path::FromFS("status")).c_str()))
++ return false;
++
++ nbytes = status_fd.Read(std::as_writable_bytes(std::span{buffer}));
++ if (nbytes <= 0)
++ return false;
++
++ const std::string_view status_content{buffer, static_cast<std::size_t>(nbytes)};
++ static constexpr auto newline{"\n"sv};
++ static constexpr auto tab{"\t"sv};
++ std::string_view name;
++ mpd_sigmask_t task_blocked_mask = 0;
++ bool task_blocked_mask_found = false;
++
++ for (auto line : std::views::split(status_content, newline)) {
++ auto text = std::string_view(line);
++ if (text.starts_with("Name:\t")) {
++ auto pos = text.find(tab);
++ if (pos < text.size() - 1) [[likely]]
++ name = text.substr(pos + 1);
++ } else if (text.starts_with("SigBlk:\t")) {
++ auto pos = text.find(tab);
++ if (pos == text.size() - 1) [[unlikely]]
++ return false;
++ std::string text_value(text.substr(pos + 1));
++ sscanf(text_value.c_str(), "%" SCNMPDSIGMASK, &task_blocked_mask);
++ task_blocked_mask_found = true;
++ }
++
++ if (!name.empty() && task_blocked_mask_found)
++ break;
++ }
++
++ if (!task_blocked_mask_found || (task_blocked_mask & expected_blocked_mask) != expected_blocked_mask) {
++ std::cerr << "Found thread (" << name << ") without blocked signals" << std::endl;
++ result = false;
++ }
++
++ }
++
++ return result;
++ } catch (...) {
++ return false;
++ }
+
+- return value;
+ }
+diff --git a/src/io/linux/ProcStatus.hxx b/src/io/linux/ProcStatus.hxx
+index ffe6bfc4c..722fd2799 100644
+--- a/src/io/linux/ProcStatus.hxx
++++ b/src/io/linux/ProcStatus.hxx
+@@ -9,5 +9,5 @@
+ * @return the number of threads or 0 on error
+ */
+ [[gnu::pure]]
+-unsigned
+-ProcStatusThreads() noexcept;
++bool
++ProcStatusThreadsCheck() noexcept;
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/mpd.git/commitdiff/f6d29cbf3d149f1c1a86308d70d61568fed9bf4d
More information about the pld-cvs-commit
mailing list