/** * @file: $RCSfile: main.c,v $ * @brief: $IEC 61850 Protocol * * @version: $Revision: 1.9 $ * @date: $Date: 2020/10/28 05:21:18 $ * @author: $Author: lizhongming $ * @state: $State: Exp $ * * @latest: $Id: main.c,v 1.9 2020/10/28 05:21:18 lizhongming Exp $ * */ #include "rdb_client.h" #include "db_interface.h" #include "node.h" /*lnk10-10 */ #include "../rocketmq/SimpleProducer.h" #include "../log4cplus/log4.h"//lnk添加log4 #include "../cfg_parse/custom_printf.h"//lnk20250225 extern G_TEST_FLAG; extern pthread_mutex_t mtx; extern pt61850app_t *g_pt61850app; extern node_t *g_node; char g_my_conf_fname[256]; char g_onlyIP[255]; //直连某个IP,仅仅为方便测试 apr_pool_t *g_root_pool; apr_pool_t *g_rdb_pool; apr_pool_t *g_cfg_pool; uint16_t g_client_id = 0; uint32_t g_node_id = 0; uint32_t g_min_free_size = 1024; int g_need_password = 0; int INITFLAG = 0; //lnk20250304 char subdir[128] = "cfg_stat_data" ; int usage(); int parse_param(int argc, const char **argv); #include "ver_conf.h" #ifdef DEBUG_SISCO SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; #endif /////////////////////////////////////////////////////// uint32_t g_dead_lock_counter = 0; uint32_t g_thread_blocked_times = 0; //给mq生产线程和定时线程都加上死锁计数器 uint32_t g_mqproducer_blocked_times = 0; uint32_t g_ontime_blocked_times = 0; /////////////////////////////////////////////////////////////////////////////// int three_secs_enabled = 0; int auto_register_report_enabled = 0; int g_front_seg_index = 0; int g_front_seg_num = 0; int FRONT_MP_NUM = 0;//终端连接数量 int g_front_num_count = 0;//终端连接数量过低次数 /////////////////////////////////////////////////////////////////////////////// //根据配置子目录判别全局功能的投退,设定四个分功能性能均衡程序的功能运行划分设定 void init_global_function_enable() { if (strcmp(subdir,"cfg_stat_data")==0) { //历史稳态 g_node_id = STAT_DATA_BASE_NODE_ID; auto_register_report_enabled = 1; }else if (strcmp(subdir,"cfg_3s_data")==0) { //实时 g_node_id = THREE_SECS_DATA_BASE_NODE_ID; three_secs_enabled = 1; }else if (strcmp(subdir,"cfg_soe_comtrade")==0) { //告警和录波和暂态 g_node_id = SOE_COMTRADE_BASE_NODE_ID; }else if (strcmp(subdir,"cfg_his_data")==0) { //不使用 g_node_id = RECALL_ALL_DATA_BASE_NODE_ID; g_node_id = HIS_DATA_BASE_NODE_ID; } else if (strcmp(subdir, "cfg_newhis_data") == 0) { //不使用 g_node_id = RECALL_ALL_DATA_BASE_NODE_ID; g_node_id = NEW_HIS_DATA_BASE_NODE_ID; } else if (strcmp(subdir, "cfg_recallhis_data") == 0) { //补招 g_node_id = RECALL_HIS_DATA_BASE_NODE_ID; } else if (strcmp(subdir, "cfg_recallall_data") == 0) { //不使用 g_node_id = RECALL_ALL_DATA_BASE_NODE_ID; } } ////////////////////////////////////////////////////////////////////////////////// #ifdef _OS_UNIX_ void init_daemon(void) { int pid; int i; if( pid = fork() ) exit(0); /** 是父进程,结束父进程 */ else if( pid < 0 ) exit(1); /** fork失败,退出 */ /** 是第一子进程,后台继续执行 */ setsid(); /** 第一子进程成为新的会话组长和进程组长并与控制终端分离 */ if( pid = fork() ) exit(0); /** 是第一子进程,结束第一子进程 */ else if( pid < 0) exit(1); /** fork失败,退出 */ chdir("/FeProject/bin/"); //multi process running at same time umask(0); /** 重设文件创建掩码 */ return; } #endif //"--subdir, set the subdir of /CloudForward/ as the working directory, \n" int usage() { fprintf(stderr,"\nUsage : pt61850netd_pqfe -d [subdir] \n"); exit(-1); } int prepare_entironment_2() { apr_status_t rv; /* apr library need call this first. */ apr_initialize(); //APACHE初始化 atexit(apr_terminate); /* Create node root pool */ rv = apr_pool_create(&g_root_pool, NULL); //分配根内存 if(rv != APR_SUCCESS) { fprintf(stderr,"%s","Create node root pool failed!\n"); return (-1); } #ifdef SIGPIPE /* Ignore writes to connections that have been closed at the other end. */ apr_signal(SIGPIPE, SIG_IGN); #endif rv = create_log_handle(g_root_pool); if(rv != APR_SUCCESS) { printf("init_log failed!\n"); return (-1); } else { unsigned int error = 0; unsigned int warn = 0; unsigned int info = 0; log_config_t *log_handle = get_log_handle(); parse_log_switch_ini(&error,&warn,&info); log_handle->status.debug = info;//0;//1; log_handle->status.warn = warn;//0;//1; log_handle->status.error = error;//0;//1; } echo_msg("==============================================================\n"); rv = apr_pool_create(&g_rdb_pool, g_root_pool); //分配RDB内存 if(rv != APR_SUCCESS) { echo_errg("Create system runtime pool failed!\n"); return (-1); } rv = apr_pool_create(&g_cfg_pool, g_root_pool); //分配配置内存 if(rv != APR_SUCCESS) { echo_errg("Create system config pool failed!\n"); return (-1); } /* Initialize the register table. Call these functions first! */ echo_msg1("%-60s","Initialize system register......"); echo_msg("OK\n\n"); initTimezoneOffset(); return APR_SUCCESS; } #ifdef _OS_UNIX_ #include #include #include void printf_cur_user() { struct passwd *pwd; pwd = getpwuid(getuid()); echo_warn1("Current user: %s\n", pwd->pw_name); } #endif int main(int argc, const char **argv) { uint32_t stimer = 1; apr_status_t rv; /* Prepare the system context */ rv=prepare_entironment_2(); if (rv!=APR_SUCCESS){ return rv; } getVersion(argc,argv); rv=parse_param(argc, argv); if (rv!=APR_SUCCESS){ return rv; } //lnk启动进程日志 init_logger_process(); //char buf[256]; //format_log_msg(buf,sizeof(buf),"前置的%s%d号进程 进程级日志初始化完毕", get_front_msg_from_subdir(), g_front_seg_index); //log_debug("process", buf); DIY_INFOLOG("process","【NORMAL】前置的%s%d号进程 进程级日志初始化完毕", get_front_msg_from_subdir(), g_front_seg_index); #ifdef _OS_UNIX_ #ifdef QT_NO_DEBUG if (!g_need_password) init_daemon(); #endif #endif init_global_function_enable(); apr_snprintf(g_my_conf_fname,sizeof(g_my_conf_fname),"../%s/etc/pt61850netd_pqfe.xml",subdir); #if defined (DEBUG_SISCO) init_log_cfg (); #endif printf("\n\n"); #ifdef _OS_UNIX_ printf_cur_user(); #endif if (g_need_password) { if ( process_login_verify() == 0) { echo_warn("User login succeeded!\n"); } else { echo_warn("User login failed!\n"); apr_sleep(apr_time_from_sec(3)); exit(-59); } } rv = init_rdb(); if (rv!=APR_SUCCESS){ //char buf[256]; //format_log_msg(buf,sizeof(buf),"前置的%s%d号进程 台账初始化失败", get_front_msg_from_subdir(), g_front_seg_index); //log_error("process", buf); DIY_ERRORLOG_CODE("process",LOG_CODE_LEDGER,"【ERROR】前置的%s%d号进程 台账初始化失败", get_front_msg_from_subdir(), g_front_seg_index); return rv; } rv = run_protocol(); if (rv!=APR_SUCCESS){ //char buf[256]; //format_log_msg(buf,sizeof(buf),"前置的%s%d号进程 线程初始化失败", get_front_msg_from_subdir(), g_front_seg_index); //log_error("process", buf); DIY_ERRORLOG_CODE("process",LOG_CODE_OTHER,"【ERROR】前置的%s%d号进程 线程初始化失败", get_front_msg_from_subdir(), g_front_seg_index); return rv; } //初始化完成标志,防止还未准备完全就接收消息处理导致崩溃 INITFLAG = 1; //调试用 printf("INITFLAG=%d\n",INITFLAG); if (1 == G_TEST_FLAG) { //lnk添加mq模拟测试,这个只能放在主线程 printf("try_start_mqtest_thread \n"); int ret = try_start_mqtest_thread(0,NULL); // 等待线程退出 echo_warn1("%-60s","System shutdown now......"); apr_pool_destroy(g_root_pool); echo_msg("OK\n"); return ret; } while(1) { /* sleep 1s, just like 1s timer */ apr_sleep(apr_time_from_sec(1)); /* 每30秒钟检查一次状态 */ if( !(stimer++ % 60) ) {//分钟 if (g_dead_lock_counter++ >=3) {//三分钟 g_thread_blocked_times++; g_dead_lock_counter = 0; } MVL_LOG_ACSE1 ("MYLOG: current g_thread_blocked_times = %u ", g_thread_blocked_times); if (FRONT_MP_NUM <= 1) {//监测点数 g_front_num_count++; } else { g_front_num_count = 0; } } //work线程死了3*13分钟,退出进程 if (g_thread_blocked_times>=13) { MVL_LOG_ACSE0 ("MYLOG: g_thread_blocked_times>=3, so exit to restart "); //char buf[256]; //format_log_msg(buf,sizeof(buf),"前置的业务线程死锁,退出进程"); //log_error("process", buf); DIY_ERRORLOG_CODE("process",LOG_CODE_OTHER,"【ERROR】前置的%s%d号进程 业务线程死锁,退出进程", get_front_msg_from_subdir(), g_front_seg_index); apr_sleep(apr_time_from_sec(10)); exit(-1039); } //lnk20241211 添加测试开关 /*pthread_mutex_lock(&mtx); if (!G_TEST_FLAG && g_front_num_count >= 30 && g_onlyIP[0] == 0 && g_node->n_clients>10) {//30分钟连接数量过低且不是单连且台账大于十个终端 MVL_LOG_ACSE0("MYLOG: g_front_num_count>=20, so exit to restart "); apr_sleep(apr_time_from_sec(10)); exit(-1039); } pthread_mutex_unlock(&mtx);*/ } echo_warn1("%-60s","System shutdown now......"); apr_pool_destroy(g_root_pool); echo_msg("OK\n"); return 0; } int parse_param(int argc, const char **argv) { apr_status_t rv; apr_getopt_t *opt; char *opt_arg; char ch; char *p; char temp[128]; g_node_id = 0; echo_warn2("================= compiled@ %s %s =================\n",__DATE__ , __TIME__ ); /* Parse the command-line parameter */ if( argc > 1 ) { rv = apr_getopt_init(&opt, g_root_pool, argc, argv); while (apr_getopt(opt, "q:Q:a:A:d:D:p:P:f:F:r:R:T:t:s:S", &ch, &opt_arg) == APR_SUCCESS) { switch (ch) { case 'q': case 'Q': if (opt_arg[0] >= '0' && opt_arg[0] <= '9' ) { g_min_free_size = atoi(opt_arg); } else return (usage()); break; case 'R': case 'r': break; case 's': case 'S': echo_warn1(">>>>>>>>>>>>>>>>>>>>>parse -s %s ", opt_arg); strcpy(temp, opt_arg); p = strtok(temp, "_"); //1_5 echo_warn1("p %s ", p); g_front_seg_index = atoi(p); printf("g_front_seg_index:%d",g_front_seg_index); p = strtok(NULL, "_"); //1_5 echo_warn1("p %s ", p); g_front_seg_num = atoi(p); printf("g_front_seg_num:%d",g_front_seg_num); break; break; case 'a': case 'A': strcpy(g_onlyIP,opt_arg); break; case 'd': case 'D': strcpy(subdir,opt_arg); break; case 'T': case 't': break; case 'f': case 'F': break; case 'P': case 'p': if (opt_arg[0] >= '0' && opt_arg[0] <= '9' ) { g_need_password = atoi(opt_arg); } else return (usage()); break; case '?': default: return (usage()); } } } return 0; } ///////////////////////////////////////////////////////////////添加测试进程的监控函数lnk20250304 void doMonitorTaskmain(void) { static int stimer = 0; stimer++; if( !(stimer++ % 60) ) {//分钟 if (g_dead_lock_counter++ >=3) {//三分钟 g_thread_blocked_times++; g_mqproducer_blocked_times++; g_ontime_blocked_times++; g_dead_lock_counter = 0; } MVL_LOG_ACSE1 ("MYLOG: current g_thread_blocked_times = %u ", g_thread_blocked_times); if (FRONT_MP_NUM <= 1) {//监测点数 g_front_num_count++; } else { g_front_num_count = 0; } } //work线程死了3*13分钟,退出进程 if (g_thread_blocked_times>=13 || g_mqproducer_blocked_times>=13 || g_ontime_blocked_times>=13 ) { MVL_LOG_ACSE0 ("MYLOG: g_thread_blocked_times>=3, so exit to restart "); apr_sleep(apr_time_from_sec(10)); exit(-1039); } //lnk20241211 添加测试开关 pthread_mutex_lock(&mtx); if (!G_TEST_FLAG && g_front_num_count >= 30 && g_onlyIP[0] == 0 && g_node->n_clients>10) {//30分钟连接数量过低且不是单连且台账大于十个终端 MVL_LOG_ACSE0("MYLOG: g_front_num_count>=20, so exit to restart "); apr_sleep(apr_time_from_sec(10)); exit(-1039); } pthread_mutex_unlock(&mtx); }