#include "precompile.h" #include "memtrace.h" #include "sp_shm.h" #include "sp_def.h" #include "fileutil.h" #include #include #include #include #include #include #ifdef _WIN32 #include "modManage.h" #include "sphostMonitor.h" #else #include #include "SpHostLog.h" #define TAG "sphost" #endif //_WIN32 #define ARG_NUM 4 HANDLE threadRunLock; #define BUFSIZE 512 #define DEFAULT_MEMORY_CLEAN_TIME 1800 #define DEFAULT_WAITENTITY_END 5000 #ifdef _WIN32 #define PROCESS_SPSHELL "spshell.exe" #else #define PROCESS_SPSHELL "spshell" #endif //_WIN32 // sphost.exe int SPBASE_API __stdcall SpRun(const char* mod_name, int epid, int range, int group, int saveFile); int SPBASE_API __stdcall SpExit(const char* mod_name); void SPBASE_API __stdcall setCurEntityIdx(int idx); int g_entityStart = 0; int g_saveFile = 0; static void SetEnvPath(const char *mod_name) { char path[MAX_PATH]; char *pe; DWORD dwSize; char *buf; const char *var = "PATH"; dwSize = GetEnvironmentVariableA(var, NULL, 0); buf = (char*)malloc(dwSize+MAX_PATH*3); if (buf == NULL) return; dwSize = GetEnvironmentVariableA(var, buf, dwSize); dwSize = GetCurrentDirectoryA(MAX_PATH, path); pe = &path[0] + dwSize; // append dmp subdir to %PATH% strcpy(pe, SPLIT_SLASH_STR "dmp"); if (ExistsDirA(path)) { strcat(buf, ENV_SEP_STR); strcat(buf, path); SetEnvironmentVariableA(var, buf); } // append dep\mod_xxx subdir to %PATH% strcpy(pe, SPLIT_SLASH_STR "dep" SPLIT_SLASH_STR); strcat(pe, mod_name); if (ExistsDirA(path)) { strcat(buf, ENV_SEP_STR); strcat(buf, path); SetEnvironmentVariableA(var, buf); } // append dev\mod_xxx subdir to %PATH% strcpy(pe, SPLIT_SLASH_STR "dev" SPLIT_SLASH_STR); strcat(pe, mod_name); if (ExistsDirA(path)) { strcat(buf, ENV_SEP_STR); strcat(buf, path); SetEnvironmentVariableA(var, buf); } free(buf); SetEnvironmentVariableA("ModuleName", mod_name); } #ifdef RVC_OS_WIN DWORD sphostMonitor(LPVOID param) { DWORD shellId = (DWORD )param; HANDLE spShellProcess = NULL; int waitTimes = 1; if (0 == shellId || NULL == (spShellProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, shellId))) { Sleep(1000 * 30); //do not affact entity start DbgWithLink_sphost("can not find shell id %d", shellId); if (NULL == (spShellProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetProcessIdFromName(PROCESS_SPSHELL))))//获取的是准确的spshell.exe的pid { CloseHandle(spShellProcess); ExitProcess(-1); //can not find spShell } } while (WAIT_TIMEOUT == WaitForSingleObject(spShellProcess, 5000)) //spshell exit { //置换内存到虚拟内存 Sleep(1000); } ExitProcess(0); return 0; } DWORD checkEntityStart(LPVOID param) {//仅检测是否被调用了start命令 Sleep(1000 * 60); if(!g_entityStart) ExitProcess(-1); return 0; } DWORD modRun(LPVOID param) { mod_runInfo *curModInfo = (mod_runInfo*)param; __try{ SetEnvPath(curModInfo->mod_name); //Add env path, \dmp, \dev\mod_name, \dep\mod_name DbgWithLink_sphost("%s entity modRun, SpRun", curModInfo->mod_name); SpRun(curModInfo->mod_name, curModInfo->epid , curModInfo->range, curModInfo->group, g_saveFile); } __finally { DbgWithLink_sphost("Entity %s exit!", curModInfo->mod_name); } return 0; } /*It seems no use anywhere*/ //DWORD modExit(LPVOID param) //{ // mod_exitInfo *curModInfo = (mod_exitInfo*)param; // SpExit(curModInfo->mod_name); // return 0; //} DWORD runThreadAndMonitor(LPVOID param) { mod_runInfo *curModInfo = (mod_runInfo*) param; DWORD exitCode = -1; HANDLE curMutex; char mod_name[MAX_PATH] = ""; sprintf_s(mod_name, sizeof(mod_name), "%s", curModInfo->mod_name);//防止map的迭代器失效 curMutex = CreateMutex(NULL, TRUE, curModInfo->modMutexName); if (NULL == curMutex) return -1; if (NULL != queryModInfo(mod_name)) removeModInfo(mod_name); curModInfo->threadHandle = GetCurrentThread(); AddmodInfo(curModInfo, curModInfo->mod_name); SetEvent(threadRunLock); //此时,主线程中param析构,会导致curModInfo失效 modRun(curModInfo); // Run mod Run by thread /* curThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&modRun, curModInfo, 0, &curModInfo->threadId); if (NULL != curThread) { const mod_runInfo *queryInfo = queryModInfo(mod_name); if (NULL != queryInfo) removeModInfo(mod_name); curModInfo->threadHandle = curThread; AddmodInfo(curModInfo, curModInfo->mod_name); SetEvent(threadRunLock); //此时,主线程中param析构,会导致curModInfo失效 WaitForSingleObject(curThread, INFINITE); GetExitCodeThread(curThread, &exitCode); removeModInfo(mod_name); DbgWithLink_sphost("%s entity exit success", mod_name); } */ ReleaseMutex(curMutex); CloseHandle(curMutex); return exitCode; } DWORD cpuMask[15] = { 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000}; void SetCurrentProcessMask() { unsigned long lProcessAffinityMask = 0; unsigned long lSystemAffinityMask = 0; int MaxCoreNum = 0; HANDLE hCurrentProc = GetCurrentProcess(); GetProcessAffinityMask(hCurrentProc, &lProcessAffinityMask, &lSystemAffinityMask); lProcessAffinityMask = lSystemAffinityMask & 0xFFFFFFFE; while (lSystemAffinityMask > 0) { lSystemAffinityMask = lSystemAffinityMask >> 1; MaxCoreNum++; if (MaxCoreNum > 16) break; } if (MaxCoreNum < 4) return;//小于4核不做相应限制 srand((unsigned int)time(NULL)); //lProcessAffinityMask = 1 << (rand() % (MaxCoreNum - 1) + 1); //DbgWithLink_sphost("lProcessAffinityMask:%u, MaxCoreNum:%d", lProcessAffinityMask, MaxCoreNum); SetProcessAffinityMask(hCurrentProc, lProcessAffinityMask); SetProcessAffinityUpdateMode(hCurrentProc, PROCESS_AFFINITY_ENABLE_AUTO_UPDATE); //SetPriorityClass(hCurrentProc, NORMAL_PRIORITY_CLASS); CloseHandle(hCurrentProc); } #endif //RVC_OS_WIN int main(int argc, char *argv[]) { #ifdef RVC_OS_WIN char readBuf[MAX_PATH] = ""; char writeBuf[MAX_PATH] = ""; DWORD dwRead = 0; DWORD dwWrite = 0; HANDLE hPipe, hMutex, mainThread; TCHAR chBuf[MAX_PATH] = ""; DWORD dwMode = PIPE_READMODE_MESSAGE; char lpszPipename[MAX_PATH] = "\\\\.\\pipe\\"; char eventName[MAX_PATH] = ""; DWORD dstShellId = 0; clock_t t_begin; int testDua1 = 0, testDual2 = 0, testDual3 = 0, testDual4 = 0, testDual5 = 0, testDual6 = 0; t_begin = clock(); threadRunLock = CreateEvent(NULL, FALSE, FALSE, NULL); _CrtSetDebugFillThreshold( 0 ); testDua1 = (clock() - t_begin) * 1000 / CLOCKS_PER_SEC; t_begin = clock(); /* return shm range */ if (argc == 2) { if (argv[1][0] == '{') sprintf(lpszPipename, "%s%s", lpszPipename, argv[1]); else { int range = atoi(argv[1]); return sp_shm_get_range(range); } } else if (argc == 3) { if (argv[1][0] == '{') { dstShellId = atoi(argv[2]); sprintf(lpszPipename, "%s%s", lpszPipename, argv[1]); } else { int range = atoi(argv[1]); return sp_shm_get_range(range); } } testDual2 = (clock() - t_begin) * 1000 / CLOCKS_PER_SEC; t_begin = clock(); setlocale(LC_ALL, "chs"); #else int range; char* mod_name; int epid; int rc; int idx; char epid_str[64]; for (idx = 0; idx < argc; ++idx) { printf("argv[%d]: %s\n", idx, argv[idx]); } if (argc == 2) { /* return shm range */ int range = atoi(argv[1]); printf("range mask: %d\n", range); range = sp_shm_get_range(range); printf("range return: %d\n", range); return range; } if (NULL == setlocale(LC_ALL, "zh_CN.UTF-8")) { //zh_CN.UTF-8 zh_CN.GBK printf("setlocale failed: %s", strerror(errno)); } #endif //RVC_OS_WIN #ifdef RVC_OS_WIN hPipe = CreateFile(lpszPipename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hPipe == INVALID_HANDLE_VALUE && !WaitNamedPipe(lpszPipename, 5000)) return -1; if (!SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL)) return -1; testDual3 = (clock() - t_begin) * 1000 / CLOCKS_PER_SEC; t_begin = clock(); hMutex = OpenEvent(EVENT_ALL_ACCESS, FALSE, argv[1]); SetEvent(hMutex); //CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&sphostMonitor, dstShellId, 0, NULL));// 监控内存及句柄线程,进程结束时关闭 testDual4 = (clock() - t_begin) * 1000 / CLOCKS_PER_SEC; t_begin = clock(); while (ReadFile(hPipe, readBuf, sizeof(readBuf), &dwRead, NULL)) { char tempBuf[MAX_PATH] = ""; char dstParam[10][MAX_PATH]; int paramNum = 0; ZeroMemory(dstParam, sizeof(dstParam)); if (-1 == (paramNum = paramSplit(readBuf, dstParam))) continue; if (!strcmp(dstParam[0], "start") && paramNum == 7) {//start mod_runInfo *curModInfo = (mod_runInfo*)malloc(sizeof(mod_runInfo)); ZeroMemory(curModInfo, sizeof(mod_runInfo)); strcpy(curModInfo->mod_name, dstParam[1]); curModInfo->epid = atoi(dstParam[2]); curModInfo->range = atoi(dstParam[3]); strcpy(curModInfo->modMutexName, dstParam[4]); curModInfo->group = 0; g_saveFile = atoi((dstParam[5])); setCurEntityIdx(atoi(dstParam[6])); //WLog_initRVC(dstParam[1]); createLogProducer(dstParam[1], dstParam[2]); if (testDua1 > 100 || testDual2 > 100 || testDual3 > 100 || testDual4 > 100) DbgWithLink_sphost("sphost initTest in %d-%d-%d-%d", testDua1, testDual2, testDual3, testDual4); DbgWithLink_sphost("sphost main start process id: %d, query Entity %s start, epid:%d, range:%d, group:%d", GetCurrentProcessId(), curModInfo->mod_name, curModInfo->epid, curModInfo->range, curModInfo->group); mainThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&runThreadAndMonitor, curModInfo, 0, &curModInfo->threadId); testDual5 = (clock() - t_begin) * 1000 / CLOCKS_PER_SEC; t_begin = clock(); if(testDual5 > 100) DbgWithLink_sphost("%s entity main, Wait threadRunLock, cost %d", curModInfo->mod_name, testDual5); if (WAIT_TIMEOUT == WaitForSingleObject(threadRunLock, 4500)) //wait for entity thread create { WriteFile(hPipe, OPERATE_FAIL, strlen(OPERATE_FAIL) + 1, &dwWrite, NULL); DbgWithLink_sphost("%s entity run timeout!", curModInfo->mod_name); } else if (NULL != curModInfo->threadHandle) { WriteFile(hPipe, OPERATE_SUCCESS, strlen(OPERATE_SUCCESS) + 1, &dwWrite, NULL); testDual6 = (clock() - t_begin) * 1000 / CLOCKS_PER_SEC; t_begin = clock(); if(testDual6 > 100) DbgWithLink_sphost("%s entity run success, cost %d!", curModInfo->mod_name, testDual6); SetCurrentProcessMask(); CloseHandle(mainThread); CloseHandle(hMutex); } else { WriteFile(hPipe, OPERATE_FAIL, strlen(OPERATE_FAIL) + 1, &dwWrite, NULL); DbgWithLink_sphost("%s entity run failed!", curModInfo->mod_name); } /* if (!g_entityStart) { g_entityStart = 1; CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&sphostMonitor, NULL, 0, NULL)); // 监控内存及句柄线程,进程结束时关闭 }*/ } else if(!strcmp(dstParam[0], "kill") && paramNum == 2) { //kill mod_runInfo* killModInfo = NULL; DbgWithLink_sphost("pipe kill %s", dstParam[1]); killModInfo = queryModInfo(dstParam[1]); if (NULL != killModInfo) { static mod_exitInfo curModInfo; HANDLE tmpHandle; sprintf_s(curModInfo.mod_name, sizeof(curModInfo.mod_name), "%s", killModInfo->mod_name); tmpHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&SpExit, &curModInfo, 0, NULL); if (tmpHandle != NULL) { CloseHandle(tmpHandle); } if (WAIT_TIMEOUT != WaitForSingleObject(killModInfo->threadHandle, DEFAULT_WAITENTITY_END)) WriteFile(hPipe, OPERATE_SUCCESS, strlen(OPERATE_SUCCESS) + 1, &dwWrite, NULL); else WriteFile(hPipe, OPERATE_FAIL, strlen(OPERATE_FAIL) + 1, &dwWrite, NULL); //监控线程自动清理 } else if (!strcmp(dstParam[1], "process")) { WriteFile(hPipe, OPERATE_SUCCESS, strlen(OPERATE_SUCCESS) + 1, &dwWrite, NULL); DbgWithLink_sphost("tell spshell the operation is done and exit process directly."); return 0; } else { WriteFile(hPipe, OPERATE_FAIL, strlen(OPERATE_FAIL) + 1, &dwWrite, NULL); } } else if (!strcmp(dstParam[0], "query") && paramNum == 2) {//查询特定实体Info const mod_runInfo *queryInfo = queryModInfo(dstParam[1]); if (NULL != queryInfo) { sprintf_s(tempBuf, sizeof(tempBuf), "%s %s %s %d", OPERATE_SUCCESS, queryInfo->mod_name, queryInfo->modMutexName, queryInfo->threadId);//threadId对于远程进程并无任何用途 WriteFile(hPipe, tempBuf, strlen(tempBuf) + 1, &dwWrite, NULL); } else WriteFile(hPipe, OPERATE_FAIL, strlen(OPERATE_FAIL) + 1, &dwWrite, NULL); } } #else range = atoi(argv[1]); mod_name = argv[2]; epid = atoi(argv[3]); g_saveFile = atoi((argv[4])); sprintf(epid_str, "%d", epid); setCurEntityIdx(atoi(argv[5])); if (!mod_name || !strlen(mod_name)) { return -300; } WLog_initRVC(mod_name); createLogProducer(mod_name, epid_str); SetEnvPath(mod_name); rc = SpRun(mod_name, epid, range, 0, g_saveFile); #endif //RVC_OS_WIN return 0; } #ifdef RVC_OS_WIN int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { return main(__argc, __argv); } #endif //RVC_OS_WIN