网上有一个文章说的是父进程守护子进程的,介绍就是acl的接口应用。简单看了下源码,把实现机制记录了下来。
就拿ACL中 sample 来研究,ACL 源码中sample目录中有 proctlc.exe(子进程程序),proctld.exe(父进程程序)。
先让父进程以守护进程模式启动 proctld.exe,然后运行 proctld.exe -d START {path}/proctlc.exe 通知父进程启动子进程;
---本例deamon进程就是指守护进程模式启动 proctld.exe,子进程就是proctlc.exe
源码分析:
- 以deamon方式启动父进程,主要是这二个接口
- void acl_proctl_deamon_init
- void proctl_monitor_loop
-
在文件 acl_proctl.c 中
-
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)
- {
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 - .......
}
return (0);
} - proctl_msg_main 函数
- 调用关系如下:
-
acl_fifo_pop-->proctl_service_start()-->proctl_service_add(service);
- 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);
}
-
---------------------------------------------------------------
-
---------------------------------------------------------------
- //子进程代码
- 主要函数void acl_proctl_child(const char *progname, void (*onexit_fn)(void *), void *arg);
到此为止,将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 使守护进程停止所有子进程并自动退出。