1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "zbxself.h"
21 #include "common.h"
22 
23 #ifndef _WINDOWS
24 #	include "mutexs.h"
25 #	include "ipc.h"
26 #	include "log.h"
27 
28 #	define MAX_HISTORY	60
29 
30 #define ZBX_SELFMON_FLUSH_DELAY		(ZBX_SELFMON_DELAY * 0.5)
31 
32 /* process state cache, updated only by the processes themselves */
33 typedef struct
34 {
35 	/* the current usage statistics */
36 	zbx_uint64_t	counter[ZBX_PROCESS_STATE_COUNT];
37 
38 	/* ticks of the last self monitoring update */
39 	clock_t		ticks;
40 
41 	/* ticks of the last self monitoring cache flush */
42 	clock_t		ticks_flush;
43 
44 	/* the current process state (see ZBX_PROCESS_STATE_* defines) */
45 	unsigned char	state;
46 }
47 zxb_stat_process_cache_t;
48 
49 /* process state statistics */
50 typedef struct
51 {
52 	/* historical process state data */
53 	unsigned short			h_counter[ZBX_PROCESS_STATE_COUNT][MAX_HISTORY];
54 
55 	/* process state data for the current data gathering cycle */
56 	unsigned short			counter[ZBX_PROCESS_STATE_COUNT];
57 
58 	/* the process state that was already applied to the historical state data */
59 	zbx_uint64_t			counter_used[ZBX_PROCESS_STATE_COUNT];
60 
61 	/* the process state cache */
62 	zxb_stat_process_cache_t	cache;
63 }
64 zbx_stat_process_t;
65 
66 typedef struct
67 {
68 	zbx_stat_process_t	**process;
69 	int			first;
70 	int			count;
71 
72 	/* number of ticks per second */
73 	int			ticks_per_sec;
74 
75 	/* ticks of the last self monitoring sync (data gathering) */
76 	clock_t			ticks_sync;
77 }
78 zbx_selfmon_collector_t;
79 
80 static zbx_selfmon_collector_t	*collector = NULL;
81 static int			shm_id;
82 
83 #	define LOCK_SM		zbx_mutex_lock(sm_lock)
84 #	define UNLOCK_SM	zbx_mutex_unlock(sm_lock)
85 
86 static zbx_mutex_t	sm_lock = ZBX_MUTEX_NULL;
87 #endif
88 
89 extern char	*CONFIG_FILE;
90 extern int	CONFIG_POLLER_FORKS;
91 extern int	CONFIG_UNREACHABLE_POLLER_FORKS;
92 extern int	CONFIG_IPMIPOLLER_FORKS;
93 extern int	CONFIG_PINGER_FORKS;
94 extern int	CONFIG_JAVAPOLLER_FORKS;
95 extern int	CONFIG_HTTPPOLLER_FORKS;
96 extern int	CONFIG_TRAPPER_FORKS;
97 extern int	CONFIG_SNMPTRAPPER_FORKS;
98 extern int	CONFIG_PROXYPOLLER_FORKS;
99 extern int	CONFIG_ESCALATOR_FORKS;
100 extern int	CONFIG_HISTSYNCER_FORKS;
101 extern int	CONFIG_DISCOVERER_FORKS;
102 extern int	CONFIG_ALERTER_FORKS;
103 extern int	CONFIG_TIMER_FORKS;
104 extern int	CONFIG_HOUSEKEEPER_FORKS;
105 extern int	CONFIG_DATASENDER_FORKS;
106 extern int	CONFIG_CONFSYNCER_FORKS;
107 extern int	CONFIG_HEARTBEAT_FORKS;
108 extern int	CONFIG_SELFMON_FORKS;
109 extern int	CONFIG_VMWARE_FORKS;
110 extern int	CONFIG_COLLECTOR_FORKS;
111 extern int	CONFIG_PASSIVE_FORKS;
112 extern int	CONFIG_ACTIVE_FORKS;
113 extern int	CONFIG_TASKMANAGER_FORKS;
114 extern int	CONFIG_IPMIMANAGER_FORKS;
115 extern int	CONFIG_ALERTMANAGER_FORKS;
116 extern int	CONFIG_PREPROCMAN_FORKS;
117 extern int	CONFIG_PREPROCESSOR_FORKS;
118 extern int	CONFIG_LLDMANAGER_FORKS;
119 extern int	CONFIG_LLDWORKER_FORKS;
120 extern int	CONFIG_ALERTDB_FORKS;
121 
122 extern unsigned char	process_type;
123 extern int		process_num;
124 
125 /******************************************************************************
126  *                                                                            *
127  * Function: get_process_type_forks                                           *
128  *                                                                            *
129  * Purpose: Returns number of processes depending on process type             *
130  *                                                                            *
131  * Parameters: proc_type - [IN] process type; ZBX_PROCESS_TYPE_*              *
132  *                                                                            *
133  * Return value: number of processes                                          *
134  *                                                                            *
135  * Author: Alexander Vladishev                                                *
136  *                                                                            *
137  ******************************************************************************/
get_process_type_forks(unsigned char proc_type)138 int	get_process_type_forks(unsigned char proc_type)
139 {
140 	switch (proc_type)
141 	{
142 		case ZBX_PROCESS_TYPE_POLLER:
143 			return CONFIG_POLLER_FORKS;
144 		case ZBX_PROCESS_TYPE_UNREACHABLE:
145 			return CONFIG_UNREACHABLE_POLLER_FORKS;
146 		case ZBX_PROCESS_TYPE_IPMIPOLLER:
147 			return CONFIG_IPMIPOLLER_FORKS;
148 		case ZBX_PROCESS_TYPE_PINGER:
149 			return CONFIG_PINGER_FORKS;
150 		case ZBX_PROCESS_TYPE_JAVAPOLLER:
151 			return CONFIG_JAVAPOLLER_FORKS;
152 		case ZBX_PROCESS_TYPE_HTTPPOLLER:
153 			return CONFIG_HTTPPOLLER_FORKS;
154 		case ZBX_PROCESS_TYPE_TRAPPER:
155 			return CONFIG_TRAPPER_FORKS;
156 		case ZBX_PROCESS_TYPE_SNMPTRAPPER:
157 			return CONFIG_SNMPTRAPPER_FORKS;
158 		case ZBX_PROCESS_TYPE_PROXYPOLLER:
159 			return CONFIG_PROXYPOLLER_FORKS;
160 		case ZBX_PROCESS_TYPE_ESCALATOR:
161 			return CONFIG_ESCALATOR_FORKS;
162 		case ZBX_PROCESS_TYPE_HISTSYNCER:
163 			return CONFIG_HISTSYNCER_FORKS;
164 		case ZBX_PROCESS_TYPE_DISCOVERER:
165 			return CONFIG_DISCOVERER_FORKS;
166 		case ZBX_PROCESS_TYPE_ALERTER:
167 			return CONFIG_ALERTER_FORKS;
168 		case ZBX_PROCESS_TYPE_TIMER:
169 			return CONFIG_TIMER_FORKS;
170 		case ZBX_PROCESS_TYPE_HOUSEKEEPER:
171 			return CONFIG_HOUSEKEEPER_FORKS;
172 		case ZBX_PROCESS_TYPE_DATASENDER:
173 			return CONFIG_DATASENDER_FORKS;
174 		case ZBX_PROCESS_TYPE_CONFSYNCER:
175 			return CONFIG_CONFSYNCER_FORKS;
176 		case ZBX_PROCESS_TYPE_HEARTBEAT:
177 			return CONFIG_HEARTBEAT_FORKS;
178 		case ZBX_PROCESS_TYPE_SELFMON:
179 			return CONFIG_SELFMON_FORKS;
180 		case ZBX_PROCESS_TYPE_VMWARE:
181 			return CONFIG_VMWARE_FORKS;
182 		case ZBX_PROCESS_TYPE_COLLECTOR:
183 			return CONFIG_COLLECTOR_FORKS;
184 		case ZBX_PROCESS_TYPE_LISTENER:
185 			return CONFIG_PASSIVE_FORKS;
186 		case ZBX_PROCESS_TYPE_ACTIVE_CHECKS:
187 			return CONFIG_ACTIVE_FORKS;
188 		case ZBX_PROCESS_TYPE_TASKMANAGER:
189 			return CONFIG_TASKMANAGER_FORKS;
190 		case ZBX_PROCESS_TYPE_IPMIMANAGER:
191 			return CONFIG_IPMIMANAGER_FORKS;
192 		case ZBX_PROCESS_TYPE_ALERTMANAGER:
193 			return CONFIG_ALERTMANAGER_FORKS;
194 		case ZBX_PROCESS_TYPE_PREPROCMAN:
195 			return CONFIG_PREPROCMAN_FORKS;
196 		case ZBX_PROCESS_TYPE_PREPROCESSOR:
197 			return CONFIG_PREPROCESSOR_FORKS;
198 		case ZBX_PROCESS_TYPE_LLDMANAGER:
199 			return CONFIG_LLDMANAGER_FORKS;
200 		case ZBX_PROCESS_TYPE_LLDWORKER:
201 			return CONFIG_LLDWORKER_FORKS;
202 		case ZBX_PROCESS_TYPE_ALERTSYNCER:
203 			return CONFIG_ALERTDB_FORKS;
204 	}
205 
206 	THIS_SHOULD_NEVER_HAPPEN;
207 	exit(EXIT_FAILURE);
208 }
209 
210 #ifndef _WINDOWS
211 /******************************************************************************
212  *                                                                            *
213  * Function: init_selfmon_collector                                           *
214  *                                                                            *
215  * Purpose: Initialize structures and prepare state                           *
216  *          for self-monitoring collector                                     *
217  *                                                                            *
218  * Author: Alexander Vladishev                                                *
219  *                                                                            *
220  ******************************************************************************/
init_selfmon_collector(char ** error)221 int	init_selfmon_collector(char **error)
222 {
223 	size_t		sz, sz_array, sz_process[ZBX_PROCESS_TYPE_COUNT], sz_total;
224 	char		*p;
225 	unsigned char	proc_type;
226 	int		proc_num, process_forks, ret = FAIL;
227 
228 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
229 
230 	sz_total = sz = sizeof(zbx_selfmon_collector_t);
231 	sz_total += sz_array = sizeof(zbx_stat_process_t *) * ZBX_PROCESS_TYPE_COUNT;
232 
233 	for (proc_type = 0; ZBX_PROCESS_TYPE_COUNT > proc_type; proc_type++)
234 		sz_total += sz_process[proc_type] = sizeof(zbx_stat_process_t) * get_process_type_forks(proc_type);
235 
236 	zabbix_log(LOG_LEVEL_DEBUG, "%s() size:" ZBX_FS_SIZE_T, __func__, (zbx_fs_size_t)sz_total);
237 
238 	if (SUCCEED != zbx_mutex_create(&sm_lock, ZBX_MUTEX_SELFMON, error))
239 	{
240 		zbx_error("unable to create mutex for a self-monitoring collector");
241 		exit(EXIT_FAILURE);
242 	}
243 
244 	if (-1 == (shm_id = shmget(IPC_PRIVATE, sz_total, 0600)))
245 	{
246 		*error = zbx_strdup(*error, "cannot allocate shared memory for a self-monitoring collector");
247 		goto out;
248 	}
249 
250 	if ((void *)(-1) == (p = (char *)shmat(shm_id, NULL, 0)))
251 	{
252 		*error = zbx_dsprintf(*error, "cannot attach shared memory for a self-monitoring collector: %s",
253 				zbx_strerror(errno));
254 		goto out;
255 	}
256 
257 	if (-1 == shmctl(shm_id, IPC_RMID, NULL))
258 		zbx_error("cannot mark shared memory %d for destruction: %s", shm_id, zbx_strerror(errno));
259 
260 	collector = (zbx_selfmon_collector_t *)p; p += sz;
261 	collector->process = (zbx_stat_process_t **)p; p += sz_array;
262 	collector->ticks_per_sec = sysconf(_SC_CLK_TCK);
263 	collector->ticks_sync = 0;
264 
265 	for (proc_type = 0; ZBX_PROCESS_TYPE_COUNT > proc_type; proc_type++)
266 	{
267 		collector->process[proc_type] = (zbx_stat_process_t *)p; p += sz_process[proc_type];
268 		memset(collector->process[proc_type], 0, sz_process[proc_type]);
269 
270 		process_forks = get_process_type_forks(proc_type);
271 		for (proc_num = 0; proc_num < process_forks; proc_num++)
272 		{
273 			collector->process[proc_type][proc_num].cache.state = ZBX_PROCESS_STATE_IDLE;
274 		}
275 	}
276 
277 	ret = SUCCEED;
278 out:
279 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() collector:%p", __func__, (void *)collector);
280 
281 	return ret;
282 }
283 
284 /******************************************************************************
285  *                                                                            *
286  * Function: free_selfmon_collector                                           *
287  *                                                                            *
288  * Purpose: Free memory allocated for self-monitoring collector               *
289  *                                                                            *
290  * Author: Alexander Vladishev                                                *
291  *                                                                            *
292  ******************************************************************************/
free_selfmon_collector(void)293 void	free_selfmon_collector(void)
294 {
295 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() collector:%p", __func__, (void *)collector);
296 
297 	if (NULL == collector)
298 		return;
299 
300 	LOCK_SM;
301 
302 	collector = NULL;
303 
304 	if (-1 == shmctl(shm_id, IPC_RMID, 0))
305 	{
306 		zabbix_log(LOG_LEVEL_WARNING, "cannot remove shared memory for self-monitoring collector: %s",
307 				zbx_strerror(errno));
308 	}
309 
310 	UNLOCK_SM;
311 
312 	zbx_mutex_destroy(&sm_lock);
313 
314 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
315 }
316 
317 /******************************************************************************
318  *                                                                            *
319  * Function: update_selfmon_counter                                           *
320  *                                                                            *
321  * Parameters: state - [IN] new process state; ZBX_PROCESS_STATE_*            *
322  *                                                                            *
323  * Author: Alexander Vladishev                                                *
324  *                                                                            *
325  ******************************************************************************/
update_selfmon_counter(unsigned char state)326 void	update_selfmon_counter(unsigned char state)
327 {
328 	zbx_stat_process_t	*process;
329 	clock_t			ticks;
330 	struct tms		buf;
331 	int			i;
332 
333 	if (ZBX_PROCESS_TYPE_UNKNOWN == process_type)
334 		return;
335 
336 	process = &collector->process[process_type][process_num - 1];
337 
338 	if (-1 == (ticks = times(&buf)))
339 	{
340 		zabbix_log(LOG_LEVEL_WARNING, "cannot get process times: %s", zbx_strerror(errno));
341 		process->cache.state = state;
342 		return;
343 	}
344 
345 	if (0 == process->cache.ticks_flush)
346 	{
347 		process->cache.ticks_flush = ticks;
348 		process->cache.state = state;
349 		process->cache.ticks = ticks;
350 		return;
351 	}
352 
353 	/* update process statistics in local cache */
354 	process->cache.counter[process->cache.state] += ticks - process->cache.ticks;
355 
356 	if (ZBX_SELFMON_FLUSH_DELAY < (double)(ticks - process->cache.ticks_flush) / collector->ticks_per_sec)
357 	{
358 		LOCK_SM;
359 
360 		for (i = 0; i < ZBX_PROCESS_STATE_COUNT; i++)
361 		{
362 			/* If process did not update selfmon counter during one self monitoring data   */
363 			/* collection interval, then self monitor will collect statistics based on the */
364 			/* current process state and the ticks passed since last self monitoring data  */
365 			/* collection. This value is stored in counter_used and the local statistics   */
366 			/* must be adjusted by this (already collected) value.                         */
367 			if (process->cache.counter[i] > process->counter_used[i])
368 			{
369 				process->cache.counter[i] -= process->counter_used[i];
370 				process->counter[i] += process->cache.counter[i];
371 			}
372 
373 			/* reset current cache statistics */
374 			process->counter_used[i] = 0;
375 			process->cache.counter[i] = 0;
376 		}
377 
378 		process->cache.ticks_flush = ticks;
379 
380 		UNLOCK_SM;
381 	}
382 
383 	/* update local self monitoring cache */
384 	process->cache.state = state;
385 	process->cache.ticks = ticks;
386 }
387 
388 /******************************************************************************
389  *                                                                            *
390  * Function: collect_selfmon_stats                                            *
391  *                                                                            *
392  * Author: Alexander Vladishev                                                *
393  *                                                                            *
394  ******************************************************************************/
collect_selfmon_stats(void)395 void	collect_selfmon_stats(void)
396 {
397 	zbx_stat_process_t	*process;
398 	clock_t			ticks, ticks_done;
399 	struct tms		buf;
400 	unsigned char		proc_type, i;
401 	int			proc_num, process_forks, index, last;
402 
403 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
404 
405 	if (-1 == (ticks = times(&buf)))
406 	{
407 		zabbix_log(LOG_LEVEL_WARNING, "cannot get process times: %s", zbx_strerror(errno));
408 		goto out;
409 	}
410 
411 	if (0 == collector->ticks_sync)
412 	{
413 		collector->ticks_sync = ticks;
414 		goto out;
415 	}
416 
417 	if (MAX_HISTORY <= (index = collector->first + collector->count))
418 		index -= MAX_HISTORY;
419 
420 	if (collector->count < MAX_HISTORY)
421 		collector->count++;
422 	else if (++collector->first == MAX_HISTORY)
423 		collector->first = 0;
424 
425 	if (0 > (last = index - 1))
426 		last += MAX_HISTORY;
427 
428 	LOCK_SM;
429 
430 	ticks_done = ticks - collector->ticks_sync;
431 
432 	for (proc_type = 0; proc_type < ZBX_PROCESS_TYPE_COUNT; proc_type++)
433 	{
434 		process_forks = get_process_type_forks(proc_type);
435 		for (proc_num = 0; proc_num < process_forks; proc_num++)
436 		{
437 			process = &collector->process[proc_type][proc_num];
438 
439 			if (process->cache.ticks_flush < collector->ticks_sync)
440 			{
441 				/* If the process local cache was not flushed during the last self monitoring  */
442 				/* data collection interval update the process statistics based on the current */
443 				/* process state and ticks passed during the collection interval. Store this   */
444 				/* value so the process local self monitoring cache can be adjusted before     */
445 				/* flushing.                                                                   */
446 				process->counter[process->cache.state] += ticks_done;
447 				process->counter_used[process->cache.state] += ticks_done;
448 			}
449 
450 			for (i = 0; i < ZBX_PROCESS_STATE_COUNT; i++)
451 			{
452 				/* The data is gathered as ticks spent in corresponding states during the */
453 				/* self monitoring data collection interval. But in history the data are  */
454 				/* stored as relative values. To achieve it we add the collected data to  */
455 				/* the last values.                                                       */
456 				process->h_counter[i][index] = process->h_counter[i][last] + process->counter[i];
457 				process->counter[i] = 0;
458 			}
459 		}
460 	}
461 
462 	collector->ticks_sync = ticks;
463 
464 	UNLOCK_SM;
465 out:
466 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
467 }
468 
469 /******************************************************************************
470  *                                                                            *
471  * Function: get_selfmon_stats                                                *
472  *                                                                            *
473  * Purpose: calculate statistics for selected process                         *
474  *                                                                            *
475  * Parameters: proc_type    - [IN] type of process; ZBX_PROCESS_TYPE_*        *
476  *             aggr_func    - [IN] one of ZBX_AGGR_FUNC_*                     *
477  *             proc_num     - [IN] process number; 1 - first process;         *
478  *                                 0 - all processes                          *
479  *             state        - [IN] process state; ZBX_PROCESS_STATE_*         *
480  *             value        - [OUT] a pointer to a variable that receives     *
481  *                                  requested statistics                      *
482  *                                                                            *
483  * Author: Alexander Vladishev                                                *
484  *                                                                            *
485  ******************************************************************************/
get_selfmon_stats(unsigned char proc_type,unsigned char aggr_func,int proc_num,unsigned char state,double * value)486 void	get_selfmon_stats(unsigned char proc_type, unsigned char aggr_func, int proc_num, unsigned char state,
487 		double *value)
488 {
489 	unsigned int	total = 0, counter = 0;
490 	unsigned char	s;
491 	int		process_forks, current;
492 
493 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
494 
495 	process_forks = get_process_type_forks(proc_type);
496 
497 	switch (aggr_func)
498 	{
499 		case ZBX_AGGR_FUNC_ONE:
500 			assert(0 < proc_num && proc_num <= process_forks);
501 			process_forks = proc_num--;
502 			break;
503 		case ZBX_AGGR_FUNC_AVG:
504 		case ZBX_AGGR_FUNC_MAX:
505 		case ZBX_AGGR_FUNC_MIN:
506 			assert(0 == proc_num && 0 < process_forks);
507 			break;
508 		default:
509 			assert(0);
510 	}
511 
512 	LOCK_SM;
513 
514 	if (1 >= collector->count)
515 		goto unlock;
516 
517 	if (MAX_HISTORY <= (current = (collector->first + collector->count - 1)))
518 		current -= MAX_HISTORY;
519 
520 	for (; proc_num < process_forks; proc_num++)
521 	{
522 		zbx_stat_process_t	*process;
523 		unsigned int		one_total = 0, one_counter;
524 
525 		process = &collector->process[proc_type][proc_num];
526 
527 		for (s = 0; s < ZBX_PROCESS_STATE_COUNT; s++)
528 		{
529 			one_total += (unsigned short)(process->h_counter[s][current] -
530 					process->h_counter[s][collector->first]);
531 		}
532 
533 		one_counter = (unsigned short)(process->h_counter[state][current] -
534 				process->h_counter[state][collector->first]);
535 
536 		switch (aggr_func)
537 		{
538 			case ZBX_AGGR_FUNC_ONE:
539 			case ZBX_AGGR_FUNC_AVG:
540 				total += one_total;
541 				counter += one_counter;
542 				break;
543 			case ZBX_AGGR_FUNC_MAX:
544 				if (0 == proc_num || one_counter > counter)
545 				{
546 					counter = one_counter;
547 					total = one_total;
548 				}
549 				break;
550 			case ZBX_AGGR_FUNC_MIN:
551 				if (0 == proc_num || one_counter < counter)
552 				{
553 					counter = one_counter;
554 					total = one_total;
555 				}
556 				break;
557 		}
558 	}
559 
560 unlock:
561 	UNLOCK_SM;
562 
563 	*value = (0 == total ? 0 : 100. * (double)counter / (double)total);
564 
565 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
566 }
567 
568 /******************************************************************************
569  *                                                                            *
570  * Function: zbx_get_all_process_stats                                        *
571  *                                                                            *
572  * Purpose: retrieves internal metrics of all running processes based on      *
573  *          process type                                                      *
574  *                                                                            *
575  * Parameters: stats - [OUT] process metrics                                  *
576  *                                                                            *
577  ******************************************************************************/
zbx_get_all_process_stats(zbx_process_info_t * stats)578 int	zbx_get_all_process_stats(zbx_process_info_t *stats)
579 {
580 	int		current, ret = FAIL;
581 	unsigned char	proc_type;
582 
583 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
584 
585 	LOCK_SM;
586 
587 	if (1 >= collector->count)
588 		goto unlock;
589 
590 	if (MAX_HISTORY <= (current = (collector->first + collector->count - 1)))
591 		current -= MAX_HISTORY;
592 
593 	for (proc_type = 0; proc_type < ZBX_PROCESS_TYPE_COUNT; proc_type++)
594 	{
595 		int		proc_num;
596 		unsigned int	total_avg = 0, counter_avg_busy = 0, counter_avg_idle = 0,
597 				total_max = 0, counter_max_busy = 0, counter_max_idle = 0,
598 				total_min = 0, counter_min_busy = 0, counter_min_idle = 0;
599 
600 		stats[proc_type].count = get_process_type_forks(proc_type);
601 
602 		for (proc_num = 0; proc_num < stats[proc_type].count; proc_num++)
603 		{
604 			zbx_stat_process_t	*process;
605 			unsigned int		one_total = 0, busy_counter, idle_counter;
606 			unsigned char		s;
607 
608 			process = &collector->process[proc_type][proc_num];
609 
610 			for (s = 0; s < ZBX_PROCESS_STATE_COUNT; s++)
611 			{
612 				one_total += (unsigned short)(process->h_counter[s][current] -
613 						process->h_counter[s][collector->first]);
614 			}
615 
616 			busy_counter = (unsigned short)(process->h_counter[ZBX_PROCESS_STATE_BUSY][current] -
617 					process->h_counter[ZBX_PROCESS_STATE_BUSY][collector->first]);
618 
619 			idle_counter = (unsigned short)(process->h_counter[ZBX_PROCESS_STATE_IDLE][current] -
620 					process->h_counter[ZBX_PROCESS_STATE_IDLE][collector->first]);
621 
622 			total_avg += one_total;
623 			counter_avg_busy += busy_counter;
624 			counter_avg_idle += idle_counter;
625 
626 			if (0 == proc_num || busy_counter > counter_max_busy)
627 			{
628 				counter_max_busy = busy_counter;
629 				total_max = one_total;
630 			}
631 
632 			if (0 == proc_num || idle_counter > counter_max_idle)
633 			{
634 				counter_max_idle = idle_counter;
635 				total_max = one_total;
636 			}
637 
638 			if (0 == proc_num || busy_counter < counter_min_busy)
639 			{
640 				counter_min_busy = busy_counter;
641 				total_min = one_total;
642 			}
643 
644 			if (0 == proc_num || idle_counter < counter_min_idle)
645 			{
646 				counter_min_idle = idle_counter;
647 				total_min = one_total;
648 			}
649 		}
650 
651 		stats[proc_type].busy_avg = (0 == total_avg ? 0 : 100. * (double)counter_avg_busy / (double)total_avg);
652 		stats[proc_type].busy_max = (0 == total_max ? 0 : 100. * (double)counter_max_busy / (double)total_max);
653 		stats[proc_type].busy_min = (0 == total_min ? 0 : 100. * (double)counter_min_busy / (double)total_min);
654 
655 		stats[proc_type].idle_avg = (0 == total_avg ? 0 : 100. * (double)counter_avg_idle / (double)total_avg);
656 		stats[proc_type].idle_max = (0 == total_max ? 0 : 100. * (double)counter_max_idle / (double)total_max);
657 		stats[proc_type].idle_min = (0 == total_min ? 0 : 100. * (double)counter_min_idle / (double)total_min);
658 	}
659 
660 	ret = SUCCEED;
661 unlock:
662 	UNLOCK_SM;
663 
664 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
665 
666 	return ret;
667 }
668 
669 static int	sleep_remains;
670 
671 /******************************************************************************
672  *                                                                            *
673  * Function: zbx_sleep_loop                                                   *
674  *                                                                            *
675  * Purpose: sleeping process                                                  *
676  *                                                                            *
677  * Parameters: sleeptime - [IN] required sleeptime, in seconds                *
678  *                                                                            *
679  * Author: Alexander Vladishev                                                *
680  *                                                                            *
681  ******************************************************************************/
zbx_sleep_loop(int sleeptime)682 void	zbx_sleep_loop(int sleeptime)
683 {
684 	if (0 >= sleeptime)
685 		return;
686 
687 	sleep_remains = sleeptime;
688 
689 	update_selfmon_counter(ZBX_PROCESS_STATE_IDLE);
690 
691 	do
692 	{
693 		sleep(1);
694 	}
695 	while (0 < --sleep_remains);
696 
697 	update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
698 }
699 
zbx_sleep_forever(void)700 void	zbx_sleep_forever(void)
701 {
702 	sleep_remains = 1;
703 
704 	update_selfmon_counter(ZBX_PROCESS_STATE_IDLE);
705 
706 	do
707 	{
708 		sleep(1);
709 	}
710 	while (0 != sleep_remains);
711 
712 	update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
713 }
714 
zbx_wakeup(void)715 void	zbx_wakeup(void)
716 {
717 	sleep_remains = 0;
718 }
719 
zbx_sleep_get_remainder(void)720 int	zbx_sleep_get_remainder(void)
721 {
722 	return sleep_remains;
723 }
724 #endif
725