power: rework sleep-wait
[platform/core/system/deviced.git] / plugins / iot-headless / power / sleep-wait.c
1 #include <libsyscommon/list.h>
2 #include <unistd.h>
3
4 #include "shared/log.h"
5 #include "shared/device-notifier.h"
6 #include "shared/common.h"
7
8 #include "sleep-wait.h"
9
10 #define MAX_WAIT_SECOND    5 /* second */
11
12 struct proc_info {
13         pid_t pid;
14         char comm[128];
15         int killed;
16 };
17
18 struct sleep_wait {
19         struct proc_info *pi;
20         int id;
21 };
22
23 static GList *proc_list;
24 static GList *sleep_waiting;
25
26 static int max_wait_timer;
27
28 static void sleep_wait_done(void)
29 {
30         if (max_wait_timer) {
31                 g_source_remove(max_wait_timer);
32                 max_wait_timer = 0;
33         }
34
35         device_notify(DEVICE_NOTIFIER_POWER_SLEEP_WAIT_DONE, NULL);
36 }
37
38 static gboolean max_wait_expired_cb(void *data)
39 {
40         struct sleep_wait *sw;
41         struct proc_info *pi;
42         GList *elem, *elem_next;
43
44         max_wait_timer = 0;
45
46         SYS_G_LIST_FOREACH_SAFE(sleep_waiting, elem, elem_next, sw) {
47                 if (kill(sw->pi->pid, 0) != 0)
48                         sw->pi->killed = 1;
49                 else
50                         _E("pid=%d(%s) hasn't confirmed sleep wait", sw->pi->pid, sw->pi->comm);
51                 sleep_waiting = g_list_remove_link(sleep_waiting, elem);
52                 g_list_free(elem);
53                 free(sw);
54         }
55
56         SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) {
57                 if (pi->killed) {
58                         _D("Clean up not existing pid=%d(%s) from sleep wait", pi->pid, pi->comm);
59                         proc_list = g_list_remove_link(proc_list, elem);
60                         g_list_free(elem);
61                         free(pi);
62                 }
63         }
64
65         _D("Maximum sleep wait expired, timeout=%ds", MAX_WAIT_SECOND);
66         device_notify(DEVICE_NOTIFIER_POWER_SLEEP_WAIT_DONE, NULL);
67
68         return G_SOURCE_REMOVE;
69 }
70
71 int add_sleep_wait(pid_t pid)
72 {
73         struct proc_info *pi;
74         GList *elem;
75
76         SYS_G_LIST_FOREACH(proc_list, elem, pi) {
77                 if (pi->pid == pid)
78                         return -EEXIST;
79         }
80
81         pi = calloc(1, sizeof(struct proc_info));
82         if (!pi)
83                 return -ENOMEM;
84
85         pi->pid = pid;
86         get_command(pid, pi->comm, sizeof(pi->comm));
87         SYS_G_LIST_APPEND(proc_list, pi);
88
89         return 0;
90 }
91
92 void remove_sleep_wait(pid_t pid)
93 {
94         struct sleep_wait *sw;
95         struct proc_info *pi;
96         GList *elem, *elem_next;
97
98         SYS_G_LIST_FOREACH_SAFE(sleep_waiting, elem, elem_next, sw) {
99                 if (sw->pi->pid == pid) {
100                         sleep_waiting = g_list_remove_link(sleep_waiting, elem);
101                         g_list_free(elem);
102                         free(sw);
103                 }
104         }
105
106         SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) {
107                 if (pi->pid == pid) {
108                         sleep_waiting = g_list_remove_link(sleep_waiting, elem);
109                         g_list_free(elem);
110                         free(pi);
111                 }
112         }
113 }
114
115 int confirm_sleep_wait(pid_t pid, int id)
116 {
117         struct sleep_wait *sw;
118         GList *elem, *elem_next;
119
120         SYS_G_LIST_FOREACH_SAFE(sleep_waiting, elem, elem_next, sw) {
121                 if (sw->pi->pid == pid && sw->id == id) {
122                         _D("pid=%d(%s) confirmed sleep id=%d", sw->pi->pid, sw->pi->comm, sw->id);
123                         sleep_waiting = g_list_remove_link(sleep_waiting, elem);
124                         g_list_free(elem);
125                         free(sw);
126
127                         if (SYS_G_LIST_LENGTH(sleep_waiting) == 0) {
128                                 /* all sleep-waits are checked */
129                                 sleep_wait_done();
130                                 return 0;
131                         }
132                 }
133         }
134
135         return 0;
136 }
137
138 int start_sleep_wait(int id)
139 {
140         struct proc_info *pi;
141         struct sleep_wait *sw;
142         GList *elem;
143         int n_sleep_wait;
144
145         /* create sleep_wait for every pid of proc_list */
146         SYS_G_LIST_FOREACH(proc_list, elem, pi) {
147                 sw = calloc(1, sizeof(struct sleep_wait));
148                         if (!sw)
149                                 continue;
150
151                 sw->pi = pi;
152                 sw->id = id;
153                 SYS_G_LIST_APPEND(sleep_waiting, sw);
154         }
155
156         n_sleep_wait = SYS_G_LIST_LENGTH(sleep_waiting);
157         if (n_sleep_wait == 0)
158                 return 0;
159
160         /* reset timer */
161         if (max_wait_timer)
162                 g_source_remove(max_wait_timer);
163
164         _D("Sleep wait is triggered, expected number of confirmation=%d", n_sleep_wait);
165         max_wait_timer = g_timeout_add_seconds(MAX_WAIT_SECOND, max_wait_expired_cb, NULL);
166
167         return n_sleep_wait;
168 }
169
170 void stop_sleep_wait(void)
171 {
172         struct sleep_wait *sw;
173         GList *elem, *elem_next;
174
175         if (max_wait_timer) {
176                 g_source_remove(max_wait_timer);
177                 max_wait_timer = 0;
178         }
179
180         SYS_G_LIST_FOREACH_SAFE(sleep_waiting, elem, elem_next, sw) {
181                 sleep_waiting = g_list_remove_link(sleep_waiting, elem);
182                 g_list_free(elem);
183                 free(sw);
184         }
185 }