Skip to content

Commit

Permalink
hciemu: Add hciemu_flush_client_events for ordering VHCI vs bthost
Browse files Browse the repository at this point in the history
bthost commands execute with a delay because events may be sitting in
the socketpair queues.  This makes it difficult to ensure, when writing
tests, that certain bthost commands have been handled, before any new
events from VHCI are processed.

To make event ordering possible, add a function that flushes client
bthost/btdev socketpair queues, before processing any new VHCI events.
This is done by pausing VHCI input processing until the kernel
socketpair queues are empty.
  • Loading branch information
pv authored and Vudentz committed Aug 21, 2023
1 parent dbe5220 commit bfcc3f7
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
54 changes: 54 additions & 0 deletions emulator/hciemu.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <stdbool.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <glib.h>

Expand All @@ -41,6 +42,7 @@ struct hciemu_client {
guint start_source;
guint host_source;
guint source;
int sock[2];
};

struct hciemu {
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
3 changes: 3 additions & 0 deletions emulator/hciemu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit bfcc3f7

Please sign in to comment.