void RunServer() { Bool16 restartServer = false; UInt32 loopCount = 0; UInt32 debugLevel = 0; Bool16 printHeader = false; Bool16 printStatus = false; //just wait until someone stops the server or a fatal error occurs. QTSS_ServerState theServerState = theSver->GetServerState(); while ((theServerState != qtssShuttingDownState) && (theServerState != qtssFatalErrorState)) { #ifdef __sgi__ OSThread::Sleep(999); #else OSThread::Sleep(1000); #endif if ((theSver->SigIntSet()) || (theSver->SigTermSet())) { // // start the shutdown process theServerState = qtssShuttingDownState; // (void)QTSS_SetValue(QTSServerInterface::GetServer(), qtssSvrState, 0, &theServerState, sizeof(theServerState)); if (theSver->SigIntSet()) restartServer = true; } } //Now, make sure that the server can't do any work TaskThreadPool::RemoveThreads(); //now that the server is definitely stopped, it is safe to initate //the shutdown process delete theSver; CleanPid(false); //ok, we're ready to exit. If we're quitting because of some fatal error //while running the server, make sure to let the parent process know by //exiting with a nonzero status. Otherwise, exit with a 0 status if (theServerState == qtssFatalErrorState || restartServer) ::exit (-2);//-2 signals parent process to restart server }
QTSS_ServerState StartServer(XMLPrefsParser* inPrefsSource, PrefsSource* inMessagesSource, UInt16 inPortOverride, int statsUpdateInterval, QTSS_ServerState inInitialState, Bool16 inDontFork, UInt32 debugLevel, UInt32 debugOptions) { //Mark when we are done starting up. If auto-restart is enabled, we want to make sure //to always exit with a status of 0 if we encountered a problem WHILE STARTING UP. This //will prevent infinite-auto-restart-loop type problems Bool16 doneStartingUp = false; QTSS_ServerState theServerState = qtssStartingUpState; sStatusUpdateInterval = statsUpdateInterval; //Initialize utility classes OS::Initialize(); OSThread::Initialize(); Socket::Initialize(); SocketUtils::Initialize(!inDontFork); #if !MACOSXEVENTQUEUE ::select_startevents();//initialize the select() implementation of the event queue #endif //start the server QTSSDictionaryMap::Initialize(); QTSServerInterface::Initialize();// this must be called before constructing the server object sServer = NEW QTSServer(); sServer->SetDebugLevel(debugLevel); sServer->SetDebugOptions(debugOptions); // re-parse config file inPrefsSource->Parse(); Bool16 createListeners = true; if (qtssShuttingDownState == inInitialState) createListeners = false; sServer->Initialize(inPrefsSource, inMessagesSource, inPortOverride,createListeners); if (inInitialState == qtssShuttingDownState) { sServer->InitModules(inInitialState); return inInitialState; } OSCharArrayDeleter runGroupName(sServer->GetPrefs()->GetRunGroupName()); OSCharArrayDeleter runUserName(sServer->GetPrefs()->GetRunUserName()); OSThread::SetPersonality(runUserName.GetObject(), runGroupName.GetObject()); if (sServer->GetServerState() != qtssFatalErrorState) { UInt32 numShortTaskThreads = 0; UInt32 numBlockingThreads = 0; UInt32 numThreads = 0; UInt32 numProcessors = 0; if (OS::ThreadSafe()) { numShortTaskThreads = sServer->GetPrefs()->GetNumThreads(); // whatever the prefs say if (numShortTaskThreads == 0) { numProcessors = OS::GetNumProcessors(); // 1 worker thread per processor, up to 2 threads. // Note: Limiting the number of worker threads to 2 on a MacOS X system with > 2 cores // results in better performance on those systems, as of MacOS X 10.5. Future // improvements should make this limit unnecessary. if (numProcessors > 2) numShortTaskThreads = 2; else numShortTaskThreads = numProcessors; } numBlockingThreads = sServer->GetPrefs()->GetNumBlockingThreads(); // whatever the prefs say if (numBlockingThreads == 0) numBlockingThreads = 1; } if (numShortTaskThreads == 0) numShortTaskThreads = 1; if (numBlockingThreads == 0) numBlockingThreads = 1; numThreads = numShortTaskThreads + numBlockingThreads; //qtss_printf("Add threads shortask=%lu blocking=%lu\n",numShortTaskThreads, numBlockingThreads); TaskThreadPool::SetNumShortTaskThreads(numShortTaskThreads); TaskThreadPool::SetNumBlockingTaskThreads(numBlockingThreads); TaskThreadPool::AddThreads(numThreads); sServer->InitNumThreads(numThreads); #if DEBUG qtss_printf("Number of task threads: %"_U32BITARG_"\n",numThreads); #endif // Start up the server's global tasks, and start listening TimeoutTask::Initialize(); // The TimeoutTask mechanism is task based, // we therefore must do this after adding task threads // this be done before starting the sockets and server tasks } //Make sure to do this stuff last. Because these are all the threads that //do work in the server, this ensures that no work can go on while the server //is in the process of staring up if (sServer->GetServerState() != qtssFatalErrorState) { IdleTask::Initialize(); Socket::StartThread(); OSThread::Sleep(1000); // // On Win32, in order to call modwatch the Socket EventQueue thread must be // created first. Modules call modwatch from their initializer, and we don't // want to prevent them from doing that, so module initialization is separated // out from other initialization, and we start the Socket EventQueue thread first. // The server is still prevented from doing anything as of yet, because there // aren't any TaskThreads yet. sServer->InitModules(inInitialState); sServer->StartTasks(); sServer->SetupUDPSockets(); // udp sockets are set up after the rtcp task is instantiated theServerState = sServer->GetServerState(); } if (theServerState != qtssFatalErrorState) { CleanPid(true); WritePid(!inDontFork); doneStartingUp = true; qtss_printf("Streaming Server done starting up\n"); OSMemory::SetMemoryError(ENOMEM); } // SWITCH TO RUN USER AND GROUP ID //if (!sServer->SwitchPersonality()) // theServerState = qtssFatalErrorState; // // Tell the caller whether the server started up or not return theServerState; }
void RunServer() { Bool16 restartServer = false; UInt32 loopCount = 0; UInt32 debugLevel = 0; Bool16 printHeader = false; Bool16 printStatus = false; //just wait until someone stops the server or a fatal error occurs. QTSS_ServerState theServerState = sServer->GetServerState(); while ((theServerState != qtssShuttingDownState) && (theServerState != qtssFatalErrorState)) { #ifdef __sgi__ OSThread::Sleep(999); #else OSThread::Sleep(1000); #endif LogStatus(theServerState); if (sStatusUpdateInterval) { debugLevel = sServer->GetDebugLevel(); printHeader = PrintHeader(loopCount); printStatus = PrintLine(loopCount); if (printStatus) { if (DebugOn(sServer) ) // debug level display or logging is on DebugStatus(debugLevel, printHeader); if (!DebugDisplayOn(sServer)) PrintStatus(printHeader); // default status output } loopCount++; } if ((sServer->SigIntSet()) || (sServer->SigTermSet())) { // // start the shutdown process theServerState = qtssShuttingDownState; (void)QTSS_SetValue(QTSServerInterface::GetServer(), qtssSvrState, 0, &theServerState, sizeof(theServerState)); if (sServer->SigIntSet()) restartServer = true; } theServerState = sServer->GetServerState(); if (theServerState == qtssIdleState) sServer->KillAllRTPSessions(); } // // Kill all the sessions and wait for them to die, // but don't wait more than 5 seconds sServer->KillAllRTPSessions(); for (UInt32 shutdownWaitCount = 0; (sServer->GetNumRTPSessions() > 0) && (shutdownWaitCount < 5); shutdownWaitCount++) OSThread::Sleep(1000); //Now, make sure that the server can't do any work TaskThreadPool::RemoveThreads(); //now that the server is definitely stopped, it is safe to initate //the shutdown process delete sServer; CleanPid(false); //ok, we're ready to exit. If we're quitting because of some fatal error //while running the server, make sure to let the parent process know by //exiting with a nonzero status. Otherwise, exit with a 0 status if (theServerState == qtssFatalErrorState || restartServer) ::exit (-2);//-2 signals parent process to restart server }
int main(int argc, char * argv[]) { extern char* optarg; // on write, don't send signal for SIGPIPE, just set errno to EPIPE // and return -1 //signal is a deprecated and potentially dangerous function //(void) ::signal(SIGPIPE, SIG_IGN); struct sigaction act; #if defined(sun) || defined(i386) || defined(__x86_64__) || defined (__MacOSX__) || defined(__powerpc__) || defined (__osf__) || defined (__sgi_cc__) || defined (__hpux__) || defined (__linux__) sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = (void(*)(int))&sigcatcher; #elif defined(__sgi__) sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = (void(*)(...))&sigcatcher; #else act.sa_mask = 0; act.sa_flags = 0; act.sa_handler = (void(*)(...))&sigcatcher; #endif (void)::sigaction(SIGPIPE, &act, NULL); (void)::sigaction(SIGHUP, &act, NULL); (void)::sigaction(SIGINT, &act, NULL); (void)::sigaction(SIGTERM, &act, NULL); (void)::sigaction(SIGQUIT, &act, NULL); (void)::sigaction(SIGALRM, &act, NULL); #if __solaris__ || __linux__ || __hpux__ //grow our pool of file descriptors to the max! struct rlimit rl; // set it to the absolute maximum that the operating system allows - have to be superuser to do this rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; setrlimit (RLIMIT_NOFILE, &rl); #endif #if __MacOSX__ struct rlimit rl; getrlimit(RLIMIT_NOFILE, &rl); //get the default values //printf("current open file limit =%"_U32BITARG_"\n", (UInt32) rl.rlim_cur); //leopard returns 256 //printf("current open file max =%"_U32BITARG_"\n", (UInt32) rl.rlim_max);//leopard returns infinity (-1) rl. rlim_max = (rlim_t) RLIM_INFINITY -1; //use a big number to find out the real max but do not use RLIM_INFINITY that is not allowed. see man page setrlimit (RLIMIT_NOFILE, &rl); //resets the max value stored by limits to the boot config values. getrlimit(RLIMIT_NOFILE, &rl); //now get the real max value //printf("current open file limit =%"_U32BITARG_"\n", (UInt32) rl.rlim_cur); //printf("current open file max =%"_U32BITARG_"\n", (UInt32) rl.rlim_max); rl.rlim_cur = (rlim_t) ( (float) rl.rlim_max * 0.9); //use 90% of the max set in /etc/rc.server and /etc/sysctl.conf.default setrlimit (RLIMIT_NOFILE, &rl); //finally set the current limit #endif #if 0 // testing getrlimit(RLIMIT_NOFILE, &rl); printf("current open file limit =%"_U32BITARG_"\n", (UInt32) rl.rlim_cur); printf("current open file max =%"_U32BITARG_"\n", (UInt32) rl.rlim_max); #endif #if __MacOSX__ || __FreeBSD__ // // These 2 OSes have problems with large socket buffer sizes. Make sure they allow even // ridiculously large ones, because we may need them to receive a large volume of ACK packets // from the client // // We raise the limit imposed by the kernel by calling the sysctl system call. int mib[CTL_MAXNAME]; mib[0] = CTL_KERN; mib[1] = KERN_IPC; mib[2] = KIPC_MAXSOCKBUF; mib[3] = 0; int maxSocketBufferSizeVal = 2000 * 1024; // Allow up to 2 MB. That is WAY more than we should need (void) ::sysctl(mib, 3, 0, 0, &maxSocketBufferSizeVal, sizeof(maxSocketBufferSizeVal)); //int sysctlErr = ::sysctl(mib, 3, 0, 0, &maxSocketBufferSizeVal, sizeof(maxSocketBufferSizeVal)); //qtss_printf("sysctl maxSocketBufferSizeVal=%d err=%d\n",maxSocketBufferSizeVal, sysctlErr); #endif //First thing to do is to read command-line arguments. int ch; int thePort = 0; //port can be set on the command line int statsUpdateInterval = 0; QTSS_ServerState theInitialState = qtssRunningState; Bool16 dontFork = false; Bool16 theXMLPrefsExist = true; UInt32 debugLevel = 0; UInt32 debugOptions = kRunServerDebug_Off; static char* sDefaultConfigFilePath = DEFAULTPATHS_ETC_DIR_OLD "easydarwin.conf"; static char* sDefaultXMLFilePath = DEFAULTPATHS_ETC_DIR "easydarwin.xml"; char* theConfigFilePath = sDefaultConfigFilePath; char* theXMLFilePath = sDefaultXMLFilePath; while ((ch = getopt(argc,argv, "vdfxp:DZ:c:o:S:Ih")) != EOF) // opt: means requires option arg { switch(ch) { case 'v': usage(); ::exit(0); case 'd': dontFork = RunInForeground(); break; case 'D': dontFork = RunInForeground(); debugOptions |= kRunServerDebugDisplay_On; if (debugLevel == 0) debugLevel = 1; if (statsUpdateInterval == 0) statsUpdateInterval = 3; break; case 'Z': Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt. debugLevel = (UInt32) ::atoi(optarg); break; case 'f': theXMLFilePath = DEFAULTPATHS_ETC_DIR "easydarwin.xml"; break; case 'p': Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt. thePort = ::atoi(optarg); break; case 'S': dontFork = RunInForeground(); Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt. statsUpdateInterval = ::atoi(optarg); break; case 'c': Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt. theXMLFilePath = optarg; break; case 'o': Assert(optarg != NULL);// this means we didn't declare getopt options correctly or there is a bug in getopt. theConfigFilePath = optarg; break; case 'x': theXMLPrefsExist = false; // Force us to generate a new XML prefs file theInitialState = qtssShuttingDownState; dontFork = true; break; case 'I': theInitialState = qtssIdleState; break; case 'h': usage(); ::exit(0); default: break; } } // Check port if (thePort < 0 || thePort > 65535) { qtss_printf("Invalid port value = %d max value = 65535\n",thePort); exit (-1); } // Check expiration date QTSSExpirationDate::PrintExpirationDate(); if (QTSSExpirationDate::IsSoftwareExpired()) { qtss_printf("Streaming Server has expired\n"); ::exit(0); } XMLPrefsParser theXMLParser(theXMLFilePath); // // Check to see if the XML file exists as a directory. If it does, // just bail because we do not want to overwrite a directory if (theXMLParser.DoesFileExistAsDirectory()) { qtss_printf("Directory located at location where streaming server prefs file should be.\n"); exit(-1); } // // Check to see if we can write to the file if (!theXMLParser.CanWriteFile()) { qtss_printf("Cannot write to the streaming server prefs file.\n"); exit(-1); } // If we aren't forced to create a new XML prefs file, whether // we do or not depends solely on whether the XML prefs file exists currently. if (theXMLPrefsExist) theXMLPrefsExist = theXMLParser.DoesFileExist(); if (!theXMLPrefsExist) { // // The XML prefs file doesn't exist, so let's create an old-style // prefs source in order to generate a fresh XML prefs file. if (theConfigFilePath != NULL) { FilePrefsSource* filePrefsSource = new FilePrefsSource(true); // Allow dups if ( filePrefsSource->InitFromConfigFile(theConfigFilePath) ) { qtss_printf("Generating a new prefs file at %s\n", theXMLFilePath); } if (GenerateAllXMLPrefs(filePrefsSource, &theXMLParser)) { qtss_printf("Fatal Error: Could not create new prefs file at: %s. (%d)\n", theXMLFilePath, OSThread::GetErrno()); ::exit(-1); } } } // // Parse the configs from the XML file int xmlParseErr = theXMLParser.Parse(); if (xmlParseErr) { qtss_printf("Fatal Error: Could not load configuration file at %s. (%d)\n", theXMLFilePath, OSThread::GetErrno()); ::exit(-1); } //Unless the command line option is set, fork & daemonize the process at this point if (!dontFork) { #ifdef __sgi__ // for some reason, this method doesn't work right on IRIX 6.4 unless the first arg // is _DF_NOFORK. if the first arg is 0 (as it should be) the result is a server // that is essentially paralized and doesn't respond to much at all. So for now, // leave the first arg as _DF_NOFORK // if (_daemonize(_DF_NOFORK, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO) != 0) if (_daemonize(0, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO) != 0) #else if (daemon(0,0) != 0) #endif { #if DEBUG qtss_printf("Failed to daemonize process. Error = %d\n", OSThread::GetErrno()); #endif exit(-1); } } //Construct a Prefs Source object to get server text messages FilePrefsSource theMessagesSource; theMessagesSource.InitFromConfigFile("qtssmessages.txt"); int status = 0; int pid = 0; pid_t processID = 0; if ( !dontFork) // if (fork) { //loop until the server exits normally. If the server doesn't exit //normally, then restart it. // normal exit means the following // the child quit do // fork at least once but stop on the status conditions returned by wait or if autoStart pref is false { processID = fork(); Assert(processID >= 0); if (processID > 0) // this is the parent and we have a child { sChildPID = processID; status = 0; while (status == 0) //loop on wait until status is != 0; { pid =::wait(&status); SInt8 exitStatus = (SInt8) WEXITSTATUS(status); //qtss_printf("Child Process %d wait exited with pid=%d status=%d exit status=%d\n", processID, pid, status, exitStatus); if (WIFEXITED(status) && pid > 0 && status != 0) // child exited with status -2 restart or -1 don't restart { //qtss_printf("child exited with status=%d\n", exitStatus); if ( exitStatus == -1) // child couldn't run don't try again { qtss_printf("child exited with -1 fatal error so parent is exiting too.\n"); exit (EXIT_FAILURE); } break; // restart the child } if (WIFSIGNALED(status)) // child exited on an unhandled signal (maybe a bus error or seg fault) { //qtss_printf("child was signalled\n"); break; // restart the child } if (pid == -1 && status == 0) // parent woken up by a handled signal { //qtss_printf("handled signal continue waiting\n"); continue; } if (pid > 0 && status == 0) { //qtss_printf("child exited cleanly so parent is exiting\n"); exit(EXIT_SUCCESS); } //qtss_printf("child died for unknown reasons parent is exiting\n"); exit (EXIT_FAILURE); } } else if (processID == 0) // must be the child break; else exit(EXIT_FAILURE); //eek. If you auto-restart too fast, you might start the new one before the OS has //cleaned up from the old one, resulting in startup errors when you create the new //one. Waiting for a second seems to work sleep(1); } while (RestartServer(theXMLFilePath)); // fork again based on pref if server dies if (processID != 0) //the parent is quitting exit(EXIT_SUCCESS); } sChildPID = 0; //we have to do this again for the child process, because sigaction states //do not span multiple processes. (void)::sigaction(SIGPIPE, &act, NULL); (void)::sigaction(SIGHUP, &act, NULL); (void)::sigaction(SIGINT, &act, NULL); (void)::sigaction(SIGTERM, &act, NULL); (void)::sigaction(SIGQUIT, &act, NULL); #ifdef __hpux__ // Set Priority Type to Real Time, timeslice = 100 milliseconds. Change the timeslice upwards as needed. This keeps the server priority above the playlist broadcaster which is a time-share scheduling type. char commandStr[64]; qtss_sprintf(commandStr, "/usr/bin/rtprio -t -%d", (int) getpid()); #if DEBUG qtss_printf("setting priority to Real Time: %s\n", commandStr); #endif (void) ::system(commandStr); #endif #ifdef __solaris__ // Set Priority Type to Real Time, timeslice = 100 milliseconds. Change the timeslice upwards as needed. This keeps the server priority above the playlist broadcaster which is a time-share scheduling type. char commandStr[64]; qtss_sprintf(commandStr, "priocntl -s -c RT -t 10 -i pid %d", (int) getpid()); (void) ::system(commandStr); #endif #ifdef __MacOSX__ (void) ::umask(S_IWGRP|S_IWOTH); // make sure files are opened with default of owner -rw-r-r- #endif //This function starts, runs, and shuts down the server if (::StartServer(&theXMLParser, &theMessagesSource, thePort, statsUpdateInterval, theInitialState, dontFork, debugLevel, debugOptions) != qtssFatalErrorState) { ::RunServer(); CleanPid(false); exit (EXIT_SUCCESS); } else exit(-1); //Cant start server don't try again }
//启动服务 QTSS_ServerState StartServer(XMLPrefsParser* inPrefsSource, PrefsSource* inMessagesSource, UInt16 inPortOverride, int statsUpdateInterval, QTSS_ServerState inInitialState, Bool16 inDontFork, UInt32 debugLevel, UInt32 debugOptions) { //Mark when we are done starting up. If auto-restart is enabled, we want to make sure //to always exit with a status of 0 if we encountered a problem WHILE STARTING UP. This //will prevent infinite-auto-restart-loop type problems Bool16 doneStartingUp = false; QTSS_ServerState theServerState = qtssStartingUpState; //服务单元状态更新间隔 sStatusUpdateInterval = statsUpdateInterval; //Initialize utility classes OS::Initialize(); OSThread::Initialize(); //建立网络事件(R/W/E事件)线程,仅建立,But未启动 Socket::Initialize(); //获取系统网卡数量sNumIPAddrs及对应的具体ip,存储在sIPAddrInfoArray结构体数组中 SocketUtils::Initialize(!inDontFork); /* #if !MACOSXEVENTQUEUE ::select_startevents();//initialize the select() implementation of the event queue #endif */ #if !MACOSXEVENTQUEUE #ifndef __Win32__ ::epollInit(); #else ::select_startevents();//initialize the select() implementation of the event queue #endif #endif //初始化系统属性字典 QTSSDictionaryMap::Initialize(); //初始化Server对象属性字典,包括其他具有属性字典的类,都要先进行Initialize QTSServerInterface::Initialize();//此部分必须在QTSServer对象构造前调用 sServer = NEW QTSServer(); sServer->SetDebugLevel(debugLevel); sServer->SetDebugOptions(debugOptions); //重新解析xml配置 inPrefsSource->Parse(); //准备开启监听,接收并处理相关事务 Bool16 createListeners = true; if (qtssShuttingDownState == inInitialState) createListeners = false; //初始化服务实例 sServer->Initialize(inPrefsSource, inMessagesSource, inPortOverride, createListeners); if (inInitialState == qtssShuttingDownState) { sServer->InitModules(inInitialState); return inInitialState; } if (sServer->GetServerState() != qtssFatalErrorState) { UInt32 numShortTaskThreads = 0; UInt32 numBlockingThreads = 0; UInt32 numThreads = 0; UInt32 numProcessors = 0; if (OS::ThreadSafe()) { //工作线程 numShortTaskThreads = sServer->GetPrefs()->GetNumThreads(); // whatever the prefs say if (numShortTaskThreads == 0) { numProcessors = OS::GetNumProcessors(); // 1 worker thread per processor, up to 2 threads. // Note:Limiting the number of worker threads to 2 on a MacOS X system with > 2 cores // results in better performance on those systems, as of MacOS X 10.5. Future // improvements should make this limit unnecessary. if (numProcessors > 2) numShortTaskThreads = 2; else numShortTaskThreads = numProcessors; } //协议处理线程 numBlockingThreads = sServer->GetPrefs()->GetNumBlockingThreads(); // whatever the prefs say if (numBlockingThreads == 0) numBlockingThreads = 1; } if (numShortTaskThreads == 0) numShortTaskThreads = 1; if (numBlockingThreads == 0) numBlockingThreads = 1; numThreads = numShortTaskThreads + numBlockingThreads; //qtss_printf("Add threads shortask=%lu blocking=%lu\n",numShortTaskThreads, numBlockingThreads); TaskThreadPool::SetNumShortTaskThreads(numShortTaskThreads); TaskThreadPool::SetNumBlockingTaskThreads(numBlockingThreads); TaskThreadPool::AddThreads(numThreads); sServer->InitNumThreads(numThreads); #if DEBUG qtss_printf("Number of task threads: %" _U32BITARG_ "\n",numThreads); #endif // Start up the server's global tasks, and start listening //超时事件处理线程 TimeoutTask::Initialize(); // The TimeoutTask mechanism is task based, // we therefore must do this after adding task threads // this be done before starting the sockets and server tasks } //Make sure to do this stuff last. Because these are all the threads that //do work in the server, this ensures that no work can go on while the server //is in the process of staring up if (sServer->GetServerState() != qtssFatalErrorState) { //Idle事务处理线程 IdleTask::Initialize(); Socket::StartThread(); OSThread::Sleep(1000); // // On Win32, in order to call modwatch the Socket EventQueue thread must be // created first. Modules call modwatch from their initializer, and we don't // want to prevent them from doing that, so module initialization is separated // out from other initialization, and we start the Socket EventQueue thread first. // The server is still prevented from doing anything as of yet, because there // aren't any TaskThreads yet. sServer->InitModules(inInitialState); sServer->StartTasks(); theServerState = sServer->GetServerState(); } if (theServerState != qtssFatalErrorState) { CleanPid(true); WritePid(!inDontFork); doneStartingUp = true; //Log char msgStr[128]; qtss_snprintf(msgStr, sizeof(msgStr), "EasyCMS Service done starting up"); QTSServerInterface::LogError(qtssMessageVerbosity, msgStr); OSMemory::SetMemoryError(ENOMEM); } //// SWITCH TO RUN USER AND GROUP ID //if (!sServer->SwitchPersonality()) // theServerState = qtssFatalErrorState; // Tell the caller whether the server started up or not return theServerState; }
void RunServer() { Bool16 restartServer = false; UInt32 loopCount = 0; UInt32 debugLevel = 0; Bool16 printHeader = false; Bool16 printStatus = false; UInt32 num=0;//add //just wait until someone stops the server or a fatal error occurs. QTSS_ServerState theServerState = sServer->GetServerState(); while ((theServerState != qtssShuttingDownState) && (theServerState != qtssFatalErrorState)) { #ifdef __sgi__ OSThread::Sleep(999); #else OSThread::Sleep(1000); #endif //add,redis,定时保活 num++; if(num%5==0) { num=0; UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kRedisTTLRole); for ( UInt32 currentModule=0;currentModule < numModules; currentModule++) { QTSSModule* theModule = QTSServerInterface::GetModule(QTSSModule::kRedisTTLRole, currentModule); (void)theModule->CallDispatch(Easy_RedisTTL_Role, NULL); } } // LogStatus(theServerState); if (sStatusUpdateInterval) { debugLevel = sServer->GetDebugLevel(); printHeader = PrintHeader(loopCount); printStatus = PrintLine(loopCount); if (printStatus) { if (DebugOn(sServer) ) // debug level display or logging is on DebugStatus(debugLevel, printHeader); if (!DebugDisplayOn(sServer)) PrintStatus(printHeader); // default status output } loopCount++; } if ((sServer->SigIntSet()) || (sServer->SigTermSet())) { // // start the shutdown process theServerState = qtssShuttingDownState; (void)QTSS_SetValue(QTSServerInterface::GetServer(), qtssSvrState, 0, &theServerState, sizeof(theServerState)); if (sServer->SigIntSet()) restartServer = true; } } //Now, make sure that the server can't do any work TaskThreadPool::RemoveThreads(); //now that the server is definitely stopped, it is safe to initate //the shutdown process delete sServer; CleanPid(false); //ok, we're ready to exit. If we're quitting because of some fatal error //while running the server, make sure to let the parent process know by //exiting with a nonzero status. Otherwise, exit with a 0 status if (theServerState == qtssFatalErrorState || restartServer) ::exit (-2);//-2 signals parent process to restart server }