-*- Mode: text -*-

Sometimes it's difficult to use GStreamer in real applications where the GUI and
the GStreamer pipeline are in different threads. You have to somehow make sure
that the object is not modifying its properties while you get and set them. This
document is a brief outline of a potential fix to this issue.

* When is it safe to get or set properties?

Well, it is only safe to do so when other threads are not accessing an object.
So, from the main thread, it is only safe to query or modify properties on an
object when it is not in the RUNNING state, because when it is RUNNING its
properties are potentially changing in the thread of execution.

The only place that it is safe to get or set properties while in the RUNNING
state is from within the thread of execution. Thus, something within the
iteration loop of the thread must check to see if there are pending property
changes or queries. There are two places this could be done, from within
gstthread itself and from within the scheduler. Doing it from gstthread sounds
like a good idea because it keeps more code out of the scheduler, but is also
bad in a way because it requires a gstthread-specific api to proxy prop_set and
prop_get. Setting it in the scheduler sounds good because of its finer
granularity, but might be bad because it would clutter the scheduler a bit more.

I propose to go with the scheduler-based solution based on system response time
and out of potentials for integration with gst_clock_wait.

* Implementation

We do want to preserve some measure of generality, however. Considering that
more threadsafety issues could pop up in the future, it would be nice to have
one function to call from the scheduler, in the interests of code
simplification. This function will be present in some elements and not in
others, and will be modified at run time, so we will make it a function pointer
within the GstElement struct.

struct _GstElement {
  ...
  void (*pre_run_func) (GstElement *);
  void (*post_run_func) (GstElement *);
}

Only the managing bin of an element is allowed to set that function, because
presumably that bin would know something about how to schedule the element.
Then, in the scheduler, before we call chain functions and before we switch into
loop functions:

if (element->pre_run_func)
  element->pre_run_func (element);

Then, to get or set properties, we use the new functions gst_element_get or
gst_element_set. _set would add the property name and a gvalue onto a queue
(probably a GAsyncQueue). Then the pre_run_func would go ahead and set the
properties. _get is a little more tricky; _set doesn't hardly block at all,
although it's not instantaneous. With _get though, you really don't know what
the properties are until you query them. The best thing would be to connect to
the ::notify signal, which executes within the thread of interest. However, say
you really want to use _get. Hmm. I think that it would have to block. On what?
Well, probably on an element's mutex. So it seems we might need a
post_run_func too, to unlock the mutex. We can use the GstObject lock for this.

But we need a little more. How do we know whether or not just calling
g_object_get/set is ok? I'm thinking this whole prop set/get proxy thing should
not be abstracted away, that it should be contained in gstelement.c. There are
more kinds of bins that need threadsafety than just gstthread (I'm thinking
about jack here). So, we can add on a GAsyncQueue *prop_set_queue; to the
GstElement struct, and only initialize it in certain managing bins. Then, we can
set a flag on gstelement, GST_ELEMENT_USE_THREADSAFE_PROPERTIES. If this flag is
set (by the managing bin), do all this complicated mess; otherwise use the
gobject native functionality.

So, this is the plan. We'll see how the implementation goes. This should make MT
gst programming much easier.

wingo.
25 May 2002.
