zeerd's blog         Search     Categories     Tags     Feed

闲来生雅趣,无事乐逍遥。对窗相望雪,一盏茶香飘。

Linux下实现通过一个进程控制另一个进程的启动、停止、崩溃重启

#Process @Linux


Contents:
create_process函数用于进行进程的启动。这里仅给出了带有简单命令行参数或者不带参数的进程的例子。如果需要启动命令行参数复杂的进程,请使用man exec查找execl的其他替代调用方法。

kill_process用于停止进程。kill掉的进程因为是这个程序的子进程,所以不作任何处理的话,会变成僵尸进程。因此,加入了对信号SIGCHLD的监控。其中的wait函数的作用是接收子进程的状态。我们的进程中接收了这个状态,linux系统就认为我们已经了解了子进程状态,就不会再子进程意外结束的时候把它变成僵尸进程了。

judge_proc_exist函数通过查询/proc路径下的ProcID来确认进程是否依然存在。如果子进程变成了僵尸进程,则它的ProcID依然会留在这里,所以无法通过这种方式判断是否进程意外退出了。

daemon_thread线程用于监控子进程是否异常退出,如果是则重启。

其实也可以不用这么麻烦,直接在sig_chld中重启子进程也是可以的。这样的话,judge_proc_exist和daemon_thread斗不需要了。



/*
gcc daemon.c -pthread
*/


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>

#include <pthread.h>

#ifndef TRUE
#define TRUE (!0)
#endif

#ifndef FALSE
#define FALSE 0
#endif

typedef int bool;

char glb_process[1024] = "";
char glb_arg[1024] = "";

int glb_pid = -1;
bool daemon_thread_running = FALSE;

int create_process(const char* cmd, const char* arg)
{
int pid = fork();
if(pid == -1)
{
printf("fork error\\n");
return -1;
}
else if(pid == 0){
int ret = execl(cmd, arg, NULL);
if(ret < 0)
{
printf("execl : %s(%d)\\n", sys_errlist[errno], errno);
return -2;
}
else{
}
}
else{
}

return pid;
}

int kill_process(int pid)
{
int ret = kill(pid, SIGKILL);
if(ret < 0)
{
printf("kill : %s(%d)\\n", sys_errlist[errno], errno);
return -1;
}
return 0;
}

bool judge_proc_exist(int pid)
{
DIR* dir;
struct dirent* s_dir;
struct stat file_stat;
const char *proc_dir = "/proc/";
char s_pid[10] = "";

if((dir = opendir(proc_dir)) == NULL) {
printf("open %s error : %s(%d)", proc_dir, sys_errlist[errno], errno);
return TRUE;
}
sprintf(s_pid, "%d", pid);

bool found = FALSE;
while((s_dir = readdir(dir)) != NULL) {
lstat(s_dir->d_name, &file_stat);
if((!strcmp(s_pid, s_dir->d_name)) && (S_ISDIR(file_stat.st_mode))){
found = TRUE;
break;
}
}

closedir(dir);

return found;
}

void* daemon_thread(void* user_data )
{
char input[ 256 ];
while(1){
if(daemon_thread_running && (glb_pid != -1)){
if(!judge_proc_exist(glb_pid)){
glb_pid = create_process(glb_process, glb_arg);
printf("process(%d) restarted...\\n", glb_pid);
}
usleep(100);
}
}
return 0;
}

void* input_thread(void* user_data )
{
char input[ 256 ];
while(1){
if( gets(input) != NULL){
if(input[0] == 's'){
glb_pid = create_process(glb_process, glb_arg);
printf("process(%d) started...\\n", glb_pid);
}
else if(input[0] == 'k'){
kill_process(glb_pid);
printf("process(%d) killed...\\n", glb_pid);
}
else if(input[0] == 'q'){
exit(0);
}
else if(input[0] == 'd'){
daemon_thread_running = !daemon_thread_running;
printf("daemon_thread_running(%s)\\n", daemon_thread_running?"TRUE":"FALSE");
}
else if( input[0] == 'h' ){
printf("s -- start the process\\n");
printf("k -- kill the process\\n");
printf("d -- switch daemon process\\n");
printf("press 'q' to end this program \\n" );

}
}
}
return 0;
}

void sig_chld( int signo ) {
pid_t pid;
int stat;
pid = wait(&stat);
printf( "child %d exit\\n", pid );
return;
}
int main(int argc, char* argv[])
{
pthread_t it;
pthread_t dt;
if(argc < 2){
printf("Usage : %s <full path and file name> [arg]\\n", argv[0]);
printf("build at %s %s\\n", __DATE__, __TIME__);
return -1;
}

if(argc > 1){
strcpy(glb_process, argv[1]);
}
if(argc > 2){
strcpy(glb_arg, argv[2]);
}

printf("h-- help\\n");

signal(SIGCHLD, &sig_chld);

pthread_create(&it, NULL, input_thread, NULL );
pthread_create(&dt, NULL, daemon_thread, NULL );

while(1);
}