一:main函数的解析
1:初始化:配置文件模块初始化和守护程序(CStartMotor类)的初始化
dts_uint32 uiRet = CStartMotor::GetStartMotor().Init( argc,argv );
if ( uiRet == -1 )
{
return -1;
}
g_iCUPNum = sysconf( _SC_NPROCESSORS_ONLN );
//如果是daemon模式,本进程变为守护进程
uiRet = CStartMotor::GetStartMotor().DeamonStart();
if ( uiRet == -1 )
{
return -1;
}
uiRet = CStartMotor::GetStartMotor().WatchDog();
if ( uiRet == -1 )
{
return -1;
}
//设置捕获、屏蔽和不屏蔽的信号
uiRet = CStartMotor::GetStartMotor().SetSigaction();
if ( uiRet == -1 )
{
return -1;
}
//屏蔽所有关心的信号,让内核暂时保留信号,不要发给程序,因为这时候程序不系统被打断。
uiRet = CStartMotor::GetStartMotor().Block_Specified_Signals();
if ( uiRet == -1 )
{
return -1;
}
CConfigFileIni stConfigFileIni;
//读取配置文件
if ( os_read_file( &stConfigFileIni ) == -1 )
{
return -1;
}
//初始化程序基础
if ( os_init_cycle( &stConfigFileIni ) == -1 )
{
return -1;
}
2:
父子进程的通信套接口(管道)初始化
//创建进程间通信的互通套接口通道 zhb
if ( CStartMotor::GetStartMotor().SetSigPipe() == -1 )
{
GAL_ERROR << "set sig pipe fail";
GAL_ERROR_PRINT << "set sig pipe fail";
return -1;
}
epoll_event event;
event.data.fd = CStartMotor::GetStartMotor().m_iSigFd[ 0 ];//父进程的接收套接口;
event.events = EPOLLIN | EPOLLET;
epoll_ctl( iEpollfd, EPOLL_CTL_ADD, event.data.fd, &event );
GAL_INFO_PRINT << "m_iSigFd[ 0 ]==" << CStartMotor::GetStartMotor().m_iSigFd[ 0 ] << "; m_iSigFd[1]==" << CStartMotor::GetStartMotor().m_iSigFd[ 1 ];
3: main函数的主体循环
3.1: fork出了所有的worker子进程,并初始化。
//这是个重要的函数,fork出了所有的工作进程(子进程); zhb
if ( g_Monitor::Instance().Init( &stConfigFileIni, iEpollfd ) == -1 )
{
break;
}
3.2: 处理来自子进程消息和外部信号的主体循环
for ( ;; )
{
//通过epoll来接收子进程发送来的消息。zhb
iEvCnt = epoll_wait( iEpollfd, events, 2048, iWaitTimeMs );
//CDTS_Auxiliary::DTS_unblockterm_sig();
if ( iEvCnt < 0 )
{
if ( CDTS_Auxiliary::GetSockErr() != EINTR )
{
GAL_ERROR_PRINT << "sig epoll_wait error : %m";
usleep( 1000 );
}
GAL_DEBUG_PRINT << "sig epoll_wait trigger";
continue;
}
if ( iEvCnt == 0 )
{
continue;
}
//fprintf( stderr,"monitor epoll_wait %d\n",iEvCnt );
for ( int i = 0; i < iEvCnt; ++i )
{
iLiveFd = events[ i ].data.fd;
if ( iLiveFd == CStartMotor::GetStartMotor().m_iSigFd[ 0 ] )
{
if ( events[ i ].events & EPOLLIN )
{
iRet = read( CStartMotor::GetStartMotor().m_iSigFd[ 0 ],iSignals,sizeof(iSignals) );
if ( iRet <= 0 )
{
continue;
}
else
{
char* action;
GAL_DEBUG_PRINT << "parent sig fd read size = " << iRet/sizeof(int);
GAL_DEBUG << "parent sig fd read size = " << iRet/sizeof(int);
for ( int i = 0 ; i < iRet/sizeof(int); ++i )
{
action = NULL;
GAL_DEBUG_PRINT << "Signals [ " << i << " ] = " << iSignals[ i ];
GAL_DEBUG << "Signals [ " << i << " ] = " << iSignals[ i ];
switch ( iSignals[ i ] )
{
case SIGQUIT:
CStartMotor::GetStartMotor().m_iRun = 0;
action = "shutting down";
break;
case SIGTERM:
case SIGINT:
CStartMotor::GetStartMotor().m_iTerminate = 1;
action = "exiting";
break;
case SIGHUP:
CStartMotor::GetStartMotor().m_iReconfigure = 1;
action = "reconfiguring";
break;
case SIGUSR1:
CStartMotor::GetStartMotor().m_iReopen = 1;
action = "reopening";
break;
case SIGALRM:
CStartMotor::GetStartMotor().m_iSigalrm = 1;
break;
case SIGIO:
CStartMotor::GetStartMotor().m_iSigio = 1;
break;
case SIGCHLD:
CStartMotor::GetStartMotor().m_iReap = 1;
if ( g_Monitor::Instance().m_iWorkProcessSum > 0 )
{
action = "chile process close";
g_Monitor::Instance().GetWorkStatus();
}
break;
default:
break;
}
GAL_INFO << "parent signal " << iSignals[ i ] << " received " << action;
GAL_INFO_PRINT << "parent signal " << iSignals[ i ] << " received " << action;
}
}
}
}
else
{
//接收子进程传过来的信令
g_Monitor::Instance().Notify( iLiveFd );
}
}
}
二: 子进程(worker)进程解析
1: 子进程的创建和初始化
CMonitor 类是子进程(worker)进程的的处理类
//子进程的创建 zhb
for ( int i = 0; i < m_iWorkProcessSum; ++i )
{
Spawn_Process( i,pstConfigFileIni );
}
2:工作进程的解析
2.1: Spawn_Process函数,fork子进程(worker进程前的初始化)前的初始化。
pid_t tPid = fork();
switch ( tPid )
{
case -1:
{
GAL_ERROR_PRINT << "fork() failed";
GAL_ERROR << "fork() failed";
CDTS_Auxiliary::DTS_socket_close( m_stProcess[ iSpawn ].iChannelFd[ 0 ] );
m_stProcess[ iSpawn ].iChannelFd[ 0 ] = -1;
CDTS_Auxiliary::DTS_socket_close( m_stProcess[ iSpawn ].iChannelFd[ 1 ] );
m_stProcess[ iSpawn ].iChannelFd[ 1 ] = -1;
}
return -1;
case 0:
{
//子进程
m_iPid = getpid();
os_worker_process_cycle( iSpawn,pstConfigFileIni );
//worker_process_cycle( m_stProcess[ iSpawn ].iChannelFd[ 1 ] );
}
break;
default:
break;
}
2.2: worker进程的初始化函数
//worker进程的初始化,也是很关键的哦;zhb
if ( g_Worker::Instance().Init( iSpawn, g_Monitor::Instance().m_stProcess[ iSpawn ].iChannelFd[ 1 ],pstConfigFileIni,iEpollfd ) == -1 )
{
GAL_ERROR_PRINT << "work process " << iSpawn << " init error";
GAL_ERROR << "work process " << iSpawn << " init error";
exit( 2 );
}
这是个关键函数,调用了CDockMgr类中的初始化函数, CDockMgr类统一处理各种类型(epr,ts,rtp,tsOverHttp)的码流创建和删除。
if ( g_DockMgr::Instance().Init( pstConfigFileIni ) == -1 )
{
GAL_ERROR << "work process " << m_iSlot << " dockmgr init fail";
GAL_ERROR_PRINT << "work process " << m_iSlot << " dockmgr init fail";
return -1;
}
重要的函数,对各种码流的接收机制进行初始化。libev实例化(也就创建了处理线程,libev初始化,设置好了回调函数)。 下面以epr为例子,看看回调函数怎么设置的。
dts_uint32 CDockMgr::Init( CConfigFileIni* pstConfigFileIni )
{
GAL_DEBUG_PRINT << " CDockMgr::Init...000!";
char szEprConfig[ 1024 ] = { 0 };
if ( pstConfigFileIni->GetParaValue( g_szEPRSeq, g_szEPRConfigPara, szEprConfig," " ) == -1 )
{
GAL_ERROR << "read [ " << g_szEPRSeq << " ] " << g_szEPRConfigPara << " fail";
GAL_ERROR_PRINT << "read [ " << g_szEPRSeq << " ] " << g_szEPRConfigPara << " fail";
return -1;
}
if ( g_EPRMgr::Instance().Init( szEprConfig ) == -1 )
{
GAL_ERROR << "create EPR fail";
GAL_ERROR_PRINT << "create EPR fail";
return -1;
}
char szRtprConfig[ 1024 ] = { 0 };
if ( pstConfigFileIni->GetParaValue( g_szRTPRSeq,g_szRTPRConfigPara,szRtprConfig," " ) == -1 )
{
GAL_ERROR << "read [ " << g_szRTPRSeq << " ] " << g_szRTPRConfigPara << " fail";
GAL_ERROR_PRINT << "read [ " << g_szRTPRSeq << " ] " << g_szRTPRConfigPara << " fail";
return -1;
}
GAL_DEBUG_PRINT << " CDockMgr::Init...111!szRtprConfig==" << szRtprConfig;
if ( g_RtprMgr::Instance().Init( szRtprConfig ) == -1 )
{
GAL_ERROR << "create RTPR fail";
GAL_ERROR_PRINT << "create RTPR fail";
return -1;
}
char szTSRConfig[ 1024 ] = { 0 };
if ( pstConfigFileIni->GetParaValue( g_szTSRSeq,g_szTSRConfigPara,szTSRConfig," " ) == -1 )
{
GAL_ERROR << "read [ " << g_szTSRSeq << " ] " << g_szTSRConfigPara << " fail";
GAL_ERROR_PRINT << "read [ " << g_szTSRSeq << " ] " << g_szTSRConfigPara << " fail";
return -1;
}
GAL_DEBUG_PRINT << " CDockMgr::Init...222!szTSRConfig==" << szTSRConfig;
if ( g_TSRMgr::Instance().Init( szTSRConfig ) == -1 )
{
GAL_ERROR << "create TSR fail";
GAL_ERROR_PRINT << "create TSR fail";
return -1;
}
char szTOHRConfig[ 1024 ] = { 0 };
if ( pstConfigFileIni->GetParaValue( g_szTSOVERHTTPRSeq,g_szTSOVERHTTPRConfigPara,szTOHRConfig," " ) == -1 )
{
GAL_ERROR << "read [ " << g_szTSOVERHTTPRSeq << " ] " << g_szTSOVERHTTPRConfigPara << " fail";
GAL_ERROR_PRINT << "read [ " << g_szTSOVERHTTPRSeq << " ] " << g_szTSOVERHTTPRConfigPara << " fail";
return -1;
}
GAL_DEBUG_PRINT << " CDockMgr::Init...333!szTOHRConfig==" << szTOHRConfig;
if ( g_TOHRMgr::Instance().Init( szTOHRConfig ) == -1 )
{
GAL_ERROR << "create TOHR fail";
GAL_ERROR_PRINT << "create TOHR fail";
return -1;
}
char szTPushConfig[ 1024 ] = { 0 };
if ( pstConfigFileIni->GetParaValue( g_szTPushSeq,g_szTPushConfigPara,szTPushConfig," " ) == -1 )
{
GAL_ERROR << "read [ " << g_szTPushSeq << " ] " << g_szTPushConfigPara << " fail";
GAL_ERROR_PRINT << "read [ " << g_szTPushSeq << " ] " << g_szTPushConfigPara << " fail";
return -1;
}
GAL_DEBUG_PRINT << " CDockMgr::Init...444!szTPushConfig==" << szTPushConfig;
if ( g_InternalTransferMgr::Instance().Init( szTPushConfig ) == -1 )
{
GAL_ERROR << "create TPush fail";
GAL_ERROR_PRINT << "create TPush fail";
return -1;
}
return 0;
}
libev初始化了,设置好回调函数,处理线程池也在这里创建好了。下面是libev的处理过程。
dts_uint32 CEPR_ReceiveMgr::Init( const char* pszConfig, const EPR_INFO_CALLBACK& f )
{
GAL_DEBUG_PRINT << "EPR Receive init";
GAL_DEBUG << "EPR Receive init";
m_strConfig = pszConfig;
m_EPR_INFO_CALLBACK = f;//设置好了 函数指针m_EPR_INFO_CALLBACK 的具体地址(回调函数)
CConfigFileIni stConfigFileIni;
if ( stConfigFileIni.OpenFile( pszConfig ) == -1 )
{
GAL_ERROR << "RTPR read config file fail " << pszConfig;
GAL_ERROR_PRINT << "RTPR read config file fail " << pszConfig;
return -1;
}
int iIdleTime = 0;
stConfigFileIni.GetParaValue( g_ListenerSeq,g_IdleTimePara,iIdleTime,30 );
iIdleTime *= 1000;
int iThread = 0;
if ( stConfigFileIni.GetParaValue( g_IOThreadSeq,g_ThreadNumPara,iThread,0 ) == -1 )
{
CDTS_Auxiliary::GetCPUNum(iThread);
if ( iThread == 0 )
{
iThread = 32;
}
}
GAL_DEBUG_PRINT << "EPR create incoming " << iThread << " thread , IdleTime = " << iIdleTime;
//创建了libev的处理线程,也设置好了回调函数 CEPR_ReceiveMgr::ClearReceiver,这个处理函数是空函数。zhb
if ( m_stIncomingThread.Init( iThread, GFD::bind( &CEPR_ReceiveMgr::ClearReceiver, this ),iIdleTime ) == -1 )
{
GAL_ERROR << "EPR create incoming " << iThread << " thread error";
GAL_ERROR_PRINT << "EPR create incoming " << iThread << " thread error";
return -1;
}
GAL_DEBUG_PRINT << "EPR Receive init success";
GAL_DEBUG << "EPR Receive init success";
return 0;
}
libev创建好的线程,进入处理线程循环。
void* PollThreadEntry( void* pThread )
{
CBasicThread* pBasicThread = static_cast< CBasicThread* >( pThread );
if ( pBasicThread == NULL )
{
return (void*)-1;
}
return (void*)( pBasicThread->ThreadLoop() );
}
dts_uint32 CPollThread::ThreadLoop()
{
GAL_DEBUG_PRINT << "Notify...777 ! ";
int iCnt = m_stEventCnt.GetAndAdd( 1 );
if ( iCnt >= CBasicThread::GetThreadNum() )
{
GAL_ERROR_PRINT << "poll thread create event loop";
//GAL_ERROR << "poll thread create event loop";
return -1;
}
//GAL_DEBUG_PRINT << "poll thread pid[ " << getpid() << " ] tid = " << (int)(gettid()) << " running ...";
while ( m_iState == DTS_THREAD_STATE_RUN )
{
//主要处理是在EpollWait函数。zhb
if ( m_vecEventLoop[ iCnt ]->EpollWait( m_iEpollWaitTimeMs ) == 0 )
{
if ( m_iState != DTS_THREAD_STATE_RUN )
{
break;
}
//这个回调函数设置为了空函数。zhb
m_fThreadLoop_Callback();
}
}
return 0;
}
dts_uint32 CEventLoop::EpollWait( int iWaitTimeMs )
{
GAL_DEBUG_PRINT << "Notify...888 ! ";
int iEvCnt = epoll_wait( m_iEpollFd, &(*m_stEvents.begin()), static_cast< int >( m_stEvents.size() ), iWaitTimeMs );
if ( iEvCnt < 0 )
{
if ( CDTS_Auxiliary::GetSockErr() != EINTR )
{
GAL_ERROR_PRINT << "epoll_wait error : %m";
usleep( 1000 );
}
return -1;
}
if ( iEvCnt == 0 )
{
GAL_DEBUG_PRINT << "epoll_wait timeput";
GAL_DEBUG_PRINT << "Notify...888...111 ! ";
}
CBasicSocket* pstSocket = NULL;
dts_uint32 uiRet;
for ( int i = 0; i < iEvCnt; ++i )
{
pstSocket = static_cast< CBasicSocket* >( m_stEvents[ i ].data.ptr );
if ( m_stEvents[ i ].events & ( EPOLLHUP | EPOLLERR ) )
{
GAL_ERROR_PRINT << "epoll_wait events[ " << m_stEvents[ i ].events << " ] EPOLLHUP | EPOLLERR fd = " << pstSocket->GetFd() << " error = " << errno;
if ( pstSocket->Release() == 0 )
{
delete pstSocket;
}
continue;
}
else
{
GAL_DEBUG_PRINT << "Notify...999! ";
//主要在这里处理呢 zhb
uiRet = pstSocket->Notify( &m_stEvents[ i ] );
if ( uiRet == -1 )
{
GAL_ERROR_PRINT << "epoll_wait events Notify -1";
if ( pstSocket->Release() == 0 )
{
delete pstSocket;
}
continue;
}
}
}
if ( iWaitTimeMs != -1 )
{
time_t tTimeNow = time( NULL );
//GAL_DEBUG_PRINT << "time check " << tTimeNow << " - " << m_tLastCheckIdle << " = "<< tTimeNow - m_tLastCheckIdle << " ? " << (iWaitTimeMs >> 1);
if ( ( tTimeNow - m_tLastCheckIdle ) > ( iWaitTimeMs / 2000 ) )
{
//GAL_DEBUG_PRINT << "time check " << tTimeNow << " - " << m_tLastCheckIdle << " = "<< tTimeNow - m_tLastCheckIdle << " > " << (iWaitTimeMs / 2000 );
m_tLastCheckIdle = tTimeNow;
COSQueueNode< CBasicSocket* >* pstCur;
COSQueueNode< CBasicSocket* >* pstNext;
OSQUEUE_FOR_EACH_SAFE( pstCur,pstNext,&m_stBusyPollerHead )
{
//GAL_DEBUG_PRINT << tTimeNow << " - " << pstCur->m_stContent->GetDealTime() << " = " << tTimeNow - pstCur->m_stContent->GetDealTime();
if ( pstCur->m_stContent != NULL &&
(tTimeNow - pstCur->m_stContent->GetDealTime()) > (iWaitTimeMs / 1000) )
{
GAL_ERROR << "client timeout " << tTimeNow << " - " << pstCur->m_stContent->GetDealTime() << " = " << tTimeNow - pstCur->m_stContent->GetDealTime() << " > " << (iWaitTimeMs/1000);
GAL_ERROR_PRINT << "client timeout " << tTimeNow << " - " << pstCur->m_stContent->GetDealTime() << " = " << tTimeNow - pstCur->m_stContent->GetDealTime() << " > " << (iWaitTimeMs/1000);
if ( pstCur->m_stContent->Release() == 0 )
{
delete pstCur->m_stContent;
}
}
}
}
}
return 0;
}
//EPR的就到这里来处理了。 zhb
dts_uint32 CEPR_Receive::Notify( epoll_event* pstEv )
{
if ( pstEv->events & ( EPOLLERR | EPOLLHUP ) )
{
GAL_ERROR << "EPR receiver epoll error events = " << pstEv->events;
GAL_ERROR_PRINT << "ts receiver epoll error events = " << pstEv->events;
return -1;
}
if ( !(pstEv->events & EPOLLIN) )
{
GAL_ERROR << "EPR receiver epoll unexpect events = " << pstEv->events;
GAL_ERROR_PRINT << "ts receiver epoll unexpect events = " << pstEv->events;
return -2;
}
if ( GetEprClientNum() >= m_iMaxSession )
{
GAL_INFO << "EPR accept client >= " << m_iMaxSession;
GAL_INFO_PRINT << "EPR accept client >= " << m_iMaxSession;
return 0;
}
//GAL_DEBUG_PRINT << "epoll events = EPOLLIN";
struct sockaddr_in stPeerAddr;
socklen_t tPeerSize = sizeof( stPeerAddr );
DTSSocket iNewSocket = DTS_SOCKET_NULL;
CEPR_Client* pstEprClient;
DTSSockInfo stSockInfo;
stSockInfo.iType = GetSocketInfo()->iType;
stSockInfo.stLocal = GetSocketInfo()->stLocal;
for ( int i = 0; ( m_stDTSListenAttr.iAcceptNum == -1 || i < m_stDTSListenAttr.iAcceptNum ); ++i )
{
switch ( m_stDTSListenAttr.iType )
{
case DTS_SOCKET_TYPE_STREAM:
{
tPeerSize = sizeof( stPeerAddr );
iNewSocket = accept( GetFd(),(struct sockaddr*)&stPeerAddr,&tPeerSize );
if ( iNewSocket < 0 )
{
if ( CDTS_Auxiliary::GetSockErr() != EAGAIN && CDTS_Auxiliary::GetSockErr() != EINTR )
{
}
return 0;
}
//这是处理一个客户端; zhb
pstEprClient = new CEPR_Client( m_pCode );
if ( pstEprClient == NULL )
{
return 0;
}
stSockInfo.iSocket = iNewSocket;
stSockInfo.stRemote.uiHost = stPeerAddr.sin_addr.s_addr;
stSockInfo.stRemote.usPort = stPeerAddr.sin_port;
GAL_DEBUG_PRINT << "EPR accept client PeerAddress = " << inet_ntoa( stPeerAddr.sin_addr ) << " : " << ntohs( stPeerAddr.sin_port );
GAL_DEBUG << "EPR accept client PeerAddress = " << inet_ntoa( stPeerAddr.sin_addr ) << " : " << ntohs( stPeerAddr.sin_port );
pstEprClient->SetSocketInfo( &stSockInfo );
pstEprClient->SetCallbackFunc();
pstEprClient->SetTriggerCallback( GFD::bind( &CEPR_Receive::Trigger,this,1,2 ),&m_EPR_INFO_CALLBACK );
pstEprClient->SetRole( ROLE_CLIENT );
if ( m_stDTSListenAttr.uiRecvBufSize > 0 )
{
CDTS_Auxiliary::DTS_socket_set_option( iNewSocket,DTS_SOCKOPT_RCVBUF,m_stDTSListenAttr.uiRecvBufSize );
}
if ( m_stDTSListenAttr.uiSendBufSize > 0 )
{
CDTS_Auxiliary::DTS_socket_set_option( iNewSocket,DTS_SOCKOPT_SNDBUF,m_stDTSListenAttr.uiSendBufSize );
}
if ( pstEprClient->SetMaxRecvLen( m_stDTSListenAttr.uiRecvBufSize ) == -1 )
{
pstEprClient->Release();
delete pstEprClient;
return 0;
}
//通过Attach函数,把回调evloop注册到了CEPR_Client类中去接收码流了。 zhb
if ( pstEprClient->Attach( m_pstPollThread->GetNextLoop(),EPOLLIN | EPOLLET ) == -1 )
{
pstEprClient->Release();
delete pstEprClient;
return 0;
}
}
break;
case DTS_SOCKET_TYPE_DATAGRAM:
break;
default:
break;
}
}
return 0;
}
上面这些代码,基本上梳理了libev的处理过程(以epr的码流接收为例子)。
主要要做的工作其实就是设置好回到函数。
这里重新定义了Notify函数。
dts_uint32 CEPR_Receive::Notify( epoll_event* pstEv )
来实现libev基本的处理函数。
这里其实就用到来一个CPollThread m_stPollThread;
这是一个线程池(个数对应CPU的个数)。