zabbix_server代码分析--多进程创建

一、如果单纯的启动多个进程,那么代码如下:

//总体思路:父进程创建多个子进程,并且使用一个特殊标记值,使每个子进程这个数值都不同
//父进程创建子进程之后,根据这个特殊数值依次给进程分配要执行的代码
	for(i = 0;i < thread_num;i++)
	{
		if(0 == (thread_pid[i] = topo_fork()))
		{
        //每个子进程thread_mark都有一个唯一的数值,该值依次递增,从1开始。
			thread_mark = i + 1;
			break;
		}
		else
		{
			printf("thread(%d): %d\n",i,thread_pid[i]); 
		}
	}
    //根据thread_mark数值不同,设置条件,使不同的进程执行不同的代码。
    //父进程的thread_mark为0
	if(0 == thread_mark)
	{
		printf("This is parent process start\n");
        //父进程执行的代码
		parent_main_loop();
	}
    //第一个子进程的thread_mark为1
	else(thread_mark == 1)
	{
		printf("This is snmp child process start\n");
        //第一个进程执行的代码
		topo_main_loop();
	}
    //第二个子进程的thread_mark为2
	else(thread_mark == 2)
	{
		printf("This is watchdog child process start\n");
        //第二个进程执行的代码
		watchdog_main_loop();	
	}
这样做的缺点是要启动的进程个数是确定的,哪个功能要启动几个进程也是确定的,而zabbix里面启动多少个进程是不确定的,哪个功能要启动多少个进程也是不确定的,比如poller进程的个数,是可以配置文件配置个数的。


二、zabbix多进程实现

int	CONFIG_ALERTER_FORKS		= 1;
int	CONFIG_DISCOVERER_FORKS		= 1;
int	CONFIG_HOUSEKEEPER_FORKS	= 1;
int	CONFIG_NODEWATCHER_FORKS	= 1;
int	CONFIG_PINGER_FORKS		= 1;
int	CONFIG_POLLER_FORKS		= 5;
int	CONFIG_UNREACHABLE_POLLER_FORKS	= 1;
int	CONFIG_HTTPPOLLER_FORKS		= 1;
int	CONFIG_IPMIPOLLER_FORKS		= 0;
int	CONFIG_TIMER_FORKS		= 1;
int	CONFIG_TRAPPER_FORKS		= 5;
int	CONFIG_SNMPTRAPPER_FORKS	= 0;
int	CONFIG_JAVAPOLLER_FORKS		= 0;
int	CONFIG_ESCALATOR_FORKS		= 1;
int	CONFIG_SELFMON_FORKS		= 1;
int	CONFIG_WATCHDOG_FORKS		= 1;
int	CONFIG_DATASENDER_FORKS		= 0;
int	CONFIG_HEARTBEAT_FORKS		= 0;
int	CONFIG_CONFSYNCER_FORKS		= 1;

int	MAIN_ZABBIX_ENTRY()
{
	pid_t		pid;
	int		i, server_num = 0, server_count = 0;
	
	//要启动的进程数量由这些变量的值决定,配置值为1就启动该进程,为0就不启动该进程。
	//这些值有的有默认值,有的根据配置文件决定。
	threads_num = CONFIG_CONFSYNCER_FORKS + CONFIG_WATCHDOG_FORKS + CONFIG_POLLER_FORKS
			+ CONFIG_UNREACHABLE_POLLER_FORKS + CONFIG_TRAPPER_FORKS + CONFIG_PINGER_FORKS
			+ CONFIG_ALERTER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_TIMER_FORKS
			+ CONFIG_NODEWATCHER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS
			+ CONFIG_HISTSYNCER_FORKS + CONFIG_ESCALATOR_FORKS + CONFIG_IPMIPOLLER_FORKS
			+ CONFIG_JAVAPOLLER_FORKS + CONFIG_SNMPTRAPPER_FORKS + CONFIG_PROXYPOLLER_FORKS
			+ CONFIG_SELFMON_FORKS;
	threads = zbx_calloc(threads, threads_num, sizeof(pid_t));

	//使用fork()产生新的进程,thread_num是多少,就产生多少个进程。
	//fork()产生新进程的过程中,对于父进程,fork函数返回了子程序的进程号,而对于子程序,fork函数则返回零
	//所以此处使用if,else结构,会使父进程和子进程执行不同的代码
	for (i = 0; i < threads_num; i++)
	{
		if (0 == (pid = zbx_child_fork()))
		{
			//每个子进程都中的server_num都会有一个唯一的依次递增的值
			//根据server_num这个在每个进程中数值都不一样的特点,可以在下面实现每个子进程去执行不同的代码
			//子进程执行break,直接跳出循环,去执行进程之后的代码
			server_num = i + 1;	/* child processes are numbered starting from 1 */
			break;
		}
		else
			//父进程返回的是子进程的进程号,父进程将每个子进程的进程号记录在thread[]结构中
			threads[i] = pid;
	}

	//父进程的server_num为0,每个子进程都有不同的server_num,根据server_num的不同,使不同的进程执行不同的代码。
	if (0 == server_num)
	{
		zabbix_log(LOG_LEVEL_INFORMATION, "server #0 started [main process]");

		while (-1 == wait(&i))	/* wait for any child to exit */
		{
			if (EINTR != errno)
			{
				zabbix_log(LOG_LEVEL_ERR, "failed to wait on child processes: %s", zbx_strerror(errno));
				break;
			}
		}

		/* all exiting child processes should be caught by signal handlers */
		THIS_SHOULD_NEVER_HAPPEN;

		zbx_on_exit();
	}
    //server_count是已启动的子进程的个数,CONFIG_CONFSYNCER_FORKS为本次要启动的子进程的个数,server_num为每个子进程的标记值,
    //以server_num <= (server_count += CONFIG_CONFSYNCER_FORKS)为条件,可实现让子进程依次去执行相关的代码功能
    //server_count初始值为0,第一个子进程的server_num数值为1,
    //如果CONFIG_CONFSYNCER_FORKS为0,则server_count += CONFIG_CONFSYNCER_FORKS 数值为0,不满足1<=0,不执行main_dbconfig_loop()
    //如果CONFIG_CONFSYNCER_FORKS为1,则server_count += CONFIG_CONFSYNCER_FORKS 数值为1,满足1 <= 1,把main_dbconfig_loop()作为子进程要执行的代码。
    //如果CONFIG_CONFSYNCER_FORKS为2,则server_count += CONFIG_CONFSYNCER_FORKS 数值为2,第一个子进程执行时满足1<=2,执行main_dbconfig_loop()
    //第二个子进程执行时,满足2<=2,执行main_dbconfig_loop();由此可以实现同样的功能启动多个进程。CONFIG_CONFSYNCER_FORKS就是该功能启动进程的个数。
	else if (server_num <= (server_count += CONFIG_CONFSYNCER_FORKS))
	{
		INIT_SERVER(ZBX_PROCESS_TYPE_CONFSYNCER, CONFIG_CONFSYNCER_FORKS);

		main_dbconfig_loop();
	}
	else if (server_num <= (server_count += CONFIG_WATCHDOG_FORKS))
	{
		INIT_SERVER(ZBX_PROCESS_TYPE_WATCHDOG, CONFIG_WATCHDOG_FORKS);

		main_watchdog_loop();
	}

	return SUCCEED;
}

    进程要有描述,这样才知道是哪个进程在执行哪个功能。有利于程序调试。

//对进程的描述,记录哪个进程执行的是什么功能
//get_process_type_string根据传入的参数,执行switch case结构,返回对进程的描述。传入的参数为程序中宏定义的变量
//server_num为第几个进程,et_process_type_string(process_type)为对进程执行功能的描述,process_num为该功能启动进程的计数(因为有的功能要启动多个进程)
#define INIT_SERVER(type, count)								\
	process_type = type;									\
	process_num = server_num - server_count + count;					\
	zabbix_log(LOG_LEVEL_INFORMATION, "server #%d started [%s #%d]",			\
			server_num, get_process_type_string(process_type), process_num)

#define ZBX_PROCESS_TYPE_POLLER		0
#define ZBX_PROCESS_TYPE_UNREACHABLE	1
#define ZBX_PROCESS_TYPE_IPMIPOLLER	2
#define ZBX_PROCESS_TYPE_PINGER		3
#define ZBX_PROCESS_TYPE_JAVAPOLLER	4
#define ZBX_PROCESS_TYPE_HTTPPOLLER	5
#define ZBX_PROCESS_TYPE_TRAPPER	6
#define ZBX_PROCESS_TYPE_SNMPTRAPPER	7
#define ZBX_PROCESS_TYPE_PROXYPOLLER	8
#define ZBX_PROCESS_TYPE_ESCALATOR	9
#define ZBX_PROCESS_TYPE_HISTSYNCER	10
#define ZBX_PROCESS_TYPE_DISCOVERER	11
#define ZBX_PROCESS_TYPE_ALERTER	12
#define ZBX_PROCESS_TYPE_TIMER		13
#define ZBX_PROCESS_TYPE_NODEWATCHER	14
#define ZBX_PROCESS_TYPE_HOUSEKEEPER	15
#define ZBX_PROCESS_TYPE_WATCHDOG	16
#define ZBX_PROCESS_TYPE_DATASENDER	17
#define ZBX_PROCESS_TYPE_CONFSYNCER	18
#define ZBX_PROCESS_TYPE_HEARTBEAT	19
#define ZBX_PROCESS_TYPE_SELFMON	20
#define ZBX_PROCESS_TYPE_COUNT		21	/* number of process types */
#define ZBX_PROCESS_TYPE_UNKNOWN	255
            
const char	*get_process_type_string(unsigned char process_type)
{
	switch (process_type)
	{
		case ZBX_PROCESS_TYPE_POLLER:
			return "poller";
		case ZBX_PROCESS_TYPE_UNREACHABLE:
			return "unreachable poller";
		case ZBX_PROCESS_TYPE_IPMIPOLLER:
			return "ipmi poller";
		case ZBX_PROCESS_TYPE_PINGER:
			return "icmp pinger";
		case ZBX_PROCESS_TYPE_JAVAPOLLER:
			return "java poller";
		case ZBX_PROCESS_TYPE_HTTPPOLLER:
			return "http poller";
		case ZBX_PROCESS_TYPE_TRAPPER:
			return "trapper";
		case ZBX_PROCESS_TYPE_SNMPTRAPPER:
			return "snmp trapper";
		case ZBX_PROCESS_TYPE_PROXYPOLLER:
			return "proxy poller";
		case ZBX_PROCESS_TYPE_ESCALATOR:
			return "escalator";
		case ZBX_PROCESS_TYPE_HISTSYNCER:
			return "history syncer";
		case ZBX_PROCESS_TYPE_DISCOVERER:
			return "discoverer";
		case ZBX_PROCESS_TYPE_ALERTER:
			return "alerter";
		case ZBX_PROCESS_TYPE_TIMER:
			return "timer";
		case ZBX_PROCESS_TYPE_NODEWATCHER:
			return "node watcher";
		case ZBX_PROCESS_TYPE_HOUSEKEEPER:
			return "housekeeper";
		case ZBX_PROCESS_TYPE_WATCHDOG:
			return "db watchdog";
		case ZBX_PROCESS_TYPE_DATASENDER:
			return "data sender";
		case ZBX_PROCESS_TYPE_CONFSYNCER:
			return "configuration syncer";
		case ZBX_PROCESS_TYPE_HEARTBEAT:
			return "heartbeat sender";
		case ZBX_PROCESS_TYPE_SELFMON:
			return "self-monitoring";
	}

	assert(0);
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值