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:
Wim Taymans 2012-07-04 16:38:15 +02:00
parent afd5db3c6b
commit 3b16efa1d1
18 changed files with 229 additions and 198 deletions

View file

@ -1339,7 +1339,7 @@ gst_memory_new_wrapped
gst_memory_ref gst_memory_ref
gst_memory_unref gst_memory_unref
gst_memory_is_exclusive gst_memory_is_writable
gst_memory_get_sizes gst_memory_get_sizes
gst_memory_resize gst_memory_resize

View file

@ -265,8 +265,10 @@ _replace_memory (GstBuffer * buffer, guint len, guint idx, guint length,
/* unref old memory */ /* unref old memory */
for (i = idx; i < end; i++) { for (i = idx; i < end; i++) {
gst_memory_unlock (GST_BUFFER_MEM_PTR (buffer, i), GST_LOCK_FLAG_EXCLUSIVE); GstMemory *old = GST_BUFFER_MEM_PTR (buffer, i);
gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i));
gst_memory_unlock (old, GST_LOCK_FLAG_EXCLUSIVE);
gst_memory_unref (old);
} }
if (mem != NULL) { if (mem != NULL) {
@ -536,7 +538,7 @@ _gst_buffer_free (GstBuffer * buffer)
static void static void
gst_buffer_init (GstBufferImpl * buffer, gsize size) 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, (GstMiniObjectCopyFunction) _gst_buffer_copy,
(GstMiniObjectDisposeFunction) _gst_buffer_dispose, (GstMiniObjectDisposeFunction) _gst_buffer_dispose,
(GstMiniObjectFreeFunction) _gst_buffer_free); (GstMiniObjectFreeFunction) _gst_buffer_free);
@ -818,7 +820,7 @@ _get_mapped (GstBuffer * buffer, guint idx, GstMapInfo * info,
* any call that modifies the memory in @buffer. * any call that modifies the memory in @buffer.
* *
* Since this call does not influence the refcount of the memory, * 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. * of the returned memory.
* *
* Returns: (transfer none): the #GstMemory at @idx. * 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_IS_BUFFER (buffer));
g_return_if_fail (gst_buffer_is_writable (buffer)); g_return_if_fail (gst_buffer_is_writable (buffer));
len = GST_BUFFER_MEM_LEN (buffer); len = GST_BUFFER_MEM_LEN (buffer);
g_return_if_fail ((len == 0 && idx == 0 && length == -1) || g_return_if_fail ((len == 0 && idx == 0 && length == -1) ||
(length == -1 && idx < len) || (length > 0 && length + idx <= len)); (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); left = MIN (bsize - offset, size);
if (offset != 0 || left != bsize) { if (offset != 0 || left != bsize) {
if (gst_memory_is_exclusive (mem)) { if (gst_memory_is_writable (mem)) {
gst_memory_resize (mem, offset, left); gst_memory_resize (mem, offset, left);
} else { } else {
GstMemory *newmem; GstMemory *newmem;

View file

@ -319,9 +319,8 @@ void gst_buffer_unmap (GstBuffer *buffer, GstMapInfo *info)
* Increases the refcount of the given buffer by one. * Increases the refcount of the given buffer by one.
* *
* Note that the refcount affects the writeability * Note that the refcount affects the writeability
* of @buf and its metadata, see gst_buffer_is_writable() and * of @buf and its metadata, see gst_buffer_is_writable().
* gst_buffer_is_metadata_writable(). It is * It is important to note that keeping additional references to
* important to note that keeping additional references to
* GstBuffer instances can potentially increase the number * GstBuffer instances can potentially increase the number
* of memcpy operations in a pipeline. * of memcpy operations in a pipeline.
* *
@ -426,10 +425,9 @@ void gst_buffer_copy_into (GstBuffer *dest, GstBuffer *src
* gst_buffer_is_writable: * gst_buffer_is_writable:
* @buf: a #GstBuffer * @buf: a #GstBuffer
* *
* Tests if you can safely write data into a buffer's data array or validly * Tests if you can safely write to a buffer's metadata or its memory array.
* modify the caps and timestamp metadata. Metadata in a GstBuffer is always * It is only safe to change buffer metadata when the current reference is
* writable, but it is only safe to change it when there is only one owner * writable, i.e. nobody can see the modifications you will make.
* of the buffer - ie, the refcount is 1.
*/ */
#define gst_buffer_is_writable(buf) gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (buf)) #define gst_buffer_is_writable(buf) gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (buf))
/** /**

View file

@ -103,7 +103,7 @@ _gst_buffer_list_free (GstBufferList * list)
static void static void
gst_buffer_list_init (GstBufferList * list, guint asize) 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, (GstMiniObjectCopyFunction) _gst_buffer_list_copy, NULL,
(GstMiniObjectFreeFunction) _gst_buffer_list_free); (GstMiniObjectFreeFunction) _gst_buffer_list_free);

View file

@ -185,7 +185,7 @@ _gst_caps_free (GstCaps * caps)
static void static void
gst_caps_init (GstCaps * caps) 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, (GstMiniObjectCopyFunction) _gst_caps_copy, NULL,
(GstMiniObjectFreeFunction) _gst_caps_free); (GstMiniObjectFreeFunction) _gst_caps_free);

View file

@ -262,7 +262,7 @@ gst_caps_copy (const GstCaps * caps)
* @caps: a #GstCaps * @caps: a #GstCaps
* *
* Tests if you can safely modify @caps. It is only safe to modify caps when * 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)) #define gst_caps_is_writable(caps) gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (caps))

View file

@ -261,7 +261,7 @@ _gst_event_copy (GstEvent * event)
static void static void
gst_event_init (GstEventImpl * event, GstEventType type) 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, (GstMiniObjectCopyFunction) _gst_event_copy, NULL,
(GstMiniObjectFreeFunction) _gst_event_free); (GstMiniObjectFreeFunction) _gst_event_free);

View file

@ -133,8 +133,6 @@ _gst_memory_copy (GstMemory * mem)
static void static void
_gst_memory_free (GstMemory * mem) _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); 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, gsize maxsize, gsize offset, gsize size, gsize align,
gpointer user_data, GDestroyNotify notify) 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, (GstMiniObjectCopyFunction) _gst_memory_copy, NULL,
(GstMiniObjectFreeFunction) _gst_memory_free); (GstMiniObjectFreeFunction) _gst_memory_free);
mem->mem.mini_object.flags = flags;
mem->mem.allocator = _default_mem_impl; mem->mem.allocator = _default_mem_impl;
mem->mem.parent = parent ? gst_memory_ref (parent) : NULL; 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.maxsize = maxsize;
mem->mem.align = align; mem->mem.align = align;
mem->mem.offset = offset; mem->mem.offset = offset;
@ -434,25 +430,6 @@ gst_memory_new_wrapped (GstMemoryFlags flags, gpointer data,
return (GstMemory *) mem; 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: * gst_memory_get_sizes:
* @mem: a #GstMemory * @mem: a #GstMemory
@ -507,99 +484,6 @@ gst_memory_resize (GstMemory * mem, gssize offset, gsize size)
mem->size = 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: * gst_memory_make_mapped:
* @mem: (transfer full): a #GstMemory * @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 (mem != NULL);
g_return_if_fail (info != NULL); g_return_if_fail (info != NULL);
g_return_if_fail (info->memory == mem); 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); mem->allocator->info.mem_unmap (mem);
gst_memory_unlock (mem, info->flags); gst_memory_unlock (mem, info->flags);
@ -861,7 +743,7 @@ gst_allocator_new (const GstMemoryInfo * info, gpointer user_data,
allocator = g_slice_new0 (GstAllocator); 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, (GstMiniObjectCopyFunction) _gst_allocator_copy, NULL,
(GstMiniObjectFreeFunction) _gst_allocator_free); (GstMiniObjectFreeFunction) _gst_allocator_free);

View file

@ -66,10 +66,10 @@ GST_EXPORT gsize gst_memory_alignment;
* Flags for wrapped memory. * Flags for wrapped memory.
*/ */
typedef enum { typedef enum {
GST_MEMORY_FLAG_READONLY = (GST_MINI_OBJECT_FLAG_LAST << 0), GST_MEMORY_FLAG_READONLY = GST_MINI_OBJECT_FLAG_LOCK_READONLY,
GST_MEMORY_FLAG_NO_SHARE = (GST_MINI_OBJECT_FLAG_LAST << 1), GST_MEMORY_FLAG_NO_SHARE = (GST_MINI_OBJECT_FLAG_LAST << 0),
GST_MEMORY_FLAG_ZERO_PREFIXED = (GST_MINI_OBJECT_FLAG_LAST << 2), GST_MEMORY_FLAG_ZERO_PREFIXED = (GST_MINI_OBJECT_FLAG_LAST << 1),
GST_MEMORY_FLAG_ZERO_PADDED = (GST_MINI_OBJECT_FLAG_LAST << 3), GST_MEMORY_FLAG_ZERO_PADDED = (GST_MINI_OBJECT_FLAG_LAST << 2),
GST_MEMORY_FLAG_LAST = (GST_MINI_OBJECT_FLAG_LAST << 16) GST_MEMORY_FLAG_LAST = (GST_MINI_OBJECT_FLAG_LAST << 16)
} GstMemoryFlags; } GstMemoryFlags;
@ -133,7 +133,6 @@ typedef enum {
* @mini_object: parent structure * @mini_object: parent structure
* @allocator: pointer to the #GstAllocator * @allocator: pointer to the #GstAllocator
* @parent: parent memory block * @parent: parent memory block
* @state: private state
* @maxsize: the maximum size allocated * @maxsize: the maximum size allocated
* @align: the alignment of the memory * @align: the alignment of the memory
* @offset: the offset where valid data starts * @offset: the offset where valid data starts
@ -148,37 +147,12 @@ struct _GstMemory {
GstAllocator *allocator; GstAllocator *allocator;
GstMemory *parent; GstMemory *parent;
volatile gint state;
gsize maxsize; gsize maxsize;
gsize align; gsize align;
gsize offset; gsize offset;
gsize size; 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: * GstMapFlags:
* @GST_MAP_READ: map for read access * @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)); 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 */ /* getting/setting memory properties */
gsize gst_memory_get_sizes (GstMemory *mem, gsize *offset, gsize *maxsize); gsize gst_memory_get_sizes (GstMemory *mem, gsize *offset, gsize *maxsize);
void gst_memory_resize (GstMemory *mem, gssize offset, gsize size); 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 */ /* retrieving data */
GstMemory * gst_memory_make_mapped (GstMemory *mem, GstMapInfo *info, GstMapFlags flags); GstMemory * gst_memory_make_mapped (GstMemory *mem, GstMapInfo *info, GstMapFlags flags);
gboolean gst_memory_map (GstMemory *mem, GstMapInfo *info, GstMapFlags flags); gboolean gst_memory_map (GstMemory *mem, GstMapInfo *info, GstMapFlags flags);

View file

@ -239,7 +239,7 @@ static void
gst_message_init (GstMessageImpl * message, GstMessageType type, gst_message_init (GstMessageImpl * message, GstMessageType type,
GstObject * src) 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, (GstMiniObjectCopyFunction) _gst_message_copy, NULL,
(GstMiniObjectFreeFunction) _gst_message_free); (GstMiniObjectFreeFunction) _gst_message_free);

View file

@ -68,6 +68,13 @@ static GstAllocTrace *_gst_mini_object_trace;
G_LOCK_DEFINE_STATIC (qdata_mutex); G_LOCK_DEFINE_STATIC (qdata_mutex);
static GQuark weak_ref_quark; 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 typedef struct
{ {
GQuark quark; GQuark quark;
@ -108,14 +115,16 @@ _priv_gst_mini_object_initialize (void)
* Returns: (transfer full): the new mini-object. * Returns: (transfer full): the new mini-object.
*/ */
void void
gst_mini_object_init (GstMiniObject * mini_object, GType type, gst_mini_object_init (GstMiniObject * mini_object, guint flags, GType type,
GstMiniObjectCopyFunction copy_func, GstMiniObjectCopyFunction copy_func,
GstMiniObjectDisposeFunction dispose_func, GstMiniObjectDisposeFunction dispose_func,
GstMiniObjectFreeFunction free_func) GstMiniObjectFreeFunction free_func)
{ {
mini_object->type = type; mini_object->type = type;
mini_object->refcount = 1; 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->copy = copy_func;
mini_object->dispose = dispose_func; mini_object->dispose = dispose_func;
@ -154,24 +163,138 @@ gst_mini_object_copy (const GstMiniObject * mini_object)
return copy; 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: * gst_mini_object_is_writable:
* @mini_object: the mini-object to check * @mini_object: the mini-object to check
* *
* Checks if a mini-object is writable. A mini-object is writable * If @mini_object has the LOCKABLE flag set, check if the current EXCLUSIVE
* if the reference count is one. Modification of a mini-object should * lock on @object is the only one, this means that changes to the object will
* only be done after verifying that it is writable. * 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. * Returns: TRUE if the object is writable.
*/ */
gboolean gboolean
gst_mini_object_is_writable (const GstMiniObject * mini_object) gst_mini_object_is_writable (const GstMiniObject * mini_object)
{ {
gboolean result;
g_return_val_if_fail (mini_object != NULL, FALSE); 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 /* if the subclass recycled the object (and returned FALSE) we don't
* want to free the instance anymore */ * want to free the instance anymore */
if (G_LIKELY (do_free)) { 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) { if (mini_object->n_qdata) {
call_finalize_notify (mini_object); call_finalize_notify (mini_object);
g_free (mini_object->qdata); g_free (mini_object->qdata);

View file

@ -84,6 +84,7 @@ typedef void (*GstMiniObjectNotify) (gpointer user_data, GstMiniObject * obj);
* This macro returns the type of the mini-object. * This macro returns the type of the mini-object.
*/ */
#define GST_MINI_OBJECT_TYPE(obj) (GST_MINI_OBJECT_CAST(obj)->type) #define GST_MINI_OBJECT_TYPE(obj) (GST_MINI_OBJECT_CAST(obj)->type)
/** /**
* GST_MINI_OBJECT_FLAGS: * GST_MINI_OBJECT_FLAGS:
* @obj: MiniObject to return flags for. * @obj: MiniObject to return flags for.
@ -118,16 +119,55 @@ typedef void (*GstMiniObjectNotify) (gpointer user_data, GstMiniObject * obj);
/** /**
* GstMiniObjectFlags: * 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. * @GST_MINI_OBJECT_FLAG_LAST: first flag that can be used by subclasses.
* *
* Flags for the mini object * Flags for the mini object
*/ */
typedef enum typedef enum
{ {
GST_MINI_OBJECT_FLAG_LOCKABLE = (1 << 0),
GST_MINI_OBJECT_FLAG_LOCK_READONLY = (1 << 1),
/* padding */ /* padding */
GST_MINI_OBJECT_FLAG_LAST = (1<<4) GST_MINI_OBJECT_FLAG_LAST = (1 << 4)
} GstMiniObjectFlags; } 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: * GST_MINI_OBJECT_REFCOUNT:
* @obj: a #GstMiniObject * @obj: a #GstMiniObject
@ -147,6 +187,7 @@ typedef enum
* GstMiniObject: * GstMiniObject:
* @type: the GType of the object * @type: the GType of the object
* @refcount: atomic refcount * @refcount: atomic refcount
* @lockstate: atomic state of the locks
* @flags: extra flags. * @flags: extra flags.
* @copy: a copy function * @copy: a copy function
* @dispose: a dispose function * @dispose: a dispose function
@ -163,6 +204,7 @@ struct _GstMiniObject {
/*< public >*/ /* with COW */ /*< public >*/ /* with COW */
gint refcount; gint refcount;
gint lockstate;
guint flags; guint flags;
GstMiniObjectCopyFunction copy; GstMiniObjectCopyFunction copy;
@ -175,14 +217,12 @@ struct _GstMiniObject {
gpointer qdata; 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, GstMiniObjectCopyFunction copy_func,
GstMiniObjectDisposeFunction dispose_func, GstMiniObjectDisposeFunction dispose_func,
GstMiniObjectFreeFunction free_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 */ /* refcounting */
GstMiniObject * gst_mini_object_ref (GstMiniObject *mini_object); GstMiniObject * gst_mini_object_ref (GstMiniObject *mini_object);
@ -195,6 +235,17 @@ void gst_mini_object_weak_unref (GstMiniObject *object,
GstMiniObjectNotify notify, GstMiniObjectNotify notify,
gpointer data); 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, void gst_mini_object_set_qdata (GstMiniObject *object, GQuark quark,
gpointer data, GDestroyNotify destroy); gpointer data, GDestroyNotify destroy);
gpointer gst_mini_object_get_qdata (GstMiniObject *object, GQuark quark); gpointer gst_mini_object_get_qdata (GstMiniObject *object, GQuark quark);

View file

@ -692,7 +692,7 @@ gst_query_new_custom (GstQueryType type, GstStructure * structure)
goto had_parent; 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, (GstMiniObjectCopyFunction) _gst_query_copy, NULL,
(GstMiniObjectFreeFunction) _gst_query_free); (GstMiniObjectFreeFunction) _gst_query_free);

View file

@ -103,7 +103,7 @@ gst_sample_new (GstBuffer * buffer, GstCaps * caps, const GstSegment * segment,
GST_LOG ("new %p", sample); 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, (GstMiniObjectCopyFunction) _gst_sample_copy, NULL,
(GstMiniObjectFreeFunction) _gst_sample_free); (GstMiniObjectFreeFunction) _gst_sample_free);

View file

@ -665,7 +665,7 @@ gst_tag_list_new_internal (GstStructure * s)
tag_list = (GstTagList *) g_slice_new (GstTagListImpl); 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, (GstMiniObjectCopyFunction) __gst_tag_list_copy, NULL,
(GstMiniObjectFreeFunction) __gst_tag_list_free); (GstMiniObjectFreeFunction) __gst_tag_list_free);

View file

@ -99,7 +99,7 @@ gst_toc_new (void)
toc = g_slice_new0 (GstToc); 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, (GstMiniObjectCopyFunction) gst_toc_copy, NULL,
(GstMiniObjectFreeFunction) gst_toc_free); (GstMiniObjectFreeFunction) gst_toc_free);
@ -117,7 +117,7 @@ gst_toc_entry_new_internal (GstTocEntryType type, const gchar * uid,
entry = g_slice_new0 (GstTocEntry); 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, (GstMiniObjectCopyFunction) gst_toc_entry_copy, NULL,
(GstMiniObjectFreeFunction) gst_toc_entry_free); (GstMiniObjectFreeFunction) gst_toc_entry_free);

View file

@ -428,7 +428,6 @@ GST_START_TEST (test_map_nested)
fail_unless (gst_memory_map (mem, &info2, GST_MAP_READ)); fail_unless (gst_memory_map (mem, &info2, GST_MAP_READ));
gst_memory_unmap (mem, &info2); gst_memory_unmap (mem, &info2);
gst_memory_unmap (mem, &info1); gst_memory_unmap (mem, &info1);
fail_unless (mem->state == 0);
fail_unless (gst_memory_map (mem, &info1, GST_MAP_WRITE)); fail_unless (gst_memory_map (mem, &info1, GST_MAP_WRITE));
/* not allowed */ /* not allowed */

View file

@ -10,6 +10,7 @@ EXPORTS
GST_CAT_ERROR_SYSTEM DATA GST_CAT_ERROR_SYSTEM DATA
GST_CAT_EVENT DATA GST_CAT_EVENT DATA
GST_CAT_GST_INIT DATA GST_CAT_GST_INIT DATA
GST_CAT_LOCKING DATA
GST_CAT_MEMORY DATA GST_CAT_MEMORY DATA
GST_CAT_MESSAGE DATA GST_CAT_MESSAGE DATA
GST_CAT_META DATA GST_CAT_META DATA
@ -518,15 +519,12 @@ EXPORTS
gst_memory_flags_get_type gst_memory_flags_get_type
gst_memory_get_sizes gst_memory_get_sizes
gst_memory_get_type gst_memory_get_type
gst_memory_is_exclusive
gst_memory_is_span gst_memory_is_span
gst_memory_lock
gst_memory_make_mapped gst_memory_make_mapped
gst_memory_map gst_memory_map
gst_memory_new_wrapped gst_memory_new_wrapped
gst_memory_resize gst_memory_resize
gst_memory_share gst_memory_share
gst_memory_unlock
gst_memory_unmap gst_memory_unmap
gst_message_get_seqnum gst_message_get_seqnum
gst_message_get_stream_status_object gst_message_get_stream_status_object
@ -605,6 +603,7 @@ EXPORTS
gst_mini_object_get_qdata gst_mini_object_get_qdata
gst_mini_object_init gst_mini_object_init
gst_mini_object_is_writable gst_mini_object_is_writable
gst_mini_object_lock
gst_mini_object_make_writable gst_mini_object_make_writable
gst_mini_object_ref gst_mini_object_ref
gst_mini_object_replace gst_mini_object_replace
@ -612,6 +611,7 @@ EXPORTS
gst_mini_object_steal gst_mini_object_steal
gst_mini_object_steal_qdata gst_mini_object_steal_qdata
gst_mini_object_take gst_mini_object_take
gst_mini_object_unlock
gst_mini_object_unref gst_mini_object_unref
gst_mini_object_weak_ref gst_mini_object_weak_ref
gst_mini_object_weak_unref gst_mini_object_weak_unref