LINUX USB 多串口通讯之四: 单守护进程及写系统日志

目的:守护进程及相关信息写入系统日志

硬件: RPI 3B+, NORDIC nRF52840 USB Dongle

系统: Linux raspberrypi 4.19.118-v7+  

说明: 参考 UNIX 高级环境编程样例实现 (UNIX 高级环境编程(第3版) 书中源码下载地址http://www.apuebook.com/src.3e.tar.gz)


文件: ttyacm-daemon-init.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <syslog.h>
#include <string.h>
#include <pthread.h>
#include <sys/resource.h>
#include <unistd.h>

#include "ttyacm-check.h"

#define LOCKFILE_TTYACM "/var/run/ttyacm-daemon.pid"
#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)

static int daemon_lockfile(int fd)
{
    struct flock fl;

    fl.l_type   = F_WRLCK;
    fl.l_start  = 0;
    fl.l_whence = SEEK_SET;
    fl.l_len    = 0;

    return( fcntl(fd, F_SETLK, &fl) );
}


static int daemon_already_running(void)
{
    int     fd;
    char    buf[16];

    fd = open( LOCKFILE_TTYACM, O_RDWR|O_CREAT, LOCKMODE );
    if ( fd < 0 )
    {
        //syslog( LOG_ERR, "can't open %s: %s", LOCKFILE_TTYACM, strerror(errno) );
        return -1;
    }


    if ( daemon_lockfile(fd) < 0 )
    {
        if ( errno == EACCES || errno == EAGAIN ) {
            close(fd);
            return -1;
        }
      //  syslog(LOG_ERR, "can't lock %s: %s", LOCKFILE_TTYACM, strerror(errno));
        return -1;
    }

    if ( ftruncate(fd,0) < 0)
        return -1;

    if ( sprintf(buf, "%ld", (long)getpid()) <= 0 )
        return -1;

    if ( write(fd, buf, strlen(buf)+1) < 0 )
        return -1;

    return(0);
}


static int thread_ttyacm_check(void)
{
    pthread_t   tid;
    int err = pthread_create( &tid,NULL,ttyacm_check,NULL );
    if ( err )
        return -1;

    pthread_join( tid,NULL );

    return 0;
}

int ttyacm_daemon_init(void)
{
    int    pid;
    struct sigaction    sa;

    /* Clear file creation mask */
    umask(0);

    /* Become a session leader to lose controlling TTY  */
    if ( (pid=fork()) < 0 )     // fork error
        return -1;
    else if ( pid != 0 )        // parent process
    {
        closelog();
        exit(0);
    }

    /* new session, child process */
    setsid();

    /* Ensure future opens won't allocate controlling TTYs. */
    sa.sa_handler = SIG_IGN;
    sigemptyset( &sa.sa_mask );
    sa.sa_flags = 0;
    if ( sigaction(SIGHUP, &sa, NULL) < 0 )
        return -1;

    /*
     * second fork, rebuild a child process and quit its parent process,
     * to avoid to open a new terminal again
     */

    if ( (pid=fork()) < 0 )     // fork error
        return -1;
    else if ( pid != 0 )
    {
        closelog();
        exit(0);
    }
#if 0
    /* Get maximum number of file descriptors  */

    struct rlimit       rl;
    if ( getrlimit(RLIMIT_NOFILE,&rl) < 0 )
        return -1;

    if ( rl.rlim_max == RLIM_INFINITY )
        rl.rlim_max = 1024;

    int i;
    for ( i=0; i<rl.rlim_max; i++ )
    {
        if ( close(i) < 0 )
            return -1;
    }
#endif

    // close std file descriptions from parent process
    int fd = open( "/dev/null",O_RDWR );
    if ( fd < 0 )
        return -1;

    dup2( fd,0 );
    dup2( fd,1 );
    dup2( fd,2 );

    if ( fd > 2 )
    {
        if ( close(fd) < 0 )
            return -1;
    }

    // change work directory to root to cut the connection of file system
    chdir( "/" );

#if 0
    if ( daemon(0,0) )      // daemon() equals close() + chdir()
    {
        syslog( LOG_ERR,"close(fd) or chdir() Err,%s.",strerror(errno) );
        return -1;
    }
#endif

    if ( daemon_already_running() )
    {
        return -1;
    }

    syslog( LOG_INFO,"TTYACM-DAEMON-INIT SUCCESS!" );

    /* call ttyacm-operation-pthread */
    if ( thread_ttyacm_check() )
        return -1;

    return 0;
}




              

单守护进程相关要点:

1. 调用 unmask(0) 将文件创建屏蔽字清零;

2. 让程序在后台执行; 调用 fork() 产生一个子进程,然后使父进程退出;

3. 调用 setsid() 创建一个新会话期; 子进程成为新的会话组长和进程组长,并与原来的登录会话、进程组和控制终端脱离;

4. 屏蔽所有 signal 信号影响;

5. 禁止进程重新打开控制终端; 再一次调用 fork() 创建新的子进程,并使第一次调用 fork() 产生的子进程退出;

6. 关闭不再需要的文件描述符;

7. 标准输入输入 stdin,stdout,stderr 批向 /dev/null;

8. 将当前目录更改为根目录;


单守护进程锁文件

此文件存储于 /var/run 目录, 通常全名为 name.pid, name 是对应的守护进程或服务名字, 文件为 root / root 权限. 文件内容是: 对应守护进程的 pid . 


守护进程配置文件

此文件存储于 /etc 目录, 通常全名为 name.conf, name 是对应的守护进程或服务名字, 文件为 root / root 权限. 

* 于守护进程中,添加程序捕捉 SIGHUP 信号,可让程序重读配置文件,使配置文件更改生效。d


守护进程启动

* 守护进程可由命令行 shell 启动; 

* 通常由系统初始化脚本启动; ( /etc/rc* 或 /etc/init.d/* )

     比如: 于 rc.local 文件中,添加 /home/pi/ttyacm-daemon, 则开机启动守护进程;  

* 守护进程终止时,如需系统可自动重新启动它,则 在 /etc/inittab 中为该守护进程添加 repawn 记录j ;


查看系统日志

$ tail -F /var/log/syslog
$ journalctl -xe

查看系统守护进程

$ ps -axj | grep -v grep | grep ttyacm

查看进程中线程父子关系

$ pstree -a

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值