1 #include <libsyscommon/list.h>
4 #include "shared/log.h"
5 #include "shared/device-notifier.h"
6 #include "shared/common.h"
8 #include "sleep-wait.h"
10 #define MAX_WAIT_SECOND 5 /* second */
19 /* inactive: This list contains sleep waits added by AddSleepWait dbus method.
20 * active: All entries of inactive list are moved to this list when sleep is requested.
21 * Each one moves to inactive list on receiving ConfirmWait dbus method.
22 * Sleep will be triggered when it becomes empty. */
23 static GList *inactive;
26 static int max_wait_timer;
27 static int current_sleep_id;
29 static void switch_active_list(void)
34 n = g_list_length(active);
36 _W("Sleep wait remains in active list, %d", n);
43 static void request_wake_unlock(void)
45 device_notify(DEVICE_NOTIFIER_REQUEST_ENABLE_AUTOSLEEP, NULL);
46 device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_UNLOCK, NULL);
49 static gboolean max_wait_expired_cb(void *data)
51 struct sleep_wait *sw;
52 GList *elem, *elem_next;
56 /* force confirmation */
57 if (g_list_length(active) != 0) {
58 SYS_G_LIST_FOREACH_SAFE(active, elem, elem_next, sw) {
59 if (kill(sw->pid, 0) != 0) {
60 _D("Remove not existing sleep wait of pid=%d(%s)", sw->pid, sw->comm);
61 active = g_list_remove(active, sw);
63 } else { /* move to inactive manually */
64 _W("pid=%d(%s) hasn't comfirmed sleep wait", sw->pid, sw->comm);
65 active = g_list_remove(active, sw);
66 inactive = g_list_append(inactive, sw);
71 _D("Force wake unlock");
72 request_wake_unlock();
74 return G_SOURCE_REMOVE;
78 * 0 if sleep_wait is found in inactive list,
79 * -EBUSY if sleep_wait is found in active list,
80 * -ESRCH if sleep_wait is not found in both list */
81 static int find_sleep_wait(pid_t pid, struct sleep_wait **sw)
83 struct sleep_wait *ret = NULL;
89 SYS_G_LIST_FOREACH(inactive, elem, ret) {
90 if (ret->pid == pid) {
96 SYS_G_LIST_FOREACH(active, elem, ret) {
97 if (ret->pid == pid) {
107 int add_sleep_wait(pid_t pid)
109 struct sleep_wait *sw;
112 ret = find_sleep_wait(pid, &sw);
113 if (ret == -ESRCH) { /* new node */
114 sw = calloc(1, sizeof(struct sleep_wait));
119 get_command(pid, sw->comm, sizeof(sw->comm));
120 inactive = g_list_append(inactive, sw);
122 _D("pid=%d(%s) is added to sleep wait list", sw->pid, sw->comm);
123 } else if (ret == 0 || ret == -EBUSY) {
124 _D("pid=%d(%s) has already been added to sleep wait list", sw->pid, sw->comm);
130 void remove_sleep_wait(pid_t pid)
132 struct sleep_wait *sw = NULL;
135 retval = find_sleep_wait(pid, &sw);
136 if (retval == -ESRCH)
140 _D("pid=%d(%s) requested removing sleep wait", sw->pid, sw->comm);
142 /* remove from where it is contained */
143 active = g_list_remove(active, sw);
144 inactive = g_list_remove(inactive, sw);
148 /* wake unlock when active becomes empty by this operation
149 * during waiting sleep confirmations */
150 if (max_wait_timer != 0 && g_list_length(active) == 0) {
151 g_source_remove(max_wait_timer);
154 _D("All sleep waits have been confirmed, wake unlock");
155 request_wake_unlock();
160 int confirm_sleep_wait(pid_t pid, int id)
162 struct sleep_wait *sw;
165 ret = find_sleep_wait(pid, &sw);
167 _E("pid=%d hasn't been added to sleep wait list", pid);
171 /* Multiple confirmation or
172 * confirm request after MAX_WAIT_SECOND */
174 _D("pid=%d(%s) sleep wait has already been confirmed", sw->pid, sw->comm);
178 if (id != current_sleep_id) {
179 _E("Confirm mismatches sleep_id, current=%d, confirm=%d", current_sleep_id, id);
183 /* Move sw from active to inactive list.
184 * Wake unlock if active becomes empty. */
186 active = g_list_remove(active, sw);
187 inactive = g_list_append(inactive, sw);
188 _D("pid=%d(%s) confirmed sleep wait", sw->pid, sw->comm);
190 if (g_list_length(active) == 0) {
191 /* remove max_wait_timer and wake unlock immediately */
192 if (max_wait_timer) {
193 g_source_remove(max_wait_timer);
197 _D("All sleep waits have been confirmed, wake unlock");
198 request_wake_unlock();
205 _E("Failed to confirm sleep wait, %d", ret);
210 void start_sleep_wait(int id)
212 if (max_wait_timer) {
213 _E("Already sleep waiting");
217 switch_active_list();
219 /* no need to defer sleep. wake unlock */
220 if (g_list_length(active) == 0) {
221 request_wake_unlock();
225 current_sleep_id = id;
227 _D("Sleep wait is triggered, maximum wait timeout=%ds", MAX_WAIT_SECOND);
228 max_wait_timer = g_timeout_add_seconds(MAX_WAIT_SECOND, max_wait_expired_cb, NULL);
231 void stop_sleep_wait(void)
233 struct sleep_wait *sw;
234 GList *elem, *elem_next;
236 if (max_wait_timer == 0)
239 /* cancel sleep wait */
240 g_source_remove(max_wait_timer);
243 _D("Wake locked during sleep wait, cancel all sleep waits");
245 SYS_G_LIST_FOREACH_SAFE(active, elem, elem_next, sw) {
246 if (kill(sw->pid, 0) != 0) {
247 _D("Remove not existing sleep wait of %d(%s)", sw->pid, sw->comm);
248 active = g_list_remove(active, sw);
250 } else { /* move to inactive manually */
251 active = g_list_remove(active, sw);
252 inactive = g_list_append(inactive, sw);