1ba5c3796Sopenharmony_ci/*
2ba5c3796Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3ba5c3796Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4ba5c3796Sopenharmony_ci * you may not use this file except in compliance with the License.
5ba5c3796Sopenharmony_ci * You may obtain a copy of the License at
6ba5c3796Sopenharmony_ci *
7ba5c3796Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8ba5c3796Sopenharmony_ci *
9ba5c3796Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10ba5c3796Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11ba5c3796Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12ba5c3796Sopenharmony_ci * See the License for the specific language governing permissions and
13ba5c3796Sopenharmony_ci * limitations under the License.
14ba5c3796Sopenharmony_ci */
15ba5c3796Sopenharmony_ci#include "kswapd_observer.h"
16ba5c3796Sopenharmony_ci
17ba5c3796Sopenharmony_ci#include <cerrno>
18ba5c3796Sopenharmony_ci#include <fcntl.h>
19ba5c3796Sopenharmony_ci#include <sstream>
20ba5c3796Sopenharmony_ci#include <string>
21ba5c3796Sopenharmony_ci#include <sys/epoll.h>
22ba5c3796Sopenharmony_ci#include <unistd.h>
23ba5c3796Sopenharmony_ci
24ba5c3796Sopenharmony_ci#include "memmgr_log.h"
25ba5c3796Sopenharmony_ci#include "memmgr_ptr_util.h"
26ba5c3796Sopenharmony_ci#include "memory_level_constants.h"
27ba5c3796Sopenharmony_ci#ifdef USE_PURGEABLE_MEMORY
28ba5c3796Sopenharmony_ci#include "purgeable_mem_manager.h"
29ba5c3796Sopenharmony_ci#endif
30ba5c3796Sopenharmony_ci
31ba5c3796Sopenharmony_cinamespace OHOS {
32ba5c3796Sopenharmony_cinamespace Memory {
33ba5c3796Sopenharmony_cinamespace {
34ba5c3796Sopenharmony_ciconst std::string TAG = "KswapdObserver";
35ba5c3796Sopenharmony_ci}
36ba5c3796Sopenharmony_ci
37ba5c3796Sopenharmony_ciKswapdObserver::KswapdObserver()
38ba5c3796Sopenharmony_ci{
39ba5c3796Sopenharmony_ci    MAKE_POINTER(handler_, shared, AppExecFwk::EventHandler, "failed to create event handler", return,
40ba5c3796Sopenharmony_ci                 AppExecFwk::EventRunner::Create());
41ba5c3796Sopenharmony_ci    HILOGI("handler init success!");
42ba5c3796Sopenharmony_ci}
43ba5c3796Sopenharmony_ci
44ba5c3796Sopenharmony_civoid KswapdObserver::Init()
45ba5c3796Sopenharmony_ci{
46ba5c3796Sopenharmony_ci    epollfd_ = epoll_create(6); // 6 : max epoll events
47ba5c3796Sopenharmony_ci    if (epollfd_ == -1) {
48ba5c3796Sopenharmony_ci        HILOGE("epoll_create failed (errno=%{public}d)", errno);
49ba5c3796Sopenharmony_ci        return;
50ba5c3796Sopenharmony_ci    }
51ba5c3796Sopenharmony_ci    HILOGI("epoll_create success epollfd_=<%{public}d>", epollfd_);
52ba5c3796Sopenharmony_ci
53ba5c3796Sopenharmony_ci    if (!RegisterKswapdListener()) {
54ba5c3796Sopenharmony_ci        HILOGE("register kswapd pressure failed!");
55ba5c3796Sopenharmony_ci        return;
56ba5c3796Sopenharmony_ci    }
57ba5c3796Sopenharmony_ci    // call MainLoop at handler thread
58ba5c3796Sopenharmony_ci    if (handler_ != nullptr) {
59ba5c3796Sopenharmony_ci        handler_->PostImmediateTask([this] { this->MainLoop(); });
60ba5c3796Sopenharmony_ci        HILOGD("call MainLoop at handler thread");
61ba5c3796Sopenharmony_ci    }
62ba5c3796Sopenharmony_ci}
63ba5c3796Sopenharmony_ci
64ba5c3796Sopenharmony_cibool KswapdObserver::RegisterKswapdListener()
65ba5c3796Sopenharmony_ci{
66ba5c3796Sopenharmony_ci    struct epoll_event epollEvent;
67ba5c3796Sopenharmony_ci
68ba5c3796Sopenharmony_ci    // open file
69ba5c3796Sopenharmony_ci    do {
70ba5c3796Sopenharmony_ci        kswapdMonitorFd_ = open(KSWAPD_PRESSURE_FILE, O_WRONLY | O_CLOEXEC);
71ba5c3796Sopenharmony_ci    } while (kswapdMonitorFd_ == -1 && errno == EINTR);
72ba5c3796Sopenharmony_ci    if (kswapdMonitorFd_ < 0) {
73ba5c3796Sopenharmony_ci        HILOGE("invalid fd (errno=%{public}d)", errno);
74ba5c3796Sopenharmony_ci        return false;
75ba5c3796Sopenharmony_ci    }
76ba5c3796Sopenharmony_ci
77ba5c3796Sopenharmony_ci    epollEvent.events = EPOLLPRI;
78ba5c3796Sopenharmony_ci    epollEvent.data.ptr = nullptr;
79ba5c3796Sopenharmony_ci    epollEvent.data.fd = kswapdMonitorFd_;
80ba5c3796Sopenharmony_ci    if (epoll_ctl(epollfd_, EPOLL_CTL_ADD, kswapdMonitorFd_, &epollEvent) < 0) {
81ba5c3796Sopenharmony_ci        close(kswapdMonitorFd_);
82ba5c3796Sopenharmony_ci        kswapdMonitorFd_ = -1;
83ba5c3796Sopenharmony_ci        HILOGE("failed to add file fd to epoll : errno=%{public}d", errno);
84ba5c3796Sopenharmony_ci        return false;
85ba5c3796Sopenharmony_ci    }
86ba5c3796Sopenharmony_ci    HILOGI("fd for kswapd monitor = %{public}d", kswapdMonitorFd_);
87ba5c3796Sopenharmony_ci    return true;
88ba5c3796Sopenharmony_ci}
89ba5c3796Sopenharmony_ci
90ba5c3796Sopenharmony_civoid KswapdObserver::MainLoop(void)
91ba5c3796Sopenharmony_ci{
92ba5c3796Sopenharmony_ci    struct epoll_event *curEpollEvent;
93ba5c3796Sopenharmony_ci
94ba5c3796Sopenharmony_ci    while (1) {
95ba5c3796Sopenharmony_ci        HILOGD("waiting for epoll event ...");
96ba5c3796Sopenharmony_ci        struct epoll_event events[1];
97ba5c3796Sopenharmony_ci        int i;
98ba5c3796Sopenharmony_ci        int nevents = epoll_wait(epollfd_, events, 1, -1);
99ba5c3796Sopenharmony_ci        HILOGD("receive events, num=%{public}d!", nevents);
100ba5c3796Sopenharmony_ci        if (nevents == -1) {
101ba5c3796Sopenharmony_ci            if (errno == EINTR) {
102ba5c3796Sopenharmony_ci                continue;
103ba5c3796Sopenharmony_ci            }
104ba5c3796Sopenharmony_ci            HILOGE("failed to wait epoll event(errno=%{public}d)", errno);
105ba5c3796Sopenharmony_ci            continue;
106ba5c3796Sopenharmony_ci        }
107ba5c3796Sopenharmony_ci
108ba5c3796Sopenharmony_ci        for (i = 0, curEpollEvent = &events[0]; i < nevents; ++i, curEpollEvent++) {
109ba5c3796Sopenharmony_ci            if (curEpollEvent->events & EPOLLHUP) {
110ba5c3796Sopenharmony_ci                HILOGE("EPOLLHUP in events[%{public}d]", i);
111ba5c3796Sopenharmony_ci                HandleEventEpollHup(curEpollEvent);
112ba5c3796Sopenharmony_ci                continue;
113ba5c3796Sopenharmony_ci            }
114ba5c3796Sopenharmony_ci            if (curEpollEvent->events & EPOLLERR) {
115ba5c3796Sopenharmony_ci                HILOGE("epoll err in events[%{public}d]", i);
116ba5c3796Sopenharmony_ci                continue;
117ba5c3796Sopenharmony_ci            }
118ba5c3796Sopenharmony_ci            if ((curEpollEvent->events & EPOLLPRI) && curEpollEvent->data.fd == kswapdMonitorFd_) {
119ba5c3796Sopenharmony_ci                HandleKswapdReport();
120ba5c3796Sopenharmony_ci            }
121ba5c3796Sopenharmony_ci        } // end of for
122ba5c3796Sopenharmony_ci    } // end of while
123ba5c3796Sopenharmony_ci}
124ba5c3796Sopenharmony_ci
125ba5c3796Sopenharmony_civoid KswapdObserver::HandleEventEpollHup(struct epoll_event *curEpollEvent)
126ba5c3796Sopenharmony_ci{
127ba5c3796Sopenharmony_ci    if (epoll_ctl(epollfd_, EPOLL_CTL_DEL, curEpollEvent->data.fd, NULL) < 0) {
128ba5c3796Sopenharmony_ci        HILOGE("Failed to unmonitor for kswapd, errno=%{public}d", errno);
129ba5c3796Sopenharmony_ci    }
130ba5c3796Sopenharmony_ci    if (curEpollEvent->data.fd >= 0) {
131ba5c3796Sopenharmony_ci        close(curEpollEvent->data.fd);
132ba5c3796Sopenharmony_ci    }
133ba5c3796Sopenharmony_ci    if (curEpollEvent->data.fd == kswapdMonitorFd_) {
134ba5c3796Sopenharmony_ci        kswapdMonitorFd_ = -1;
135ba5c3796Sopenharmony_ci    }
136ba5c3796Sopenharmony_ci}
137ba5c3796Sopenharmony_ci
138ba5c3796Sopenharmony_civoid HandleKswapdReport()
139ba5c3796Sopenharmony_ci{
140ba5c3796Sopenharmony_ci    HILOGD("called");
141ba5c3796Sopenharmony_ci#ifdef USE_PURGEABLE_MEMORY
142ba5c3796Sopenharmony_ci    SystemMemoryInfo info = {MemorySource::KSWAPD, SystemMemoryLevel::MEMORY_LEVEL_LOW};
143ba5c3796Sopenharmony_ci    PurgeableMemManager::GetInstance().NotifyMemoryLevel(info);
144ba5c3796Sopenharmony_ci#endif
145ba5c3796Sopenharmony_ci}
146ba5c3796Sopenharmony_ci
147ba5c3796Sopenharmony_ciKswapdObserver::~KswapdObserver()
148ba5c3796Sopenharmony_ci{
149ba5c3796Sopenharmony_ci    if (kswapdMonitorFd_ >= 0) {
150ba5c3796Sopenharmony_ci        epoll_ctl(epollfd_, EPOLL_CTL_DEL, kswapdMonitorFd_, NULL);
151ba5c3796Sopenharmony_ci        close(kswapdMonitorFd_);
152ba5c3796Sopenharmony_ci    }
153ba5c3796Sopenharmony_ci    if (epollfd_ >= 0) {
154ba5c3796Sopenharmony_ci        close(epollfd_);
155ba5c3796Sopenharmony_ci    }
156ba5c3796Sopenharmony_ci}
157ba5c3796Sopenharmony_ci} // namespace Memory
158ba5c3796Sopenharmony_ci} // namespace OHOS
159