mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 18:36:15 -08:00
fix: stabilize linux embedded mpv startup
This commit is contained in:
1 parent
21bf695779
commit
0c4fbd0891
2 files changed
+87
-25
No files matched your search
@@ -53,27 +53,29 @@ IPTVNATOR_DECLARE_MPV_DYNAMIC_SYMBOL(mpv_wakeup)
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <charconv>
|
||||
#include <chrono>
|
||||
#include <cctype>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <locale>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#ifdef __linux__
|
||||
#include <csignal>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
@@ -204,10 +206,19 @@ std::string formatInvariantDouble(double value)
|
||||
return "0";
|
||||
}
|
||||
|
||||
std::ostringstream output;
|
||||
output.imbue(std::locale::classic());
|
||||
output << std::setprecision(17) << value;
|
||||
return output.str();
|
||||
char buffer[64]{};
|
||||
const auto result = std::to_chars(
|
||||
buffer,
|
||||
buffer + sizeof(buffer),
|
||||
value,
|
||||
std::chars_format::general,
|
||||
17
|
||||
);
|
||||
if (result.ec != std::errc()) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
return std::string(buffer, result.ptr);
|
||||
}
|
||||
|
||||
std::string nowIsoString()
|
||||
@@ -594,18 +605,37 @@ std::vector<std::string> buildLinuxMpvArguments(
|
||||
return arguments;
|
||||
}
|
||||
|
||||
long inheritedFileDescriptorLimit()
|
||||
void closeInheritedFileDescriptors()
|
||||
{
|
||||
const long maxOpenFiles = sysconf(_SC_OPEN_MAX);
|
||||
return maxOpenFiles > 0 ? maxOpenFiles : 1024;
|
||||
}
|
||||
DIR* directory = opendir("/proc/self/fd");
|
||||
if (directory) {
|
||||
const int directoryFd = dirfd(directory);
|
||||
while (dirent* entry = readdir(directory)) {
|
||||
char* end = nullptr;
|
||||
const long value = std::strtol(entry->d_name, &end, 10);
|
||||
if (
|
||||
!end ||
|
||||
*end != '\0' ||
|
||||
value <= STDERR_FILENO ||
|
||||
value > INT_MAX
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
void closeInheritedFileDescriptors(long fileDescriptorLimit)
|
||||
{
|
||||
for (long fileDescriptor = STDERR_FILENO + 1;
|
||||
fileDescriptor < fileDescriptorLimit;
|
||||
fileDescriptor += 1) {
|
||||
const int descriptor = static_cast<int>(fileDescriptor);
|
||||
const int descriptor = static_cast<int>(value);
|
||||
if (descriptor == directoryFd) {
|
||||
continue;
|
||||
}
|
||||
const int flags = fcntl(descriptor, F_GETFD);
|
||||
if (flags >= 0) {
|
||||
fcntl(descriptor, F_SETFD, flags | FD_CLOEXEC);
|
||||
}
|
||||
}
|
||||
closedir(directory);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int descriptor = STDERR_FILENO + 1; descriptor < 1024; descriptor += 1) {
|
||||
const int flags = fcntl(descriptor, F_GETFD);
|
||||
if (flags >= 0) {
|
||||
fcntl(descriptor, F_SETFD, flags | FD_CLOEXEC);
|
||||
@@ -945,7 +975,6 @@ pid_t spawnLinuxMpvProcess(
|
||||
envp.push_back(nullptr);
|
||||
|
||||
const bool traceEnabled = std::getenv("IPTVNATOR_TRACE_EMBEDDED_MPV");
|
||||
const long fileDescriptorLimit = inheritedFileDescriptorLimit();
|
||||
const pid_t processId = fork();
|
||||
if (processId != 0) {
|
||||
return processId;
|
||||
@@ -962,7 +991,7 @@ pid_t spawnLinuxMpvProcess(
|
||||
}
|
||||
}
|
||||
|
||||
closeInheritedFileDescriptors(fileDescriptorLimit);
|
||||
closeInheritedFileDescriptors();
|
||||
execvpe(argv[0], argv.data(), envp.data());
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
@@ -324,14 +324,19 @@ describe('Embedded MPV native source recording invariants', () => {
|
||||
expect(widCommonSource).toContain(
|
||||
'arguments.push_back("--gpu-context=x11egl");'
|
||||
);
|
||||
expect(widCommonSource).toContain('inheritedFileDescriptorLimit()');
|
||||
expect(widCommonSource).toContain(
|
||||
'void closeInheritedFileDescriptors()'
|
||||
);
|
||||
expect(widCommonSource).toContain('opendir("/proc/self/fd")');
|
||||
expect(widCommonSource).toContain('readdir(directory)');
|
||||
expect(widCommonSource).toContain(
|
||||
'fcntl(descriptor, F_SETFD, flags | FD_CLOEXEC)'
|
||||
);
|
||||
expect(widCommonSource).toContain('closeInheritedFileDescriptors();');
|
||||
expect(widCommonSource).not.toContain('inheritedFileDescriptorLimit()');
|
||||
expect(widCommonSource).not.toContain(
|
||||
'closeInheritedFileDescriptors(fileDescriptorLimit);'
|
||||
);
|
||||
expect(widCommonSource).toContain('flags | FD_CLOEXEC');
|
||||
expect(widCommonSource).not.toContain('opendir(');
|
||||
expect(widCommonSource).not.toContain('readdir(');
|
||||
expect(widCommonSource).not.toContain('closedir(');
|
||||
});
|
||||
|
||||
it('drives Linux out-of-process MPV state and controls over JSON IPC', () => {
|
||||
@@ -370,14 +375,42 @@ describe('Embedded MPV native source recording invariants', () => {
|
||||
expect(refreshBody).not.toContain('clampVolumePercent(*volume)');
|
||||
});
|
||||
|
||||
it('only marks open file descriptors close-on-exec before Linux MPV exec', () => {
|
||||
const closeDescriptorsBody = sourceFunctionBody(
|
||||
widCommonSource,
|
||||
'void closeInheritedFileDescriptors(',
|
||||
'closeInheritedFileDescriptors'
|
||||
);
|
||||
expect(closeDescriptorsBody).toContain('opendir("/proc/self/fd")');
|
||||
expect(closeDescriptorsBody).toContain('readdir(directory)');
|
||||
expect(closeDescriptorsBody).toContain('fcntl(descriptor, F_GETFD)');
|
||||
expect(closeDescriptorsBody).toContain(
|
||||
'fcntl(descriptor, F_SETFD, flags | FD_CLOEXEC)'
|
||||
);
|
||||
expect(widCommonSource).not.toContain('sysconf(_SC_OPEN_MAX)');
|
||||
expect(widCommonSource).not.toContain(
|
||||
'fileDescriptor < fileDescriptorLimit'
|
||||
);
|
||||
|
||||
const spawnBody = sourceFunctionBody(
|
||||
widCommonSource,
|
||||
'pid_t spawnLinuxMpvProcess(',
|
||||
'spawnLinuxMpvProcess'
|
||||
);
|
||||
expect(spawnBody).toContain('closeInheritedFileDescriptors();');
|
||||
expect(spawnBody).not.toContain('inheritedFileDescriptorLimit()');
|
||||
});
|
||||
|
||||
it('formats MPV floating-point values independently from the user locale', () => {
|
||||
const formatterBody = sourceFunctionBody(
|
||||
widCommonSource,
|
||||
'std::string formatInvariantDouble(',
|
||||
'formatInvariantDouble'
|
||||
);
|
||||
expect(formatterBody).toContain('std::locale::classic()');
|
||||
expect(formatterBody).toContain('std::setprecision(17)');
|
||||
expect(formatterBody).toContain('std::to_chars(');
|
||||
expect(formatterBody).toContain('std::chars_format::general');
|
||||
expect(formatterBody).not.toContain('std::locale::classic()');
|
||||
expect(formatterBody).not.toContain('std::ostringstream');
|
||||
|
||||
const linuxArgumentsBody = sourceFunctionBody(
|
||||
widCommonSource,
|
||||
|
||||
Reference in new issue
Block a user