diff options
Diffstat (limited to 'gst/gstminiobject.c')
-rw-r--r-- | gst/gstminiobject.c | 117 |
1 files changed, 83 insertions, 34 deletions
diff --git a/gst/gstminiobject.c b/gst/gstminiobject.c index 78749ddc9..bfc572428 100644 --- a/gst/gstminiobject.c +++ b/gst/gstminiobject.c @@ -66,6 +66,7 @@ gst_mini_object_init (GstMiniObject * mini_object, GType type, gsize size) mini_object->type = type; mini_object->refcount = 1; mini_object->flags = 0; + mini_object->lock = 0; mini_object->size = size; mini_object->n_weak_refs = 0; mini_object->weak_refs = NULL; @@ -97,47 +98,26 @@ gst_mini_object_copy (const GstMiniObject * mini_object) } /** - * gst_mini_object_is_writable: - * @mini_object: the mini-object to check - * - * Checks if a mini-object is writable. A mini-object is writable - * if the reference count is one and the #GST_MINI_OBJECT_FLAG_READONLY - * flag is not set. Modification of a mini-object should only be - * done after verifying that it is writable. - * - * MT safe - * - * Returns: TRUE if the object is writable. - */ -gboolean -gst_mini_object_is_writable (const GstMiniObject * mini_object) -{ - g_return_val_if_fail (mini_object != NULL, FALSE); - - return (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1); -} - -/** - * gst_mini_object_make_writable: + * gst_mini_object_make_locked: * @mini_object: (transfer full): the mini-object to make writable * - * Checks if a mini-object is writable. If not, a writable copy is made and - * returned. This gives away the reference to the original mini object, + * Checks if @mini-object can be locked according to @mode. If not, a copy + * is made and returned. This gives away the reference to the original mini object, * and returns a reference to the new object. * * MT safe * * Returns: (transfer full): a mini-object (possibly the same pointer) that - * is writable. + * is locked according to @mode. */ GstMiniObject * -gst_mini_object_make_writable (GstMiniObject * mini_object) +gst_mini_object_make_locked (GstMiniObject * mini_object, GstLockMode mode) { GstMiniObject *ret; g_return_val_if_fail (mini_object != NULL, NULL); - if (gst_mini_object_is_writable (mini_object)) { + if (gst_mini_object_try_lock (mini_object, mode)) { ret = mini_object; } else { ret = gst_mini_object_copy (mini_object); @@ -145,7 +125,6 @@ gst_mini_object_make_writable (GstMiniObject * mini_object) g_type_name (GST_MINI_OBJECT_TYPE (mini_object)), mini_object, ret); gst_mini_object_unref (mini_object); } - return ret; } @@ -155,12 +134,9 @@ gst_mini_object_make_writable (GstMiniObject * mini_object) * * Increase the reference count of the mini-object. * - * Note that the refcount affects the writeability - * of @mini-object, see gst_mini_object_is_writable(). It is - * important to note that keeping additional references to - * GstMiniObject instances can potentially increase the number - * of memcpy operations in a pipeline, especially if the miniobject - * is a #GstBuffer. + * Note that the refcount does not affect the writability of @mini_object. If + * you don't want other threads to modify @mini_object, you should use + * gst_mini_object_try_lock(). * * Returns: (transfer full): the mini-object. */ @@ -236,6 +212,79 @@ gst_mini_object_unref (GstMiniObject * mini_object) } /** + * gst_mini_object_try_lock: + * @mini_object: the mini-object + * @mode: the desired access mode + * + * Try to lock @mini_object in @mode. For each successful call to + * gst_mini_object_try_lock() a corresponding call to gst_mini_object_unlock() + * should be made. + * + * Once an object is locked in a certain mode, it cannot be locked in another + * mode. To make the object readonly, one can use a @mode of GST_LOCK_READ. + * + * Note that locking an object in write-only mode is dangerous when there are other + * references to the mini object because any attempt to read will fail as will + * any attempt to make a copy. + * + * Returns: %TRUE if @mini_object could be locked in @mode. %FALSE is returned + * when the object was already locked in a different mode. + */ +gboolean +gst_mini_object_try_lock (GstMiniObject * mini_object, GstLockMode mode) +{ + gint access_mode, state, newstate; + + access_mode = mode & 3; + + do { + state = g_atomic_int_get (&mini_object->lock); + if (state == 0) { + /* nothing mapped, set access_mode and refcount */ + newstate = 4 | access_mode; + } else { + /* access_mode must match */ + if ((state & access_mode) != access_mode) + goto lock_failed; + /* increase refcount */ + newstate = state + 4; + } + } while (!g_atomic_int_compare_and_exchange (&mini_object->lock, state, + newstate)); + + return TRUE; + +lock_failed: + { + GST_ERROR ("lock failed %p: state %d, access_mode %d", mini_object, state, + access_mode); + return FALSE; + } +} + +/** + * gst_mini_object_lock: + * @mini_object: the mini-object + * + * Unlock @mini_object. + */ +void +gst_mini_object_unlock (GstMiniObject * mini_object) +{ + gint state, newstate; + + do { + state = g_atomic_int_get (&mini_object->lock); + /* decrease the refcount */ + newstate = state - 4; + /* last refcount, unset access_mode */ + if (newstate < 4) + newstate = 0; + } while (!g_atomic_int_compare_and_exchange (&mini_object->lock, state, + newstate)); +} + +/** * gst_mini_object_replace: * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to * be replaced |