refactor epoll manager

Signed-off-by: blueyouh <bailiang18@huawei.com>
Change-Id: Id3451546e448d28a1973bf6f84605b3ade81e5cb
Signed-off-by: blueyouh <bailiang18@huawei.com>
This commit is contained in:
blueyouh 2023-10-28 01:04:44 +00:00
parent b4dc5b32cb
commit 47e7a00896
8 changed files with 296 additions and 89 deletions

35
common/epoll/BUILD.gn Executable file
View File

@ -0,0 +1,35 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("../../device_status.gni")
config("devicestatus_epoll_public_config") {
include_dirs = [ "include" ]
}
ohos_source_set("devicestatus_epoll") {
include_dirs = [ "include" ]
sources = [ "src/epoll_manager.cpp" ]
public_configs = [ ":devicestatus_epoll_public_config" ]
deps = [ "${device_status_utils_path}:devicestatus_util" ]
public_deps = [ "${device_status_root_path}/data:devicestatus_data" ]
external_deps = [ "hilog:libhilog" ]
subsystem_name = "${device_status_subsystem_name}"
part_name = "${device_status_part_name}"
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2021-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef EPOLL_MANAGER_H
#define EPOLL_MANAGER_H
#include <cinttypes>
#include <memory>
#include <vector>
#include "nocopyable.h"
#include "i_epoll_event_source.h"
namespace OHOS {
namespace Msdp {
namespace DeviceStatus {
class EpollManager final : public IEpollEventSource {
public:
EpollManager() = default;
~EpollManager();
DISALLOW_COPY_AND_MOVE(EpollManager);
int32_t Open();
void Close();
int32_t Add(IEpollEventSource &source);
void Remove(IEpollEventSource &source);
int32_t Update(IEpollEventSource &source);
int32_t Wait(struct epoll_event *events, int32_t maxevents);
int32_t WaitTimeout(struct epoll_event *events, int32_t maxevents, int32_t timeout);
int32_t GetFd() const override;
void Dispatch(const struct epoll_event &ev) override;
private:
void DispatchOne(const struct epoll_event &ev);
private:
int32_t epollFd_ { -1 };
};
inline int32_t EpollManager::GetFd() const
{
return epollFd_;
}
} // namespace DeviceStatus
} // namespace Msdp
} // namespace OHOS
#endif // EPOLL_MANAGER_H

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2021-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "epoll_manager.h"
#include <unistd.h>
#include "devicestatus_define.h"
namespace OHOS {
namespace Msdp {
namespace DeviceStatus {
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL { LOG_CORE, MSDP_DOMAIN_ID, "EpollManager" };
constexpr int32_t MAX_N_EVENTS { 64 };
} // namespace
EpollManager::~EpollManager()
{
Close();
}
int32_t EpollManager::Open()
{
epollFd_ = ::epoll_create1(EPOLL_CLOEXEC);
if (epollFd_ == -1) {
FI_HILOGE("epoll_create1 failed: %{public}s", ::strerror(errno));
return RET_ERR;
}
return RET_OK;
}
void EpollManager::Close()
{
if (epollFd_ != -1) {
if (::close(epollFd_) != 0) {
FI_HILOGE("close(%{public}d) failed:%{public}s", epollFd_, ::strerror(errno));
}
epollFd_ = -1;
}
}
int32_t EpollManager::Add(IEpollEventSource &source)
{
CALL_DEBUG_ENTER;
struct epoll_event ev {};
ev.events = source.GetEvents();
ev.data.ptr = &source;
int32_t ret = ::epoll_ctl(epollFd_, EPOLL_CTL_ADD, source.GetFd(), &ev);
if (ret != 0) {
FI_HILOGE("epoll_ctl failed:%{public}s", ::strerror(errno));
return RET_ERR;
}
return RET_OK;
}
void EpollManager::Remove(IEpollEventSource &source)
{
CALL_DEBUG_ENTER;
int32_t ret = ::epoll_ctl(epollFd_, EPOLL_CTL_DEL, source.GetFd(), nullptr);
if (ret != 0) {
FI_HILOGE("epoll_ctl failed:%{public}s", ::strerror(errno));
}
}
int32_t EpollManager::Update(IEpollEventSource &source)
{
CALL_DEBUG_ENTER;
struct epoll_event ev {};
ev.events = source.GetEvents();
ev.data.ptr = &source;
int32_t ret = ::epoll_ctl(epollFd_, EPOLL_CTL_MOD, source.GetFd(), &ev);
if (ret != 0) {
FI_HILOGE("epoll_ctl failed:%{public}s", ::strerror(errno));
return RET_ERR;
}
return RET_OK;
}
int32_t EpollManager::Wait(struct epoll_event *events, int32_t maxevents)
{
return WaitTimeout(events, maxevents, -1);
}
int32_t EpollManager::WaitTimeout(struct epoll_event *events, int32_t maxevents, int32_t timeout)
{
int32_t ret = ::epoll_wait(epollFd_, events, maxevents, timeout);
if (ret < 0) {
FI_HILOGE("epoll_wait failed:%{public}s", ::strerror(errno));
} else if (ret == 0) {
FI_HILOGE("epoll_wait timeout");
}
return ret;
}
void EpollManager::Dispatch(const struct epoll_event &ev)
{
CALL_DEBUG_ENTER;
if ((ev.events & EPOLLIN) == EPOLLIN) {
DispatchOne(ev);
} else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
FI_HILOGE("Epoll hangup:%{public}s", ::strerror(errno));
}
}
void EpollManager::DispatchOne(const struct epoll_event &ev)
{
struct epoll_event evs[MAX_N_EVENTS];
int32_t cnt = WaitTimeout(evs, MAX_N_EVENTS, 0);
for (int32_t index = 0; index < cnt; ++index) {
IEpollEventSource *source = reinterpret_cast<IEpollEventSource *>(evs[index].data.ptr);
CHKPC(source);
if ((evs[index].events & EPOLLIN) == EPOLLIN) {
source->Dispatch(evs[index]);
} else if ((evs[index].events & (EPOLLHUP | EPOLLERR)) != 0) {
FI_HILOGE("Epoll hangup:%{public}s", ::strerror(errno));
}
}
}
} // namespace DeviceStatus
} // namespace Msdp
} // namespace OHOS

29
data/BUILD.gn Executable file
View File

@ -0,0 +1,29 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("../device_status.gni")
config("devicestatus_data_public_config") {
include_dirs = [ "include" ]
}
ohos_source_set("devicestatus_data") {
include_dirs = [ "include" ]
sources = []
public_configs = [ ":devicestatus_data_public_config" ]
subsystem_name = "${device_status_subsystem_name}"
part_name = "${device_status_part_name}"
}

View File

@ -26,9 +26,15 @@ public:
IEpollEventSource() = default;
virtual ~IEpollEventSource() = default;
virtual uint32_t GetEvents() const;
virtual int32_t GetFd() const = 0;
virtual void Dispatch(const struct epoll_event &ev) = 0;
};
inline uint32_t IEpollEventSource::GetEvents() const
{
return (EPOLLIN | EPOLLHUP | EPOLLERR);
}
} // namespace DeviceStatus
} // namespace Msdp
} // namespace OHOS

View File

@ -102,6 +102,8 @@ ohos_shared_library("devicestatus_service") {
deps += [ "interaction/coordination:coordination" ]
}
public_deps = [ "${device_status_root_path}/common/epoll:devicestatus_epoll" ]
external_deps = external_deps_set
if (fusion_interaction_coordination) {
external_deps += [
@ -140,6 +142,8 @@ ohos_static_library("devicestatus_static_service") {
deps += [ "interaction/coordination:coordination" ]
}
public_deps = [ "${device_status_root_path}/common/epoll:devicestatus_epoll" ]
external_deps = external_deps_set
if (fusion_interaction_coordination) {
external_deps += [

View File

@ -27,7 +27,7 @@
#include "enumerator.h"
#include "i_context.h"
#include "i_device_mgr.h"
#include "i_epoll_event_source.h"
#include "epoll_manager.h"
#include "monitor.h"
namespace OHOS {
@ -67,17 +67,13 @@ private:
int32_t OnInit(IContext *context);
int32_t OnEnable();
int32_t OnDisable();
int32_t OnEpollDispatch();
int32_t OnEpollDispatch(uint32_t events);
int32_t ParseDeviceId(const std::string &devNode);
void OnDeviceAdded(std::shared_ptr<IDevice> dev);
void OnDeviceRemoved(std::shared_ptr<IDevice> dev);
int32_t OnAddDeviceObserver(std::weak_ptr<IDeviceObserver> observer);
int32_t OnRemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer);
int32_t OnRetriggerHotplug(std::weak_ptr<IDeviceObserver> observer);
int32_t EpollCreate();
int32_t EpollAdd(IEpollEventSource *source);
void EpollDel(IEpollEventSource *source);
void EpollClose();
int32_t RunGetDevice(std::packaged_task<std::shared_ptr<IDevice>(int32_t)> &task, int32_t id) const;
std::shared_ptr<IDevice> OnGetDevice(int32_t id) const;
std::shared_ptr<IDevice> AddDevice(const std::string &devNode);
@ -86,17 +82,17 @@ private:
private:
IContext *context_ { nullptr };
int32_t epollFd_ { -1 };
Enumerator enumerator_;
Monitor monitor_;
HotplugHandler hotplug_;
std::shared_ptr<EpollManager> epollMgr_ { nullptr };
std::set<std::weak_ptr<IDeviceObserver>> observers_;
std::unordered_map<int32_t, std::shared_ptr<IDevice>> devices_;
};
inline int32_t DeviceManager::GetFd() const
{
return epollFd_;
return (epollMgr_ != nullptr ? epollMgr_->GetFd() : -1);
}
} // namespace DeviceStatus
} // namespace Msdp

View File

@ -36,7 +36,6 @@ namespace Msdp {
namespace DeviceStatus {
namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL { LOG_CORE, MSDP_DOMAIN_ID, "DeviceManager" };
constexpr int32_t MAX_N_EVENTS { 64 };
constexpr size_t EXPECTED_N_SUBMATCHES { 2 };
constexpr size_t EXPECTED_SUBMATCH { 1 };
} // namespace
@ -96,19 +95,17 @@ int32_t DeviceManager::Enable()
int32_t DeviceManager::OnEnable()
{
CALL_DEBUG_ENTER;
int32_t ret = EpollCreate();
epollMgr_ = std::make_shared<EpollManager>();
int32_t ret = epollMgr_->Open();
if (ret != RET_OK) {
FI_HILOGE("EpollCreate failed");
return ret;
}
ret = monitor_.Enable();
if (ret != RET_OK) {
FI_HILOGE("Failed to enable monitor");
goto CLOSE_EPOLL;
}
ret = EpollAdd(&monitor_);
ret = epollMgr_->Add(monitor_);
if (ret != RET_OK) {
FI_HILOGE("EpollAdd failed");
goto DISABLE_MONITOR;
}
enumerator_.ScanDevices();
@ -118,7 +115,7 @@ DISABLE_MONITOR:
monitor_.Disable();
CLOSE_EPOLL:
EpollClose();
epollMgr_.reset();
return ret;
}
@ -136,9 +133,10 @@ int32_t DeviceManager::Disable()
int32_t DeviceManager::OnDisable()
{
EpollDel(&monitor_);
CHKPR(epollMgr_, RET_ERR);
epollMgr_->Remove(monitor_);
monitor_.Disable();
EpollClose();
epollMgr_.reset();
return RET_OK;
}
@ -266,85 +264,25 @@ void DeviceManager::OnDeviceRemoved(std::shared_ptr<IDevice> dev)
}
}
int32_t DeviceManager::EpollCreate()
{
CALL_DEBUG_ENTER;
epollFd_ = epoll_create1(EPOLL_CLOEXEC);
if (epollFd_ < 0) {
FI_HILOGE("epoll_create1 failed");
return RET_ERR;
}
return RET_OK;
}
int32_t DeviceManager::EpollAdd(IEpollEventSource *source)
{
CALL_DEBUG_ENTER;
CHKPR(source, RET_ERR);
struct epoll_event ev {};
ev.events = EPOLLIN | EPOLLHUP | EPOLLERR;
ev.data.ptr = source;
int32_t ret = epoll_ctl(epollFd_, EPOLL_CTL_ADD, source->GetFd(), &ev);
if (ret != 0) {
FI_HILOGE("epoll_ctl failed:%{public}s", strerror(errno));
return RET_ERR;
}
return RET_OK;
}
void DeviceManager::EpollDel(IEpollEventSource *source)
{
CALL_DEBUG_ENTER;
CHKPV(source);
int32_t ret = epoll_ctl(epollFd_, EPOLL_CTL_DEL, source->GetFd(), nullptr);
if (ret != 0) {
FI_HILOGE("epoll_ctl failed:%{public}s", strerror(errno));
}
}
void DeviceManager::EpollClose()
{
CALL_DEBUG_ENTER;
if (epollFd_ >= 0) {
if (close(epollFd_) < 0) {
FI_HILOGE("Close epoll fd failed, error:%{public}s, epollFd_:%{public}d", strerror(errno), epollFd_);
}
epollFd_ = -1;
}
}
void DeviceManager::Dispatch(const struct epoll_event &ev)
{
CALL_DEBUG_ENTER;
if ((ev.events & EPOLLIN) == EPOLLIN) {
CHKPV(context_);
int32_t ret = context_->GetDelegateTasks().PostAsyncTask(
std::bind(&DeviceManager::OnEpollDispatch, this));
if (ret != RET_OK) {
FI_HILOGE("PostAsyncTask failed");
}
} else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
FI_HILOGE("Epoll hangup:%{public}s", strerror(errno));
CHKPV(context_);
int32_t ret = context_->GetDelegateTasks().PostAsyncTask(
std::bind(&DeviceManager::OnEpollDispatch, this, ev.events));
if (ret != RET_OK) {
FI_HILOGE("PostAsyncTask failed");
}
}
int32_t DeviceManager::OnEpollDispatch()
int32_t DeviceManager::OnEpollDispatch(uint32_t events)
{
struct epoll_event evs[MAX_N_EVENTS];
int32_t cnt = epoll_wait(epollFd_, evs, MAX_N_EVENTS, 0);
if (cnt < 0) {
FI_HILOGE("epoll_wait failed");
return RET_ERR;
}
for (int32_t index = 0; index < cnt; ++index) {
IEpollEventSource *source = reinterpret_cast<IEpollEventSource *>(evs[index].data.ptr);
CHKPC(source);
if ((evs[index].events & EPOLLIN) == EPOLLIN) {
source->Dispatch(evs[index]);
} else if ((evs[index].events & (EPOLLHUP | EPOLLERR)) != 0) {
FI_HILOGE("Epoll hangup:%{public}s", strerror(errno));
}
}
struct epoll_event ev {};
ev.events = events;
ev.data.ptr = epollMgr_.get();
CHKPR(epollMgr_, RET_ERR);
epollMgr_->Dispatch(ev);
return RET_OK;
}