Chinaunix首页 | 论坛 | 博客
  • 博客访问: 58497
  • 博文数量: 8
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 88
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-13 16:18
个人简介

不积跬步无以至千里,不积小流无以成江河。

文章分类
文章存档

2014年(8)

我的朋友

分类: 其他UNIX

2014-11-12 19:37:32

有许多人可能以为直接fork个子进程把父进程结束了就可以生成一个守护进程,其实里面还有很多问题,下面的代码是依照APUE中的代码修改的。
注解中有很多自己遇到的关于SIGHUP信号处理,和setsid后为什么还要fork的理解。

头文件:

点击(此处)折叠或打开

  1. #ifndef __unix_test__daemon__
  2. #define __unix_test__daemon__


  3. extern void daemonize(void(*)(int));
  4. extern int already_open(int);
  5. extern int my_writelog(const char* pname,const char* str) ;
  6. extern int create_daemon(int (*daemon_handler)() , void (*sighup_handler)(int));
  7. #endif /* defined(__unix_test__daemon__) */

实现:

点击(此处)折叠或打开

  1. #include "daemon.h"

  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <pthread.h>
  5. #include <fcntl.h>
  6. #include <stdlib.h>
  7. #include <sys/resource.h>
  8. #include <signal.h>
  9. #include <sys/signal.h>
  10. #include <sys/stat.h>
  11. #include <string.h>
  12. #include <syslog.h>
  13. #include <sys/file.h>

  14. //守护进程注销
  15. int daemondestroy(){
  16.     return 0;
  17. }
  18. //重新加载配置文件
  19. int reread(){
  20.     return 0;
  21. }
  22. //get signal thread
  23. //argument : ptr is wait signal set.
  24. void * get_signal(void*ptr) {
  25.     sigset_t * wt = (sigset_t*)ptr;
  26.     int signo = 0 ;
  27.     int ret = 0;
  28.     
  29.     //wait signal is empty , process exit.(not thread exit)
  30.     if (!ptr || !(*wt) ) {
  31.         exit(0);
  32.     }
  33.     sigaddset(wt, SIGQUIT);
  34.     printf("wt %u\n",*wt);
  35.     while (1) {
  36.         sigwait(wt, &signo);
  37.         switch (signo) {
  38.             case SIGHUP:
  39.                 ret = reread();
  40.                 if (ret) {
  41.                     ret = my_writelog("unix_test","reread error");
  42.                 }
  43.                 break;
  44.             case SIGQUIT:
  45.                 ret = daemondestroy();
  46.                 if (ret) {
  47.                     ret = my_writelog("unix_test","daemon quit error");
  48.                 }
  49.                 exit(0);
  50.                 break;
  51.             default:
  52.                 break;
  53.         }
  54.     }
  55.     return (void*)5;
  56. }
  57. //write system log
  58. //return zero is success.
  59. int my_writelog(const char* pname,const char* str) {
  60.     if (!pname || !str) {
  61.         return 1;
  62.     }
  63.     openlog(pname,LOG_PID ,LOG_USER);
  64.     syslog(LOG_ERR, "info:{ %s %m.} \n",str);
  65.     closelog();
  66.     return 0;
  67. }
  68. //【daemon程序】守护进程
  69. //功能:
  70. //主线程:
  71. // 【阻塞】所有信号
  72. // 循环写test1.txt文件10000次
  73. //次线程:
  74. // 【开启】SIGHUP and SIGQUIT
  75. // 开辟另一个线程tid来处理信号,如果是SIGHUP就重新读取守护进程,SIGQUIT就退出守护进程

  76. int create_daemon(int (*daemon_handler)() , void (*sighup_handler)(int)){
  77.     int fd = 0;
  78.     pthread_t tid;
  79.     sigset_t wt,set,save;
  80.     int ret = 0;
  81.     
  82.     //NOTE:
  83.     //SIGHUP is sighup_handler , close all file descriptor
  84.     //1. don't used already file descriptor.
  85.     //2. SIGHUP signal is not default.
  86.     daemonize(sighup_handler);
  87.     
  88.     
  89.     fd = open("./lock.txt",O_RDWR|O_CREAT, \
  90.              ((S_IRUSR)|(S_IWUSR)|(S_IRGRP)|(S_IROTH)));
  91.     if (fd < 0) {
  92.         char buf[1024] ={0};
  93.         sprintf(buf, "don't open file %5d ",fd);
  94.         my_writelog("unix_test", buf);
  95.         exit(0);
  96.     }
  97.     
  98.     if (already_open(fd)) {
  99.         my_writelog("unix_test", "don't second daemon");
  100.         exit(0);
  101.     }
  102.     
  103.     
  104.     sigfillset(&set);
  105.     sigemptyset(&wt);
  106.     sigemptyset(&save);
  107.     //daemon wait signal set.
  108.     sigaddset(&wt, SIGQUIT);
  109.     sigaddset(&wt, SIGHUP);
  110.     
  111.     ret = pthread_sigmask(SIG_BLOCK, &set, &save);
  112.     if (ret) {
  113.         return 1;
  114.     }
  115.     
  116.     ret = pthread_create(&tid, NULL, get_signal, &wt);
  117.     if (ret) {
  118.         return 1;
  119.     }
  120.     
  121.     ret = daemon_handler();
  122.     
  123.     
  124.     if (ret) {
  125.         return 1;
  126.     }
  127.     
  128.     //daemon exit clean.
  129.     
  130.     //igrone return value.
  131.     pthread_sigmask(SIG_SETMASK, &save, NULL);
  132.     
  133.     ret = pthread_cancel(tid);
  134.     if (ret) {
  135.         return 1;
  136.     }
  137.     //igrone return value.
  138.     pthread_join(tid, (void*)&wt);
  139.     close(fd);
  140.     return 0;
  141. }


  142. //return is success lock file, reutnr other file is locked.
  143. int already_open(int fd){
  144.     if (fd > 0) {
  145.         int m = flock(fd, LOCK_EX|LOCK_NB);
  146.         if ( m ) {
  147.             my_writelog("unix_test", "file is locked");
  148.         }else {
  149.             return 0;
  150.         }
  151.     }else {
  152.         my_writelog("unix_test", "file is open error");
  153.     }
  154.     return 1;
  155. }


  156. //让进程变成守护进程函数
  157. //当进程调用daemonize,此进程变成【守护进程】
  158. //1.修改文件屏蔽属性【防止改文件时候有屏蔽字不成功】创建文件rw-r--r--
  159. //2.把SIGHUP信号重定向到一个空函数,防止父进程退出,子进程收到SIGHUP
  160. // 【当父进程退出后子进程组变成孤儿进程组将收到SIGHUP和SIGCONT信号】,让子进程退出。
  161. //3.进程1 fork 进程2
  162. //4.进程2 setsid,setsid后进程成session leader 进程组长,没有控制终端
  163. //5.进程2 fork 进程3【守护进程】,
  164. // 此时为什么还要fork 进程3,因为进程2是session leader,是进程组组长可能还会获得控制终端
  165. //6.进程3【守护进程】是一个没有控制终端,也不是进程组长的进程【孤儿进程组中的孤儿进程】
  166. //7.进程3符合所有守护进程的条件,所以进程3才是最后的守护进程
  167. //8.关闭文件描述符【防止程序和终端连接】,写或读终端
  168. void daemonize(void (*sighup_handler)(int)){
  169.     int fd = 0 ;
  170.     int i = 0 ;
  171.     pid_t pid;
  172.     struct sigaction sa;
  173.     struct rlimit r;
  174.     
  175.     umask(0);
  176.     
  177.     sa.sa_flags = 0;
  178.     sigemptyset(&sa.sa_mask);
  179.     //这里忽略SIGHUP是防止进程2退出后给我们的守护进程发送SIGHUP信号
  180.     //但是这里如果忽略信号则在以后的sigwait中会丢失这个信号所以用一个空函数来处理这个信号
  181.     //sa.__sigaction_u.__sa_handler = SIG_IGN;
  182.     sa.__sigaction_u.__sa_handler = sighup_handler;
  183.     sigaction(SIGHUP, &sa, NULL);
  184.     
  185.     if ( 0 > (pid = fork())) {
  186.         exit(0);
  187.     }else if (0 != pid) {
  188.         exit(0);
  189.     }
  190.     
  191.     //if process isn't session leader
  192.     //1).become sessoin leader
  193.     //2).become team leader of new process group .
  194.     //3).terminate controlling terminal of the process.
  195.     setsid();
  196.     if ( 0 > (pid = fork())) {
  197.         exit(0);
  198.     }else if (0 != pid) {
  199.         exit(0);
  200.     }
  201.     getrlimit(RLIMIT_NOFILE, &r);
  202.     
  203.     //close standard input/output(close controlling terminal) and other files.
  204.     for (i = 0 ; i < r.rlim_cur; ++i) {
  205.         close(i);
  206.     }
  207.     i = 0;
  208.     //assign input/output/errout to /dev/null
  209.     fd = open("/dev/null", O_RDWR);
  210.     fd = dup(0);
  211.     fd = dup(0);
  212. }

阅读(2633) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~