/** * 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); }
/** * 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; }
// 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); }
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); }
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); }
/** * 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; }
/** * 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)); }
/** * 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))); }
/* 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; }
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); }
/** * 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; } } }
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)); }
/** * 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; }
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); }
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; }
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; }
/** * 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); }
/** * 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; }
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; } }
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); }
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; }
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); }
/** * 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; } }
/** * 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; } }