Auto-select web server port (for Ubuntu); --port option for PiPedalConfig

This commit is contained in:
Robin E. R. Davies
2024-11-24 12:41:30 -05:00
parent 96df3acabd
commit 8787073338
23 changed files with 261 additions and 111 deletions
+1 -1
View File
@@ -11,7 +11,7 @@
"/usr/lib", "/usr/lib",
"~/src/vst3sdk" "~/src/vst3sdk"
], ],
"compilerPath": "/usr/bin/gcc", "compilerPath": "/usr/bin/gcc-12",
"cStandard": "c17", "cStandard": "c17",
"cppStandard": "c++20", "cppStandard": "c++20",
"intelliSenseMode": "linux-gcc-arm64", "intelliSenseMode": "linux-gcc-arm64",
+42 -40
View File
@@ -266,6 +266,48 @@
} }
] ]
}, },
{
"name": "(gdb) pipedalconfigX",
"type": "cppdbg",
"request": "launch",
// Resolved by CMake Tools:
"program": "/home/robin/src/pipedal/build/src/pipedalconfig",
"args": [
"--nosudo", // run without sudo (which will fail because of perms, but allow us to debug deeper into install code.)
//"--get-current-port"
// "--uninstall"
//"--enable-p2p" , "CA", "PiPedalTest","12345678","14"
// "--alsa-devices"
"--prefix", "/usr",
"--install", "--port", "0"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [
{
"name": "PATH",
"value": "$PATH:${command:cmake.launchTargetDirectory}"
},
{
"name": "ASAN_OPTIONS",
"value": "detect_leaks=0"
},
{
"name": "OTHER_VALUE",
"value": "Something something"
}
],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
},
{ {
@@ -312,46 +354,6 @@
} }
] ]
}, },
{
"name": "(gdb) pipedalconfig",
"type": "cppdbg",
"request": "launch",
// Resolved by CMake Tools:
"program": "${command:cmake.launchTargetPath}",
"args": [
"--nosudo", // run without sudo (which will fail because of perms, but allow us to debug deeper into install code.)
//"--get-current-port"
// "--uninstall"
//"--enable-p2p" , "CA", "PiPedalTest","12345678","14"
"--alsa-devices"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [
{
"name": "PATH",
"value": "$PATH:${command:cmake.launchTargetDirectory}"
},
{
"name": "ASAN_OPTIONS",
"value": "detect_leaks=0"
},
{
"name": "OTHER_VALUE",
"value": "Something something"
}
],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
},
{ {
"name": "(gdb) pipedal_alsa_check", "name": "(gdb) pipedal_alsa_check",
"type": "cppdbg", "type": "cppdbg",
+2 -1
View File
@@ -110,5 +110,6 @@
"pipedalshutdownd", "pipedalshutdownd",
"pipedaltest", "pipedaltest",
"ToobAmp" "ToobAmp"
] ],
"C_Cpp.default.compilerPath": "/usr/bin/g++-13"
} }
+1 -1
View File
@@ -98,7 +98,7 @@ endif()
set(CPACK_GENERATOR "DEB") set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Robin E. R. Davies<rerdavies@gmail.com>") # required set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Robin E. R. Davies<rerdavies@gmail.com>") # required
set(CPACK_PACKAGE_VENDOR "Robin Davies") set(CPACK_PACKAGE_VENDOR "Robin E. R. Davies")
set(CPACK_PACKAGE_DESCRIPTION "IoT guitar effect pedal for Raspberry Pi, with phone-friendly web interface.") set(CPACK_PACKAGE_DESCRIPTION "IoT guitar effect pedal for Raspberry Pi, with phone-friendly web interface.")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IoT guitar effect pedal for Raspberry Pi") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IoT guitar effect pedal for Raspberry Pi")
set(CPACK_DEBIAN_PACKAGE_SECTION sound) set(CPACK_DEBIAN_PACKAGE_SECTION sound)
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright 2021-2024 Robin Davies Copyright 2021-2024 Robin E. R. Davies
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the "Software"), a copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -17,7 +17,7 @@ using namespace std;
static void PrintHelp() static void PrintHelp()
{ {
cout << "nm-pipedal-p2p - P2P Manager for NetworkManager network stack." << endl cout << "nm-pipedal-p2p - P2P Manager for NetworkManager network stack." << endl
<< "Copyright (c) 2024 Robin Davies." << endl << "Copyright (c) 2024 Robin E. R. Davies." << endl
<< endl << endl
<< "Provides P2P connections on LINUX distributions that use NetworkManager." << endl << "Provides P2P connections on LINUX distributions that use NetworkManager." << endl
<< endl << endl
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2022 Robin Davies // Copyright (c) 2022 Robin E. R. Davies
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of // Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in // this software and associated documentation files (the "Software"), to deal in
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2022 Robin Davies // Copyright (c) 2022 Robin E. R. Davies
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of // Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in // this software and associated documentation files (the "Software"), to deal in
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2022 Robin Davies // Copyright (c) 2022 Robin E. R. Davies
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of // Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in // this software and associated documentation files (the "Software"), to deal in
+1 -1
View File
@@ -3,7 +3,7 @@ Copyright (c) 2007, 2008 Johannes Berg
Copyright (c) 2007 Andy Lutomirski Copyright (c) 2007 Andy Lutomirski
Copyright (c) 2007 Mike Kershaw Copyright (c) 2007 Mike Kershaw
Copyright (c) 2008 Luis R. Rodriguez Copyright (c) 2008 Luis R. Rodriguez
Copyright (c) 2024 Robin Davies Copyright (c) 2024 Robin E. R. Davies
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
+1 -1
View File
@@ -3,7 +3,7 @@ Copyright (c) 2007, 2008 Johannes Berg
Copyright (c) 2007 Andy Lutomirski Copyright (c) 2007 Andy Lutomirski
Copyright (c) 2007 Mike Kershaw Copyright (c) 2007 Mike Kershaw
Copyright (c) 2008 Luis R. Rodriguez Copyright (c) 2008 Luis R. Rodriguez
Copyright (c) 2024 Robin Davies Copyright (c) 2024 Robin E. R. Davies
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2022 Robin Davies // Copyright (c) 2022 Robin E. R. Davies
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy of // Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in // this software and associated documentation files (the "Software"), to deal in
+5 -5
View File
@@ -1,24 +1,24 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: pipedal Upstream-Name: pipedal
Upstream-Contact: Robin Davies <rerdavies@gmail.com> Upstream-Contact: Robin E. R. Davies <rerdavies@gmail.com>
Source: https://www.example.com/software/project Source: https://www.example.com/software/project
Files: * Files: *
Copyright: 2021, Robin Davies Copyright: 2021, Robin E. R. Davies
License: Expat License: Expat
Files: src/* Files: src/*
Copyright: 2021, Robin Davies Copyright: 2021, Robin E. R. Davies
License: Expat License: Expat
Files: react/src Files: react/src
Copyright: 2020, Robin Davies. Copyright: 2020, Robin E. R. Davies.
License: Expat License: Expat
Files: src/Lv2EventBufferWriter.hpp Files: src/Lv2EventBufferWriter.hpp
Copyright: 2008-2014, David Robillard <d@drobilla.net> Copyright: 2008-2014, David Robillard <d@drobilla.net>
2021, Robin Davies 2021, Robin E. R. Davies
License: ISC and Expat License: ISC and Expat
Files: react/node_modules/@babel/* Files: react/node_modules/@babel/*
+2 -2
View File
@@ -1,11 +1,11 @@
--- ---
/: /:
license: Expat license: Expat
copyright: 2021, Robin Davies. copyright: 2021, Robin E. R. Davies.
src/react/: src/react/:
license: Expat license: Expat
copyright: 2021, Robin Davies. copyright: 2021, Robin E. R. Davies.
react/node_modules/webpack/: react/node_modules/webpack/:
license: Expat license: Expat
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright 2021-2024 Robin Davies Copyright 2021-2024 Robin E. R. Davies
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the "Software"), a copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright 2021-2023 Robin Davies Copyright 2021-2023 Robin E. R. Davies
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the "Software"), a copy of this software and associated documentation files (the "Software"),
+1 -1
View File
@@ -1014,7 +1014,7 @@ export class PiPedalModel //implements PiPedalModel
try { try {
await this.webSocket.connect(); await this.webSocket.connect();
} catch (error) { } catch (error) {
this.setError("Failed to connect to server. (" + getErrorMessage(error)); this.setError("Failed to connect to server. " + getErrorMessage(error) );
return false; return false;
} }
+2 -2
View File
@@ -281,7 +281,7 @@ class PiPedalSocket {
ws.onerror = (evt: Event) => { ws.onerror = (evt: Event) => {
ws.onclose = null; ws.onclose = null;
ws.onerror = null; ws.onerror = null;
reject("Failed to connect."); reject("Connection not accepted.");
}; };
ws.onopen = (event: Event) => { ws.onopen = (event: Event) => {
ws.onerror = self.handleError.bind(self); ws.onerror = self.handleError.bind(self);
@@ -290,7 +290,7 @@ class PiPedalSocket {
resolve(ws); resolve(ws);
}; };
} catch (e: any){ } catch (e: any){
reject("Failed to connect. " + e.toString()); reject("Failed to connect: " + e.toString());
}; };
}); });
} }
+1
View File
@@ -181,6 +181,7 @@ void AvahiService::EntryGroupCallback(AvahiEntryGroup *g, AvahiEntryGroupState s
char *n = avahi_alternative_service_name(avahiNameString); char *n = avahi_alternative_service_name(avahiNameString);
avahi_free(avahiNameString); avahi_free(avahiNameString);
avahiNameString = n; avahiNameString = n;
this->serviceName = n;
Lv2Log::warning(SS("Service name collision, renaming service to '" << avahiNameString << "'\n")); Lv2Log::warning(SS("Service name collision, renaming service to '" << avahiNameString << "'\n"));
/* And recreate the services */ /* And recreate the services */
create_group(avahi_entry_group_get_client(g)); create_group(avahi_entry_group_get_client(g));
+160 -23
View File
@@ -27,6 +27,7 @@
#include "alsaCheck.hpp" #include "alsaCheck.hpp"
#include "RegDb.hpp" #include "RegDb.hpp"
#include "Locale.hpp" #include "Locale.hpp"
#include "Finally.hpp"
#include <filesystem> #include <filesystem>
#include <stdlib.h> #include <stdlib.h>
@@ -953,6 +954,110 @@ void InstallPgpKey()
sysExec(cmd.c_str()); sysExec(cmd.c_str());
} }
} }
static uint32_t autoSelectPorts[] = {
80,
81, // unofficial alternate
8080, // unofficial alternate
8081, // unofficial alternate
8008, // unofficial alternate
83 // Not official at all.
};
static bool isPortInUse(int port) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
throw std::runtime_error(SS("Socket creation failed: " << strerror(errno)));
}
Finally ff{[sockfd]() {
close(sockfd);
}};
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
// Try to bind to the port
int result = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
if (result < 0) {
if (errno == EADDRINUSE) {
return true; // Port is in use
} else {
cout << "Warning: Unexpected error binding socket to port " << port << ": " << strerror(errno) << endl;
return true;
}
}
return false; // Port is free
}
static std::string AutoSelectPort() {
constexpr size_t MAX_PORT = sizeof(autoSelectPorts)/sizeof(autoSelectPorts[0]);
int32_t port = -1;
for (size_t i = 0; i < MAX_PORT; ++i)
{
if (!isPortInUse(autoSelectPorts[i]))
{
port = autoSelectPorts[i];
break;
}
}
if (port == -1) {
cout << "Warning: Can't find an available HTTP port. Setting to port 80 anyway." << endl;
port = 80;
} else if (port != 80)
{
cout << "Warning: Port 80 is already in use. Using port " << port << " instead." << endl;
}
return SS(port);
}
bool SetWebServerPort(std::string portOption)
{
try {
auto nPos = portOption.find_last_of(':');
std::string strPort;
if (nPos != std::string::npos)
{
strPort = portOption.substr(nPos+1);
} else {
strPort = portOption;
}
std::istringstream ss(strPort);
uint16_t iPort = 0;
ss >> iPort;
if (!ss)
{
throw std::runtime_error(SS("Invalid port number: " << strPort));
}
StopService(false);
PrepareServiceConfigurationFile(iPort);
StartService(true);
cout << "PiPedal web server is listening on port " << iPort << endl;
} catch (const std::exception&e)
{
cout << "Error: " << e.what() << endl;
return false;
}
return true;
}
void Install(const fs::path &programPrefix, const std::string endpointAddress) void Install(const fs::path &programPrefix, const std::string endpointAddress)
{ {
cout << "Configuring pipedal" << endl; cout << "Configuring pipedal" << endl;
@@ -1000,14 +1105,14 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
{ {
throw std::runtime_error("Invalid endpoint address: " + endpointAddress); throw std::runtime_error("Invalid endpoint address: " + endpointAddress);
} }
uint16_t port; uint16_t port = 80;
auto strPort = endpointAddress.substr(endpos + 1); auto strPort = endpointAddress.substr(endpos + 1);
try try
{ {
auto lport = std::stoul(strPort); auto lport = std::stoul(strPort);
if (lport == 0 || lport >= std::numeric_limits<uint16_t>::max()) if (lport == 0 || lport >= std::numeric_limits<uint16_t>::max())
{ {
throw std::runtime_error("out of range."); throw std::runtime_error("Port number is too large.");
} }
port = (uint16_t)lport; port = (uint16_t)lport;
std::stringstream s; std::stringstream s;
@@ -1020,6 +1125,7 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
s << "Invalid port number: " << strPort; s << "Invalid port number: " << strPort;
throw std::runtime_error(s.str()); throw std::runtime_error(s.str());
} }
PrepareServiceConfigurationFile(port); PrepareServiceConfigurationFile(port);
bool authBindRequired = port < 512; bool authBindRequired = port < 512;
@@ -1188,9 +1294,18 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
{ {
// don't allow abnormal termination, which leaves the package in a state that's // don't allow abnormal termination, which leaves the package in a state that's
// difficult to uninstall. // difficult to uninstall.
cout << "Error: " << e.what(); cout << "Error: " << e.what() << endl;
cout << " Run 'pipedalconfig --install' again to complete setup of PiPedal." << endl; cout << " Run 'pipedalconfig --install' again to complete setup of PiPedal." << endl;
} }
const std::string ADDR_ANY = "0.0.0.0:";
if (endpointAddress.starts_with(ADDR_ANY))
{
cout << "PiPedal web server is listening on port " << endpointAddress.substr(ADDR_ANY.length()) << endl;
} else {
cout << "PiPedal web server is listening on port " << endpointAddress << endl;
}
} }
static std::string GetCurrentWebServicePort() static std::string GetCurrentWebServicePort()
@@ -1199,7 +1314,7 @@ static std::string GetCurrentWebServicePort()
config.Load("/etc/pipedal/config", ""); config.Load("/etc/pipedal/config", "");
std::ostringstream ss; std::ostringstream ss;
ss << config.GetSocketServerPort(); ss << config.GetSocketServerAddress() << ":" << config.GetSocketServerPort();
return ss.str(); return ss.str();
} }
@@ -1208,7 +1323,7 @@ static void PrintHelp()
PrettyPrinter pp; PrettyPrinter pp;
pp << "pipedalconfig - Command-line post-install configuration for PiPedal" pp << "pipedalconfig - Command-line post-install configuration for PiPedal"
<< "\n" << "\n"
<< "Copyright (c) 2022-2024 Robin Davies." << "Copyright (c) 2022-2024 Robin E. R. Davies."
<< "\n" << "\n"
<< "\n" << "\n"
<< "See https://rerdavies.github.io/pipedal/Documentation.html for " << "See https://rerdavies.github.io/pipedal/Documentation.html for "
@@ -1239,6 +1354,10 @@ static void PrintHelp()
<< "The --port option controls which TCP/IP port the web server uses." << "The --port option controls which TCP/IP port the web server uses."
<< "\n\n" << "\n\n"
<< HangingIndent() << " --port <port#>\t"
<< "Set the TCP/IP port that the web server will use."
<< "\n"
<< HangingIndent() << " --uninstall\t" << HangingIndent() << " --uninstall\t"
<< "Remove installed services." << "Remove installed services."
<< "\n" << "\n"
@@ -1401,6 +1520,29 @@ void ListValidCountryCodes()
} }
} }
static std::string ProcessPortOption(std::string portOption)
{
if (portOption == "" || portOption == "0") // allow testing of port autodetect.
{
std::string t = GetCurrentWebServicePort();
if (portOption != "0") {// allows easy debugging of port AutoSelectPort.
portOption = t;
} else {
portOption = "";
}
if (portOption == "")
{
portOption = AutoSelectPort();
}
}
std::string ADDR_ANY = "0.0.0.0:";
if (portOption.find(':') == string::npos)
{
portOption = ADDR_ANY + portOption;
}
return portOption;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@@ -1457,6 +1599,10 @@ int main(int argc, char **argv)
uninstall + stop + start + enable + disable + enable_hotspot + uninstall + stop + start + enable + disable + enable_hotspot +
disable_hotspot + restart + enable_p2p + disable_p2p + list_p2p_channels + disable_hotspot + restart + enable_p2p + disable_p2p + list_p2p_channels +
fix_permissions + list_wifi_country_codes; fix_permissions + list_wifi_country_codes;
if (actionCount == 0 && portOption.length() != 0)
{
++actionCount;
}
if (actionCount > 1) if (actionCount > 1)
{ {
throw std::runtime_error("Please provide only one action."); throw std::runtime_error("Please provide only one action.");
@@ -1553,12 +1699,6 @@ int main(int argc, char **argv)
{ {
return ListP2PChannels(parser.Arguments()); return ListP2PChannels(parser.Arguments());
} }
if (portOption.size() != 0 && !install)
{
cout << "Error: -port option can only be specified with the -install option."
<< "\n";
exit(EXIT_FAILURE);
}
auto uid = getuid(); auto uid = getuid();
if (uid != 0 && !nosudo) if (uid != 0 && !nosudo)
@@ -1568,6 +1708,12 @@ int main(int argc, char **argv)
try try
{ {
if (portOption.length() != 0 && !install)
{
portOption = ProcessPortOption(portOption);
SetWebServerPort(portOption);
return EXIT_SUCCESS;
}
if (fix_permissions) if (fix_permissions)
{ {
FixPermissions(); FixPermissions();
@@ -1595,20 +1741,11 @@ int main(int argc, char **argv)
} }
} }
if (portOption == "") portOption = ProcessPortOption(portOption);
{
portOption = GetCurrentWebServicePort();
if (portOption == "")
{
portOption = "80";
}
}
if (portOption.find(':') == string::npos)
{
portOption = "0.0.0.0:" + portOption;
}
Install(prefix, portOption); Install(prefix, portOption);
FileSystemSync(); FileSystemSync();
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
+1 -1
View File
@@ -44,7 +44,7 @@ void Lv2PluginChangeMonitor::Shutdown()
{ {
terminateThread = true; terminateThread = true;
uint64_t val = 1; uint64_t val = 1;
write(shutdown_eventfd,(void*)&val, sizeof(val)); auto _ = write(shutdown_eventfd,(void*)&val, sizeof(val));
monitorThread->join(); monitorThread->join();
monitorThread = nullptr; monitorThread = nullptr;
close(shutdown_eventfd); close(shutdown_eventfd);
+33 -23
View File
@@ -24,25 +24,22 @@
#include "ss.hpp" #include "ss.hpp"
#include <stdexcept> #include <stdexcept>
#ifdef __linux__ #include <unistd.h> // for nice().
#include "unistd.h" // for nice()`
#endif
using namespace pipedal; using namespace pipedal;
static constexpr int EXPECTED_RT_THREAD_PRIORITY_MAX = 81; static constexpr int EXPECTED_RT_THREAD_PRIORITY_MAX = 95;
static constexpr int RT_AUDIO_THREAD_PRIORITY = 80; static constexpr int RT_AUDIO_THREAD_PRIORITY = 90; // one above pipewire.
static constexpr int NICE_AUDIO_THREAD_PRIORITY = -19;
static constexpr int RT_AUDIOSERVICE_THREAD_PRIORITY = 10; static constexpr int RT_AUDIOSERVICE_THREAD_PRIORITY = 85; // one above pipewire service thread
static constexpr int NICE_AUDIOSERVICE_THREAD_PRIORITY = -17;
static constexpr int RT_LV2SCHEDULER_THREAD_PRIORITY = -1; static constexpr int RT_LV2SCHEDULER_THREAD_PRIORITY = 5;
static constexpr int NICE_LV2SCHEDULER_THREAD_PRIORITY = 2; // nice(2): don't let plugins screw things up by pinning the CPU
static constexpr int RT_WEBSERVER_THREAD_PRIORITY = -1; static constexpr int RT_WEBSERVER_THREAD_PRIORITY = -1;
static constexpr int NICE_WEBSERVER_THREAD_PRIORITY = -2; // don't get bogged down by UI threads.
static constexpr int NICE_WEBSERVER_PROCESS_PRIORITY = -9; // above chrome renderer, below pipewire..
bool pipedal::IsRtPreemptKernel(SchedulerPriority priority) bool pipedal::IsRtPreemptKernel(SchedulerPriority priority)
{ {
@@ -71,7 +68,7 @@ bool pipedal::IsRtPreemptKernel(SchedulerPriority priority)
#endif #endif
} }
static void SetPriority(int realtimePriority, int nicePriority, const char *priorityName) static void SetPriority(int realtimePriority, const char *priorityName)
{ {
if (realtimePriority != -1) if (realtimePriority != -1)
@@ -79,12 +76,20 @@ static void SetPriority(int realtimePriority, int nicePriority, const char *prio
int initialPriority = realtimePriority; int initialPriority = realtimePriority;
int min = sched_get_priority_min(SCHED_RR); int min = sched_get_priority_min(SCHED_RR);
int max = sched_get_priority_max(SCHED_RR); int max = sched_get_priority_max(SCHED_RR);
if (max > EXPECTED_RT_THREAD_PRIORITY_MAX)
{
max = EXPECTED_RT_THREAD_PRIORITY_MAX;
}
if (realtimePriority > max) { if (realtimePriority > max) {
realtimePriority = max + EXPECTED_RT_THREAD_PRIORITY_MAX-realtimePriority; realtimePriority = max + EXPECTED_RT_THREAD_PRIORITY_MAX-realtimePriority;
} }
if (realtimePriority < min) { if (realtimePriority < min) {
realtimePriority = min; realtimePriority = min;
} }
if (realtimePriority < 1)
{
realtimePriority = 1;
}
if (initialPriority != realtimePriority) if (initialPriority != realtimePriority)
{ {
Lv2Log::warning( Lv2Log::warning(
@@ -104,15 +109,9 @@ static void SetPriority(int realtimePriority, int nicePriority, const char *prio
} }
else else
{ {
Lv2Log::debug(SS("Failed to set RT thread priority for " << priorityName << " (" << strerror(result) << ")")); Lv2Log::warning(SS("Failed to set RT thread priority for " << priorityName << " (" << strerror(result) << ")"));
} }
} }
// If the RT scheduler isn't working, fall back to using NICE priority.
int result = nice(nicePriority);
if (result == -1)
{
Lv2Log::error(SS("Failed to set thread priority. (" << priorityName << ")"));
}
} }
void pipedal::SetThreadPriority(SchedulerPriority priority) void pipedal::SetThreadPriority(SchedulerPriority priority)
@@ -122,16 +121,27 @@ void pipedal::SetThreadPriority(SchedulerPriority priority)
switch (priority) switch (priority)
{ {
case SchedulerPriority::RealtimeAudio: case SchedulerPriority::RealtimeAudio:
SetPriority(RT_AUDIO_THREAD_PRIORITY, NICE_AUDIO_THREAD_PRIORITY, "RealtimeAudio"); SetPriority(RT_AUDIO_THREAD_PRIORITY, "RealtimeAudio");
break; break;
case SchedulerPriority::AudioService: case SchedulerPriority::AudioService:
SetPriority(RT_AUDIOSERVICE_THREAD_PRIORITY, NICE_AUDIOSERVICE_THREAD_PRIORITY, "AudioService"); SetPriority(RT_AUDIOSERVICE_THREAD_PRIORITY, "AudioService");
break; break;
case SchedulerPriority::Lv2Scheduler: case SchedulerPriority::Lv2Scheduler:
SetPriority(RT_LV2SCHEDULER_THREAD_PRIORITY, NICE_LV2SCHEDULER_THREAD_PRIORITY, "Lv2Scheduler"); SetPriority(RT_LV2SCHEDULER_THREAD_PRIORITY, "Lv2Scheduler");
break; break;
case SchedulerPriority::WebServerThread: case SchedulerPriority::WebServerThread:
SetPriority(RT_WEBSERVER_THREAD_PRIORITY, NICE_WEBSERVER_THREAD_PRIORITY, "Lv2Scheduler"); {
// do this by boosting the process priority
int currentNiceValue = nice(0);
if (currentNiceValue != NICE_WEBSERVER_PROCESS_PRIORITY)
{
errno = 0;
int ret = nice(NICE_WEBSERVER_PROCESS_PRIORITY-currentNiceValue);
if (ret == -1 && errno != 0) {
Lv2Log::error("Failed to set process nice value.");
}
}
}
break; break;
default: default:
Lv2Log::error("Invalid scheduler priority."); Lv2Log::error("Invalid scheduler priority.");
-1
View File
@@ -39,7 +39,6 @@
#include <lv2/lv2plug.in/ns/ext/worker/worker.h> #include <lv2/lv2plug.in/ns/ext/worker/worker.h>
#include "Lv2Log.hpp" #include "Lv2Log.hpp"
#include <iostream> #include <iostream>
#include <unistd.h> // for nice(
#include <utility> #include <utility>
#include "util.hpp" #include "util.hpp"
#include "SchedulerPriority.hpp" #include "SchedulerPriority.hpp"