在WIN32下,在一个进程里我们可以使用CreateProcess()创建一个进程,然后通过调用WaitForSingleObect(), WaitForMultipleObject()等待进程退出。那么在linux下该如何实现呢?
以下的代码实现了一个daemon程序, daemon程序负责系统启动其它所有App,当其它应用出现异常退出的时候,daemon程序会重新启动它们。
/********************************************************************
filename: daemon.c
created: 2013-07-17
author: firehood
purpose: daemon implement
*********************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
typedef enum APP_ID_
{
APP_ID_MIN,
APP_ID_RTMP = APP_ID_MIN,
APP_ID_VIDTRANSFILT,
APP_ID_SOS,
//
APP_ID_MAX,
}APP_ID;
typedef struct APP_INFO_
{
APP_ID id; // app id
const char* app_path; // app file path
const char* cmdline; // app cmdline
int start_interval; // waitting time before starting the app. (unit:ms)
}APP_INFO;
static APP_INFO APP_INFO_Array[] =
{
{APP_ID_RTMP, "/opt/exe/crtmpserver/sbin/crtmpserver", "/opt/exe/crtmpserver/etc/crtmpserver.lua" ,0},
{APP_ID_VIDTRANSFILT, "./VidTransFilt", NULL, 2000},
{APP_ID_SOS, "/opt/exe/sos", NULL, 5000},
};
pid_t APP_pid[APP_ID_MAX];
int ExecuteApp(const char *app_path,const char *argv[]);
int GetAppIdByPid(pid_t pid);
int main(void)
{
/* Our process ID and Session ID */
pid_t pid, sid;
/* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then
we can exit the parent process. */
if (pid > 0) {
exit(EXIT_SUCCESS);
}
#if 0
/* Change the file mode mask */
umask(0);
/* Open any logs here */
/* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
/* Log the failure */
exit(EXIT_FAILURE);
}
/* Change the current working directory */
if ((chdir("/")) < 0) {
/* Log the failure */
exit(EXIT_FAILURE);
}
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
#endif
/* Daemon-specific initialization goes here */
printf("Daemon is running..\n");
int nAppCount = sizeof(APP_INFO_Array)/sizeof(APP_INFO);
printf("Daemon: AppCount is [%d]\n",nAppCount);
int i = 0;
for(i =0; i<nAppCount;i++)
{
usleep(APP_INFO_Array[i].start_interval*1000);
if(APP_INFO_Array[i].cmdline)
{
char* argv[3] ={0};
argv[0] = strrchr(APP_INFO_Array[i].app_path,'/')+1;
argv[1] = APP_INFO_Array[i].cmdline;
argv[2] = NULL;
APP_pid[APP_INFO_Array[i].id] = ExecuteApp(APP_INFO_Array[i].app_path,argv);
}
else
{
APP_pid[APP_INFO_Array[i].id] = ExecuteApp(APP_INFO_Array[i].app_path,NULL);
}
printf("Daemon: %s is running pid = [%d]\n",APP_INFO_Array[i].app_path,APP_pid[APP_INFO_Array[i].id]);
}
int status;
while(1)
{
pid_t ret_pid = wait(&status);
if(ret_pid == -1)
{
printf("Daemon: all app are exited!\n");
break;
}
printf("Daemon: app [%d] returns\n",ret_pid);
if(!WIFEXITED(status))
{
printf("Daemon: app [%d] terminated abnormally\n",ret_pid);
}
else
{
printf("Daemon: app [%d] exited with code[%d]\n",ret_pid,WEXITSTATUS(status));
}
int app_id = GetAppIdByPid(ret_pid);
if(app_id>=0 && app_id!=APP_ID_RTMP)
{
// restart the app
APP_pid[app_id] = ExecuteApp(APP_INFO_Array[app_id].app_path,APP_INFO_Array[app_id].cmdline);
}
}
exit(EXIT_SUCCESS);
}
int GetAppIdByPid(pid_t pid)
{
int i = 0;
for(i = 0; i<APP_ID_MAX;i++)
{
if(pid == APP_pid[i] & i != APP_ID_RTMP)
{
return i;
}
}
return -1;
}
int ExecuteApp(const char *app_path,const char *argv[])
{
if(app_path == NULL)
{
return 0;
}
pid_t pid = fork();
int ret;
switch(pid)
{
case -1:
perror("fork failed");
exit(-1);
case 0 :
ret = execv(app_path,argv);
printf("start app[%s] failed, ret= [%d]\n",app_path,ret);
break;
default:
break;
}
return pid;
}