4 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
22 #include <libsyscommon/list.h>
23 #include <device/power-internal.h>
25 #include "shared/log.h"
26 #include "shared/device-notifier.h"
27 #include "shared/common.h"
29 #include "power-state-wait.h"
30 #include "power-state-manager.h"
32 #define POWER_CONF_FILE "/etc/deviced/power.conf"
33 #define MAX_WAIT_SECOND 5 /* second */
35 static int max_wait_timeout = 5; /* second */
44 struct change_state_wait {
50 static GList *proc_list;
51 static GList *waiting_list;
52 static int max_wait_timer;
53 static void (*__change_state_wait_done) (void);
54 static enum psm_state waiting_state;
56 static void change_state_wait_done(void)
58 _D("%s wait done", psm_name[waiting_state]);
61 g_source_remove(max_wait_timer);
65 if (__change_state_wait_done) {
66 __change_state_wait_done();
70 static gboolean max_wait_expired_cb(void *data)
72 struct change_state_wait *csw;
74 GList *elem, *elem_next;
78 SYS_G_LIST_FOREACH_SAFE(waiting_list, elem, elem_next, csw) {
79 if (kill(csw->pi->pid, 0) != 0)
82 _E("pid=%d(%s) hasn't confirmed id=%"PRIu64"(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]);
83 waiting_list = g_list_remove_link(waiting_list, elem);
88 SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) {
90 _D("Clean up not existing pid=%d(%s)", pi->pid, pi->comm);
91 proc_list = g_list_remove_link(proc_list, elem);
97 change_state_wait_done();
99 return G_SOURCE_REMOVE;
102 int add_change_state_wait(pid_t pid, guint64 state)
104 struct proc_info *pi;
107 SYS_G_LIST_FOREACH(proc_list, elem, pi) {
108 if (pi->pid == pid) {
109 pi->state_bitmap |= state;
110 _D("pid=%d(%s) updated csw for %#"PRIx64, pid, pi->comm, state);
115 pi = calloc(1, sizeof(struct proc_info));
120 pi->state_bitmap = state;
121 get_command(pid, pi->comm, sizeof(pi->comm));
122 SYS_G_LIST_APPEND(proc_list, pi);
124 _D("pid=%d(%s) added csw for %#"PRIx64, pid, pi->comm, state);
129 void remove_change_state_wait(pid_t pid, guint64 state)
131 struct proc_info *pi;
132 GList *elem, *elem_next;
134 _D("pid=%d removed csw for %#"PRIx64, pid, state);
136 SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) {
137 if (pi->pid == pid) {
138 pi->state_bitmap &= ~state;
139 if (pi->state_bitmap == 0) {
140 proc_list = g_list_remove_link(proc_list, elem);
148 int confirm_change_state_wait(pid_t pid, guint64 id)
150 struct change_state_wait *csw;
151 GList *elem, *elem_next;
153 SYS_G_LIST_FOREACH_SAFE(waiting_list, elem, elem_next, csw) {
154 if (csw->pi->pid == pid && csw->id == id) {
155 _D("pid=%d(%s) confirmed id=%"PRIu64"(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]);
156 waiting_list = g_list_remove_link(waiting_list, elem);
160 if (SYS_G_LIST_LENGTH(waiting_list) == 0) {
161 change_state_wait_done();
170 static int check_proc_requested_wait_for_state(struct proc_info *pi, enum psm_state state)
175 if (state == PSM_NORMAL)
176 return (pi->state_bitmap & POWER_STATE_NORMAL);
177 if (state == PSM_SLEEP)
178 return (pi->state_bitmap & POWER_STATE_SLEEP);
179 if (state == PSM_POWEROFF)
180 return (pi->state_bitmap & POWER_STATE_POWEROFF);
181 if (state == PSM_REBOOT)
182 return (pi->state_bitmap & POWER_STATE_REBOOT);
187 int update_change_state_wait(guint64 id, const struct trans_info *ti, change_state_wait_done_cb callback)
189 struct proc_info *pi;
190 struct change_state_wait *csw;
191 GList *elem, *elem_next;
195 if (max_wait_timer) {
196 g_source_remove(max_wait_timer);
200 // we are waiting for confirm of transition to the next state
201 waiting_state = ti->next;
202 _D("%s wait is triggered, id=%"PRIu64, psm_name[waiting_state], id);
204 // cancel all ongoing csw that is not a waiting for the next state
205 SYS_G_LIST_FOREACH_SAFE(waiting_list, elem, elem_next, csw) {
206 if (csw->state != waiting_state) {
207 waiting_list = g_list_remove_link(waiting_list, elem);
209 _D("Cancel waiting: pid=%d(%s) for id=%"PRIu64"(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]);
215 SYS_G_LIST_FOREACH(proc_list, elem, pi) {
216 if (check_proc_requested_wait_for_state(pi, waiting_state)) {
217 csw = calloc(1, sizeof(struct change_state_wait));
223 csw->state = waiting_state;
224 SYS_G_LIST_APPEND(waiting_list, csw);
228 n_waiting = SYS_G_LIST_LENGTH(waiting_list);
229 if (n_waiting == 0) {
230 _D("There were no csw requests for %s, skip waiting", psm_name[waiting_state]);
231 __change_state_wait_done = NULL;
235 __change_state_wait_done = callback;
237 _D("The number of pending wait confirm=%d", n_waiting);
238 max_wait_timer = g_timeout_add_seconds(max_wait_timeout, max_wait_expired_cb, NULL);
243 static int load_max_wait_timeout(struct parse_result *result, void *user_data)
245 if (MATCH(result->section, "PowerState")
246 && MATCH(result->name, "ChangeStateMaxWaitSecond"))
247 max_wait_timeout = atoi(result->value);
252 void power_state_wait_init(void)
254 config_parse(POWER_CONF_FILE, load_max_wait_timeout, NULL);
256 CRITICAL_LOG("Change state max wait timeout=%ds", max_wait_timeout);