コード例 #1
0
ファイル: gatomic.c プロジェクト: johndpope/PocketOrchestra
/**
 * g_atomic_pointer_compare_and_exchange:
 * @atomic: a pointer to a #gpointer-sized value
 * @oldval: the value to compare with
 * @newval: the value to conditionally replace with
 *
 * Compares @atomic to @oldval and, if equal, sets it to @newval.
 * If @atomic was not equal to @oldval then no change occurs.
 *
 * This compare and exchange is done atomically.
 *
 * Think of this operation as an atomic version of
 * `{ if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`.
 *
 * This call acts as a full compiler and hardware memory barrier.
 *
 * Returns: %TRUE if the exchange took place
 *
 * Since: 2.4
 **/
gboolean
(g_atomic_pointer_compare_and_exchange) (volatile void *atomic,
                                         gpointer       oldval,
                                         gpointer       newval)
{
  return g_atomic_pointer_compare_and_exchange ((volatile gpointer *) atomic,
                                                oldval, newval);
}
コード例 #2
0
ファイル: lf-queue.c プロジェクト: stieg/dukes_of_hazard
/**
 * lf_queue_dequeue:
 * @queue: A #LfQUeue
 *
 * Dequeues an item from the queue.  If the queue is empty, %NULL is returned.
 *
 * Returns: An item from the queue or %NULL.
 *
 * Side effects: Hazard pointer reclaimation can occur meaning that structures
 *   no longer in use may be freed by the system.
 */
gpointer
lf_queue_dequeue(LfQueue *queue)
{
	LfNode *head, *tail, *next;
	gpointer data;
	LF_HAZARD_INIT;

	g_return_val_if_fail(queue != NULL, NULL);

	/*
	 * Attempt to retrieve an LfNode off the linked-list until we succeed.
	 * If the queue is in an inconsistent state we will attempt to clean
	 * up after the last operation before retreiving our item.
	 */
	while (TRUE) {
		head = queue->head;      /* Retrieve the current head of queue */
		LF_HAZARD_SET(0, head);  /* Notify threads that head is a hazard */
		if (queue->head != head) /* Ensure head is still the queues head */
			continue;
		tail = queue->tail;      /* Retreive the current tail of queue */
		next = head->next;       /* Retreive heads next (to become new head) */
		LF_HAZARD_SET(1, next);  /* Notify threads next is a hazard */ 
		if (queue->head != head) /* Ensure head is still the queues head */
			continue;
		if (next == NULL)        /* If there is no next, queue is empty */
			return NULL;
		if (head == tail) {      /* Inconsistent state, help thread along */
			g_atomic_pointer_compare_and_exchange((gpointer *)&queue->tail,
			                                      tail, next);
			continue;
		}
		data = next->data;       /* Retrieve data for the removing node */
		                         /* Take the head of the queue */
		if (g_atomic_pointer_compare_and_exchange((gpointer *)&queue->head,
		                                          head, next))
			break;
	}

	/*
	 * head is no longer a hazard.  Potentially do a reclaimation of
	 * memory no longer hazardous.
	 */
	LF_HAZARD_UNSET(head);

	return data;
}
コード例 #3
0
ファイル: openslide-error.c プロジェクト: AwAkEd/openslide
// private error functions
void _openslide_propagate_error(openslide_t *osr, GError *err) {
  g_return_if_fail(err);
  gchar *msg = g_strdup(err->message);
  if (!g_atomic_pointer_compare_and_exchange(&osr->error, NULL, msg)) {
    // didn't replace the error, free it
    g_free(msg);
  }
  g_error_free(err);
}
コード例 #4
0
static inline gboolean
frame_done (FrameState *frame)
{
  GstMfxWindowWaylandPrivate *const priv =
         GST_MFX_WINDOW_WAYLAND_GET_PRIVATE (frame->window);
  g_atomic_int_set (&frame->done, TRUE);
  g_atomic_pointer_compare_and_exchange (&priv->last_frame, frame, NULL);
  return g_atomic_int_dec_and_test (&priv->num_frames_pending);

}
コード例 #5
0
static void
frame_done_callback (void *data, struct wl_callback *callback, uint32_t time)
{
    FrameState *const frame = data;
    GstVaapiWindowWaylandPrivate *const priv =
        GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (frame->window);

    g_atomic_pointer_compare_and_exchange (&priv->last_frame, frame, NULL);
    g_atomic_int_dec_and_test (&priv->num_frames_pending);
}
コード例 #6
0
ファイル: iris-rrobin.c プロジェクト: crnt/iris
/**
 * iris_rrobin_remove:
 * @rrobin: An #IrisRRobin
 * @data: a gpointer to callback data
 *
 * Removes the first instance of @data within the @rrobin structure.
 */
void
iris_rrobin_remove (IrisRRobin *rrobin,
                    gpointer    data)
{
	gint i;

	g_return_if_fail (data != NULL);

	for (i = 0; i < rrobin->size; i++)
		if (g_atomic_pointer_compare_and_exchange (&rrobin->data [i], data, NULL))
			break;
}
コード例 #7
0
ファイル: gresource.c プロジェクト: 492852238/SourceLearning
/**
 * g_static_resource_init:
 * @static_resource: pointer to a static #GStaticResource
 *
 * Initializes a GResource from static data using a
 * GStaticResource.
 *
 * This is normally used by code generated by
 * <link linkend="glib-compile-resources">glib-compile-resources</link>
 * and is not typically used by other code.
 *
 * Since: 2.32
 **/
void
g_static_resource_init (GStaticResource *static_resource)
{
  gpointer next;

  do
    {
      next = lazy_register_resources;
      static_resource->next = next;
    }
  while (!g_atomic_pointer_compare_and_exchange (&lazy_register_resources, next, static_resource));
}
コード例 #8
0
ファイル: gdataset.c プロジェクト: 0xmono/miranda-ng
/**
 * g_datalist_unset_flags:
 * @datalist: pointer to the location that holds a list
 * @flags: the flags to turn off. The values of the flags are
 *   restricted by %G_DATALIST_FLAGS_MASK (currently
 *   3: giving two possible boolean flags).
 *   A value for @flags that doesn't fit within the mask is
 *   an error.
 * 
 * Turns off flag values for a data list. See g_datalist_unset_flags()
 *
 * Since: 2.8
 **/
void
g_datalist_unset_flags (GData **datalist,
			guint   flags)
{
  gpointer oldvalue;
  g_return_if_fail (datalist != NULL);
  g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
  
  do
    {
      oldvalue = g_atomic_pointer_get (datalist);
    }
  while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, oldvalue,
                                                 (gpointer) ((gsize) oldvalue & ~(gsize) flags)));
}
コード例 #9
0
ファイル: ice.c プロジェクト: Zodiac-Evil/rtpengine
/* call(W) or call(R)+agent must be locked - no in_lock or out_lock must be held */
static int __check_valid(struct ice_agent *ag) {
	struct call_media *media = ag->media;
	struct packet_stream *ps;
	GList *l, *k;
	GQueue all_compos;
	struct ice_candidate_pair *pair;
	struct interface_address *ifa;

	if (!ag) {
		ilog(LOG_ERR, "ice ag is NULL");
		return 0;
	}

	__get_complete_valid_pairs(&all_compos, ag);

	if (!all_compos.length) {
		ilog(LOG_DEBUG, "ICE not completed yet");
		return 0;
	}

	pair = all_compos.head->data;
	ilog(LOG_DEBUG, "ICE completed, using pair "PAIR_FORMAT, PAIR_FMT(pair));
	AGENT_SET(ag, COMPLETED);

	ifa = g_atomic_pointer_get(&media->local_address);
	if (ifa != pair->local_address
			&& g_atomic_pointer_compare_and_exchange(&media->local_address, ifa,
				pair->local_address))
		ilog(LOG_INFO, "ICE negotiated: local interface %s", smart_ntop_buf(&pair->local_address->addr));

	for (l = media->streams.head, k = all_compos.head; l && k; l = l->next, k = k->next) {
		ps = l->data;
		pair = k->data;

		mutex_lock(&ps->out_lock);
		if (memcmp(&ps->endpoint, &pair->remote_candidate->endpoint, sizeof(ps->endpoint))) {
			ilog(LOG_INFO, "ICE negotiated: peer for component %u is %s", ps->component,
					smart_ntop_ep_buf(&pair->remote_candidate->endpoint));
			ps->endpoint = pair->remote_candidate->endpoint;
		}
		mutex_unlock(&ps->out_lock);
	}

	call_media_unkernelize(media);

	g_queue_clear(&all_compos);
	return 1;
}
コード例 #10
0
ファイル: gmem.c プロジェクト: 492852238/SourceLearning
void
g_clear_pointer (gpointer      *pp,
                 GDestroyNotify destroy)
{
  gpointer _p;

  /* This is a little frustrating.
   * Would be nice to have an atomic exchange (with no compare).
   */
  do
    _p = g_atomic_pointer_get (pp);
  while G_UNLIKELY (!g_atomic_pointer_compare_and_exchange (pp, _p, NULL));

  if (_p)
    destroy (_p);
}
コード例 #11
0
ファイル: iris-rrobin.c プロジェクト: antono/iris
/**
 * iris_rrobin_remove:
 * @rrobin: An #IrisRRobin
 * @data: a pointer to data
 *
 * Removes the first instance of @data within the @rrobin structure.
 */
void
iris_rrobin_remove (IrisRRobin *rrobin,
                    gpointer    data)
{
	gint     i;
	gboolean ignore;

	g_return_if_fail (data != NULL);

	for (i = 0; i < rrobin->size; i++) {
		if (g_atomic_pointer_compare_and_exchange (&rrobin->data [i], data, NULL)) {
			ignore = g_atomic_int_dec_and_test (&rrobin->count);
			break;
		}
	}
}
コード例 #12
0
ファイル: gum.c プロジェクト: 0xItx/frida-gum
static void
gum_capstone_free (gpointer mem)
{
  GumBlock * block, * next;
  GumPool * pool;

  if (mem == NULL)
    return;

  block = GUM_BLOCK_FROM_DATA_POINTER (mem);
  pool = block->pool;
  do
  {
    next = pool->free;
    block->next = next;
  }
  while (!g_atomic_pointer_compare_and_exchange (&pool->free, next, block));
}
コード例 #13
0
ファイル: gstminiobject.c プロジェクト: tieto/gstreamer-pkg
/**
 * gst_mini_object_steal:
 * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
 *     be stolen
 *
 * Replace the current #GstMiniObject pointer to by @olddata with NULL and
 * return the old value.
 *
 * Returns: the #GstMiniObject at @oldata
 */
GstMiniObject *
gst_mini_object_steal (GstMiniObject ** olddata)
{
  GstMiniObject *olddata_val;

  g_return_val_if_fail (olddata != NULL, NULL);

  GST_CAT_TRACE (GST_CAT_REFCOUNTING, "steal %p (%d)",
      *olddata, *olddata ? (*olddata)->refcount : 0);

  do {
    olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
    if (olddata_val == NULL)
      break;
  } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
              olddata, olddata_val, NULL)));

  return olddata_val;
}
コード例 #14
0
static void
gst_auto_convert_dispose (GObject * object)
{
  GstAutoConvert *autoconvert = GST_AUTO_CONVERT (object);

  g_clear_object (&autoconvert->current_subelement);
  g_clear_object (&autoconvert->current_internal_sinkpad);
  g_clear_object (&autoconvert->current_internal_srcpad);

  for (;;) {
    GList *factories = g_atomic_pointer_get (&autoconvert->factories);

    if (g_atomic_pointer_compare_and_exchange (&autoconvert->factories,
            factories, NULL)) {
      gst_plugin_feature_list_free (factories);
      break;
    }
  }

  G_OBJECT_CLASS (gst_auto_convert_parent_class)->dispose (object);
}
コード例 #15
0
static gpointer
_my_mem_map (MyMemory * mem, gsize maxsize, GstMapFlags flags)
{
  gpointer res;

  while (TRUE) {
    if ((res = g_atomic_pointer_get (&mem->data)) != NULL)
      break;

    res = g_malloc (maxsize);

    if (g_atomic_pointer_compare_and_exchange (&mem->data, NULL, res))
      break;

    g_free (res);
  }

  GST_DEBUG ("%p: mapped %p", mem, res);

  return res;
}
コード例 #16
0
ファイル: chase_lev.c プロジェクト: toddaaro/chase_lev
void * pop_bottom(ws_deque *q) {

  long int b = q->bottom;
  circular_array *a = q->active_array;

  b = b - 1;
  q->bottom = b;

  long int t = (long int) g_atomic_pointer_get(&(q->top));
  long int size = b - t;
  long int zero = 0;

  if(size < zero) {
    q->bottom = t;
    return NULL;
  }

  void *value = ca_get(a, b);

  if(size > 0) {
    return value;
  }

  // this is the case for exactly one element, this is now the top so act accordingly

  long int new_t = t+1;
  gboolean cas = g_atomic_pointer_compare_and_exchange((void * volatile*)&(q->top), 
                                                       (void*)t, 
                                                       (void*)new_t);

  if( !cas ) {
    value = NULL;
  }
  
  q->bottom = t+1;

  return value;

}
コード例 #17
0
/**
 * gst_vaapi_video_meta_replace:
 * @old_meta_ptr: a pointer to a #GstVaapiVideoMeta
 * @new_meta: a #GstVaapiVideoMeta
 *
 * @new_meta. This means that @old_meta_ptr shall reference a valid
 * Atomically replaces the meta object held in @old_meta_ptr with
 * object. However, @new_meta can be NULL.
 */
void
gst_vaapi_video_meta_replace (GstVaapiVideoMeta ** old_meta_ptr,
    GstVaapiVideoMeta * new_meta)
{
  GstVaapiVideoMeta *old_meta;

  g_return_if_fail (old_meta_ptr != NULL);

  old_meta = g_atomic_pointer_get ((gpointer *) old_meta_ptr);

  if (old_meta == new_meta)
    return;

  if (new_meta)
    gst_vaapi_video_meta_ref (new_meta);

  while (!g_atomic_pointer_compare_and_exchange ((gpointer *) old_meta_ptr,
          old_meta, new_meta))
    old_meta = g_atomic_pointer_get ((gpointer *) old_meta_ptr);

  if (old_meta)
    gst_vaapi_video_meta_unref (old_meta);
}
コード例 #18
0
ファイル: gstminiobject.c プロジェクト: tieto/gstreamer-pkg
/**
 * gst_mini_object_take:
 * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
 *     be replaced
 * @newdata: pointer to new mini-object
 *
 * Modifies a pointer to point to a new mini-object. The modification
 * is done atomically. This version is similar to gst_mini_object_replace()
 * except that it does not increase the refcount of @newdata and thus
 * takes ownership of @newdata.
 *
 * Either @newdata and the value pointed to by @olddata may be NULL.
 *
 * Returns: TRUE if @newdata was different from @olddata
 */
gboolean
gst_mini_object_take (GstMiniObject ** olddata, GstMiniObject * newdata)
{
  GstMiniObject *olddata_val;

  g_return_val_if_fail (olddata != NULL, FALSE);

  GST_CAT_TRACE (GST_CAT_REFCOUNTING, "take %p (%d) with %p (%d)",
      *olddata, *olddata ? (*olddata)->refcount : 0,
      newdata, newdata ? newdata->refcount : 0);

  do {
    olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
    if (G_UNLIKELY (olddata_val == newdata))
      break;
  } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
              olddata, olddata_val, newdata)));

  if (olddata_val)
    gst_mini_object_unref (olddata_val);

  return olddata_val != newdata;
}
コード例 #19
0
ファイル: gresource.c プロジェクト: 492852238/SourceLearning
static void
register_lazy_static_resources_unlocked (void)
{
  GStaticResource *list;

  do
    list = lazy_register_resources;
  while (!g_atomic_pointer_compare_and_exchange (&lazy_register_resources, list, NULL));

  while (list != NULL)
    {
      GBytes *bytes = g_bytes_new_static (list->data, list->data_len);
      GResource *resource = g_resource_new_from_data (bytes, NULL);
      if (resource)
        {
          g_resources_register_unlocked (resource);
          g_atomic_pointer_set (&list->resource, resource);
        }
      g_bytes_unref (bytes);

      list = list->next;
    }
}
コード例 #20
0
ファイル: gxcabinet.cpp プロジェクト: dafx/guitarix
inline bool atomic_compare_and_exchange(T **p, T *oldv, T *newv)
{
  return g_atomic_pointer_compare_and_exchange(reinterpret_cast<void* volatile*>(p), oldv, newv);
}
コード例 #21
0
int 
main (int   argc,
      char *argv[])
{
  gint i;
  gint atomic = -5;
  gpointer atomic_pointer = NULL;
  
  gpointer biggest_pointer = (gpointer)((gsize)atomic_pointer - 1);
  
  #ifdef SYMBIAN
  g_log_set_handler (NULL,  G_LOG_FLAG_FATAL| G_LOG_FLAG_RECURSION | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, &mrtLogHandler, NULL);
  g_set_print_handler(mrtPrintHandler);
  #endif /*SYMBIAN*/

  for (i = 0; i < 15; i++)
    g_atomic_int_inc (&atomic);
  g_assert (atomic == 10);
  for (i = 0; i < 9; i++)
    g_assert (!g_atomic_int_dec_and_test (&atomic));
  g_assert (g_atomic_int_dec_and_test (&atomic));
  g_assert (atomic == 0);

  g_assert (g_atomic_int_exchange_and_add (&atomic, 5) == 0);
  g_assert (atomic == 5);

  g_assert (g_atomic_int_exchange_and_add (&atomic, -10) == 5);
  g_assert (atomic == -5);

  g_atomic_int_add (&atomic, 20);
  g_assert (atomic == 15);

  g_atomic_int_add (&atomic, -35);
  g_assert (atomic == -20);

  g_assert (atomic == g_atomic_int_get (&atomic));

  g_assert (g_atomic_int_compare_and_exchange (&atomic, -20, 20));
  g_assert (atomic == 20);
  
  g_assert (!g_atomic_int_compare_and_exchange (&atomic, 42, 12));
  g_assert (atomic == 20);
  
  g_assert (g_atomic_int_compare_and_exchange (&atomic, 20, G_MAXINT));
  g_assert (atomic == G_MAXINT);

  g_assert (g_atomic_int_compare_and_exchange (&atomic, G_MAXINT, G_MININT));
  g_assert (atomic == G_MININT);

  g_assert (g_atomic_pointer_compare_and_exchange (&atomic_pointer, 
						   NULL, biggest_pointer));
  g_assert (atomic_pointer == biggest_pointer);

  g_assert (atomic_pointer == g_atomic_pointer_get (&atomic_pointer));

  g_assert (g_atomic_pointer_compare_and_exchange (&atomic_pointer, 
						   biggest_pointer, NULL));
  g_assert (atomic_pointer == NULL);
  
  #ifdef SYMBIAN
  testResultXml("atomic-test");
  #endif /* EMULATOR */
  
  return 0;
}
コード例 #22
0
ファイル: gum.c プロジェクト: 0xItx/frida-gum
static gpointer
gum_capstone_malloc (gsize size)
{
  guint page_size;

  page_size = gum_query_page_size ();

  do
  {
    GumPool * head, * pool;
    GumBlock * block, * next_block;
    gsize aligned_block_size, pool_size, pages;
    gpointer pool_start, pool_end;

    head = pools;
    pool = NULL;
    for (pool = pools; pool != NULL; pool = pool->next)
    {
      if (pool->block_size == size)
      {
        do
        {
          block = pool->free;
          if (block == NULL)
            break;
        }
        while (!g_atomic_pointer_compare_and_exchange (&pool->free, block,
            block->next));

        if (block != NULL)
          return GUM_BLOCK_TO_DATA_POINTER (block);
      }
    }

    aligned_block_size = GUM_BLOCK_HEADER_SIZE + GUM_ALIGNED_SIZE (size);
    pool_size = GUM_POOL_HEADER_SIZE + (100 * aligned_block_size);
    pages = pool_size / page_size;
    if (pool_size % page_size != 0)
      pages++;

    pool_start = gum_alloc_n_pages (pages, GUM_PAGE_RW);
    pool_end = (guint8 *) pool_start + pool_size;
    pool = (GumPool *) pool_start;
    pool->block_size = size;
    block = (GumBlock *) ((guint8 *) pool_start + GUM_POOL_HEADER_SIZE);
    pool->free = block;
    do
    {
      next_block = (GumBlock *) ((guint8 *) block + aligned_block_size);
      if (next_block == pool_end)
        next_block = NULL;
      block->pool = pool;
      block->next = next_block;
      block = next_block;
    }
    while (next_block != NULL);
    pool->next = head;
    if (!g_atomic_pointer_compare_and_exchange (&pools, head, pool))
      gum_free_pages (pool);
  }
  while (TRUE);
}
コード例 #23
0
/**
 * gst_element_factory_create:
 * @factory: factory to instantiate
 * @name: (allow-none): name of new element, or %NULL to automatically create
 *    a unique name
 *
 * Create a new element of the type defined by the given elementfactory.
 * It will be given the name supplied, since all elements require a name as
 * their first argument.
 *
 * Returns: (transfer floating) (nullable): new #GstElement or %NULL
 *     if the element couldn't be created
 */
GstElement *
gst_element_factory_create (GstElementFactory * factory, const gchar * name)
{
  GstElement *element;
  GstElementClass *oclass;
  GstElementFactory *newfactory;

  g_return_val_if_fail (factory != NULL, NULL);

  newfactory =
      GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
          (factory)));

  if (newfactory == NULL)
    goto load_failed;

  factory = newfactory;

  if (name)
    GST_INFO ("creating element \"%s\" named \"%s\"",
        GST_OBJECT_NAME (factory), GST_STR_NULL (name));
  else
    GST_INFO ("creating element \"%s\"", GST_OBJECT_NAME (factory));

  if (factory->type == 0)
    goto no_type;

  /* create an instance of the element, cast so we don't assert on NULL
   * also set name as early as we can
   */
  if (name)
    element = g_object_new (factory->type, "name", name, NULL);
  else
    element = g_object_new (factory->type, NULL);
  if (G_UNLIKELY (element == NULL))
    goto no_element;

  /* fill in the pointer to the factory in the element class. The
   * class will not be unreffed currently.
   * Be thread safe as there might be 2 threads creating the first instance of
   * an element at the same moment
   */
  oclass = GST_ELEMENT_GET_CLASS (element);
  if (!g_atomic_pointer_compare_and_exchange (&oclass->elementfactory, NULL,
          factory))
    gst_object_unref (factory);
  else
    /* This ref will never be dropped as the class is never destroyed */
    GST_OBJECT_FLAG_SET (factory, GST_OBJECT_FLAG_MAY_BE_LEAKED);

  GST_DEBUG ("created element \"%s\"", GST_OBJECT_NAME (factory));

  return element;

  /* ERRORS */
load_failed:
  {
    GST_WARNING_OBJECT (factory,
        "loading plugin containing feature %s returned NULL!", name);
    return NULL;
  }
no_type:
  {
    GST_WARNING_OBJECT (factory, "factory has no type");
    gst_object_unref (factory);
    return NULL;
  }
no_element:
  {
    GST_WARNING_OBJECT (factory, "could not create element");
    gst_object_unref (factory);
    return NULL;
  }
}
コード例 #24
0
/**
 * gst_device_provider_factory_get:
 * @factory: factory to instantiate
 *
 * Returns the device provider of the type defined by the given device
 * providerfactory.
 *
 * Returns: (transfer full) (nullable): the #GstDeviceProvider or %NULL
 * if the device provider couldn't be created
 *
 * Since: 1.4
 */
GstDeviceProvider *
gst_device_provider_factory_get (GstDeviceProviderFactory * factory)
{
  GstDeviceProvider *device_provider;
  GstDeviceProviderClass *oclass;
  GstDeviceProviderFactory *newfactory;

  g_return_val_if_fail (factory != NULL, NULL);

  newfactory =
      GST_DEVICE_PROVIDER_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
          (factory)));

  if (newfactory == NULL)
    goto load_failed;

  factory = newfactory;

  GST_INFO ("getting device provider \"%s\"", GST_OBJECT_NAME (factory));

  if (factory->type == 0)
    goto no_type;

  device_provider = g_atomic_pointer_get (&newfactory->provider);
  if (device_provider)
    return gst_object_ref (device_provider);

  /* create an instance of the device provider, cast so we don't assert on NULL
   * also set name as early as we can
   */
  device_provider = GST_DEVICE_PROVIDER_CAST (g_object_newv (factory->type, 0,
          NULL));
  if (G_UNLIKELY (device_provider == NULL))
    goto no_device_provider;

  /* fill in the pointer to the factory in the device provider class. The
   * class will not be unreffed currently.
   * Be thread safe as there might be 2 threads creating the first instance of
   * an device provider at the same moment
   */
  oclass = GST_DEVICE_PROVIDER_GET_CLASS (device_provider);
  if (!g_atomic_pointer_compare_and_exchange (&oclass->factory, NULL, factory))
    gst_object_unref (factory);

  gst_object_ref_sink (device_provider);

  /* We use an atomic to make sure we don't create two in parallel */
  if (!g_atomic_pointer_compare_and_exchange (&newfactory->provider, NULL,
          device_provider)) {
    gst_object_unref (device_provider);

    device_provider = g_atomic_pointer_get (&newfactory->provider);
  }

  GST_DEBUG ("created device provider \"%s\"", GST_OBJECT_NAME (factory));

  return gst_object_ref (device_provider);

  /* ERRORS */
load_failed:
  {
    GST_WARNING_OBJECT (factory,
        "loading plugin containing feature %s returned NULL!",
        GST_OBJECT_NAME (factory));
    return NULL;
  }
no_type:
  {
    GST_WARNING_OBJECT (factory, "factory has no type");
    gst_object_unref (factory);
    return NULL;
  }
no_device_provider:
  {
    GST_WARNING_OBJECT (factory, "could not create device provider");
    gst_object_unref (factory);
    return NULL;
  }
}