Skip to content

Commit 0e34df5

Browse files
committed
Single lock for all gattlib library
1 parent 014c280 commit 0e34df5

16 files changed

+819
-226
lines changed

common/gattlib_callback_connected_device.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,22 +50,31 @@ static gpointer _gattlib_connected_device_thread(gpointer data) {
5050
gattlib_connection_t* connection = data;
5151
const gchar *device_mac_address = org_bluez_device1_get_address(connection->backend.device);
5252

53-
// Mutex to ensure the device is valid and not freed during its use
54-
g_mutex_lock(&connection->device->device_mutex);
5553
// Mutex to ensure the handler is valid
56-
g_rec_mutex_lock(&connection->on_connection.mutex);
54+
g_rec_mutex_lock(&m_gattlib_mutex);
55+
56+
if (!gattlib_connection_is_connected(connection)) {
57+
g_rec_mutex_unlock(&m_gattlib_mutex);
58+
return NULL;
59+
}
5760

5861
if (!gattlib_has_valid_handler(&connection->on_connection)) {
59-
goto EXIT;
62+
g_rec_mutex_unlock(&m_gattlib_mutex);
63+
return NULL;
6064
}
6165

66+
// Ensure we increment device reference counter to prevent the device/connection is freed during the execution
67+
gattlib_device_ref(connection->device);
68+
69+
// We need to release the lock here to ensure the connection callback that is actually
70+
// doing the application sepcific work is not locking the BLE state.
71+
g_rec_mutex_unlock(&m_gattlib_mutex);
72+
6273
connection->on_connection.callback.connection_handler(
6374
connection->device->adapter, device_mac_address, connection, 0 /* no error */,
6475
connection->on_connection.user_data);
6576

66-
EXIT:
67-
g_rec_mutex_unlock(&connection->on_connection.mutex);
68-
g_mutex_unlock(&connection->device->device_mutex);
77+
gattlib_device_unref(connection->device);
6978
return NULL;
7079
}
7180

@@ -75,6 +84,10 @@ static void* _connected_device_thread_args_allocator(va_list args) {
7584
}
7685

7786
void gattlib_on_connected_device(gattlib_connection_t* connection) {
87+
if (!gattlib_device_is_valid(connection->device)) {
88+
return;
89+
}
90+
7891
gattlib_handler_dispatch_to_thread(
7992
&connection->on_connection,
8093
#if defined(WITH_PYTHON)

common/gattlib_callback_disconnected_device.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,14 @@ void gattlib_disconnected_device_python_callback(gattlib_connection_t* connectio
3131
#endif
3232

3333
void gattlib_on_disconnected_device(gattlib_connection_t* connection) {
34-
if (gattlib_has_valid_handler(&connection->on_disconnection)) {
35-
g_rec_mutex_lock(&connection->on_disconnection.mutex);
34+
g_rec_mutex_lock(&m_gattlib_mutex);
35+
36+
if (!gattlib_connection_is_connected(connection)) {
37+
g_rec_mutex_unlock(&m_gattlib_mutex);
38+
return;
39+
}
3640

41+
if (gattlib_has_valid_handler(&connection->on_disconnection)) {
3742
#if defined(WITH_PYTHON)
3843
// Check if we are using the Python callback, in case of Python argument we keep track of the argument to free them
3944
// once we are done with the handler.
@@ -44,16 +49,16 @@ void gattlib_on_disconnected_device(gattlib_connection_t* connection) {
4449

4550
// For GATT disconnection we do not use thread to ensure the callback is synchronous.
4651
connection->on_disconnection.callback.disconnection_handler(connection, connection->on_disconnection.user_data);
47-
48-
g_rec_mutex_unlock(&connection->on_disconnection.mutex);
4952
}
5053

51-
// Signal the device is now disconnected
52-
g_mutex_lock(&connection->device->device_mutex);
53-
connection->disconnection_wait.value = true;
54-
g_cond_broadcast(&connection->disconnection_wait.condition);
55-
g_mutex_unlock(&connection->device->device_mutex);
56-
5754
// Clean GATTLIB connection on disconnection
5855
gattlib_connection_free(connection);
56+
57+
g_rec_mutex_unlock(&m_gattlib_mutex);
58+
59+
// Signal the device is now disconnected
60+
g_mutex_lock(&m_gattlib_signal.mutex);
61+
m_gattlib_signal.signals |= GATTLIB_SIGNAL_DEVICE_DISCONNECTION;
62+
g_cond_broadcast(&m_gattlib_signal.condition);
63+
g_mutex_unlock(&m_gattlib_signal.mutex);
5964
}

common/gattlib_callback_discovered_device.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,33 @@ struct gattlib_discovered_device_thread_args {
5555
static gpointer _gattlib_discovered_device_thread(gpointer data) {
5656
struct gattlib_discovered_device_thread_args* args = data;
5757

58-
g_rec_mutex_lock(&args->gattlib_adapter->discovered_device_callback.mutex);
58+
g_rec_mutex_lock(&m_gattlib_mutex);
59+
60+
if (!gattlib_adapter_is_valid(args->gattlib_adapter)) {
61+
g_rec_mutex_unlock(&m_gattlib_mutex);
62+
goto EXIT;
63+
}
5964

6065
if (!gattlib_has_valid_handler(&args->gattlib_adapter->discovered_device_callback)) {
66+
g_rec_mutex_unlock(&m_gattlib_mutex);
6167
goto EXIT;
6268
}
6369

70+
// Increase adapter reference counter to ensure the adapter is not freed while
71+
// the callback is in use.
72+
gattlib_adapter_ref(args->gattlib_adapter);
73+
74+
g_rec_mutex_unlock(&m_gattlib_mutex);
75+
6476
args->gattlib_adapter->discovered_device_callback.callback.discovered_device(
6577
args->gattlib_adapter,
6678
args->mac_address, args->name,
6779
args->gattlib_adapter->discovered_device_callback.user_data
6880
);
6981

70-
EXIT:
71-
g_rec_mutex_unlock(&args->gattlib_adapter->discovered_device_callback.mutex);
82+
gattlib_adapter_unref(args->gattlib_adapter);
7283

84+
EXIT:
7385
free(args->mac_address);
7486
if (args->name != NULL) {
7587
free(args->name);
@@ -96,6 +108,10 @@ static void* _discovered_device_thread_args_allocator(va_list args) {
96108
}
97109

98110
void gattlib_on_discovered_device(gattlib_adapter_t* gattlib_adapter, OrgBluezDevice1* device1) {
111+
if (!gattlib_adapter_is_valid(gattlib_adapter)) {
112+
return;
113+
}
114+
99115
gattlib_handler_dispatch_to_thread(
100116
&gattlib_adapter->discovered_device_callback,
101117
#if defined(WITH_PYTHON)

common/gattlib_callback_notification_device.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,19 @@ void gattlib_notification_device_thread(gpointer data, gpointer user_data) {
5656
struct gattlib_notification_device_thread_args* args = data;
5757
struct gattlib_handler* handler = user_data;
5858

59-
g_rec_mutex_lock(&handler->mutex);
59+
g_rec_mutex_lock(&m_gattlib_mutex);
60+
61+
if (!gattlib_connection_is_connected(args->connection)) {
62+
g_rec_mutex_unlock(&m_gattlib_mutex);
63+
return;
64+
}
6065

6166
handler->callback.notification_handler(
6267
args->uuid, args->data, args->data_length,
6368
handler->user_data
6469
);
6570

66-
g_rec_mutex_unlock(&handler->mutex);
71+
g_rec_mutex_unlock(&m_gattlib_mutex);
6772

6873
if (args->uuid != NULL) {
6974
free(args->uuid);

common/gattlib_common.c

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,21 @@
88

99
#include "gattlib_internal.h"
1010

11+
1112
int gattlib_register_notification(gattlib_connection_t* connection, gattlib_event_handler_t notification_handler, void* user_data) {
1213
GError *error = NULL;
14+
int ret = GATTLIB_SUCCESS;
15+
16+
g_rec_mutex_lock(&m_gattlib_mutex);
1317

1418
if (connection == NULL) {
15-
return GATTLIB_INVALID_PARAMETER;
19+
ret = GATTLIB_INVALID_PARAMETER;
20+
goto EXIT;
21+
}
22+
23+
if (!gattlib_device_is_valid(connection->device)) {
24+
ret = GATTLIB_INVALID_PARAMETER;
25+
goto EXIT;
1626
}
1727

1828
connection->notification.callback.notification_handler = notification_handler;
@@ -25,19 +35,33 @@ int gattlib_register_notification(gattlib_connection_t* connection, gattlib_even
2535
if (error != NULL) {
2636
GATTLIB_LOG(GATTLIB_ERROR, "gattlib_register_notification: Failed to create thread pool: %s", error->message);
2737
g_error_free(error);
28-
return GATTLIB_ERROR_INTERNAL;
38+
ret = GATTLIB_ERROR_INTERNAL;
39+
goto EXIT;
2940
} else {
3041
assert(connection->notification.thread_pool != NULL);
31-
return GATTLIB_SUCCESS;
3242
}
43+
44+
EXIT:
45+
g_rec_mutex_unlock(&m_gattlib_mutex);
46+
return ret;
3347
}
3448

3549
int gattlib_register_indication(gattlib_connection_t* connection, gattlib_event_handler_t indication_handler, void* user_data) {
3650
GError *error = NULL;
51+
int ret = GATTLIB_SUCCESS;
52+
53+
g_rec_mutex_lock(&m_gattlib_mutex);
3754

3855
if (connection == NULL) {
39-
return GATTLIB_INVALID_PARAMETER;
56+
ret = GATTLIB_INVALID_PARAMETER;
57+
goto EXIT;
4058
}
59+
60+
if (!gattlib_device_is_valid(connection->device)) {
61+
ret = GATTLIB_INVALID_PARAMETER;
62+
goto EXIT;
63+
}
64+
4165
connection->indication.callback.notification_handler = indication_handler;
4266
connection->indication.user_data = user_data;
4367

@@ -48,19 +72,36 @@ int gattlib_register_indication(gattlib_connection_t* connection, gattlib_event_
4872
if (error != NULL) {
4973
GATTLIB_LOG(GATTLIB_ERROR, "gattlib_register_indication: Failed to create thread pool: %s", error->message);
5074
g_error_free(error);
51-
return GATTLIB_ERROR_INTERNAL;
52-
} else {
53-
return GATTLIB_SUCCESS;
75+
ret = GATTLIB_ERROR_INTERNAL;
76+
goto EXIT;
5477
}
78+
79+
EXIT:
80+
g_rec_mutex_unlock(&m_gattlib_mutex);
81+
return ret;
5582
}
5683

5784
int gattlib_register_on_disconnect(gattlib_connection_t *connection, gattlib_disconnection_handler_t handler, void* user_data) {
85+
int ret = GATTLIB_SUCCESS;
86+
87+
g_rec_mutex_lock(&m_gattlib_mutex);
88+
5889
if (connection == NULL) {
59-
return GATTLIB_INVALID_PARAMETER;
90+
ret = GATTLIB_INVALID_PARAMETER;
91+
goto EXIT;
92+
}
93+
94+
if (!gattlib_device_is_valid(connection->device)) {
95+
ret = GATTLIB_INVALID_PARAMETER;
96+
goto EXIT;
6097
}
98+
6199
connection->on_disconnection.callback.disconnection_handler = handler;
62100
connection->on_disconnection.user_data = user_data;
63-
return GATTLIB_SUCCESS;
101+
102+
EXIT:
103+
g_rec_mutex_unlock(&m_gattlib_mutex);
104+
return ret;
64105
}
65106

66107
void bt_uuid_to_uuid(bt_uuid_t* bt_uuid, uuid_t* uuid) {
@@ -144,10 +185,8 @@ int gattlib_uuid_cmp(const uuid_t *uuid1, const uuid_t *uuid2) {
144185
}
145186

146187
void gattlib_handler_free(struct gattlib_handler* handler) {
147-
g_rec_mutex_lock(&handler->mutex);
148-
149188
if (!gattlib_has_valid_handler(handler)) {
150-
goto EXIT;
189+
return;
151190
}
152191

153192
// Reset callback to stop calling it after we stopped
@@ -172,9 +211,6 @@ void gattlib_handler_free(struct gattlib_handler* handler) {
172211
g_thread_pool_free(handler->thread_pool, FALSE /* immediate */, TRUE /* wait */);
173212
handler->thread_pool = NULL;
174213
}
175-
176-
EXIT:
177-
g_rec_mutex_unlock(&handler->mutex);
178214
}
179215

180216
bool gattlib_has_valid_handler(struct gattlib_handler* handler) {
@@ -185,8 +221,11 @@ void gattlib_handler_dispatch_to_thread(struct gattlib_handler* handler, void (*
185221
GThreadFunc thread_func, const char* thread_name, void* (*thread_args_allocator)(va_list args), ...) {
186222
GError *error = NULL;
187223

224+
g_rec_mutex_lock(&m_gattlib_mutex);
225+
188226
if (!gattlib_has_valid_handler(handler)) {
189227
// We do not have (anymore) a callback, nothing to do
228+
g_rec_mutex_unlock(&m_gattlib_mutex);
190229
return;
191230
}
192231

@@ -198,6 +237,8 @@ void gattlib_handler_dispatch_to_thread(struct gattlib_handler* handler, void (*
198237
}
199238
#endif
200239

240+
g_rec_mutex_unlock(&m_gattlib_mutex);
241+
201242
// We create a thread to ensure the callback is not blocking the mainloop
202243
va_list args;
203244
va_start(args, thread_args_allocator);
@@ -218,3 +259,10 @@ void gattlib_free_mem(void *ptr) {
218259
free(ptr);
219260
}
220261
}
262+
263+
int gattlib_device_ref(gattlib_device_t* device) {
264+
g_rec_mutex_lock(&m_gattlib_mutex);
265+
device->reference_counter++;
266+
g_rec_mutex_unlock(&m_gattlib_mutex);
267+
return GATTLIB_SUCCESS;
268+
}

0 commit comments

Comments
 (0)