static bool CAPeripheralCheckStarted()
{
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
- bool const started = (g_context.base != NULL);
+ bool const started =
+ (g_context.event_loop != NULL
+ && g_main_loop_is_running(g_context.event_loop));
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
/**
* @todo Fix potential TOCTOU race condition. A peripheral could
static bool CAPeripheralAdaptersFound(CALEContext * context)
{
// Check if BlueZ detected bluetooth hardware adapters.
- ca_mutex_lock(context->lock);
+ oc_mutex_lock(context->lock);
bool const found = (context->adapters != NULL);
- ca_mutex_unlock(context->lock);
+ oc_mutex_unlock(context->lock);
if (!found)
{
bool success = true;
- ca_mutex_lock(context->lock);
+ oc_mutex_lock(context->lock);
for (GList * l = context->gatt_services; l != NULL; l = l->next)
{
g_variant_unref(ret);
}
- ca_mutex_unlock(context->lock);
+ oc_mutex_unlock(context->lock);
return success;
}
LE Advertisement Manager.
*/
- ca_mutex_lock(context->lock);
+ oc_mutex_lock(context->lock);
char const * const advertisement_path =
g_dbus_interface_skeleton_get_object_path(
success = true;
}
- ca_mutex_unlock(context->lock);
+ oc_mutex_unlock(context->lock);
return success;
}
Synchronize access to the adapter information using the base
context lock since we don't own the adapter_infos.
*/
- ca_mutex_lock(context->lock);
+ oc_mutex_lock(context->lock);
// Make all detected adapters discoverable.
g_list_foreach(context->adapters,
discoverability_func,
&result);
- ca_mutex_unlock(context->lock);
+ oc_mutex_unlock(context->lock);
return result;
}
"Lost name \"%s\" on D-Bus!", name);
}
+/**
+ * Inform thread waiting for the event loop to start that the loop has
+ * started. This is done in the context of the event loop itself so
+ * that we can be certain that the event loop is indeed running.
+ */
+static gboolean CAPeripheralEventLoopStarted(gpointer user_data)
+{
+ oc_cond const condition = user_data;
+
+ oc_cond_signal(condition); // For service registration
+
+ return G_SOURCE_REMOVE;
+}
+
static void CAPeripheralStartEventLoop(void * data)
{
CALEContext * const context = data;
"manager interface.");
}
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
assert(g_context.event_loop == NULL);
g_context.event_loop = event_loop;
context->connection,
advertising_managers);
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
- ca_cond_signal(g_context.condition);
+ /*
+ Add an idle handler that notifies a thread waiting for the
+ GLib event loop to run that the event loop is actually
+ running. We do this in the context of the event loop itself
+ to avoid race conditions.
+ */
+ GSource * const source = g_idle_source_new();
+ g_source_set_priority(source, G_PRIORITY_HIGH_IDLE);
+ g_source_set_callback(source,
+ CAPeripheralEventLoopStarted,
+ g_context.condition, // data
+ NULL); // notify
+ (void) g_source_attach(source, loop_context);
+ g_source_unref(source);
g_main_loop_run(event_loop); // Blocks until loop is quit.
static void CAPeripheralStopEventLoop(CAPeripheralContext * context)
{
- ca_mutex_lock(context->lock);
+ oc_mutex_lock(context->lock);
GMainLoop * const event_loop = context->event_loop;
context->event_loop = NULL;
- ca_mutex_unlock(context->lock);
+ oc_mutex_unlock(context->lock);
if (event_loop != NULL)
{
void CAPeripheralInitialize()
{
- g_context.lock = ca_mutex_new();
- g_context.condition = ca_cond_new();
+ g_context.lock = oc_mutex_new();
+ g_context.condition = oc_cond_new();
}
void CAPeripheralFinalize()
{
- ca_cond_free(g_context.condition);
- ca_mutex_free(g_context.lock);
+ oc_cond_free(g_context.condition);
+ oc_mutex_free(g_context.lock);
}
CAResult_t CAPeripheralStart(CALEContext * context)
*/
result = ca_thread_pool_add_task(context->server_thread_pool,
CAPeripheralStartEventLoop,
- context);
+ context, NULL);
if (result != CA_STATUS_OK)
{
}
/*
- Wait until initialization completes before proceeding to
- service and advertisement registration.
+ Wait until initialization completes and the event loop is up and
+ running before proceeding to service and advertisement
+ registration.
*/
// Number of times to wait for initialization to complete.
static uint64_t const timeout =
2 * MICROSECS_PER_SEC; // Microseconds
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
for (int i = 0;
g_context.gatt_services == NULL && i < max_retries;
++i)
{
- if (ca_cond_wait_for(g_context.condition,
+ if (oc_cond_wait_for(g_context.condition,
g_context.lock,
- timeout) == CA_WAIT_SUCCESS)
+ timeout) == OC_WAIT_SUCCESS)
{
result = CA_STATUS_OK;
}
}
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
if (result != CA_STATUS_OK)
{
// Only stop if we were previously started.
if (!CAPeripheralCheckStarted())
{
- result = CA_STATUS_OK;
return result;
}
CAPeripheralStopEventLoop(&g_context);
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
guint const owner_id = g_context.owner_id;
g_context.owner_id = 0;
g_context.base = NULL;
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
CALEAdvertisementDestroy(&g_context.advertisement);
void CAPeripheralForEachService(GFunc func, void * user_data)
{
- ca_mutex_lock(g_context.lock);
+ oc_mutex_lock(g_context.lock);
g_list_foreach(g_context.gatt_services, func, user_data);
- ca_mutex_unlock(g_context.lock);
+ oc_mutex_unlock(g_context.lock);
}