#include #include "qappctrl.h" #include "../../src/defines.h" ///////////////////////////////////////////////////////////////////////////// #define _INVALID_SLOT_INDEX -1 #define _APP_CTRL_MAX_SLOTS ((int)(sizeof(appid_t) * 8)) #define _APP_INDEX_FROM_APP_ID(aid) (ffsll(aid) - 1) #define _IS_POWER_OF_2(x) (!!(x) && !((x) & ((x) - 1))) #define _IS_VALID_APP_ID(i) _IS_POWER_OF_2(i) #define _TIMESPEC_2_US(ts) (((clock64_t)(ts).tv_sec) * 1000000LL + ((clock64_t)(ts).tv_nsec) / 1000LL) #define _TIMESPEC_DIFF_US(ts1, ts2) (_TIMESPEC_2_US(ts1) - _TIMESPEC_2_US(ts2)) #define _MIN_TIMER_INT 20 ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// QGfaAppCtrl::QGfaAppCtrl(QObject *pParent) : QObject(pParent), m_bSysInfoRunning(false), m_hAC(NULL), m_nAppID(0), m_nTimerID(0), m_sysInfo(this), m_curPass(0), m_minPass(LLONG_MAX), m_maxPass(LLONG_MIN), m_avgPass(0), m_nEvtSrcs(0), m_nHeavyLoadUpdateIntervalUs(2500000) { for(int i = 0; i < _APP_CTRL_MAX_SLOTS; ++i) { QGfaAppInfo *pai = new QGfaAppInfo(i, this); connect(pai, SIGNAL(sendControlMessage(appid_t, ctrlmsg_t)), SLOT(onSendControlMessage(appid_t, ctrlmsg_t))); m_appInfo.append(pai); } memset(&m_tsLastHeavyLoadUpdate, 0, sizeof(m_tsLastHeavyLoadUpdate)); setObjectName("QGfaAppCtrl"); } QGfaAppCtrl::~QGfaAppCtrl(void) { Release(); for(int i = 0; i < _APP_CTRL_MAX_SLOTS; ++i) { QGfaAppInfo *pai = m_appInfo.at(i); delete pai; } } ///////////////////////////////////////////////////////////////////////////// bool QGfaAppCtrl::Create(appid_t nAppID, const char *pszDisplayName, int nTimerIntMs, clock64_t nHeavyLoadUpdateIntervalMs) { if(!m_hAC) { if(nTimerIntMs < _MIN_TIMER_INT) nTimerIntMs = _MIN_TIMER_INT; if(nHeavyLoadUpdateIntervalMs < (nTimerIntMs * 50)) nHeavyLoadUpdateIntervalMs = (nTimerIntMs * 50); if((m_hAC = ::GfaIpcAppCtrlAcquire(nAppID, pszDisplayName, 0, (clock64_t)(nTimerIntMs * 1000 * 2)))) { m_nAppID = nAppID; m_nHeavyLoadUpdateIntervalUs = nHeavyLoadUpdateIntervalMs * 1000; ::GfaIpcAppCtrlSubscribeSysEvents(m_hAC, GFA_APPCTRL_SYSEVENT_ALL_STG_DEV); m_nTimerID = startTimer(nTimerIntMs, Qt::CoarseTimer); } } return !!m_hAC; } ///////////////////////////////////////////////////////////////////////////// void QGfaAppCtrl::Release(void) { if(m_hAC) { killTimer(m_nTimerID); ::GfaIpcAppCtrlRelease(m_hAC); m_hAC = NULL; } } ///////////////////////////////////////////////////////////////////////////// void QGfaAppCtrl::RegisterQmlTypes(QQmlEngine &rEng, int nVerMajor, int nVerMinor) { qmlRegisterUncreatableType("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QGfaStgDevList", QStringLiteral("class not creatable in QML")); qmlRegisterUncreatableType("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QGfaSysInfo", QStringLiteral("class not creatable in QML")); qmlRegisterUncreatableType("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QGfaAppInfo", QStringLiteral("class not creatable in QML")); qmlRegisterUncreatableType("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QGfaAppCtrl", QStringLiteral("class not creatable in QML")); rEng.rootContext()->setContextProperty(QStringLiteral("qGfaAppCtrl"), this); } ///////////////////////////////////////////////////////////////////////////// bool QGfaAppCtrl::PresetDisplayName(appid_t nAppID, const char *pszName) { if(m_hAC) return ::GfaIpcAppCtrlPresetDisplayName(m_hAC, nAppID, pszName); return false; } ///////////////////////////////////////////////////////////////////////////// bool QGfaAppCtrl::SubscribeStateEvents(appid_t nAppMask) { if(m_hAC) { nAppMask &= ~m_nAppID; m_nEvtSrcs |= nAppMask; return ::GfaIpcAppCtrlSubscribeStateEvents(m_hAC, nAppMask); } return false; } ///////////////////////////////////////////////////////////////////////////// void QGfaAppCtrl::timerEvent(QTimerEvent *event) { if((event->timerId() == m_nTimerID) && m_hAC) { static clock64_t nCurPass = 0; struct timespec tsEnterUpdate, tsLeaveUpdate; ::clock_gettime(CLOCK_MONOTONIC, &tsEnterUpdate); GFA_APPCTRL_SYSMEM sm; HAPPINFO hAI; bool bDoHeavyLoadUpdate = (_TIMESPEC_DIFF_US(tsEnterUpdate, m_tsLastHeavyLoadUpdate) >= m_nHeavyLoadUpdateIntervalUs); if((hAI = ::GfaIpcAppCtrlInfoUpdate(m_hAC, nCurPass))) { int b; appid_t app, nAppIdSrc; sysevt_t nSysEvt; GFA_APPCTRL_APPTIMES at; GFA_APPCTRL_APPMEM am; GFA_SYSINFO_DISK disk; GFA_SYSINFO_PARTITION part; char szDispName[128]; while((nAppIdSrc = ::GfaIpcAppCtrlGetNextStateEvtSrc(hAI))) { GfaIpcAppStates state = ::GfaIpcAppCtrlGetState(m_hAC, nAppIdSrc); int nIndex = appIndexFromAppID(nAppIdSrc); QGfaAppInfo &ai = *m_appInfo[nIndex]; bool bStateChanged = ai.setState(state); if(bStateChanged) { if(state == GIAS_Running) memset(&m_tsLastHeavyLoadUpdate, 0, sizeof(m_tsLastHeavyLoadUpdate)); else if(state != GIAS_Paused) { ai.setAppTimes(NULL, state); ai.setAppMemInfo(NULL, state); } if(nAppIdSrc == GFA_APPCTRL_APPID_SYSINFO) { m_bSysInfoRunning = (state == GIAS_Running); m_sysInfo.setSysInfoRunning(m_bSysInfoRunning); } } if((state >= GIAS_StateNotRunning) && (state <= GIAS_Paused)) { if(::GfaIpcAppCtrlGetDisplayName(m_hAC, nAppIdSrc, szDispName, sizeof(szDispName))) { ai.setName(szDispName); } } } if(m_bSysInfoRunning) { while((nSysEvt = ::GfaIpcAppCtrlGetNextSysEvt(hAI))) { int nIndex; switch(nSysEvt) { case GFA_APPCTRL_SYSEVENT_DISK_EVT: while((nIndex = ::GfaIpcAppCtrlGetNextDiskRemoved(m_hAC, &disk)) >= 0) { m_sysInfo.diskRemoved(nIndex, disk); } while((nIndex = ::GfaIpcAppCtrlGetNextDiskAdded(m_hAC, &disk)) >= 0) { m_sysInfo.diskAdded(nIndex, disk); } break; case GFA_APPCTRL_SYSEVENT_PART_EVT: while((nIndex = ::GfaIpcAppCtrlGetNextPartitionRemoved(m_hAC, &part)) >= 0) { m_sysInfo.partitionRemoved(nIndex, part); } while((nIndex = ::GfaIpcAppCtrlGetNextPartitionAdded(m_hAC, &part)) >= 0) { m_sysInfo.partitionAdded(nIndex, part); } break; case GFA_APPCTRL_SYSEVENT_MOUNT_EVT: while((nIndex = ::GfaIpcAppCtrlGetNextMountRemoved(m_hAC, &part)) >= 0) { m_sysInfo.mountRemoved(nIndex, part); } while((nIndex = ::GfaIpcAppCtrlGetNextMountAdded(m_hAC, &part)) >= 0) { m_sysInfo.mountAdded(nIndex, part); } break; } } } nAppIdSrc = m_nEvtSrcs; bool bDontSaveLast = false; while(nAppIdSrc) { b = ffsll(nAppIdSrc) - 1; app = ((appid_t)0x1 << b); nAppIdSrc &= ~app; QGfaAppInfo &ai = *m_appInfo[b]; GfaIpcAppStates state = ::GfaIpcAppCtrlGetState(m_hAC, app); if(::GfaIpcAppCtrlGetAppMem(m_hAC, app, &am)) { ai.setAppMemInfo(&am, state, bDoHeavyLoadUpdate); } if(::GfaIpcAppCtrlGetAppTimes(m_hAC, app, &at) >= 0) { if(!at.nCycleLastUs) { bDontSaveLast = true; continue; } ai.setAppTimes(&at, state, bDoHeavyLoadUpdate); } size_t nSize = ::GfaIpcAppCtrlGetAppSize(m_hAC, app); ai.setAppSize((quint32)nSize, state); } if(bDoHeavyLoadUpdate && !bDontSaveLast) m_tsLastHeavyLoadUpdate = tsEnterUpdate; } if(::GfaIpcAppCtrlGetSysMem(m_hAC, &sm)) { m_sysInfo.setSysMemInfo(&sm, bDoHeavyLoadUpdate); } ::clock_gettime(CLOCK_MONOTONIC, &tsLeaveUpdate); m_curPass = nCurPass = _TIMESPEC_DIFF_US(tsLeaveUpdate, tsEnterUpdate); if(m_minPass > m_curPass) { m_minPass = m_curPass; emit minPassChanged(m_minPass); } if(m_maxPass < m_curPass) { m_maxPass = m_curPass; emit maxPassChanged(m_maxPass); } if(!m_avgPass) { m_avgPass = m_curPass; emit avgPassChanged(m_avgPass); } else { static uint64_t nPasses = 0; ++nPasses; clock64_t avgPass = (m_avgPass + m_curPass) / 2; if(m_avgPass != avgPass) { m_avgPass = avgPass; if(!(nPasses % 50)) emit avgPassChanged(m_avgPass); } } } } ///////////////////////////////////////////////////////////////////////////// void QGfaAppCtrl::onSendControlMessage(appid_t nAppID, ctrlmsg_t msg) { if(m_hAC) ::GfaIpcAppCtrlSendCtrlMsg(m_hAC, nAppID, msg); } ///////////////////////////////////////////////////////////////////////////// int QGfaAppCtrl::SetState(int nState) { if(m_hAC) ::GfaIpcAppCtrlSetState(m_hAC, (GfaIpcAppStates)nState); return GIAS_Invalid; } ///////////////////////////////////////////////////////////////////////////// quint64 QGfaAppCtrl::minPass(void) const { return m_minPass; } quint64 QGfaAppCtrl::maxPass(void) const { return m_maxPass; } quint64 QGfaAppCtrl::avgPass(void) const { return m_avgPass; } QGfaSysInfo* QGfaAppCtrl::sysInfo(void) { return &m_sysInfo; } ///////////////////////////////////////////////////////////////////////////// int QGfaAppCtrl::appIndexFromAppID(quint64 nAppID) { if(_IS_VALID_APP_ID(nAppID)) return _APP_INDEX_FROM_APP_ID(nAppID); return _INVALID_SLOT_INDEX; } ///////////////////////////////////////////////////////////////////////////// QQmlListProperty QGfaAppCtrl::appInfo(void) { return QQmlListProperty(this, m_appInfo); }