#define COTHREAD_MAXTHREADS 16
#define COTHREAD_STACKSIZE (STACK_SIZE/COTHREAD_MAXTHREADS)
+static void cothread_destroy (cothread_state *thread);
+
struct _cothread_context
{
cothread_state *threads[COTHREAD_MAXTHREADS];
{
gint i;
+ GST_INFO (GST_CAT_COTHREADS, "free cothread context");
+
for (i = 0; i < ctx->nthreads; i++) {
#ifndef COTHREAD_ATOMIC
if (ctx->threads[i]) {
for (slot = 1; slot < ctx->nthreads; slot++) {
if (ctx->threads[slot] == NULL)
break;
+ else if (ctx->threads[slot]->flags & COTHREAD_DESTROYED) {
+ cothread_destroy (ctx->threads[slot]);
+ break;
+ }
+
}
sp = CURRENT_STACK_FRAME;
{
g_return_if_fail (thread != NULL);
+ GST_INFO (GST_CAT_COTHREADS, "flag cothread for destruction");
+
/* we simply flag the cothread for destruction here */
thread->flags |= COTHREAD_DESTROYED;
}
g_return_if_fail (thread != NULL);
+ GST_INFO (GST_CAT_COTHREADS, "destroy cothread");
+
ctx = thread->ctx;
#ifndef COTHREAD_ATOMIC
g_mutex_free (thread->lock);
static gboolean gst_bin_change_state_type (GstBin *bin,
GstElementState state,
GType type);
-static void gst_bin_child_state_change (GstBin *bin, GstElementState old,
- GstElementState new, GstElement *child);
static void gst_bin_send_event (GstElement *element, GstEvent *event);
static gboolean gst_bin_iterate_func (GstBin * bin);
gst_object_unparent (GST_OBJECT (element));
/* if we're down to zero children, force state to NULL */
- if (bin->numchildren == 0 && GST_ELEMENT_SCHED (bin) != NULL)
- gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
+ if (bin->numchildren == 0 && GST_ELEMENT_SCHED (bin) != NULL) {
+ GST_STATE_PENDING (bin) = GST_STATE_NULL;
+ gst_bin_change_state_norecurse (bin);
+ }
}
-static void
+void
gst_bin_child_state_change (GstBin * bin, GstElementState old, GstElementState new,
GstElement * child)
{
gst_element_get_name (GST_ELEMENT (GST_EVENT_SRC (event))),
gst_element_get_name (element));
- if (GST_ELEMENT (GST_EVENT_SRC (event)) == element) {
- GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
- return;
- }
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_STATE_CHANGE:
- gst_bin_child_state_change (GST_BIN (element), GST_EVENT_STATE_OLD (event),
- GST_EVENT_STATE_NEW (event), GST_ELEMENT (GST_EVENT_SRC (event)));
- gst_event_free (event);
- break;
- default:
- GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
- break;
- }
+ GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
}
static GstElementStateReturn
gboolean gst_bin_iterate (GstBin *bin);
+/* internal */
+void gst_bin_child_state_change (GstBin *bin, GstElementState oldstate,
+ GstElementState newstate, GstElement *child);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
}
else {
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_STATE_CHANGE:
- g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE], 0,
- GST_EVENT_STATE_OLD (event), GST_EVENT_STATE_NEW (event));
default:
g_signal_emit (G_OBJECT (element), gst_element_signals[EVENT], 0, event);
}
gst_element_change_state (GstElement *element)
{
GstElementState old_state;
+ //GstEvent *event;
g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
gst_element_statename (GST_STATE_PENDING (element)),
GST_STATE_TRANSITION (element));
- if (GST_STATE_TRANSITION (element) == GST_STATE_PAUSED_TO_PLAYING) {
- g_return_val_if_fail (GST_ELEMENT_SCHED (element), GST_STATE_FAILURE);
-
- if (GST_ELEMENT_PARENT (element)) {
- GST_DEBUG (GST_CAT_STATES, "PAUSED->PLAYING: element \"%s\" has parent \"%s\" and sched %p\n",
- GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (GST_ELEMENT_PARENT (element)),
- GST_ELEMENT_SCHED (element));
- }
- gst_scheduler_enable_element (element->sched, element);
- }
- else if (GST_STATE_TRANSITION (element) == GST_STATE_PLAYING_TO_PAUSED) {
- if (GST_ELEMENT_PARENT (element)) {
- GST_DEBUG (GST_CAT_STATES, "PLAYING->PAUSED: element \"%s\" has parent \"%s\" and sched %p\n",
- GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (GST_ELEMENT_PARENT (element)),
- GST_ELEMENT_SCHED (element));
- }
- gst_scheduler_disable_element (element->sched, element);
- }
+ /* tell the scheduler if we have one */
+ if (element->sched)
+ gst_scheduler_state_transition (element->sched, element, GST_STATE_TRANSITION (element));
GST_STATE (element) = GST_STATE_PENDING (element);
GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
g_cond_signal (element->state_cond);
g_mutex_unlock (element->state_mutex);
- {
- GstEvent *event = gst_event_new_state_change (old_state, GST_STATE (element));
-
- gst_element_send_event (element, event);
+ if (GST_ELEMENT_PARENT (element)) {
+ gst_bin_child_state_change (GST_BIN (GST_ELEMENT_PARENT (element)), old_state, GST_STATE (element), element);
}
+ //event = gst_event_new_state_change (old_state, GST_STATE (element));
+ //gst_element_send_event (element, event);
return GST_STATE_SUCCESS;
}
return event;
}
-/**
- * gst_event_new_state_change:
- * @old: The old state
- * @state: The new state
- *
- * Allocate a new state change event with the given props.
- *
- * Returns: A new state change event.
- */
-GstEvent*
-gst_event_new_state_change (GstElementState old, GstElementState state)
-{
- GstEvent *event;
-
- event = gst_event_new (GST_EVENT_STATE_CHANGE);
- GST_EVENT_STATE_OLD (event) = old;
- GST_EVENT_STATE_NEW (event) = state;
-
- return event;
-}
/* vertical events */
GST_EVENT_INFO,
GST_EVENT_ERROR,
- GST_EVENT_STATE_CHANGE,
} GstEventType;
extern GType _gst_event_type;
#define GST_EVENT_INFO_PROPS(event) (GST_EVENT(event)->event_data.info.props)
-#define GST_EVENT_STATE_OLD(event) (GST_EVENT(event)->event_data.state.old_state)
-#define GST_EVENT_STATE_NEW(event) (GST_EVENT(event)->event_data.state.new_state)
-
-
struct _GstEvent {
GstData data;
/* info events */
GstEvent* gst_event_new_info (const gchar *firstname, ...);
-/* state change events */
-GstEvent* gst_event_new_state_change (GstElementState old, GstElementState state);
-
#ifdef __cplusplus
}
#endif /* __cplusplus */
while (queue->level_buffers == queue->size_buffers) {
/* if there's a pending state change for this queue or its manager, switch */
/* back to iterator so bottom half of state change executes */
- while (GST_STATE (queue) != GST_STATE_PLAYING) {
- //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) {
+ while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) {
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!\n");
g_mutex_unlock (queue->qlock);
cothread_switch(cothread_current_main());
/* if there's a pending state change for this queue or its manager, switch
* back to iterator so bottom half of state change executes
*/
- while (GST_STATE (queue) != GST_STATE_PLAYING) {
- //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) {
+ while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) {
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!\n");
g_mutex_unlock (queue->qlock);
cothread_switch(cothread_current_main());
}
/**
- * gst_scheduler_enable_element:
+ * gst_scheduler_state_transition:
* @sched: the schedulerr
- * @element: the element to enable
+ * @element: the element with the state transition
+ * @transition: the state transition
*
- * Enable an element for scheduling.
+ * Tell the scheduler that an element changed its state.
*/
void
-gst_scheduler_enable_element (GstScheduler *sched, GstElement *element)
+gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition)
{
- if (CLASS (sched)->enable_element)
- CLASS (sched)->enable_element (sched, element);
-}
-
-/**
- * gst_scheduler_disable_element:
- * @sched: the schedulerr
- * @element: the element to disable
- *
- * Disable an element for scheduling.
- */
-void
-gst_scheduler_disable_element (GstScheduler *sched, GstElement *element)
-{
- if (CLASS (sched)->disable_element)
- CLASS (sched)->disable_element (sched, element);
+ if (CLASS (sched)->state_transition)
+ CLASS (sched)->state_transition (sched, element, transition);
}
/**
void (*reset) (GstScheduler *sched);
void (*add_element) (GstScheduler *sched, GstElement *element);
void (*remove_element) (GstScheduler *sched, GstElement *element);
- void (*enable_element) (GstScheduler *sched, GstElement *element);
- void (*disable_element) (GstScheduler *sched, GstElement *element);
+ void (*state_transition) (GstScheduler *sched, GstElement *element, gint transition);
void (*lock_element) (GstScheduler *sched, GstElement *element);
void (*unlock_element) (GstScheduler *sched, GstElement *element);
void (*pad_connect) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
void gst_scheduler_reset (GstScheduler *sched);
void gst_scheduler_add_element (GstScheduler *sched, GstElement *element);
void gst_scheduler_remove_element (GstScheduler *sched, GstElement *element);
-void gst_scheduler_enable_element (GstScheduler *sched, GstElement *element);
-void gst_scheduler_disable_element (GstScheduler *sched, GstElement *element);
+void gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition);
void gst_scheduler_lock_element (GstScheduler *sched, GstElement *element);
void gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element);
void gst_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
THR_DEBUG (" element \"%s\"\n", GST_ELEMENT_NAME (element));
elements = g_list_next (elements);
if (GST_IS_QUEUE (element)) {
+ GstQueue *queue = GST_QUEUE (element);
/* FIXME make this more efficient by only waking queues that are asleep
* FIXME and only waking the appropriate condition (depending on if it's
* FIXME on up- or down-stream side)
* FIXME also make this more efficient by keeping list of managed queues
*/
THR_DEBUG ("waking queue \"%s\"\n", GST_ELEMENT_NAME (element));
- gst_element_set_state (element, GST_STATE_PAUSED);
+ g_mutex_lock (queue->qlock);
+ GST_STATE_PENDING (element) = GST_STATE_PAUSED;
+ g_cond_signal (queue->not_full);
+ g_cond_signal (queue->not_empty);
+ g_mutex_unlock (queue->qlock);
}
else {
GList *pads = GST_ELEMENT_PADS (element);
static void gst_basic_scheduler_reset (GstScheduler *sched);
static void gst_basic_scheduler_add_element (GstScheduler *sched, GstElement *element);
static void gst_basic_scheduler_remove_element (GstScheduler *sched, GstElement *element);
-static void gst_basic_scheduler_enable_element (GstScheduler *sched, GstElement *element);
-static void gst_basic_scheduler_disable_element (GstScheduler *sched, GstElement *element);
+static void gst_basic_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition);
static void gst_basic_scheduler_lock_element (GstScheduler *sched, GstElement *element);
static void gst_basic_scheduler_unlock_element (GstScheduler *sched, GstElement *element);
static void gst_basic_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
klass->reset = GST_DEBUG_FUNCPTR (gst_basic_scheduler_reset);
klass->add_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_add_element);
klass->remove_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_remove_element);
- klass->enable_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_enable_element);
- klass->disable_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_disable_element);
+ klass->state_transition = GST_DEBUG_FUNCPTR (gst_basic_scheduler_state_transition);
klass->lock_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_lock_element);
klass->unlock_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_unlock_element);
klass->pad_connect = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_connect);
/* reschedule the chain */
/* FIXME this should be done only if manager state != NULL */
/* gst_basic_scheduler_cothreaded_chain(GST_BIN(chain->sched->parent),chain); */
- /* FIXME is this right? */
- /* we have to check for a threadstate here because a queue doesn't have one */
- if (element->threadstate) {
- cothread_free (element->threadstate);
- element->threadstate = NULL;
- }
}
static void
if (g_list_find (chain->elements, element)) {
gst_basic_scheduler_chain_disable_element (chain, element);
}
+ /* we have to check for a threadstate here because a queue doesn't have one */
+ if (element->threadstate) {
+ cothread_free (element->threadstate);
+ element->threadstate = NULL;
+ }
/* remove the element from the list of elements */
chain->disabled = g_list_remove (chain->disabled, element);
}
static void
-gst_basic_scheduler_enable_element (GstScheduler *sched, GstElement *element)
-{
- GstSchedulerChain *chain;
-
- /* find the chain the element's in */
- chain = gst_basic_scheduler_find_chain (sched, element);
-
- if (chain) {
- gst_basic_scheduler_chain_enable_element (chain, element);
- }
- else {
- GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" not found in any chain, not enabling", GST_ELEMENT_NAME (element));
- }
-}
-
-static void
-gst_basic_scheduler_disable_element (GstScheduler *sched, GstElement *element)
+gst_basic_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition)
{
GstSchedulerChain *chain;
/* remove it from the chain */
if (chain) {
- gst_basic_scheduler_chain_disable_element (chain, element);
+ if (transition == GST_STATE_PLAYING_TO_PAUSED)
+ gst_basic_scheduler_chain_disable_element (chain, element);
+ if (transition == GST_STATE_PAUSED_TO_PLAYING)
+ gst_basic_scheduler_chain_enable_element (chain, element);
}
else {
- GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" not found in any chain, not disabling", GST_ELEMENT_NAME (element));
+ GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" not found in any chain, no state change", GST_ELEMENT_NAME (element));
}
}
while (queue->level_buffers == queue->size_buffers) {
/* if there's a pending state change for this queue or its manager, switch */
/* back to iterator so bottom half of state change executes */
- while (GST_STATE (queue) != GST_STATE_PLAYING) {
- //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) {
+ while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) {
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!\n");
g_mutex_unlock (queue->qlock);
cothread_switch(cothread_current_main());
/* if there's a pending state change for this queue or its manager, switch
* back to iterator so bottom half of state change executes
*/
- while (GST_STATE (queue) != GST_STATE_PLAYING) {
- //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) {
+ while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) {
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!\n");
g_mutex_unlock (queue->qlock);
cothread_switch(cothread_current_main());