nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* GIO - GLib Input, Output and Streaming Library |
2 | * |
||
3 | * Copyright (C) 2006-2007 Red Hat, Inc. |
||
4 | * |
||
5 | * This library is free software; you can redistribute it and/or |
||
6 | * modify it under the terms of the GNU Lesser General Public |
||
7 | * License as published by the Free Software Foundation; either |
||
8 | * version 2 of the License, or (at your option) any later version. |
||
9 | * |
||
10 | * This library is distributed in the hope that it will be useful, |
||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
13 | * Lesser General Public License for more details. |
||
14 | * |
||
15 | * You should have received a copy of the GNU Lesser General |
||
16 | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
||
17 | * |
||
18 | * Author: Alexander Larsson <alexl@redhat.com> |
||
19 | */ |
||
20 | |||
21 | #include "config.h" |
||
22 | |||
23 | #include "gioscheduler.h" |
||
24 | #include "gcancellable.h" |
||
25 | #include "gtask.h" |
||
26 | |||
27 | /** |
||
28 | * SECTION:gioscheduler |
||
29 | * @short_description: I/O Scheduler |
||
30 | * @include: gio/gio.h |
||
31 | * |
||
32 | * As of GLib 2.36, #GIOScheduler is deprecated in favor of |
||
33 | * #GThreadPool and #GTask. |
||
34 | * |
||
35 | * Schedules asynchronous I/O operations. #GIOScheduler integrates |
||
36 | * into the main event loop (#GMainLoop) and uses threads. |
||
37 | */ |
||
38 | |||
39 | struct _GIOSchedulerJob { |
||
40 | GList *active_link; |
||
41 | GTask *task; |
||
42 | |||
43 | GIOSchedulerJobFunc job_func; |
||
44 | gpointer data; |
||
45 | GDestroyNotify destroy_notify; |
||
46 | |||
47 | GCancellable *cancellable; |
||
48 | gulong cancellable_id; |
||
49 | GMainContext *context; |
||
50 | }; |
||
51 | |||
52 | G_LOCK_DEFINE_STATIC(active_jobs); |
||
53 | static GList *active_jobs = NULL; |
||
54 | |||
55 | static void |
||
56 | g_io_job_free (GIOSchedulerJob *job) |
||
57 | { |
||
58 | if (job->destroy_notify) |
||
59 | job->destroy_notify (job->data); |
||
60 | |||
61 | G_LOCK (active_jobs); |
||
62 | active_jobs = g_list_delete_link (active_jobs, job->active_link); |
||
63 | G_UNLOCK (active_jobs); |
||
64 | |||
65 | if (job->cancellable) |
||
66 | g_object_unref (job->cancellable); |
||
67 | g_main_context_unref (job->context); |
||
68 | g_slice_free (GIOSchedulerJob, job); |
||
69 | } |
||
70 | |||
71 | static void |
||
72 | io_job_thread (GTask *task, |
||
73 | gpointer source_object, |
||
74 | gpointer task_data, |
||
75 | GCancellable *cancellable) |
||
76 | { |
||
77 | GIOSchedulerJob *job = task_data; |
||
78 | gboolean result; |
||
79 | |||
80 | if (job->cancellable) |
||
81 | g_cancellable_push_current (job->cancellable); |
||
82 | |||
83 | do |
||
84 | { |
||
85 | result = job->job_func (job, job->cancellable, job->data); |
||
86 | } |
||
87 | while (result); |
||
88 | |||
89 | if (job->cancellable) |
||
90 | g_cancellable_pop_current (job->cancellable); |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * g_io_scheduler_push_job: |
||
95 | * @job_func: a #GIOSchedulerJobFunc. |
||
96 | * @user_data: data to pass to @job_func |
||
97 | * @notify: (allow-none): a #GDestroyNotify for @user_data, or %NULL |
||
98 | * @io_priority: the [I/O priority][io-priority] |
||
99 | * of the request. |
||
100 | * @cancellable: optional #GCancellable object, %NULL to ignore. |
||
101 | * |
||
102 | * Schedules the I/O job to run in another thread. |
||
103 | * |
||
104 | * @notify will be called on @user_data after @job_func has returned, |
||
105 | * regardless whether the job was cancelled or has run to completion. |
||
106 | * |
||
107 | * If @cancellable is not %NULL, it can be used to cancel the I/O job |
||
108 | * by calling g_cancellable_cancel() or by calling |
||
109 | * g_io_scheduler_cancel_all_jobs(). |
||
110 | * |
||
111 | * Deprecated: use #GThreadPool or g_task_run_in_thread() |
||
112 | **/ |
||
113 | void |
||
114 | g_io_scheduler_push_job (GIOSchedulerJobFunc job_func, |
||
115 | gpointer user_data, |
||
116 | GDestroyNotify notify, |
||
117 | gint io_priority, |
||
118 | GCancellable *cancellable) |
||
119 | { |
||
120 | GIOSchedulerJob *job; |
||
121 | GTask *task; |
||
122 | |||
123 | g_return_if_fail (job_func != NULL); |
||
124 | |||
125 | job = g_slice_new0 (GIOSchedulerJob); |
||
126 | job->job_func = job_func; |
||
127 | job->data = user_data; |
||
128 | job->destroy_notify = notify; |
||
129 | |||
130 | if (cancellable) |
||
131 | job->cancellable = g_object_ref (cancellable); |
||
132 | |||
133 | job->context = g_main_context_ref_thread_default (); |
||
134 | |||
135 | G_LOCK (active_jobs); |
||
136 | active_jobs = g_list_prepend (active_jobs, job); |
||
137 | job->active_link = active_jobs; |
||
138 | G_UNLOCK (active_jobs); |
||
139 | |||
140 | task = g_task_new (NULL, cancellable, NULL, NULL); |
||
141 | g_task_set_task_data (task, job, (GDestroyNotify)g_io_job_free); |
||
142 | g_task_set_priority (task, io_priority); |
||
143 | g_task_run_in_thread (task, io_job_thread); |
||
144 | g_object_unref (task); |
||
145 | } |
||
146 | |||
147 | /** |
||
148 | * g_io_scheduler_cancel_all_jobs: |
||
149 | * |
||
150 | * Cancels all cancellable I/O jobs. |
||
151 | * |
||
152 | * A job is cancellable if a #GCancellable was passed into |
||
153 | * g_io_scheduler_push_job(). |
||
154 | * |
||
155 | * Deprecated: You should never call this function, since you don't |
||
156 | * know how other libraries in your program might be making use of |
||
157 | * gioscheduler. |
||
158 | **/ |
||
159 | void |
||
160 | g_io_scheduler_cancel_all_jobs (void) |
||
161 | { |
||
162 | GList *cancellable_list, *l; |
||
163 | |||
164 | G_LOCK (active_jobs); |
||
165 | cancellable_list = NULL; |
||
166 | for (l = active_jobs; l != NULL; l = l->next) |
||
167 | { |
||
168 | GIOSchedulerJob *job = l->data; |
||
169 | if (job->cancellable) |
||
170 | cancellable_list = g_list_prepend (cancellable_list, |
||
171 | g_object_ref (job->cancellable)); |
||
172 | } |
||
173 | G_UNLOCK (active_jobs); |
||
174 | |||
175 | for (l = cancellable_list; l != NULL; l = l->next) |
||
176 | { |
||
177 | GCancellable *c = l->data; |
||
178 | g_cancellable_cancel (c); |
||
179 | g_object_unref (c); |
||
180 | } |
||
181 | g_list_free (cancellable_list); |
||
182 | } |
||
183 | |||
184 | typedef struct { |
||
185 | GSourceFunc func; |
||
186 | gboolean ret_val; |
||
187 | gpointer data; |
||
188 | GDestroyNotify notify; |
||
189 | |||
190 | GMutex ack_lock; |
||
191 | GCond ack_condition; |
||
192 | gboolean ack; |
||
193 | } MainLoopProxy; |
||
194 | |||
195 | static gboolean |
||
196 | mainloop_proxy_func (gpointer data) |
||
197 | { |
||
198 | MainLoopProxy *proxy = data; |
||
199 | |||
200 | proxy->ret_val = proxy->func (proxy->data); |
||
201 | |||
202 | if (proxy->notify) |
||
203 | proxy->notify (proxy->data); |
||
204 | |||
205 | g_mutex_lock (&proxy->ack_lock); |
||
206 | proxy->ack = TRUE; |
||
207 | g_cond_signal (&proxy->ack_condition); |
||
208 | g_mutex_unlock (&proxy->ack_lock); |
||
209 | |||
210 | return FALSE; |
||
211 | } |
||
212 | |||
213 | static void |
||
214 | mainloop_proxy_free (MainLoopProxy *proxy) |
||
215 | { |
||
216 | g_mutex_clear (&proxy->ack_lock); |
||
217 | g_cond_clear (&proxy->ack_condition); |
||
218 | g_free (proxy); |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * g_io_scheduler_job_send_to_mainloop: |
||
223 | * @job: a #GIOSchedulerJob |
||
224 | * @func: a #GSourceFunc callback that will be called in the original thread |
||
225 | * @user_data: data to pass to @func |
||
226 | * @notify: (allow-none): a #GDestroyNotify for @user_data, or %NULL |
||
227 | * |
||
228 | * Used from an I/O job to send a callback to be run in the thread |
||
229 | * that the job was started from, waiting for the result (and thus |
||
230 | * blocking the I/O job). |
||
231 | * |
||
232 | * Returns: The return value of @func |
||
233 | * |
||
234 | * Deprecated: Use g_main_context_invoke(). |
||
235 | **/ |
||
236 | gboolean |
||
237 | g_io_scheduler_job_send_to_mainloop (GIOSchedulerJob *job, |
||
238 | GSourceFunc func, |
||
239 | gpointer user_data, |
||
240 | GDestroyNotify notify) |
||
241 | { |
||
242 | GSource *source; |
||
243 | MainLoopProxy *proxy; |
||
244 | gboolean ret_val; |
||
245 | |||
246 | g_return_val_if_fail (job != NULL, FALSE); |
||
247 | g_return_val_if_fail (func != NULL, FALSE); |
||
248 | |||
249 | proxy = g_new0 (MainLoopProxy, 1); |
||
250 | proxy->func = func; |
||
251 | proxy->data = user_data; |
||
252 | proxy->notify = notify; |
||
253 | g_mutex_init (&proxy->ack_lock); |
||
254 | g_cond_init (&proxy->ack_condition); |
||
255 | g_mutex_lock (&proxy->ack_lock); |
||
256 | |||
257 | source = g_idle_source_new (); |
||
258 | g_source_set_priority (source, G_PRIORITY_DEFAULT); |
||
259 | g_source_set_callback (source, mainloop_proxy_func, proxy, |
||
260 | NULL); |
||
261 | g_source_set_name (source, "[gio] mainloop_proxy_func"); |
||
262 | |||
263 | g_source_attach (source, job->context); |
||
264 | g_source_unref (source); |
||
265 | |||
266 | while (!proxy->ack) |
||
267 | g_cond_wait (&proxy->ack_condition, &proxy->ack_lock); |
||
268 | g_mutex_unlock (&proxy->ack_lock); |
||
269 | |||
270 | ret_val = proxy->ret_val; |
||
271 | mainloop_proxy_free (proxy); |
||
272 | |||
273 | return ret_val; |
||
274 | } |
||
275 | |||
276 | /** |
||
277 | * g_io_scheduler_job_send_to_mainloop_async: |
||
278 | * @job: a #GIOSchedulerJob |
||
279 | * @func: a #GSourceFunc callback that will be called in the original thread |
||
280 | * @user_data: data to pass to @func |
||
281 | * @notify: (allow-none): a #GDestroyNotify for @user_data, or %NULL |
||
282 | * |
||
283 | * Used from an I/O job to send a callback to be run asynchronously in |
||
284 | * the thread that the job was started from. The callback will be run |
||
285 | * when the main loop is available, but at that time the I/O job might |
||
286 | * have finished. The return value from the callback is ignored. |
||
287 | * |
||
288 | * Note that if you are passing the @user_data from g_io_scheduler_push_job() |
||
289 | * on to this function you have to ensure that it is not freed before |
||
290 | * @func is called, either by passing %NULL as @notify to |
||
291 | * g_io_scheduler_push_job() or by using refcounting for @user_data. |
||
292 | * |
||
293 | * Deprecated: Use g_main_context_invoke(). |
||
294 | **/ |
||
295 | void |
||
296 | g_io_scheduler_job_send_to_mainloop_async (GIOSchedulerJob *job, |
||
297 | GSourceFunc func, |
||
298 | gpointer user_data, |
||
299 | GDestroyNotify notify) |
||
300 | { |
||
301 | GSource *source; |
||
302 | MainLoopProxy *proxy; |
||
303 | |||
304 | g_return_if_fail (job != NULL); |
||
305 | g_return_if_fail (func != NULL); |
||
306 | |||
307 | proxy = g_new0 (MainLoopProxy, 1); |
||
308 | proxy->func = func; |
||
309 | proxy->data = user_data; |
||
310 | proxy->notify = notify; |
||
311 | g_mutex_init (&proxy->ack_lock); |
||
312 | g_cond_init (&proxy->ack_condition); |
||
313 | |||
314 | source = g_idle_source_new (); |
||
315 | g_source_set_priority (source, G_PRIORITY_DEFAULT); |
||
316 | g_source_set_callback (source, mainloop_proxy_func, proxy, |
||
317 | (GDestroyNotify)mainloop_proxy_free); |
||
318 | g_source_set_name (source, "[gio] mainloop_proxy_func"); |
||
319 | |||
320 | g_source_attach (source, job->context); |
||
321 | g_source_unref (source); |
||
322 | } |