diff mbox series

[2/9] wmediumd: properly wait for control socket ACK

Message ID 20200625150754.57939c4eed52.Iebbeb7ba51a6f3c3ada3091d7a2da0ebc7da803f@changeid (mailing list archive)
State Not Applicable
Delegated to: Johannes Berg
Headers show
Series [1/9] wmediumd: add -lstdc++ for SANITIZE=1 | expand

Commit Message

Johannes Berg June 25, 2020, 1:08 p.m. UTC
From: Johannes Berg <johannes.berg@intel.com>

When the control socket is used in conjunction with a time
controller, then it may happen that we have

wmediumd               app                  time controller
  ------ message ------>
  (wait for ack)
                         ----- request runtime --->
  <-------------- update scheduler ----------------
                                              (wait for ack)

and deadlock here, because the update scheduler message
isn't processed by wmediumd.

Fix this by properly deferring to the mainloop when waiting
for an ACK message on the control socket.

---
 wmediumd/wmediumd.c | 23 +++++++++++++++++++++--
 wmediumd/wmediumd.h |  1 +
 2 files changed, 22 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/wmediumd/wmediumd.c b/wmediumd/wmediumd.c
index d756dc4be5b9..8a9d97b6a427 100644
--- a/wmediumd/wmediumd.c
+++ b/wmediumd/wmediumd.c
@@ -26,6 +26,7 @@ 
 #include <netlink/genl/genl.h>
 #include <netlink/genl/ctrl.h>
 #include <netlink/genl/family.h>
+#include <assert.h>
 #include <stdint.h>
 #include <getopt.h>
 #include <signal.h>
@@ -264,6 +265,15 @@  static struct station *get_station_by_used_addr(struct wmediumd *ctx, u8 *addr)
 	return NULL;
 }
 
+static void wmediumd_wait_for_client_ack(struct wmediumd *ctx,
+					 struct client *client)
+{
+	client->wait_for_ack = true;
+
+	while (client->wait_for_ack)
+		usfstl_loop_wait_and_handle();
+}
+
 static void queue_frame(struct wmediumd *ctx, struct station *station,
 			struct frame *frame)
 {
@@ -430,8 +440,7 @@  static void wmediumd_send_to_client(struct wmediumd *ctx,
 		hdr.data_len = len;
 		write(client->loop.fd, &hdr, sizeof(hdr));
 		write(client->loop.fd, (void *)nlmsg_hdr(msg), len);
-		/* read the ACK back */
-		read(client->loop.fd, &hdr, sizeof(hdr));
+		wmediumd_wait_for_client_ack(ctx, client);
 		break;
 	}
 }
@@ -871,6 +880,14 @@  static void wmediumd_api_handler(struct usfstl_loop_entry *entry)
 	if (len != hdr.data_len)
 		goto disconnect;
 
+	if (client->wait_for_ack) {
+		assert(hdr.type == WMEDIUMD_MSG_ACK);
+		assert(hdr.data_len == 0);
+		client->wait_for_ack = false;
+		/* don't send a response to a response, of course */
+		return;
+	}
+
 	switch (hdr.type) {
 	case WMEDIUMD_MSG_REGISTER:
 		if (!list_empty(&client->list)) {
@@ -900,6 +917,8 @@  static void wmediumd_api_handler(struct usfstl_loop_entry *entry)
 
 		nlmsg_free(nlmsg);
 		break;
+	case WMEDIUMD_MSG_ACK:
+		abort();
 	default:
 		response = WMEDIUMD_MSG_INVALID;
 		break;
diff --git a/wmediumd/wmediumd.h b/wmediumd/wmediumd.h
index e201788b9b52..fb7b47a43574 100644
--- a/wmediumd/wmediumd.h
+++ b/wmediumd/wmediumd.h
@@ -183,6 +183,7 @@  struct client {
 
 	/* for API socket */
 	struct usfstl_loop_entry loop;
+	bool wait_for_ack;
 };
 
 struct wmediumd {