[PATCHv4] android/tester: Setup bluetooth module in separate thread

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 | 289 ++++++++++++++++++++++----------------------------
 1 file changed, 129 insertions(+), 160 deletions(-)

diff --git a/android/tester-main.c b/android/tester-main.c
index b65029a..bf6e55b 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"
@@ -28,6 +30,8 @@ static gint scheduled_cbacks_num;
 #define EMULATOR_SIGNAL_TIMEOUT 2 /* in seconds */
 #define EMULATOR_SIGNAL "emulator_started"
 
+static pthread_t thread;
+
 static gboolean check_callbacks_called(gpointer user_data)
 {
 	/*
@@ -1474,242 +1478,216 @@ static bool setup_base(struct test_data *data)
 	return true;
 }
 
-static void setup(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(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;
 	}
 
-	tester_setup_complete();
+	if (!init_func || init_func() == BT_STATUS_SUCCESS)
+		tester_setup_complete();
+	else
+		tester_setup_failed();
+
+	return FALSE;
 }
 
-static void setup_socket(const void *test_data)
+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))
+{
+	if (pthread_create(&thread, NULL, init_thread, init) != 0)
+		return false;
+
+	return true;
+}
+
+static void setup_generic(int (*init)(void))
 {
 	struct test_data *data = tester_get_data();
-	bt_status_t status;
-	const void *sock;
 
 	if (!setup_base(data)) {
 		tester_setup_failed();
 		return;
 	}
 
-	status = data->if_bluetooth->init(&bt_callbacks);
-	if (status != BT_STATUS_SUCCESS) {
-		data->if_bluetooth = NULL;
+	if (!start_init_thread(init))
 		tester_setup_failed();
-		return;
-	}
+}
+
+static void setup(const void *test_data)
+{
+	setup_generic(NULL);
+}
+
+static int init_socket(void)
+{
+	struct test_data *data = tester_get_data();
+	const void *sock;
 
 	sock = data->if_bluetooth->get_profile_interface(BT_PROFILE_SOCKETS_ID);
-	if (!sock) {
-		tester_setup_failed();
-		return;
-	}
+	if (!sock)
+		return BT_STATUS_FAIL;
 
 	data->if_sock = sock;
 
-	tester_setup_complete();
+	return BT_STATUS_SUCCESS;
 }
 
-static void setup_hidhost(const void *test_data)
+static void setup_socket(const void *test_data)
+{
+	setup_generic(init_socket);
+}
+
+static int init_hidhost(void)
 {
 	struct test_data *data = tester_get_data();
 	bt_status_t status;
 	const void *hid;
 
-	if (!setup_base(data)) {
-		tester_setup_failed();
-		return;
-	}
-
-	status = data->if_bluetooth->init(&bt_callbacks);
-	if (status != BT_STATUS_SUCCESS) {
-		data->if_bluetooth = NULL;
-		tester_setup_failed();
-		return;
-	}
-
 	hid = data->if_bluetooth->get_profile_interface(BT_PROFILE_HIDHOST_ID);
-	if (!hid) {
-		tester_setup_failed();
-		return;
-	}
+	if (!hid)
+		return BT_STATUS_FAIL;
 
 	data->if_hid = hid;
 
 	status = data->if_hid->init(&bthh_callbacks);
-	if (status != BT_STATUS_SUCCESS) {
+	if (status != BT_STATUS_SUCCESS)
 		data->if_hid = NULL;
-		tester_setup_failed();
-		return;
-	}
 
-	tester_setup_complete();
+	return status;
 }
 
-static void setup_pan(const void *test_data)
+static void setup_hidhost(const void *test_data)
+{
+	setup_generic(init_hidhost);
+}
+
+static int init_pan(void)
 {
 	struct test_data *data = tester_get_data();
 	bt_status_t status;
 	const void *pan;
 
-	if (!setup_base(data)) {
-		tester_setup_failed();
-		return;
-	}
-
-	status = data->if_bluetooth->init(&bt_callbacks);
-	if (status != BT_STATUS_SUCCESS) {
-		data->if_bluetooth = NULL;
-		tester_setup_failed();
-		return;
-	}
-
 	pan = data->if_bluetooth->get_profile_interface(BT_PROFILE_PAN_ID);
-	if (!pan) {
-		tester_setup_failed();
-		return;
-	}
+	if (!pan)
+		return BT_STATUS_FAIL;
 
 	data->if_pan = pan;
 
 	status = data->if_pan->init(&btpan_callbacks);
-	if (status != BT_STATUS_SUCCESS) {
+	if (status != BT_STATUS_SUCCESS)
 		data->if_pan = NULL;
-		tester_setup_failed();
-		return;
-	}
 
-	tester_setup_complete();
+	return status;
 }
 
-static void setup_hdp(const void *test_data)
+static void setup_pan(const void *test_data)
+{
+	setup_generic(init_pan);
+}
+
+static int init_hdp(void)
 {
 	struct test_data *data = tester_get_data();
 	bt_status_t status;
 	const void *hdp;
 
-	if (!setup_base(data)) {
-		tester_setup_failed();
-		return;
-	}
-
-	status = data->if_bluetooth->init(&bt_callbacks);
-	if (status != BT_STATUS_SUCCESS) {
-		data->if_bluetooth = NULL;
-		tester_setup_failed();
-		return;
-	}
-
 	hdp = data->if_bluetooth->get_profile_interface(BT_PROFILE_HEALTH_ID);
-	if (!hdp) {
-		tester_setup_failed();
-		return;
-	}
+	if (!hdp)
+		return BT_STATUS_FAIL;
 
 	data->if_hdp = hdp;
 
 	status = data->if_hdp->init(&bthl_callbacks);
-	if (status != BT_STATUS_SUCCESS) {
+	if (status != BT_STATUS_SUCCESS)
 		data->if_hdp = NULL;
-		tester_setup_failed();
-		return;
-	}
 
-	tester_setup_complete();
+	return status;
 }
 
-static void setup_a2dp(const void *test_data)
+static void setup_hdp(const void *test_data)
+{
+	setup_generic(init_hdp);
+}
+
+static int init_a2dp(void)
 {
 	struct test_data *data = tester_get_data();
 	const bt_interface_t *if_bt;
 	bt_status_t status;
 	const void *a2dp;
 
-	if (!setup_base(data)) {
-		tester_setup_failed();
-		return;
-	}
-
 	if_bt = data->if_bluetooth;
 
-	status = if_bt->init(&bt_callbacks);
-	if (status != BT_STATUS_SUCCESS) {
-		data->if_bluetooth = NULL;
-		tester_setup_failed();
-		return;
-	}
-
 	a2dp = if_bt->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID);
-	if (!a2dp) {
-		tester_setup_failed();
-		return;
-	}
+	if (!a2dp)
+		return BT_STATUS_FAIL;
 
 	data->if_a2dp = a2dp;
 
 	status = data->if_a2dp->init(&bta2dp_callbacks);
-	if (status != BT_STATUS_SUCCESS) {
+	if (status != BT_STATUS_SUCCESS)
 		data->if_a2dp = NULL;
-		tester_setup_failed();
-		return;
-	}
 
-	tester_setup_complete();
+	return status;
 }
 
-static void setup_avrcp(const void *test_data)
+static void setup_a2dp(const void *test_data)
+{
+	setup_generic(init_a2dp);
+}
+
+static int init_avrcp(void)
 {
 	struct test_data *data = tester_get_data();
-	const bt_interface_t *if_bt;
+	const bt_interface_t *if_bt = data->if_bluetooth;
 	bt_status_t status;
 	const void *a2dp, *avrcp;
 
-	if (!setup_base(data)) {
-		tester_setup_failed();
-		return;
-	}
-
-	if_bt = data->if_bluetooth;
-
-	status = if_bt->init(&bt_callbacks);
-	if (status != BT_STATUS_SUCCESS) {
-		data->if_bluetooth = NULL;
-		tester_setup_failed();
-		return;
-	}
-
 	a2dp = if_bt->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID);
-	if (!a2dp) {
-		tester_setup_failed();
-		return;
-	}
+	if (!a2dp)
+		return BT_STATUS_FAIL;
 
 	data->if_a2dp = a2dp;
 
 	status = data->if_a2dp->init(&bta2dp_callbacks);
 	if (status != BT_STATUS_SUCCESS) {
 		data->if_a2dp = NULL;
-		tester_setup_failed();
-		return;
+		return status;
 	}
 
 	avrcp = if_bt->get_profile_interface(BT_PROFILE_AV_RC_ID);
 	if (!avrcp) {
-		tester_setup_failed();
-		return;
+		data->if_a2dp = NULL;
+		return BT_STATUS_FAIL;
 	}
 
 	data->if_avrcp = avrcp;
@@ -1717,48 +1695,39 @@ static void setup_avrcp(const void *test_data)
 	status = data->if_avrcp->init(&btavrcp_callbacks);
 	if (status != BT_STATUS_SUCCESS) {
 		data->if_avrcp = NULL;
-		tester_setup_failed();
-		return;
+		data->if_a2dp = NULL;
 	}
 
-	tester_setup_complete();
+	return status;
 }
 
-static void setup_gatt(const void *test_data)
+static void setup_avrcp(const void *test_data)
+{
+	setup_generic(init_avrcp);
+}
+
+static int init_gatt(void)
 {
 	struct test_data *data = tester_get_data();
 	bt_status_t status;
 	const void *gatt;
 
-	if (!setup_base(data)) {
-		tester_setup_failed();
-		return;
-	}
-
-	status = data->if_bluetooth->init(&bt_callbacks);
-	if (status != BT_STATUS_SUCCESS) {
-		data->if_bluetooth = NULL;
-		tester_setup_failed();
-		return;
-	}
-
 	gatt = data->if_bluetooth->get_profile_interface(BT_PROFILE_GATT_ID);
-	if (!gatt) {
-		tester_setup_failed();
-		return;
-	}
+	if (!gatt)
+		return BT_STATUS_FAIL;
 
 	data->if_gatt = gatt;
 
 	status = data->if_gatt->init(&btgatt_callbacks);
-	if (status != BT_STATUS_SUCCESS) {
+	if (status != BT_STATUS_SUCCESS)
 		data->if_gatt = NULL;
 
-		tester_setup_failed();
-		return;
-	}
+	return status;
+}
 
-	tester_setup_complete();
+static void setup_gatt(const void *test_data)
+{
+	setup_generic(init_gatt);
 }
 
 static void teardown(const void *test_data)
-- 
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




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux