int lcm_dispatch_handlers (lcm_t * lcm, lcm_recv_buf_t * buf, const char *channel) { g_static_rec_mutex_lock (&lcm->mutex); GPtrArray * handlers = lcm_get_handlers (lcm, channel); // ref the handlers to prevent them from being destroyed by an // lcm_unsubscribe. This guarantees that handlers 0-(nhandlers-1) will not // be destroyed during the callbacks. Store nhandlers in a local variable // so that we don't iterate over handlers that are added during the // callbacks. int nhandlers = handlers->len; for (int i = 0; i < nhandlers; i++) { lcm_subscription_t *h = (lcm_subscription_t *) g_ptr_array_index(handlers, i); h->callback_scheduled = 1; } // now, call the handlers. for (int i = 0; i < nhandlers; i++) { lcm_subscription_t *h = (lcm_subscription_t *) g_ptr_array_index(handlers, i); if (!h->marked_for_deletion && h->num_queued_messages > 0) { h->num_queued_messages--; int depth = g_static_rec_mutex_unlock_full (&lcm->mutex); h->handler (buf, channel, h->userdata); g_static_rec_mutex_lock_full (&lcm->mutex, depth); } } // unref the handlers and check if any should be deleted GList *to_remove = NULL; for (int i = 0; i < nhandlers; i++) { lcm_subscription_t *h = (lcm_subscription_t *) g_ptr_array_index(handlers, i); h->callback_scheduled = 0; if (h->marked_for_deletion) to_remove = g_list_prepend (to_remove, h); } // actually delete handlers marked for deletion for (;to_remove; to_remove = g_list_delete_link (to_remove, to_remove)) { lcm_subscription_t *h = (lcm_subscription_t *) to_remove->data; g_ptr_array_remove (lcm->handlers_all, h); g_hash_table_foreach (lcm->handlers_map, map_remove_handler_callback, h); lcm_handler_free (h); } g_static_rec_mutex_unlock (&lcm->mutex); return 0; }
static void gst_task_func (GstTask * task, GstTaskClass * tclass) { GStaticRecMutex *lock; GThread *tself; tself = g_thread_self (); GST_DEBUG ("Entering task %p, thread %p", task, tself); /* we have to grab the lock to get the mutex. We also * mark our state running so that nobody can mess with * the mutex. */ GST_OBJECT_LOCK (task); if (task->state == GST_TASK_STOPPED) goto exit; lock = GST_TASK_GET_LOCK (task); if (G_UNLIKELY (lock == NULL)) goto no_lock; task->abidata.ABI.thread = tself; GST_OBJECT_UNLOCK (task); /* locking order is TASK_LOCK, LOCK */ g_static_rec_mutex_lock (lock); GST_OBJECT_LOCK (task); while (G_LIKELY (task->state != GST_TASK_STOPPED)) { while (G_UNLIKELY (task->state == GST_TASK_PAUSED)) { gint t; t = g_static_rec_mutex_unlock_full (lock); if (t <= 0) { g_warning ("wrong STREAM_LOCK count %d", t); } GST_TASK_SIGNAL (task); GST_TASK_WAIT (task); GST_OBJECT_UNLOCK (task); /* locking order.. */ if (t > 0) g_static_rec_mutex_lock_full (lock, t); GST_OBJECT_LOCK (task); if (G_UNLIKELY (task->state == GST_TASK_STOPPED)) goto done; } GST_OBJECT_UNLOCK (task); task->func (task->data); GST_OBJECT_LOCK (task); } done: GST_OBJECT_UNLOCK (task); g_static_rec_mutex_unlock (lock); GST_OBJECT_LOCK (task); task->abidata.ABI.thread = NULL; exit: /* now we allow messing with the lock again by setting the running flag to * FALSE. Together with the SIGNAL this is the sign for the _join() to * complete. * Note that we still have not dropped the final ref on the task. We could * check here if there is a pending join() going on and drop the last ref * before releasing the lock as we can be sure that a ref is held by the * caller of the join(). */ task->running = FALSE; GST_TASK_SIGNAL (task); GST_OBJECT_UNLOCK (task); GST_DEBUG ("Exit task %p, thread %p", task, g_thread_self ()); gst_object_unref (task); return; no_lock: { g_warning ("starting task without a lock"); goto exit; } }
static void gst_task_func (GstTask * task) { GStaticRecMutex *lock; GThread *tself; GstTaskPrivate *priv; priv = task->priv; tself = g_thread_self (); GST_DEBUG ("Entering task %p, thread %p", task, tself); /* we have to grab the lock to get the mutex. We also * mark our state running so that nobody can mess with * the mutex. */ GST_OBJECT_LOCK (task); if (task->state == GST_TASK_STOPPED) goto exit; lock = GST_TASK_GET_LOCK (task); if (G_UNLIKELY (lock == NULL)) goto no_lock; task->abidata.ABI.thread = tself; /* only update the priority when it was changed */ if (priv->prio_set) g_thread_set_priority (tself, priv->priority); GST_OBJECT_UNLOCK (task); /* fire the enter_thread callback when we need to */ if (priv->thr_callbacks.enter_thread) priv->thr_callbacks.enter_thread (task, tself, priv->thr_user_data); /* locking order is TASK_LOCK, LOCK */ g_static_rec_mutex_lock (lock); GST_OBJECT_LOCK (task); /* configure the thread name now */ gst_task_configure_name (task); while (G_LIKELY (task->state != GST_TASK_STOPPED)) { while (G_UNLIKELY (task->state == GST_TASK_PAUSED)) { gint t; t = g_static_rec_mutex_unlock_full (lock); if (t <= 0) { g_warning ("wrong STREAM_LOCK count %d", t); } GST_TASK_SIGNAL (task); GST_TASK_WAIT (task); GST_OBJECT_UNLOCK (task); /* locking order.. */ if (t > 0) g_static_rec_mutex_lock_full (lock, t); GST_OBJECT_LOCK (task); if (G_UNLIKELY (task->state == GST_TASK_STOPPED)) goto done; } GST_OBJECT_UNLOCK (task); task->func (task->data); GST_OBJECT_LOCK (task); } done: GST_OBJECT_UNLOCK (task); g_static_rec_mutex_unlock (lock); GST_OBJECT_LOCK (task); task->abidata.ABI.thread = NULL; exit: if (priv->thr_callbacks.leave_thread) { /* fire the leave_thread callback when we need to. We need to do this before * we signal the task and with the task lock released. */ GST_OBJECT_UNLOCK (task); priv->thr_callbacks.leave_thread (task, tself, priv->thr_user_data); GST_OBJECT_LOCK (task); } else { /* restore normal priority when releasing back into the pool, we will not * touch the priority when a custom callback has been installed. */ g_thread_set_priority (tself, G_THREAD_PRIORITY_NORMAL); } /* now we allow messing with the lock again by setting the running flag to * FALSE. Together with the SIGNAL this is the sign for the _join() to * complete. * Note that we still have not dropped the final ref on the task. We could * check here if there is a pending join() going on and drop the last ref * before releasing the lock as we can be sure that a ref is held by the * caller of the join(). */ task->running = FALSE; GST_TASK_SIGNAL (task); GST_OBJECT_UNLOCK (task); GST_DEBUG ("Exit task %p, thread %p", task, g_thread_self ()); gst_object_unref (task); return; no_lock: { g_warning ("starting task without a lock"); goto exit; } }