Merge lp:~charlesk/powerd/add-hardware-alarms into lp:powerd
- add-hardware-alarms
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Ricardo Salveti |
Approved revision: | 143 |
Merged at revision: | 139 |
Proposed branch: | lp:~charlesk/powerd/add-hardware-alarms |
Merge into: | lp:powerd |
Diff against target: |
658 lines (+439/-12) 9 files modified
CMakeLists.txt (+3/-1) cli/powerd-cli.c (+99/-0) data/com.canonical.powerd.xml (+13/-0) debian/control (+2/-0) src/log.h (+23/-0) src/powerd-internal.h (+8/-1) src/powerd-object.c (+101/-10) src/powerd.cpp (+2/-0) src/wakeup.cpp (+188/-0) |
To merge this branch: | bzr merge lp:~charlesk/powerd/add-hardware-alarms |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ricardo Salveti (community) | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Review via email: mp+231302@code.launchpad.net |
Commit message
Add hardware wakeup support.
Description of the change
Add hardware wakeup support. As discussed in #phablet, the u_hardware_
This adds a little new public API: two methods (requestWakeup() and clearWakeup()) and a broadcast signal (Wakeup).
Also added are wakeup and clear-wakeup commands in powerd-cli.
The wakeup.cpp implementation is fairly straightforward. One point that might be contentious is the new logging functions in log.h. I think they're pretty useful but don't mind removing them if they're too un-powerd-like.
See related MP for indicator-datetime to make use of this: <https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
Ricardo Salveti (rsalveti) wrote : | # |
Code looks fine, just one inline comment for the packaging. Will do some further tests and then approve with the proper feedback.
Charles Kerr (charlesk) : | # |
- 143. By Charles Kerr
-
in debian/control, remove [armhf i386 amd64] arch restrictions for libubuntu-
platform- hardware- api-*
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:143
http://
Executed test runs:
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Ricardo Salveti (rsalveti) wrote : | # |
Looks good, works as expected.
Would be nice for powerd-cli list to also show the current list of the pending wakeup events, but that can be done later on.
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2014-05-21 03:17:03 +0000 |
3 | +++ CMakeLists.txt 2014-08-19 19:23:22 +0000 |
4 | @@ -9,7 +9,7 @@ |
5 | endif() |
6 | |
7 | set(CMAKE_C_FLAGS "-Wall") |
8 | -set(CMAKE_CXX_FLAGS "-Wall") |
9 | +set(CMAKE_CXX_FLAGS "-Wall -std=c++11") |
10 | set(CMAKE_C_FLAGS_DEBUG "-O0 -ggdb -g") |
11 | set(CMAKE_CXX_FLAGS_DEBUG "-O0 -ggdb -g") |
12 | set(CMAKE_C_FLAGS_RELEASE "-O3") |
13 | @@ -56,6 +56,7 @@ |
14 | src/spline.c |
15 | src/stats.c |
16 | src/util.c |
17 | + src/wakeup.cpp |
18 | src/${GDBUS_NAME}.c |
19 | ) |
20 | |
21 | @@ -103,6 +104,7 @@ |
22 | ${GIO_LIBRARIES} |
23 | ${GIO-UNIX_LIBRARIES} |
24 | ${PHABLET_LIBRARIES} |
25 | + "-lubuntu_platform_hardware_api" |
26 | "-lubuntu_application_api" |
27 | "-landroid-properties" |
28 | "-lhardware" |
29 | |
30 | === modified file 'cli/powerd-cli.c' |
31 | --- cli/powerd-cli.c 2014-06-18 18:06:10 +0000 |
32 | +++ cli/powerd-cli.c 2014-08-19 19:23:22 +0000 |
33 | @@ -141,6 +141,55 @@ |
34 | } |
35 | |
36 | static gboolean |
37 | +requestWakeup(const char *name, |
38 | + uint64_t wakeup_time, |
39 | + powerd_cookie_t setme_cookie) |
40 | +{ |
41 | + GVariant *ret; |
42 | + GError *error; |
43 | + gboolean success; |
44 | + |
45 | + g_return_val_if_fail (setme_cookie != NULL, FALSE); |
46 | + |
47 | + error = NULL; |
48 | + ret = g_dbus_proxy_call_sync(powerd_proxy, |
49 | + "requestWakeup", |
50 | + g_variant_new("(st)", name, wakeup_time), |
51 | + G_DBUS_CALL_FLAGS_NONE, |
52 | + -1, /* use default timeout */ |
53 | + NULL, /* cancellable */ |
54 | + &error); |
55 | + |
56 | + if (ret == NULL) { |
57 | + cli_warn("%s failed: %s", G_STRFUNC, error->message); |
58 | + success = FALSE; |
59 | + } |
60 | + else if (!g_variant_is_of_type(ret, G_VARIANT_TYPE("(s)"))) { |
61 | + char * s = g_variant_print(ret, TRUE); |
62 | + cli_warn("Unexpected response: %s", s); |
63 | + g_free(s); |
64 | + success = FALSE; |
65 | + } |
66 | + else { |
67 | + const char* s = NULL; |
68 | + g_variant_get(ret, "(&s)", &s); |
69 | + if (strlen(s) != sizeof(powerd_cookie_t) - 1) { |
70 | + cli_warn("Returned cookie has incorrect size"); |
71 | + success = FALSE; |
72 | + } |
73 | + else { |
74 | + memcpy(setme_cookie, s, sizeof(powerd_cookie_t)); |
75 | + cli_debug("Got cookie: %s", setme_cookie); |
76 | + success = TRUE; |
77 | + } |
78 | + } |
79 | + |
80 | + g_clear_error(&error); |
81 | + g_clear_pointer(&ret, g_variant_unref); |
82 | + return success; |
83 | +} |
84 | + |
85 | +static gboolean |
86 | requestDisplayState(int *cookie) |
87 | { |
88 | GVariant *ret = NULL; |
89 | @@ -286,6 +335,35 @@ |
90 | } |
91 | } |
92 | |
93 | +static gboolean |
94 | +clearWakeup(const char* cookie_str) |
95 | +{ |
96 | + GVariant *ret; |
97 | + GError *error; |
98 | + gboolean success; |
99 | + |
100 | + error = NULL; |
101 | + ret = g_dbus_proxy_call_sync(powerd_proxy, |
102 | + "clearWakeup", |
103 | + g_variant_new("(s)", cookie_str), |
104 | + G_DBUS_CALL_FLAGS_NONE, |
105 | + -1, /* default timeout */ |
106 | + NULL, /* cancellable */ |
107 | + &error); |
108 | + |
109 | + if (ret == NULL) { |
110 | + cli_warn("%s failed: %s", G_STRFUNC, error->message); |
111 | + success = FALSE; |
112 | + } else { |
113 | + cli_debug("%s success", G_STRFUNC); |
114 | + success = TRUE; |
115 | + } |
116 | + |
117 | + g_clear_error(&error); |
118 | + g_clear_pointer(&ret, g_variant_unref); |
119 | + return success; |
120 | +} |
121 | + |
122 | gboolean |
123 | clearSysState(powerd_cookie_t cookie) |
124 | { |
125 | @@ -618,6 +696,8 @@ |
126 | printf("listen\t- listen for signals from powerd. This runs a\n"\ |
127 | "\t gmainloop and must be manually killed.\n"); |
128 | printf("stats\t- print request statistics.\n"); |
129 | + printf("wakeup <n>\t- request a hardware wakeup n seconds from now.\n"); |
130 | + printf("clear-wakeup <cookie>\t- clear a hardware wakeup request given a cookie.\n"); |
131 | printf("test\t- runs tests.\n"); |
132 | } |
133 | |
134 | @@ -646,6 +726,8 @@ |
135 | (strcmp(argv[1],"stats")) && |
136 | (strcmp(argv[1],"active")) && |
137 | (strcmp(argv[1],"active-nc")) && |
138 | + (strcmp(argv[1],"wakeup")) && |
139 | + (strcmp(argv[1],"clear-wakeup")) && |
140 | (strcmp(argv[1],"test")) && |
141 | (strcmp(argv[1],"dbusnametest")) && |
142 | (strcmp(argv[1],"listen")) && |
143 | @@ -751,6 +833,9 @@ |
144 | if (!strcmp(argv[1],"clear-sys")) { |
145 | clearSysState(argv[2]); |
146 | } |
147 | + else if (!g_strcmp0(argv[1], "clear-wakeup")) { |
148 | + clearWakeup(argv[2]); |
149 | + } |
150 | else { |
151 | // Note: We should never get here due to earlier checks |
152 | fprintf(stderr,"Invalid option %s\n",argv[1]); |
153 | @@ -844,6 +929,20 @@ |
154 | exit(-1); |
155 | } |
156 | setUserBrightness((int)brightness); |
157 | + } else if (!g_strcmp0(argv[1], "wakeup")) { |
158 | + int n_seconds; |
159 | + powerd_cookie_t cookie; |
160 | + if (argc != 3) { |
161 | + usage(argv[0]); |
162 | + exit(-1); |
163 | + } |
164 | + n_seconds = atoi(argv[2]); |
165 | + if (n_seconds < 1) { |
166 | + fprintf(stderr, "Invalid number of seconds %s\n", argv[2]); |
167 | + usage(argv[0]); |
168 | + exit(-1); |
169 | + } |
170 | + requestWakeup(argv[0], time(NULL)+n_seconds, cookie); |
171 | } |
172 | return 0; |
173 | } |
174 | |
175 | === modified file 'data/com.canonical.powerd.xml' |
176 | --- data/com.canonical.powerd.xml 2014-05-13 22:05:20 +0000 |
177 | +++ data/com.canonical.powerd.xml 2014-08-19 19:23:22 +0000 |
178 | @@ -14,6 +14,16 @@ |
179 | <arg type="s" name="cookie" direction="in" /> |
180 | </method> |
181 | |
182 | + <method name="requestWakeup"> |
183 | + <arg type="s" name="name" direction="in" /> |
184 | + <arg type="t" name="time" direction="in" /> |
185 | + <arg type="s" name="cookie" direction="out" /> |
186 | + </method> |
187 | + |
188 | + <method name="clearWakeup"> |
189 | + <arg type="s" name="cookie" direction="in" /> |
190 | + </method> |
191 | + |
192 | <method name="registerClient"> |
193 | <arg type="s" name="name" direction="in" /> |
194 | </method> |
195 | @@ -55,5 +65,8 @@ |
196 | <arg type="i" name="sysState" direction="out" /> |
197 | </signal> |
198 | |
199 | + <signal name="Wakeup"> |
200 | + </signal> |
201 | + |
202 | </interface> |
203 | </node> |
204 | |
205 | === modified file 'debian/control' |
206 | --- debian/control 2014-06-13 15:56:20 +0000 |
207 | +++ debian/control 2014-08-19 19:23:22 +0000 |
208 | @@ -10,6 +10,8 @@ |
209 | python:any, |
210 | libandroid-properties-dev, |
211 | libubuntu-application-api-dev, |
212 | + libubuntu-platform-hardware-api-headers, |
213 | + libubuntu-platform-hardware-api-dev, |
214 | libupower-glib-dev, |
215 | uuid-dev, |
216 | libhardware-dev (>= 0.1.0+git20131207+e452e83-0ubuntu12), |
217 | |
218 | === modified file 'src/log.h' |
219 | --- src/log.h 2013-07-10 21:28:20 +0000 |
220 | +++ src/log.h 2014-08-19 19:23:22 +0000 |
221 | @@ -39,6 +39,29 @@ |
222 | __attribute__ ((format (printf, 2, 3))); |
223 | void powerd_log_init(void); |
224 | |
225 | +#define powerd_warn_if_fail(expr) \ |
226 | + do { \ |
227 | + if (!(expr)) \ |
228 | + powerd_warn("%s", #expr); \ |
229 | + } while (0) |
230 | + |
231 | +#define powerd_return_if_fail(expr) \ |
232 | + do { \ |
233 | + if (!(expr)) { \ |
234 | + powerd_warn("%s: assertion '%s' failed", __func__, #expr); \ |
235 | + return; \ |
236 | + } \ |
237 | + } while (0) |
238 | + |
239 | +#define powerd_return_val_if_fail(expr,val) \ |
240 | + do { \ |
241 | + if (!(expr)) { \ |
242 | + powerd_warn("%s: assertion '%s' failed", __func__, #expr); \ |
243 | + return val; \ |
244 | + } \ |
245 | + } while (0) |
246 | + |
247 | + |
248 | #ifdef __cplusplus |
249 | } |
250 | #endif |
251 | |
252 | === modified file 'src/powerd-internal.h' |
253 | --- src/powerd-internal.h 2014-07-02 16:24:51 +0000 |
254 | +++ src/powerd-internal.h 2014-08-19 19:23:22 +0000 |
255 | @@ -19,8 +19,8 @@ |
256 | #ifndef __POWERD_INTERNAL_H__ |
257 | #define __POWERD_INTERNAL_H__ |
258 | |
259 | +#include <time.h> /* time_t */ |
260 | #include <uuid/uuid.h> |
261 | -#include <glib.h> |
262 | #include <gio/gio.h> |
263 | |
264 | #include "powerd-object.h" |
265 | @@ -107,6 +107,7 @@ |
266 | enum SysPowerStates current_system_power_state(void); |
267 | const gchar * state_to_string(int state); |
268 | void powerd_sys_state_signal_emit(enum SysPowerStates state); |
269 | +void powerd_wakeup_signal_emit(void); |
270 | void clear_sys_state_by_owner(const char *owner); |
271 | gboolean powerd_suspend_active(void); |
272 | |
273 | @@ -164,6 +165,12 @@ |
274 | int powerd_ps_init(void); |
275 | void powerd_ps_deinit(void); |
276 | |
277 | +/* Hardware alarm functions */ |
278 | +void wakeup_init(void); |
279 | +void wakeup_deinit(void); |
280 | +int wakeup_request(const char *name, time_t time, powerd_cookie_t setme_cookie); |
281 | +int wakeup_clear(const powerd_cookie_t cookie); |
282 | + |
283 | /* Client functions */ |
284 | int powerd_client_register(const char *dbus_name, const char *name); |
285 | void powerd_client_unregister(const char *dbus_name); |
286 | |
287 | === modified file 'src/powerd-object.c' |
288 | --- src/powerd-object.c 2014-07-02 16:24:51 +0000 |
289 | +++ src/powerd-object.c 2014-08-19 19:23:22 +0000 |
290 | @@ -19,6 +19,7 @@ |
291 | #include <glib.h> |
292 | #include <glib-object.h> |
293 | #include <gio/gio.h> |
294 | +#include <inttypes.h> |
295 | #include <string.h> |
296 | #include <stdio.h> |
297 | #include <errno.h> |
298 | @@ -135,11 +136,69 @@ |
299 | return TRUE; |
300 | } |
301 | |
302 | +static gboolean |
303 | +handle_request_wakeup(PowerdSource *obj, |
304 | + GDBusMethodInvocation *invocation, |
305 | + const char *name, |
306 | + uint64_t wakeup_time) |
307 | +{ |
308 | + int err; |
309 | + powerd_cookie_t cookie; |
310 | + |
311 | + powerd_debug("handle_requestWakeup from %s - %s, %zu", |
312 | + g_dbus_method_invocation_get_sender(invocation), |
313 | + name, |
314 | + (size_t)wakeup_time); |
315 | + |
316 | + if ((err = wakeup_request(name, wakeup_time, cookie))) |
317 | + { |
318 | + g_dbus_method_invocation_return_error_literal(invocation, |
319 | + G_DBUS_ERROR, |
320 | + G_DBUS_ERROR_FAILED, |
321 | + strerror(err)); |
322 | + } |
323 | + else |
324 | + { |
325 | + g_dbus_method_invocation_return_value(invocation, |
326 | + g_variant_new("(s)", cookie)); |
327 | + } |
328 | + |
329 | + return TRUE; |
330 | +} |
331 | + |
332 | +static gboolean |
333 | +handle_clear_wakeup(PowerdSource *obj, |
334 | + GDBusMethodInvocation *invocation, |
335 | + const char* cookie) |
336 | +{ |
337 | + int err; |
338 | + |
339 | + powerd_debug("handle_clearWakeup from %s, cookie: %s", |
340 | + g_dbus_method_invocation_get_sender(invocation), |
341 | + cookie); |
342 | + |
343 | + if ((err = wakeup_clear(cookie))) |
344 | + { |
345 | + g_dbus_method_invocation_return_error_literal(invocation, |
346 | + G_DBUS_ERROR, |
347 | + G_DBUS_ERROR_FAILED, |
348 | + strerror(err)); |
349 | + } |
350 | + else |
351 | + { |
352 | + g_dbus_method_invocation_return_value(invocation, NULL); |
353 | + } |
354 | + |
355 | + return TRUE; |
356 | +} |
357 | + |
358 | + |
359 | void |
360 | powerd_bus_acquired_cb (GDBusConnection *connection, |
361 | const gchar *name, |
362 | gpointer user_data) |
363 | { |
364 | + GObject * oskel; |
365 | GError *error = NULL; |
366 | |
367 | powerd_debug("Bus acquired (guid %s)", g_dbus_connection_get_guid (connection)); |
368 | @@ -156,28 +215,35 @@ |
369 | powerd_exit(-1); |
370 | } |
371 | |
372 | - g_signal_connect(G_OBJECT(powerd_source->priv->skel), "handle-request-sys-state", |
373 | + oskel = G_OBJECT(powerd_source->priv->skel); |
374 | + |
375 | + g_signal_connect(oskel, "handle-request-sys-state", |
376 | G_CALLBACK(handle_request_sys_state), powerd_source); |
377 | - g_signal_connect(G_OBJECT(powerd_source->priv->skel), "handle-clear-sys-state", |
378 | + g_signal_connect(oskel, "handle-clear-sys-state", |
379 | G_CALLBACK(handle_clear_sys_state), powerd_source); |
380 | - g_signal_connect(G_OBJECT(powerd_source->priv->skel), "handle-list-sys-requests", |
381 | + g_signal_connect(oskel, "handle-list-sys-requests", |
382 | G_CALLBACK(handle_list_sys_requests), powerd_source); |
383 | |
384 | - g_signal_connect(G_OBJECT(powerd_source->priv->skel), "handle-register-client", |
385 | + g_signal_connect(oskel, "handle-register-client", |
386 | G_CALLBACK(handle_register_client), powerd_source); |
387 | - g_signal_connect(G_OBJECT(powerd_source->priv->skel), "handle-unregister-client", |
388 | + g_signal_connect(oskel, "handle-unregister-client", |
389 | G_CALLBACK(handle_unregister_client), powerd_source); |
390 | - g_signal_connect(G_OBJECT(powerd_source->priv->skel), "handle-ack-state-change", |
391 | + g_signal_connect(oskel, "handle-ack-state-change", |
392 | G_CALLBACK(handle_ack_state_change), powerd_source); |
393 | - g_signal_connect(G_OBJECT(powerd_source->priv->skel), "handle-get-sys-request-stats", |
394 | + g_signal_connect(oskel, "handle-get-sys-request-stats", |
395 | G_CALLBACK(handle_get_sys_request_stats), powerd_source); |
396 | - g_signal_connect(G_OBJECT(powerd_source->priv->skel), "handle-user-autobrightness-enable", |
397 | + g_signal_connect(oskel, "handle-user-autobrightness-enable", |
398 | G_CALLBACK(handle_user_autobrightness_enable), powerd_source); |
399 | - g_signal_connect(G_OBJECT(powerd_source->priv->skel), "handle-get-brightness-params", |
400 | + g_signal_connect(oskel, "handle-get-brightness-params", |
401 | G_CALLBACK(handle_get_brightness_params), powerd_source); |
402 | - g_signal_connect(G_OBJECT(powerd_source->priv->skel), "handle-set-user-brightness", |
403 | + g_signal_connect(oskel, "handle-set-user-brightness", |
404 | G_CALLBACK(handle_set_user_brightness), powerd_source); |
405 | |
406 | + g_signal_connect(oskel, "handle-request-wakeup", |
407 | + G_CALLBACK(handle_request_wakeup), powerd_source); |
408 | + g_signal_connect(oskel, "handle-clear-wakeup", |
409 | + G_CALLBACK(handle_clear_wakeup), powerd_source); |
410 | + |
411 | powerd_dbus_init_complete(); |
412 | } |
413 | |
414 | @@ -224,6 +290,31 @@ |
415 | } |
416 | |
417 | void |
418 | +powerd_wakeup_signal_emit (void) |
419 | +{ |
420 | + GError *error = NULL; |
421 | + |
422 | + /* Make sure dbus has been set up */ |
423 | + if (!powerd_source) |
424 | + return; |
425 | + |
426 | + powerd_debug("Emitting wakeup signal"); |
427 | + |
428 | + g_dbus_connection_emit_signal( |
429 | + POWERD_SOURCE_GET_PRIVATE(powerd_source)->system_bus, |
430 | + NULL, /* destination */ |
431 | + "/com/canonical/powerd", |
432 | + "com.canonical.powerd", |
433 | + "Wakeup", |
434 | + NULL, |
435 | + &error); |
436 | + if (error) { |
437 | + powerd_warn("Unable to emit wakeup signal: %s", error->message); |
438 | + g_error_free(error); |
439 | + } |
440 | +} |
441 | + |
442 | +void |
443 | ofono_manager_proxy_connect_cb(GObject *source_object, |
444 | GAsyncResult *res, |
445 | gpointer user_data) |
446 | |
447 | === modified file 'src/powerd.cpp' |
448 | --- src/powerd.cpp 2014-08-12 07:23:07 +0000 |
449 | +++ src/powerd.cpp 2014-08-19 19:23:22 +0000 |
450 | @@ -577,6 +577,7 @@ |
451 | powerd_autobrightness_init(); |
452 | powerd_sensors_init(); |
453 | powerd_ps_init(); |
454 | + wakeup_init(); |
455 | |
456 | main_loop = g_main_loop_new (NULL, FALSE); |
457 | signal(SIGTERM, sigterm_quit); |
458 | @@ -598,6 +599,7 @@ |
459 | g_bus_unown_name(name_id); |
460 | g_main_loop_unref(main_loop); |
461 | |
462 | + wakeup_deinit(); |
463 | powerd_ps_deinit(); |
464 | dbus_name_watch_deinit(); |
465 | powerd_autobrightness_deinit(); |
466 | |
467 | === added file 'src/wakeup.cpp' |
468 | --- src/wakeup.cpp 1970-01-01 00:00:00 +0000 |
469 | +++ src/wakeup.cpp 2014-08-19 19:23:22 +0000 |
470 | @@ -0,0 +1,188 @@ |
471 | +/* |
472 | + * Copyright 2014 Canonical Ltd. |
473 | + * |
474 | + * Authors: |
475 | + * Charles Kerr: charles.kerr@canonical.com |
476 | + * |
477 | + * This file is part of powerd. |
478 | + * |
479 | + * powerd is free software; you can redistribute it and/or modify |
480 | + * it under the terms of the GNU General Public License as published by |
481 | + * the Free Software Foundation; version 3. |
482 | + * |
483 | + * powerd is distributed in the hope that it will be useful, |
484 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
485 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
486 | + * GNU General Public License for more details. |
487 | + * |
488 | + * You should have received a copy of the GNU General Public License |
489 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
490 | + */ |
491 | + |
492 | + |
493 | +#include <ctime> |
494 | +#include <map> |
495 | +#include <memory> // std::unique_ptr |
496 | +#include <string> |
497 | +#include <thread> |
498 | + |
499 | +#include <glib.h> |
500 | + |
501 | +#include <ubuntu/hardware/alarm.h> |
502 | + |
503 | +#include "powerd-internal.h" |
504 | +#include "log.h" |
505 | + |
506 | +namespace |
507 | +{ |
508 | + |
509 | +struct Request |
510 | +{ |
511 | + std::string name; |
512 | + time_t time; |
513 | +}; |
514 | + |
515 | +std::map<std::string,Request> requests; |
516 | + |
517 | +UHardwareAlarm hardware_alarm = nullptr; |
518 | + |
519 | +// NB: only the main thread accesses 'worker' |
520 | +std::unique_ptr<std::thread> worker; |
521 | + |
522 | +void start_worker_thread(); |
523 | + |
524 | +void set_wakeup_time(time_t wakeup_time, const std::string& name) |
525 | +{ |
526 | + powerd_return_if_fail(hardware_alarm != nullptr); |
527 | + powerd_return_if_fail(wakeup_time >= time(nullptr)); |
528 | + |
529 | + struct tm tm; |
530 | + char buf[32]; |
531 | + localtime_r(&wakeup_time, &tm); |
532 | + strftime(buf, sizeof(buf), "%F %T", &tm); |
533 | + powerd_debug("setting hardware wakeup time to %s for %s", buf, name.c_str()); |
534 | + |
535 | + struct timespec sleep_interval; |
536 | + sleep_interval.tv_sec = wakeup_time; |
537 | + sleep_interval.tv_nsec = 0; |
538 | + u_hardware_alarm_set_relative_to_with_behavior( |
539 | + hardware_alarm, |
540 | + U_HARDWARE_ALARM_TIME_REFERENCE_RTC, |
541 | + U_HARDWARE_ALARM_SLEEP_BEHAVIOR_WAKEUP_DEVICE, |
542 | + &sleep_interval); |
543 | +} |
544 | + |
545 | +void reset_alarm_clock() |
546 | +{ |
547 | + // find request that will occur next |
548 | + const time_t now = time(nullptr); |
549 | + const Request* next = nullptr; |
550 | + size_t n_left = 0; |
551 | + for (const auto& it : requests) { |
552 | + if (now < it.second.time) { |
553 | + ++n_left; |
554 | + if (!next || (it.second.time < next->time)) |
555 | + next = &it.second; |
556 | + } |
557 | + } |
558 | + |
559 | + if (next != nullptr) |
560 | + { |
561 | + powerd_debug("%s found %zu remaining wakeup requests", G_STRFUNC, n_left); |
562 | + set_wakeup_time(next->time, next->name); |
563 | + if (!worker) |
564 | + start_worker_thread(); |
565 | + } |
566 | + else if (worker) // no pending requests... |
567 | + { |
568 | + powerd_debug("shortening wakeup_time so worker thread will finish soon"); |
569 | + set_wakeup_time(time(nullptr)+1, G_STRFUNC); |
570 | + } |
571 | +} |
572 | + |
573 | +gboolean on_worker_thread_finished(gpointer /*unused*/) |
574 | +{ |
575 | + // tell the world that we woke up |
576 | + powerd_wakeup_signal_emit(); |
577 | + |
578 | + // worker thread is done, so clean up our 'worker' variable |
579 | + powerd_debug("worker thread is finished working; calling join()"); |
580 | + worker->join(); |
581 | + worker.reset(); |
582 | + powerd_debug("worker thread is destroyed."); |
583 | + |
584 | + reset_alarm_clock(); |
585 | + |
586 | + return G_SOURCE_REMOVE; |
587 | +} |
588 | + |
589 | +void threadfunc(UHardwareAlarm hw_alarm) |
590 | +{ |
591 | + // wait for the next alarm |
592 | + powerd_debug("calling wait_for_next_alarm"); |
593 | + UHardwareAlarmWaitResult wait_result; |
594 | + auto rc = u_hardware_alarm_wait_for_next_alarm(hw_alarm, &wait_result); |
595 | + powerd_debug("worker thread finished waiting for hw alarm"); |
596 | + powerd_warn_if_fail(rc == U_STATUS_SUCCESS); |
597 | + u_hardware_alarm_unref(hw_alarm); |
598 | + |
599 | + // kick back to the main loop |
600 | + g_idle_add(on_worker_thread_finished, nullptr); |
601 | +} |
602 | + |
603 | +void start_worker_thread() |
604 | +{ |
605 | + powerd_return_if_fail(hardware_alarm != nullptr); |
606 | + |
607 | + powerd_debug("starting hardware alarm worker thread"); |
608 | + u_hardware_alarm_ref(hardware_alarm); |
609 | + worker.reset(new std::thread(threadfunc, hardware_alarm)); |
610 | +} |
611 | + |
612 | +} // private impl in unnamed namespace |
613 | + |
614 | +void |
615 | +wakeup_init(void) |
616 | +{ |
617 | + hardware_alarm = u_hardware_alarm_create(); |
618 | +} |
619 | + |
620 | +void |
621 | +wakeup_deinit(void) |
622 | +{ |
623 | + requests.clear(); |
624 | + reset_alarm_clock(); |
625 | + g_clear_pointer(&hardware_alarm, u_hardware_alarm_unref); |
626 | +} |
627 | + |
628 | +int |
629 | +wakeup_request(const char* name, time_t wakeup_time, powerd_cookie_t cookie) |
630 | +{ |
631 | + powerd_return_val_if_fail(hardware_alarm, ENOTSUP); |
632 | + powerd_return_val_if_fail(wakeup_time > time(nullptr), EINVAL); |
633 | + powerd_return_val_if_fail(cookie != NULL, EINVAL); |
634 | + |
635 | + // generate a new uuid string |
636 | + uuid_t tmp; |
637 | + uuid_generate(tmp); |
638 | + uuid_unparse(tmp, cookie); |
639 | + |
640 | + requests[cookie] = { name, wakeup_time }; |
641 | + |
642 | + reset_alarm_clock(); |
643 | + return 0; |
644 | +} |
645 | + |
646 | +int |
647 | +wakeup_clear(const powerd_cookie_t cookie) |
648 | +{ |
649 | + powerd_return_val_if_fail(hardware_alarm, ENOTSUP); |
650 | + auto it = requests.find(cookie); |
651 | + powerd_return_val_if_fail(it != requests.end(), EINVAL); |
652 | + |
653 | + requests.erase(it); |
654 | + |
655 | + reset_alarm_clock(); |
656 | + return 0; |
657 | +} |
658 | + |
PASSED: Continuous integration, rev:142 jenkins. qa.ubuntu. com/job/ powerd- ci/160/ jenkins. qa.ubuntu. com/job/ powerd- utopic- armhf-ci/ 12 jenkins. qa.ubuntu. com/job/ powerd- utopic- armhf-ci/ 12/artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/powerd- ci/160/ rebuild
http://