summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin-log.c67
-rw-r--r--revision.c22
-rw-r--r--revision.h4
3 files changed, 93 insertions, 0 deletions
diff --git a/builtin-log.c b/builtin-log.c
index 8b2bf63..4e9d0cb 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -77,11 +77,78 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
}
}
+static void log_show_early(struct rev_info *revs, struct commit_list *list)
+{
+ int i = revs->early_output;
+
+ sort_in_topological_order(&list, revs->lifo);
+ while (list && i) {
+ struct commit *commit = list->item;
+ log_tree_commit(revs, commit);
+ list = list->next;
+ i--;
+ }
+}
+
+static void early_output(int signal)
+{
+ show_early_output = log_show_early;
+}
+
+static void setup_early_output(struct rev_info *rev)
+{
+ struct sigaction sa;
+ struct itimerval v;
+
+ /*
+ * Set up the signal handler, minimally intrusively:
+ * we only set a single volatile integer word (not
+ * using sigatomic_t - trying to avoid unnecessary
+ * system dependencies and headers), and using
+ * SA_RESTART.
+ */
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = early_output;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGALRM, &sa, NULL);
+
+ /*
+ * If we can get the whole output in less than a
+ * tenth of a second, don't even bother doing the
+ * early-output thing..
+ *
+ * This is a one-time-only trigger.
+ */
+ memset(&v, 0, sizeof(v));
+ v.it_value.tv_sec = 0;
+ v.it_value.tv_usec = 100000;
+ setitimer(ITIMER_REAL, &v, NULL);
+}
+
+static void finish_early_output(struct rev_info *rev)
+{
+ signal(SIGALRM, SIG_IGN);
+ if (rev->shown_one) {
+ rev->shown_one = 0;
+ if (rev->commit_format != CMIT_FMT_ONELINE)
+ putchar(rev->diffopt.line_termination);
+ }
+ printf("Final output:\n");
+}
+
static int cmd_log_walk(struct rev_info *rev)
{
struct commit *commit;
+ if (rev->early_output)
+ setup_early_output(rev);
+
prepare_revision_walk(rev);
+
+ if (rev->early_output)
+ finish_early_output(rev);
+
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
if (!rev->reflog_info) {
diff --git a/revision.c b/revision.c
index e85b4af..26610bb 100644
--- a/revision.c
+++ b/revision.c
@@ -10,6 +10,8 @@
#include "reflog-walk.h"
#include "patch-ids.h"
+volatile show_early_output_fn_t show_early_output;
+
static char *path_name(struct name_path *path, const char *name)
{
struct name_path *p;
@@ -533,6 +535,7 @@ static int limit_list(struct rev_info *revs)
struct commit_list *entry = list;
struct commit *commit = list->item;
struct object *obj = &commit->object;
+ show_early_output_fn_t show;
list = list->next;
free(entry);
@@ -550,6 +553,13 @@ static int limit_list(struct rev_info *revs)
if (revs->min_age != -1 && (commit->date > revs->min_age))
continue;
p = &commit_list_insert(commit, p)->next;
+
+ show = show_early_output;
+ if (!show)
+ continue;
+
+ show(revs, newlist);
+ show_early_output = NULL;
}
if (revs->cherry_pick)
cherry_pick_list(newlist, revs);
@@ -991,6 +1001,18 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->topo_order = 1;
continue;
}
+ if (!prefixcmp(arg, "--early-output")) {
+ int count = 100;
+ switch (arg[14]) {
+ case '=':
+ count = atoi(arg+15);
+ /* Fallthrough */
+ case 0:
+ revs->topo_order = 1;
+ revs->early_output = count;
+ continue;
+ }
+ }
if (!strcmp(arg, "--parents")) {
revs->parents = 1;
continue;
diff --git a/revision.h b/revision.h
index 1f64576..d8a5a50 100644
--- a/revision.h
+++ b/revision.h
@@ -30,6 +30,8 @@ struct rev_info {
void *prune_data;
prune_fn_t *prune_fn;
+ unsigned int early_output;
+
/* Traversal flags */
unsigned int dense:1,
no_merges:1,
@@ -105,6 +107,8 @@ struct rev_info {
#define REV_TREE_DIFFERENT 2
/* revision.c */
+typedef void (*show_early_output_fn_t)(struct rev_info *, struct commit_list *);
+volatile show_early_output_fn_t show_early_output;
extern void init_revisions(struct rev_info *revs, const char *prefix);
extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def);