#include "precompile.h" #include "sp_mod.h" #include "sp_svc.h" #include "sp_env.h" #include "sp_def.h" #include "SpBase.h" #include "shm_mem.h" #include "process_monitor.h" #include "refcnt.h" #include "spinlock.h" #include "strutil.h" #include "sp_logwithlinkforc.h" #include "dbgutil.h" #ifdef _WIN32 #include #include #include "sp_groupProcess.h" #endif //_WIN32 #include "sp_gui.h" #include "sp_env.h" #include #include #include #include #include #include #include #include #define TAG SPBASE_TAG("sp_mod") #include "toolkit.h" #include "StartUpBase.h" #define BUFSIZE 10240 #define MOD_CMD_INIT 0 #define MOD_CMD_TERM 1 #define MOD_CMD_START 2 #define MOD_CMD_STOP 3 #define MOD_CMD_PAUSE 4 #define MOD_CMD_CONTINUE 5 #define MOD_CMD_TEST 6 #define MOD_CMD_MOD_RESULT 7 #define MOD_CMD_ENT_RESULT 8 #define MOD_CMD_REPORT_CREATE_CONN 9 #define MOD_CMD_REPROT_CLOSE_CONN 10 #define MOD_CMD_REPORT_EXCEPTION 12 #define MOD_CMD_SUBSCRIBE_STATE_LISTENER 13 #define MOD_CMD_UNSUBSCRIBE_STATE_LISTENER 14 #define MOD_CMD_SUBSCRIBE_LIFE_LISTENER 15 #define MOD_CMD_UNSUBSCRIBE_LIFE_LISTENER 16 #define MOD_CMD_RECORD_STATE_EVENT 17 #define MOD_CMD_RECORD_CREATE_CONN 18 #define MOD_CMD_RECORD_CLOSE_CONN 19 #define MOD_CMD_RECORD_ENTITY_CLOSE 20 #define MOD_CMD_RECORD_ENTITY_CREATE 21 #define MOD_CMD_RECORD_ENTITY_EXCEPTION 22 #define MOD_CMD_SWITCH_RUNNING_MODE 23 #define MOD_CMD_USER_STATE_EVENT 24 #define MOD_CMD_ENT_RESULT_EX 25 #define MOD_CMD_NOTIFY_REDIRECT_SUBSCRIBE 31 // shell -> entity #define MOD_CMD_REPORT_REDIRECT_SUBSCRIBE 32 // entity -> shell //#define PROCESS_TIMEOUT 10000 #define PROCESS_TIMEOUT 120000 #define PROCESS_EXIT_TIMEOUT 4000 #define ENTITY_TEST_TIMEOUT 30000 #if defined(_MSC_VER) #define PROCESS_TIMEOUT_FOR_TERMINAL PROCESS_TIMEOUT #else #define PROCESS_TIMEOUT_FOR_TERMINAL 20000 #endif //_MSC_VER #ifdef _WIN32 extern void sp_mod_mgr_lockEx(int EntityId); extern void sp_mod_mgr_unlockEx(int EntityId); extern void sp_mod_mgr_lockArrClean(); #endif //_WIN32 struct sp_mod_stub_t { sp_mod_stub_cb cb; sp_iom_t *iom; }; struct sp_mod_entity_stub_t { sp_mod_entity_stub_cb cb; strand_t *strand; sp_svc_t *svc; }; #define SP_MOD_CMDTYPE_DEFINE(x) \ case x : return #x; break; static const char* str_cmdtype(int cmdtype) { switch (cmdtype) { SP_MOD_CMDTYPE_DEFINE(MOD_CMD_INIT) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_TERM) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_START) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_STOP) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_PAUSE) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_CONTINUE) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_TEST) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_MOD_RESULT) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_ENT_RESULT) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_REPORT_CREATE_CONN) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_REPROT_CLOSE_CONN) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_REPORT_EXCEPTION) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_SUBSCRIBE_STATE_LISTENER) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_UNSUBSCRIBE_STATE_LISTENER) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_SUBSCRIBE_LIFE_LISTENER) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_UNSUBSCRIBE_LIFE_LISTENER) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_RECORD_STATE_EVENT) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_RECORD_CREATE_CONN) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_RECORD_CLOSE_CONN) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_RECORD_ENTITY_CLOSE) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_RECORD_ENTITY_CREATE) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_RECORD_ENTITY_EXCEPTION) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_SWITCH_RUNNING_MODE) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_USER_STATE_EVENT) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_ENT_RESULT_EX) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_NOTIFY_REDIRECT_SUBSCRIBE) SP_MOD_CMDTYPE_DEFINE(MOD_CMD_REPORT_REDIRECT_SUBSCRIBE) default: return "unknown-cmdtype"; break; } } static int mod_kill_process(sp_mod_t* mod) { DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "to kill mod %s's process", mod->cfg->name); #ifdef _WIN32 if (0 != killModByPipe(findGroupProcessInfo(0, mod->cfg->name), mod->cfg->name)) { char szCmd[256]; int nRet = 0; DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "terminate %s fail: 0x%X, retry with taskkill", mod->cfg->name, GetLastError()); sprintf_s(szCmd, 256, "TASKKILL /PID %d /F", mod->process.pid); WinExec(szCmd, SW_HIDE); } return 0; #else //to kill -15 BOOL result = TerminateProcess(mod->process.handle, -1); if (!result && errno != 3) { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "to kill 15 cmd: %d", errno); if(kill(mod->process.pid, 9/*SIGKILL*/) && errno != 3) //No such process DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "kill 9 cmd for %s fail: %d", mod->cfg->name, errno); else result = TRUE; } return (result ? 0 : -1); #endif //_WIN32 } static int mod_on_pkt(sp_iom_t *iom, int to_svc_id, int epid, int svc_id, int pkt_type, int pkt_id, iobuffer_t **p_pkt, void *user_data) { sp_mod_stub_t *stub = (sp_mod_stub_t *)user_data; if (SP_GET_PKT_TYPE(pkt_type) == SP_PKT_MOD) { int cmd_type = SP_GET_TYPE(pkt_type); int result = Error_Bug; int processed = 0; if (cmd_type == MOD_CMD_INIT) { int service_flag = 0; int multithread_flag = 0; DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "receive module init cmd!"); __try { result = stub->cb.on_module_init(stub, stub->cb.user_data); } __except(EXCEPTION_EXECUTE_HANDLER) { result = Error_Exception; } if (result != 0) { DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM, "module init end! %d, %s", result, sp_strerror(result)); } sp_iom_post(iom, SP_INVALID_SVC_ID, epid, svc_id, SP_PKT_MOD|MOD_CMD_MOD_RESULT, result, NULL); } else if (cmd_type == MOD_CMD_TERM) { DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "receive module term cmd!"); __try { result = stub->cb.on_module_term(stub, stub->cb.user_data); } __except(EXCEPTION_EXECUTE_HANDLER) { result = Error_Exception; } sp_iom_post(iom, SP_INVALID_SVC_ID, epid, svc_id, SP_PKT_MOD|MOD_CMD_MOD_RESULT, result, NULL); sp_iom_post_quit(iom); } else { return TRUE; } return FALSE; } return TRUE; } int sp_mod_stub_create(const sp_mod_stub_cb *cb, sp_iom_t *iom, sp_mod_stub_t **p_stub) { sp_mod_stub_t *stub = MALLOC_T(sp_mod_stub_t); memcpy(&stub->cb, cb, sizeof(sp_mod_stub_cb)); stub->iom = iom; sp_iom_add_pkt_handler(iom, (int)stub, &mod_on_pkt, stub); *p_stub = stub; return 0; } void sp_mod_stub_destroy(sp_mod_stub_t *stub) { sp_iom_remove_pkt_handler(stub->iom, (int)stub); FREE(stub); } static void mod_entity_process_cmd(threadpool_t *threadpool, void *arg) { iobuffer_t *pkt = arg; sp_mod_entity_stub_t *stub; int epid; int svc_id; int pkt_type; int pkt_id; int cmd_type; WLog_DBG(TAG, "==> %s", __FUNCTION__); iobuffer_read(pkt, IOBUF_T_PTR, &stub, NULL); iobuffer_read(pkt, IOBUF_T_I4, &epid, NULL); iobuffer_read(pkt, IOBUF_T_I4, &svc_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &pkt_type, NULL); iobuffer_read(pkt, IOBUF_T_I4, &pkt_id, NULL); cmd_type = SP_GET_TYPE(pkt_type); switch (cmd_type) { case MOD_CMD_TEST: { int trigger_entity_id; int test_type; iobuffer_read(pkt, IOBUF_T_I4, &trigger_entity_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &test_type, NULL); stub->cb.on_entity_test(stub, trigger_entity_id, test_type, stub->cb.user_data); } break; case MOD_CMD_CONTINUE: { int trigger_entity_id; iobuffer_read(pkt, IOBUF_T_I4, &trigger_entity_id, NULL); stub->cb.on_entity_precontinue(stub, trigger_entity_id, stub->cb.user_data); } break; case MOD_CMD_PAUSE: { int trigger_entity_id; iobuffer_read(pkt, IOBUF_T_I4, &trigger_entity_id, NULL); stub->cb.on_entity_prepause(stub, trigger_entity_id, stub->cb.user_data); } break; case MOD_CMD_STOP: { int trigger_entity_id; int cause_code; iobuffer_read(pkt, IOBUF_T_I4, &trigger_entity_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &cause_code, NULL); stub->cb.on_entity_stop(stub, trigger_entity_id, cause_code, stub->cb.user_data); } break; case MOD_CMD_START: { int slen = 0; char *cmdline = NULL; int numargs, numchars; char *p = NULL; int argc = 0; char **argv = NULL; int trigger_entity_id; iobuffer_read(pkt, IOBUF_T_STR, NULL, &slen); if (slen) { cmdline = malloc(slen+1); iobuffer_read(pkt, IOBUF_T_STR, cmdline, NULL); str_parse_cmdline(cmdline, NULL, NULL, &numargs, &numchars); p = malloc(numargs*sizeof(char*) + numchars); argc = numargs - 1; /*except program.exe name, and actually it doesn't exist*/ argv = (char**)p; str_parse_cmdline(cmdline, (char **)p, p + numargs * sizeof(char *), &numargs, &numchars); } iobuffer_read(pkt, IOBUF_T_I4, &trigger_entity_id, NULL); WLog_DBG(TAG, "on_entity_prestart address: %p", (void*)stub->cb.on_entity_prestart); stub->cb.on_entity_prestart(stub, trigger_entity_id, argc, argv, stub->cb.user_data); WLog_DBG(TAG, "after invoke on_entity_prestart(trigger %d)", trigger_entity_id); free(p); free(cmdline); } break; case MOD_CMD_NOTIFY_REDIRECT_SUBSCRIBE: { int slen = 0; int from_entity_id = pkt_id; sp_uid_t uid; char *param = NULL; iobuffer_read(pkt, IOBUF_T_I8, &uid, 0); iobuffer_read(pkt, IOBUF_T_STR, NULL, &slen); if (slen) { param = malloc(slen + 1); iobuffer_read(pkt, IOBUF_T_STR, param, NULL); } stub->cb.on_entity_redirect_subscribe(stub, &uid, from_entity_id, param, stub->cb.user_data); free(param); } break; default: TOOLKIT_ASSERT(0); break; } iobuffer_dec_ref(pkt); WLog_DBG(TAG, "<== %s", __FUNCTION__); } static int mod_entity_on_pkt(sp_svc_t *svc, int epid, int svc_id, int pkt_type, int pkt_id, iobuffer_t **p_pkt, void *user_data) { sp_mod_entity_stub_t *stub = (sp_mod_entity_stub_t *)user_data; if (SP_GET_PKT_TYPE(pkt_type) == SP_PKT_MOD) { int cmd_type = SP_GET_TYPE(pkt_type); DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "rx entity cmd: %s !", str_cmdtype(cmd_type)); if (cmd_type == MOD_CMD_START || cmd_type == MOD_CMD_STOP || cmd_type == MOD_CMD_PAUSE || cmd_type == MOD_CMD_CONTINUE || cmd_type == MOD_CMD_TEST || cmd_type == MOD_CMD_NOTIFY_REDIRECT_SUBSCRIBE) { iobuffer_t *pkt = *p_pkt; *p_pkt = NULL; iobuffer_write_head(pkt, IOBUF_T_I4, &pkt_id, 0); iobuffer_write_head(pkt, IOBUF_T_I4, &pkt_type, 0); iobuffer_write_head(pkt, IOBUF_T_I4, &svc_id, 0); iobuffer_write_head(pkt, IOBUF_T_I4, &epid, 0); iobuffer_write_head(pkt, IOBUF_T_PTR, &stub, 0); threadpool_queue_workitem(sp_svc_get_threadpool(stub->svc), stub->strand, &mod_entity_process_cmd, pkt); return FALSE; } } return TRUE; } int sp_mod_entity_stub_create(const sp_mod_entity_stub_cb *cb, sp_svc_t *svc, sp_mod_entity_stub_t **p_stub) { sp_mod_entity_stub_t *stub = MALLOC_T(sp_mod_entity_stub_t); memcpy(&stub->cb, cb, sizeof(sp_mod_entity_stub_cb)); stub->svc = svc; stub->strand = strand_create(); sp_svc_add_pkt_handler(svc, (int)stub, SP_PKT_MOD, &mod_entity_on_pkt, stub); *p_stub = stub; return 0; } void sp_mod_entity_stub_destroy(sp_mod_entity_stub_t *stub) { sp_svc_remove_pkt_handler(stub->svc, (int)stub, SP_PKT_MOD); strand_destroy(stub->strand); free(stub); } int sp_mod_entity_stub_report_create_connection(sp_mod_entity_stub_t *stub, int remote_entity) { sp_svc_post(stub->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_REPORT_CREATE_CONN, remote_entity, NULL); return 0; } int sp_mod_entity_stub_report_close_connection(sp_mod_entity_stub_t *stub, int remote_entity) { sp_svc_post(stub->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_REPROT_CLOSE_CONN, remote_entity, NULL); return 0; } int sp_mod_entity_stub_report_exception(sp_mod_entity_stub_t *stub, int win32_exception_code, int eip, int in_func) { iobuffer_t *pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_I4, &win32_exception_code, 0); iobuffer_write(pkt, IOBUF_T_I4, &eip, 0); iobuffer_write(pkt, IOBUF_T_I4, &in_func, 0); sp_svc_post(stub->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_REPORT_EXCEPTION, SP_SHELL_SVC_ID, &pkt); if (pkt) iobuffer_dec_ref(pkt); return 0; } int sp_mod_entity_stub_switch_running_state(sp_mod_entity_stub_t *stub, int state) { sp_svc_post(stub->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_SWITCH_RUNNING_MODE, state, NULL); return 0; } int sp_mod_entity_stub_report_user_state_change(sp_mod_entity_stub_t *stub, int last_state, int curr_state) { iobuffer_t *pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_I4, &last_state, 0); iobuffer_write(pkt, IOBUF_T_I4, &curr_state, 0); sp_svc_post(stub->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_USER_STATE_EVENT, 0, &pkt); if (pkt) iobuffer_dec_ref(pkt); return 0; } int sp_mod_entity_stub_finish_start(sp_mod_entity_stub_t *stub, int result) { sp_svc_post(stub->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_ENT_RESULT, result, NULL); return 0; } int sp_mod_entity_stub_finish_stop(sp_mod_entity_stub_t *stub, int result) { sp_svc_post(stub->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_ENT_RESULT, result, NULL); return 0; } int sp_mod_entity_stub_finish_pause(sp_mod_entity_stub_t *stub, int result) { sp_svc_post(stub->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_ENT_RESULT, result, NULL); return 0; } int sp_mod_entity_stub_finish_continue(sp_mod_entity_stub_t *stub, int result) { sp_svc_post(stub->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_ENT_RESULT, result, NULL); return 0; } int sp_mod_entity_stub_finish_test(sp_mod_entity_stub_t *stub, int result) { sp_svc_post(stub->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_ENT_RESULT, result, NULL); return 0; } int sp_mod_entity_stub_finish_exam(sp_mod_entity_stub_t* stub, int result, int statistic) { iobuffer_t* pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_I4, &statistic, 0); sp_svc_post(stub->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD | MOD_CMD_ENT_RESULT_EX, result, &pkt); if (pkt) iobuffer_dec_ref(pkt); return 0; } int sp_mod_entity_stub_finish_redirect_subscribe(sp_mod_entity_stub_t *stub, sp_uid_t *uid, int suggest_entity_id) { iobuffer_t *pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_I8, uid, 0); iobuffer_write(pkt, IOBUF_T_I4, &suggest_entity_id, 0); sp_svc_post(stub->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_REPORT_REDIRECT_SUBSCRIBE, 0, &pkt); if (pkt) iobuffer_dec_ref(pkt); return 0; } // // entity event listener // struct sp_mod_entity_state_listener_t { sp_mod_entity_event_cb cb; sp_svc_t *svc; int target_entity_id; spinlock_t lock; strand_t *strand; int stop; void *user_data; DECLARE_REF_COUNT_MEMBER(ref_cnt); }; DECLARE_REF_COUNT_STATIC(sp_mod_entity_state_listener, sp_mod_entity_state_listener_t) static void mod_entity_state_listener_process_cmd(threadpool_t *threadpool, void *arg) { sp_mod_entity_state_listener_t *listener; iobuffer_t *pkt = arg; iobuffer_read(pkt, IOBUF_T_PTR, &listener, NULL); spinlock_enter(&listener->lock, -1); if (!listener->stop) { int epid; int svc_id; int pkt_type; int pkt_id; int cmd_type; iobuffer_read(pkt, IOBUF_T_I4, &epid, NULL); iobuffer_read(pkt, IOBUF_T_I4, &svc_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &pkt_type, NULL); iobuffer_read(pkt, IOBUF_T_I4, &pkt_id, NULL); cmd_type = SP_GET_TYPE(pkt_type); if (cmd_type == MOD_CMD_RECORD_STATE_EVENT) { int entity_id; int trigger_entity_id; int last_state; int curr_state; iobuffer_read(pkt, IOBUF_T_I4, &entity_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &trigger_entity_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &last_state, NULL); iobuffer_read(pkt, IOBUF_T_I4, &curr_state, NULL); if (listener->target_entity_id == -1 || listener->target_entity_id == entity_id) listener->cb.on_entity_state(listener, entity_id, trigger_entity_id, last_state, curr_state, listener->cb.user_data); } else if (cmd_type == MOD_CMD_USER_STATE_EVENT) { int entity_id; int last_state; int curr_state; iobuffer_read(pkt, IOBUF_T_I4, &entity_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &last_state, NULL); iobuffer_read(pkt, IOBUF_T_I4, &curr_state, NULL); if (listener->target_entity_id == -1 || listener->target_entity_id == entity_id) listener->cb.on_user_state(listener, entity_id, last_state, curr_state, listener->cb.user_data); } else if (cmd_type == MOD_CMD_RECORD_CREATE_CONN) { int src_entity_id; int dst_entity_id; iobuffer_read(pkt, IOBUF_T_I4, &src_entity_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &dst_entity_id, NULL); if (listener->target_entity_id == -1 || listener->target_entity_id == src_entity_id || listener->target_entity_id == dst_entity_id) listener->cb.on_create_connection(listener, src_entity_id, dst_entity_id, listener->cb.user_data); } else if (cmd_type == MOD_CMD_RECORD_CLOSE_CONN) { int src_entity_id; int dst_entity_id; iobuffer_read(pkt, IOBUF_T_I4, &src_entity_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &dst_entity_id, NULL); if (listener->target_entity_id == -1 || listener->target_entity_id == src_entity_id || listener->target_entity_id == dst_entity_id) listener->cb.on_close_connection(listener, src_entity_id, dst_entity_id, listener->cb.user_data); } else { TOOLKIT_ASSERT(0); } } spinlock_leave(&listener->lock); iobuffer_dec_ref(pkt); sp_mod_entity_state_listener_dec_ref(listener); } static int mod_entity_state_listener_on_pkt(sp_svc_t *svc, int epid, int svc_id, int pkt_type, int pkt_id, iobuffer_t **p_pkt, void *user_data) { sp_mod_entity_state_listener_t *listener = (sp_mod_entity_state_listener_t *)user_data; if (SP_GET_PKT_TYPE(pkt_type) == SP_PKT_MOD && !listener->stop) { const int cmd_type = SP_GET_TYPE(pkt_type); if (cmd_type == MOD_CMD_RECORD_STATE_EVENT || cmd_type == MOD_CMD_USER_STATE_EVENT || cmd_type == MOD_CMD_RECORD_CREATE_CONN || cmd_type == MOD_CMD_RECORD_CLOSE_CONN) { iobuffer_t *pkt = iobuffer_clone(*p_pkt); iobuffer_write_head(pkt, IOBUF_T_I4, &pkt_id, 0); iobuffer_write_head(pkt, IOBUF_T_I4, &pkt_type, 0); iobuffer_write_head(pkt, IOBUF_T_I4, &svc_id, 0); iobuffer_write_head(pkt, IOBUF_T_I4, &epid, 0); iobuffer_write_head(pkt, IOBUF_T_PTR, &listener, 0); sp_mod_entity_state_listener_inc_ref(listener); if (threadpool_queue_workitem( sp_svc_get_threadpool(listener->svc), listener->strand, mod_entity_state_listener_process_cmd, pkt) < 0) { sp_mod_entity_state_listener_dec_ref(listener); iobuffer_dec_ref(pkt); } } } return TRUE; } int sp_mod_entity_listener_create(int target_entity_id, const sp_mod_entity_event_cb *cb, sp_svc_t *svc, void *tag, sp_mod_entity_state_listener_t **p_listener) { sp_mod_entity_state_listener_t *listener = MALLOC_T(sp_mod_entity_state_listener_t); memcpy(&listener->cb, cb, sizeof(sp_mod_entity_event_cb)); listener->svc = svc; listener->stop = 0; listener->user_data = tag; listener->target_entity_id = target_entity_id; spinlock_init(&listener->lock); listener->strand = strand_create(); REF_COUNT_INIT(&listener->ref_cnt); sp_svc_add_pkt_handler(svc, (int)listener, SP_PKT_MOD, &mod_entity_state_listener_on_pkt, listener); *p_listener = listener; sp_svc_post(svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_SUBSCRIBE_STATE_LISTENER, target_entity_id, NULL); return 0; } static void __sp_mod_entity_listener_destroy(sp_mod_entity_state_listener_t *listener) { strand_destroy(listener->strand); free(listener); } IMPLEMENT_REF_COUNT_MT_STATIC(sp_mod_entity_state_listener,sp_mod_entity_state_listener_t,ref_cnt, __sp_mod_entity_listener_destroy) void sp_mod_entity_listener_destroy(sp_mod_entity_state_listener_t *listener) { sp_svc_post(listener->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_UNSUBSCRIBE_STATE_LISTENER, listener->target_entity_id, NULL); spinlock_enter(&listener->lock, -1); listener->stop = TRUE; spinlock_leave(&listener->lock); sp_svc_remove_pkt_handler(listener->svc, (int)listener, SP_PKT_MOD); sp_mod_entity_state_listener_dec_ref(listener); } void sp_mod_entity_listener_set_tag(sp_mod_entity_state_listener_t *listener, void *data) { listener->user_data = data; } void *sp_mod_entity_listener_get_tag(sp_mod_entity_state_listener_t *listener) { return listener->user_data; } // entity life listener struct sp_mod_entity_life_listener_t { sp_mod_entity_life_cb cb; sp_svc_t *svc; spinlock_t lock; strand_t *strand; int stop; void *user_data; DECLARE_REF_COUNT_MEMBER(ref_cnt); }; DECLARE_REF_COUNT_STATIC(sp_mod_entity_life_listener, sp_mod_entity_life_listener_t) static void mod_entity_life_listener_process_cmd(threadpool_t *threadpool, void *arg) { sp_mod_entity_life_listener_t *listener; iobuffer_t *pkt = arg; iobuffer_read(pkt, IOBUF_T_PTR, &listener, NULL); spinlock_enter(&listener->lock, -1); if (!listener->stop) { int epid; int svc_id; int pkt_type; int pkt_id; int cmd_type; iobuffer_read(pkt, IOBUF_T_I4, &epid, NULL); iobuffer_read(pkt, IOBUF_T_I4, &svc_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &pkt_type, NULL); iobuffer_read(pkt, IOBUF_T_I4, &pkt_id, NULL); cmd_type = SP_GET_TYPE(pkt_type); if (cmd_type == MOD_CMD_RECORD_ENTITY_CREATE) { int entity_id; int trigger_entity_id; iobuffer_read(pkt, IOBUF_T_I4, &entity_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &trigger_entity_id, NULL); listener->cb.on_entity_create(listener, entity_id, trigger_entity_id, listener->cb.user_data); } else if (cmd_type == MOD_CMD_RECORD_ENTITY_CLOSE) { int entity_id; int trigger_entity_id; int close_cause; iobuffer_read(pkt, IOBUF_T_I4, &entity_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &trigger_entity_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &close_cause, NULL); listener->cb.on_entity_close(listener, entity_id, trigger_entity_id, close_cause, listener->cb.user_data); } else if (cmd_type == MOD_CMD_RECORD_ENTITY_EXCEPTION) { int entity_id; int error; int entity_state; iobuffer_read(pkt, IOBUF_T_I4, &entity_id, NULL); iobuffer_read(pkt, IOBUF_T_I4, &error, NULL); iobuffer_read(pkt, IOBUF_T_I4, &entity_state, NULL); listener->cb.on_entity_exception(listener, entity_id, error, entity_state, listener->cb.user_data); } else { TOOLKIT_ASSERT(0); } } spinlock_leave(&listener->lock); iobuffer_dec_ref(pkt); sp_mod_entity_life_listener_dec_ref(listener); } static int mod_entity_life_listener_on_pkt(sp_svc_t *svc, int epid, int svc_id, int pkt_type, int pkt_id, iobuffer_t **p_pkt, void *user_data) { sp_mod_entity_life_listener_t *listener = (sp_mod_entity_life_listener_t *)user_data; if (SP_GET_PKT_TYPE(pkt_type) == SP_PKT_MOD && !listener->stop) { int cmd_type = SP_GET_TYPE(pkt_type); if (cmd_type == MOD_CMD_RECORD_ENTITY_CREATE || cmd_type == MOD_CMD_RECORD_ENTITY_CLOSE || cmd_type == MOD_CMD_RECORD_ENTITY_EXCEPTION) { iobuffer_t *pkt = iobuffer_clone(*p_pkt); iobuffer_write_head(pkt, IOBUF_T_I4, &pkt_id, 0); iobuffer_write_head(pkt, IOBUF_T_I4, &pkt_type, 0); iobuffer_write_head(pkt, IOBUF_T_I4, &svc_id, 0); iobuffer_write_head(pkt, IOBUF_T_I4, &epid, 0); iobuffer_write_head(pkt, IOBUF_T_PTR, &listener, 0); sp_mod_entity_life_listener_inc_ref(listener); if (threadpool_queue_workitem( sp_svc_get_threadpool(listener->svc), listener->strand, &mod_entity_life_listener_process_cmd, pkt) < 0) { sp_mod_entity_life_listener_dec_ref(listener); iobuffer_dec_ref(pkt); } } } return TRUE; } int sp_mod_entity_life_listener_create(const sp_mod_entity_life_cb *cb, sp_svc_t *svc, void *tag, sp_mod_entity_life_listener_t **p_listener) { sp_mod_entity_life_listener_t *listener = MALLOC_T(sp_mod_entity_life_listener_t); memcpy(&listener->cb, cb, sizeof(sp_mod_entity_life_cb)); listener->svc = svc; listener->stop = 0; listener->user_data = tag; spinlock_init(&listener->lock); listener->strand = strand_create(); REF_COUNT_INIT(&listener->ref_cnt); sp_svc_add_pkt_handler(svc, (int)listener, SP_PKT_MOD, &mod_entity_life_listener_on_pkt, listener); *p_listener = listener; sp_svc_post(svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_SUBSCRIBE_LIFE_LISTENER, 0, NULL); return 0; } void __sp_mod_entity_life_listener_destroy(sp_mod_entity_life_listener_t *listener) { strand_destroy(listener->strand); free(listener); } IMPLEMENT_REF_COUNT_MT_STATIC(sp_mod_entity_life_listener, sp_mod_entity_life_listener_t, ref_cnt, __sp_mod_entity_life_listener_destroy) void sp_mod_entity_life_listener_destroy(sp_mod_entity_life_listener_t *listener) { sp_svc_post(listener->svc, SP_SHELL_MOD_ID, SP_SHELL_SVC_ID, SP_PKT_MOD|MOD_CMD_UNSUBSCRIBE_LIFE_LISTENER, 0, NULL); spinlock_enter(&listener->lock, -1); listener->stop = TRUE; spinlock_leave(&listener->lock); sp_svc_remove_pkt_handler(listener->svc, (int)listener, SP_PKT_MOD); sp_mod_entity_life_listener_dec_ref(listener); } void sp_mod_entity_life_listener_set_tag(sp_mod_entity_life_listener_t *listener, void *data) { listener->user_data = data; } void *sp_mod_entity_life_listener_get_tag(sp_mod_entity_life_listener_t *listener) { return listener->user_data; } typedef struct entity_state_subscribe_entry { struct list_head entry; int mod_id; int svc_id; int instance; int target_entity_id; }entity_state_subscribe_entry; typedef struct entity_life_subscribe_entry { struct list_head entry; int mod_id; int svc_id; int instance; }entity_life_subscribe_entry; struct sp_mod_mgr_t { sp_bcm_daemon_t *shell_daemon; // only for shell use sp_svc_t *shell_svc; CRITICAL_SECTION lock; process_monitor_t *process_monitor; spinlock_t entity_state_subscribe_lock; struct list_head entity_state_subscribe_list; spinlock_t entity_life_subscribe_lock; struct list_head entity_life_subscribe_list; struct list_head mod_list; // list of sp_mod_t* array_header_t *arr_mod; // array of sp_mod_t* array_header_t *arr_ent; // array of sp_entity_t* LONG instance_seq; }; static __inline int mgr_new_instance_id(sp_mod_mgr_t *mgr) { return (int)InterlockedIncrement((LONG*)&mgr->instance_seq); } #if defined(RVC_OS_WIN) int assigntoJob(HANDLE process, int pid) { //创建一个job内核对象 HANDLE hd = CreateJobObjectA(NULL, NULL); if (hd) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION extLimitInfo; extLimitInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; if (!SetInformationJobObject(hd, JobObjectExtendedLimitInformation, &extLimitInfo, sizeof(extLimitInfo))) { CloseHandle(hd); return -1; } //insert the process into the job if (AssignProcessToJobObject(hd, process)) return 0; else { DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "AssignProcessToJobObject err! process: %d, %d", process, pid); return -1; } } else { DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "CreateJobObjectA err!"); return -1; } } #endif //RVC_OS_WIN static int create_module_process(const char *mod_name, int epid, int range, int debugFileExist, tk_process_t* new_process, int runType, int entity_id) { char app[MAX_PATH] = {'\0'}; int group = 0; #ifdef _WIN32 char writeParam[MAX_PATH] = ""; char mutexName[MAX_PATH] = ""; char eventName[MAX_PATH] = ""; //BOOL bRet; STARTUPINFOA si = { sizeof(STARTUPINFOA) }; PROCESS_INFORMATION pi; DWORD dwSessionId; HANDLE hUserTokenDup = NULL, hThisToken = NULL; HANDLE hProcess = NULL; HANDLE hMutex = NULL; int result = 0; sp_process_t* groupProcess = NULL; BOOL fConnected = FALSE; DWORD dwThreadId = 0; HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL; char lpszPipename[MAX_PATH] = "\\\\.\\pipe\\"; static DWORD shellId = 0; if (0 == shellId) shellId = GetCurrentProcessId(); if (0 != getNewGuid(mutexName)) { DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM, "get new gui failed!"); return -1; } if (runType == 1) sprintf(app, ".\\bin\\sphost.exe {%s} %d", mutexName, shellId); else sprintf(app, ".\\bin\\sphost_re.exe {%s} %d", mutexName, shellId); sprintf_s(writeParam, sizeof(writeParam), "%s %d %d %s %d %d", mod_name, epid, range, mutexName, debugFileExist, entity_id); do { sp_process_t* curProcess = ZALLOC_T(sp_process_t); LUID luid; TOKEN_PRIVILEGES tp; LPVOID pEnv = NULL; if (0 == group) checkGroupProcesInfo(group, mod_name); groupProcess = findGroupProcessInfo(group, mod_name);//1,group为0时,基于每个group0_entityName的进程;2,gourp不为0,基于groupN的进程 if (NULL != groupProcess) break;//already exist addStartupStep(epid, "open group process", "", 0, 0, 0); dwSessionId = WTSGetActiveConsoleSessionId(); if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hThisToken)) { addStartupStep(epid, "open process token", "failed", 0, 0, GetLastError()); break; } LookupPrivilegeValueA(NULL, SE_DEBUG_NAME, &luid); tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; DuplicateTokenEx(hThisToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hUserTokenDup); SetTokenInformation(hUserTokenDup, TokenSessionId, (void*)&dwSessionId, sizeof(DWORD)); AdjustTokenPrivileges(hUserTokenDup, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, NULL); //提升权限 sprintf(lpszPipename, "%s{%s}", lpszPipename, mutexName); sprintf(eventName, "{%s}", mutexName); hPipe = CreateNamedPipe(lpszPipename, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, 0, NULL); if (hPipe == INVALID_HANDLE_VALUE && !ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED)) return -1; hMutex = CreateEvent(NULL, FALSE, FALSE, eventName); if (!CreateProcessAsUserA(hUserTokenDup, NULL, app, NULL, NULL, FALSE, 0, pEnv, NULL, &si, &pi)) { addStartupStep(epid, "CreateProcessAsUserA failed!", "failed", 0, 0, GetLastError()); break; } new_process->pid = pi.dwProcessId; new_process->handle = pi.hProcess; CloseHandle(pi.hThread); hProcess = pi.hProcess; curProcess->process_Handle = hProcess; curProcess->pid = pi.dwProcessId; curProcess->group = group; curProcess->write_pipe = hPipe; curProcess->read_pipe = hPipe; AddGroupProcessInfo(group, curProcess, mod_name); assigntoJob(hProcess, pi.dwProcessId); if (WAIT_TIMEOUT == WaitForSingleObject(hMutex, 10000))//确定实体进程已启动 addStartupStep(epid, "open process timeout", "failed", 0, 0, Error_TimeOut); CloseHandle(hMutex); } while (0); CloseHandle(hUserTokenDup); CloseHandle(hThisToken); addStartupStep(entity_id, "start_mod", "", 0, 0, 0); //通过管道通知进程创建实体线程 if (NULL != (groupProcess = findGroupProcessInfo(group, mod_name)) && 0 == startModByPipe(groupProcess, writeParam)) { char dstParam[10][MAX_PATH]; int paramNum = 0; ZeroMemory(dstParam, sizeof(dstParam)); addStartupStep(entity_id, "query_mod", "", 0, 0, 0); if (-1 != (paramNum = queryModByPipe(groupProcess, mod_name, dstParam))) //return paramNum { char processId[20]; HANDLE processMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, dstParam[2]); new_process->pid = (int)groupProcess->pid; sprintf(processId, "%d", new_process->pid); addStartupStep(entity_id, "open_process_id", processId, 0, 0, 0); return 0; } } #else tk_process_t* process = NULL; tk_process_option_t option; sprintf(app, "./bin/sphost %d %s %d %d %d", range, mod_name, epid, debugFileExist, entity_id); option.exit_cb = NULL; option.file = NULL; option.flags = 0; option.params = app; if (0 == process_spawn(&option, &process)) { new_process->pid = process->pid; new_process->handle = process->handle; FREE(process); return 0; } #endif //_WIN32 return -1; } static void mgr_bcast_entity_state_event(sp_mod_mgr_t *mgr, sp_entity_t *changed_entity, int pkt_type, iobuffer_t *pkt) { entity_state_subscribe_entry *pos; spinlock_enter(&mgr->entity_state_subscribe_lock, -1); list_for_each_entry(pos, &mgr->entity_state_subscribe_list, entity_state_subscribe_entry, entry) { if (pos->target_entity_id == -1 || changed_entity->cfg->idx == pos->target_entity_id) { iobuffer_t *copy = iobuffer_clone(pkt); sp_svc_post(mgr->shell_svc, pos->mod_id, pos->svc_id, pkt_type, 0, ©); if (copy) iobuffer_dec_ref(copy); } } spinlock_leave(&mgr->entity_state_subscribe_lock); } static void mgr_bcast_entity_on_connection(sp_mod_mgr_t *mgr, sp_entity_t *entity_src, sp_entity_t *entity_dst, int pkt_type, iobuffer_t *pkt) { entity_state_subscribe_entry *pos; spinlock_enter(&mgr->entity_state_subscribe_lock, -1); list_for_each_entry(pos, &mgr->entity_state_subscribe_list, entity_state_subscribe_entry, entry) { if (pos->target_entity_id == -1 || entity_src->cfg->idx == pos->target_entity_id || entity_dst->cfg->idx == pos->target_entity_id) { iobuffer_t *copy = iobuffer_clone(pkt); sp_svc_post(mgr->shell_svc, pos->mod_id, pos->svc_id, pkt_type, 0, ©); if (copy) iobuffer_dec_ref(copy); } } spinlock_leave(&mgr->entity_state_subscribe_lock); DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "bcast entity on connection! src: %s, dst: %s", entity_src->cfg->name, entity_dst->cfg->name); } static void mgr_on_entity_state(sp_mod_mgr_t *mgr, sp_entity_t *entity, int trigger_entity_id, int last_state, int curr_state) { sp_env_t *env = NULL; iobuffer_t *pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_I4, &entity->cfg->idx, 0); iobuffer_write(pkt, IOBUF_T_I4, &trigger_entity_id, 0); iobuffer_write(pkt, IOBUF_T_I4, &last_state, 0); iobuffer_write(pkt, IOBUF_T_I4, &curr_state, 0); mgr_bcast_entity_state_event(mgr, entity, SP_PKT_MOD|MOD_CMD_RECORD_STATE_EVENT, pkt); iobuffer_dec_ref(pkt); addStartupStep(entity->cfg->idx, "state_change", "", last_state, curr_state, 0); // gui显示实体状态变化 env = sp_get_env(); #if defined(_MSC_VER) sp_gui_show_entity_info(env->gui, entity->cfg->name, curr_state); #else if (env->gui != NULL) { env->gui->show_entity_info(env->gui->gui_inst, entity->cfg->name, curr_state); } #endif //_MSC_VER } static void mgr_on_user_state(sp_mod_mgr_t *mgr, sp_entity_t *entity, int last_state, int curr_state) { iobuffer_t *pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_I4, &entity->cfg->idx, 0); iobuffer_write(pkt, IOBUF_T_I4, &last_state, 0); iobuffer_write(pkt, IOBUF_T_I4, &curr_state, 0); mgr_bcast_entity_state_event(mgr, entity, SP_PKT_MOD|MOD_CMD_USER_STATE_EVENT, pkt); iobuffer_dec_ref(pkt); } static void mgr_on_create_connection(sp_mod_mgr_t *mgr, sp_entity_t *entity_src, sp_entity_t *entity_dst) { iobuffer_t *pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_I4, &entity_src->cfg->idx, 0); iobuffer_write(pkt, IOBUF_T_I4, &entity_dst->cfg->idx, 0); mgr_bcast_entity_on_connection(mgr, entity_src, entity_dst, SP_PKT_MOD|MOD_CMD_RECORD_CREATE_CONN, pkt); iobuffer_dec_ref(pkt); } static void mgr_on_close_connection(sp_mod_mgr_t *mgr, sp_entity_t *entity_src, sp_entity_t *entity_dst) { iobuffer_t *pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_I4, &entity_src->cfg->idx, 0); iobuffer_write(pkt, IOBUF_T_I4, &entity_dst->cfg->idx, 0); mgr_bcast_entity_on_connection(mgr, entity_src, entity_dst, SP_PKT_MOD|MOD_CMD_RECORD_CLOSE_CONN, pkt); iobuffer_dec_ref(pkt); } static void mgr_bcast_entity_life_event(sp_mod_mgr_t *mgr, int pkt_type, iobuffer_t *pkt) { entity_life_subscribe_entry *pos; spinlock_enter(&mgr->entity_life_subscribe_lock, -1); list_for_each_entry(pos, &mgr->entity_life_subscribe_list, entity_life_subscribe_entry, entry) { iobuffer_t *copy = iobuffer_clone(pkt); sp_svc_post(mgr->shell_svc, pos->mod_id, pos->svc_id, pkt_type, 0, ©); if (copy) iobuffer_dec_ref(copy); } spinlock_leave(&mgr->entity_life_subscribe_lock); } static void mgr_on_entity_create(sp_mod_mgr_t *mgr, sp_entity_t *entity, int trigger_entity_id) { iobuffer_t *pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_I4, &entity->cfg->idx, 0); iobuffer_write(pkt, IOBUF_T_I4, &trigger_entity_id, 0); mgr_bcast_entity_life_event(mgr, SP_PKT_MOD|MOD_CMD_RECORD_ENTITY_CREATE, pkt); iobuffer_dec_ref(pkt); } static void mgr_on_entity_close(sp_mod_mgr_t *mgr, sp_entity_t *entity, int trigger_entity_id, int cause_code) { iobuffer_t *pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_I4, &entity->cfg->idx, 0); iobuffer_write(pkt, IOBUF_T_I4, &trigger_entity_id, 0); iobuffer_write(pkt, IOBUF_T_I4, &cause_code, 0); mgr_bcast_entity_life_event(mgr, SP_PKT_MOD|MOD_CMD_RECORD_ENTITY_CLOSE, pkt); iobuffer_dec_ref(pkt); } static void mgr_on_entity_exception(sp_mod_mgr_t *mgr, sp_entity_t *entity, int trigger_entity_id, int error) { iobuffer_t *pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_I4, &entity->cfg->idx, 0); iobuffer_write(pkt, IOBUF_T_I4, &error, 0); iobuffer_write(pkt, IOBUF_T_I4, &entity->state, 0); mgr_bcast_entity_life_event(mgr, SP_PKT_MOD|MOD_CMD_RECORD_ENTITY_EXCEPTION, pkt); iobuffer_dec_ref(pkt); } static int on_detect_process_end(process_monitor_t *monitor, HANDLE hproc, void *user_data) { sp_mod_mgr_t *mgr = (sp_mod_mgr_t*)user_data; sp_mod_t *mod; list_for_each_entry(mod, &mgr->mod_list, sp_mod_t, entry) { if (mod->loaded && mod->process.handle == hproc) { sp_entity_t *ent; #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "detect process [mod=%s] exit", mod->cfg->name); //no exit code process_close(&mod->process); mod->loaded = SP_MODULE_STATE_UNLOAD; list_for_each_entry(ent, &mod->entity_list, sp_entity_t, entry) { if (ent->state != EntityState_Killed && ent->state != EntityState_Close) { // int last_state = ent->state; ent->state = EntityState_Lost; mgr_on_entity_state(mgr, ent, ent->cfg->idx, last_state, ent->state); mgr_on_entity_close(mgr, ent, ent->cfg->idx, CloseCause_Lost); } } SetEvent(mod->evt_app_exit); #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 break; } } return TRUE; // delete process handle } static void subscribe_entity_state(sp_mod_mgr_t *mgr, int mod_id, int svc_id, int target_entity_id) { int found = 0; entity_state_subscribe_entry *pos; spinlock_enter(&mgr->entity_state_subscribe_lock, -1); list_for_each_entry(pos, &mgr->entity_state_subscribe_list, entity_state_subscribe_entry, entry) { if (pos->mod_id == mod_id && pos->svc_id == svc_id && pos->target_entity_id == target_entity_id) { found = TRUE; break; } } if (found) { pos->instance ++; } else { pos = MALLOC_T(entity_state_subscribe_entry); pos->instance = 1; pos->mod_id = mod_id; pos->svc_id = svc_id; pos->target_entity_id = target_entity_id; list_add_tail(&pos->entry, &mgr->entity_state_subscribe_list); } spinlock_leave(&mgr->entity_state_subscribe_lock); } static void unsubscribe_entity_state(sp_mod_mgr_t *mgr, int mod_id, int svc_id, int target_entity_id) { int found = 0; entity_state_subscribe_entry *pos; spinlock_enter(&mgr->entity_state_subscribe_lock, -1); list_for_each_entry(pos, &mgr->entity_state_subscribe_list, entity_state_subscribe_entry, entry) { if (pos->mod_id == mod_id && pos->svc_id == svc_id && pos->target_entity_id == target_entity_id) { found = TRUE; break; } } if (found) { pos->instance--; if (pos->instance == 0) { list_del(&pos->entry); FREE(pos); } } spinlock_leave(&mgr->entity_state_subscribe_lock); } static void subscribe_entity_life(sp_mod_mgr_t *mgr, int mod_id, int svc_id) { int found = 0; entity_life_subscribe_entry *pos; spinlock_enter(&mgr->entity_life_subscribe_lock, -1); list_for_each_entry(pos, &mgr->entity_life_subscribe_list, entity_life_subscribe_entry, entry) { if (pos->mod_id == mod_id && pos->svc_id == svc_id) { found = TRUE; break; } } if (found) { pos->instance ++; } else { pos = MALLOC_T(entity_life_subscribe_entry); pos->instance = 1; pos->mod_id = mod_id; pos->svc_id = svc_id; list_add_tail(&pos->entry, &mgr->entity_life_subscribe_list); } spinlock_leave(&mgr->entity_life_subscribe_lock); } static void unsubscribe_entity_life(sp_mod_mgr_t *mgr, int mod_id, int svc_id) { int found = 0; entity_life_subscribe_entry *pos; spinlock_enter(&mgr->entity_life_subscribe_lock, -1); list_for_each_entry(pos, &mgr->entity_life_subscribe_list, entity_life_subscribe_entry, entry) { if (pos->mod_id == mod_id && pos->svc_id == svc_id ) { found = TRUE; break; } } if (found) { pos->instance--; if (pos->instance == 0) { list_del(&pos->entry); FREE(pos); } } spinlock_leave(&mgr->entity_life_subscribe_lock); } static void clear_entity_state(sp_mod_mgr_t *mgr, int mod_id) { entity_state_subscribe_entry *pos, *n; spinlock_enter(&mgr->entity_state_subscribe_lock, -1); list_for_each_entry_safe(pos, n, &mgr->entity_state_subscribe_list, entity_state_subscribe_entry, entry) { if (pos->mod_id == mod_id) { list_del(&pos->entry); FREE(pos); } } spinlock_leave(&mgr->entity_state_subscribe_lock); } static void clear_entity_state_list_all(sp_mod_mgr_t *mgr) { entity_state_subscribe_entry *pos, *n; spinlock_enter(&mgr->entity_state_subscribe_lock, -1); list_for_each_entry_safe(pos, n, &mgr->entity_state_subscribe_list, entity_state_subscribe_entry, entry) { list_del(&pos->entry); FREE(pos); } spinlock_leave(&mgr->entity_state_subscribe_lock); } static void clear_entity_life(sp_mod_mgr_t *mgr, int mod_id) { entity_life_subscribe_entry *pos, *n; spinlock_enter(&mgr->entity_life_subscribe_lock, -1); list_for_each_entry_safe(pos, n, &mgr->entity_life_subscribe_list, entity_life_subscribe_entry, entry) { if (pos->mod_id == mod_id) { list_del(&pos->entry); FREE(pos); } } spinlock_leave(&mgr->entity_life_subscribe_lock); } static void clear_entity_life_list_all(sp_mod_mgr_t *mgr) { entity_life_subscribe_entry *pos, *n; spinlock_enter(&mgr->entity_life_subscribe_lock, -1); list_for_each_entry_safe(pos, n, &mgr->entity_life_subscribe_list, entity_life_subscribe_entry, entry) { list_del(&pos->entry); FREE(pos); } spinlock_leave(&mgr->entity_life_subscribe_lock); } static int mgr_on_pkt(sp_svc_t *svc,int epid, int svc_id, int pkt_type, int pkt_id, iobuffer_t **p_pkt, void *user_data) { sp_mod_mgr_t *mgr = (sp_mod_mgr_t *)user_data; if (SP_GET_PKT_TYPE(pkt_type) == SP_PKT_MOD) { int result = pkt_id; int cmd_type = SP_GET_TYPE(pkt_type); sp_mod_t *mod; if (cmd_type == MOD_CMD_INIT || cmd_type == MOD_CMD_TERM) { // not necessary {bug} list_for_each_entry(mod, &mgr->mod_list, sp_mod_t, entry) { if (mod->cfg->idx == epid) { if (mod->doing) { mod->wait_result = result; SetEvent(mod->evt_wait_handle); } break; } } } else if (cmd_type == MOD_CMD_USER_STATE_EVENT) { int last_state, curr_state; sp_entity_t *entity = sp_mod_mgr_find_entity_by_idx(mgr, svc_id); iobuffer_read(*p_pkt, IOBUF_T_I4, &last_state, NULL); iobuffer_read(*p_pkt, IOBUF_T_I4, &curr_state, NULL); mgr_on_user_state(mgr, entity, last_state, curr_state); } else if (cmd_type == MOD_CMD_REPORT_CREATE_CONN) { sp_entity_t *entity_src = sp_mod_mgr_find_entity_by_idx(mgr, svc_id); sp_entity_t *entity_dst = sp_mod_mgr_find_entity_by_idx(mgr, pkt_id); if (entity_src && entity_dst) mgr_on_create_connection(mgr, entity_src, entity_dst); } else if (cmd_type == MOD_CMD_REPROT_CLOSE_CONN) { sp_entity_t *entity_src = sp_mod_mgr_find_entity_by_idx(mgr, svc_id); sp_entity_t *entity_dst = sp_mod_mgr_find_entity_by_idx(mgr, pkt_id); mgr_on_close_connection(mgr, entity_src, entity_dst); } else if (cmd_type == MOD_CMD_REPORT_EXCEPTION) { sp_entity_t *ent = sp_mod_mgr_find_entity_by_idx(mgr, svc_id); mgr_on_entity_exception(mgr, ent, ent->cfg->idx, Error_Exception); } else if (cmd_type == MOD_CMD_SWITCH_RUNNING_MODE) { // BugFix [4/3/2020 9:09 Gifur] sp_entity_t *ent = sp_mod_mgr_find_entity_by_idx(mgr, svc_id); int state = pkt_id; mod = sp_mod_mgr_find_module_by_idx(mgr, epid); if ((ent->state == EntityState_Idle || ent->state == EntityState_Busy) && state != ent->state) { #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (ent->state == EntityState_Idle || ent->state == EntityState_Busy) { if (ent->state != state) { int old_state = ent->state; ent->state = state; mgr_on_entity_state(mgr, ent, ent->cfg->idx, old_state, state); } } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 } } else if (cmd_type == MOD_CMD_SUBSCRIBE_STATE_LISTENER) { subscribe_entity_state(mgr, epid, svc_id, pkt_id); } else if (cmd_type == MOD_CMD_UNSUBSCRIBE_STATE_LISTENER) { unsubscribe_entity_state(mgr, epid, svc_id, pkt_id); } else if (cmd_type == MOD_CMD_SUBSCRIBE_LIFE_LISTENER) { subscribe_entity_life(mgr, epid, svc_id); } else if (cmd_type == MOD_CMD_UNSUBSCRIBE_LIFE_LISTENER) { unsubscribe_entity_life(mgr, epid, svc_id); } else if (cmd_type == MOD_CMD_ENT_RESULT) { sp_entity_t *ent = sp_mod_mgr_find_entity_by_idx(mgr, svc_id); if (ent->mod->doing) { ent->wait_result = result; SetEvent(ent->evt_wait_handle); } /** this for new for entity unit test, we need to know the exam result*/ } else if (cmd_type == MOD_CMD_ENT_RESULT_EX) { sp_entity_t* ent = sp_mod_mgr_find_entity_by_idx(mgr, svc_id); if (ent->mod->doing) { unsigned int statistic = 0; iobuffer_read(*p_pkt, IOBUF_T_I4, &statistic, NULL); ent->wait_result = result; ent->result_param1 = statistic; SetEvent(ent->evt_wait_handle); } } else if (cmd_type == MOD_CMD_MOD_RESULT) { mod = sp_mod_mgr_find_module_by_idx(mgr, epid); if (mod->doing) { mod->wait_result = result; SetEvent(mod->evt_wait_handle); } } else if (cmd_type == MOD_CMD_REPORT_REDIRECT_SUBSCRIBE) { sp_uid_t uid; int suggest_entity_id; iobuffer_read(*p_pkt, IOBUF_T_I8, &uid, NULL); iobuffer_read(*p_pkt, IOBUF_T_I4, &suggest_entity_id, NULL); sp_bcm_daemon_process_redirect_subscribe(mgr->shell_daemon, svc_id, &uid, suggest_entity_id); } else { TOOLKIT_ASSERT(0); } return FALSE; } return TRUE; } static void mgr_on_sys(sp_svc_t *svc,int epid, int state, void *user_data) { sp_mod_mgr_t *mgr = (sp_mod_mgr_t *)user_data; if (state == BUS_STATE_OFF) { clear_entity_state(mgr, epid); clear_entity_life(mgr, epid); } } int sp_mod_mgr_create(sp_mod_mgr_t **p_mgr) { sp_mod_mgr_t *mgr = shm_malloc(sizeof(sp_mod_mgr_t)); memset(mgr, 0, sizeof(sp_mod_mgr_t)); InitializeCriticalSection(&mgr->lock); INIT_LIST_HEAD(&mgr->mod_list); process_monitor_create(&mgr->process_monitor); process_monitor_set_cb(mgr->process_monitor, &on_detect_process_end, mgr); spinlock_init(&mgr->entity_life_subscribe_lock); INIT_LIST_HEAD(&mgr->entity_life_subscribe_list); spinlock_init(&mgr->entity_state_subscribe_lock); INIT_LIST_HEAD(&mgr->entity_state_subscribe_list); mgr->arr_ent = shm_array_make(SP_MAX_ENTITY, sizeof(sp_entity_t*)); mgr->arr_mod = shm_array_make(SP_MAX_MODULE, sizeof(sp_mod_t*)); mgr->instance_seq = 0; mgr->shell_svc = NULL; mgr->shell_daemon = NULL; *p_mgr = mgr; return 0; } void sp_mod_mgr_destroy(sp_mod_mgr_t *mgr) { TOOLKIT_ASSERT(list_empty(&mgr->mod_list)); clear_entity_life_list_all(mgr); clear_entity_state_list_all(mgr); process_monitor_destroy(mgr->process_monitor); #ifdef _WIN32 ClearGroupProcessInfo(); #endif //_WIN32 DeleteCriticalSection(&mgr->lock); shm_free(mgr); } void sp_mod_mgr_bind_shell_svc(sp_mod_mgr_t *mgr, sp_svc_t *svc) { mgr->shell_svc = svc; } int sp_mod_mgr_add_module(sp_mod_mgr_t *mgr, sp_cfg_shell_module_t *cfg_mod) { sp_mod_t *mod; TOOLKIT_ASSERT(mgr); mod = sp_mod_mgr_find_module_by_name(mgr, cfg_mod->name); if (!mod) { mod = shm_malloc(sizeof(sp_mod_t)); mod->loaded = SP_MODULE_STATE_UNLOAD; mod->mgr = mgr; mod->cfg = cfg_mod; mod->doing = mod->closing = 0; mod->wait_result = 0; mod->start_time = 0; mod->evt_app_exit = CreateEventA(NULL, TRUE, TRUE, NULL); mod->evt_wait_handle = CreateEventA(NULL, TRUE, FALSE, NULL); process_init(&mod->process); INIT_LIST_HEAD(&mod->entity_list); list_add_tail(&mod->entry, &mgr->mod_list); ARRAY_IDX(mgr->arr_mod, cfg_mod->idx, sp_mod_t*) = mod; } else { //DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "module %s already exist!", cfg_mod->name); //return Error_Duplication; } return 0; } int sp_mod_mgr_add_entity(sp_mod_mgr_t *mgr, sp_cfg_shell_entity_t *cfg_ent) { sp_mod_t *mod; sp_entity_t *ent; TOOLKIT_ASSERT(mgr); mod = sp_mod_mgr_find_module_by_name(mgr, cfg_ent->mod->name); if (mod) { ent = sp_mod_find_entity_by_name(mod, cfg_ent->name); if (!ent) { ent = shm_malloc(sizeof(sp_entity_t)); ent->state = EntityState_NoStart; ent->mod = mod; ent->wait_result = 0; ent->result_param1 = ent->result_param2 = 0; ent->first_start_time = 0; ent->last_start_time = 0; ent->state_start_time = 0; ent->cfg = cfg_ent; ent->service_flag = 0; ent->evt_wait_handle = CreateEventA(NULL, TRUE, FALSE, NULL); ent->instance_id = 0; ent->user_state = 0; ent->last_err.sys_code = ent->last_err.usr_code = 0; memset(ent->last_err.msg, '\0', sizeof(ent->last_err.msg)); list_add_tail(&ent->entry, &mod->entity_list); ARRAY_IDX(mgr->arr_ent, cfg_ent->idx, sp_entity_t*) = ent; } else { //return Error_Duplication; } } else { return Error_NotExist; } return 0; } int sp_mod_mgr_remove_module(sp_mod_mgr_t *mgr, const char *mod_name) { sp_mod_t *mod; TOOLKIT_ASSERT(mgr); TOOLKIT_ASSERT(mod_name); mod = sp_mod_mgr_find_module_by_name(mgr, mod_name); if (mod) { TOOLKIT_ASSERT(mod->loaded == SP_MODULE_STATE_UNLOAD); TOOLKIT_ASSERT(list_empty(&mod->entity_list)); list_del(&mod->entry); CloseHandle(mod->evt_app_exit); CloseHandle(mod->evt_wait_handle); shm_free(mod); } else { return Error_NotExist; } return 0; } int sp_mod_mgr_remove_entity(sp_mod_mgr_t *mgr, const char *entity_name) { sp_entity_t *ent; TOOLKIT_ASSERT(mgr); TOOLKIT_ASSERT(entity_name); ent = sp_mod_mgr_find_entity_by_name(mgr, entity_name); if (ent) { list_del(&ent->entry); CloseHandle(ent->evt_wait_handle); shm_free(ent); } else { return Error_NotExist; } return 0; } int sp_mod_mgr_init(sp_mod_mgr_t *mgr) { int rc; sp_mod_t *mod_pos; int existMod = mgr->arr_mod->nelts; mgr->arr_mod->nelts = mgr->arr_ent->nelts = 0; list_for_each_entry(mod_pos, &mgr->mod_list, sp_mod_t, entry) { //遍历 sp_entity_t *ent_pos; mgr->arr_mod->nelts++; list_for_each_entry(ent_pos, &mod_pos->entity_list, sp_entity_t, entry) { mgr->arr_ent->nelts++; } } if (existMod == 0) rc = sp_svc_add_pkt_handler(mgr->shell_svc, (int)mgr, SP_PKT_MOD, &mgr_on_pkt, mgr); else rc = 0; return rc; } void sp_mod_mgr_term(sp_mod_mgr_t *mgr) { sp_svc_remove_pkt_handler(mgr->shell_svc, (int)mgr, SP_PKT_MOD); process_monitor_stop(mgr->process_monitor); mgr->arr_ent->nelts = 0; mgr->arr_mod->nelts = 0; } void sp_mod_mgr_bind_bcm_daemon(sp_mod_mgr_t *mgr, sp_bcm_daemon_t *daemon) { mgr->shell_daemon = daemon; } void sp_mod_mgr_lock(sp_mod_mgr_t *mgr) { EnterCriticalSection(&mgr->lock); } void sp_mod_mgr_unlock(sp_mod_mgr_t *mgr) { LeaveCriticalSection(&mgr->lock); } sp_mod_t *sp_mod_mgr_find_module_by_name(sp_mod_mgr_t *mgr, const char *mod_name) { sp_mod_t *mod; if (!mod_name) return NULL; list_for_each_entry(mod, &mgr->mod_list, sp_mod_t, entry) { if (_stricmp(mod_name, mod->cfg->name) == 0) return mod; } return NULL; } sp_mod_t *sp_mod_mgr_find_module_by_idx(sp_mod_mgr_t *mgr, int mod_idx) { if (mod_idx == -1 || mod_idx > mgr->arr_mod->nelts) return NULL; return ARRAY_IDX(mgr->arr_mod, mod_idx, sp_mod_t*); } sp_entity_t *sp_mod_find_entity_by_name(sp_mod_t *mod, const char *entity_name) { sp_entity_t *ent; if (!entity_name) return NULL; list_for_each_entry(ent, &mod->entity_list, sp_entity_t, entry) { if (_stricmp(ent->cfg->name, entity_name) == 0) return ent; } return NULL; } sp_entity_t *sp_mod_find_entity_by_idx(sp_mod_t *mod, int entity_idx) { if (entity_idx == -1 || entity_idx >= mod->mgr->arr_ent->nelts) return NULL; return ARRAY_IDX(mod->mgr->arr_ent, entity_idx, sp_entity_t*); } sp_entity_t *sp_mod_find_entity_by_devel_id(sp_mod_t *mod, int devel_id) { sp_entity_t *ent; list_for_each_entry(ent, &mod->entity_list, sp_entity_t, entry) { if (ent->cfg->devel_id == devel_id) return ent; } return NULL; } sp_entity_t *sp_mod_find_entity_by_inst_id(sp_mod_t *mod, int inst_id) { sp_entity_t *ent; list_for_each_entry(ent, &mod->entity_list, sp_entity_t, entry) { if (ent->instance_id == inst_id) return ent; } return NULL; } void sp_mod_supress_last_err_for_all_entity(sp_mod_t* mod, const char* err_msg) { sp_entity_t* ent; if (err_msg != NULL && strlen(err_msg) > 0) { list_for_each_entry(ent, &mod->entity_list, sp_entity_t, entry) { ent->last_err.sys_code = (uint32_t)0x300; /*Error_InvalidState*/ ent->last_err.usr_code = 0; strcpy_s(ent->last_err.msg, SP_ENTITY_ERRMSG_MAX_LEN, err_msg); } } } sp_entity_t *sp_mod_mgr_find_entity_by_name(sp_mod_mgr_t *mgr, const char *entity_name) { sp_mod_t *mod; if (!entity_name) return NULL; list_for_each_entry(mod, &mgr->mod_list, sp_mod_t, entry) { sp_entity_t *ent = sp_mod_find_entity_by_name(mod, entity_name); if (ent) return ent; } return NULL; } sp_entity_t *sp_mod_mgr_find_entity_by_idx(sp_mod_mgr_t *mgr, int entity_id) { if (entity_id == -1 || entity_id > mgr->arr_ent->nelts) return NULL; return ARRAY_IDX(mgr->arr_ent, entity_id, sp_entity_t*); } sp_entity_t *sp_mod_mgr_find_entity_by_devel_id(sp_mod_mgr_t *mgr, int devel_id) { int i; for (i = 1; i < mgr->arr_ent->nelts; ++i) { sp_entity_t *ent = ARRAY_IDX(mgr->arr_ent, i, sp_entity_t*); if (ent->cfg->devel_id == devel_id) return ent; } return NULL; } sp_entity_t *sp_mod_mgr_find_entity_by_inst_id(sp_mod_mgr_t *mgr, int inst_id) { int i; for (i = 1; i < mgr->arr_ent->nelts; ++i) { sp_entity_t *ent = ARRAY_IDX(mgr->arr_ent, i, sp_entity_t*); if (ent->instance_id == inst_id) return ent; } return NULL; } struct list_head* sp_mod_mgr_get_module_list_head(sp_mod_mgr_t *mgr) { return &mgr->mod_list; } int sp_mod_mgr_get_entity_array_nelts(sp_mod_mgr_t *mgr) { return mgr->arr_ent->nelts; } static int try_lock_doing(sp_mod_mgr_t *mgr, sp_mod_t *mod) { int ok = FALSE; #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (!mod->doing) { mod->doing = 1; ok = TRUE; } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 return ok; } static void unlock_doing(sp_mod_mgr_t *mgr, sp_mod_t *mod) { #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 mod->doing = 0; #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 } static int load_module(sp_mod_mgr_t *mgr, sp_mod_t *mod, int trigger_entity_id, int entity_id) { int rc = 0; sp_env_t *env = sp_get_env(); addStartupStep(mod->cfg->idx, "begin_load", "", 0, 0, 0); #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (!mod->loaded) { ResetEvent(mod->evt_app_exit); if (0 != create_module_process(mod->cfg->name, mod->cfg->idx, env->shm_range, mod->cfg->debugFileExist, &mod->process, mod->cfg->runType, entity_id)) { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "sp_mod_mgr_load_module %s failed! create module process failed", mod->cfg->name); rc = Error_Unexpect; } else { char pidBuffer[20] = ""; _itoa(mod->process.pid, pidBuffer, sizeof(pidBuffer)); addStartupStep(entity_id, "create module process succ", pidBuffer, 0, 0, 0); } } else { rc = Error_Duplication; } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 if (rc == 0) { const int interval = 50; //consider sleep operation below, here would consume 4 min at terriable situation. const int tries = PROCESS_TIMEOUT / interval; int i; ResetEvent(mod->evt_wait_handle); DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "get remote entitiy state..."); for (i = 0; i < tries; ++i) { int state = BUS_STATE_OFF; rc = sp_svc_get_state(mgr->shell_svc, mod->cfg->idx, &state); WLog_DBG(TAG, "cfg::idx: %d, state: %d", mod->cfg->idx, state); if (rc == 0) { if (state != BUS_STATE_ON) { DWORD dwRet; dwRet = WaitForSingleObject(mod->process.handle, (DWORD)interval); //wait for entity thread end if (dwRet == WAIT_OBJECT_0) { addStartupStep(mod->cfg->idx, "mod_online", "process exit exception!", 0, 0, Error_Exception); rc = Error_Exception; break; } } else { addStartupStep(mod->cfg->idx, "mod_online", "", 0, 0, 0); break; } } else { addStartupStep(mod->cfg->idx, "mod_online", "get epid state failed!", 0, 0, Error_Exception); break; } } if (rc == 0) rc = sp_svc_send(mgr->shell_svc, mod->cfg->idx, SP_INVALID_SVC_ID, SP_PKT_MOD|MOD_CMD_INIT, 0, NULL); if (rc) { addStartupStep(mod->cfg->idx, "send_init", "failed", 0, 0, rc); } else { addStartupStep(mod->cfg->idx, "send_init", "", 0, 0, 0); for (i = 0; i < tries; ++i) { #ifdef _WIN32 HANDLE hs[] = { mod->evt_wait_handle, mod->process.handle }; //wait for entity thread end DWORD dwRet = WaitForMultipleObjects(array_size(hs), &hs[0], FALSE, (DWORD)interval); #else DWORD dwRet = WaitForSingleObject(mod->evt_wait_handle, (DWORD)interval); if (dwRet == WAIT_TIMEOUT) { dwRet = WaitForSingleObject(mod->process.handle, 0); if (dwRet == WAIT_OBJECT_0) { dwRet = WAIT_OBJECT_0 + 1; } } #endif //_WIN32 if (dwRet == WAIT_OBJECT_0) { addStartupStep(mod->cfg->idx, "entity_reply", "", 0, 0, 0); rc = mod->wait_result; if (rc != 0) { addStartupStep(mod->cfg->idx, "entity_reply", "failed", 0, 0, rc); } break; } else if (dwRet == WAIT_OBJECT_0+1) { addStartupStep(mod->cfg->idx, "entity_reply", "process end", 0, 0, Error_Exception); rc = Error_Exception; break; } else if(dwRet == WAIT_TIMEOUT) { addStartupStep(mod->cfg->idx, "entity_reply", "timeout", 0, 0, Error_TimeOut); rc = Error_TimeOut; } else { addStartupStep(mod->cfg->idx, "entity_reply", "multi obj", 0, 0, Error_Unexpect); rc = Error_Unexpect; break; } } } } #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (rc == 0) { mod->loaded = SP_MODULE_STATE_LOAD; mod->start_time = y2k_time_now(); process_monitor_add(mgr->process_monitor, &mod->process); DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "load module ok! start time = %d, state = LOADED", mod->start_time); } else { DWORD result = 0; mod_kill_process(mod); result = WaitForSingleObject(mod->process.handle, PROCESS_EXIT_TIMEOUT); process_close(&mod->process); DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "load module %s failed! 0x%x, 0x%x", mod->cfg->name, rc, result); } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 return rc; } static int unload_module(sp_mod_mgr_t *mgr, sp_mod_t *mod, int trigger_entity_id) { int rc = 0; sp_entity_t *pos; #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (mod->loaded) { list_for_each_entry(pos, &mod->entity_list, sp_entity_t, entry) { if (pos->state != EntityState_Killed && pos->state != EntityState_Close && pos->state != EntityState_NoStart) { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "unload %s module, has entity in normal state!", mod->cfg->name); rc = Error_Bug; break; } } if (rc == 0) { ResetEvent(mod->evt_wait_handle); rc = sp_svc_send(mod->mgr->shell_svc, mod->cfg->idx, SP_INVALID_SVC_ID, SP_PKT_MOD|MOD_CMD_TERM, 0, NULL); if (rc == 0) { DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "unload %s module, send pkt cmd ok!", mod->cfg->name); } else { DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM, "unload %s module, send pkt cmd failed: %d!", mod->cfg->name, rc); } } } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "module %s already unloaded!", mod->cfg->name); rc = Error_InvalidState; } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 if (rc == 0) { int removed = 0; /*TODO: the clear job depend on different result seems no different.*/ for (;;) { HANDLE hs[] = {mod->evt_app_exit, mod->evt_wait_handle}; DWORD dwRet = WaitForMultipleObjects(array_size(hs), &hs[0], FALSE, PROCESS_TIMEOUT_FOR_TERMINAL); if (dwRet == WAIT_OBJECT_0) { // app exit DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "module %s app exit", mod->cfg->name); break; } else if (dwRet == WAIT_OBJECT_0+1) { ResetEvent(mod->evt_wait_handle); DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "module %s wait handle received, wait result: %d", mod->cfg->name, mod->wait_result); if (mod->wait_result != 0) { HANDLE hprocess = mod->process.handle; if (hprocess && process_monitor_remove(mgr->process_monitor, &mod->process) == 0) { DWORD result; removed = 1; mod_kill_process(mod); result = WaitForSingleObject(mod->process.handle, PROCESS_EXIT_TIMEOUT); process_close(&mod->process); break; } //TODO: } else { HANDLE hprocess = mod->process.handle; if (hprocess && process_monitor_remove(mgr->process_monitor, &mod->process) == 0) { DWORD tmp; removed = 1; tmp = WaitForSingleObject(hprocess, PROCESS_EXIT_TIMEOUT); if (tmp == WAIT_TIMEOUT) { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "wait process %s(%d) normal exit timeout!", mod->cfg->name, mod->process.pid); mod_kill_process(mod); WaitForSingleObject(mod->process.handle, PROCESS_EXIT_TIMEOUT); } process_close(&mod->process); break; } } } else { HANDLE hprocess; DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "wait unexpect: %u", dwRet); hprocess = mod->process.handle; if (hprocess && process_monitor_remove(mgr->process_monitor, &mod->process) == 0) { removed = 1; mod_kill_process(mod); WaitForSingleObject(mod->process.handle, PROCESS_EXIT_TIMEOUT); process_close(&mod->process); break; } } } #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (removed) { DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "set mod %s unload state line: %d", mod->cfg->name, __LINE__); mod->loaded = SP_MODULE_STATE_UNLOAD; SetEvent(mod->evt_app_exit); } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 } return rc; } /*remove from monitor and kill it directory!!*/ static int terminate_module(sp_mod_mgr_t *mgr, sp_mod_t *mod, int trigger_entity_id) { int rc = 0; sp_entity_t *pos; #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (mod->loaded) { DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "%s: %s by entity %d", __FUNCTION__, mod->cfg->name, trigger_entity_id); if (mod->process.handle) { if (process_monitor_remove(mgr->process_monitor, &mod->process) == 0) { DWORD result; mod_kill_process(mod); result = WaitForSingleObject(mod->process.handle, PROCESS_EXIT_TIMEOUT); DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "mod %s 's process removed now! %u", mod->cfg->name, result); process_close(&mod->process); mod->loaded = SP_MODULE_STATE_UNLOAD; list_for_each_entry(pos, &mod->entity_list, sp_entity_t, entry) { int old_state = pos->state; if (old_state != EntityState_Close && old_state != EntityState_Killed) { pos->state = EntityState_Killed; mgr_on_entity_state(mgr, pos, trigger_entity_id, old_state, pos->state); mgr_on_entity_close(mgr, pos, trigger_entity_id, CloseCause_Lost); } } SetEvent(mod->evt_app_exit); } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "mod %s is remove monitor failed!", mod->cfg->name); rc = -1; } } else { list_for_each_entry(pos, &mod->entity_list, sp_entity_t, entry) { if (pos->state != EntityState_Killed && pos->state != EntityState_Close) { int old_state = pos->state; pos->state = EntityState_Killed; mgr_on_entity_state(mgr, pos, trigger_entity_id, old_state, pos->state); mgr_on_entity_close(mgr, pos, trigger_entity_id, CloseCause_Lost); } } DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "set mod %s unload state line: %d", mod->cfg->name, __LINE__); mod->loaded = SP_MODULE_STATE_UNLOAD; } } else { list_for_each_entry(pos, &mod->entity_list, sp_entity_t, entry) { if (pos->state != EntityState_Killed && pos->state != EntityState_Close && pos->state != EntityState_NoStart) { int old_state = pos->state; pos->state = EntityState_Killed; mgr_on_entity_state(mgr, pos, trigger_entity_id, old_state, pos->state); mgr_on_entity_close(mgr, pos, trigger_entity_id, CloseCause_Lost); } } } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 WLog_DBG(TAG, "terminal module %s turned out: %d", mod->cfg->name, rc); return rc; } static int start_entity(sp_mod_mgr_t *mgr, sp_entity_t *ent, const char *cmdline, int trigger_entity_id) { int rc = 0; sp_mod_t *mod = ent->mod; addStartupLog(mod->cfg->name, mod->cfg->idx); #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (mod->loaded) { if (ent->state == EntityState_NoStart || ent->state == EntityState_Killed || ent->state == EntityState_Close) { iobuffer_t *pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_STR, cmdline, -1); iobuffer_write(pkt, IOBUF_T_I4, &trigger_entity_id, 0); ResetEvent(ent->evt_wait_handle); ent->instance_id = mgr_new_instance_id(mgr); rc = sp_svc_send(mgr->shell_svc, mod->cfg->idx, ent->cfg->idx, SP_PKT_MOD|MOD_CMD_START, ent->cfg->idx, &pkt); if (rc == 0) { int last_state = ent->state; addStartupStep(mod->cfg->idx, "send_start", "", 0, 0, 0); ent->state_start_time = y2k_time_now(); if (ent->first_start_time == 0) ent->first_start_time = ent->state_start_time; ent->last_start_time = ent->state_start_time; ent->state = EntityState_Starting; mgr_on_entity_state(mgr, ent, trigger_entity_id, last_state, ent->state); } else { addStartupStep(mod->cfg->idx, "send_start", "failed", 0, 0, Error_Unexpect); } if (pkt) iobuffer_dec_ref(pkt); } else { rc = Error_InvalidState; addStartupStep(mod->cfg->idx, "send_start", "state is not correct", 0, 0, Error_InvalidState); } } else { addStartupStep(mod->cfg->idx, "send_start", "module is not load", 0, 0, Error_InvalidState); rc = Error_InvalidState; } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 if (rc == 0) { int last_state = ent->state; HANDLE hs[] = {mod->evt_app_exit, ent->evt_wait_handle}; DWORD dwRet = WaitForMultipleObjects(array_size(hs), &hs[0], FALSE, PROCESS_TIMEOUT); if (dwRet == WAIT_OBJECT_0) { addStartupStep(mod->cfg->idx, "wait_result", "app exit", 0, 0, Error_Unexpect); rc = Error_Unexpect; } else if (dwRet == WAIT_OBJECT_0+1) { addStartupStep(mod->cfg->idx, "wait_result", "", 0, 0, 0); rc = ent->wait_result; if (rc != 0) { addStartupStep(mod->cfg->idx, "wait_result", "turned out result", 0, 0, ent->wait_result); } } else { addStartupStep(mod->cfg->idx, "wait_result", "timeout", 0, 0, Error_TimeOut); rc = Error_TimeOut; } #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (rc == 0) { ent->state = EntityState_Idle; ent->state_start_time = y2k_time_now(); mgr_on_entity_create(mgr, ent, trigger_entity_id); } else { ent->state = EntityState_Lost; ent->state_start_time = y2k_time_now(); mgr_on_entity_exception(mgr, ent, trigger_entity_id, Error_Exception); } mgr_on_entity_state(mgr, ent, trigger_entity_id, last_state, ent->state); #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 } return rc; } static int stop_entity(sp_mod_mgr_t *mgr, sp_entity_t *ent, int trigger_entity_id, int cause_code) { int rc = 0; sp_mod_t *mod = ent->mod; #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (mod->loaded) {//judge module state if (ent->state == EntityState_Busy || ent->state == EntityState_Idle || ent->state == EntityState_Pause) { iobuffer_t *body = iobuffer_create(-1, -1); ResetEvent(ent->evt_wait_handle); iobuffer_write(body, IOBUF_T_I4, &trigger_entity_id, 0); iobuffer_write(body, IOBUF_T_I4, &cause_code, 0); rc = sp_svc_send(mgr->shell_svc, mod->cfg->idx, ent->cfg->idx, SP_PKT_MOD|MOD_CMD_STOP, ent->cfg->idx, &body); if (rc == 0) { int last_state = ent->state; DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "stop entity %s, send cmd stop ok!", ent->cfg->name); ent->state = EntityState_UnLoading; ent->state_start_time = y2k_time_now(); mgr_on_entity_state(mgr, ent, trigger_entity_id, last_state, ent->state); } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "stop entity %s, send cmd stop failed!", ent->cfg->name); } if (body) iobuffer_dec_ref(body); } else { rc = Error_InvalidState; DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "entity %s state is not correct for stop! state: %d", ent->cfg->name, ent->state); } } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "%s's mod %s has been unloaded!", ent->cfg->name, mod->cfg->name); rc = Error_InvalidState; } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 if (rc == 0) { int last_state = ent->state; HANDLE hs[] = {mod->evt_app_exit, ent->evt_wait_handle}; DWORD dwRet = WaitForMultipleObjects(array_size(hs), &hs[0], FALSE, PROCESS_TIMEOUT_FOR_TERMINAL); //20secs at uos if (dwRet == WAIT_OBJECT_0) { DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "wait for stop entity %s result, app exit!", ent->cfg->name); rc = Error_Unexpect; } else if (dwRet == WAIT_OBJECT_0+1) { DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "wait for stop entity %s result ok, result = %d!", ent->cfg->name, ent->wait_result); rc = ent->wait_result; } else if(dwRet == WAIT_TIMEOUT){ DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "wait for stop entity %s timeout!", ent->cfg->name); rc = Error_TimeOut; } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "wait for stop entity %s failed: %u!", ent->cfg->name, dwRet); rc = Error_Unexpect; } #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (rc == 0) { ent->state = EntityState_Close; ent->state_start_time = y2k_time_now(); mgr_on_entity_close(mgr, ent, trigger_entity_id, trigger_entity_id != ent->cfg->idx ? CloseCause_Other : CloseCause_Self); } else { ent->state = EntityState_Lost; ent->state_start_time = y2k_time_now(); mgr_on_entity_exception(mgr, ent, trigger_entity_id, Error_Exception); } mgr_on_entity_state(mgr, ent, trigger_entity_id, last_state, ent->state); #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 } return rc; } static int pause_entity(sp_mod_mgr_t *mgr, sp_entity_t *ent, int trigger_entity_id) { int rc = 0; sp_mod_t *mod; mod = ent->mod; #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (mod->loaded) { if (ent->state == EntityState_Busy || ent->state == EntityState_Idle) { iobuffer_t *body = iobuffer_create(-1, -1); ResetEvent(ent->evt_wait_handle); iobuffer_write(body, IOBUF_T_I4, &trigger_entity_id, 0); rc = sp_svc_send(mgr->shell_svc, mod->cfg->idx, ent->cfg->idx, SP_PKT_MOD|MOD_CMD_PAUSE, ent->cfg->idx, &body); if (rc == 0) { DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "pause entity %s, send cmd pause ok!", ent->cfg->name); } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "pause entity %s, send cmd pause failed!", ent->cfg->name); } if (body) iobuffer_dec_ref(body); } else { rc = Error_InvalidState; DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "%s: entity %s state is not correct! current state: %d", __FUNCTION__, ent->cfg->name, (int)ent->state); } } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "%s: entity's %s mod %s is not load!", __FUNCTION__, ent->cfg->name, mod->cfg->name); rc = Error_InvalidState; } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 if (rc == 0) { HANDLE hs[] = {mod->evt_app_exit, ent->evt_wait_handle}; DWORD dwRet = WaitForMultipleObjects(array_size(hs), &hs[0], FALSE, PROCESS_TIMEOUT); if (dwRet == WAIT_OBJECT_0) { DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "wait for pause entity %s result, app exit!", ent->cfg->name); rc = Error_Unexpect; } else if (dwRet == WAIT_OBJECT_0+1) { DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "wait for pause entity %s result ok, result = %d!", ent->cfg->name, ent->wait_result); rc = ent->wait_result; } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "wait for pause entity %s timeout!", ent->cfg->name); rc = Error_TimeOut; } #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (rc == 0) { int last_state = ent->state; ent->state = EntityState_Pause; ent->state_start_time = y2k_time_now(); mgr_on_entity_state(mgr, ent, trigger_entity_id, last_state, ent->state); } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 } return rc; } static int continue_entity(sp_mod_mgr_t *mgr, sp_entity_t *ent, int trigger_entity_id) { int rc = 0; sp_mod_t*mod; mod = ent->mod; #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (mod->loaded) { if (ent->state == EntityState_Pause) { iobuffer_t *body = iobuffer_create(-1, -1); ResetEvent(ent->evt_wait_handle); iobuffer_write(body, IOBUF_T_I4, &trigger_entity_id, 0); rc = sp_svc_send(mgr->shell_svc, mod->cfg->idx, ent->cfg->idx, SP_PKT_MOD|MOD_CMD_CONTINUE, ent->cfg->idx, &body); if (rc == 0) { DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "continue entity %s, send cmd continue ok!", ent->cfg->name); } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "continue entity %s, send cmd continue failed!", ent->cfg->name); } if (body) iobuffer_dec_ref(body); } else { rc = Error_InvalidState; DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "%s: entity %s state is not correct! current state: %d", __FUNCTION__, ent->cfg->name, (int)ent->state); } } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "%s: entity's %s mod %s is not load!", __FUNCTION__, ent->cfg->name, mod->cfg->name); rc = Error_InvalidState; } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 if (rc == 0) { HANDLE hs[] = {mod->evt_app_exit, ent->evt_wait_handle}; DWORD dwRet = WaitForMultipleObjects(array_size(hs), &hs[0], FALSE, PROCESS_TIMEOUT); if (dwRet == WAIT_OBJECT_0) { DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "wait for continue entity %s result, app exit!", ent->cfg->name); rc = Error_Unexpect; } else if (dwRet == WAIT_OBJECT_0+1) { DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "wait for continue entity %s result ok, result = %d!", ent->cfg->name, ent->wait_result); rc = ent->wait_result; } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "wait for continue entity %s timeout!", ent->cfg->name); rc = Error_TimeOut; } #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (rc == 0) { ent->state = EntityState_Idle; ent->state_start_time = y2k_time_now(); mgr_on_entity_state(mgr, ent, trigger_entity_id, EntityState_Pause, ent->state); } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 } return rc; } static int test_entity(sp_mod_mgr_t *mgr, sp_entity_t *ent, int test_type, int trigger_entity_id, int* result) { int rc = 0; sp_mod_t *mod; mod = ent->mod; #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (mod->loaded) { if (ent->state == EntityState_Idle || ent->state == EntityState_Busy || ent->state == EntityState_Pause) { iobuffer_t *body = iobuffer_create(-1, -1); ResetEvent(ent->evt_wait_handle); iobuffer_write(body, IOBUF_T_I4, &trigger_entity_id, 0); iobuffer_write(body, IOBUF_T_I4, &test_type, 0); rc = sp_svc_send(mgr->shell_svc, mod->cfg->idx, ent->cfg->idx, SP_PKT_MOD|MOD_CMD_TEST, ent->cfg->idx, &body); if (rc == 0) { //DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "test entity %s, send cmd test ok!", ent->cfg->name); } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "test entity %s, send cmd test failed!", ent->cfg->name); } if (body) iobuffer_dec_ref(body); } else { rc = Error_InvalidState; DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "%s: entity %s state is not correct! current state: %d", __FUNCTION__, ent->cfg->name, ent->state); } } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "%s: entity's %s mod %s is not load!", __FUNCTION__, ent->cfg->name, mod->cfg->name); rc = Error_InvalidState; } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 if (rc == 0) { HANDLE hs[] = {mod->evt_app_exit, ent->evt_wait_handle}; DWORD dwRet = WaitForMultipleObjects(array_size(hs), &hs[0], FALSE, ENTITY_TEST_TIMEOUT); if (dwRet == WAIT_OBJECT_0) { DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "wait for test entity %s result, app exit!", ent->cfg->name); rc = Error_Unexpect; } else if (dwRet == WAIT_OBJECT_0+1) { rc = ent->wait_result; if (rc != 0) { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "wait for test entity %s result = %s!", ent->cfg->name, sp_strerror(rc)); } if (result) *result = ent->result_param1; } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "wait for test entity %s timeout!", ent->cfg->name); rc = Error_TimeOut; } } return rc; } int sp_mod_mgr_start_entity(sp_mod_mgr_t *mgr, int entity_id, const char *cmdline, int trigger_entity_id) { sp_entity_t *ent; ent = sp_mod_mgr_find_entity_by_idx(mgr, entity_id); if (!ent) return Error_NotExist; return sp_mod_mgr_start_entity2(mgr, ent, cmdline, trigger_entity_id, entity_id); } int sp_mod_mgr_stop_entity(sp_mod_mgr_t *mgr, int entity_id, int trigger_entity_id, int cause_code) { sp_entity_t *ent; ent = sp_mod_mgr_find_entity_by_idx(mgr, entity_id); if (!ent) return Error_NotExist; return sp_mod_mgr_stop_entity2(mgr, ent, trigger_entity_id, cause_code); } int sp_mod_mgr_terminate_entity(sp_mod_mgr_t *mgr, int entity_id, int trigger_entity_id) { sp_entity_t *ent; ent = sp_mod_mgr_find_entity_by_idx(mgr, entity_id); if (!ent) return Error_NotExist; return sp_mod_mgr_terminate_entity2(mgr, ent, trigger_entity_id); } int sp_mod_mgr_pause_entity(sp_mod_mgr_t *mgr, int entity_id, int trigger_entity_id) { sp_entity_t *ent; ent = sp_mod_mgr_find_entity_by_idx(mgr, entity_id); if (!ent) return Error_NotExist; return sp_mod_mgr_pause_entity2(mgr, ent, trigger_entity_id); } int sp_mod_mgr_continue_entity(sp_mod_mgr_t *mgr, int entity_id, int trigger_entity_id) { sp_entity_t *ent; ent = sp_mod_mgr_find_entity_by_idx(mgr, entity_id); if (!ent) return Error_NotExist; return sp_mod_mgr_continue_entity2(mgr, ent, trigger_entity_id); } int sp_mod_mgr_test_entity(sp_mod_mgr_t *mgr, int entity_id, int trigger_entity_id, int test_type, int* cause) { sp_entity_t *ent; ent = sp_mod_mgr_find_entity_by_idx(mgr, entity_id); if (!ent) return Error_NotExist; return sp_mod_mgr_test_entity2(mgr, ent, trigger_entity_id, test_type, cause); } int sp_mod_mgr_lost_entity(sp_mod_mgr_t *mgr, int entity_id, int trigger_entity_id) { sp_entity_t *ent; sp_mod_t *mod; ent = sp_mod_mgr_find_entity_by_idx(mgr, entity_id); if (!ent) return Error_NotExist; mod = ent->mod; #ifdef _WIN32 sp_mod_mgr_lockEx(mod->cfg->idx); #else sp_mod_mgr_lock(mgr); #endif //_WIN32 if (mod->loaded) { const int last_state = ent->state; DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "set entity %s lost ok!", ent->cfg->name); ent->state = EntityState_Lost; mgr_on_entity_state(mgr, ent, ent->cfg->idx, last_state, ent->state); } #ifdef _WIN32 sp_mod_mgr_unlockEx(mod->cfg->idx); #else sp_mod_mgr_unlock(mgr); #endif //_WIN32 return Error_Succeed; } int sp_mod_mgr_terminate_all_entity(sp_mod_mgr_t* mgr, int trigger_entity_id) { int i; int rc = 0; TOOLKIT_ASSERT(mgr); for (i = 1; i < mgr->arr_ent->nelts; ++i) { int res; sp_entity_t* ent = ARRAY_IDX(mgr->arr_ent, i, sp_entity_t*); res = sp_mod_mgr_terminate_entity2(mgr, ent, trigger_entity_id); if (res != 0) rc = res; } return rc; } int sp_mod_mgr_start_entity2(sp_mod_mgr_t *mgr, sp_entity_t *ent, const char *cmdline, int trigger_entity_id, int entity_id) { int rc = 0; ULONGLONG curTickCount; if (!ent) { return Error_Param; } if (try_lock_doing(mgr, ent->mod)) { int isFirstStart = 0; ent->cfg->m_startTimes++; if (1 == ent->cfg->m_startTimes) isFirstStart = 1; if (isFirstStart) #if defined(_MSC_VER) ent->cfg->m_EntityStartTime.longPart = sp_cfg_getShellFirstStartTime().longPart + clock() * 10000; #else GetLocalTime(&ent->cfg->m_EntityStartTime); #endif //_MSC_VER if (!ent->mod->loaded) rc = load_module(mgr, ent->mod, trigger_entity_id, entity_id); //start Entity process return init ok if (isFirstStart) #if defined(_MSC_VER) ent->cfg->m_EntityInitEndTime.longPart = sp_cfg_getShellFirstStartTime().longPart + clock() * 10000; GetLocalTime(&ent->cfg->m_EntityInitEndTime); #else //GetLocalTime(&ent->cfg->m_EntityInitEndTime); ZeroMemory(&ent->cfg->m_EntityInitEndTime, sizeof(SYSTEMTIME)); curTickCount = GetTickCount64(); memcpy(&ent->cfg->m_EntityInitEndTime, &curTickCount, sizeof(ULONGLONG)); #endif //_MSC_VER if (rc == 0) rc = start_entity(mgr, ent, cmdline, trigger_entity_id);//wait Entity start end, set Idle/lost if (isFirstStart) #if defined(_MSC_VER) ent->cfg->m_EntityStartEndTime.longPart = sp_cfg_getShellFirstStartTime().longPart + clock() * 10000; #else GetLocalTime(&ent->cfg->m_EntityStartEndTime); #endif //_MSC_VER unlock_doing(mgr, ent->mod); } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "mod %s is busy doing now! line: %s", ent->mod->cfg->name, __FUNCTION__); rc = Error_Busy; } return rc; } /*send {MOD_CMD_STOP} cmd and then {MOD_CMD_TERM} cmd*/ int sp_mod_mgr_stop_entity2(sp_mod_mgr_t *mgr, sp_entity_t *ent, int trigger_entity_id, int cause_code) { int rc; if (!ent) return Error_NotExist; if (try_lock_doing(mgr, ent->mod)) { rc = stop_entity(mgr, ent, trigger_entity_id, cause_code); if (rc == 0) { sp_mod_t *mod = ent->mod; sp_entity_t *pos; int unload = TRUE; list_for_each_entry(pos, &mod->entity_list, sp_entity_t, entry) { if ((pos->state != EntityState_Close && pos->state != EntityState_Killed && pos->state != EntityState_NoStart) ){ unload = FALSE; break; } } if (unload) { DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "to unload module..."); rc = unload_module(mgr, mod, trigger_entity_id); DbgWithLinkForC(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM, "unload module returned: %d", rc); } } unlock_doing(mgr, ent->mod); } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "mod %s is busy doing now! line: %s", ent->mod->cfg->name, __FUNCTION__); rc = Error_Busy; } return rc; } int sp_mod_mgr_terminate_entity2(sp_mod_mgr_t *mgr, sp_entity_t *ent, int trigger_entity_id) { int rc; if (!ent) return Error_NotExist; if (try_lock_doing(mgr, ent->mod)) { rc = terminate_module(mgr, ent->mod, trigger_entity_id); unlock_doing(mgr, ent->mod); } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "mod %s is busy doing now! line: %s", ent->mod->cfg->name, __FUNCTION__); rc = Error_Busy; } return rc; } int sp_mod_mgr_pause_entity2(sp_mod_mgr_t *mgr, sp_entity_t *ent, int trigger_entity_id) { int rc; if (!ent) return Error_NotExist; if (try_lock_doing(mgr, ent->mod)) { rc = pause_entity(mgr, ent, trigger_entity_id); unlock_doing(mgr, ent->mod); } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "mod %s is busy doing now! line: %s", ent->mod->cfg->name, __FUNCTION__); rc = Error_Busy; } return rc; } int sp_mod_mgr_continue_entity2(sp_mod_mgr_t *mgr, sp_entity_t *ent, int trigger_entity_id) { int rc; if (!ent) return Error_NotExist; if (try_lock_doing(mgr, ent->mod)) { rc = continue_entity(mgr, ent, trigger_entity_id); unlock_doing(mgr, ent->mod); } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "mod %s is busy doing now! line: %s", ent->mod->cfg->name, __FUNCTION__); rc = Error_Busy; } return rc; } int sp_mod_mgr_test_entity2(sp_mod_mgr_t *mgr, sp_entity_t *ent, int trigger_entity_id, int test_type, int* result) { int rc; if (!ent) return Error_NotExist; if (try_lock_doing(mgr, ent->mod)) { rc = test_entity(mgr, ent, test_type, trigger_entity_id, result); unlock_doing(mgr, ent->mod); } else { DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM, "mod %s is busy doing now! line: %s", ent->mod->cfg->name, __FUNCTION__); rc = Error_Busy; } return rc; } // from shell-> entity int sp_mod_mgr_notify_redirect_subscribe(sp_mod_mgr_t *mgr, sp_entity_t *entity, sp_uid_t *uid, int from_entity_id, const char *param) { int rc; iobuffer_t *pkt = iobuffer_create(-1, -1); iobuffer_write(pkt, IOBUF_T_I8, uid, 0); iobuffer_write(pkt, IOBUF_T_STR, param, -1); rc = sp_svc_post(mgr->shell_svc, entity->mod->cfg->idx, entity->cfg->idx, SP_PKT_MOD|MOD_CMD_NOTIFY_REDIRECT_SUBSCRIBE, from_entity_id, &pkt); if (pkt) iobuffer_dec_ref(pkt); return rc; }