Skip to content

Commit 575f206

Browse files
authored
feat: add single instance lock mechanism for fcitx5-helper (#105)
- Implement setSingleInstance() function to prevent multiple instances per user - Add lock file management with proper cleanup on exit and signal handling - Include signal handler cleanup for lock file when receiving SIGTERM from init Log: add single instance lock mechanism for fcitx5-helper
1 parent d5d402e commit 575f206

1 file changed

Lines changed: 62 additions & 2 deletions

File tree

src/fcitx5helper/main.cpp

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,61 @@
77
Q_LOGGING_CATEGORY(fcitx5Helper, "fcitx5.helper")
88

99
#include <QCoreApplication>
10+
#include <QDir>
11+
#include <QLockFile>
12+
#include <QScopedPointer>
13+
#include <unistd.h>
1014

1115
#include <signal.h>
1216

17+
static QScopedPointer<QLockFile> g_lockFile;
18+
19+
// Extract from DGuiApplicationHelper::setSingleInstance (UserScope only)
20+
static bool setSingleInstance() {
21+
QString socket_key = "_fcitx5_single_instance_";
22+
socket_key += QString("%1_").arg(getuid());
23+
socket_key += QString("fcitx5-helper");
24+
25+
QString lockfile = socket_key;
26+
if (!lockfile.startsWith(QLatin1Char('/'))) {
27+
lockfile = QDir::cleanPath(QDir::tempPath());
28+
lockfile += QLatin1Char('/') + socket_key;
29+
qCDebug(fcitx5Helper) << "lockfile:" << lockfile;
30+
}
31+
lockfile += QStringLiteral(".lock");
32+
33+
qint64 pid = -1;
34+
QString hostname, appname;
35+
if (!g_lockFile.isNull() && g_lockFile->isLocked() && g_lockFile->getLockInfo(&pid, &hostname, &appname) && pid == getpid()) {
36+
qCWarning(fcitx5Helper) << "call setSingleInstance again within the same process";
37+
g_lockFile->unlock();
38+
g_lockFile.reset();
39+
qCDebug(fcitx5Helper) << "unlock lock file";
40+
}
41+
42+
// Create new lock file
43+
g_lockFile.reset(new QLockFile(lockfile));
44+
45+
// Try to lock
46+
if (!g_lockFile->tryLock()) {
47+
qCInfo(fcitx5Helper) << "fcitx5-helper instance already exists for current user, exiting";
48+
return false;
49+
}
50+
51+
qCDebug(fcitx5Helper) << "Created lock file:" << lockfile;
52+
return true;
53+
}
54+
1355
static void signal_callback_handler(int signum, siginfo_t *siginfo, void *context) {
1456
Q_UNUSED(context)
1557
qCDebug(fcitx5Helper) << "Received signal:" << signum << "from pid:" << (long)siginfo->si_pid;
1658
if (signum == SIGTERM && (long)siginfo->si_pid == 1) {
1759
qCInfo(fcitx5Helper) << "Terminating fcitx5 processes due to SIGTERM from init";
60+
// Clean up lock file
61+
if (!g_lockFile.isNull() && g_lockFile->isLocked()) {
62+
qCInfo(fcitx5Helper) << "unlock lock file";
63+
g_lockFile->unlock();
64+
}
1865
QString output, error;
1966
ProcessMonitor::exeCommand("pidof fcitx5 | xargs kill -9", QStringList(), output, error);
2067
qCDebug(fcitx5Helper) << "Command output:" << output << "Error:" << error;
@@ -23,7 +70,7 @@ static void signal_callback_handler(int signum, siginfo_t *siginfo, void *contex
2370
}
2471

2572
static void setupSignalHandler() {
26-
//进城被init杀死,视为关机
73+
//进程被init杀死,视为关机
2774
struct sigaction act;
2875
memset(&act, 0, sizeof(act));
2976
act.sa_sigaction = &signal_callback_handler;
@@ -34,11 +81,24 @@ static void setupSignalHandler() {
3481
int main(int argc, char *argv[])
3582
{
3683
qCInfo(fcitx5Helper) << "Starting fcitx5 helper process";
84+
// Check single instance for current user
85+
if (!setSingleInstance()) {
86+
qCInfo(fcitx5Helper) << "fcitx5-helper already running";
87+
return 0;
88+
}
3789
QCoreApplication app(argc, argv);
3890

91+
// Register cleanup function to unlock on exit
92+
QObject::connect(&app, &QCoreApplication::aboutToQuit, []() {
93+
if (!g_lockFile.isNull() && g_lockFile->isLocked()) {
94+
qCInfo(fcitx5Helper) << "unlock lock file";
95+
g_lockFile->unlock();
96+
}
97+
});
98+
3999
qCDebug(fcitx5Helper) << "Setting up signal handlers";
40100
setupSignalHandler();
41-
101+
42102
qCDebug(fcitx5Helper) << "Initializing process monitor";
43103
ProcessMonitor monitor;
44104
monitor.startMonitoring();

0 commit comments

Comments
 (0)