| /* | 
 |  * Copyright (C) 2018 The Android Open Source Project | 
 |  * | 
 |  * 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. | 
 |  */ | 
 |  | 
 | #define LOG_TAG "libpsi" | 
 |  | 
 | #include <errno.h> | 
 | #include <string.h> | 
 | #include <sys/epoll.h> | 
 |  | 
 | #include <log/log.h> | 
 | #include "psi/psi.h" | 
 |  | 
 | #define PSI_MON_FILE_MEMORY "/proc/pressure/memory" | 
 |  | 
 | static const char* stall_type_name[] = { | 
 |         "some", | 
 |         "full", | 
 | }; | 
 |  | 
 | int init_psi_monitor(enum psi_stall_type stall_type, | 
 |              int threshold_us, int window_us) { | 
 |     int fd; | 
 |     int res; | 
 |     char buf[256]; | 
 |  | 
 |     fd = TEMP_FAILURE_RETRY(open(PSI_MON_FILE_MEMORY, O_WRONLY | O_CLOEXEC)); | 
 |     if (fd < 0) { | 
 |         ALOGE("No kernel psi monitor support (errno=%d)", errno); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     switch (stall_type) { | 
 |     case (PSI_SOME): | 
 |     case (PSI_FULL): | 
 |         res = snprintf(buf, sizeof(buf), "%s %d %d", | 
 |             stall_type_name[stall_type], threshold_us, window_us); | 
 |         break; | 
 |     default: | 
 |         ALOGE("Invalid psi stall type: %d", stall_type); | 
 |         errno = EINVAL; | 
 |         goto err; | 
 |     } | 
 |  | 
 |     if (res >= (ssize_t)sizeof(buf)) { | 
 |         ALOGE("%s line overflow for psi stall type '%s'", | 
 |             PSI_MON_FILE_MEMORY, stall_type_name[stall_type]); | 
 |         errno = EINVAL; | 
 |         goto err; | 
 |     } | 
 |  | 
 |     res = TEMP_FAILURE_RETRY(write(fd, buf, strlen(buf) + 1)); | 
 |     if (res < 0) { | 
 |         ALOGE("%s write failed for psi stall type '%s'; errno=%d", | 
 |             PSI_MON_FILE_MEMORY, stall_type_name[stall_type], errno); | 
 |         goto err; | 
 |     } | 
 |  | 
 |     return fd; | 
 |  | 
 | err: | 
 |     close(fd); | 
 |     return -1; | 
 | } | 
 |  | 
 | int register_psi_monitor(int epollfd, int fd, void* data) { | 
 |     int res; | 
 |     struct epoll_event epev; | 
 |  | 
 |     epev.events = EPOLLPRI; | 
 |     epev.data.ptr = data; | 
 |     res = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &epev); | 
 |     if (res < 0) { | 
 |         ALOGE("epoll_ctl for psi monitor failed; errno=%d", errno); | 
 |     } | 
 |     return res; | 
 | } | 
 |  | 
 | int unregister_psi_monitor(int epollfd, int fd) { | 
 |     return epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL); | 
 | } | 
 |  | 
 | void destroy_psi_monitor(int fd) { | 
 |     if (fd >= 0) { | 
 |         close(fd); | 
 |     } | 
 | } |