diff --git a/UI/CMakeLists.txt b/UI/CMakeLists.txt index 256bb6646..1206f2bef 100644 --- a/UI/CMakeLists.txt +++ b/UI/CMakeLists.txt @@ -132,6 +132,11 @@ elseif(UNIX) set(obs_PLATFORM_LIBRARIES Qt5::X11Extras) + + if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") + list(APPEND obs_PLATFORM_LIBRARIES + procstat) + endif() endif() if(BROWSER_AVAILABLE_INTERNAL) diff --git a/UI/obs-app.cpp b/UI/obs-app.cpp index bc0fcabc4..93098fa11 100644 --- a/UI/obs-app.cpp +++ b/UI/obs-app.cpp @@ -1950,6 +1950,8 @@ static int run_program(fstream &logFile, int argc, char *argv[]) CheckAppWithSameBundleID(already_running); #elif defined(__linux__) RunningInstanceCheck(already_running); +#elif defined(__FreeBSD__) || defined(__DragonFly__) + PIDFileCheck(already_running); #endif if (!already_running) { diff --git a/UI/platform-x11.cpp b/UI/platform-x11.cpp index f74e0f43b..dd4a9c321 100644 --- a/UI/platform-x11.cpp +++ b/UI/platform-x11.cpp @@ -35,6 +35,17 @@ #include #include #endif +#if defined(__FreeBSD__) || defined(__DragonFly__) +#include +#include +#include +#include +#include + +#include +#include +#include +#endif using namespace std; @@ -90,6 +101,75 @@ void RunningInstanceCheck(bool &already_running) fclose(fp); } #endif +#if defined(__FreeBSD__) || defined(__DragonFly__) +struct RunOnce { + std::thread thr; + static const char *thr_name; + std::condition_variable cv; + std::condition_variable wait_cv; + std::mutex mtx; + bool exiting = false; + bool name_changed = false; + + void thr_proc() + { + std::unique_lock lk(mtx); + pthread_setname_np(pthread_self(), thr_name); + name_changed = true; + wait_cv.notify_all(); + cv.wait(lk, [this]() { return exiting; }); + } + + ~RunOnce() + { + if (thr.joinable()) { + std::unique_lock lk(mtx); + exiting = true; + cv.notify_one(); + lk.unlock(); + thr.join(); + } + } +} RO; +const char *RunOnce::thr_name = "OBS runonce"; + +void PIDFileCheck(bool &already_running) +{ + std::string tmpfile_name = + "/tmp/obs-studio.lock." + to_string(geteuid()); + int fd = open(tmpfile_name.c_str(), O_RDWR | O_CREAT | O_EXLOCK, 0600); + if (fd == -1) { + already_running = true; + return; + } + + already_running = false; + + procstat *ps = procstat_open_sysctl(); + unsigned int count; + auto procs = procstat_getprocs(ps, KERN_PROC_UID | KERN_PROC_INC_THREAD, + geteuid(), &count); + for (unsigned int i = 0; i < count; i++) { + if (!strncmp(procs[i].ki_tdname, RunOnce::thr_name, + sizeof(procs[i].ki_tdname))) { + already_running = true; + break; + } + } + procstat_freeprocs(ps, procs); + procstat_close(ps); + + RO.thr = std::thread(std::mem_fn(&RunOnce::thr_proc), &RO); + + { + std::unique_lock lk(RO.mtx); + RO.wait_cv.wait(lk, []() { return RO.name_changed; }); + } + + unlink(tmpfile_name.c_str()); + close(fd); +} +#endif static inline bool check_path(const char *data, const char *path, string &output) diff --git a/UI/platform.hpp b/UI/platform.hpp index f8717cb43..7e7d47ed1 100644 --- a/UI/platform.hpp +++ b/UI/platform.hpp @@ -73,3 +73,6 @@ void CheckAppWithSameBundleID(bool &already_running); #ifdef __linux__ void RunningInstanceCheck(bool &already_running); #endif +#if defined(__FreeBSD__) || defined(__DragonFly__) +void PIDFileCheck(bool &already_running); +#endif