Merge lp:~sforshee/powerd/worker into lp:powerd

Proposed by Seth Forshee
Status: Merged
Approved by: Matt Fischer
Approved revision: 36
Merged at revision: 39
Proposed branch: lp:~sforshee/powerd/worker
Merge into: lp:powerd
Diff against target: 310 lines (+136/-32)
5 files modified
CMakeLists.txt (+1/-0)
src/power-request.c (+36/-32)
src/powerd-internal.h (+4/-0)
src/powerd.cpp (+19/-0)
src/util.c (+76/-0)
To merge this branch: bzr merge lp:~sforshee/powerd/worker
Reviewer Review Type Date Requested Status
Matt Fischer (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+168506@code.launchpad.net

Commit message

* Add powerd_run_mainloop_sync() for running a task on the main loop and waiting for it to complete
* Convert system request code to use powerd_run_mainloop_sync() rather than using mutexes

Description of the change

* Add powerd_run_mainloop_sync() for running a task on the main loop and waiting for it to complete
* Convert system request code to use powerd_run_mainloop_sync() rather than using mutexes

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Matt Fischer (mfisch) wrote :

Approved per IRC discussion. Coders need to avoid making the calls per comment and since the functions are static, I'm confident that other coders of powerd will respect that. We did discuss making a check function but it might be wasteful perf wise.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2013-06-06 21:25:50 +0000
3+++ CMakeLists.txt 2013-06-10 18:15:31 +0000
4@@ -38,6 +38,7 @@
5 src/powerd-object.c
6 src/power-request.c
7 src/powerd-sensors.cpp
8+ src/util.c
9 src/${GDBUS_NAME}.c
10 )
11
12
13=== modified file 'src/power-request.c'
14--- src/power-request.c 2013-06-04 20:07:30 +0000
15+++ src/power-request.c 2013-06-10 18:15:31 +0000
16@@ -60,15 +60,6 @@
17 static gint state_request_count[POWERD_NUM_POWER_STATES - 1];
18
19 /*
20- * Mutex to protect code accessing state_request_hash
21- *
22- * XXX: Try to move all access to main loop to eliminate need for mutex.
23- * Dbus calls are already processed from main loop, just need to move
24- * internal requests to be made there as well.
25- */
26-static GMutex state_request_mutex;
27-
28-/*
29 * States for "state transition" state machine.
30 *
31 * When no state transition is in progress we're in the idle state. When
32@@ -179,19 +170,21 @@
33 g_variant_builder_add(builder, "(sii)", sr->owner, sr->pid, sr->state);
34 }
35
36-/* internal callers should pass in NULL for the builder, its only used
37+/*
38+ * Must only be called from main loop.
39+ *
40+ * internal callers should pass in NULL for the builder, its only used
41 * by dbus callers. Returns a count of the total number of active
42- * requests. */
43+ * requests.
44+ */
45 static guint
46 list_sys_requests_internal(GVariantBuilder *builder)
47 {
48 guint count = 0;
49
50- g_mutex_lock(&state_request_mutex);
51 g_message("System state requests:");
52 g_hash_table_foreach(state_request_hash, list_request, builder);
53 count = g_hash_table_size(state_request_hash);
54- g_mutex_unlock(&state_request_mutex);
55
56 return count;
57 }
58@@ -227,6 +220,15 @@
59 return memcmp(sr_a->cookie, sr_b->cookie, sizeof(sr_a->cookie));
60 }
61
62+/* Should be called only on main loop */
63+static int request_sys_state_worker(gpointer data)
64+{
65+ struct SysStateRequest *sr = data;
66+ g_hash_table_insert(state_request_hash, sr->cookie, sr);
67+ state_request_count[sr->state - 1] += 1;
68+ return 0;
69+}
70+
71 /* Note: owner is NULL for internal usage */
72 gboolean
73 request_sys_state_internal(int state, int pid, uuid_t *cookie, const gchar *owner)
74@@ -257,11 +259,7 @@
75 uuid_generate(sr->cookie);
76 memcpy(*cookie, sr->cookie, sizeof(sr->cookie));
77
78- g_mutex_lock(&state_request_mutex);
79- g_hash_table_insert(state_request_hash, sr->cookie, sr);
80- state_request_count[state - 1] += 1;
81- g_mutex_unlock(&state_request_mutex);
82-
83+ powerd_run_mainloop_sync(request_sys_state_worker, sr);
84 update_system_state();
85 return TRUE;
86 }
87@@ -291,14 +289,13 @@
88 return TRUE;
89 }
90
91-gboolean
92-clear_sys_state_internal(uuid_t cookie)
93+/* Must only be called from main loop */
94+static int clear_sys_state_worker(gpointer data)
95 {
96+ unsigned char *uuid = data;
97 struct SysStateRequest *sr;
98- gboolean found = FALSE;
99- char cookie_str[UUID_STR_LEN];
100-
101- g_mutex_lock(&state_request_mutex);
102+ int found = FALSE;
103+ enum SysPowerStates state;
104
105 /*
106 * This involves two lookups into the hash, one to find the
107@@ -307,21 +304,29 @@
108 * way to do this; too bad g_hash_table_steal() doesn't return
109 * a pointer to the data.
110 */
111- sr = g_hash_table_lookup(state_request_hash, cookie);
112+ sr = g_hash_table_lookup(state_request_hash, uuid);
113 if (sr) {
114- enum SysPowerStates state = sr->state;
115- found = g_hash_table_remove(state_request_hash, cookie);
116+ state = sr->state;
117+ found = g_hash_table_remove(state_request_hash, uuid);
118 if (!found)
119 g_warning("State request found on lookup but not on remove");
120 else
121 state_request_count[state - 1] -= 1;
122 }
123- g_mutex_unlock(&state_request_mutex);
124-
125+
126+ return found;
127+}
128+
129+gboolean
130+clear_sys_state_internal(uuid_t cookie)
131+{
132+ char cookie_str[UUID_STR_LEN];
133+ int found;
134+
135+ found = powerd_run_mainloop_sync(clear_sys_state_worker, cookie);
136 if (!found) {
137 uuid_unparse(cookie, cookie_str);
138 g_warning("request (%s) not found", cookie_str);
139- g_mutex_unlock(&state_request_mutex);
140 return FALSE;
141 }
142
143@@ -357,19 +362,18 @@
144 return TRUE;
145 }
146
147+/* Must only be called from main loop */
148 static enum SysPowerStates max_requested_state(void)
149 {
150 enum SysPowerStates ret = POWERD_SYS_STATE_SUSPEND;
151 int i;
152
153- g_mutex_lock(&state_request_mutex);
154 for (i = POWERD_NUM_POWER_STATES - 1; i > POWERD_SYS_STATE_SUSPEND; i--) {
155 if (state_request_count[i - 1] != 0) {
156 ret = i;
157 break;
158 }
159 };
160- g_mutex_unlock(&state_request_mutex);
161
162 return ret;
163 }
164
165=== modified file 'src/powerd-internal.h'
166--- src/powerd-internal.h 2013-05-31 13:53:47 +0000
167+++ src/powerd-internal.h 2013-06-10 18:15:31 +0000
168@@ -41,6 +41,7 @@
169 void powerd_exit(void);
170 void powerd_reset_activity_timer(int add);
171 void powerd_dbus_init_complete(void);
172+int powerd_is_mainloop(void);
173
174 /* Display functions */
175 void powerd_brightness_set_value(gint value);
176@@ -83,6 +84,9 @@
177 void ofono_proxy_connect_cb(GObject *source_object, GAsyncResult *res,
178 gpointer user_data);
179
180+/* Utility functions */
181+int powerd_run_mainloop_sync(int (*func)(gpointer), gpointer data);
182+
183 #ifdef __cplusplus
184 }
185 #endif
186
187=== modified file 'src/powerd.cpp'
188--- src/powerd.cpp 2013-06-05 19:13:42 +0000
189+++ src/powerd.cpp 2013-06-10 18:15:31 +0000
190@@ -47,6 +47,8 @@
191
192 #include "libsuspend.h"
193
194+static GThread *powerd_mainloop_thread;
195+
196 namespace
197 {
198
199@@ -215,6 +217,20 @@
200 return g_variant_get_uint32(val);
201 }
202
203+/* Must be first to run on main loop */
204+static gboolean main_init(gpointer unused)
205+{
206+ powerd_mainloop_thread = g_thread_self();
207+ return FALSE;
208+}
209+
210+/* Returns TRUE if current thread of execution is the default main loop */
211+int powerd_is_mainloop(void)
212+{
213+ return (g_thread_self() == powerd_mainloop_thread);
214+}
215+
216+
217 int main(int argc, char** argv)
218 {
219 int i, ret;
220@@ -267,6 +283,9 @@
221 android_input_stack_initialize(&listener, &config);
222 android_input_stack_start();
223
224+ /* This needs to be the first thing to run on the main loop */
225+ g_idle_add_full(G_PRIORITY_HIGH, main_init, NULL, NULL);
226+
227 powerd_reset_activity_timer(1);
228
229 g_main_loop_run(main_loop);
230
231=== added file 'src/util.c'
232--- src/util.c 1970-01-01 00:00:00 +0000
233+++ src/util.c 2013-06-10 18:15:31 +0000
234@@ -0,0 +1,76 @@
235+/*
236+ * Copyright 2013 Canonical Ltd.
237+ *
238+ * This file is part of powerd.
239+ *
240+ * powerd is free software; you can redistribute it and/or modify
241+ * it under the terms of the GNU General Public License as published by
242+ * the Free Software Foundation; version 3.
243+ *
244+ * powerd is distributed in the hope that it will be useful,
245+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
246+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
247+ * GNU General Public License for more details.
248+ *
249+ * You should have received a copy of the GNU General Public License
250+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
251+ */
252+
253+#include <glib.h>
254+
255+struct sync_work_data {
256+ GCond cond;
257+ GMutex mutex;
258+ gboolean done;
259+ int (*func)(gpointer);
260+ gpointer data;
261+ int return_val;
262+};
263+
264+static gboolean run_mainloop_sync_worker(gpointer data)
265+{
266+ struct sync_work_data *work_data = data;
267+
268+ g_mutex_lock(&work_data->mutex);
269+ work_data->return_val = work_data->func(work_data->data);
270+ work_data->done = TRUE;
271+ g_cond_signal(&work_data->cond);
272+ g_mutex_unlock(&work_data->mutex);
273+
274+ return FALSE;
275+}
276+
277+static int __powerd_run_mainloop_sync(int (*func)(gpointer), gpointer data)
278+{
279+ struct sync_work_data work_data;
280+
281+ g_cond_init(&work_data.cond);
282+ g_mutex_init(&work_data.mutex);
283+ work_data.done = FALSE;
284+ work_data.func = func;
285+ work_data.data = data;
286+
287+ g_mutex_lock(&work_data.mutex);
288+ g_timeout_add(0, run_mainloop_sync_worker, &work_data);
289+ while (!work_data.done)
290+ g_cond_wait(&work_data.cond, &work_data.mutex);
291+ g_mutex_unlock(&work_data.mutex);
292+
293+ g_mutex_clear(&work_data.mutex);
294+ g_cond_clear(&work_data.cond);
295+
296+ return work_data.return_val;
297+}
298+
299+/*
300+ * Run the supplied function on the main loop, passing it the
301+ * supplied data, and wait for it to complete. If currently
302+ * executing on the main loop then the function is simply called
303+ * inline.
304+ */
305+int powerd_run_mainloop_sync(int (*func)(gpointer), gpointer data)
306+{
307+ if (powerd_is_mainloop())
308+ return func(data);
309+ return __powerd_run_mainloop_sync(func, data);
310+}

Subscribers

People subscribed via source and target branches