diff mbox series

[3/4] network_ipc: update swupdate_async_thread to use notify

Message ID 20211122031619.2202449-3-dominique.martinet@atmark-techno.com
State Changes Requested
Headers show
Series [1/4] ipc_notify_receive: add timeout_ms argument | expand

Commit Message

Dominique Martinet Nov. 22, 2021, 3:16 a.m. UTC
The former mechanism of sending update then checking for
ipc_wait_for_complete is inherently racy: it is possible the update has
not started yet when ipc_wait_for_complete sends the first STATUS
request, so it is possible the update is considered over before it
actually is.

Instead of periodically check for status, use the newer notify mechanism
to receive updates as they happen:
 - register a notify socket
 - send update image while checking that socket does not fill up
 - wait for notify to come back to IDLE state
 - if required, query status after all is done to get install result

(Bonus: we no longer rely on sleep(1) so test scripts installing small
updates in a loop now run much faster)

Signed-off-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
---

This is the v2 of 'ipc_wait_for_complete: wait a bit if the first status
we get was IDLE' from Friday: instead of fiddling with the wait time,
use the progress interface as you suggested.

I've tested this with the two users of swupdate_async_start() we have:
 swupdate -i
 swupdate-client with another swupdate process in the background

In both case the exit status still correctly reflects a successful or
failed update, and messages from swupdate-client (rq->get callback) are
mostly identical to the previous version (mostly because there seems to
be an extra blank line with the old code, I'm not sure where it came
from... But all non-empty messages are there)


FWIW I couldn't get -d to hit this race, so I haven't touched that part
of the code.

 ipc/network_ipc-if.c    | 59 ++++++++++++++++++++++++++++++++---------
 tools/swupdate-client.c |  4 +--
 2 files changed, 48 insertions(+), 15 deletions(-)
diff mbox series

Patch

diff --git a/ipc/network_ipc-if.c b/ipc/network_ipc-if.c
index fc5419ccaa38..90c49709b0fb 100644
--- a/ipc/network_ipc-if.c
+++ b/ipc/network_ipc-if.c
@@ -37,17 +37,25 @@  static void *swupdate_async_thread(void *data)
 	sigset_t saved_mask;
 	struct timespec zerotime = {0, 0};
 	struct async_lib *rq = (struct async_lib *)data;
-	int swupdate_result;
+	int notify_fd, ret;
+	ipc_message msg;
+	msg.data.notify.status = RUN;
 
 	sigemptyset(&sigpipe_mask);
 	sigaddset(&sigpipe_mask, SIGPIPE);
 
 	if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) {
-		  perror("pthread_sigmask");
-		    exit(1);
+		perror("pthread_sigmask");
+		exit(1);
 	}
-	/* Start writing the image until end */
 
+	notify_fd = ipc_notify_connect();
+	if (notify_fd < 0) {
+		perror("could not setup notify fd");
+		exit(1);
+	}
+
+	/* Start writing the image until end */
 	do {
 		if (!rq->wr)
 			break;
@@ -55,17 +63,32 @@  static void *swupdate_async_thread(void *data)
 		rq->wr(&pbuf, &size);
 		if (size)
 			swupdate_image_write(pbuf, size);
+
+		/* handle any notification coming */
+		while ((ret = ipc_notify_receive(&notify_fd, &msg, 0))
+				!= -ETIMEDOUT) {
+			if (ret < 0) {
+				perror("ipc_notify receive failed");
+				exit(1);
+			}
+			if (rq->get)
+				rq->get(&msg);
+		}
 	} while(size > 0);
 
 	ipc_end(rq->connfd);
 
-	/*
-	 * Everything sent, ask for status
-	 */
-
-	swupdate_result = ipc_wait_for_complete(rq->get);
-
-	handle = 0;
+	/* Everything sent, wait until we are IDLE again */
+	while (msg.data.notify.status != IDLE) {
+		ret = ipc_notify_receive(&notify_fd, &msg, -1);
+		if (ret < 0) {
+			perror("ipc_notify receive failed");
+			exit(1);
+		}
+		if (rq->get)
+			rq->get(&msg);
+	}
+	ipc_end(notify_fd);
 
 	if (sigtimedwait(&sigpipe_mask, 0, &zerotime) == -1) {
 		// currently ignored
@@ -75,8 +98,18 @@  static void *swupdate_async_thread(void *data)
 		  perror("pthread_sigmask");
 	}
 
-	if (rq->end)
-		rq->end((RECOVERY_STATUS)swupdate_result);
+	if (rq->end) {
+		/* Get status to get update return code */
+		ret = ipc_get_status(&msg);
+		if (ret < 0) {
+			perror("ipc_get_status failed");
+			exit(1);
+		}
+
+		rq->end(msg.data.status.last_result);
+	}
+
+	handle = 0;
 
 	pthread_exit(NULL);
 }
diff --git a/tools/swupdate-client.c b/tools/swupdate-client.c
index 22e55de3794d..c545fa43fe89 100644
--- a/tools/swupdate-client.c
+++ b/tools/swupdate-client.c
@@ -85,8 +85,8 @@  static int printstatus(ipc_message *msg)
 {
 	if (verbose)
 		fprintf(stdout, "Status: %d message: %s\n",
-			msg->data.status.current,
-			strlen(msg->data.status.desc) > 0 ? msg->data.status.desc : "");
+			msg->data.notify.status,
+			msg->data.notify.msg);
 
 	return 0;
 }