Files
Toastconcern--FrameStudio/src/proc_util.h
T
ToastconcernandClaude Opus 5.5 f7345a5ac3 Frame Studio and Frame Home: cross-platform builds
Frame Studio now builds for Windows (x64, x86, ARM64), Linux (x64, x86, ARM64)
and macOS (Apple Silicon, Intel):
- studio/platform.h with Win32 and POSIX implementations (dialogs through
  tinyfiledialogs on Linux/macOS), a GLFW window beside the Win32 one, and a
  platform-neutral frame pacer
- MoltenVK support in the renderer (portability enumeration) and bundled in
  the macOS app
- 32-bit builds: large-address-aware, LZMA packing within a 32-bit address space
- unaligned file reads in the loaders go through loadUnaligned (no UB)
- scripts/build-studio.sh, studio/build_windows.bat [x64|x86|arm64],
  cmake/llvm-mingw.cmake, and a GitHub Actions workflow building every target

Frame Home installs without Studio: frame/install-frame-home.{sh,ps1} and
"Install Frame Home.bat" (packaged as FrameHome-installer.zip).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 12:03:25 -05:00

64 lines
2.6 KiB
C++

#pragma once
// Running copies of a Frame program, for the installers. SteamVR's own bookkeeping (GetApplicationProcessId) loses
// track of an app once a utility process started from the same binary has connected, so look at /proc instead.
#include <signal.h>
#include <unistd.h>
#include <filesystem>
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
// Processes named `name` running without arguments: the environment / the panel, not tools (--snapshot, --list).
inline std::vector<pid_t> runningCopies(const char* name) {
std::vector<pid_t> out;
std::error_code ec;
for (const auto& e : std::filesystem::directory_iterator("/proc", ec)) {
const std::string id = e.path().filename().string();
if (id.empty() || id.find_first_not_of("0123456789") != std::string::npos) continue;
const pid_t pid = static_cast<pid_t>(std::stol(id));
if (pid == getpid()) continue;
std::string comm;
std::getline(std::ifstream(e.path() / "comm"), comm);
if (comm != name) continue;
std::ifstream c(e.path() / "cmdline", std::ios::binary);
const std::string cmd((std::istreambuf_iterator<char>(c)), std::istreambuf_iterator<char>());
size_t args = 0;
for (char ch : cmd) args += ch == '\0';
if (args <= 1) out.push_back(pid);
}
return out;
}
// Asks them to quit, then insists after 5 s.
// Running copies of `name` (other than this process) started with `arg` among their arguments.
inline std::vector<pid_t> runningWith(const char* name, const std::string& arg) {
std::vector<pid_t> out;
std::error_code ec;
for (const auto& e : std::filesystem::directory_iterator("/proc", ec)) {
const std::string id = e.path().filename().string();
if (id.empty() || id.find_first_not_of("0123456789") != std::string::npos) continue;
const pid_t pid = static_cast<pid_t>(std::stol(id));
if (pid == getpid()) continue;
std::string comm;
std::getline(std::ifstream(e.path() / "comm"), comm);
if (comm != name) continue;
std::ifstream c(e.path() / "cmdline", std::ios::binary);
for (std::string a; std::getline(c, a, '\0');) if (a == arg) { out.push_back(pid); break; }
}
return out;
}
inline void stopCopies(const char* name) {
const std::vector<pid_t> pids = runningCopies(name);
for (pid_t p : pids) kill(p, SIGTERM);
for (int i = 0; i < 50; ++i) {
bool alive = false;
for (pid_t p : pids) alive |= kill(p, 0) == 0;
if (!alive) return;
usleep(100000);
}
for (pid_t p : pids) kill(p, SIGKILL);
}