summaryrefslogtreecommitdiff
path: root/gst/gstminiobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/gstminiobject.c')
-rw-r--r--gst/gstminiobject.c117
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