#include <sys/types.h> // 提供 pid_t 类型定义
#include <sys/stat.h> // 提供 umask 函数
#include <sys/wait.h> // 提供 waitpid 函数
#include <fcntl.h> // 提供 open 和 lockf 函数
#include <signal.h> // 提供信号处理函数和类型定义
#include <unistd.h> // 提供 fork、setsid、chdir、dup2、close、write 等函数
#include <time.h> // 提供 time、timespec、difftime 等函数
#include <errno.h> // 提供 errno 定义
#include <cstring> // 提供 strerror 函数
#include <iostream> // 提供标准输入输出流(用于日志记录)
#include <string> // 提供 std::string 类
#include <array> // 提供 std::array 容器
void Daemonize(const std::string& pid_file)
{
std::cout << "Starting daemonization" << std::endl;
pid_t pid = 0;
pid_t original_pid = getpid();
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigprocmask(SIG_BLOCK, &mask, nullptr);
if ((pid = fork()) < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid > 0) {
constexpr int timeout_val = 5;
struct timespec timeout { timeout_val, 0 };
const time_t start = time(nullptr);
siginfo_t info;
do {
const int signum = sigtimedwait(&mask, &info, &timeout);
if (signum == SIGUSR1 && info.si_signo == SIGUSR1 && info.si_pid == pid) {
waitpid(pid, nullptr, 0);
std::cout << "Finished daemonization" << std::endl;
exit(EXIT_SUCCESS);
}
if (signum == -1 && errno == EAGAIN) {
break; // timed out
}
timeout.tv_sec = timeout_val - difftime(time(nullptr), start); // avoid potentially endless loop
}
while (true);
std::cerr << "Waiting on pid file write timeout!" << std::endl;
exit(EXIT_FAILURE);
}
// Now we are forked
if (setsid() < 0) {
perror("setsid");
exit(EXIT_FAILURE);
}
signal(SIGCHLD, SIG_IGN);
int pid_fd = open(pid_file.c_str(), O_RDWR | O_CREAT, 0640);
if (pid_fd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
if (lockf(pid_fd, F_TLOCK, 0) < 0) {
perror("lockf");
exit(EXIT_FAILURE);
}
if ((pid = fork()) < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid > 0) {
try {
std::string pid_str = std::to_string(pid);
if (write(pid_fd, pid_str.c_str(), pid_str.size()) != static_cast<ssize_t>(pid_str.size())) {
perror("write");
kill(pid, SIGKILL);
exit(EXIT_FAILURE);
}
kill(original_pid, SIGUSR1);
exit(EXIT_SUCCESS);
}
catch (...) {
kill(pid, SIGKILL);
throw;
}
}
// Now we are forked 2nd time
umask(0047); // no need for world-accessible or executable files
chdir("/");
const std::array<int, 3> std_fds {{STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}};
int fd_null = open("/dev/null", O_RDWR);
if (fd_null < 0) {
perror("open /dev/null");
exit(EXIT_FAILURE);
}
// We do not need to close all fds because there is only logging open at this point
for (auto fd : std_fds) {
close(fd);
if (dup2(fd_null, fd) < 0) {
perror("dup2");
exit(EXIT_FAILURE);
}
}
close(fd_null);
if (lockf(pid_fd, F_LOCK, 0) < 0) {
perror("lockf");
exit(EXIT_FAILURE);
}
}
将当前进程转换为守护进程(c++)
最新推荐文章于 2024-09-01 16:42:17 发布