Commit f5affde6 authored by Wim Taymans's avatar Wim Taymans

- Reclaim cothread state even if the cothread was never activated after the free.

Original commit message from CVS:
- Reclaim cothread state even if the cothread was never activated after
the free.
- fix the bin state change when there are no more children.
- use a real method to signal the parent bin of a state change.
- move the state change policy in the scheduler.
- remove the unused and ridiculous state change event
- don't free the cothread state when the element is disabled. only free it
when the element is removed from the scheduler.
parent a8b13468
......@@ -40,6 +40,8 @@
#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];
......@@ -116,6 +118,8 @@ cothread_context_free (cothread_context *ctx)
{
gint i;
GST_INFO (GST_CAT_COTHREADS, "free cothread context");
for (i = 0; i < ctx->nthreads; i++) {
#ifndef COTHREAD_ATOMIC
if (ctx->threads[i]) {
......@@ -158,6 +162,11 @@ cothread_create (cothread_context *ctx)
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;
......@@ -209,6 +218,8 @@ cothread_free (cothread_state *thread)
{
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;
}
......@@ -220,6 +231,8 @@ cothread_destroy (cothread_state *thread)
g_return_if_fail (thread != NULL);
GST_INFO (GST_CAT_COTHREADS, "destroy cothread");
ctx = thread->ctx;
#ifndef COTHREAD_ATOMIC
g_mutex_free (thread->lock);
......
......@@ -46,8 +46,6 @@ static GstElementStateReturn gst_bin_change_state_norecurse (GstBin *bin);
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);
......@@ -359,11 +357,13 @@ gst_bin_remove (GstBin * bin, GstElement * element)
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)
{
......@@ -401,21 +401,7 @@ gst_bin_send_event (GstElement *element, GstEvent *event)
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
......
......@@ -110,6 +110,10 @@ gboolean gst_bin_set_state_type (GstBin *bin, GstElementState state, GType type
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 */
......
......@@ -831,9 +831,6 @@ gst_element_send_event_func (GstElement *element, GstEvent *event)
}
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);
}
......@@ -968,6 +965,7 @@ static GstElementStateReturn
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);
......@@ -984,24 +982,9 @@ gst_element_change_state (GstElement *element)
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;
......@@ -1010,11 +993,11 @@ gst_element_change_state (GstElement *element)
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;
}
......
......@@ -153,25 +153,5 @@ gst_event_new_info (const gchar *firstname, ...)
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;
}
......@@ -45,7 +45,6 @@ typedef enum {
/* vertical events */
GST_EVENT_INFO,
GST_EVENT_ERROR,
GST_EVENT_STATE_CHANGE,
} GstEventType;
extern GType _gst_event_type;
......@@ -71,10 +70,6 @@ typedef enum {
#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;
......@@ -112,9 +107,6 @@ GstEvent* gst_event_new_seek (GstSeekType type, guint64 offset, gboolean flush);
/* 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 */
......
......@@ -331,8 +331,7 @@ restart:
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());
......@@ -400,8 +399,7 @@ restart:
/* 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());
......
......@@ -154,31 +154,18 @@ gst_scheduler_add_element (GstScheduler *sched, GstElement *element)
}
/**
* 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);
}
/**
......
......@@ -69,8 +69,7 @@ struct _GstSchedulerClass {
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);
......@@ -90,8 +89,7 @@ void gst_scheduler_setup (GstScheduler *sched);
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);
......
......@@ -324,13 +324,18 @@ gst_thread_change_state (GstElement * element)
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);
......
......@@ -50,8 +50,7 @@ static void gst_basic_scheduler_setup (GstScheduler *sched);
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);
......@@ -102,8 +101,7 @@ gst_basic_scheduler_class_init (GstSchedulerClass * klass)
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);
......@@ -622,12 +620,6 @@ gst_basic_scheduler_chain_disable_element (GstSchedulerChain * chain, GstElement
/* 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
......@@ -640,6 +632,11 @@ gst_basic_scheduler_chain_remove_element (GstSchedulerChain * chain, GstElement
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);
......@@ -907,23 +904,7 @@ gst_basic_scheduler_remove_element (GstScheduler * sched, GstElement * 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;
......@@ -932,10 +913,13 @@ gst_basic_scheduler_disable_element (GstScheduler *sched, GstElement *element)
/* 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));
}
}
......
......@@ -331,8 +331,7 @@ restart:
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());
......@@ -400,8 +399,7 @@ restart:
/* 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());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment