EXPORT_C #endif gboolean gst_task_pause (GstTask * task) { GstTaskState old; g_return_val_if_fail (GST_IS_TASK (task), FALSE); GST_DEBUG_OBJECT (task, "Pausing task %p", task); GST_OBJECT_LOCK (task); if (G_UNLIKELY (GST_TASK_GET_LOCK (task) == NULL)) goto no_lock; old = task->state; task->state = GST_TASK_PAUSED; switch (old) { case GST_TASK_STOPPED: { GstTaskClass *tclass; if (task->running) break; gst_object_ref (task); task->running = TRUE; tclass = GST_TASK_GET_CLASS (task); g_static_mutex_lock (&pool_lock); g_thread_pool_push (tclass->pool, task, NULL); g_static_mutex_unlock (&pool_lock); break; } case GST_TASK_PAUSED: break; case GST_TASK_STARTED: break; } GST_OBJECT_UNLOCK (task); return TRUE; /* ERRORS */ no_lock: { GST_WARNING_OBJECT (task, "pausing task without a lock"); GST_OBJECT_UNLOCK (task); g_warning ("pausing task without a lock"); return FALSE; } }
/** * gst_task_set_state: * @task: a #GstTask * @state: the new task state * * Sets the state of @task to @state. * * The @task must have a lock associated with it using * gst_task_set_lock() when going to GST_TASK_STARTED or GST_TASK_PAUSED or * this function will return %FALSE. * * MT safe. * * Returns: %TRUE if the state could be changed. * * Since: 0.10.24 */ gboolean gst_task_set_state (GstTask * task, GstTaskState state) { GstTaskState old; gboolean res = TRUE; g_return_val_if_fail (GST_IS_TASK (task), FALSE); GST_DEBUG_OBJECT (task, "Changing task %p to state %d", task, state); GST_OBJECT_LOCK (task); if (state != GST_TASK_STOPPED) if (G_UNLIKELY (GST_TASK_GET_LOCK (task) == NULL)) goto no_lock; /* if the state changed, do our thing */ old = task->state; if (old != state) { task->state = state; switch (old) { case GST_TASK_STOPPED: /* If the task already has a thread scheduled we don't have to do * anything. */ if (G_UNLIKELY (!task->running)) res = start_task (task); break; case GST_TASK_PAUSED: /* when we are paused, signal to go to the new state */ GST_TASK_SIGNAL (task); break; case GST_TASK_STARTED: /* if we were started, we'll go to the new state after the next * iteration. */ break; } } GST_OBJECT_UNLOCK (task); return res; /* ERRORS */ no_lock: { GST_WARNING_OBJECT (task, "state %d set on task without a lock", state); GST_OBJECT_UNLOCK (task); g_warning ("task without a lock can't be set to state %d", state); return FALSE; } }
/** * gst_task_set_lock: * @task: The #GstTask to use * @mutex: The #GMutex to use * * Set the mutex used by the task. The mutex will be acquired before * calling the #GstTaskFunction. * * This function has to be called before calling gst_task_pause() or * gst_task_start(). * * MT safe. */ void gst_task_set_lock (GstTask * task, GStaticRecMutex * mutex) { GST_OBJECT_LOCK (task); if (G_UNLIKELY (task->running)) goto is_running; GST_TASK_GET_LOCK (task) = mutex; GST_OBJECT_UNLOCK (task); return; /* ERRORS */ is_running: { GST_OBJECT_UNLOCK (task); g_warning ("cannot call set_lock on a running task"); } }
EXPORT_C #endif gboolean gst_task_start (GstTask * task) { GstTaskState old; g_return_val_if_fail (GST_IS_TASK (task), FALSE); GST_DEBUG_OBJECT (task, "Starting task %p", task); GST_OBJECT_LOCK (task); if (G_UNLIKELY (GST_TASK_GET_LOCK (task) == NULL)) goto no_lock; old = task->state; task->state = GST_TASK_STARTED; switch (old) { case GST_TASK_STOPPED: { GstTaskClass *tclass; /* If the task already has a thread scheduled we don't have to do * anything. */ if (task->running) break; /* new task, push on threadpool. We ref before so * that it remains alive while on the threadpool. */ gst_object_ref (task); /* mark task as running so that a join will wait until we schedule * and exit the task function. */ task->running = TRUE; tclass = GST_TASK_GET_CLASS (task); g_static_mutex_lock (&pool_lock); g_thread_pool_push (tclass->pool, task, NULL); g_static_mutex_unlock (&pool_lock); break; } case GST_TASK_PAUSED: /* PAUSE to PLAY, signal */ GST_TASK_SIGNAL (task); break; case GST_TASK_STARTED: /* was OK */ break; } GST_OBJECT_UNLOCK (task); return TRUE; /* ERRORS */ no_lock: { GST_WARNING_OBJECT (task, "starting task without a lock"); GST_OBJECT_UNLOCK (task); g_warning ("starting task without a lock"); return FALSE; } }
static void gst_task_func (GstTask * task, GstTaskClass * tclass) { GStaticRecMutex *lock; GThread *tself; tself = g_thread_self (); GST_DEBUG ("Entering task %p, thread %p", task, tself); /* we have to grab the lock to get the mutex. We also * mark our state running so that nobody can mess with * the mutex. */ GST_OBJECT_LOCK (task); if (task->state == GST_TASK_STOPPED) goto exit; lock = GST_TASK_GET_LOCK (task); if (G_UNLIKELY (lock == NULL)) goto no_lock; task->abidata.ABI.thread = tself; GST_OBJECT_UNLOCK (task); /* locking order is TASK_LOCK, LOCK */ g_static_rec_mutex_lock (lock); GST_OBJECT_LOCK (task); while (G_LIKELY (task->state != GST_TASK_STOPPED)) { while (G_UNLIKELY (task->state == GST_TASK_PAUSED)) { gint t; t = g_static_rec_mutex_unlock_full (lock); if (t <= 0) { g_warning ("wrong STREAM_LOCK count %d", t); } GST_TASK_SIGNAL (task); GST_TASK_WAIT (task); GST_OBJECT_UNLOCK (task); /* locking order.. */ if (t > 0) g_static_rec_mutex_lock_full (lock, t); GST_OBJECT_LOCK (task); if (G_UNLIKELY (task->state == GST_TASK_STOPPED)) goto done; } GST_OBJECT_UNLOCK (task); task->func (task->data); GST_OBJECT_LOCK (task); } done: GST_OBJECT_UNLOCK (task); g_static_rec_mutex_unlock (lock); GST_OBJECT_LOCK (task); task->abidata.ABI.thread = NULL; exit: /* now we allow messing with the lock again by setting the running flag to * FALSE. Together with the SIGNAL this is the sign for the _join() to * complete. * Note that we still have not dropped the final ref on the task. We could * check here if there is a pending join() going on and drop the last ref * before releasing the lock as we can be sure that a ref is held by the * caller of the join(). */ task->running = FALSE; GST_TASK_SIGNAL (task); GST_OBJECT_UNLOCK (task); GST_DEBUG ("Exit task %p, thread %p", task, g_thread_self ()); gst_object_unref (task); return; no_lock: { g_warning ("starting task without a lock"); goto exit; } }
static void gst_task_func (GstTask * task) { GStaticRecMutex *lock; GThread *tself; GstTaskPrivate *priv; priv = task->priv; tself = g_thread_self (); GST_DEBUG ("Entering task %p, thread %p", task, tself); /* we have to grab the lock to get the mutex. We also * mark our state running so that nobody can mess with * the mutex. */ GST_OBJECT_LOCK (task); if (task->state == GST_TASK_STOPPED) goto exit; lock = GST_TASK_GET_LOCK (task); if (G_UNLIKELY (lock == NULL)) goto no_lock; task->abidata.ABI.thread = tself; /* only update the priority when it was changed */ if (priv->prio_set) g_thread_set_priority (tself, priv->priority); GST_OBJECT_UNLOCK (task); /* fire the enter_thread callback when we need to */ if (priv->thr_callbacks.enter_thread) priv->thr_callbacks.enter_thread (task, tself, priv->thr_user_data); /* locking order is TASK_LOCK, LOCK */ g_static_rec_mutex_lock (lock); GST_OBJECT_LOCK (task); /* configure the thread name now */ gst_task_configure_name (task); while (G_LIKELY (task->state != GST_TASK_STOPPED)) { while (G_UNLIKELY (task->state == GST_TASK_PAUSED)) { gint t; t = g_static_rec_mutex_unlock_full (lock); if (t <= 0) { g_warning ("wrong STREAM_LOCK count %d", t); } GST_TASK_SIGNAL (task); GST_TASK_WAIT (task); GST_OBJECT_UNLOCK (task); /* locking order.. */ if (t > 0) g_static_rec_mutex_lock_full (lock, t); GST_OBJECT_LOCK (task); if (G_UNLIKELY (task->state == GST_TASK_STOPPED)) goto done; } GST_OBJECT_UNLOCK (task); task->func (task->data); GST_OBJECT_LOCK (task); } done: GST_OBJECT_UNLOCK (task); g_static_rec_mutex_unlock (lock); GST_OBJECT_LOCK (task); task->abidata.ABI.thread = NULL; exit: if (priv->thr_callbacks.leave_thread) { /* fire the leave_thread callback when we need to. We need to do this before * we signal the task and with the task lock released. */ GST_OBJECT_UNLOCK (task); priv->thr_callbacks.leave_thread (task, tself, priv->thr_user_data); GST_OBJECT_LOCK (task); } else { /* restore normal priority when releasing back into the pool, we will not * touch the priority when a custom callback has been installed. */ g_thread_set_priority (tself, G_THREAD_PRIORITY_NORMAL); } /* now we allow messing with the lock again by setting the running flag to * FALSE. Together with the SIGNAL this is the sign for the _join() to * complete. * Note that we still have not dropped the final ref on the task. We could * check here if there is a pending join() going on and drop the last ref * before releasing the lock as we can be sure that a ref is held by the * caller of the join(). */ task->running = FALSE; GST_TASK_SIGNAL (task); GST_OBJECT_UNLOCK (task); GST_DEBUG ("Exit task %p, thread %p", task, g_thread_self ()); gst_object_unref (task); return; no_lock: { g_warning ("starting task without a lock"); goto exit; } }