zabbix-4.2.1/src/libs/zbxsysinfo/sysinfo.c
/******************************************************************************
 *                                                                            *
 * Function: zbx_execute_threaded_metric                                      *
 *                                                                            *
 * Purpose: execute metric in a separate process/thread so it can be          *
 *          killed/terminated when timeout is detected                        *
 *                                                                            *
 * Parameters: metric_func - [IN] the metric function to execute              *
 *             ...                the metric function parameters              *
 *                                                                            *
 * Return value:                                                              *
 *         SYSINFO_RET_OK - the metric was executed successfully              *
 *         SYSINFO_RET_FAIL - otherwise                                       *
 *                                                                            *
 ******************************************************************************/


execute metric in a separate process/thread so it can be
killed/terminated when timeout is detected

[IN] the metric function to execute
the metric function parameters

Return value:
SYSINFO_RET_OK - the metric was executed successfully
SYSINFO_RET_FAIL - otherwise
execute metric in a separate process / thread so it can be killed / terminated when timeout is detected [ IN ] the metric function to execute the metric function parameters Return value : SYSINFO_RET_OK - the metric was executed successfully SYSINFO_RET_FAIL - otherwise
int	zbx_execute_threaded_metric(zbx_metric_func_t metric_func, AGENT_REQUEST *request, AGENT_RESULT *result)
{
	ZBX_THREAD_HANDLE		thread;
	zbx_thread_args_t		thread_args;
	zbx_metric_thread_args_t	metric_args = {metric_func, request, result, ZBX_MUTEX_THREAD_DENIED |
							ZBX_MUTEX_LOGGING_DENIED};
	DWORD				rc;
	BOOL				terminate_thread = FALSE;
	zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s'", __func__, request->key);
	if (NULL == (metric_args.timeout_event = CreateEvent(NULL, TRUE, FALSE, NULL)))
	{
		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot create timeout event for data thread: %s",
				strerror_from_system(GetLastError())));
		return SYSINFO_RET_FAIL;
	}
	thread_args.args = (void *)&metric_args;
	zbx_thread_start(agent_metric_thread, &thread_args, &thread);
	if (ZBX_THREAD_ERROR == thread)
	{
		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot start data thread: %s",
				strerror_from_system(GetLastError())));
		CloseHandle(metric_args.timeout_event);
		return SYSINFO_RET_FAIL;
	}
	if (WAIT_FAILED == (rc = WaitForSingleObject(thread, CONFIG_TIMEOUT * 1000)))
	{
		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot wait for data: %s",
				strerror_from_system(GetLastError())));
		terminate_thread = TRUE;
	}
	else if (WAIT_TIMEOUT == rc)
	{
		SET_MSG_RESULT(result, zbx_strdup(NULL, "Timeout while waiting for data."));
		if (FALSE == SetEvent(metric_args.timeout_event))
		{
			zabbix_log(LOG_LEVEL_ERR, "SetEvent() failed: %s", strerror_from_system(GetLastError()));
			terminate_thread = TRUE;
		}
		else
		{
			DWORD	timeout_rc = WaitForSingleObject(thread, 3000);	
			if (WAIT_FAILED == timeout_rc)
			{
				zabbix_log(LOG_LEVEL_ERR, "Waiting for data failed: %s",
						strerror_from_system(GetLastError()));
				terminate_thread = TRUE;
			}
			else if (WAIT_TIMEOUT == timeout_rc)
			{
				zabbix_log(LOG_LEVEL_ERR, "Stuck data thread");
				terminate_thread = TRUE;
			}
		}
	}
	if (TRUE == terminate_thread)
	{
		if (FALSE != TerminateThread(thread, 0))
		{
			zabbix_log(LOG_LEVEL_ERR, "%s(): TerminateThread() for %s[%s%s] succeeded", __func__,
					request->key, (0 < request->nparam) ? request->params[0] : "",
					(1 < request->nparam) ? ",..." : "");
		}
		else
		{
			zabbix_log(LOG_LEVEL_ERR, "%s(): TerminateThread() for %s[%s%s] failed: %s", __func__,
					request->key, (0 < request->nparam) ? request->params[0] : "",
					(1 < request->nparam) ? ",..." : "",
					strerror_from_system(GetLastError()));
		}
	}
	CloseHandle(thread);
	CloseHandle(metric_args.timeout_event);
	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s '%s'", __func__,
			zbx_sysinfo_ret_string(metric_args.agent_ret), ISSET_MSG(result) ? result->msg : "");
	return WAIT_OBJECT_0 == rc ? metric_args.agent_ret : SYSINFO_RET_FAIL;
}
int zbx_execute_threaded_metric ( zbx_metric_func_t metric_func , AGENT_REQUEST * request , AGENT_RESULT * result ) { ZBX_THREAD_HANDLE thread ; zbx_thread_args_t thread_args ; zbx_metric_thread_args_t metric_args = { metric_func , request , result , ZBX_MUTEX_THREAD_DENIED | ZBX_MUTEX_LOGGING_DENIED } ; DWORD rc ; BOOL terminate_thread = FALSE ; zabbix_log ( LOG_LEVEL_DEBUG , " " , __func__ , request -> key ) ; if ( NULL == ( metric_args . timeout_event = CreateEvent ( NULL , TRUE , FALSE , NULL ) ) ) { SET_MSG_RESULT ( result , zbx_dsprintf ( NULL , " " , strerror_from_system ( GetLastError ( ) ) ) ) ; return SYSINFO_RET_FAIL ; } thread_args . args = ( void * ) & metric_args ; zbx_thread_start ( agent_metric_thread , & thread_args , & thread ) ; if ( ZBX_THREAD_ERROR == thread ) { SET_MSG_RESULT ( result , zbx_dsprintf ( NULL , " " , strerror_from_system ( GetLastError ( ) ) ) ) ; CloseHandle ( metric_args . timeout_event ) ; return SYSINFO_RET_FAIL ; } if ( WAIT_FAILED == ( rc = WaitForSingleObject ( thread , CONFIG_TIMEOUT * 1000 ) ) ) { SET_MSG_RESULT ( result , zbx_dsprintf ( NULL , " " , strerror_from_system ( GetLastError ( ) ) ) ) ; terminate_thread = TRUE ; } else if ( WAIT_TIMEOUT == rc ) { SET_MSG_RESULT ( result , zbx_strdup ( NULL , " " ) ) ; if ( FALSE == SetEvent ( metric_args . timeout_event ) ) { zabbix_log ( LOG_LEVEL_ERR , " " , strerror_from_system ( GetLastError ( ) ) ) ; terminate_thread = TRUE ; } else { DWORD timeout_rc = WaitForSingleObject ( thread , 3000 ) ; if ( WAIT_FAILED == timeout_rc ) { zabbix_log ( LOG_LEVEL_ERR , " " , strerror_from_system ( GetLastError ( ) ) ) ; terminate_thread = TRUE ; } else if ( WAIT_TIMEOUT == timeout_rc ) { zabbix_log ( LOG_LEVEL_ERR , " " ) ; terminate_thread = TRUE ; } } } if ( TRUE == terminate_thread ) { if ( FALSE != TerminateThread ( thread , 0 ) ) { zabbix_log ( LOG_LEVEL_ERR , " " , __func__ , request -> key , ( 0 < request -> nparam ) ? request -> params [ 0 ] : " " , ( 1 < request -> nparam ) ? " " : " " ) ; } else { zabbix_log ( LOG_LEVEL_ERR , " " , __func__ , request -> key , ( 0 < request -> nparam ) ? request -> params [ 0 ] : " " , ( 1 < request -> nparam ) ? " " : " " , strerror_from_system ( GetLastError ( ) ) ) ; } } CloseHandle ( thread ) ; CloseHandle ( metric_args . timeout_event ) ; zabbix_log ( LOG_LEVEL_DEBUG , " " , __func__ , zbx_sysinfo_ret_string ( metric_args . agent_ret ) , ISSET_MSG ( result ) ? result -> msg : " " ) ; return WAIT_OBJECT_0 == rc ? metric_args . agent_ret : SYSINFO_RET_FAIL ; }
Function: zbx_execute_threaded_metric
Function : zbx_execute_threaded_metric
/* 1000 is multiplier for converting seconds into milliseconds */ /* unexpected error */ /* timeout; notify thread to clean up and exit, if stuck then terminate it */ /* wait up to 3 seconds */ /* timeout_rc must be WAIT_OBJECT_0 (signaled) */