Chinaunix首页 | 论坛 | 博客
  • 博客访问: 292199
  • 博文数量: 63
  • 博客积分: 814
  • 博客等级: 军士长
  • 技术积分: 700
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-09 15:46
文章分类

全部博文(63)

文章存档

2017年(1)

2016年(4)

2015年(13)

2014年(9)

2012年(3)

2011年(33)

分类: WINDOWS

2011-08-08 13:28:54

   在linux经常提到deamon进程,父进程监控管理子进程,在服务端或不间断服务编程中常用,且实现原理较容易,因为linux 有完善的信号机制,在win32下也可以实现,虽然有些复杂。下面就说说win32实现的原理。分析ACL 实现机制。
    网上有一个文章说的是父进程守护子进程的,介绍就是acl的接口应用。简单看了下源码,把实现机制记录了下来。

   就拿ACL中 sample 来研究,ACL 源码中sample目录中有 proctlc.exe(子进程程序),proctld.exe(父进程程序)。

先让父进程以守护进程模式启动 proctld.exe,然后运行 proctld.exe -d START {path}/proctlc.exe 通知父进程启动子进程;

---本例deamon进程就是指守护进程模式启动 proctld.exe,子进程就是proctlc.exe

源码分析:
  1. 以deamon方式启动父进程,主要是这二个接口
  2. void acl_proctl_deamon_init
  3. void proctl_monitor_loop

  4. 在文件 acl_proctl.c 中
  5. void acl_proctl_deamon_init(const char *progname)
    {
        acl_pthread_attr_t attr;
        acl_pthread_t tid;

        var_progname = acl_mystrdup(progname);
        proctl_start_init(var_progname);      //
        acl_pthread_attr_init(&attr);
        (void) acl_pthread_attr_setdetachstate(&attr, 1);
        acl_pthread_create(&tid, &attr, proctl_monitor_thread, NULL);//
    }
 
1) proctl_start_init(var_progname); 主要是完成如下

    __sem_handle = CreateSemaphore(NULL, 0, 1024, NULL);   //创建信号灯允许1024个子进程
    handles_add(__sem_handle);                             //增加到handle 数组 后面用到
2)proctl_monitor_thread 线程函数
调用关系:
proctl_monitor_loop-->proctl_monitor_main-->proctl_monitor_cmd_start-->proctl_msg_push(msg)

主要完成本地端口bind,listen,accept, 进入recv循环,收到要启动的子进程信息。这里要说明一下 proctld.exe -d START {path}/proctlc.exe的实现,这里会socket方式 连接到proctld.exe ,告知deamon进程要启动的子进程的信息,路径、文件名等。然后此进程收到服务端(proctld.exe)响应后就退出了。服务端将收到的信息构造成“msg”,proctl_msg_push(msg)放到了队列中,然后ReleaseSemaphore(__sem_handle, 1, NULL); 发出信号,这是线程函数完成功能。

那主线程呢?看proctl_monitor_loop

void acl_proctl_daemon_loop()
{
    const char *myname = "acl_proctl_daemon_loop";
    time_t tm_start, tm_end;

    while (1) {
        tm_start = time(NULL);
        proctl_service_wait();              // --> proctl_service_wait(void)
        proctl_service_join();              //****

        tm_end = time(NULL);

        if (tm_end - tm_start <= 1) {
            acl_msg_warn("%s(%d): start process too fast, sleep 2 second",
                myname, __LINE__);
            sleep(2);
        }
    }
}

int proctl_service_wait(void)
  1. {
        const char *myname = "proctl_service_wait";
        DWORD timeout = 1000 * 2, ret;
        char  ebuf[256];
        HANDLE handle_sem;
        if (__cur_handle == 0)
            return (0);
        /* Create the semaphore, with max value 32K */
        handle_sem = CreateSemaphore(NULL, 0, 32 * 1024, NULL);
        while (1) {
            ret = WaitForMultipleObjects(__cur_handle, __handles, FALSE, timeout);  //接收到上面提到的发出的信号
            if (ret == WAIT_OBJECT_0) {
                proctl_msg_main();
            } else 
  2.         .......
        }
        return (0);
    }

  3. proctl_msg_main 函数
  4. 调用关系如下
  5.             acl_fifo_pop-->proctl_service_start()-->proctl_service_add(service);
  6.                               proctl_service_start(service)-->handles_add(service->hProcess);
  功能:从队列中取出消息,启动子进程。



int proctl_service_join(void)
{
    const char *myname = "proctl_service_join";
    PROCTL_SERVICE *service;
    HANDLE hProcess;
    DWORD status;
    int   i;
    char  ebuf[256];

    for (i = 0; i < __cur_handle; i++) {
        hProcess = __handles[i];
        if (hProcess == INVALID_HANDLE_VALUE)
            service = proctl_service_find(hProcess);
        if (service == NULL) {
            if (hProcess == __sem_handle)
                continue;
        }

        status = 0;
        if (!GetExitCodeProcess(hProcess, &status)) {  //不断获得子进程的状态,若停止了就重新启动
            if (proctl_service_restart(service) < 0)
                proctl_service_stopped(service);
        } else if (status == 0) {
            proctl_service_stopped(service);
        } else if (status != STILL_ACTIVE) {
            if (proctl_service_restart(service) < 0)
                proctl_service_stopped(service);
        }
        /* else: STILL_ACTIVE */
    }

    return (0);
}
  1. ---------------------------------------------------------------
  2. ---------------------------------------------------------------
  3. //子进程代码
  4. 主要函数void acl_proctl_child(const char *progname, void (*onexit_fn)(void *), void *arg);
    子进程在启动时会用local_listenacl_vstream_accept,acl_vstream_gets_nonl等函数bind,accept,recv与父进程进行socket连接,在输入命令proctld.exe -d STOP {path}/proctld.exe时,父进程需要主动连接到对应的子进程,然后发送“STOP”命令给子进程,由子进程自己结束自己,而不是父进程直接结束子进程,这一点很不错,可以由子进程来选择自己适当的停止或重新等操作。

    到此为止,将win32 下ACL watch dog 机制简单的理顺了一下。但是这样做法也有个问题,若是在一台没有网卡的机器上运行,因需要bind ip和port, 所以会不成功。那么是不是就失效了,虽然现在很少有这种情况。唉,还是linux 下舒服。

可以运行 proctld.exe -d LIST 列出当前正在运行的子进程,运行 proctld.exe -d PROBE {path}/proctld.exe 判断子进程是否在运行,运行 proctld.exe -d STOP {path}/proctld.exe 让守护父进程停止子进程,运行 proctld.exe -d QUID 使守护进程停止所有子进程并自动退出。




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

bactq2016-01-21 09:56:23

写的挺好的。