OpenCPN Partial API docs
Loading...
Searching...
No Matches
std_instance_chk.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2023 Alec Leamas *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/ *
16 **************************************************************************/
17
24#ifdef _WIN32
25#include <winsock2.h>
26#include <windows.h>
27#elif defined(__APPLE__)
28#include <errno.h>
29#include <libproc.h>
30#endif
31
32#include <chrono>
33#include <cstdio>
34#include <fstream>
35#include <sstream>
36#include <thread>
37
38#ifdef HAVE_UNISTD_H
39#include <signal.h>
40#include <unistd.h>
41#endif
42
43#include <wx/string.h>
44
45#include "model/base_platform.h"
46#include "model/ocpn_utils.h"
47
49#include "std_filesystem.h"
50
51static const char* const kName = "_OpenCPN_SILock";
52
53static int GetLockfilePid(const std::string& path) {
54 std::ifstream f(path.c_str());
55 std::stringstream ss;
56 ss << f.rdbuf();
57 int pid = -1;
58 try {
59 ss >> pid;
60 } catch (...) {
61 pid = -1;
62 }
63 return pid;
64}
65
66static bool DoesProcessExist(int pid) {
67#ifdef _WIN32
68 HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, static_cast<DWORD>(pid));
69 DWORD ret = WaitForSingleObject(process, 0);
70 CloseHandle(process);
71 return ret == WAIT_TIMEOUT;
72#elif defined(__APPLE__)
73 char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
74 bool is_active;
75 int rv = proc_pidpath(pid, pathbuf, sizeof(pathbuf));
76 return true;
77#else
78 int rv = kill(pid, 0);
79 return rv == 0 || errno != ESRCH;
80#endif
81}
82
83static int GetPid() {
84#ifdef _WIN32
85 return _getpid();
86#else
87 return getpid();
88#endif
89}
90
91StdInstanceCheck::StdInstanceCheck()
92 : m_is_main_instance(false), is_inited(false), is_my_lock(false) {}
93
94void StdInstanceCheck::Init() {
95 m_path = g_BasePlatform->GetPrivateDataDir().ToStdString();
96 m_path /= kName;
97 for (int i = 0; i < 5; i += 1) {
98 std::FILE* f = std::fopen(m_path.generic_u8string().c_str(), "wx");
99 if (f) {
100 std::stringstream ss;
101 ss << getpid() << "\n";
102 std::fputs(ss.str().c_str(), f);
103 fclose(f);
104 m_is_main_instance = true;
105 is_my_lock = true;
106 break;
107 }
108 if (i >= 2) {
109 wxLogDebug("Removing unusable lock file");
110 fs::remove(m_path); // unusable
111 continue;
112 }
113 int pid = -1;
114 try {
115 std::ifstream stream(m_path);
116 stream >> pid;
117 } catch (...) {
118 // Handle race conditions: other process creates lock
119 using namespace std::chrono;
120 std::this_thread::sleep_for(50ms);
121 continue;
122 }
123 if (pid == GetPid()) {
124 m_is_main_instance = true;
125 break;
126 }
127 if (pid != -1 && !DoesProcessExist(pid)) {
128 wxLogDebug("Removing orphaned lock for pid: %d", pid);
129 fs::remove(m_path);
130 }
131 if (pid != -1 && fs::exists(m_path)) break;
132 };
133 is_inited = true;
134}
135
137 if (!is_inited) Init();
138 return m_is_main_instance;
139}
140
142 if (!is_inited && g_BasePlatform) Init();
143 if (fs::exists(m_path)) fs::remove(m_path);
144}
145
146StdInstanceCheck::~StdInstanceCheck() {
147 if (fs::exists(m_path) && is_my_lock) fs::remove(m_path);
148}
BasePlatform * g_BasePlatform
points to g_platform, handles brain-dead MS linker.
Basic platform specific support utilities without GUI deps.
wxString & GetPrivateDataDir()
Return dir path for opencpn.log, etc., respecting -c cli option.
bool IsMainInstance() override
Return true if this process is the primary opencpn instance.
void CleanUp() override
Remove all persistent instance state, including possible lock file and defunct opencpn processes.
Miscellaneous utilities, many of which string related.
Posix native instance check implementation.