Download raw body.
tog log in shallow Git repositories
In a Git repository cloned with git clone --depth=1, tog hangs
on startup and is unresponsive to any input. This requires a
kill -9 to recover from.
The patch below fixes this such that 'tog log' displays the same
error message as 'got log' in such a repository:
$ got log
got: open: /tmp/test-got-clone-shallow/.git/objects/23/0e1f1bfa1d7bbd0dee0217e22bc2817e848ad0: No such file or directory
$ tog
tog: open: /tmp/test-got-clone-shallow/.git/objects/23/0e1f1bfa1d7bbd0dee0217e22bc2817e848ad0: No such file or directory
$
To do this properly we need to synchronize start-up of the log thread
with view_input(), otherwise tog will still hang forever in case the log
thread executes in parallel, and runs into an error in queue_commits(), and
exits before we even start waiting for its signal in trigger_log_thread().
This in turns means that mutex locking/unlocking in the log thread needs
to be revised.
Any errors from the log thread need to be propagated up via view_close()
to become visible when tog closes all active views during exit.
There is now a global tog_thread_error flag which should cause tog to
exit and which could also be used to improve error handling for other
threads in the future.
ok?
diff d2366e29426c9d2c88244cf41683f6574928caff c82b2a2333ce71095f7eaf674c13c22bcfc9db5e
commit - d2366e29426c9d2c88244cf41683f6574928caff
commit + c82b2a2333ce71095f7eaf674c13c22bcfc9db5e
blob - 7dc49c638a583244ce89554bdfee75bd523d1a99
blob + 17cc60e73fceae8247da28708b2bf8895bdfc2df
--- tog/tog.c
+++ tog/tog.c
@@ -337,6 +337,7 @@ struct tog_diff_view_state {
};
pthread_mutex_t tog_mutex = PTHREAD_MUTEX_INITIALIZER;
+static volatile sig_atomic_t tog_thread_error;
struct tog_log_thread_args {
pthread_cond_t need_commits;
@@ -657,10 +658,10 @@ tog_fatal_signal_received(void)
static const struct got_error *
view_close(struct tog_view *view)
{
- const struct got_error *err = NULL;
+ const struct got_error *err = NULL, *child_err = NULL;
if (view->child) {
- view_close(view->child);
+ child_err = view_close(view->child);
view->child = NULL;
}
if (view->close)
@@ -670,7 +671,7 @@ view_close(struct tog_view *view)
if (view->window)
delwin(view->window);
free(view);
- return err;
+ return err ? err : child_err;
}
static struct tog_view *
@@ -1361,7 +1362,8 @@ view_loop(struct tog_view *view)
return err;
update_panels();
doupdate();
- while (!TAILQ_EMPTY(&views) && !done && !tog_fatal_signal_received()) {
+ while (!TAILQ_EMPTY(&views) && !done && !tog_thread_error &&
+ !tog_fatal_signal_received()) {
/* Refresh fast during initialization, then become slower. */
if (fast_refresh && fast_refresh-- == 0)
halfdelay(10); /* switch to once per second */
@@ -1460,9 +1462,12 @@ view_loop(struct tog_view *view)
}
done:
while (!TAILQ_EMPTY(&views)) {
+ const struct got_error *close_err;
view = TAILQ_FIRST(&views);
TAILQ_REMOVE(&views, view, entry);
- view_close(view);
+ close_err = view_close(view);
+ if (close_err && err == NULL)
+ err = close_err;
}
errcode = pthread_mutex_unlock(&tog_mutex);
@@ -2198,10 +2203,8 @@ trigger_log_thread(struct tog_view *view, int wait)
halfdelay(1); /* fast refresh while loading commits */
- while (ta->commits_needed > 0 || ta->load_all) {
- if (ta->log_complete)
- break;
-
+ while (!ta->log_complete && !tog_thread_error &&
+ (ta->commits_needed > 0 || ta->load_all)) {
/* Wake the log thread. */
errcode = pthread_cond_signal(&ta->need_commits);
if (errcode)
@@ -2476,15 +2479,33 @@ log_thread(void *arg)
struct tog_log_thread_args *a = arg;
int done = 0;
- err = block_signals_used_by_main_thread();
- if (err)
+ /*
+ * Sync startup with main thread such that we begin our
+ * work once view_input() has released the mutex.
+ */
+ errcode = pthread_mutex_lock(&tog_mutex);
+ if (errcode) {
+ err = got_error_set_errno(errcode, "pthread_mutex_lock");
return (void *)err;
+ }
+ err = block_signals_used_by_main_thread();
+ if (err) {
+ pthread_mutex_unlock(&tog_mutex);
+ goto done;
+ }
+
while (!done && !err && !tog_fatal_signal_received()) {
+ errcode = pthread_mutex_unlock(&tog_mutex);
+ if (errcode) {
+ err = got_error_set_errno(errcode,
+ "pthread_mutex_unlock");
+ goto done;
+ }
err = queue_commits(a);
if (err) {
if (err->code != GOT_ERR_ITER_COMPLETED)
- return (void *)err;
+ goto done;
err = NULL;
done = 1;
} else if (a->commits_needed > 0 && !a->load_all)
@@ -2494,7 +2515,7 @@ log_thread(void *arg)
if (errcode) {
err = got_error_set_errno(errcode,
"pthread_mutex_lock");
- break;
+ goto done;
} else if (*a->quit)
done = 1;
else if (*a->first_displayed_entry == NULL) {
@@ -2508,7 +2529,7 @@ log_thread(void *arg)
err = got_error_set_errno(errcode,
"pthread_cond_signal");
pthread_mutex_unlock(&tog_mutex);
- break;
+ goto done;
}
if (done)
@@ -2517,27 +2538,33 @@ log_thread(void *arg)
if (a->commits_needed == 0 && !a->load_all) {
errcode = pthread_cond_wait(&a->need_commits,
&tog_mutex);
- if (errcode)
+ if (errcode) {
err = got_error_set_errno(errcode,
"pthread_cond_wait");
+ pthread_mutex_unlock(&tog_mutex);
+ goto done;
+ }
if (*a->quit)
done = 1;
}
}
-
- errcode = pthread_mutex_unlock(&tog_mutex);
- if (errcode && err == NULL)
- err = got_error_set_errno(errcode,
- "pthread_mutex_unlock");
}
a->log_complete = 1;
+ errcode = pthread_mutex_unlock(&tog_mutex);
+ if (errcode)
+ err = got_error_set_errno(errcode, "pthread_mutex_unlock");
+done:
+ if (err) {
+ tog_thread_error = 1;
+ pthread_cond_signal(&a->commit_loaded);
+ }
return (void *)err;
}
static const struct got_error *
stop_log_thread(struct tog_log_view_state *s)
{
- const struct got_error *err = NULL;
+ const struct got_error *err = NULL, *thread_err = NULL;
int errcode;
if (s->thread) {
@@ -2550,7 +2577,7 @@ stop_log_thread(struct tog_log_view_state *s)
if (errcode)
return got_error_set_errno(errcode,
"pthread_mutex_unlock");
- errcode = pthread_join(s->thread, (void **)&err);
+ errcode = pthread_join(s->thread, (void **)&thread_err);
if (errcode)
return got_error_set_errno(errcode, "pthread_join");
errcode = pthread_mutex_lock(&tog_mutex);
@@ -2578,7 +2605,7 @@ stop_log_thread(struct tog_log_view_state *s)
s->thread_args.graph = NULL;
}
- return err;
+ return err ? err : thread_err;
}
static const struct got_error *
tog log in shallow Git repositories