blob: d61829baf863385689f2d412a51e63370b0fddf0 [file] [log] [blame]
Wim Taymansc2f41a82005-03-21 17:34:02 +00001/* GStreamer
2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2005 Wim Taymans <wim@fluendo.com>
4 *
5 * gsttask.c: Streaming tasks
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
Wim Taymans9e28a122005-10-20 19:30:57 +000023/**
24 * SECTION:gsttask
25 * @short_description: Abstraction of GStreamer streaming threads.
26 * @see_also: #GstElement, #GstPad
27 *
Wim Taymans5151ea32005-11-09 16:32:49 +000028 * #GstTask is used by #GstElement and #GstPad to provide the data passing
29 * threads in a #GstPipeline.
Wim Taymans9e28a122005-10-20 19:30:57 +000030 *
Wim Taymans5151ea32005-11-09 16:32:49 +000031 * A #GstPad will typically start a #GstTask to push or pull data to/from the
32 * peer pads. Most source elements start a #GstTask to push data. In some cases
33 * a demuxer element can start a #GstTask to pull data from a peer element. This
Wim Taymans9e28a122005-10-20 19:30:57 +000034 * is typically done when the demuxer can perform random access on the upstream
35 * peer element for improved performance.
36 *
Wim Taymans5151ea32005-11-09 16:32:49 +000037 * Although convenience functions exist on #GstPad to start/pause/stop tasks, it
38 * might sometimes be needed to create a #GstTask manually if it is not related to
39 * a #GstPad.
Wim Taymans9e28a122005-10-20 19:30:57 +000040 *
Wim Taymans5151ea32005-11-09 16:32:49 +000041 * Before the #GstTask can be run, it needs a #GStaticRecMutex that can be set with
Wim Taymans9e28a122005-10-20 19:30:57 +000042 * gst_task_set_lock().
43 *
44 * The task can be started, paused and stopped with gst_task_start(), gst_task_pause()
45 * and gst_task_stop() respectively.
46 *
Wim Taymans5151ea32005-11-09 16:32:49 +000047 * A #GstTask will repeadedly call the #GstTaskFunction with the user data
Wim Taymans9e28a122005-10-20 19:30:57 +000048 * that was provided when creating the task with gst_task_create(). Before calling
49 * the function it will acquire the provided lock.
50 *
51 * Stopping a task with gst_task_stop() will not immediatly make sure the task is
Wim Taymans5151ea32005-11-09 16:32:49 +000052 * not running anymore. Use gst_task_join() to make sure the task is completely
Wim Taymans9e28a122005-10-20 19:30:57 +000053 * stopped and the thread is stopped.
54 *
Wim Taymans5151ea32005-11-09 16:32:49 +000055 * After creating a #GstTask, use gst_object_unref() to free its resources. This can
Wim Taymans9e28a122005-10-20 19:30:57 +000056 * only be done it the task is not running anymore.
Wim Taymans5151ea32005-11-09 16:32:49 +000057 *
Wim Taymans2681eae2006-02-13 17:03:23 +000058 * Last reviewed on 2006-02-13 (0.10.4)
Wim Taymans9e28a122005-10-20 19:30:57 +000059 */
60
Wim Taymansc2f41a82005-03-21 17:34:02 +000061#include "gst_private.h"
62
63#include "gstinfo.h"
64#include "gsttask.h"
65
Thomas Vander Stichele92f49012005-10-15 19:57:03 +000066GST_DEBUG_CATEGORY_STATIC (task_debug);
Wim Taymans1e40e472005-08-24 20:49:53 +000067#define GST_CAT_DEFAULT (task_debug)
68
Wim Taymansc2f41a82005-03-21 17:34:02 +000069static void gst_task_class_init (GstTaskClass * klass);
70static void gst_task_init (GstTask * task);
Wim Taymanse1aeec62005-07-18 12:49:53 +000071static void gst_task_finalize (GObject * object);
72
73static void gst_task_func (GstTask * task, GstTaskClass * tclass);
Wim Taymansc2f41a82005-03-21 17:34:02 +000074
75static GstObjectClass *parent_class = NULL;
76
Wim Taymans1e40e472005-08-24 20:49:53 +000077static GStaticMutex pool_lock = G_STATIC_MUTEX_INIT;
78
Wim Taymansc2f41a82005-03-21 17:34:02 +000079GType
80gst_task_get_type (void)
81{
82 static GType _gst_task_type = 0;
83
Wim Taymansa1939812006-02-28 10:52:02 +000084 if (G_UNLIKELY (_gst_task_type == 0)) {
Wim Taymansc2f41a82005-03-21 17:34:02 +000085 static const GTypeInfo task_info = {
86 sizeof (GstTaskClass),
87 NULL,
88 NULL,
89 (GClassInitFunc) gst_task_class_init,
90 NULL,
91 NULL,
92 sizeof (GstTask),
93 0,
94 (GInstanceInitFunc) gst_task_init,
95 NULL
96 };
97
98 _gst_task_type =
Wim Taymanse1aeec62005-07-18 12:49:53 +000099 g_type_register_static (GST_TYPE_OBJECT, "GstTask", &task_info, 0);
Wim Taymans1e40e472005-08-24 20:49:53 +0000100
101 GST_DEBUG_CATEGORY_INIT (task_debug, "task", 0, "Processing tasks");
Wim Taymansc2f41a82005-03-21 17:34:02 +0000102 }
103 return _gst_task_type;
104}
105
106static void
107gst_task_class_init (GstTaskClass * klass)
108{
109 GObjectClass *gobject_class;
110
111 gobject_class = (GObjectClass *) klass;
112
Stefan Kost77a56952006-04-08 20:57:31 +0000113 parent_class = g_type_class_peek_parent (klass);
Wim Taymansc2f41a82005-03-21 17:34:02 +0000114
Wim Taymanse1aeec62005-07-18 12:49:53 +0000115 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_task_finalize);
116
117 klass->pool = g_thread_pool_new (
118 (GFunc) gst_task_func, klass, -1, FALSE, NULL);
Wim Taymansc2f41a82005-03-21 17:34:02 +0000119}
120
121static void
122gst_task_init (GstTask * task)
123{
Wim Taymans1e40e472005-08-24 20:49:53 +0000124 task->running = FALSE;
Wim Taymans2681eae2006-02-13 17:03:23 +0000125 task->abidata.ABI.thread = NULL;
Wim Taymansadd280c2005-05-25 11:50:11 +0000126 task->lock = NULL;
Wim Taymansc2f41a82005-03-21 17:34:02 +0000127 task->cond = g_cond_new ();
128 task->state = GST_TASK_STOPPED;
129}
130
131static void
Wim Taymanse1aeec62005-07-18 12:49:53 +0000132gst_task_finalize (GObject * object)
Wim Taymansc2f41a82005-03-21 17:34:02 +0000133{
134 GstTask *task = GST_TASK (object);
135
Wim Taymanse1aeec62005-07-18 12:49:53 +0000136 GST_DEBUG ("task %p finalize", task);
Wim Taymansc2f41a82005-03-21 17:34:02 +0000137
Wim Taymanse1a166a2005-10-21 11:36:32 +0000138 /* task thread cannot be running here since it holds a ref
139 * to the task so that the finalize could not have happened */
Wim Taymansc2f41a82005-03-21 17:34:02 +0000140 g_cond_free (task->cond);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000141 task->cond = NULL;
Wim Taymansc2f41a82005-03-21 17:34:02 +0000142
Wim Taymans74c68bb2005-08-25 10:01:47 +0000143 G_OBJECT_CLASS (parent_class)->finalize (object);
Wim Taymansc2f41a82005-03-21 17:34:02 +0000144}
145
Wim Taymanse1aeec62005-07-18 12:49:53 +0000146static void
147gst_task_func (GstTask * task, GstTaskClass * tclass)
148{
Wim Taymans1e40e472005-08-24 20:49:53 +0000149 GStaticRecMutex *lock;
Wim Taymans2681eae2006-02-13 17:03:23 +0000150 GThread *tself;
Wim Taymans1e40e472005-08-24 20:49:53 +0000151
Wim Taymans2681eae2006-02-13 17:03:23 +0000152 tself = g_thread_self ();
153
154 GST_DEBUG ("Entering task %p, thread %p", task, tself);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000155
Wim Taymans1e40e472005-08-24 20:49:53 +0000156 /* we have to grab the lock to get the mutex. We also
157 * mark our state running so that nobody can mess with
158 * the mutex. */
Andy Wingo44c548b2005-11-21 16:34:26 +0000159 GST_OBJECT_LOCK (task);
Wim Taymans1e40e472005-08-24 20:49:53 +0000160 if (task->state == GST_TASK_STOPPED)
161 goto exit;
162 lock = GST_TASK_GET_LOCK (task);
Wim Taymans2681eae2006-02-13 17:03:23 +0000163 if (G_UNLIKELY (lock == NULL))
164 goto no_lock;
Wim Taymans1e40e472005-08-24 20:49:53 +0000165 task->running = TRUE;
Wim Taymans2681eae2006-02-13 17:03:23 +0000166 task->abidata.ABI.thread = tself;
Andy Wingo44c548b2005-11-21 16:34:26 +0000167 GST_OBJECT_UNLOCK (task);
Wim Taymans1e40e472005-08-24 20:49:53 +0000168
Wim Taymanse1aeec62005-07-18 12:49:53 +0000169 /* locking order is TASK_LOCK, LOCK */
Wim Taymans1e40e472005-08-24 20:49:53 +0000170 g_static_rec_mutex_lock (lock);
Andy Wingo44c548b2005-11-21 16:34:26 +0000171 GST_OBJECT_LOCK (task);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000172 while (G_LIKELY (task->state != GST_TASK_STOPPED)) {
173 while (G_UNLIKELY (task->state == GST_TASK_PAUSED)) {
174 gint t;
175
Wim Taymans1e40e472005-08-24 20:49:53 +0000176 t = g_static_rec_mutex_unlock_full (lock);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000177 if (t <= 0) {
178 g_warning ("wrong STREAM_LOCK count %d", t);
179 }
180 GST_TASK_SIGNAL (task);
181 GST_TASK_WAIT (task);
Andy Wingo44c548b2005-11-21 16:34:26 +0000182 GST_OBJECT_UNLOCK (task);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000183 /* locking order.. */
184 if (t > 0)
Wim Taymans1e40e472005-08-24 20:49:53 +0000185 g_static_rec_mutex_lock_full (lock, t);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000186
Andy Wingo44c548b2005-11-21 16:34:26 +0000187 GST_OBJECT_LOCK (task);
Wim Taymanse1a166a2005-10-21 11:36:32 +0000188 if (G_UNLIKELY (task->state == GST_TASK_STOPPED))
Wim Taymanse1aeec62005-07-18 12:49:53 +0000189 goto done;
190 }
Andy Wingo44c548b2005-11-21 16:34:26 +0000191 GST_OBJECT_UNLOCK (task);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000192
193 task->func (task->data);
194
Andy Wingo44c548b2005-11-21 16:34:26 +0000195 GST_OBJECT_LOCK (task);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000196 }
197done:
Andy Wingo44c548b2005-11-21 16:34:26 +0000198 GST_OBJECT_UNLOCK (task);
Wim Taymans1e40e472005-08-24 20:49:53 +0000199 g_static_rec_mutex_unlock (lock);
200
201 /* now we allow messing with the lock again */
Andy Wingo44c548b2005-11-21 16:34:26 +0000202 GST_OBJECT_LOCK (task);
Wim Taymans1e40e472005-08-24 20:49:53 +0000203 task->running = FALSE;
Wim Taymans2681eae2006-02-13 17:03:23 +0000204 task->abidata.ABI.thread = NULL;
Wim Taymans1e40e472005-08-24 20:49:53 +0000205exit:
206 GST_TASK_SIGNAL (task);
Andy Wingo44c548b2005-11-21 16:34:26 +0000207 GST_OBJECT_UNLOCK (task);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000208
209 GST_DEBUG ("Exit task %p, thread %p", task, g_thread_self ());
210
211 gst_object_unref (task);
Wim Taymans2681eae2006-02-13 17:03:23 +0000212 return;
213
214no_lock:
215 {
216 g_warning ("starting task without a lock");
217 goto exit;
218 }
Wim Taymanse1aeec62005-07-18 12:49:53 +0000219}
220
Wim Taymansc2f41a82005-03-21 17:34:02 +0000221/**
Wim Taymans1e40e472005-08-24 20:49:53 +0000222 * gst_task_cleanup_all:
223 *
224 * Wait for all tasks to be stopped. This is mainly used internally
225 * to ensure proper cleanup of internal datastructures in testsuites.
226 *
227 * MT safe.
228 */
229void
230gst_task_cleanup_all (void)
231{
232 GstTaskClass *klass;
233
234 if ((klass = g_type_class_peek (GST_TYPE_TASK))) {
235 g_static_mutex_lock (&pool_lock);
236 if (klass->pool) {
237 /* Shut down all the threads, we still process the ones scheduled
238 * because the unref happens in the thread function.
239 * Also wait for currently running ones to finish. */
240 g_thread_pool_free (klass->pool, FALSE, TRUE);
241 /* create new pool, so we can still do something after this
242 * call. */
243 klass->pool = g_thread_pool_new (
244 (GFunc) gst_task_func, klass, -1, FALSE, NULL);
245 }
246 g_static_mutex_unlock (&pool_lock);
247 }
248}
249
250/**
Wim Taymansc2f41a82005-03-21 17:34:02 +0000251 * gst_task_create:
252 * @func: The #GstTaskFunction to use
253 * @data: User data to pass to @func
254 *
255 * Create a new Task that will repeadedly call the provided @func
256 * with @data as a parameter. Typically the task will run in
257 * a new thread.
258 *
259 * Returns: A new #GstTask.
260 *
261 * MT safe.
262 */
263GstTask *
264gst_task_create (GstTaskFunction func, gpointer data)
265{
Wim Taymanse1aeec62005-07-18 12:49:53 +0000266 GstTask *task;
267
268 task = g_object_new (GST_TYPE_TASK, NULL);
269 task->func = func;
270 task->data = data;
271
272 GST_DEBUG ("Created task %p", task);
273
274 return task;
Wim Taymansc2f41a82005-03-21 17:34:02 +0000275}
276
277/**
Wim Taymansadd280c2005-05-25 11:50:11 +0000278 * gst_task_set_lock:
279 * @task: The #GstTask to use
280 * @mutex: The GMutex to use
281 *
Wim Taymanse1a166a2005-10-21 11:36:32 +0000282 * Set the mutex used by the task. The mutex will be acquired before
283 * calling the #GstTaskFunction.
Wim Taymansadd280c2005-05-25 11:50:11 +0000284 *
Wim Taymans2681eae2006-02-13 17:03:23 +0000285 * This function has to be called before calling gst_task_pause() or
286 * gst_task_start().
287 *
Wim Taymansadd280c2005-05-25 11:50:11 +0000288 * MT safe.
289 */
290void
291gst_task_set_lock (GstTask * task, GStaticRecMutex * mutex)
292{
Andy Wingo44c548b2005-11-21 16:34:26 +0000293 GST_OBJECT_LOCK (task);
Wim Taymans1e40e472005-08-24 20:49:53 +0000294 if (task->running)
295 goto is_running;
296 GST_TASK_GET_LOCK (task) = mutex;
Andy Wingo44c548b2005-11-21 16:34:26 +0000297 GST_OBJECT_UNLOCK (task);
Wim Taymans1e40e472005-08-24 20:49:53 +0000298
299 return;
300
301 /* ERRORS */
302is_running:
303 {
Andy Wingo44c548b2005-11-21 16:34:26 +0000304 GST_OBJECT_UNLOCK (task);
Wim Taymans2681eae2006-02-13 17:03:23 +0000305 g_warning ("cannot call set_lock on a running task");
Wim Taymans1e40e472005-08-24 20:49:53 +0000306 }
Wim Taymansadd280c2005-05-25 11:50:11 +0000307}
308
309
310/**
Wim Taymansc2f41a82005-03-21 17:34:02 +0000311 * gst_task_get_state:
312 * @task: The #GstTask to query
313 *
314 * Get the current state of the task.
315 *
316 * Returns: The #GstTaskState of the task
317 *
318 * MT safe.
319 */
320GstTaskState
321gst_task_get_state (GstTask * task)
322{
323 GstTaskState result;
324
325 g_return_val_if_fail (GST_IS_TASK (task), GST_TASK_STOPPED);
326
Andy Wingo44c548b2005-11-21 16:34:26 +0000327 GST_OBJECT_LOCK (task);
Wim Taymansc2f41a82005-03-21 17:34:02 +0000328 result = task->state;
Andy Wingo44c548b2005-11-21 16:34:26 +0000329 GST_OBJECT_UNLOCK (task);
Wim Taymansc2f41a82005-03-21 17:34:02 +0000330
331 return result;
332}
333
334/**
335 * gst_task_start:
336 * @task: The #GstTask to start
337 *
Wim Taymanse1a166a2005-10-21 11:36:32 +0000338 * Starts @task. The @task must have a lock associated with it using
Wim Taymans5151ea32005-11-09 16:32:49 +0000339 * gst_task_set_lock() or thsi function will return FALSE.
Wim Taymansc2f41a82005-03-21 17:34:02 +0000340 *
341 * Returns: TRUE if the task could be started.
342 *
343 * MT safe.
344 */
345gboolean
346gst_task_start (GstTask * task)
347{
Wim Taymanse1aeec62005-07-18 12:49:53 +0000348 GstTaskState old;
Wim Taymansc2f41a82005-03-21 17:34:02 +0000349
350 g_return_val_if_fail (GST_IS_TASK (task), FALSE);
351
Wim Taymanse1aeec62005-07-18 12:49:53 +0000352 GST_DEBUG_OBJECT (task, "Starting task %p", task);
Wim Taymansc2f41a82005-03-21 17:34:02 +0000353
Andy Wingo44c548b2005-11-21 16:34:26 +0000354 GST_OBJECT_LOCK (task);
Wim Taymans1e40e472005-08-24 20:49:53 +0000355 if (G_UNLIKELY (GST_TASK_GET_LOCK (task) == NULL))
356 goto no_lock;
Wim Taymanse1aeec62005-07-18 12:49:53 +0000357
358 old = task->state;
359 task->state = GST_TASK_STARTED;
360 switch (old) {
361 case GST_TASK_STOPPED:
Wim Taymans1e40e472005-08-24 20:49:53 +0000362 {
363 GstTaskClass *tclass;
364
365 tclass = GST_TASK_GET_CLASS (task);
366
367 /* new task, push on threadpool. We ref before so
368 * that it remains alive while on the threadpool. */
Wim Taymanse1aeec62005-07-18 12:49:53 +0000369 gst_object_ref (task);
Wim Taymans1e40e472005-08-24 20:49:53 +0000370 g_static_mutex_lock (&pool_lock);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000371 g_thread_pool_push (tclass->pool, task, NULL);
Wim Taymans1e40e472005-08-24 20:49:53 +0000372 g_static_mutex_unlock (&pool_lock);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000373 break;
Wim Taymans1e40e472005-08-24 20:49:53 +0000374 }
Wim Taymanse1aeec62005-07-18 12:49:53 +0000375 case GST_TASK_PAUSED:
Wim Taymans1e40e472005-08-24 20:49:53 +0000376 /* PAUSE to PLAY, signal */
Wim Taymanse1aeec62005-07-18 12:49:53 +0000377 GST_TASK_SIGNAL (task);
378 break;
379 case GST_TASK_STARTED:
Wim Taymans1e40e472005-08-24 20:49:53 +0000380 /* was OK */
Wim Taymanse1aeec62005-07-18 12:49:53 +0000381 break;
382 }
Andy Wingo44c548b2005-11-21 16:34:26 +0000383 GST_OBJECT_UNLOCK (task);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000384
385 return TRUE;
Wim Taymans1e40e472005-08-24 20:49:53 +0000386
387 /* ERRORS */
388no_lock:
389 {
Wim Taymans2681eae2006-02-13 17:03:23 +0000390 GST_WARNING_OBJECT (task, "starting task without a lock");
391 GST_OBJECT_UNLOCK (task);
Wim Taymans1e40e472005-08-24 20:49:53 +0000392 g_warning ("starting task without a lock");
393 return FALSE;
394 }
Wim Taymansc2f41a82005-03-21 17:34:02 +0000395}
396
397/**
398 * gst_task_stop:
399 * @task: The #GstTask to stop
400 *
Wim Taymanse1a166a2005-10-21 11:36:32 +0000401 * Stops @task. This method merely schedules the task to stop and
402 * will not wait for the task to have completely stopped. Use
Wim Taymans5151ea32005-11-09 16:32:49 +0000403 * gst_task_join() to stop and wait for completion.
Wim Taymansc2f41a82005-03-21 17:34:02 +0000404 *
405 * Returns: TRUE if the task could be stopped.
406 *
407 * MT safe.
408 */
409gboolean
410gst_task_stop (GstTask * task)
411{
412 GstTaskClass *tclass;
Wim Taymanse1aeec62005-07-18 12:49:53 +0000413 GstTaskState old;
Wim Taymansc2f41a82005-03-21 17:34:02 +0000414
415 g_return_val_if_fail (GST_IS_TASK (task), FALSE);
416
417 tclass = GST_TASK_GET_CLASS (task);
418
Wim Taymanse1aeec62005-07-18 12:49:53 +0000419 GST_DEBUG_OBJECT (task, "Stopping task %p", task);
Wim Taymansc2f41a82005-03-21 17:34:02 +0000420
Andy Wingo44c548b2005-11-21 16:34:26 +0000421 GST_OBJECT_LOCK (task);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000422 old = task->state;
423 task->state = GST_TASK_STOPPED;
424 switch (old) {
425 case GST_TASK_STOPPED:
426 break;
427 case GST_TASK_PAUSED:
428 GST_TASK_SIGNAL (task);
429 break;
430 case GST_TASK_STARTED:
431 break;
432 }
Andy Wingo44c548b2005-11-21 16:34:26 +0000433 GST_OBJECT_UNLOCK (task);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000434
435 return TRUE;
Wim Taymansc2f41a82005-03-21 17:34:02 +0000436}
437
438/**
439 * gst_task_pause:
440 * @task: The #GstTask to pause
441 *
Wim Taymanse1a166a2005-10-21 11:36:32 +0000442 * Pauses @task. This method can also be called on a task in the
443 * stopped state, in which case a thread will be started and will remain
444 * in the paused state. This function does not wait for the task to complete
445 * the paused state.
Wim Taymansc2f41a82005-03-21 17:34:02 +0000446 *
447 * Returns: TRUE if the task could be paused.
448 *
449 * MT safe.
450 */
451gboolean
452gst_task_pause (GstTask * task)
453{
Wim Taymanse1aeec62005-07-18 12:49:53 +0000454 GstTaskState old;
Wim Taymansc2f41a82005-03-21 17:34:02 +0000455
456 g_return_val_if_fail (GST_IS_TASK (task), FALSE);
457
Wim Taymanse1aeec62005-07-18 12:49:53 +0000458 GST_DEBUG_OBJECT (task, "Pausing task %p", task);
Wim Taymansc2f41a82005-03-21 17:34:02 +0000459
Andy Wingo44c548b2005-11-21 16:34:26 +0000460 GST_OBJECT_LOCK (task);
Wim Taymans2681eae2006-02-13 17:03:23 +0000461 if (G_UNLIKELY (GST_TASK_GET_LOCK (task) == NULL))
462 goto no_lock;
463
Wim Taymanse1aeec62005-07-18 12:49:53 +0000464 old = task->state;
465 task->state = GST_TASK_PAUSED;
466 switch (old) {
467 case GST_TASK_STOPPED:
Wim Taymans1e40e472005-08-24 20:49:53 +0000468 {
469 GstTaskClass *tclass;
470
471 tclass = GST_TASK_GET_CLASS (task);
472
Wim Taymanse1aeec62005-07-18 12:49:53 +0000473 gst_object_ref (task);
Wim Taymans1e40e472005-08-24 20:49:53 +0000474 g_static_mutex_lock (&pool_lock);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000475 g_thread_pool_push (tclass->pool, task, NULL);
Wim Taymans1e40e472005-08-24 20:49:53 +0000476 g_static_mutex_unlock (&pool_lock);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000477 break;
Wim Taymans1e40e472005-08-24 20:49:53 +0000478 }
Wim Taymanse1aeec62005-07-18 12:49:53 +0000479 case GST_TASK_PAUSED:
480 break;
481 case GST_TASK_STARTED:
482 break;
483 }
Andy Wingo44c548b2005-11-21 16:34:26 +0000484 GST_OBJECT_UNLOCK (task);
Wim Taymanse1aeec62005-07-18 12:49:53 +0000485
486 return TRUE;
Wim Taymans2681eae2006-02-13 17:03:23 +0000487
488 /* ERRORS */
489no_lock:
490 {
491 GST_WARNING_OBJECT (task, "pausing task without a lock");
492 GST_OBJECT_UNLOCK (task);
493 g_warning ("pausing task without a lock");
494 return FALSE;
495 }
Wim Taymansc2f41a82005-03-21 17:34:02 +0000496}
Wim Taymans1e40e472005-08-24 20:49:53 +0000497
498/**
499 * gst_task_join:
500 * @task: The #GstTask to join
501 *
502 * Joins @task. After this call, it is safe to unref the task
Wim Taymans5151ea32005-11-09 16:32:49 +0000503 * and clean up the lock set with gst_task_set_lock().
Wim Taymans1e40e472005-08-24 20:49:53 +0000504 *
505 * The task will automatically be stopped with this call.
506 *
Wim Taymanse1a166a2005-10-21 11:36:32 +0000507 * This function cannot be called from within a task function as this
508 * will cause a deadlock.
Wim Taymans1e40e472005-08-24 20:49:53 +0000509 *
510 * Returns: TRUE if the task could be joined.
511 *
512 * MT safe.
513 */
514gboolean
515gst_task_join (GstTask * task)
516{
Wim Taymans2681eae2006-02-13 17:03:23 +0000517 GThread *tself;
518
Wim Taymans1e40e472005-08-24 20:49:53 +0000519 g_return_val_if_fail (GST_IS_TASK (task), FALSE);
520
Wim Taymans2681eae2006-02-13 17:03:23 +0000521 tself = g_thread_self ();
522
523 GST_DEBUG_OBJECT (task, "Joining task %p, thread %p", task, tself);
Wim Taymans1e40e472005-08-24 20:49:53 +0000524
Andy Wingo44c548b2005-11-21 16:34:26 +0000525 GST_OBJECT_LOCK (task);
Wim Taymans2681eae2006-02-13 17:03:23 +0000526 if (tself == task->abidata.ABI.thread)
527 goto joining_self;
Wim Taymans1e40e472005-08-24 20:49:53 +0000528 task->state = GST_TASK_STOPPED;
529 GST_TASK_SIGNAL (task);
530 while (task->running)
531 GST_TASK_WAIT (task);
Andy Wingo44c548b2005-11-21 16:34:26 +0000532 GST_OBJECT_UNLOCK (task);
Wim Taymans1e40e472005-08-24 20:49:53 +0000533
Thomas Vander Stichele9648a412005-11-12 10:03:08 +0000534 GST_DEBUG_OBJECT (task, "Joined task %p", task);
535
Wim Taymans1e40e472005-08-24 20:49:53 +0000536 return TRUE;
Wim Taymans2681eae2006-02-13 17:03:23 +0000537
538 /* ERRORS */
539joining_self:
540 {
541 GST_WARNING_OBJECT (task, "trying to join task from its thread");
542 GST_OBJECT_UNLOCK (task);
543 g_warning ("trying to join task %p from its thread would deadlock", task);
544 return FALSE;
545 }
Wim Taymans1e40e472005-08-24 20:49:53 +0000546}