mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-29 21:21:12 +00:00
miniobject: add lock functionality to GstMiniObject
Move the locking methods from GstMemory to GstMiniObject. Add a miniobject flag to enable LOCKABLE objects. LOCKABLE objects can use the lock/unlock API to control the access to the object. Add a minobject flag that allows you to lock an object in readonly mode. Modify the _is_writable() method to check the shared counter for LOCKABLE objects. This allows us to control writability separately from the refcount for LOCKABLE objects.
This commit is contained in:
parent
afd5db3c6b
commit
3b16efa1d1
18 changed files with 229 additions and 198 deletions
|
@ -1339,7 +1339,7 @@ gst_memory_new_wrapped
|
|||
gst_memory_ref
|
||||
gst_memory_unref
|
||||
|
||||
gst_memory_is_exclusive
|
||||
gst_memory_is_writable
|
||||
|
||||
gst_memory_get_sizes
|
||||
gst_memory_resize
|
||||
|
|
|
@ -265,8 +265,10 @@ _replace_memory (GstBuffer * buffer, guint len, guint idx, guint length,
|
|||
|
||||
/* unref old memory */
|
||||
for (i = idx; i < end; i++) {
|
||||
gst_memory_unlock (GST_BUFFER_MEM_PTR (buffer, i), GST_LOCK_FLAG_EXCLUSIVE);
|
||||
gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i));
|
||||
GstMemory *old = GST_BUFFER_MEM_PTR (buffer, i);
|
||||
|
||||
gst_memory_unlock (old, GST_LOCK_FLAG_EXCLUSIVE);
|
||||
gst_memory_unref (old);
|
||||
}
|
||||
|
||||
if (mem != NULL) {
|
||||
|
@ -536,7 +538,7 @@ _gst_buffer_free (GstBuffer * buffer)
|
|||
static void
|
||||
gst_buffer_init (GstBufferImpl * buffer, gsize size)
|
||||
{
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (buffer), _gst_buffer_type,
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (buffer), 0, _gst_buffer_type,
|
||||
(GstMiniObjectCopyFunction) _gst_buffer_copy,
|
||||
(GstMiniObjectDisposeFunction) _gst_buffer_dispose,
|
||||
(GstMiniObjectFreeFunction) _gst_buffer_free);
|
||||
|
@ -818,7 +820,7 @@ _get_mapped (GstBuffer * buffer, guint idx, GstMapInfo * info,
|
|||
* any call that modifies the memory in @buffer.
|
||||
*
|
||||
* Since this call does not influence the refcount of the memory,
|
||||
* gst_memory_is_exclusive() can be used to check if @buffer is the sole owner
|
||||
* gst_memory_is_writable() can be used to check if @buffer is the sole owner
|
||||
* of the returned memory.
|
||||
*
|
||||
* Returns: (transfer none): the #GstMemory at @idx.
|
||||
|
@ -924,6 +926,7 @@ gst_buffer_replace_memory_range (GstBuffer * buffer, guint idx, gint length,
|
|||
|
||||
g_return_if_fail (GST_IS_BUFFER (buffer));
|
||||
g_return_if_fail (gst_buffer_is_writable (buffer));
|
||||
|
||||
len = GST_BUFFER_MEM_LEN (buffer);
|
||||
g_return_if_fail ((len == 0 && idx == 0 && length == -1) ||
|
||||
(length == -1 && idx < len) || (length > 0 && length + idx <= len));
|
||||
|
@ -1230,7 +1233,7 @@ gst_buffer_resize_range (GstBuffer * buffer, guint idx, gint length,
|
|||
left = MIN (bsize - offset, size);
|
||||
|
||||
if (offset != 0 || left != bsize) {
|
||||
if (gst_memory_is_exclusive (mem)) {
|
||||
if (gst_memory_is_writable (mem)) {
|
||||
gst_memory_resize (mem, offset, left);
|
||||
} else {
|
||||
GstMemory *newmem;
|
||||
|
|
|
@ -319,9 +319,8 @@ void gst_buffer_unmap (GstBuffer *buffer, GstMapInfo *info)
|
|||
* Increases the refcount of the given buffer by one.
|
||||
*
|
||||
* Note that the refcount affects the writeability
|
||||
* of @buf and its metadata, see gst_buffer_is_writable() and
|
||||
* gst_buffer_is_metadata_writable(). It is
|
||||
* important to note that keeping additional references to
|
||||
* of @buf and its metadata, see gst_buffer_is_writable().
|
||||
* It is important to note that keeping additional references to
|
||||
* GstBuffer instances can potentially increase the number
|
||||
* of memcpy operations in a pipeline.
|
||||
*
|
||||
|
@ -426,10 +425,9 @@ void gst_buffer_copy_into (GstBuffer *dest, GstBuffer *src
|
|||
* gst_buffer_is_writable:
|
||||
* @buf: a #GstBuffer
|
||||
*
|
||||
* Tests if you can safely write data into a buffer's data array or validly
|
||||
* modify the caps and timestamp metadata. Metadata in a GstBuffer is always
|
||||
* writable, but it is only safe to change it when there is only one owner
|
||||
* of the buffer - ie, the refcount is 1.
|
||||
* Tests if you can safely write to a buffer's metadata or its memory array.
|
||||
* It is only safe to change buffer metadata when the current reference is
|
||||
* writable, i.e. nobody can see the modifications you will make.
|
||||
*/
|
||||
#define gst_buffer_is_writable(buf) gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (buf))
|
||||
/**
|
||||
|
|
|
@ -103,7 +103,7 @@ _gst_buffer_list_free (GstBufferList * list)
|
|||
static void
|
||||
gst_buffer_list_init (GstBufferList * list, guint asize)
|
||||
{
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (list), _gst_buffer_list_type,
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (list), 0, _gst_buffer_list_type,
|
||||
(GstMiniObjectCopyFunction) _gst_buffer_list_copy, NULL,
|
||||
(GstMiniObjectFreeFunction) _gst_buffer_list_free);
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ _gst_caps_free (GstCaps * caps)
|
|||
static void
|
||||
gst_caps_init (GstCaps * caps)
|
||||
{
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (caps), _gst_caps_type,
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (caps), 0, _gst_caps_type,
|
||||
(GstMiniObjectCopyFunction) _gst_caps_copy, NULL,
|
||||
(GstMiniObjectFreeFunction) _gst_caps_free);
|
||||
|
||||
|
|
|
@ -262,7 +262,7 @@ gst_caps_copy (const GstCaps * caps)
|
|||
* @caps: a #GstCaps
|
||||
*
|
||||
* Tests if you can safely modify @caps. It is only safe to modify caps when
|
||||
* there is only one owner of the caps - ie, the refcount is 1.
|
||||
* there is only one owner of the caps - ie, the object is writable.
|
||||
*/
|
||||
#define gst_caps_is_writable(caps) gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (caps))
|
||||
|
||||
|
|
|
@ -261,7 +261,7 @@ _gst_event_copy (GstEvent * event)
|
|||
static void
|
||||
gst_event_init (GstEventImpl * event, GstEventType type)
|
||||
{
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (event), _gst_event_type,
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (event), 0, _gst_event_type,
|
||||
(GstMiniObjectCopyFunction) _gst_event_copy, NULL,
|
||||
(GstMiniObjectFreeFunction) _gst_event_free);
|
||||
|
||||
|
|
124
gst/gstmemory.c
124
gst/gstmemory.c
|
@ -133,8 +133,6 @@ _gst_memory_copy (GstMemory * mem)
|
|||
static void
|
||||
_gst_memory_free (GstMemory * mem)
|
||||
{
|
||||
/* there should be no outstanding mappings */
|
||||
g_return_if_fail ((g_atomic_int_get (&mem->state) & LOCK_MASK) < 4);
|
||||
mem->allocator->info.mem_free (mem);
|
||||
}
|
||||
|
||||
|
@ -145,15 +143,13 @@ _default_mem_init (GstMemoryDefault * mem, GstMemoryFlags flags,
|
|||
gsize maxsize, gsize offset, gsize size, gsize align,
|
||||
gpointer user_data, GDestroyNotify notify)
|
||||
{
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (mem), GST_TYPE_MEMORY,
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (mem),
|
||||
flags | GST_MINI_OBJECT_FLAG_LOCKABLE, GST_TYPE_MEMORY,
|
||||
(GstMiniObjectCopyFunction) _gst_memory_copy, NULL,
|
||||
(GstMiniObjectFreeFunction) _gst_memory_free);
|
||||
|
||||
mem->mem.mini_object.flags = flags;
|
||||
|
||||
mem->mem.allocator = _default_mem_impl;
|
||||
mem->mem.parent = parent ? gst_memory_ref (parent) : NULL;
|
||||
mem->mem.state = (flags & GST_MEMORY_FLAG_READONLY ? GST_LOCK_FLAG_READ : 0);
|
||||
mem->mem.maxsize = maxsize;
|
||||
mem->mem.align = align;
|
||||
mem->mem.offset = offset;
|
||||
|
@ -434,25 +430,6 @@ gst_memory_new_wrapped (GstMemoryFlags flags, gpointer data,
|
|||
return (GstMemory *) mem;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_memory_is_exclusive:
|
||||
* @mem: a #GstMemory
|
||||
*
|
||||
* Check if the current EXCLUSIVE lock on @mem is the only one, this means that
|
||||
* changes to the object will not be visible to any other object.
|
||||
*/
|
||||
gboolean
|
||||
gst_memory_is_exclusive (GstMemory * mem)
|
||||
{
|
||||
gint state;
|
||||
|
||||
g_return_val_if_fail (mem != NULL, FALSE);
|
||||
|
||||
state = g_atomic_int_get (&mem->state);
|
||||
|
||||
return (state & SHARE_MASK) < 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_memory_get_sizes:
|
||||
* @mem: a #GstMemory
|
||||
|
@ -507,99 +484,6 @@ gst_memory_resize (GstMemory * mem, gssize offset, gsize size)
|
|||
mem->size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_memory_lock:
|
||||
* @mem: a #GstMemory
|
||||
* @flags: #GstLockFlags
|
||||
*
|
||||
* Lock the memory with the specified access mode in @flags.
|
||||
*
|
||||
* Returns: %TRUE if the memory could be locked.
|
||||
*/
|
||||
gboolean
|
||||
gst_memory_lock (GstMemory * mem, GstLockFlags flags)
|
||||
{
|
||||
gint access_mode, state, newstate;
|
||||
|
||||
access_mode = flags & FLAG_MASK;
|
||||
|
||||
do {
|
||||
newstate = state = g_atomic_int_get (&mem->state);
|
||||
|
||||
GST_CAT_TRACE (GST_CAT_MEMORY, "lock %p: state %08x, access_mode %d",
|
||||
mem, state, access_mode);
|
||||
|
||||
if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
|
||||
/* shared ref */
|
||||
newstate += SHARE_ONE;
|
||||
access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE;
|
||||
}
|
||||
|
||||
if (access_mode) {
|
||||
if ((state & LOCK_FLAG_MASK) == 0) {
|
||||
/* shared counter > 1 and write access */
|
||||
if (state > SHARE_ONE && access_mode & GST_LOCK_FLAG_WRITE)
|
||||
goto lock_failed;
|
||||
/* nothing mapped, set access_mode */
|
||||
newstate |= access_mode;
|
||||
} else {
|
||||
/* access_mode must match */
|
||||
if ((state & access_mode) != access_mode)
|
||||
goto lock_failed;
|
||||
}
|
||||
/* increase refcount */
|
||||
newstate += LOCK_ONE;
|
||||
}
|
||||
} while (!g_atomic_int_compare_and_exchange (&mem->state, state, newstate));
|
||||
|
||||
return TRUE;
|
||||
|
||||
lock_failed:
|
||||
{
|
||||
GST_CAT_DEBUG (GST_CAT_MEMORY, "lock failed %p: state %08x, access_mode %d",
|
||||
mem, state, access_mode);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_memory_unlock:
|
||||
* @mem: a #GstMemory
|
||||
* @flags: #GstLockFlags
|
||||
*
|
||||
* Unlock the memory with the specified access mode in @flags.
|
||||
*/
|
||||
void
|
||||
gst_memory_unlock (GstMemory * mem, GstLockFlags flags)
|
||||
{
|
||||
gint access_mode, state, newstate;
|
||||
|
||||
access_mode = flags & FLAG_MASK;
|
||||
|
||||
do {
|
||||
newstate = state = g_atomic_int_get (&mem->state);
|
||||
|
||||
GST_CAT_TRACE (GST_CAT_MEMORY, "unlock %p: state %08x, access_mode %d",
|
||||
mem, state, access_mode);
|
||||
|
||||
if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
|
||||
/* shared counter */
|
||||
g_return_if_fail (state >= SHARE_ONE);
|
||||
newstate -= SHARE_ONE;
|
||||
access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE;
|
||||
}
|
||||
|
||||
if (access_mode) {
|
||||
g_return_if_fail ((state & access_mode) == access_mode);
|
||||
/* decrease the refcount */
|
||||
newstate -= LOCK_ONE;
|
||||
/* last refcount, unset access_mode */
|
||||
if ((newstate & LOCK_FLAG_MASK) == access_mode)
|
||||
newstate &= ~LOCK_FLAG_MASK;
|
||||
}
|
||||
} while (!g_atomic_int_compare_and_exchange (&mem->state, state, newstate));
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_memory_make_mapped:
|
||||
* @mem: (transfer full): a #GstMemory
|
||||
|
@ -721,8 +605,6 @@ gst_memory_unmap (GstMemory * mem, GstMapInfo * info)
|
|||
g_return_if_fail (mem != NULL);
|
||||
g_return_if_fail (info != NULL);
|
||||
g_return_if_fail (info->memory == mem);
|
||||
/* there must be a ref */
|
||||
g_return_if_fail (g_atomic_int_get (&mem->state) >= 4);
|
||||
|
||||
mem->allocator->info.mem_unmap (mem);
|
||||
gst_memory_unlock (mem, info->flags);
|
||||
|
@ -861,7 +743,7 @@ gst_allocator_new (const GstMemoryInfo * info, gpointer user_data,
|
|||
|
||||
allocator = g_slice_new0 (GstAllocator);
|
||||
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (allocator), GST_TYPE_ALLOCATOR,
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (allocator), 0, GST_TYPE_ALLOCATOR,
|
||||
(GstMiniObjectCopyFunction) _gst_allocator_copy, NULL,
|
||||
(GstMiniObjectFreeFunction) _gst_allocator_free);
|
||||
|
||||
|
|
|
@ -66,10 +66,10 @@ GST_EXPORT gsize gst_memory_alignment;
|
|||
* Flags for wrapped memory.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_MEMORY_FLAG_READONLY = (GST_MINI_OBJECT_FLAG_LAST << 0),
|
||||
GST_MEMORY_FLAG_NO_SHARE = (GST_MINI_OBJECT_FLAG_LAST << 1),
|
||||
GST_MEMORY_FLAG_ZERO_PREFIXED = (GST_MINI_OBJECT_FLAG_LAST << 2),
|
||||
GST_MEMORY_FLAG_ZERO_PADDED = (GST_MINI_OBJECT_FLAG_LAST << 3),
|
||||
GST_MEMORY_FLAG_READONLY = GST_MINI_OBJECT_FLAG_LOCK_READONLY,
|
||||
GST_MEMORY_FLAG_NO_SHARE = (GST_MINI_OBJECT_FLAG_LAST << 0),
|
||||
GST_MEMORY_FLAG_ZERO_PREFIXED = (GST_MINI_OBJECT_FLAG_LAST << 1),
|
||||
GST_MEMORY_FLAG_ZERO_PADDED = (GST_MINI_OBJECT_FLAG_LAST << 2),
|
||||
|
||||
GST_MEMORY_FLAG_LAST = (GST_MINI_OBJECT_FLAG_LAST << 16)
|
||||
} GstMemoryFlags;
|
||||
|
@ -133,7 +133,6 @@ typedef enum {
|
|||
* @mini_object: parent structure
|
||||
* @allocator: pointer to the #GstAllocator
|
||||
* @parent: parent memory block
|
||||
* @state: private state
|
||||
* @maxsize: the maximum size allocated
|
||||
* @align: the alignment of the memory
|
||||
* @offset: the offset where valid data starts
|
||||
|
@ -148,37 +147,12 @@ struct _GstMemory {
|
|||
GstAllocator *allocator;
|
||||
|
||||
GstMemory *parent;
|
||||
volatile gint state;
|
||||
gsize maxsize;
|
||||
gsize align;
|
||||
gsize offset;
|
||||
gsize size;
|
||||
};
|
||||
|
||||
/**
|
||||
* GstLockFlags:
|
||||
* @GST_LOCK_FLAG_READ: lock for read access
|
||||
* @GST_LOCK_FLAG_WRITE: lock for write access
|
||||
* @GST_LOCK_FLAG_EXCLUSIVE: lock for exclusive access
|
||||
* @GST_LOCK_FLAG_LAST: first flag that can be used for custom purposes
|
||||
*
|
||||
* Flags used when locking memory
|
||||
*/
|
||||
typedef enum {
|
||||
GST_LOCK_FLAG_READ = (1 << 0),
|
||||
GST_LOCK_FLAG_WRITE = (1 << 1),
|
||||
GST_LOCK_FLAG_EXCLUSIVE = (1 << 2),
|
||||
|
||||
GST_LOCK_FLAG_LAST = (1 << 4)
|
||||
} GstLockFlags;
|
||||
|
||||
/**
|
||||
* GST_LOCK_FLAG_READWRITE:
|
||||
*
|
||||
* GstLockFlags value alias for GST_LOCK_FLAG_READ | GST_LOCK_FLAG_WRITE
|
||||
*/
|
||||
#define GST_LOCK_FLAG_READWRITE (GST_LOCK_FLAG_READ | GST_LOCK_FLAG_WRITE)
|
||||
|
||||
/**
|
||||
* GstMapFlags:
|
||||
* @GST_MAP_READ: map for read access
|
||||
|
@ -487,17 +461,14 @@ gst_memory_unref (GstMemory * memory)
|
|||
gst_mini_object_unref (GST_MINI_OBJECT_CAST (memory));
|
||||
}
|
||||
|
||||
/* locking */
|
||||
|
||||
gboolean gst_memory_is_exclusive (GstMemory *mem);
|
||||
|
||||
gboolean gst_memory_lock (GstMemory *mem, GstLockFlags flags);
|
||||
void gst_memory_unlock (GstMemory *mem, GstLockFlags flags);
|
||||
|
||||
/* getting/setting memory properties */
|
||||
gsize gst_memory_get_sizes (GstMemory *mem, gsize *offset, gsize *maxsize);
|
||||
void gst_memory_resize (GstMemory *mem, gssize offset, gsize size);
|
||||
|
||||
#define gst_memory_lock(m,f) gst_mini_object_lock (GST_MINI_OBJECT_CAST (m), (f))
|
||||
#define gst_memory_unlock(m,f) gst_mini_object_unlock (GST_MINI_OBJECT_CAST (m), (f))
|
||||
#define gst_memory_is_writable(m) gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (m))
|
||||
|
||||
/* retrieving data */
|
||||
GstMemory * gst_memory_make_mapped (GstMemory *mem, GstMapInfo *info, GstMapFlags flags);
|
||||
gboolean gst_memory_map (GstMemory *mem, GstMapInfo *info, GstMapFlags flags);
|
||||
|
|
|
@ -239,7 +239,7 @@ static void
|
|||
gst_message_init (GstMessageImpl * message, GstMessageType type,
|
||||
GstObject * src)
|
||||
{
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (message), _gst_message_type,
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (message), 0, _gst_message_type,
|
||||
(GstMiniObjectCopyFunction) _gst_message_copy, NULL,
|
||||
(GstMiniObjectFreeFunction) _gst_message_free);
|
||||
|
||||
|
|
|
@ -68,6 +68,13 @@ static GstAllocTrace *_gst_mini_object_trace;
|
|||
G_LOCK_DEFINE_STATIC (qdata_mutex);
|
||||
static GQuark weak_ref_quark;
|
||||
|
||||
#define SHARE_ONE (1 << 16)
|
||||
#define SHARE_MASK (~(SHARE_ONE - 1))
|
||||
#define LOCK_ONE (GST_LOCK_FLAG_LAST)
|
||||
#define FLAG_MASK (GST_LOCK_FLAG_LAST - 1)
|
||||
#define LOCK_MASK ((SHARE_ONE - 1) - FLAG_MASK)
|
||||
#define LOCK_FLAG_MASK (SHARE_ONE - 1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GQuark quark;
|
||||
|
@ -108,14 +115,16 @@ _priv_gst_mini_object_initialize (void)
|
|||
* Returns: (transfer full): the new mini-object.
|
||||
*/
|
||||
void
|
||||
gst_mini_object_init (GstMiniObject * mini_object, GType type,
|
||||
gst_mini_object_init (GstMiniObject * mini_object, guint flags, GType type,
|
||||
GstMiniObjectCopyFunction copy_func,
|
||||
GstMiniObjectDisposeFunction dispose_func,
|
||||
GstMiniObjectFreeFunction free_func)
|
||||
{
|
||||
mini_object->type = type;
|
||||
mini_object->refcount = 1;
|
||||
mini_object->flags = 0;
|
||||
mini_object->lockstate =
|
||||
(flags & GST_MINI_OBJECT_FLAG_LOCK_READONLY ? GST_LOCK_FLAG_READ : 0);
|
||||
mini_object->flags = flags;
|
||||
|
||||
mini_object->copy = copy_func;
|
||||
mini_object->dispose = dispose_func;
|
||||
|
@ -154,24 +163,138 @@ gst_mini_object_copy (const GstMiniObject * mini_object)
|
|||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_mini_object_lock:
|
||||
* @object: the mini-object to lock
|
||||
* @flags: #GstLockFlags
|
||||
*
|
||||
* Lock the mini-object with the specified access mode in @flags.
|
||||
*
|
||||
* Returns: %TRUE if @object could be locked.
|
||||
*/
|
||||
gboolean
|
||||
gst_mini_object_lock (GstMiniObject * object, GstLockFlags flags)
|
||||
{
|
||||
gint access_mode, state, newstate;
|
||||
|
||||
g_return_val_if_fail (object != NULL, FALSE);
|
||||
g_return_val_if_fail (GST_MINI_OBJECT_IS_LOCKABLE (object), FALSE);
|
||||
|
||||
access_mode = flags & FLAG_MASK;
|
||||
|
||||
do {
|
||||
newstate = state = g_atomic_int_get (&object->lockstate);
|
||||
|
||||
GST_CAT_TRACE (GST_CAT_LOCKING, "lock %p: state %08x, access_mode %d",
|
||||
object, state, access_mode);
|
||||
|
||||
if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
|
||||
/* shared ref */
|
||||
newstate += SHARE_ONE;
|
||||
access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE;
|
||||
}
|
||||
|
||||
if (access_mode) {
|
||||
if ((state & LOCK_FLAG_MASK) == 0) {
|
||||
/* shared counter > 1 and write access */
|
||||
if (state > SHARE_ONE && access_mode & GST_LOCK_FLAG_WRITE)
|
||||
goto lock_failed;
|
||||
/* nothing mapped, set access_mode */
|
||||
newstate |= access_mode;
|
||||
} else {
|
||||
/* access_mode must match */
|
||||
if ((state & access_mode) != access_mode)
|
||||
goto lock_failed;
|
||||
}
|
||||
/* increase refcount */
|
||||
newstate += LOCK_ONE;
|
||||
}
|
||||
} while (!g_atomic_int_compare_and_exchange (&object->lockstate, state,
|
||||
newstate));
|
||||
|
||||
return TRUE;
|
||||
|
||||
lock_failed:
|
||||
{
|
||||
GST_CAT_DEBUG (GST_CAT_LOCKING,
|
||||
"lock failed %p: state %08x, access_mode %d", object, state,
|
||||
access_mode);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_mini_object_unlock:
|
||||
* @object: the mini-object to unlock
|
||||
* @flags: #GstLockFlags
|
||||
*
|
||||
* Unlock the mini-object with the specified access mode in @flags.
|
||||
*/
|
||||
void
|
||||
gst_mini_object_unlock (GstMiniObject * object, GstLockFlags flags)
|
||||
{
|
||||
gint access_mode, state, newstate;
|
||||
|
||||
g_return_if_fail (object != NULL);
|
||||
g_return_if_fail (GST_MINI_OBJECT_IS_LOCKABLE (object));
|
||||
|
||||
access_mode = flags & FLAG_MASK;
|
||||
|
||||
do {
|
||||
newstate = state = g_atomic_int_get (&object->lockstate);
|
||||
|
||||
GST_CAT_TRACE (GST_CAT_LOCKING, "unlock %p: state %08x, access_mode %d",
|
||||
object, state, access_mode);
|
||||
|
||||
if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
|
||||
/* shared counter */
|
||||
g_return_if_fail (state >= SHARE_ONE);
|
||||
newstate -= SHARE_ONE;
|
||||
access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE;
|
||||
}
|
||||
|
||||
if (access_mode) {
|
||||
g_return_if_fail ((state & access_mode) == access_mode);
|
||||
/* decrease the refcount */
|
||||
newstate -= LOCK_ONE;
|
||||
/* last refcount, unset access_mode */
|
||||
if ((newstate & LOCK_FLAG_MASK) == access_mode)
|
||||
newstate &= ~LOCK_FLAG_MASK;
|
||||
}
|
||||
} while (!g_atomic_int_compare_and_exchange (&object->lockstate, state,
|
||||
newstate));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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. Modification of a mini-object should
|
||||
* only be done after verifying that it is writable.
|
||||
* If @mini_object has the LOCKABLE flag set, check if the current EXCLUSIVE
|
||||
* lock on @object is the only one, this means that changes to the object will
|
||||
* not be visible to any other object.
|
||||
*
|
||||
* MT safe
|
||||
* If the LOCKABLE flag is not set, check if the refcount of @mini_object is
|
||||
* exactly 1, meaning that no other reference exists to the object and that the
|
||||
* object is therefore writable.
|
||||
*
|
||||
* Modification of a mini-object should only be done after verifying that it
|
||||
* is writable.
|
||||
*
|
||||
* Returns: TRUE if the object is writable.
|
||||
*/
|
||||
gboolean
|
||||
gst_mini_object_is_writable (const GstMiniObject * mini_object)
|
||||
{
|
||||
gboolean result;
|
||||
|
||||
g_return_val_if_fail (mini_object != NULL, FALSE);
|
||||
|
||||
return (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1);
|
||||
if (GST_MINI_OBJECT_IS_LOCKABLE (mini_object)) {
|
||||
result = (g_atomic_int_get (&mini_object->lockstate) & SHARE_MASK) < 2;
|
||||
} else {
|
||||
result = (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -328,6 +451,10 @@ gst_mini_object_unref (GstMiniObject * mini_object)
|
|||
/* if the subclass recycled the object (and returned FALSE) we don't
|
||||
* want to free the instance anymore */
|
||||
if (G_LIKELY (do_free)) {
|
||||
/* there should be no outstanding locks */
|
||||
g_return_if_fail ((g_atomic_int_get (&mini_object->lockstate) & LOCK_MASK)
|
||||
< 4);
|
||||
|
||||
if (mini_object->n_qdata) {
|
||||
call_finalize_notify (mini_object);
|
||||
g_free (mini_object->qdata);
|
||||
|
|
|
@ -84,6 +84,7 @@ typedef void (*GstMiniObjectNotify) (gpointer user_data, GstMiniObject * obj);
|
|||
* This macro returns the type of the mini-object.
|
||||
*/
|
||||
#define GST_MINI_OBJECT_TYPE(obj) (GST_MINI_OBJECT_CAST(obj)->type)
|
||||
|
||||
/**
|
||||
* GST_MINI_OBJECT_FLAGS:
|
||||
* @obj: MiniObject to return flags for.
|
||||
|
@ -118,16 +119,55 @@ typedef void (*GstMiniObjectNotify) (gpointer user_data, GstMiniObject * obj);
|
|||
|
||||
/**
|
||||
* GstMiniObjectFlags:
|
||||
* @GST_MINI_OBJECT_FLAG_LOCKABLE: the object can be locked and unlocked with
|
||||
* gst_mini_object_lock() and gst_mini_object_unlock().
|
||||
* @GST_MINI_OBJECT_FLAG_LOCK_READONLY: the object is permanently locked in
|
||||
* READONLY mode. Only read locks can be performed on the object.
|
||||
* @GST_MINI_OBJECT_FLAG_LAST: first flag that can be used by subclasses.
|
||||
*
|
||||
* Flags for the mini object
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GST_MINI_OBJECT_FLAG_LOCKABLE = (1 << 0),
|
||||
GST_MINI_OBJECT_FLAG_LOCK_READONLY = (1 << 1),
|
||||
/* padding */
|
||||
GST_MINI_OBJECT_FLAG_LAST = (1 << 4)
|
||||
} GstMiniObjectFlags;
|
||||
|
||||
/**
|
||||
* GST_MINI_OBJECT_IS_LOCKABLE:
|
||||
* @obj: a #GstMiniObject
|
||||
*
|
||||
* Check if @obj is lockable. A lockable object can be locked and unlocked with
|
||||
* gst_mini_object_lock() and gst_mini_object_unlock().
|
||||
*/
|
||||
#define GST_MINI_OBJECT_IS_LOCKABLE(obj) GST_MINI_OBJECT_FLAG_IS_SET(obj, GST_MINI_OBJECT_FLAG_LOCKABLE)
|
||||
|
||||
/**
|
||||
* GstLockFlags:
|
||||
* @GST_LOCK_FLAG_READ: lock for read access
|
||||
* @GST_LOCK_FLAG_WRITE: lock for write access
|
||||
* @GST_LOCK_FLAG_EXCLUSIVE: lock for exclusive access
|
||||
* @GST_LOCK_FLAG_LAST: first flag that can be used for custom purposes
|
||||
*
|
||||
* Flags used when locking miniobjects
|
||||
*/
|
||||
typedef enum {
|
||||
GST_LOCK_FLAG_READ = (1 << 0),
|
||||
GST_LOCK_FLAG_WRITE = (1 << 1),
|
||||
GST_LOCK_FLAG_EXCLUSIVE = (1 << 2),
|
||||
|
||||
GST_LOCK_FLAG_LAST = (1 << 4)
|
||||
} GstLockFlags;
|
||||
|
||||
/**
|
||||
* GST_LOCK_FLAG_READWRITE:
|
||||
*
|
||||
* GstLockFlags value alias for GST_LOCK_FLAG_READ | GST_LOCK_FLAG_WRITE
|
||||
*/
|
||||
#define GST_LOCK_FLAG_READWRITE (GST_LOCK_FLAG_READ | GST_LOCK_FLAG_WRITE)
|
||||
|
||||
/**
|
||||
* GST_MINI_OBJECT_REFCOUNT:
|
||||
* @obj: a #GstMiniObject
|
||||
|
@ -147,6 +187,7 @@ typedef enum
|
|||
* GstMiniObject:
|
||||
* @type: the GType of the object
|
||||
* @refcount: atomic refcount
|
||||
* @lockstate: atomic state of the locks
|
||||
* @flags: extra flags.
|
||||
* @copy: a copy function
|
||||
* @dispose: a dispose function
|
||||
|
@ -163,6 +204,7 @@ struct _GstMiniObject {
|
|||
|
||||
/*< public >*/ /* with COW */
|
||||
gint refcount;
|
||||
gint lockstate;
|
||||
guint flags;
|
||||
|
||||
GstMiniObjectCopyFunction copy;
|
||||
|
@ -175,14 +217,12 @@ struct _GstMiniObject {
|
|||
gpointer qdata;
|
||||
};
|
||||
|
||||
void gst_mini_object_init (GstMiniObject *mini_object, GType type,
|
||||
void gst_mini_object_init (GstMiniObject *mini_object,
|
||||
guint flags, GType type,
|
||||
GstMiniObjectCopyFunction copy_func,
|
||||
GstMiniObjectDisposeFunction dispose_func,
|
||||
GstMiniObjectFreeFunction free_func);
|
||||
|
||||
GstMiniObject * gst_mini_object_copy (const GstMiniObject *mini_object) G_GNUC_MALLOC;
|
||||
gboolean gst_mini_object_is_writable (const GstMiniObject *mini_object);
|
||||
GstMiniObject * gst_mini_object_make_writable (GstMiniObject *mini_object);
|
||||
|
||||
/* refcounting */
|
||||
GstMiniObject * gst_mini_object_ref (GstMiniObject *mini_object);
|
||||
|
@ -195,6 +235,17 @@ void gst_mini_object_weak_unref (GstMiniObject *object,
|
|||
GstMiniObjectNotify notify,
|
||||
gpointer data);
|
||||
|
||||
/* locking */
|
||||
gboolean gst_mini_object_lock (GstMiniObject *object, GstLockFlags flags);
|
||||
void gst_mini_object_unlock (GstMiniObject *object, GstLockFlags flags);
|
||||
|
||||
gboolean gst_mini_object_is_writable (const GstMiniObject *mini_object);
|
||||
GstMiniObject * gst_mini_object_make_writable (GstMiniObject *mini_object);
|
||||
|
||||
/* copy */
|
||||
GstMiniObject * gst_mini_object_copy (const GstMiniObject *mini_object) G_GNUC_MALLOC;
|
||||
|
||||
|
||||
void gst_mini_object_set_qdata (GstMiniObject *object, GQuark quark,
|
||||
gpointer data, GDestroyNotify destroy);
|
||||
gpointer gst_mini_object_get_qdata (GstMiniObject *object, GQuark quark);
|
||||
|
|
|
@ -692,7 +692,7 @@ gst_query_new_custom (GstQueryType type, GstStructure * structure)
|
|||
goto had_parent;
|
||||
}
|
||||
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (query), _gst_query_type,
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (query), 0, _gst_query_type,
|
||||
(GstMiniObjectCopyFunction) _gst_query_copy, NULL,
|
||||
(GstMiniObjectFreeFunction) _gst_query_free);
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ gst_sample_new (GstBuffer * buffer, GstCaps * caps, const GstSegment * segment,
|
|||
|
||||
GST_LOG ("new %p", sample);
|
||||
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (sample), _gst_sample_type,
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (sample), 0, _gst_sample_type,
|
||||
(GstMiniObjectCopyFunction) _gst_sample_copy, NULL,
|
||||
(GstMiniObjectFreeFunction) _gst_sample_free);
|
||||
|
||||
|
|
|
@ -665,7 +665,7 @@ gst_tag_list_new_internal (GstStructure * s)
|
|||
|
||||
tag_list = (GstTagList *) g_slice_new (GstTagListImpl);
|
||||
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (tag_list), GST_TYPE_TAG_LIST,
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (tag_list), 0, GST_TYPE_TAG_LIST,
|
||||
(GstMiniObjectCopyFunction) __gst_tag_list_copy, NULL,
|
||||
(GstMiniObjectFreeFunction) __gst_tag_list_free);
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ gst_toc_new (void)
|
|||
|
||||
toc = g_slice_new0 (GstToc);
|
||||
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (toc), GST_TYPE_TOC,
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (toc), 0, GST_TYPE_TOC,
|
||||
(GstMiniObjectCopyFunction) gst_toc_copy, NULL,
|
||||
(GstMiniObjectFreeFunction) gst_toc_free);
|
||||
|
||||
|
@ -117,7 +117,7 @@ gst_toc_entry_new_internal (GstTocEntryType type, const gchar * uid,
|
|||
|
||||
entry = g_slice_new0 (GstTocEntry);
|
||||
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (entry), GST_TYPE_TOC_ENTRY,
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (entry), 0, GST_TYPE_TOC_ENTRY,
|
||||
(GstMiniObjectCopyFunction) gst_toc_entry_copy, NULL,
|
||||
(GstMiniObjectFreeFunction) gst_toc_entry_free);
|
||||
|
||||
|
|
|
@ -428,7 +428,6 @@ GST_START_TEST (test_map_nested)
|
|||
fail_unless (gst_memory_map (mem, &info2, GST_MAP_READ));
|
||||
gst_memory_unmap (mem, &info2);
|
||||
gst_memory_unmap (mem, &info1);
|
||||
fail_unless (mem->state == 0);
|
||||
|
||||
fail_unless (gst_memory_map (mem, &info1, GST_MAP_WRITE));
|
||||
/* not allowed */
|
||||
|
|
|
@ -10,6 +10,7 @@ EXPORTS
|
|||
GST_CAT_ERROR_SYSTEM DATA
|
||||
GST_CAT_EVENT DATA
|
||||
GST_CAT_GST_INIT DATA
|
||||
GST_CAT_LOCKING DATA
|
||||
GST_CAT_MEMORY DATA
|
||||
GST_CAT_MESSAGE DATA
|
||||
GST_CAT_META DATA
|
||||
|
@ -518,15 +519,12 @@ EXPORTS
|
|||
gst_memory_flags_get_type
|
||||
gst_memory_get_sizes
|
||||
gst_memory_get_type
|
||||
gst_memory_is_exclusive
|
||||
gst_memory_is_span
|
||||
gst_memory_lock
|
||||
gst_memory_make_mapped
|
||||
gst_memory_map
|
||||
gst_memory_new_wrapped
|
||||
gst_memory_resize
|
||||
gst_memory_share
|
||||
gst_memory_unlock
|
||||
gst_memory_unmap
|
||||
gst_message_get_seqnum
|
||||
gst_message_get_stream_status_object
|
||||
|
@ -605,6 +603,7 @@ EXPORTS
|
|||
gst_mini_object_get_qdata
|
||||
gst_mini_object_init
|
||||
gst_mini_object_is_writable
|
||||
gst_mini_object_lock
|
||||
gst_mini_object_make_writable
|
||||
gst_mini_object_ref
|
||||
gst_mini_object_replace
|
||||
|
@ -612,6 +611,7 @@ EXPORTS
|
|||
gst_mini_object_steal
|
||||
gst_mini_object_steal_qdata
|
||||
gst_mini_object_take
|
||||
gst_mini_object_unlock
|
||||
gst_mini_object_unref
|
||||
gst_mini_object_weak_ref
|
||||
gst_mini_object_weak_unref
|
||||
|
|
Loading…
Reference in a new issue