This is needed to not block mainloop while initializing stack. In some cases, bluetooth->init blocks mainloop and bluetoothd cannot properly initialize controller, because HCI frames are not serviced in hciemu. Because pthread_join() is blocking, it is added to mainloop from thread right before pthread_exit() is called. Therefore this time is extremely short. --- android/tester-main.c | 64 +++++++++++++++++++++++++++++++++++++++++++-------- android/tester-main.h | 2 ++ 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/android/tester-main.c b/android/tester-main.c index 5d459b0..9a4a2e0 100644 --- a/android/tester-main.c +++ b/android/tester-main.c @@ -15,8 +15,10 @@ * */ #include <stdbool.h> +#include <pthread.h> #include "emulator/bthost.h" +#include "src/shared/util.h" #include "tester-main.h" #include "monitor/bt.h" @@ -1332,27 +1334,71 @@ static bool setup_base(struct test_data *data) return true; } -static void setup_generic(const void *test_data) +static gboolean join_init_thread(gpointer user_data) { struct test_data *data = tester_get_data(); - bt_status_t status; + int (*init_func)(void) = user_data; + int status; + void *ret; - if (!setup_base(data)) { + /* + * Note that pthread_join is blocking mainloop, + * therefore thread we want to join must + * exit immediately. This is done in init_thread() + */ + status = pthread_join(data->thread, &ret); + if (status != 0) { + tester_warn("Failed to join init thread, status %d", status); tester_setup_failed(); - return; + return FALSE; } - status = data->if_bluetooth->init(&bt_callbacks); - if (status != BT_STATUS_SUCCESS) { - data->if_bluetooth = NULL; + if (PTR_TO_INT(ret) != BT_STATUS_SUCCESS) { tester_setup_failed(); - return; + return FALSE; } - if (!data->init_routine || data->init_routine() == BT_STATUS_SUCCESS) + if (!init_func || init_func() == BT_STATUS_SUCCESS) tester_setup_complete(); else tester_setup_failed(); + + return FALSE; +} + +static void *init_thread(void *user_data) +{ + struct test_data *data = tester_get_data(); + int status; + + status = data->if_bluetooth->init(&bt_callbacks); + + g_idle_add(join_init_thread, user_data); + + pthread_exit(INT_TO_PTR(status)); +} + +static bool start_init_thread(int (*init)(void)) +{ + struct test_data *data = tester_get_data(); + + if (pthread_create(&data->thread, NULL, init_thread, init) != 0) + return false; + + return true; +} + +static void setup_generic(const void *test_data) +{ + struct test_data *data = tester_get_data(); + + if (!setup_base(data)) { + tester_setup_failed(); + return; + } + + if (!start_init_thread(data->init_routine)) + tester_setup_failed(); } static int init_socket(void) diff --git a/android/tester-main.h b/android/tester-main.h index 92cbd13..23c7c77 100644 --- a/android/tester-main.h +++ b/android/tester-main.h @@ -332,6 +332,8 @@ struct test_data { pid_t bluetoothd_pid; struct queue *pdus; + + pthread_t thread; }; /* -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html