Commit Diff


commit - ccdddf69864eb9ac5c10c0f5d58b68df1cf26ea1
commit + 99301cec42290cd26b9757c17eaaab5d70781bf1
blob - 07cb22fd98f7b10c110a8a5d0c0627770c5b7e76
blob + 02e203f9626eba60a84658a1f9e7a8d0fb043418
--- include/got_worktree.h
+++ include/got_worktree.h
@@ -137,13 +137,14 @@ const struct got_error *got_worktree_set_base_commit_i
  * Get the state of the work tree. If the work tree's global base commit is
  * the tip of the work tree's current branch, and each file in the index is
  * based on this same commit, the char out parameter will be
- * GOT_WORKTREE_UPTODATE, else it will be GOT_WORKTREE_OUTOFDATE.
+ * GOT_WORKTREE_STATE_UPTODATE, else it will be GOT_WORKTREE_STATE_OUTOFDATE.
  */
 const struct got_error *got_worktree_get_state(char *,
     struct got_repository *, struct got_worktree *);
 
-#define GOT_WORKTREE_UPTODATE	'*'
-#define GOT_WORKTREE_OUTOFDATE	'~'
+#define GOT_WORKTREE_STATE_UNKNOWN	' '
+#define GOT_WORKTREE_STATE_UPTODATE	'*'
+#define GOT_WORKTREE_STATE_OUTOFDATE	'~'
 
 /*
  * Obtain a parsed representation of this worktree's got.conf file.
blob - 6b14bc178bf5fbc6065088656b0ecae4a8fd2aad
blob + e0c7318204bffd754947e3848dcb9e7b6ad3ae9e
--- lib/worktree.c
+++ lib/worktree.c
@@ -3273,7 +3273,7 @@ got_worktree_get_state(char *state, struct got_reposit
 	if (err)
 		goto done;
 
-	*state = GOT_WORKTREE_OUTOFDATE;
+	*state = GOT_WORKTREE_STATE_UNKNOWN;
 	base_id = got_worktree_get_base_commit_id(worktree);
 
 	if (got_object_id_cmp(base_id, head_id) == 0) {
@@ -3284,10 +3284,13 @@ got_worktree_get_state(char *state, struct got_reposit
 		err = got_fileindex_for_each_entry_safe(fileindex,
 		    check_mixed_commits, worktree);
 		if (err == NULL)
-			*state = GOT_WORKTREE_UPTODATE;
-		else if (err->code == GOT_ERR_MIXED_COMMITS)
+			*state = GOT_WORKTREE_STATE_UPTODATE;
+		else if (err->code == GOT_ERR_MIXED_COMMITS) {
+			*state = GOT_WORKTREE_STATE_OUTOFDATE;
 			err = NULL;
-	}
+		}
+	} else
+		*state = GOT_WORKTREE_STATE_OUTOFDATE;
 
 done:
 	free(head_id);
blob - d10c8e4e269c29522a88fa8b7f94b5658cacd469
blob + a7c92801a63e2df3de71afd808cde146986b7efc
--- regress/tog/log.sh
+++ regress/tog/log.sh
@@ -397,6 +397,7 @@ test_log_commit_keywords()
 	done
 
 	cat <<-EOF >$TOG_TEST_SCRIPT
+	WAIT_FOR_UI	wait for log thread to finish
 	SCREENDUMP
 	EOF
 
@@ -526,6 +527,7 @@ test_log_show_base_commit()
 
 	# check up-to-date base commit marker prefixes base commit log message
 	cat <<-EOF >$TOG_TEST_SCRIPT
+	WAIT_FOR_UI	wait for log thread to finish
 	SCREENDUMP
 	EOF
 
@@ -566,6 +568,7 @@ test_log_show_base_commit()
 	head_id=$(git_show_head "$repo")
 
 	cat <<-EOF >$TOG_TEST_SCRIPT
+	WAIT_FOR_UI	wait for log thread to finish
 	SCREENDUMP
 	EOF
 
blob - 897b0c14098c0b8440dbdfbedd2bb8c0792e6efb
blob + 1bd75430ffde37cc2e0c9ceb60677641c9813dc3
--- tog/tog.c
+++ tog/tog.c
@@ -370,6 +370,7 @@ struct tog_log_thread_args {
 	struct got_repository *repo;
 	int *pack_fds;
 	int log_complete;
+	pthread_cond_t log_loaded;
 	sig_atomic_t *quit;
 	struct commit_queue_entry **first_displayed_entry;
 	struct commit_queue_entry **selected_entry;
@@ -380,6 +381,8 @@ struct tog_log_thread_args {
 	int limit_match;
 	regex_t *limit_regex;
 	struct commit_queue *limit_commits;
+	struct got_worktree *worktree;
+	int need_commit_marker;
 };
 
 struct tog_log_view_state {
@@ -730,7 +733,7 @@ static const struct got_error *search_next_view_match(
 
 static const struct got_error *open_log_view(struct tog_view *,
     struct got_object_id *, struct got_repository *,
-    const char *, const char *, int);
+    const char *, const char *, int, struct got_worktree *);
 static const struct got_error * show_log_view(struct tog_view *);
 static const struct got_error *input_log_view(struct tog_view **,
     struct tog_view *, int);
@@ -2423,6 +2426,10 @@ draw_commit(struct tog_view *view, struct commit_queue
 	struct tog_color *tc;
 	struct got_reflist_head *refs;
 
+	if (tog_base_commit.id != NULL && tog_base_commit.idx == -1 &&
+	    got_object_id_cmp(id, tog_base_commit.id) == 0)
+		tog_base_commit.idx = entry->idx;
+
 	committer_time = got_object_commit_get_committer_time(commit);
 	if (gmtime_r(&committer_time, &tm) == NULL)
 		return got_error_from_errno("gmtime_r");
@@ -2482,7 +2489,7 @@ draw_commit(struct tog_view *view, struct commit_queue
 	waddwstr(view->window, wauthor);
 	col += author_width;
 	while (col < avail && author_width < author_display_cols + 2) {
-		if (tog_base_commit.id != NULL &&
+		if (tog_base_commit.marker != GOT_WORKTREE_STATE_UNKNOWN &&
 		    author_width == marker_column &&
 		    entry->idx == tog_base_commit.idx) {
 			tc = get_color(&s->colors, TOG_COLOR_COMMIT);
@@ -2709,10 +2716,6 @@ queue_commits(struct tog_log_thread_args *a)
 		TAILQ_INSERT_TAIL(&a->real_commits->head, entry, entry);
 		a->real_commits->ncommits++;
 
-		if (tog_base_commit.id != NULL && tog_base_commit.idx == -1 &&
-		    got_object_id_cmp(&id, tog_base_commit.id) == 0)
-			tog_base_commit.idx = entry->idx;
-
 		if (*a->limiting) {
 			err = match_commit(&limit_match, &id, commit,
 			    a->limit_regex);
@@ -3327,6 +3330,7 @@ log_thread(void *arg)
 				goto done;
 			err = NULL;
 			done = 1;
+			a->commits_needed = 0;
 		} else if (a->commits_needed > 0 && !a->load_all) {
 			if (*a->limiting) {
 				if (a->limit_match)
@@ -3360,10 +3364,49 @@ log_thread(void *arg)
 			goto done;
 		}
 
+		if (a->commits_needed == 0 &&
+		    a->need_commit_marker && a->worktree) {
+			errcode = pthread_mutex_unlock(&tog_mutex);
+			if (errcode) {
+				err = got_error_set_errno(errcode,
+				    "pthread_mutex_unlock");
+				goto done;
+			}
+			err = got_worktree_get_state(&tog_base_commit.marker,
+			    a->repo, a->worktree);
+			if (err)
+				goto done;
+			errcode = pthread_mutex_lock(&tog_mutex);
+			if (errcode) {
+				err = got_error_set_errno(errcode,
+				    "pthread_mutex_lock");
+				goto done;
+			}
+			a->need_commit_marker = 0;
+			/*
+			 * The main thread did not close this
+			 * work tree yet. Close it now.
+			 */
+			got_worktree_close(a->worktree);
+			a->worktree = NULL;
+
+			if (*a->quit)
+				done = 1;
+		}
+
 		if (done)
 			a->commits_needed = 0;
 		else {
 			if (a->commits_needed == 0 && !a->load_all) {
+				if (tog_io.wait_for_ui) {
+					errcode = pthread_cond_signal(
+					    &a->log_loaded);
+					if (errcode && err == NULL)
+						err = got_error_set_errno(
+						    errcode,
+						    "pthread_cond_signal");
+				}
+
 				errcode = pthread_cond_wait(&a->need_commits,
 				    &tog_mutex);
 				if (errcode) {
@@ -3378,6 +3421,13 @@ log_thread(void *arg)
 		}
 	}
 	a->log_complete = 1;
+	if (tog_io.wait_for_ui) {
+		errcode = pthread_cond_signal(&a->log_loaded);
+		if (errcode && err == NULL)
+			err = got_error_set_errno(errcode,
+			    "pthread_cond_signal");
+	}
+
 	errcode = pthread_mutex_unlock(&tog_mutex);
 	if (errcode)
 		err = got_error_set_errno(errcode, "pthread_mutex_unlock");
@@ -3385,6 +3435,10 @@ done:
 	if (err) {
 		tog_thread_error = 1;
 		pthread_cond_signal(&a->commit_loaded);
+		if (a->worktree) {
+			got_worktree_close(a->worktree);
+			a->worktree = NULL;
+		}
 	}
 	return (void *)err;
 }
@@ -3705,7 +3759,8 @@ search_next_log_view(struct tog_view *view)
 static const struct got_error *
 open_log_view(struct tog_view *view, struct got_object_id *start_id,
     struct got_repository *repo, const char *head_ref_name,
-    const char *in_repo_path, int log_branches)
+    const char *in_repo_path, int log_branches,
+    struct got_worktree *worktree)
 {
 	const struct got_error *err = NULL;
 	struct tog_log_view_state *s = &view->state.log;
@@ -3803,6 +3858,14 @@ open_log_view(struct tog_view *view, struct got_object
 		goto done;
 	}
 
+	if (using_mock_io) {
+		int rc;
+
+		rc = pthread_cond_init(&s->thread_args.log_loaded, NULL);
+		if (rc)
+			return got_error_set_errno(rc, "pthread_cond_init");
+	}
+
 	s->thread_args.commits_needed = view->nlines;
 	s->thread_args.graph = thread_graph;
 	s->thread_args.real_commits = &s->real_commits;
@@ -3820,6 +3883,9 @@ open_log_view(struct tog_view *view, struct got_object
 	s->thread_args.limiting = &s->limit_view;
 	s->thread_args.limit_regex = &s->limit_regex;
 	s->thread_args.limit_commits = &s->limit_commits;
+	s->thread_args.worktree = worktree;
+	if (worktree)
+		s->thread_args.need_commit_marker = 1;
 done:
 	if (err) {
 		if (view->close == NULL)
@@ -3844,6 +3910,16 @@ show_log_view(struct tog_view *view)
 			err = trigger_log_thread(view, 1);
 			if (err)
 				return err;
+			if (tog_io.wait_for_ui) {
+				int rc;
+
+				rc = pthread_cond_wait(&s->thread_args.log_loaded,
+				    &tog_mutex);
+				if (rc)
+					return got_error_set_errno(rc,
+					    "pthread_cond_wait");
+				tog_io.wait_for_ui = 0;
+			}
 		}
 	}
 
@@ -4393,10 +4469,7 @@ set_tog_base_commit(struct got_repository *repo, struc
 	if (tog_base_commit.id == NULL)
 		return got_error_from_errno( "got_object_id_dup");
 
-	tog_base_commit.idx = -1;
-
-	return got_worktree_get_state(&tog_base_commit.marker, repo,
-	    worktree);
+	return NULL;
 }
 
 static const struct got_error *
@@ -4551,18 +4624,20 @@ cmd_log(int argc, char *argv[])
 		error = got_error_from_errno("view_open");
 		goto done;
 	}
-	error = open_log_view(view, start_id, repo, head_ref_name,
-	    in_repo_path, log_branches);
-	if (error)
-		goto done;
 
 	if (worktree) {
 		error = set_tog_base_commit(repo, worktree);
 		if (error != NULL)
 			goto done;
+	}
 
-		/* Release work tree lock. */
-		got_worktree_close(worktree);
+	error = open_log_view(view, start_id, repo, head_ref_name,
+	    in_repo_path, log_branches, worktree);
+	if (error)
+		goto done;
+
+	if (worktree) {
+		/* The work tree will be closed by the log thread. */
 		worktree = NULL;
 	}
 
@@ -6814,7 +6889,7 @@ log_annotated_line(struct tog_view **new_view, int beg
 	if (log_view == NULL)
 		return got_error_from_errno("view_open");
 
-	err = open_log_view(log_view, id, repo, GOT_REF_HEAD, "", 0);
+	err = open_log_view(log_view, id, repo, GOT_REF_HEAD, "", 0, NULL);
 	if (err)
 		view_close(log_view);
 	else
@@ -7616,7 +7691,7 @@ log_selected_tree_entry(struct tog_view **new_view, in
 		return err;
 
 	err = open_log_view(log_view, s->commit_id, s->repo, s->head_ref_name,
-	    path, 0);
+	    path, 0, NULL);
 	if (err)
 		view_close(log_view);
 	else
@@ -8474,7 +8549,7 @@ log_ref_entry(struct tog_view **new_view, int begin_y,
 	}
 
 	err = open_log_view(log_view, commit_id, repo,
-	    got_ref_get_name(re->ref), "", 0);
+	    got_ref_get_name(re->ref), "", 0, NULL);
 done:
 	if (err)
 		view_close(log_view);
@@ -10082,6 +10157,9 @@ main(int argc, char *argv[])
 			tog_diff_algo = GOT_DIFF_ALGORITHM_MYERS;
 	}
 
+	tog_base_commit.idx = -1;
+	tog_base_commit.marker = GOT_WORKTREE_STATE_UNKNOWN;
+
 	if (cmd == NULL) {
 		if (argc != 1)
 			usage(0, 1);