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