~ubuntu-branches/ubuntu/trusty/gstreamer1.0/trusty

« back to all changes in this revision

Viewing changes to gst/gstminiobject.c

  • Committer: Package Import Robot
  • Author(s): Sebastian Dröge
  • Date: 2012-08-08 18:12:33 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20120808181233-riejwxprfsxh1njl
Tags: 0.11.93-1
* New upstream release:
  + debian/libgstreamer.symbols:
    - Update symbols file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
 * object. gst_mini_object_make_writable() will return a writable version of the
41
41
 * object, which might be a new copy when the refcount was not 1.
42
42
 *
43
 
 * Last reviewed on 2012-03-28 (0.11.3)
 
43
 * Opaque data can be associated with a #GstMiniObject with
 
44
 * gst_mini_object_set_qdata() and gst_mini_object_get_qdata(). The data is
 
45
 * meant to be specific to the particular object and is not automatically copied
 
46
 * with gst_mini_object_copy() or similar methods.
 
47
 *
 
48
 * A weak reference can be added and remove with gst_mini_object_weak_ref()
 
49
 * and gst_mini_object_weak_unref() respectively.
 
50
 *
 
51
 * Last reviewed on 2012-06-15 (0.11.93)
44
52
 */
45
53
#ifdef HAVE_CONFIG_H
46
54
#include "config.h"
57
65
#endif
58
66
 
59
67
/* Mutex used for weak referencing */
60
 
G_LOCK_DEFINE_STATIC (weak_refs_mutex);
 
68
G_LOCK_DEFINE_STATIC (qdata_mutex);
 
69
static GQuark weak_ref_quark;
 
70
 
 
71
#define SHARE_ONE (1 << 16)
 
72
#define SHARE_TWO (2 << 16)
 
73
#define SHARE_MASK (~(SHARE_ONE - 1))
 
74
#define IS_SHARED(state) (state >= SHARE_TWO)
 
75
#define LOCK_ONE (GST_LOCK_FLAG_LAST)
 
76
#define FLAG_MASK (GST_LOCK_FLAG_LAST - 1)
 
77
#define LOCK_MASK ((SHARE_ONE - 1) - FLAG_MASK)
 
78
#define LOCK_FLAG_MASK (SHARE_ONE - 1)
 
79
 
 
80
typedef struct
 
81
{
 
82
  GQuark quark;
 
83
  GstMiniObjectNotify notify;
 
84
  gpointer data;
 
85
  GDestroyNotify destroy;
 
86
} GstQData;
 
87
 
 
88
#define QDATA(o,i)          ((GstQData *)(o)->qdata)[(i)]
 
89
#define QDATA_QUARK(o,i)    (QDATA(o,i).quark)
 
90
#define QDATA_NOTIFY(o,i)   (QDATA(o,i).notify)
 
91
#define QDATA_DATA(o,i)     (QDATA(o,i).data)
 
92
#define QDATA_DESTROY(o,i)  (QDATA(o,i).destroy)
61
93
 
62
94
void
63
95
_priv_gst_mini_object_initialize (void)
64
96
{
 
97
  weak_ref_quark = g_quark_from_static_string ("GstMiniObjectWeakRefQuark");
 
98
 
65
99
#ifndef GST_DISABLE_TRACE
66
100
  _gst_mini_object_trace = _gst_alloc_trace_register ("GstMiniObject", 0);
67
101
#endif
68
102
}
69
103
 
70
104
/**
71
 
 * gst_mini_object_init:
72
 
 * @mini_object: a #GstMiniObject 
 
105
 * gst_mini_object_init: (skip)
 
106
 * @mini_object: a #GstMiniObject
73
107
 * @type: the #GType of the mini-object to create
74
 
 * @size: the size of the data
75
 
 *
76
 
 * Initializes a mini-object with the desired type and size.
77
 
 *
78
 
 * MT safe
79
 
 *
80
 
 * Returns: (transfer full): the new mini-object.
 
108
 * @copy_func: the copy function, or NULL
 
109
 * @dispose_func: the dispose function, or NULL
 
110
 * @free_func: the free function or NULL
 
111
 *
 
112
 * Initializes a mini-object with the desired type and copy/dispose/free
 
113
 * functions.
81
114
 */
82
115
void
83
 
gst_mini_object_init (GstMiniObject * mini_object, GType type, gsize size)
 
116
gst_mini_object_init (GstMiniObject * mini_object, guint flags, GType type,
 
117
    GstMiniObjectCopyFunction copy_func,
 
118
    GstMiniObjectDisposeFunction dispose_func,
 
119
    GstMiniObjectFreeFunction free_func)
84
120
{
85
121
  mini_object->type = type;
86
122
  mini_object->refcount = 1;
87
 
  mini_object->flags = 0;
88
 
  mini_object->size = size;
89
 
  mini_object->n_weak_refs = 0;
90
 
  mini_object->weak_refs = NULL;
 
123
  mini_object->lockstate =
 
124
      (flags & GST_MINI_OBJECT_FLAG_LOCK_READONLY ? GST_LOCK_FLAG_READ : 0);
 
125
  mini_object->flags = flags;
 
126
 
 
127
  mini_object->copy = copy_func;
 
128
  mini_object->dispose = dispose_func;
 
129
  mini_object->free = free_func;
 
130
 
 
131
  mini_object->n_qdata = 0;
 
132
  mini_object->qdata = NULL;
91
133
 
92
134
#ifndef GST_DISABLE_TRACE
93
135
  _gst_alloc_trace_new (_gst_mini_object_trace, mini_object);
120
162
}
121
163
 
122
164
/**
 
165
 * gst_mini_object_lock:
 
166
 * @object: the mini-object to lock
 
167
 * @flags: #GstLockFlags
 
168
 *
 
169
 * Lock the mini-object with the specified access mode in @flags.
 
170
 *
 
171
 * Returns: %TRUE if @object could be locked.
 
172
 */
 
173
gboolean
 
174
gst_mini_object_lock (GstMiniObject * object, GstLockFlags flags)
 
175
{
 
176
  gint access_mode, state, newstate;
 
177
 
 
178
  g_return_val_if_fail (object != NULL, FALSE);
 
179
  g_return_val_if_fail (GST_MINI_OBJECT_IS_LOCKABLE (object), FALSE);
 
180
 
 
181
  do {
 
182
    access_mode = flags & FLAG_MASK;
 
183
    newstate = state = g_atomic_int_get (&object->lockstate);
 
184
 
 
185
    GST_CAT_TRACE (GST_CAT_LOCKING, "lock %p: state %08x, access_mode %d",
 
186
        object, state, access_mode);
 
187
 
 
188
    if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
 
189
      /* shared ref */
 
190
      newstate += SHARE_ONE;
 
191
      access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE;
 
192
    }
 
193
 
 
194
    if (access_mode) {
 
195
      /* shared counter > 1 and write access is not allowed */
 
196
      if (access_mode & GST_LOCK_FLAG_WRITE && IS_SHARED (state))
 
197
        goto lock_failed;
 
198
 
 
199
      if ((state & LOCK_FLAG_MASK) == 0) {
 
200
        /* nothing mapped, set access_mode */
 
201
        newstate |= access_mode;
 
202
      } else {
 
203
        /* access_mode must match */
 
204
        if ((state & access_mode) != access_mode)
 
205
          goto lock_failed;
 
206
      }
 
207
      /* increase refcount */
 
208
      newstate += LOCK_ONE;
 
209
    }
 
210
  } while (!g_atomic_int_compare_and_exchange (&object->lockstate, state,
 
211
          newstate));
 
212
 
 
213
  return TRUE;
 
214
 
 
215
lock_failed:
 
216
  {
 
217
    GST_CAT_DEBUG (GST_CAT_LOCKING,
 
218
        "lock failed %p: state %08x, access_mode %d", object, state,
 
219
        access_mode);
 
220
    return FALSE;
 
221
  }
 
222
}
 
223
 
 
224
/**
 
225
 * gst_mini_object_unlock:
 
226
 * @object: the mini-object to unlock
 
227
 * @flags: #GstLockFlags
 
228
 *
 
229
 * Unlock the mini-object with the specified access mode in @flags.
 
230
 */
 
231
void
 
232
gst_mini_object_unlock (GstMiniObject * object, GstLockFlags flags)
 
233
{
 
234
  gint access_mode, state, newstate;
 
235
 
 
236
  g_return_if_fail (object != NULL);
 
237
  g_return_if_fail (GST_MINI_OBJECT_IS_LOCKABLE (object));
 
238
 
 
239
  do {
 
240
    access_mode = flags & FLAG_MASK;
 
241
    newstate = state = g_atomic_int_get (&object->lockstate);
 
242
 
 
243
    GST_CAT_TRACE (GST_CAT_LOCKING, "unlock %p: state %08x, access_mode %d",
 
244
        object, state, access_mode);
 
245
 
 
246
    if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
 
247
      /* shared counter */
 
248
      g_return_if_fail (state >= SHARE_ONE);
 
249
      newstate -= SHARE_ONE;
 
250
      access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE;
 
251
    }
 
252
 
 
253
    if (access_mode) {
 
254
      g_return_if_fail ((state & access_mode) == access_mode);
 
255
      /* decrease the refcount */
 
256
      newstate -= LOCK_ONE;
 
257
      /* last refcount, unset access_mode */
 
258
      if ((newstate & LOCK_FLAG_MASK) == access_mode)
 
259
        newstate &= ~LOCK_FLAG_MASK;
 
260
    }
 
261
  } while (!g_atomic_int_compare_and_exchange (&object->lockstate, state,
 
262
          newstate));
 
263
}
 
264
 
 
265
/**
123
266
 * gst_mini_object_is_writable:
124
267
 * @mini_object: the mini-object to check
125
268
 *
126
 
 * Checks if a mini-object is writable.  A mini-object is writable
127
 
 * if the reference count is one. Modification of a mini-object should
128
 
 * only be done after verifying that it is writable.
129
 
 *
130
 
 * MT safe
 
269
 * If @mini_object has the LOCKABLE flag set, check if the current EXCLUSIVE
 
270
 * lock on @object is the only one, this means that changes to the object will
 
271
 * not be visible to any other object.
 
272
 *
 
273
 * If the LOCKABLE flag is not set, check if the refcount of @mini_object is
 
274
 * exactly 1, meaning that no other reference exists to the object and that the
 
275
 * object is therefore writable.
 
276
 *
 
277
 * Modification of a mini-object should only be done after verifying that it
 
278
 * is writable.
131
279
 *
132
280
 * Returns: TRUE if the object is writable.
133
281
 */
134
282
gboolean
135
283
gst_mini_object_is_writable (const GstMiniObject * mini_object)
136
284
{
 
285
  gboolean result;
 
286
 
137
287
  g_return_val_if_fail (mini_object != NULL, FALSE);
138
288
 
139
 
  return (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1);
 
289
  if (GST_MINI_OBJECT_IS_LOCKABLE (mini_object)) {
 
290
    result = (g_atomic_int_get (&mini_object->lockstate) & SHARE_MASK) < 2;
 
291
  } else {
 
292
    result = (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1);
 
293
  }
 
294
  return result;
140
295
}
141
296
 
142
297
/**
205
360
  return mini_object;
206
361
}
207
362
 
208
 
static void
209
 
weak_refs_notify (GstMiniObject * obj)
210
 
{
211
 
  guint i;
212
 
 
213
 
  for (i = 0; i < obj->n_weak_refs; i++)
214
 
    obj->weak_refs[i].notify (obj->weak_refs[i].data, obj);
215
 
  g_free (obj->weak_refs);
 
363
static gint
 
364
find_notify (GstMiniObject * object, GQuark quark, gboolean match_notify,
 
365
    GstMiniObjectNotify notify, gpointer data)
 
366
{
 
367
  guint i;
 
368
 
 
369
  for (i = 0; i < object->n_qdata; i++) {
 
370
    if (QDATA_QUARK (object, i) == quark) {
 
371
      /* check if we need to match the callback too */
 
372
      if (!match_notify || (QDATA_NOTIFY (object, i) == notify &&
 
373
              QDATA_DATA (object, i) == data))
 
374
        return i;
 
375
    }
 
376
  }
 
377
  return -1;
 
378
}
 
379
 
 
380
static void
 
381
remove_notify (GstMiniObject * object, gint index)
 
382
{
 
383
  /* remove item */
 
384
  if (--object->n_qdata == 0) {
 
385
    /* we don't shrink but free when everything is gone */
 
386
    g_free (object->qdata);
 
387
    object->qdata = NULL;
 
388
  } else if (index != object->n_qdata)
 
389
    QDATA (object, index) = QDATA (object, object->n_qdata);
 
390
}
 
391
 
 
392
static void
 
393
set_notify (GstMiniObject * object, gint index, GQuark quark,
 
394
    GstMiniObjectNotify notify, gpointer data, GDestroyNotify destroy)
 
395
{
 
396
  if (index == -1) {
 
397
    /* add item */
 
398
    index = object->n_qdata++;
 
399
    object->qdata =
 
400
        g_realloc (object->qdata, sizeof (GstQData) * object->n_qdata);
 
401
  }
 
402
  QDATA_QUARK (object, index) = quark;
 
403
  QDATA_NOTIFY (object, index) = notify;
 
404
  QDATA_DATA (object, index) = data;
 
405
  QDATA_DESTROY (object, index) = destroy;
 
406
}
 
407
 
 
408
static void
 
409
call_finalize_notify (GstMiniObject * obj)
 
410
{
 
411
  guint i;
 
412
 
 
413
  for (i = 0; i < obj->n_qdata; i++) {
 
414
    if (QDATA_QUARK (obj, i) == weak_ref_quark)
 
415
      QDATA_NOTIFY (obj, i) (QDATA_DATA (obj, i), obj);
 
416
    if (QDATA_DESTROY (obj, i))
 
417
      QDATA_DESTROY (obj, i) (QDATA_DATA (obj, i));
 
418
  }
216
419
}
217
420
 
218
421
/**
245
448
    /* if the subclass recycled the object (and returned FALSE) we don't
246
449
     * want to free the instance anymore */
247
450
    if (G_LIKELY (do_free)) {
248
 
      /* The weak reference stack is freed in the notification function */
249
 
      if (mini_object->n_weak_refs)
250
 
        weak_refs_notify (mini_object);
 
451
      /* there should be no outstanding locks */
 
452
      g_return_if_fail ((g_atomic_int_get (&mini_object->lockstate) & LOCK_MASK)
 
453
          < 4);
251
454
 
 
455
      if (mini_object->n_qdata) {
 
456
        call_finalize_notify (mini_object);
 
457
        g_free (mini_object->qdata);
 
458
      }
252
459
#ifndef GST_DISABLE_TRACE
253
460
      _gst_alloc_trace_free (_gst_mini_object_trace, mini_object);
254
461
#endif
385
592
 * to the mini object without calling gst_mini_object_ref()
386
593
 * (gst_mini_object_ref() adds a strong reference, that is, forces the object
387
594
 * to stay alive).
388
 
 *
389
 
 * Since: 0.10.35
390
595
 */
391
596
void
392
597
gst_mini_object_weak_ref (GstMiniObject * object,
393
 
    GstMiniObjectWeakNotify notify, gpointer data)
 
598
    GstMiniObjectNotify notify, gpointer data)
394
599
{
395
 
  guint i;
396
 
 
397
600
  g_return_if_fail (object != NULL);
398
601
  g_return_if_fail (notify != NULL);
399
602
  g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (object) >= 1);
400
603
 
401
 
  G_LOCK (weak_refs_mutex);
402
 
 
403
 
  if (object->n_weak_refs) {
404
 
    /* Don't add the weak reference if it already exists. */
405
 
    for (i = 0; i < object->n_weak_refs; i++) {
406
 
      if (object->weak_refs[i].notify == notify &&
407
 
          object->weak_refs[i].data == data) {
408
 
        g_warning ("%s: Attempt to re-add existing weak ref %p(%p) failed.",
409
 
            G_STRFUNC, notify, data);
410
 
        goto found;
411
 
      }
412
 
    }
413
 
 
414
 
    i = object->n_weak_refs++;
415
 
    object->weak_refs =
416
 
        g_realloc (object->weak_refs, sizeof (object->weak_refs[0]) * i);
417
 
  } else {
418
 
    object->weak_refs = g_malloc0 (sizeof (object->weak_refs[0]));
419
 
    object->n_weak_refs = 1;
420
 
    i = 0;
421
 
  }
422
 
  object->weak_refs[i].notify = notify;
423
 
  object->weak_refs[i].data = data;
424
 
found:
425
 
  G_UNLOCK (weak_refs_mutex);
 
604
  G_LOCK (qdata_mutex);
 
605
  set_notify (object, -1, weak_ref_quark, notify, data, NULL);
 
606
  G_UNLOCK (qdata_mutex);
426
607
}
427
608
 
428
609
/**
431
612
 * @notify: callback to search for
432
613
 * @data: data to search for
433
614
 *
434
 
 * Removes a weak reference callback to a mini object.
435
 
 *
436
 
 * Since: 0.10.35
 
615
 * Removes a weak reference callback from a mini object.
437
616
 */
438
617
void
439
618
gst_mini_object_weak_unref (GstMiniObject * object,
440
 
    GstMiniObjectWeakNotify notify, gpointer data)
 
619
    GstMiniObjectNotify notify, gpointer data)
441
620
{
442
 
  gboolean found_one = FALSE;
 
621
  gint i;
443
622
 
444
623
  g_return_if_fail (object != NULL);
445
624
  g_return_if_fail (notify != NULL);
446
625
 
447
 
  G_LOCK (weak_refs_mutex);
448
 
 
449
 
  if (object->n_weak_refs) {
450
 
    guint i;
451
 
 
452
 
    for (i = 0; i < object->n_weak_refs; i++)
453
 
      if (object->weak_refs[i].notify == notify &&
454
 
          object->weak_refs[i].data == data) {
455
 
        found_one = TRUE;
456
 
        object->n_weak_refs -= 1;
457
 
        if (i != object->n_weak_refs)
458
 
          object->weak_refs[i] = object->weak_refs[object->n_weak_refs];
459
 
 
460
 
        break;
461
 
      }
462
 
  }
463
 
  G_UNLOCK (weak_refs_mutex);
464
 
  if (!found_one)
 
626
  G_LOCK (qdata_mutex);
 
627
  if ((i = find_notify (object, weak_ref_quark, TRUE, notify, data)) != -1) {
 
628
    remove_notify (object, i);
 
629
  } else {
465
630
    g_warning ("%s: couldn't find weak ref %p(%p)", G_STRFUNC, notify, data);
 
631
  }
 
632
  G_UNLOCK (qdata_mutex);
 
633
}
 
634
 
 
635
/**
 
636
 * gst_mini_object_set_qdata:
 
637
 * @object: a #GstMiniObject
 
638
 * @quark: A #GQuark, naming the user data pointer
 
639
 * @data: An opaque user data pointer
 
640
 * @destroy: Function to invoke with @data as argument, when @data
 
641
 *           needs to be freed
 
642
 *
 
643
 * This sets an opaque, named pointer on a miniobject.
 
644
 * The name is specified through a #GQuark (retrived e.g. via
 
645
 * g_quark_from_static_string()), and the pointer
 
646
 * can be gotten back from the @object with gst_mini_object_get_qdata()
 
647
 * until the @object is disposed.
 
648
 * Setting a previously set user data pointer, overrides (frees)
 
649
 * the old pointer set, using #NULL as pointer essentially
 
650
 * removes the data stored.
 
651
 *
 
652
 * @destroy may be specified which is called with @data as argument
 
653
 * when the @object is disposed, or the data is being overwritten by
 
654
 * a call to gst_mini_object_set_qdata() with the same @quark.
 
655
 */
 
656
void
 
657
gst_mini_object_set_qdata (GstMiniObject * object, GQuark quark,
 
658
    gpointer data, GDestroyNotify destroy)
 
659
{
 
660
  gint i;
 
661
  gpointer old_data = NULL;
 
662
  GDestroyNotify old_notify = NULL;
 
663
 
 
664
  g_return_if_fail (object != NULL);
 
665
  g_return_if_fail (quark > 0);
 
666
 
 
667
  G_LOCK (qdata_mutex);
 
668
  if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
 
669
 
 
670
    old_data = QDATA_DATA (object, i);
 
671
    old_notify = QDATA_DESTROY (object, i);
 
672
 
 
673
    if (data == NULL)
 
674
      remove_notify (object, i);
 
675
  }
 
676
  if (data != NULL)
 
677
    set_notify (object, i, quark, NULL, data, destroy);
 
678
  G_UNLOCK (qdata_mutex);
 
679
 
 
680
  if (old_notify)
 
681
    old_notify (old_data);
 
682
}
 
683
 
 
684
/**
 
685
 * gst_mini_object_get_qdata:
 
686
 * @object: The GstMiniObject to get a stored user data pointer from
 
687
 * @quark: A #GQuark, naming the user data pointer
 
688
 *
 
689
 * This function gets back user data pointers stored via
 
690
 * gst_mini_object_set_qdata().
 
691
 *
 
692
 * Returns: (transfer none): The user data pointer set, or %NULL
 
693
 */
 
694
gpointer
 
695
gst_mini_object_get_qdata (GstMiniObject * object, GQuark quark)
 
696
{
 
697
  guint i;
 
698
  gpointer result;
 
699
 
 
700
  g_return_val_if_fail (object != NULL, NULL);
 
701
  g_return_val_if_fail (quark > 0, NULL);
 
702
 
 
703
  G_LOCK (qdata_mutex);
 
704
  if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1)
 
705
    result = QDATA_DATA (object, i);
 
706
  else
 
707
    result = NULL;
 
708
  G_UNLOCK (qdata_mutex);
 
709
 
 
710
  return result;
 
711
}
 
712
 
 
713
/**
 
714
 * gst_mini_object_steal_qdata:
 
715
 * @object: The GstMiniObject to get a stored user data pointer from
 
716
 * @quark: A #GQuark, naming the user data pointer
 
717
 *
 
718
 * This function gets back user data pointers stored via gst_mini_object_set_qdata()
 
719
 * and removes the data from @object without invoking its destroy() function (if
 
720
 * any was set).
 
721
 *
 
722
 * Returns: (transfer full): The user data pointer set, or %NULL
 
723
 */
 
724
gpointer
 
725
gst_mini_object_steal_qdata (GstMiniObject * object, GQuark quark)
 
726
{
 
727
  guint i;
 
728
  gpointer result;
 
729
 
 
730
  g_return_val_if_fail (object != NULL, NULL);
 
731
  g_return_val_if_fail (quark > 0, NULL);
 
732
 
 
733
  G_LOCK (qdata_mutex);
 
734
  if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
 
735
    result = QDATA_DATA (object, i);
 
736
    remove_notify (object, i);
 
737
  } else {
 
738
    result = NULL;
 
739
  }
 
740
  G_UNLOCK (qdata_mutex);
 
741
 
 
742
  return result;
466
743
}