commit 472bdb824c6e30d0d7becab2a826f6a13bffb384
from: Mark Jamsek <mark@jamsek.dev>
via: Thomas Adam <thomas@xteddy.org>
date: Fri Jan 24 22:02:34 2025 UTC

tog: don't make users wait for the worktree diff to quit

Reported by naddy: if the user opens tog and quickly quits before the
log thread has finished fetching work tree state for displaying dirty
work tree entries, the main thread waits for the log thread to finish
before acting on the user's quit input. This produces a noticeable lag
between entering 'q' and tog actually terminating. Pass a pointer to
the quit flag to the worktree diff cancel callback so we can act on it
immediately without making the user wait.

tested by naddy who confirmed it greatly reduces the lag

commit - acca3e784b8d3ba91774e39aa50d325db895b434
commit + 472bdb824c6e30d0d7becab2a826f6a13bffb384
blob - a5a632533613cb01b96fee51cdd4d7033964b7e2
blob + eeeaf674438fcb6535713a5673c82658840f9501
--- tog/tog.c
+++ tog/tog.c
@@ -3143,7 +3143,15 @@ push_worktree_entry(struct tog_log_thread_args *ta, in
 static const struct got_error *
 check_cancelled(void *arg)
 {
-	if (tog_sigint_received || tog_sigpipe_received)
+	int rc, quit = 0;
+
+	if ((rc = pthread_mutex_lock(&tog_mutex)) != 0)
+		return got_error_set_errno(rc, "pthread_mutex_lock");
+	if (tog_sigint_received || tog_sigpipe_received || *((int *)arg))
+		quit = 1;
+	if ((rc = pthread_mutex_unlock(&tog_mutex)) != 0)
+		return got_error_set_errno(rc, "pthread_mutex_unlock");
+	if (quit)
 		return got_error(GOT_ERR_CANCELLED);
 	return NULL;
 }
@@ -3215,12 +3223,9 @@ tog_worktree_status(struct tog_log_thread_args *ta)
 		goto done;
 
 	err = got_worktree_status(wt, &paths, ta->repo, 0,
-	    check_local_changes, &wt_state, check_cancelled, NULL);
-	if (err != NULL) {
-		if (err->code != GOT_ERR_CANCELLED)
-			goto done;
-		err = NULL;
-	}
+	    check_local_changes, &wt_state, check_cancelled, ta->quit);
+	if (err != NULL)
+		goto done;
 
 	if (wt_state != 0) {
 		err = get_author(&wctx->wt_author, ta->repo, wt);
@@ -4052,8 +4057,11 @@ log_thread(void *arg)
 				goto done;
 			}
 			err = tog_worktree_status(a);
-			if (err != NULL)
+			if (err != NULL) {
+				if (err->code == GOT_ERR_CANCELLED)
+					err = NULL;
 				goto done;
+			}
 			errcode = pthread_mutex_lock(&tog_mutex);
 			if (errcode) {
 				err = got_error_set_errno(errcode,