Consolidate handlers

pull/274/head
Olivier Martin 2024-03-28 10:17:30 +01:00
parent 5ca46ad208
commit a85dd83015
7 changed files with 61 additions and 15 deletions

View File

@ -51,9 +51,18 @@ static gpointer _gattlib_connected_device_thread(gpointer data) {
gattlib_context_t* conn_context = connection->context;
const gchar *device_mac_address = org_bluez_device1_get_address(conn_context->device);
g_rec_mutex_lock(&connection->on_connection.mutex);
if (!gattlib_has_valid_handler(&connection->on_connection)) {
goto EXIT;
}
connection->on_connection.callback.connection_handler(
conn_context->adapter, device_mac_address, connection, 0 /* no error */,
connection->on_connection.user_data);
EXIT:
g_rec_mutex_unlock(&connection->on_connection.mutex);
return NULL;
}

View File

@ -31,22 +31,22 @@ void gattlib_disconnected_device_python_callback(gatt_connection_t* connection,
#endif
void gattlib_on_disconnected_device(gatt_connection_t* connection) {
if (connection->on_disconnection.callback.callback == NULL) {
// We do not have (anymore) a callback, nothing to do
GATTLIB_LOG(GATTLIB_DEBUG, "No callback for GATT disconnection.");
return;
}
if (gattlib_has_valid_handler(&connection->on_disconnection)) {
g_rec_mutex_lock(&connection->on_disconnection.mutex);
#if defined(WITH_PYTHON)
// Check if we are using the Python callback, in case of Python argument we keep track of the argument to free them
// once we are done with the handler.
if ((gattlib_disconnection_handler_t)connection->on_disconnection.callback.callback == gattlib_disconnected_device_python_callback) {
connection->on_disconnection.python_args = connection->on_disconnection.user_data;
}
// Check if we are using the Python callback, in case of Python argument we keep track of the argument to free them
// once we are done with the handler.
if ((gattlib_disconnection_handler_t)connection->on_disconnection.callback.callback == gattlib_disconnected_device_python_callback) {
connection->on_disconnection.python_args = connection->on_disconnection.user_data;
}
#endif
// For GATT disconnection we do not use thread to ensure the callback is synchronous.
connection->on_disconnection.callback.disconnection_handler(connection, connection->on_disconnection.user_data);
// For GATT disconnection we do not use thread to ensure the callback is synchronous.
connection->on_disconnection.callback.disconnection_handler(connection, connection->on_disconnection.user_data);
g_rec_mutex_unlock(&connection->on_disconnection.mutex);
}
// Clean GATTLIB connection on disconnection
gattlib_connection_free(connection);

View File

@ -55,12 +55,21 @@ struct gattlib_discovered_device_thread_args {
static gpointer _gattlib_discovered_device_thread(gpointer data) {
struct gattlib_discovered_device_thread_args* args = data;
g_rec_mutex_lock(&args->gattlib_adapter->ble_scan.discovered_device_callback.mutex);
if (!gattlib_has_valid_handler(&args->gattlib_adapter->ble_scan.discovered_device_callback)) {
goto EXIT;
}
args->gattlib_adapter->ble_scan.discovered_device_callback.callback.discovered_device(
args->gattlib_adapter,
args->mac_address, args->name,
args->gattlib_adapter->ble_scan.discovered_device_callback.user_data
);
EXIT:
g_rec_mutex_unlock(&args->gattlib_adapter->ble_scan.discovered_device_callback.mutex);
free(args->mac_address);
if (args->name != NULL) {
free(args->name);

View File

@ -56,11 +56,15 @@ void gattlib_notification_device_thread(gpointer data, gpointer user_data) {
struct gattlib_notification_device_thread_args* args = data;
struct gattlib_handler* handler = user_data;
g_rec_mutex_lock(&handler->mutex);
handler->callback.notification_handler(
args->uuid, args->data, args->data_length,
handler->user_data
);
g_rec_mutex_unlock(&handler->mutex);
if (args->uuid != NULL) {
free(args->uuid);
args->uuid = NULL;

View File

@ -144,6 +144,12 @@ int gattlib_uuid_cmp(const uuid_t *uuid1, const uuid_t *uuid2) {
}
void gattlib_handler_free(struct gattlib_handler* handler) {
g_rec_mutex_lock(&handler->mutex);
if (!gattlib_has_valid_handler(handler)) {
goto EXIT;
}
// Reset callback to stop calling it after we stopped
handler->callback.callback = NULL;
@ -162,17 +168,20 @@ void gattlib_handler_free(struct gattlib_handler* handler) {
g_thread_pool_free(handler->thread_pool, FALSE /* immediate */, TRUE /* wait */);
handler->thread_pool = NULL;
}
EXIT:
g_rec_mutex_unlock(&handler->mutex);
}
bool gattlib_has_valid_handler(struct gattlib_handler* handler) {
return (handler->callback.callback != NULL);
return (handler != NULL) && (handler->callback.callback != NULL);
}
void gattlib_handler_dispatch_to_thread(struct gattlib_handler* handler, void (*python_callback)(),
GThreadFunc thread_func, const char* thread_name, void* (*thread_args_allocator)(va_list args), ...) {
GError *error = NULL;
if (handler->callback.callback == NULL) {
if (!gattlib_has_valid_handler(handler)) {
// We do not have (anymore) a callback, nothing to do
return;
}

View File

@ -35,6 +35,11 @@ struct gattlib_handler {
void* user_data;
// We create a thread to ensure the callback is not blocking the mainloop
GThread *thread;
// The mutex ensures the callbacks is not being freed while being called
// We use a recursive mutex to be able to disable BLE scan from 'on_discovered_device'
// when we want to connect to the discovered device.
// Note: The risk is that we are actually realising the handle from the one we are executing
GRecMutex mutex;
// Thread pool
GThreadPool *thread_pool;
#if defined(WITH_PYTHON)
@ -49,7 +54,6 @@ struct _gatt_connection_t {
GMutex connection_mutex;
struct gattlib_handler on_connection;
struct gattlib_handler on_connection_error;
struct gattlib_handler notification;
struct gattlib_handler indication;
struct gattlib_handler on_disconnection;

View File

@ -176,6 +176,11 @@ int gattlib_connect(void *adapter, const char *dst,
return GATTLIB_NOT_FOUND;
}
if (connect_cb == NULL) {
GATTLIB_LOG(GATTLIB_DEBUG, "gattlib_connect: Missing connection callback");
return GATTLIB_INVALID_PARAMETER;
}
get_device_path_from_mac(adapter_name, dst, object_path, sizeof(object_path));
gattlib_context_t* conn_context = calloc(sizeof(gattlib_context_t), 1);
@ -303,6 +308,12 @@ void gattlib_connection_free(gatt_connection_t* connection) {
disconnect_all_notifications(conn_context);
// Free all handler
gattlib_handler_free(&connection->on_connection);
gattlib_handler_free(&connection->on_disconnection);
gattlib_handler_free(&connection->indication);
gattlib_handler_free(&connection->notification);
// Note: We do not free adapter as it might still be used by other devices
free(connection->context);