makepidfile-daemon-unix

复制代码
static int
lock_pidfile__(FILE *file, int command, struct flock *lck)
{
    int error;

    lck->l_type = F_WRLCK;
    lck->l_whence = SEEK_SET;
    lck->l_start = 0;
    lck->l_len = 0;
    lck->l_pid = 0;

    do {
        error = fcntl(fileno(file), command, lck) == -1 ? errno : 0;
    } while (error == EINTR);
    return error;
}

static int
lock_pidfile(FILE *file, int command)
{
    struct flock lck;

    return lock_pidfile__(file, command, &lck);
}
static void
make_pidfile(void)
{
    long int pid = getpid();
    struct stat s;
    char *tmpfile;
    FILE *file;
    int error;

    /* Create a temporary pidfile. */
  
    tmpfile = xasprintf("%s.tmp", pidfile);
 

    file = fopen(tmpfile, "a+");
    if (!file) {
        log("%s: create failed (%s)", tmpfile, ovs_strerror(errno));
    }

    error = lock_pidfile(file, F_SETLK);
    if (error) {
        /* Looks like we failed to acquire the lock.  Note that, if we failed
         * for some other reason (and '!overwrite_pidfile'), we will have
         * left 'tmpfile' as garbage in the file system. */
        VLOG_FATAL("%s: fcntl(F_SETLK) failed (%s)", tmpfile,
                   ovs_strerror(error));
    }

    /* We acquired the lock.  Make sure to clean up on exit, and verify
         * that we're allowed to create the actual pidfile. */
    fatal_signal_add_file_to_unlink(tmpfile);
    check_already_running();
  

    if (fstat(fileno(file), &s) == -1) {
        VLOG_FATAL("%s: fstat failed (%s)", tmpfile, ovs_strerror(errno));
    }

    if (ftruncate(fileno(file), 0) == -1) {
        VLOG_FATAL("%s: truncate failed (%s)", tmpfile, ovs_strerror(errno));
    }

    fprintf(file, "%ld\n", pid);
    if (fflush(file) == EOF) {
        VLOG_FATAL("%s: write failed (%s)", tmpfile, ovs_strerror(errno));
    }

    error = rename(tmpfile, pidfile);

    /* Due to a race, 'tmpfile' may be owned by a different process, so we
     * shouldn't delete it on exit. */
    fatal_signal_remove_file_to_unlink(tmpfile);

    if (error < 0) {
        VLOG_FATAL("failed to rename \"%s\" to \"%s\" (%s)",
                   tmpfile, pidfile, ovs_strerror(errno));
    }

    /* Ensure that the pidfile will get deleted on exit. */
    fatal_signal_add_file_to_unlink(pidfile);

    /* Clean up.
     *
     * We don't close 'file' because its file descriptor must remain open to
     * hold the lock. */
    pidfile_dev = s.st_dev;
    pidfile_ino = s.st_ino;
    free(tmpfile);
}
复制代码
复制代码
daemonize_start(bool access_datapath)
#endif
{
    assert_single_threaded();
    daemonize_fd = -1;

#ifndef OPS
    if (switch_user) {
        daemon_become_new_user__(access_datapath);
        switch_user = false;
    }
#endif

    if (detach) {
        pid_t pid;

        if (fork_and_wait_for_startup(&daemonize_fd, &pid)) {
            VLOG_FATAL("could not detach from foreground session");
        }
        if (pid > 0) {
            /* Running in parent process. */
            exit(0);
        }

        /* Running in daemon or monitor process. */
        setsid();
    }

    if (monitor) {
        int saved_daemonize_fd = daemonize_fd;
        pid_t daemon_pid;

        if (fork_and_wait_for_startup(&daemonize_fd, &daemon_pid)) {
            VLOG_FATAL("could not initiate process monitoring");
        }
        if (daemon_pid > 0) {
            /* Running in monitor process. */
            fork_notify_startup(saved_daemonize_fd);
            close_standard_fds();
            monitor_daemon(daemon_pid);
        }
        /* Running in daemon process. */
    }

    forbid_forking("running in daemon process");

    if (pidfile) {
        make_pidfile();
    }

    /* Make sure that the unixctl commands for vlog get registered in a
     * daemon, even before the first log message. */
    vlog_init();
}
复制代码

这份代码是标准的守护进程的写法:

fork---fork_and_wait_for_startup(子进程先起来)-----setsid()终端控制分离-----fork---fork_and_wait_for_startup(进程先起来)--- fork_notify_startup(saved_daemonize_fd);通知主进程

通知方法其实就是:一开始创建管道pipe; 父进程阻塞的读, 等待子进程执行完后写fd 让父进程唤醒

 

 

makepid:就是防止进程启动多个副本。通过文件锁,可以保证一时间内只有一个进程能持有这个文件的写权限,所以在程序启动的检测逻辑中加入获取pid 文件锁并写pid文件的逻辑就可以防止重复启动进程的多个副本了

 

复制代码
static int
lock_pidfile__(FILE *file, int command, struct flock *lck)
{
    int error;

    lck->l_type = F_WRLCK;
    lck->l_whence = SEEK_SET;
    lck->l_start = 0;
    lck->l_len = 0;
    lck->l_pid = 0;

    do {
        error = fcntl(fileno(file), command, lck) == -1 ? errno : 0;
    } while (error == EINTR);
    return error;
}
//核心逻辑
复制代码

 

觉得这套代码比较经典就记录保存起来

posted @   codestacklinuxer  阅读(235)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示