Diff between dbe52200549bdc61fcd94c8c41d56c58d258ad7c and bfcc3f7bf48fa3c1fdbd3ae9bf6ae671575a4f1c

Changed Files

File Additions Deletions Status
emulator/hciemu.c +54 -0 modified
emulator/hciemu.h +3 -0 modified

Full Patch

diff --git a/emulator/hciemu.c b/emulator/hciemu.c
index dcfed9b..0b5847c 100644
--- a/emulator/hciemu.c
+++ b/emulator/hciemu.c
@@ -21,6 +21,7 @@
 #include <stdbool.h>
 #include <errno.h>
 #include <sys/socket.h>
+#include <sys/ioctl.h>
 
 #include <glib.h>
 
@@ -41,6 +42,7 @@ struct hciemu_client {
 	guint start_source;
 	guint host_source;
 	guint source;
+	int sock[2];
 };
 
 struct hciemu {
@@ -54,6 +56,8 @@ struct hciemu {
 	hciemu_debug_func_t debug_callback;
 	hciemu_destroy_func_t debug_destroy;
 	void *debug_data;
+
+	unsigned int flush_id;
 };
 
 struct hciemu_command_hook {
@@ -338,6 +342,9 @@ static struct hciemu_client *hciemu_client_new(struct hciemu *hciemu,
 		return NULL;
 	}
 
+	client->sock[0] = sv[0];
+	client->sock[1] = sv[1];
+
 	client->source = create_source_btdev(sv[0], client->dev);
 	client->host_source = create_source_bthost(sv[1], client->host);
 	client->start_source = g_idle_add(start_host, client);
@@ -435,6 +442,9 @@ void hciemu_unref(struct hciemu *hciemu)
 	queue_destroy(hciemu->post_command_hooks, destroy_command_hook);
 	queue_destroy(hciemu->clients, hciemu_client_destroy);
 
+	if (hciemu->flush_id)
+		g_source_remove(hciemu->flush_id);
+
 	vhci_close(hciemu->vhci);
 
 	free(hciemu);
@@ -744,3 +754,47 @@ bool hciemu_del_hook(struct hciemu *hciemu, enum hciemu_hook_type type,
 
 	return btdev_del_hook(dev, hook_type, opcode);
 }
+
+static bool client_is_pending(const void *data, const void *match_data)
+{
+	struct hciemu_client *client = (struct hciemu_client *)data;
+	int used, i;
+
+	if (!client->source || !client->host_source)
+		return false;
+
+	for (i = 0; i < 2; ++i) {
+		if (!ioctl(client->sock[i], TIOCOUTQ, &used) && used > 0)
+			return true;
+		if (!ioctl(client->sock[i], TIOCINQ, &used) && used > 0)
+			return true;
+	}
+
+	return false;
+}
+
+static gboolean flush_client_events(gpointer user_data)
+{
+	struct hciemu *hciemu = user_data;
+
+	if (queue_find(hciemu->clients, client_is_pending, NULL))
+		return TRUE;
+
+	hciemu->flush_id = 0;
+
+	util_debug(hciemu->debug_callback, hciemu->debug_data, "vhci: resume");
+	if (hciemu->vhci)
+		vhci_pause_input(hciemu->vhci, false);
+
+	return FALSE;
+}
+
+void hciemu_flush_client_events(struct hciemu *hciemu)
+{
+	if (hciemu->flush_id || !hciemu->vhci)
+		return;
+
+	util_debug(hciemu->debug_callback, hciemu->debug_data, "vhci: pause");
+	vhci_pause_input(hciemu->vhci, true);
+	hciemu->flush_id = g_idle_add(flush_client_events, hciemu);
+}
diff --git a/emulator/hciemu.h b/emulator/hciemu.h
index 3a06ca5..3449eae 100644
--- a/emulator/hciemu.h
+++ b/emulator/hciemu.h
@@ -48,6 +48,9 @@ bool hciemu_set_debug(struct hciemu *hciemu, hciemu_debug_func_t callback,
 struct vhci *hciemu_get_vhci(struct hciemu *hciemu);
 struct bthost *hciemu_client_get_host(struct hciemu *hciemu);
 
+/* Process pending client events before new VHCI events */
+void hciemu_flush_client_events(struct hciemu *hciemu);
+
 const char *hciemu_get_address(struct hciemu *hciemu);
 uint8_t *hciemu_get_features(struct hciemu *hciemu);