2004-12-09 17:25:00 +00:00
|
|
|
Conventions for thread a safe API
|
|
|
|
---------------------------------
|
|
|
|
|
|
|
|
The GStreamer API is designed to be thread safe. This means that API functions can be
|
|
|
|
called from multiple threads at the same time. GStreamer internally uses threads to
|
|
|
|
perform the data passing and various asynchronous services such as the clock can also
|
|
|
|
use threads.
|
|
|
|
|
|
|
|
This design decision has implication for the usage of the API and the objects which
|
|
|
|
this document explains.
|
|
|
|
|
|
|
|
MT safety techniques
|
|
|
|
--------------------
|
|
|
|
|
|
|
|
Several design patterns are used to guarantee object consistency in GStreamer. This
|
|
|
|
is an overview of the methods used in various GStreamer subsystems.
|
|
|
|
|
|
|
|
Refcounting
|
|
|
|
|
|
|
|
All object have a refcount associated with them. Each reference obtained to the
|
|
|
|
object should increase the refcount and each reference lost should decrease the
|
|
|
|
refcount.
|
|
|
|
|
|
|
|
The refcounting is used to make sure that when another thread destroys the object,
|
|
|
|
the ones which still hold a reference to the object do not read from invalid
|
|
|
|
memory when accessing the object.
|
|
|
|
|
|
|
|
It is a requirement that when two threads have a handle to an object, the
|
|
|
|
refcount must be one, this means that when one thread passes an object to another
|
|
|
|
thread it must increase the refcount. This requirement makes sure that one
|
|
|
|
thread cannot suddenly dispose the object making the other thread crash when it
|
|
|
|
tries to access the pointer to invalid memory.
|
|
|
|
|
|
|
|
Copy-on-write:
|
|
|
|
|
|
|
|
All object have a refcount associated with them. Each reference obtained to the
|
|
|
|
object should increase the refcount and each reference lost should decrease the
|
|
|
|
refcount.
|
|
|
|
|
|
|
|
Each thread having a refcount to the object can safely read from the object. but
|
|
|
|
modifications made to the object should be preceeded with a _copy_on_write()
|
|
|
|
function call. This function will check the refcount of the object and if the
|
|
|
|
object is referenced by more than one instance, a copy is made of the object that
|
|
|
|
is then by definition only referenced from the calling thread. This new copy
|
|
|
|
is then modifyable without being visible to other refcount holders.
|
|
|
|
|
|
|
|
This technique is used for information objects that, once created, never change
|
|
|
|
their values. The lifetime of these objects is generally short, the objects are
|
|
|
|
usually simple and cheap to copy/create.
|
|
|
|
|
|
|
|
The advantage of this method is that no reader/writers locks are needed. all
|
|
|
|
threads can concurrently read but writes happen locally on a new copy. In most
|
|
|
|
cases _copy_on_write() can avoid a real copy because the calling method is the
|
|
|
|
only one holding a reference, wich makes read/writes very cheap.
|
|
|
|
|
|
|
|
The drawback is that sometimes 1 needless copy can be done. This would happen
|
|
|
|
when N threads call _copy_on_write() at the same time, all seeing that N references
|
|
|
|
are held to the object. In this case 1 copy too many will be done. This is not
|
|
|
|
a problem in any practical situation because the copy operation is fast.
|
|
|
|
|
|
|
|
Object locking:
|
|
|
|
|
|
|
|
For objects that contain state information and generally have a longer lifetime,
|
|
|
|
object locking is used to update the information contained in the object.
|
|
|
|
|
|
|
|
All readers and writers acquire the lock before accessing the object. Only one
|
|
|
|
thread is allowed access the protected structures at a time.
|
|
|
|
|
|
|
|
Object locking is used for all objects extending from GstObject such as GstElement,
|
|
|
|
GstPad.
|
|
|
|
|
|
|
|
Atomic operations
|
|
|
|
|
|
|
|
Atomic operations are operations that are performed as one consistent operation
|
|
|
|
even when executed by multiple threads. They do however not use the conventional
|
|
|
|
aproach of using mutexes to protect the critical section but rely on CPU features
|
|
|
|
and instructions.
|
|
|
|
|
|
|
|
The advantages are mostly speed related since there are no heavyweight locks
|
|
|
|
involved. Most of this instructions also do not cause a context switch in case
|
|
|
|
of concurrent access but use a retry mechanism or spinlocking.
|
|
|
|
|
|
|
|
Disadvantages are that each of these instructions usually cause a cache flush
|
|
|
|
on multi-CPU machines when two processors perform concurrent access.
|
|
|
|
|
|
|
|
Atomic operations are generally used for refcounting and for the allocation of
|
|
|
|
small fixed size objects in a memchunk. They can also be used to implement a
|
|
|
|
lockfree list or stack.
|
|
|
|
|
|
|
|
|
|
|
|
Objects
|
|
|
|
-------
|
|
|
|
|
|
|
|
* Locking involved:
|
|
|
|
|
|
|
|
- atomic operations for refcounting
|
|
|
|
- object locking
|
|
|
|
|
|
|
|
All objects should have a lock associated with them. This lock is used to keep
|
|
|
|
internal consistency when multiple threads call API function on the object.
|
|
|
|
|
|
|
|
For objects that extend the GStreamer base object class this lock can be obtained with
|
|
|
|
the macros GST_LOCK() and GST_UNLOCK(). For other object that do not extend from the
|
|
|
|
base GstObject class these macros can be different.
|
|
|
|
|
|
|
|
* refcounting
|
|
|
|
|
|
|
|
All new objects created have the FLOATING flag set. This means that the object is
|
|
|
|
not owned or managed yet by anybody other than the one holding a reference to
|
|
|
|
the object. The object in this state has a reference count of 1.
|
|
|
|
|
|
|
|
Various object methods can take ownership of another object, this means that after
|
|
|
|
calling a method on object A with an object B as an argument, the object B is made
|
|
|
|
sole property of object A. This means that after the method call you are not allowed
|
|
|
|
to access the object anymore unless you keep an extra reference to the object.
|
|
|
|
An example of such a method is the _bin_add() method. As soon as this function is
|
|
|
|
called in a Bin, the element passed as an argument is owned by the bin and you
|
|
|
|
are not allowed to access it anymore without taking a _ref() before adding it
|
|
|
|
to the bin. The reason being that after the _bin_add() call disposing the bin
|
|
|
|
also destroys the element.
|
|
|
|
|
|
|
|
Taking ownership of an object happens trough the process of "sinking" the object.
|
|
|
|
the _sink() method on an object will decrease the refcount of the object if the
|
|
|
|
FLOATING flag is set. The act of taking ownership of an object is then performed
|
|
|
|
as a _ref() followed by a _sink() call on the object.
|
|
|
|
|
|
|
|
Sinking objects is very usefull because you don't have to worry about the lifetime
|
|
|
|
of these sunken objects anymore since it is managed by the owner element.
|
|
|
|
|
|
|
|
* parent-child relations
|
|
|
|
|
|
|
|
One can create parent child relationships with the _object_set_parent() method. This
|
|
|
|
method sinks the object and assigns its parent property to that of the managing
|
|
|
|
parent.
|
|
|
|
|
|
|
|
The child is said to have a weak link to the parent since the refcount of the parent
|
|
|
|
is not increased in this process. This means that if the parent is disposed it has
|
|
|
|
to unset itself as the parent of the object before disposing itself, else the child
|
|
|
|
object holds a parent pointer to invalid memory.
|
|
|
|
|
|
|
|
The responsabilites for an object that sinks other objects are summarised as:
|
|
|
|
|
|
|
|
- taking ownership of the object
|
|
|
|
- call _object_set_parent() to set itself as the object parent, this call will
|
|
|
|
_ref() and _sink() the object.
|
|
|
|
- keep reference to object in a datastructure such as a list or array.
|
|
|
|
|
|
|
|
- on dispose
|
|
|
|
- call _object_unparent() to reset the parent property and unref the object.
|
|
|
|
- remove the object from the list.
|
|
|
|
|
|
|
|
|
|
|
|
* Properties
|
|
|
|
|
|
|
|
Most objects also expose state information with public properties in the object. Two
|
|
|
|
types of properties might exist: accessible with or without holding the object lock.
|
|
|
|
All properties should only be accessed with their corresponding macros.
|
|
|
|
The public object properties are marked in the .h files with /*< public >*/. The
|
|
|
|
public properties that require a lock to be held are marked with
|
|
|
|
/*< public >*/ /* with <lock_type> */, where <lock_type> can be "LOCK" or "STATE_LOCK"
|
|
|
|
to mark the type(s) of lock to be held.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
in GstPad there is a public property "direction". It can be found in the section
|
|
|
|
marked as public and requiring the LOCK to be held. There exists also a macro
|
|
|
|
to access the property.
|
|
|
|
|
|
|
|
struct _GstRealPad {
|
|
|
|
...
|
|
|
|
/*< public >*/ /* with LOCK */
|
|
|
|
...
|
|
|
|
GstPadDirection direction;
|
|
|
|
...
|
|
|
|
};
|
|
|
|
|
|
|
|
#define GST_RPAD_DIRECTION(pad) (GST_REAL_PAD_CAST(pad)->direction)
|
|
|
|
|
|
|
|
Accessing the property is therefore allowed with the following code example:
|
|
|
|
|
|
|
|
GST_LOCK (pad);
|
|
|
|
direction = GST_RPAD_DIRECTION (pad);
|
|
|
|
GST_UNLOCK (pad);
|
|
|
|
|
|
|
|
* Property lifetime
|
|
|
|
|
|
|
|
All properties requiring a lock can change after releasing the associated lock.
|
|
|
|
This means that as soon as long as you hold the lock, the state of the object
|
|
|
|
regarding the locked properties is consistent with the information obtained. As
|
|
|
|
soon as the lock is released, any values required from the properties might not
|
|
|
|
be valid anymore and can as best be described as a snapshot of the state when
|
|
|
|
the lock was held.
|
|
|
|
|
|
|
|
This means that all properties that require access beyond the scope of the critial
|
|
|
|
section should be copied or refcounted before releasing the lock.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
the following example correctly gets the peer pad of an element. It is required
|
|
|
|
to increase the refcount of the peer pad because as soon as the lock is released,
|
|
|
|
the peer could be unreffed and disposed, making the pointer obtained in the critical
|
|
|
|
section point to invalid memory.
|
|
|
|
|
|
|
|
GST_LOCK (pad);
|
|
|
|
peer = GST_RPAD_PEER (pad);
|
|
|
|
if (peer)
|
|
|
|
gst_object_ref (GST_OBJECT (peer));
|
|
|
|
GST_UNLOCK (pad);
|
|
|
|
... use peer ...
|
|
|
|
|
More MT fixes, added design document describing refcounting policies used in GStreamer and locking involved.
Original commit message from CVS:
* docs/design/part-MT-refcounting.txt:
* docs/design/part-conventions.txt:
* gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock),
(gst_bin_add_func), (gst_bin_remove_func),
(gst_bin_iterate_elements), (gst_bin_change_state),
(gst_bin_dispose), (gst_bin_get_by_name_recurse_up):
* gst/gstcaps.c:
* gst/gstelement.c: (gst_element_add_pad),
(gst_element_remove_pad), (pad_compare_name),
(gst_element_get_static_pad), (gst_element_get_request_pad),
(gst_element_get_pad), (gst_element_iterate_pads),
(gst_element_class_get_pad_template_list),
(gst_element_class_get_pad_template), (gst_element_get_random_pad),
(gst_element_get_event_masks), (gst_element_send_event),
(gst_element_seek), (gst_element_get_query_types),
(gst_element_query), (gst_element_get_formats),
(gst_element_convert), (gst_element_post_message),
(gst_element_set_locked_state), (gst_element_get_state),
(gst_element_set_state), (gst_element_pads_activate),
(gst_element_dispose), (gst_element_set_manager_func),
(gst_element_get_manager):
* gst/gstelement.h:
* gst/gstiterator.c: (gst_iterator_new), (gst_list_iterator_next),
(gst_list_iterator_resync), (gst_list_iterator_free),
(gst_iterator_new_list):
* gst/gstiterator.h:
* gst/gstmessage.c: (_gst_message_copy):
* gst/gstobject.c: (gst_object_class_init), (gst_object_init),
(gst_object_ref), (gst_object_unref), (gst_object_sink),
(gst_object_replace), (gst_object_dispose),
(gst_object_dispatch_properties_changed), (gst_object_set_name),
(gst_object_set_parent), (gst_object_get_parent),
(gst_object_unparent), (gst_object_check_uniqueness),
(gst_object_get_path_string):
* gst/gstobject.h:
* gst/gstpad.c: (gst_pad_dispose), (gst_pad_set_active),
(gst_pad_is_active), (gst_pad_set_blocked_async),
(gst_pad_is_blocked), (gst_pad_unlink), (gst_pad_is_linked),
(gst_pad_link_prepare_filtered), (gst_pad_link_filtered),
(gst_pad_get_real_parent), (gst_pad_relink_filtered),
(gst_pad_get_peer), (gst_pad_realize), (gst_pad_get_allowed_caps),
(gst_pad_alloc_buffer), (gst_pad_push), (gst_pad_pull),
(gst_pad_pull_range), (gst_pad_push_event):
* gst/gstpad.h:
* gst/gstpipeline.c: (gst_pipeline_init), (gst_pipeline_dispose),
(is_eos), (pipeline_bus_handler):
* gst/gstutils.c: (gst_element_get_compatible_pad_filtered),
(gst_element_link_pads_filtered), (gst_element_unlink):
* gst/parse/grammar.y:
* tools/gst-compprep.c: (main):
* tools/gst-inspect.c: (print_pad_info):
* tools/gst-launch.c: (main):
* tools/gst-xmlinspect.c: (print_element_info):
More MT fixes, added design document describing refcounting
policies used in GStreamer and locking involved.
Fixed unsafe ghostpad dereffing.
Removed old unsafe methods.
2004-12-13 11:33:55 +00:00
|
|
|
if (peer)
|
|
|
|
gst_object_unref (GST_OBJECT (peer));
|
|
|
|
|
2004-12-09 17:25:00 +00:00
|
|
|
Note that after releasing the lock the peer might not actually be the peer anymore
|
|
|
|
of the pad. If you need to be sure it is, you need to extend the critical section
|
|
|
|
to include the operations on the peer.
|
|
|
|
|
|
|
|
* Accessor methods
|
|
|
|
|
|
|
|
For aplications it is encouraged to use the public methods of the object. Most usefull
|
|
|
|
operations can be performed with the methods so it is seldom required to access the
|
|
|
|
public fields manually.
|
|
|
|
|
|
|
|
All accessor methods that return an object should increase the refcount of the returned
|
More MT fixes, added design document describing refcounting policies used in GStreamer and locking involved.
Original commit message from CVS:
* docs/design/part-MT-refcounting.txt:
* docs/design/part-conventions.txt:
* gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock),
(gst_bin_add_func), (gst_bin_remove_func),
(gst_bin_iterate_elements), (gst_bin_change_state),
(gst_bin_dispose), (gst_bin_get_by_name_recurse_up):
* gst/gstcaps.c:
* gst/gstelement.c: (gst_element_add_pad),
(gst_element_remove_pad), (pad_compare_name),
(gst_element_get_static_pad), (gst_element_get_request_pad),
(gst_element_get_pad), (gst_element_iterate_pads),
(gst_element_class_get_pad_template_list),
(gst_element_class_get_pad_template), (gst_element_get_random_pad),
(gst_element_get_event_masks), (gst_element_send_event),
(gst_element_seek), (gst_element_get_query_types),
(gst_element_query), (gst_element_get_formats),
(gst_element_convert), (gst_element_post_message),
(gst_element_set_locked_state), (gst_element_get_state),
(gst_element_set_state), (gst_element_pads_activate),
(gst_element_dispose), (gst_element_set_manager_func),
(gst_element_get_manager):
* gst/gstelement.h:
* gst/gstiterator.c: (gst_iterator_new), (gst_list_iterator_next),
(gst_list_iterator_resync), (gst_list_iterator_free),
(gst_iterator_new_list):
* gst/gstiterator.h:
* gst/gstmessage.c: (_gst_message_copy):
* gst/gstobject.c: (gst_object_class_init), (gst_object_init),
(gst_object_ref), (gst_object_unref), (gst_object_sink),
(gst_object_replace), (gst_object_dispose),
(gst_object_dispatch_properties_changed), (gst_object_set_name),
(gst_object_set_parent), (gst_object_get_parent),
(gst_object_unparent), (gst_object_check_uniqueness),
(gst_object_get_path_string):
* gst/gstobject.h:
* gst/gstpad.c: (gst_pad_dispose), (gst_pad_set_active),
(gst_pad_is_active), (gst_pad_set_blocked_async),
(gst_pad_is_blocked), (gst_pad_unlink), (gst_pad_is_linked),
(gst_pad_link_prepare_filtered), (gst_pad_link_filtered),
(gst_pad_get_real_parent), (gst_pad_relink_filtered),
(gst_pad_get_peer), (gst_pad_realize), (gst_pad_get_allowed_caps),
(gst_pad_alloc_buffer), (gst_pad_push), (gst_pad_pull),
(gst_pad_pull_range), (gst_pad_push_event):
* gst/gstpad.h:
* gst/gstpipeline.c: (gst_pipeline_init), (gst_pipeline_dispose),
(is_eos), (pipeline_bus_handler):
* gst/gstutils.c: (gst_element_get_compatible_pad_filtered),
(gst_element_link_pads_filtered), (gst_element_unlink):
* gst/parse/grammar.y:
* tools/gst-compprep.c: (main):
* tools/gst-inspect.c: (print_pad_info):
* tools/gst-launch.c: (main):
* tools/gst-xmlinspect.c: (print_element_info):
More MT fixes, added design document describing refcounting
policies used in GStreamer and locking involved.
Fixed unsafe ghostpad dereffing.
Removed old unsafe methods.
2004-12-13 11:33:55 +00:00
|
|
|
object. The called should _unref() the object after usage. Each method should state this
|
2004-12-09 17:25:00 +00:00
|
|
|
refcounting policy in the documentation.
|
|
|
|
|
|
|
|
* Accessing lists
|
|
|
|
|
More MT fixes, added design document describing refcounting policies used in GStreamer and locking involved.
Original commit message from CVS:
* docs/design/part-MT-refcounting.txt:
* docs/design/part-conventions.txt:
* gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock),
(gst_bin_add_func), (gst_bin_remove_func),
(gst_bin_iterate_elements), (gst_bin_change_state),
(gst_bin_dispose), (gst_bin_get_by_name_recurse_up):
* gst/gstcaps.c:
* gst/gstelement.c: (gst_element_add_pad),
(gst_element_remove_pad), (pad_compare_name),
(gst_element_get_static_pad), (gst_element_get_request_pad),
(gst_element_get_pad), (gst_element_iterate_pads),
(gst_element_class_get_pad_template_list),
(gst_element_class_get_pad_template), (gst_element_get_random_pad),
(gst_element_get_event_masks), (gst_element_send_event),
(gst_element_seek), (gst_element_get_query_types),
(gst_element_query), (gst_element_get_formats),
(gst_element_convert), (gst_element_post_message),
(gst_element_set_locked_state), (gst_element_get_state),
(gst_element_set_state), (gst_element_pads_activate),
(gst_element_dispose), (gst_element_set_manager_func),
(gst_element_get_manager):
* gst/gstelement.h:
* gst/gstiterator.c: (gst_iterator_new), (gst_list_iterator_next),
(gst_list_iterator_resync), (gst_list_iterator_free),
(gst_iterator_new_list):
* gst/gstiterator.h:
* gst/gstmessage.c: (_gst_message_copy):
* gst/gstobject.c: (gst_object_class_init), (gst_object_init),
(gst_object_ref), (gst_object_unref), (gst_object_sink),
(gst_object_replace), (gst_object_dispose),
(gst_object_dispatch_properties_changed), (gst_object_set_name),
(gst_object_set_parent), (gst_object_get_parent),
(gst_object_unparent), (gst_object_check_uniqueness),
(gst_object_get_path_string):
* gst/gstobject.h:
* gst/gstpad.c: (gst_pad_dispose), (gst_pad_set_active),
(gst_pad_is_active), (gst_pad_set_blocked_async),
(gst_pad_is_blocked), (gst_pad_unlink), (gst_pad_is_linked),
(gst_pad_link_prepare_filtered), (gst_pad_link_filtered),
(gst_pad_get_real_parent), (gst_pad_relink_filtered),
(gst_pad_get_peer), (gst_pad_realize), (gst_pad_get_allowed_caps),
(gst_pad_alloc_buffer), (gst_pad_push), (gst_pad_pull),
(gst_pad_pull_range), (gst_pad_push_event):
* gst/gstpad.h:
* gst/gstpipeline.c: (gst_pipeline_init), (gst_pipeline_dispose),
(is_eos), (pipeline_bus_handler):
* gst/gstutils.c: (gst_element_get_compatible_pad_filtered),
(gst_element_link_pads_filtered), (gst_element_unlink):
* gst/parse/grammar.y:
* tools/gst-compprep.c: (main):
* tools/gst-inspect.c: (print_pad_info):
* tools/gst-launch.c: (main):
* tools/gst-xmlinspect.c: (print_element_info):
More MT fixes, added design document describing refcounting
policies used in GStreamer and locking involved.
Fixed unsafe ghostpad dereffing.
Removed old unsafe methods.
2004-12-13 11:33:55 +00:00
|
|
|
If the object property is a list, concurrent list iteration is needed to get the
|
More MT fixes. Header cleanups, design doc update.
Original commit message from CVS:
* docs/design/part-MT-refcounting.txt:
* gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock),
(gst_bin_add_func), (gst_bin_add), (gst_bin_remove_func),
(gst_bin_remove), (gst_bin_iterate_elements),
(bin_element_is_sink), (gst_bin_get_state), (gst_bin_change_state),
(gst_bin_get_by_name), (gst_bin_get_by_name_recurse_up),
(gst_bin_get_by_interface), (gst_bin_get_all_by_interface):
* gst/gstbin.h:
* gst/gstbuffer.h:
* gst/gstbus.h:
* gst/gstcaps.h:
* gst/gstclock.h:
* gst/gstdata.h:
* gst/gstelement.h:
* gst/gstevent.h:
* gst/gstmessage.h:
* gst/gststructure.h:
More MT fixes. Header cleanups, design doc update.
2004-12-09 23:28:31 +00:00
|
|
|
contents of the list. GStreamer uses the cookie mechanism to mark the last update
|
|
|
|
of a list. The list and the cookie are protected by the same lock. Each update to
|
|
|
|
a list requires the following actions:
|
2004-12-09 17:25:00 +00:00
|
|
|
|
|
|
|
- acquire lock
|
|
|
|
- update list
|
|
|
|
- update cookie
|
|
|
|
- release lock
|
|
|
|
|
More MT fixes. Header cleanups, design doc update.
Original commit message from CVS:
* docs/design/part-MT-refcounting.txt:
* gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock),
(gst_bin_add_func), (gst_bin_add), (gst_bin_remove_func),
(gst_bin_remove), (gst_bin_iterate_elements),
(bin_element_is_sink), (gst_bin_get_state), (gst_bin_change_state),
(gst_bin_get_by_name), (gst_bin_get_by_name_recurse_up),
(gst_bin_get_by_interface), (gst_bin_get_all_by_interface):
* gst/gstbin.h:
* gst/gstbuffer.h:
* gst/gstbus.h:
* gst/gstcaps.h:
* gst/gstclock.h:
* gst/gstdata.h:
* gst/gstelement.h:
* gst/gstevent.h:
* gst/gstmessage.h:
* gst/gststructure.h:
More MT fixes. Header cleanups, design doc update.
2004-12-09 23:28:31 +00:00
|
|
|
Updating the cookie is usually done by incrementing its value by one. Since cookies
|
|
|
|
use guint32 its wraparound is for all practical reasons is not a problem.
|
|
|
|
|
2004-12-09 17:25:00 +00:00
|
|
|
Iterating a list can safely be done by surrounding the list iteration with a
|
|
|
|
lock/unlock of the lock.
|
|
|
|
|
|
|
|
In some cases it is not a good idea to hold the lock for a long time while iterating
|
|
|
|
the list. The state change code for a bin in GStreamer, for example, has to iterate
|
|
|
|
over each element and perform a blocking call on each of them causing infinite bin
|
|
|
|
locking. In this case the cookie can be used to iterate a list.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
The following algorithm iterates a list and reverses the updates in the case a
|
|
|
|
concurrent update was done to the list while iterating. The idea is that whenever
|
|
|
|
we reacquire the lock, we check for updates to the cookie to decide if we are
|
|
|
|
still iterating the right list.
|
|
|
|
|
|
|
|
GST_LOCK (lock);
|
|
|
|
/* grab list and cookie */
|
|
|
|
cookie = object->list_cookie;
|
|
|
|
list = object-list;
|
|
|
|
while (list) {
|
|
|
|
GstObject *item = GST_OBJECT (list->data);
|
|
|
|
/* need to ref the item before releasing the lock */
|
|
|
|
gst_object_ref (item);
|
|
|
|
GST_UNLOCK (lock);
|
|
|
|
|
|
|
|
... use/change item here...
|
|
|
|
|
|
|
|
/* release item here */
|
|
|
|
gst_object_unref (item);
|
|
|
|
|
|
|
|
GST_LOCK (lock);
|
|
|
|
if (cookie != object->list_cookie) {
|
More MT fixes. Header cleanups, design doc update.
Original commit message from CVS:
* docs/design/part-MT-refcounting.txt:
* gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock),
(gst_bin_add_func), (gst_bin_add), (gst_bin_remove_func),
(gst_bin_remove), (gst_bin_iterate_elements),
(bin_element_is_sink), (gst_bin_get_state), (gst_bin_change_state),
(gst_bin_get_by_name), (gst_bin_get_by_name_recurse_up),
(gst_bin_get_by_interface), (gst_bin_get_all_by_interface):
* gst/gstbin.h:
* gst/gstbuffer.h:
* gst/gstbus.h:
* gst/gstcaps.h:
* gst/gstclock.h:
* gst/gstdata.h:
* gst/gstelement.h:
* gst/gstevent.h:
* gst/gstmessage.h:
* gst/gststructure.h:
More MT fixes. Header cleanups, design doc update.
2004-12-09 23:28:31 +00:00
|
|
|
/* handle rollback caused by concurrent modification
|
|
|
|
* of the list here */
|
2004-12-09 17:25:00 +00:00
|
|
|
|
More MT fixes. Header cleanups, design doc update.
Original commit message from CVS:
* docs/design/part-MT-refcounting.txt:
* gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock),
(gst_bin_add_func), (gst_bin_add), (gst_bin_remove_func),
(gst_bin_remove), (gst_bin_iterate_elements),
(bin_element_is_sink), (gst_bin_get_state), (gst_bin_change_state),
(gst_bin_get_by_name), (gst_bin_get_by_name_recurse_up),
(gst_bin_get_by_interface), (gst_bin_get_all_by_interface):
* gst/gstbin.h:
* gst/gstbuffer.h:
* gst/gstbus.h:
* gst/gstcaps.h:
* gst/gstclock.h:
* gst/gstdata.h:
* gst/gstelement.h:
* gst/gstevent.h:
* gst/gstmessage.h:
* gst/gststructure.h:
More MT fixes. Header cleanups, design doc update.
2004-12-09 23:28:31 +00:00
|
|
|
...rollback changes to items...
|
2004-12-09 17:25:00 +00:00
|
|
|
|
|
|
|
/* grab new cookie and list */
|
|
|
|
cookie = object->list_cookie;
|
|
|
|
list = object->list;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
list = g_list_next (list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
GST_UNLOCK (lock);
|
|
|
|
|
|
|
|
* GstIterator
|
|
|
|
|
More MT fixes, added design document describing refcounting policies used in GStreamer and locking involved.
Original commit message from CVS:
* docs/design/part-MT-refcounting.txt:
* docs/design/part-conventions.txt:
* gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock),
(gst_bin_add_func), (gst_bin_remove_func),
(gst_bin_iterate_elements), (gst_bin_change_state),
(gst_bin_dispose), (gst_bin_get_by_name_recurse_up):
* gst/gstcaps.c:
* gst/gstelement.c: (gst_element_add_pad),
(gst_element_remove_pad), (pad_compare_name),
(gst_element_get_static_pad), (gst_element_get_request_pad),
(gst_element_get_pad), (gst_element_iterate_pads),
(gst_element_class_get_pad_template_list),
(gst_element_class_get_pad_template), (gst_element_get_random_pad),
(gst_element_get_event_masks), (gst_element_send_event),
(gst_element_seek), (gst_element_get_query_types),
(gst_element_query), (gst_element_get_formats),
(gst_element_convert), (gst_element_post_message),
(gst_element_set_locked_state), (gst_element_get_state),
(gst_element_set_state), (gst_element_pads_activate),
(gst_element_dispose), (gst_element_set_manager_func),
(gst_element_get_manager):
* gst/gstelement.h:
* gst/gstiterator.c: (gst_iterator_new), (gst_list_iterator_next),
(gst_list_iterator_resync), (gst_list_iterator_free),
(gst_iterator_new_list):
* gst/gstiterator.h:
* gst/gstmessage.c: (_gst_message_copy):
* gst/gstobject.c: (gst_object_class_init), (gst_object_init),
(gst_object_ref), (gst_object_unref), (gst_object_sink),
(gst_object_replace), (gst_object_dispose),
(gst_object_dispatch_properties_changed), (gst_object_set_name),
(gst_object_set_parent), (gst_object_get_parent),
(gst_object_unparent), (gst_object_check_uniqueness),
(gst_object_get_path_string):
* gst/gstobject.h:
* gst/gstpad.c: (gst_pad_dispose), (gst_pad_set_active),
(gst_pad_is_active), (gst_pad_set_blocked_async),
(gst_pad_is_blocked), (gst_pad_unlink), (gst_pad_is_linked),
(gst_pad_link_prepare_filtered), (gst_pad_link_filtered),
(gst_pad_get_real_parent), (gst_pad_relink_filtered),
(gst_pad_get_peer), (gst_pad_realize), (gst_pad_get_allowed_caps),
(gst_pad_alloc_buffer), (gst_pad_push), (gst_pad_pull),
(gst_pad_pull_range), (gst_pad_push_event):
* gst/gstpad.h:
* gst/gstpipeline.c: (gst_pipeline_init), (gst_pipeline_dispose),
(is_eos), (pipeline_bus_handler):
* gst/gstutils.c: (gst_element_get_compatible_pad_filtered),
(gst_element_link_pads_filtered), (gst_element_unlink):
* gst/parse/grammar.y:
* tools/gst-compprep.c: (main):
* tools/gst-inspect.c: (print_pad_info):
* tools/gst-launch.c: (main):
* tools/gst-xmlinspect.c: (print_element_info):
More MT fixes, added design document describing refcounting
policies used in GStreamer and locking involved.
Fixed unsafe ghostpad dereffing.
Removed old unsafe methods.
2004-12-13 11:33:55 +00:00
|
|
|
GstIterator provides an easier way of retrieving elements in a concurrent list.
|
|
|
|
The followgin code example is equivalent to the previous example.
|
2004-12-09 17:25:00 +00:00
|
|
|
|
More MT fixes, added design document describing refcounting policies used in GStreamer and locking involved.
Original commit message from CVS:
* docs/design/part-MT-refcounting.txt:
* docs/design/part-conventions.txt:
* gst/gstbin.c: (gst_bin_set_index), (gst_bin_set_clock),
(gst_bin_add_func), (gst_bin_remove_func),
(gst_bin_iterate_elements), (gst_bin_change_state),
(gst_bin_dispose), (gst_bin_get_by_name_recurse_up):
* gst/gstcaps.c:
* gst/gstelement.c: (gst_element_add_pad),
(gst_element_remove_pad), (pad_compare_name),
(gst_element_get_static_pad), (gst_element_get_request_pad),
(gst_element_get_pad), (gst_element_iterate_pads),
(gst_element_class_get_pad_template_list),
(gst_element_class_get_pad_template), (gst_element_get_random_pad),
(gst_element_get_event_masks), (gst_element_send_event),
(gst_element_seek), (gst_element_get_query_types),
(gst_element_query), (gst_element_get_formats),
(gst_element_convert), (gst_element_post_message),
(gst_element_set_locked_state), (gst_element_get_state),
(gst_element_set_state), (gst_element_pads_activate),
(gst_element_dispose), (gst_element_set_manager_func),
(gst_element_get_manager):
* gst/gstelement.h:
* gst/gstiterator.c: (gst_iterator_new), (gst_list_iterator_next),
(gst_list_iterator_resync), (gst_list_iterator_free),
(gst_iterator_new_list):
* gst/gstiterator.h:
* gst/gstmessage.c: (_gst_message_copy):
* gst/gstobject.c: (gst_object_class_init), (gst_object_init),
(gst_object_ref), (gst_object_unref), (gst_object_sink),
(gst_object_replace), (gst_object_dispose),
(gst_object_dispatch_properties_changed), (gst_object_set_name),
(gst_object_set_parent), (gst_object_get_parent),
(gst_object_unparent), (gst_object_check_uniqueness),
(gst_object_get_path_string):
* gst/gstobject.h:
* gst/gstpad.c: (gst_pad_dispose), (gst_pad_set_active),
(gst_pad_is_active), (gst_pad_set_blocked_async),
(gst_pad_is_blocked), (gst_pad_unlink), (gst_pad_is_linked),
(gst_pad_link_prepare_filtered), (gst_pad_link_filtered),
(gst_pad_get_real_parent), (gst_pad_relink_filtered),
(gst_pad_get_peer), (gst_pad_realize), (gst_pad_get_allowed_caps),
(gst_pad_alloc_buffer), (gst_pad_push), (gst_pad_pull),
(gst_pad_pull_range), (gst_pad_push_event):
* gst/gstpad.h:
* gst/gstpipeline.c: (gst_pipeline_init), (gst_pipeline_dispose),
(is_eos), (pipeline_bus_handler):
* gst/gstutils.c: (gst_element_get_compatible_pad_filtered),
(gst_element_link_pads_filtered), (gst_element_unlink):
* gst/parse/grammar.y:
* tools/gst-compprep.c: (main):
* tools/gst-inspect.c: (print_pad_info):
* tools/gst-launch.c: (main):
* tools/gst-xmlinspect.c: (print_element_info):
More MT fixes, added design document describing refcounting
policies used in GStreamer and locking involved.
Fixed unsafe ghostpad dereffing.
Removed old unsafe methods.
2004-12-13 11:33:55 +00:00
|
|
|
Example:
|
|
|
|
|
|
|
|
it = _get_iterator(object);
|
|
|
|
while (!done) {
|
|
|
|
switch (gst_iterator_next (it, &item)) {
|
|
|
|
case GST_ITERATOR_OK:
|
|
|
|
|
|
|
|
... use/change item here...
|
|
|
|
|
|
|
|
/* release item here */
|
|
|
|
gst_object_unref (item);
|
|
|
|
break;
|
|
|
|
case GST_ITERATOR_RESYNC:
|
|
|
|
/* handle rollback caused by concurrent modification
|
|
|
|
* of the list here */
|
|
|
|
|
|
|
|
...rollback changes to items...
|
|
|
|
|
|
|
|
/* resync iterator to start again */
|
|
|
|
gst_iterator_resync (it);
|
|
|
|
break;
|
|
|
|
case GST_ITERATOR_DONE:
|
|
|
|
done = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
gst_iterator_free (it);
|