|
@@ -0,0 +1,491 @@
|
|
|
+#include <stdio.h>
|
|
|
+#include <fcntl.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <string.h>
|
|
|
+#include <poll.h>
|
|
|
+#include <signal.h>
|
|
|
+#include <errno.h>
|
|
|
+#include <limits.h>
|
|
|
+#include <sys/types.h>
|
|
|
+#include <sys/stat.h>
|
|
|
+#include <asm/types.h>
|
|
|
+#include <sys/socket.h>
|
|
|
+#include <net/if.h>
|
|
|
+#include "gfanetmon.h"
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+#define TRACE(...) printf(__VA_ARGS__), fflush(stdout)
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+#define _THREAD_CMD_WAIT_COND 0
|
|
|
+#define _THREAD_CMD_EXIT 1
|
|
|
+#define _THREAD_CMD_CONTINUE 2
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+static void _GetAttribs(struct rtattr *pIn, LPRT_ATTRIBUTE pOut, size_t nMaxOut, size_t nLen)
|
|
|
+{
|
|
|
+ memset(pOut, 0, sizeof(RT_ATTRIBUTE) * nMaxOut);
|
|
|
+
|
|
|
+ while(RTA_OK(pIn, nLen))
|
|
|
+ {
|
|
|
+ if((size_t)pIn->rta_type < nMaxOut)
|
|
|
+ {
|
|
|
+ pOut[pIn->rta_type].pat = pIn;
|
|
|
+ pOut[pIn->rta_type].pData = RTA_DATA(pIn);
|
|
|
+ }
|
|
|
+ pIn = RTA_NEXT(pIn, nLen);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+static int _BuildGetLinkMessage(struct nlmsghdr *pmh, unsigned short flags, unsigned int nSeq)
|
|
|
+{
|
|
|
+ pmh->nlmsg_type = RTM_GETLINK;
|
|
|
+ pmh->nlmsg_flags = NLM_F_REQUEST | flags;
|
|
|
+ pmh->nlmsg_seq = nSeq;
|
|
|
+ pmh->nlmsg_pid = getpid();
|
|
|
+
|
|
|
+ struct ifinfomsg *pim = (struct ifinfomsg*)NLMSG_DATA(pmh);
|
|
|
+ pim->ifi_family = AF_INET;
|
|
|
+ pim->ifi_change = 0xFFFFFFFF;
|
|
|
+
|
|
|
+ pmh->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
|
|
+ return pmh->nlmsg_len;
|
|
|
+}
|
|
|
+
|
|
|
+static int _BuildGetAddrMessage(struct nlmsghdr *pmh, unsigned short flags, unsigned int nSeq)
|
|
|
+{
|
|
|
+ pmh->nlmsg_type = RTM_GETADDR;
|
|
|
+ pmh->nlmsg_flags = NLM_F_REQUEST | flags;
|
|
|
+ pmh->nlmsg_seq = nSeq;
|
|
|
+ pmh->nlmsg_pid = getpid();
|
|
|
+
|
|
|
+ struct ifaddrmsg *pam = (struct ifaddrmsg*)NLMSG_DATA(pmh);
|
|
|
+ pam->ifa_family = AF_INET;
|
|
|
+
|
|
|
+ pmh->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
|
|
+ return pmh->nlmsg_len;
|
|
|
+}
|
|
|
+
|
|
|
+static int _BuildGetRoute(struct nlmsghdr *pmh, unsigned short flags, unsigned int nSeq)
|
|
|
+{
|
|
|
+ pmh->nlmsg_type = RTM_GETROUTE;
|
|
|
+ pmh->nlmsg_flags = NLM_F_REQUEST | flags;
|
|
|
+ pmh->nlmsg_seq = nSeq;
|
|
|
+ pmh->nlmsg_pid = getpid();
|
|
|
+
|
|
|
+ struct rtmsg *prm = (struct rtmsg*)NLMSG_DATA(pmh);
|
|
|
+ prm->rtm_family = AF_INET;
|
|
|
+ prm->rtm_flags = RTM_F_NOTIFY;
|
|
|
+
|
|
|
+ pmh->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
|
|
+ return pmh->nlmsg_len;
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+CGfaNetMon::CGfaNetMon(void) : m_fdNetlink(-1),
|
|
|
+ m_mtx(PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP),
|
|
|
+ m_tCond(PTHREAD_COND_INITIALIZER),
|
|
|
+ m_fdReadPipe(m_fdPipe[0]),
|
|
|
+ m_fdWritePipe(m_fdPipe[1]),
|
|
|
+ m_bThreadRunning(false),
|
|
|
+ m_bWaitingCond(false),
|
|
|
+ m_pfnCallback(NULL),
|
|
|
+ m_pUserParam(NULL)
|
|
|
+{
|
|
|
+ m_fdReadPipe = m_fdWritePipe = -1;
|
|
|
+}
|
|
|
+
|
|
|
+CGfaNetMon::~CGfaNetMon(void)
|
|
|
+{
|
|
|
+ Close();
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+bool CGfaNetMon::Init(void)
|
|
|
+{
|
|
|
+ struct sockaddr_nl sa;
|
|
|
+ memset(&sa, 0, sizeof(sa));
|
|
|
+ sa.nl_family = AF_NETLINK;
|
|
|
+ sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
|
|
|
+
|
|
|
+ if(IsMonitorThreadContext())
|
|
|
+ return false;
|
|
|
+ else if(m_fdNetlink >= 0)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ if(m_fdReadPipe >= 0)
|
|
|
+ {
|
|
|
+ close(m_fdReadPipe);
|
|
|
+ m_fdReadPipe = -1;
|
|
|
+ }
|
|
|
+ if(m_fdWritePipe >= 0)
|
|
|
+ {
|
|
|
+ close(m_fdWritePipe);
|
|
|
+ m_fdWritePipe = -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if((m_fdNetlink = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) >= 0)
|
|
|
+ {
|
|
|
+ if(bind(m_fdNetlink, (struct sockaddr*)&sa, sizeof(sa)) >= 0)
|
|
|
+ {
|
|
|
+ if(::pipe(m_fdPipe) >= 0)
|
|
|
+ {
|
|
|
+ if(m_thread.Create(&CGfaNetMon::MonitorThreadRoutine, reinterpret_cast<void*>(this)) >= 0)
|
|
|
+ {
|
|
|
+ while(!m_bThreadRunning)
|
|
|
+ ::pthread_yield();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ close(m_fdReadPipe);
|
|
|
+ close(m_fdWritePipe);
|
|
|
+ close(m_fdNetlink);
|
|
|
+ m_fdReadPipe = m_fdWritePipe = m_fdNetlink = -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ close(m_fdNetlink);
|
|
|
+ m_fdNetlink = -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ close(m_fdNetlink);
|
|
|
+ m_fdNetlink = -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return (m_fdNetlink >= 0);
|
|
|
+}
|
|
|
+
|
|
|
+void CGfaNetMon::Close(void)
|
|
|
+{
|
|
|
+ SignalMonitorThread(_THREAD_CMD_EXIT);
|
|
|
+ LockMutex();
|
|
|
+ if(m_fdNetlink >= 0)
|
|
|
+ {
|
|
|
+ close(m_fdNetlink);
|
|
|
+ m_fdNetlink = -1;
|
|
|
+ }
|
|
|
+ if(m_fdReadPipe >= 0)
|
|
|
+ {
|
|
|
+ close(m_fdReadPipe);
|
|
|
+ m_fdReadPipe = -1;
|
|
|
+ }
|
|
|
+ if(m_fdWritePipe >= 0)
|
|
|
+ {
|
|
|
+ close(m_fdWritePipe);
|
|
|
+ m_fdWritePipe = -1;
|
|
|
+ }
|
|
|
+ UnlockMutex();
|
|
|
+
|
|
|
+ if(!IsMonitorThreadContext())
|
|
|
+ m_thread.Join(NULL);
|
|
|
+}
|
|
|
+
|
|
|
+bool CGfaNetMon::StartMonitor(PFN_NETMON_CALLBACK pfnCb, void *pParam)
|
|
|
+{
|
|
|
+ if(IsMonitorThreadContext())
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if(!pfnCb)
|
|
|
+ {
|
|
|
+ errno = EINVAL;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!SuspendMonitorThread()) // signal the monitor thread to enter the condition waiting state, while this thread gains ownership of the mutex
|
|
|
+ return false;
|
|
|
+ m_pfnCallback = pfnCb;
|
|
|
+ m_pUserParam = pParam;
|
|
|
+ ResumeMonitorThread(); // signal the monitor thread to leave the condition waiting state and to enter notification processing state
|
|
|
+ return RefreshMonitor();
|
|
|
+}
|
|
|
+
|
|
|
+bool CGfaNetMon::RefreshMonitor(void)
|
|
|
+{
|
|
|
+ if(IsMonitorThreadContext())
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+ int nRet;
|
|
|
+ static unsigned int nSeq = 0;
|
|
|
+ char szBuf[2048] __attribute__ ((aligned(__alignof__(struct nlmsghdr))));
|
|
|
+ memset(szBuf, 0, sizeof(szBuf));
|
|
|
+ size_t nMsgLen = 0;
|
|
|
+ struct nlmsghdr *pmh = (struct nlmsghdr*)szBuf;
|
|
|
+
|
|
|
+ struct sockaddr_nl sa;
|
|
|
+ memset(&sa, 0, sizeof(sa));
|
|
|
+ sa.nl_family = AF_NETLINK;
|
|
|
+
|
|
|
+ struct iovec iov;
|
|
|
+ memset(&iov, 0, sizeof(iov));
|
|
|
+ struct msghdr msg = {&sa, sizeof(sa), &iov, 1, NULL, 0, 0};
|
|
|
+
|
|
|
+ /////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+ nMsgLen = NLMSG_ALIGN(_BuildGetAddrMessage(pmh, NLM_F_ROOT, ++nSeq));
|
|
|
+ iov = {szBuf, nMsgLen};
|
|
|
+ if(!SuspendMonitorThread()) // signal the monitor thread to enter the condition waiting state, while this thread gains ownership of the mutex
|
|
|
+ return false;
|
|
|
+ nRet = sendmsg(m_fdNetlink, &msg, 0); // send request
|
|
|
+ ResumeMonitorThread(); // signal the monitor thread to leave the condition waiting state and to enter notification processing state
|
|
|
+
|
|
|
+ if(nRet <= 0)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // at this point the monitor thread has regained the ownership of the mutex and is processing notifications
|
|
|
+
|
|
|
+ nMsgLen = NLMSG_ALIGN(_BuildGetLinkMessage(pmh, NLM_F_ROOT, ++nSeq));
|
|
|
+ iov = {szBuf, nMsgLen};
|
|
|
+ if(!SuspendMonitorThread()) // signal the monitor thread to enter the condition waiting state, while this thread gains ownership of the mutex
|
|
|
+ return false;
|
|
|
+ nRet = sendmsg(m_fdNetlink, &msg, 0); // send next request
|
|
|
+ ResumeMonitorThread(); // signal the monitor thread to leave the condition waiting state and to enter notification processing state
|
|
|
+
|
|
|
+ // at this point the monitor thread has regained the ownership of the mutex and is processing notifications
|
|
|
+
|
|
|
+ nMsgLen = NLMSG_ALIGN(_BuildGetRoute(pmh, NLM_F_ROOT, ++nSeq));
|
|
|
+ iov = {szBuf, nMsgLen};
|
|
|
+ if(!SuspendMonitorThread()) // signal the monitor thread to enter the condition waiting state, while this thread gains ownership of the mutex
|
|
|
+ return false;
|
|
|
+ nRet = sendmsg(m_fdNetlink, &msg, 0); // send next request
|
|
|
+ ResumeMonitorThread(); // signal the monitor thread to leave the condition waiting state and to enter notification processing state
|
|
|
+
|
|
|
+ // at this point the monitor thread has regained the ownership of the mutex and is processing notifications
|
|
|
+
|
|
|
+ return nRet > 0;
|
|
|
+}
|
|
|
+
|
|
|
+bool CGfaNetMon::StopMonitor(void)
|
|
|
+{
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+void CGfaNetMon::LockMutex(void)
|
|
|
+{
|
|
|
+ ::pthread_mutex_lock(&m_mtx);
|
|
|
+}
|
|
|
+
|
|
|
+void CGfaNetMon::UnlockMutex(void)
|
|
|
+{
|
|
|
+ ::pthread_mutex_unlock(&m_mtx);
|
|
|
+}
|
|
|
+
|
|
|
+void CGfaNetMon::WaitCondition(void)
|
|
|
+{
|
|
|
+ m_bWaitingCond = true;
|
|
|
+ ::pthread_cond_wait(&m_tCond, &m_mtx);
|
|
|
+ m_bWaitingCond = false;
|
|
|
+}
|
|
|
+
|
|
|
+bool CGfaNetMon::SuspendMonitorThread(void)
|
|
|
+{
|
|
|
+ if(IsMonitorThreadContext())
|
|
|
+ return true;
|
|
|
+ if(SignalMonitorThread(_THREAD_CMD_WAIT_COND))
|
|
|
+ {
|
|
|
+ LockMutex();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+void CGfaNetMon::ResumeMonitorThread(void)
|
|
|
+{
|
|
|
+ if(IsMonitorThreadContext())
|
|
|
+ return;
|
|
|
+ if(m_bWaitingCond)
|
|
|
+ {
|
|
|
+ ::pthread_cond_signal(&m_tCond);
|
|
|
+ UnlockMutex();
|
|
|
+ while(m_bWaitingCond)
|
|
|
+ ::pthread_yield();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool CGfaNetMon::SignalMonitorThread(int sig)
|
|
|
+{
|
|
|
+ return write(m_fdWritePipe, &sig, sizeof(sig)) == sizeof(sig);
|
|
|
+}
|
|
|
+
|
|
|
+bool CGfaNetMon::IsMonitorThreadContext(void)
|
|
|
+{
|
|
|
+ return m_thread.GetID() == ::pthread_self();
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+void* CGfaNetMon::MonitorThreadRoutine(void *pParam)
|
|
|
+{
|
|
|
+ CGfaNetMon *pThis = reinterpret_cast<CGfaNetMon*>(pParam);
|
|
|
+ int ret;
|
|
|
+ bool bRun = true;
|
|
|
+ char buf[8192] __attribute__ ((aligned(__alignof__(struct nlmsghdr))));
|
|
|
+ struct pollfd pfd[2];
|
|
|
+ memset(pfd, 0, sizeof(pfd));
|
|
|
+ pfd[0].events = POLLIN;
|
|
|
+ pfd[1].events = POLLIN;
|
|
|
+
|
|
|
+ pThis->LockMutex();
|
|
|
+ pThis->m_bThreadRunning = true;
|
|
|
+
|
|
|
+ do
|
|
|
+ {
|
|
|
+ if((pThis->m_fdNetlink >= 0) && (pThis->m_fdReadPipe >= 0))
|
|
|
+ {
|
|
|
+ pfd[0].fd = pThis->m_fdReadPipe;
|
|
|
+ pfd[1].fd = pThis->m_fdNetlink;
|
|
|
+
|
|
|
+ if((ret = poll(pfd, 2, -1)) > 0)
|
|
|
+ {
|
|
|
+ if(pfd[1].revents & POLLIN)
|
|
|
+ {
|
|
|
+ int len;
|
|
|
+ struct iovec iov = { buf, sizeof(buf) };
|
|
|
+ struct sockaddr_nl sa;
|
|
|
+ struct msghdr msg;
|
|
|
+ struct nlmsghdr *pmh;
|
|
|
+ msg = {&sa, sizeof(sa), &iov, 1, NULL, 0, 0};
|
|
|
+
|
|
|
+ if((len = recvmsg(pThis->m_fdNetlink, &msg, 0)) >= 0)
|
|
|
+ {
|
|
|
+ for (pmh = (struct nlmsghdr *) buf; NLMSG_OK(pmh, len); pmh = NLMSG_NEXT(pmh, len))
|
|
|
+ {
|
|
|
+ switch(pmh->nlmsg_type)
|
|
|
+ {
|
|
|
+ case NLMSG_DONE:
|
|
|
+ break;
|
|
|
+
|
|
|
+ case NLMSG_ERROR:
|
|
|
+ {
|
|
|
+ struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(pmh);
|
|
|
+ if(pThis->m_pfnCallback)
|
|
|
+ (*pThis->m_pfnCallback)(pmh->nlmsg_type, err, NULL, 0, pThis->m_pUserParam);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case RTM_NEWLINK:
|
|
|
+ {
|
|
|
+ RT_ATTRIBUTE atts[__IFLA_MAX];
|
|
|
+ struct ifinfomsg *ifm = (struct ifinfomsg*)NLMSG_DATA(pmh);
|
|
|
+ struct rtattr *rta = IFLA_RTA(ifm);
|
|
|
+ _GetAttribs(rta, atts, __IFLA_MAX, pmh->nlmsg_len - ((char*)rta - (char*)pmh));
|
|
|
+ if(pThis->m_pfnCallback)
|
|
|
+ (*pThis->m_pfnCallback)(pmh->nlmsg_type, ifm, atts, __IFLA_MAX, pThis->m_pUserParam);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case RTM_DELLINK:
|
|
|
+ {
|
|
|
+ RT_ATTRIBUTE atts[__IFLA_MAX];
|
|
|
+ struct ifinfomsg *ifm = (struct ifinfomsg*)NLMSG_DATA(pmh);
|
|
|
+ struct rtattr *rta = IFLA_RTA(ifm);
|
|
|
+ _GetAttribs(rta, atts, __IFLA_MAX, pmh->nlmsg_len - ((char*)rta - (char*)pmh));
|
|
|
+ if(pThis->m_pfnCallback)
|
|
|
+ (*pThis->m_pfnCallback)(pmh->nlmsg_type, ifm, atts, __IFLA_MAX, pThis->m_pUserParam);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case RTM_NEWADDR:
|
|
|
+ {
|
|
|
+ RT_ATTRIBUTE atts[__IFA_MAX];
|
|
|
+ struct ifaddrmsg *pam = (struct ifaddrmsg*)NLMSG_DATA(pmh);
|
|
|
+ struct rtattr *rtad = IFA_RTA(pam);
|
|
|
+ _GetAttribs(rtad, atts, __IFA_MAX, pmh->nlmsg_len - ((char*)rtad - (char*)pmh));
|
|
|
+ if(pThis->m_pfnCallback)
|
|
|
+ (*pThis->m_pfnCallback)(pmh->nlmsg_type, pam, atts, __IFA_MAX, pThis->m_pUserParam);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case RTM_DELADDR:
|
|
|
+ {
|
|
|
+ RT_ATTRIBUTE atts[__IFA_MAX];
|
|
|
+ struct ifaddrmsg *pam = (struct ifaddrmsg*)NLMSG_DATA(pmh);
|
|
|
+ struct rtattr *rtad = IFA_RTA(pam);
|
|
|
+ _GetAttribs(rtad, atts, __IFA_MAX, pmh->nlmsg_len - ((char*)rtad - (char*)pmh));
|
|
|
+ if(pThis->m_pfnCallback)
|
|
|
+ (*pThis->m_pfnCallback)(pmh->nlmsg_type, pam, atts, __IFA_MAX, pThis->m_pUserParam);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case RTM_NEWROUTE:
|
|
|
+ {
|
|
|
+ RT_ATTRIBUTE atts[__RTA_MAX];
|
|
|
+ struct rtmsg *prm = (struct rtmsg*)NLMSG_DATA(pmh);
|
|
|
+ struct rtattr *rta = RTM_RTA(prm);
|
|
|
+ _GetAttribs(rta, atts, __RTA_MAX, pmh->nlmsg_len - ((char*)rta - (char*)pmh));
|
|
|
+ if(pThis->m_pfnCallback)
|
|
|
+ (*pThis->m_pfnCallback)(pmh->nlmsg_type, prm, atts, __RTA_MAX, pThis->m_pUserParam);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case RTM_DELROUTE:
|
|
|
+ {
|
|
|
+ RT_ATTRIBUTE atts[__RTA_MAX];
|
|
|
+ struct rtmsg *prm = (struct rtmsg*)NLMSG_DATA(pmh);
|
|
|
+ struct rtattr *rta = RTM_RTA(prm);
|
|
|
+ _GetAttribs(rta, atts, __RTA_MAX, pmh->nlmsg_len - ((char*)rta - (char*)pmh));
|
|
|
+ if(pThis->m_pfnCallback)
|
|
|
+ (*pThis->m_pfnCallback)(pmh->nlmsg_type, prm, atts, __RTA_MAX, pThis->m_pUserParam);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ default:
|
|
|
+ TRACE("MSG Type: Unknown\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(pfd[0].revents & POLLIN)
|
|
|
+ {
|
|
|
+ int cmd;
|
|
|
+ if((ret = read(pThis->m_fdReadPipe, &cmd, sizeof(cmd))) == sizeof(cmd))
|
|
|
+ {
|
|
|
+ switch(cmd)
|
|
|
+ {
|
|
|
+ case _THREAD_CMD_WAIT_COND:
|
|
|
+ pThis->WaitCondition();
|
|
|
+ break;
|
|
|
+ case _THREAD_CMD_CONTINUE:
|
|
|
+ break;
|
|
|
+ case _THREAD_CMD_EXIT:
|
|
|
+ bRun = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ bRun = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ bRun = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ while(bRun);
|
|
|
+
|
|
|
+ pThis->m_bThreadRunning = false;
|
|
|
+ pThis->UnlockMutex();
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|