313 lines
7.4 KiB
C++
313 lines
7.4 KiB
C++
/*
|
|
* SPDX-License-Identifier: LicenseRef-Unisoc-General-1.0
|
|
|
|
* Copyright 2016-2023 Unisoc (Shanghai) Technologies Co., Ltd
|
|
|
|
* Licensed under the Unisoc General Software License, version 1.0 (the License);
|
|
* you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
|
|
|
* https://www.unisoc.com/en_us/license/UNISOC_GENERAL_LICENSE_V1.0-EN_US
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OF ANY KIND, either express or implied.
|
|
* See the Unisoc General Software License, version 1.0 for more details.
|
|
*/
|
|
#include <cassert>
|
|
#include <errno.h>
|
|
#include <Debug.h>
|
|
#include <dbus/dbus.h>
|
|
#include <stdio.h>
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include "EventLoop.h"
|
|
#include "CommonTimeout.h"
|
|
using namespace UDBus;
|
|
|
|
EventLoop::EventLoop()
|
|
: mRunning(false)
|
|
{
|
|
}
|
|
|
|
EventLoop::~EventLoop()
|
|
{
|
|
for (list<BusWatch *>::iterator iter = mBusWatchList.begin(); iter != mBusWatchList.end(); iter++)
|
|
{
|
|
delete (*iter);
|
|
}
|
|
|
|
for (list<CommonWatch *>::iterator iter = mCommonWatchList.begin(); iter != mCommonWatchList.end(); iter++)
|
|
{
|
|
delete (*iter);
|
|
}
|
|
|
|
for (list<BusTimeout *>::iterator ti = mBusTimeouts.begin(); ti != mBusTimeouts.end(); ti++)
|
|
{
|
|
delete (*ti);
|
|
}
|
|
|
|
for (list<CommonTimeout *>::iterator ti = mCommonTimeouts.begin(); ti != mCommonTimeouts.end(); ti++)
|
|
{
|
|
delete (*ti);
|
|
}
|
|
}
|
|
|
|
void EventLoop::AddDispatcher(Dispatcher *dispatcher)
|
|
{
|
|
mDispatches.push_back(dispatcher);
|
|
}
|
|
|
|
void EventLoop::RemoveDispatcher(Dispatcher *dispatcher)
|
|
{
|
|
mDispatches.remove(dispatcher);
|
|
}
|
|
|
|
void EventLoop::Stop()
|
|
{
|
|
mRunning = false;
|
|
}
|
|
|
|
void EventLoop::DispatcherScheme()
|
|
{
|
|
DispatcherList::iterator dispatcerIter = mDispatches.begin();
|
|
for (; dispatcerIter != mDispatches.end(); ++dispatcerIter)
|
|
{
|
|
Dispatcher *dispatcher = *dispatcerIter;
|
|
dispatcher->Dispatch();
|
|
}
|
|
}
|
|
|
|
void EventLoop::PollFdsAdd(int fd, short flag)
|
|
{
|
|
mPollFds.push_back({fd, flag, 0});
|
|
}
|
|
|
|
void EventLoop::PreparePollFds()
|
|
{
|
|
mPollFds.clear();
|
|
for (auto &watch : mBusWatchList)
|
|
{
|
|
if (watch->GetEnabled())
|
|
PollFdsAdd(watch->GetDescriptor(), watch->GetFlags());
|
|
}
|
|
|
|
map<int, vector<CommonWatch *>> watchMap;
|
|
for (auto &watch : mCommonWatchList)
|
|
{
|
|
watchMap[watch->GetDescriptor()].push_back(watch);
|
|
}
|
|
|
|
for (auto &elem : watchMap)
|
|
{
|
|
int flag = 0;
|
|
for (auto &watch : elem.second)
|
|
{
|
|
flag |= watch->GetFlags();
|
|
}
|
|
PollFdsAdd(elem.first, flag);
|
|
}
|
|
}
|
|
|
|
int EventLoop::GetPollTimeout()
|
|
{
|
|
int waitMs = -1;
|
|
for (list<BusTimeout *>::iterator ti = mBusTimeouts.begin(); ti != mBusTimeouts.end(); ++ti)
|
|
{
|
|
if (((*ti)->GetInterval() < waitMs) || (waitMs < 0))
|
|
waitMs = (*ti)->GetInterval();
|
|
}
|
|
|
|
for (list<CommonTimeout *>::iterator ti = mCommonTimeouts.begin(); ti != mCommonTimeouts.end(); ++ti)
|
|
{
|
|
if (((*ti)->GetInterval() < waitMs) || (waitMs < 0))
|
|
waitMs = (*ti)->GetInterval();
|
|
}
|
|
DEBUG("wait millsecond:%d", waitMs);
|
|
return waitMs;
|
|
}
|
|
|
|
// @return value: ms
|
|
double EventLoop::GetMonotonicTime()
|
|
{
|
|
struct timespec ts;
|
|
int result = clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
if (result != 0)
|
|
{
|
|
DEBUG("get CLOCK_MONOTONIC fail");
|
|
}
|
|
return (((long)ts.tv_sec) * 1000.0) + (ts.tv_nsec / 1000000.0);
|
|
}
|
|
|
|
void EventLoop::TimeoutScheme()
|
|
{
|
|
DEBUG("");
|
|
|
|
double nowMillis = GetMonotonicTime();
|
|
|
|
for (list<BusTimeout *>::iterator ti = mBusTimeouts.begin(); ti != mBusTimeouts.end();)
|
|
{
|
|
BusTimeout *timeout = *ti;
|
|
if (!timeout)
|
|
{
|
|
ti++;
|
|
continue;
|
|
}
|
|
bool enable = timeout->GetEnabled();
|
|
if (!enable)
|
|
{
|
|
if (timeout)
|
|
{
|
|
delete timeout;
|
|
DEBUG(" delete BusTimeout ");
|
|
}
|
|
ti = mBusTimeouts.erase(ti);
|
|
}
|
|
else
|
|
{
|
|
if (nowMillis >= timeout->mExpiration)
|
|
{
|
|
if (timeout->mRepeat)
|
|
{
|
|
timeout->mExpiration = nowMillis + timeout->mInterval;
|
|
}
|
|
timeout->mBusExpired(*timeout);
|
|
}
|
|
ti++;
|
|
}
|
|
}
|
|
|
|
for (list<CommonTimeout *>::iterator ti = mCommonTimeouts.begin(); ti != mCommonTimeouts.end();)
|
|
{
|
|
CommonTimeout *timeout = *ti;
|
|
if (!timeout)
|
|
{
|
|
ti++;
|
|
continue;
|
|
}
|
|
bool enable = timeout->GetEnabled();
|
|
if (!enable)
|
|
{
|
|
if (timeout)
|
|
{
|
|
delete timeout;
|
|
DEBUG(" delete CommonTimeout ");
|
|
}
|
|
ti = mCommonTimeouts.erase(ti);
|
|
}
|
|
else
|
|
{
|
|
if (nowMillis >= timeout->mExpiration)
|
|
{
|
|
if (timeout->mRepeat)
|
|
{
|
|
timeout->mExpiration = nowMillis + timeout->mInterval;
|
|
}
|
|
timeout->mCommmonExpired(*timeout);
|
|
}
|
|
ti++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void EventLoop::BusWatchScheme(pollfd &pollFd)
|
|
{
|
|
for (auto it = mBusWatchList.begin(); it != mBusWatchList.end();)
|
|
{
|
|
BusWatch *watch = *it;
|
|
if (nullptr == watch || false == watch->GetEnabled())
|
|
{
|
|
it = mBusWatchList.erase(it);
|
|
delete watch;
|
|
continue;
|
|
}
|
|
|
|
if (watch->mFd != pollFd.fd)
|
|
{
|
|
++it;
|
|
continue;
|
|
}
|
|
DEBUG("watch %p flag %d revent %d", watch, watch->GetFlags(), pollFd.revents);
|
|
watch->mState = pollFd.revents;
|
|
watch->mReady(*watch);
|
|
pollFd.revents = 0;
|
|
++it;
|
|
}
|
|
}
|
|
|
|
void EventLoop::CommonWatchScheme()
|
|
{
|
|
// mCommonWatchList allready sorted by priority while added
|
|
for (auto it = mCommonWatchList.begin(); it != mCommonWatchList.end();)
|
|
{
|
|
CommonWatch *watch = *it;
|
|
if (nullptr == watch || false == watch->GetEnabled())
|
|
{
|
|
delete watch;
|
|
it = mCommonWatchList.erase(it);
|
|
continue;
|
|
}
|
|
|
|
for (auto &pollFd : mPollFds)
|
|
{
|
|
if (watch->mFd != pollFd.fd)
|
|
continue;
|
|
|
|
int flag = pollFd.revents & watch->GetFlags();
|
|
if (0 == flag)
|
|
break;
|
|
|
|
watch->mState = flag;
|
|
watch->mReady(*watch);
|
|
break;
|
|
}
|
|
++it;
|
|
}
|
|
}
|
|
|
|
void EventLoop::WatchScheme()
|
|
{
|
|
for (auto &pollFd : mPollFds)
|
|
{
|
|
if (0 == pollFd.revents)
|
|
continue;
|
|
|
|
BusWatchScheme(pollFd);
|
|
}
|
|
|
|
CommonWatchScheme();
|
|
}
|
|
|
|
void EventLoop::Run()
|
|
{
|
|
mRunning = true;
|
|
while (mRunning)
|
|
{
|
|
try
|
|
{
|
|
DispatcherScheme();
|
|
|
|
PreparePollFds();
|
|
|
|
int timeWait = GetPollTimeout();
|
|
int fdReady = poll(mPollFds.data(), mPollFds.size(), timeWait);
|
|
TimeoutScheme();
|
|
|
|
if (fdReady > 0)
|
|
WatchScheme();
|
|
}
|
|
catch (const std::exception &e)
|
|
{
|
|
std::cerr << e.what() << '\n';
|
|
DEBUG("error %s", e.what());
|
|
}
|
|
}
|
|
}
|
|
|
|
bool EventLoop::CommonWatchFdEmpty(int fd) const
|
|
{
|
|
for (const auto &watch : mCommonWatchList)
|
|
{
|
|
if (watch && fd == watch->GetDescriptor() && watch->GetEnabled())
|
|
return false;
|
|
}
|
|
return true;
|
|
} |