@@ -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(¬ify_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(¬ify_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);
}
@@ -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;
}
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(-)