summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Adam <thomas@xteddy.org>2017-04-20 12:01:14 +0100
committerThomas Adam <thomas@xteddy.org>2017-04-20 12:01:14 +0100
commit48371216df07c588180b8e2246930a96e94de62b (patch)
treeb7fe5d01adee8885d766616fcea5ff41d773ec01
parente30f9dc1fae848d659295a9dfab0a5e0cf4e1a46 (diff)
parent21993105e53da0f5aae583b494c83f1cbbf48b1b (diff)
Merge branch 'obsd-master'
-rw-r--r--cmd-if-shell.c4
-rw-r--r--cmd-run-shell.c4
-rw-r--r--cmd-show-messages.c2
-rw-r--r--format.c64
-rw-r--r--job.c49
-rw-r--r--server.c11
-rw-r--r--tmux.12
-rw-r--r--tmux.h33
-rw-r--r--window-copy.c2
-rw-r--r--window.c12
10 files changed, 119 insertions, 64 deletions
diff --git a/cmd-if-shell.c b/cmd-if-shell.c
index f7d95d53..0b1fe7f5 100644
--- a/cmd-if-shell.c
+++ b/cmd-if-shell.c
@@ -127,8 +127,8 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->item = NULL;
memcpy(&cdata->mouse, &item->mouse, sizeof cdata->mouse);
- job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free,
- cdata);
+ job_run(shellcmd, s, cwd, NULL, cmd_if_shell_callback,
+ cmd_if_shell_free, cdata);
free(shellcmd);
if (args_has(args, 'b'))
diff --git a/cmd-run-shell.c b/cmd-run-shell.c
index d06d7f99..48d88049 100644
--- a/cmd-run-shell.c
+++ b/cmd-run-shell.c
@@ -110,8 +110,8 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(args, 'b'))
cdata->item = item;
- job_run(cdata->cmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free,
- cdata);
+ job_run(cdata->cmd, s, cwd, NULL, cmd_run_shell_callback,
+ cmd_run_shell_free, cdata);
if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL);
diff --git a/cmd-show-messages.c b/cmd-show-messages.c
index c88e0511..e7e56172 100644
--- a/cmd-show-messages.c
+++ b/cmd-show-messages.c
@@ -75,7 +75,7 @@ cmd_show_messages_jobs(struct cmdq_item *item, int blank)
u_int n;
n = 0;
- LIST_FOREACH(job, &all_jobs, lentry) {
+ LIST_FOREACH(job, &all_jobs, entry) {
if (blank) {
cmdq_print(item, "%s", "");
blank = 0;
diff --git a/format.c b/format.c
index 839cf48a..5be10e1a 100644
--- a/format.c
+++ b/format.c
@@ -40,7 +40,6 @@
struct format_entry;
typedef void (*format_cb)(struct format_tree *, struct format_entry *);
-static void format_job_callback(struct job *);
static char *format_job_get(struct format_tree *, const char *);
static void format_job_timer(int, short, void *);
@@ -76,7 +75,7 @@ static int format_replace(struct format_tree *, const char *, size_t,
static void format_defaults_session(struct format_tree *,
struct session *);
static void format_defaults_client(struct format_tree *, struct client *);
-static void format_defaults_winlink(struct format_tree *, struct session *,
+static void format_defaults_winlink(struct format_tree *,
struct winlink *);
/* Entry in format job tree. */
@@ -87,6 +86,7 @@ struct format_job {
time_t last;
char *out;
+ int updated;
struct job *job;
int status;
@@ -207,9 +207,35 @@ static const char *format_lower[] = {
NULL /* z */
};
-/* Format job callback. */
+/* Format job update callback. */
static void
-format_job_callback(struct job *job)
+format_job_update(struct job *job)
+{
+ struct format_job *fj = job->data;
+ char *line;
+ time_t t;
+ struct client *c;
+
+ if ((line = evbuffer_readline(job->event->input)) == NULL)
+ return;
+ fj->updated = 1;
+
+ free(fj->out);
+ fj->out = line;
+
+ log_debug("%s: %s: %s", __func__, fj->cmd, fj->out);
+
+ t = time (NULL);
+ if (fj->status && fj->last != t) {
+ TAILQ_FOREACH(c, &clients, entry)
+ server_status_client(c);
+ fj->last = t;
+ }
+}
+
+/* Format job complete callback. */
+static void
+format_job_complete(struct job *job)
{
struct format_job *fj = job->data;
char *line, *buf;
@@ -217,7 +243,6 @@ format_job_callback(struct job *job)
struct client *c;
fj->job = NULL;
- free(fj->out);
buf = NULL;
if ((line = evbuffer_readline(job->event->input)) == NULL) {
@@ -228,15 +253,19 @@ format_job_callback(struct job *job)
buf[len] = '\0';
} else
buf = line;
- fj->out = buf;
+
+ if (*buf != '\0' || !fj->updated) {
+ free(fj->out);
+ fj->out = buf;
+ log_debug("%s: %s: %s", __func__, fj->cmd, fj->out);
+ } else
+ free(buf);
if (fj->status) {
TAILQ_FOREACH(c, &clients, entry)
server_status_client(c);
fj->status = 0;
}
-
- log_debug("%s: %s: %s", __func__, fj->cmd, fj->out);
}
/* Find a job. */
@@ -271,8 +300,8 @@ format_job_get(struct format_tree *ft, const char *cmd)
t = time(NULL);
if (fj->job == NULL && (force || fj->last != t)) {
- fj->job = job_run(expanded, NULL, NULL, format_job_callback,
- NULL, fj);
+ fj->job = job_run(expanded, NULL, NULL, format_job_update,
+ format_job_complete, NULL, fj);
if (fj->job == NULL) {
free(fj->out);
xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
@@ -1112,8 +1141,8 @@ format_defaults(struct format_tree *ft, struct client *c, struct session *s,
format_defaults_client(ft, c);
if (s != NULL)
format_defaults_session(ft, s);
- if (s != NULL && wl != NULL)
- format_defaults_winlink(ft, s, wl);
+ if (wl != NULL)
+ format_defaults_winlink(ft, wl);
if (wp != NULL)
format_defaults_pane(ft, wp);
}
@@ -1224,21 +1253,18 @@ format_defaults_window(struct format_tree *ft, struct window *w)
/* Set default format keys for a winlink. */
static void
-format_defaults_winlink(struct format_tree *ft, struct session *s,
- struct winlink *wl)
+format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
{
+ struct session *s = wl->session;
struct window *w = wl->window;
- char *flags;
if (ft->w == NULL)
ft->w = wl->window;
- flags = window_printable_flags(s, wl);
-
format_defaults_window(ft, w);
format_add(ft, "window_index", "%d", wl->idx);
- format_add(ft, "window_flags", "%s", flags);
+ format_add(ft, "window_flags", "%s", window_printable_flags(wl));
format_add(ft, "window_active", "%d", wl == s->curw);
format_add(ft, "window_bell_flag", "%d",
@@ -1250,8 +1276,6 @@ format_defaults_winlink(struct format_tree *ft, struct session *s,
format_add(ft, "window_last_flag", "%d",
!!(wl == TAILQ_FIRST(&s->lastw)));
format_add(ft, "window_linked", "%d", session_is_linked(s, wl->window));
-
- free(flags);
}
/* Set default format keys for a window pane. */
diff --git a/job.c b/job.c
index bf3b261a..1ed74e2a 100644
--- a/job.c
+++ b/job.c
@@ -32,8 +32,9 @@
* output.
*/
-static void job_callback(struct bufferevent *, short, void *);
+static void job_read_callback(struct bufferevent *, void *);
static void job_write_callback(struct bufferevent *, void *);
+static void job_error_callback(struct bufferevent *, short, void *);
/* All jobs list. */
struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
@@ -41,7 +42,8 @@ struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
/* Start a job running, if it isn't already. */
struct job *
job_run(const char *cmd, struct session *s, const char *cwd,
- void (*callbackfn)(struct job *), void (*freefn)(void *), void *data)
+ job_update_cb updatecb, job_complete_cb completecb, job_free_cb freecb,
+ void *data)
{
struct job *job;
struct environ *env;
@@ -103,17 +105,18 @@ job_run(const char *cmd, struct session *s, const char *cwd,
job->pid = pid;
job->status = 0;
- LIST_INSERT_HEAD(&all_jobs, job, lentry);
+ LIST_INSERT_HEAD(&all_jobs, job, entry);
- job->callbackfn = callbackfn;
- job->freefn = freefn;
+ job->updatecb = updatecb;
+ job->completecb = completecb;
+ job->freecb = freecb;
job->data = data;
job->fd = out[0];
setblocking(job->fd, 0);
- job->event = bufferevent_new(job->fd, NULL, job_write_callback,
- job_callback, job);
+ job->event = bufferevent_new(job->fd, job_read_callback,
+ job_write_callback, job_error_callback, job);
bufferevent_enable(job->event, EV_READ|EV_WRITE);
log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
@@ -126,11 +129,11 @@ job_free(struct job *job)
{
log_debug("free job %p: %s", job, job->cmd);
- LIST_REMOVE(job, lentry);
+ LIST_REMOVE(job, entry);
free(job->cmd);
- if (job->freefn != NULL && job->data != NULL)
- job->freefn(job->data);
+ if (job->freecb != NULL && job->data != NULL)
+ job->freecb(job->data);
if (job->pid != -1)
kill(job->pid, SIGTERM);
@@ -142,7 +145,21 @@ job_free(struct job *job)
free(job);
}
-/* Called when output buffer falls below low watermark (default is 0). */
+/* Job buffer read callback. */
+static void
+job_read_callback(__unused struct bufferevent *bufev, void *data)
+{
+ struct job *job = data;
+
+ if (job->updatecb != NULL)
+ job->updatecb (job);
+}
+
+/*
+ * Job buffer write callback. Fired when the buffer falls below watermark
+ * (default is empty). If all the data has been written, disable the write
+ * event.
+ */
static void
job_write_callback(__unused struct bufferevent *bufev, void *data)
{
@@ -160,7 +177,7 @@ job_write_callback(__unused struct bufferevent *bufev, void *data)
/* Job buffer error callback. */
static void
-job_callback(__unused struct bufferevent *bufev, __unused short events,
+job_error_callback(__unused struct bufferevent *bufev, __unused short events,
void *data)
{
struct job *job = data;
@@ -168,8 +185,8 @@ job_callback(__unused struct bufferevent *bufev, __unused short events,
log_debug("job error %p: %s, pid %ld", job, job->cmd, (long) job->pid);
if (job->state == JOB_DEAD) {
- if (job->callbackfn != NULL)
- job->callbackfn(job);
+ if (job->completecb != NULL)
+ job->completecb(job);
job_free(job);
} else {
bufferevent_disable(job->event, EV_READ);
@@ -186,8 +203,8 @@ job_died(struct job *job, int status)
job->status = status;
if (job->state == JOB_CLOSED) {
- if (job->callbackfn != NULL)
- job->callbackfn(job);
+ if (job->completecb != NULL)
+ job->completecb(job);
job_free(job);
} else {
job->pid = -1;
diff --git a/server.c b/server.c
index 24e3ab61..0d8179fe 100644
--- a/server.c
+++ b/server.c
@@ -133,7 +133,8 @@ server_create_socket(void)
int
server_start(struct event_base *base, int lockfd, char *lockfile)
{
- int pair[2];
+ int pair[2];
+ struct job *job;
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
fatal("socketpair failed");
@@ -179,6 +180,12 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
server_add_accept(0);
proc_loop(server_proc, server_loop);
+
+ LIST_FOREACH(job, &all_jobs, entry) {
+ if (job->pid != -1)
+ kill(job->pid, SIGTERM);
+ }
+
status_prompt_save_history();
exit(0);
}
@@ -399,7 +406,7 @@ server_child_exited(pid_t pid, int status)
}
}
- LIST_FOREACH(job, &all_jobs, lentry) {
+ LIST_FOREACH(job, &all_jobs, entry) {
if (pid == job->pid) {
job_died(job, status); /* might free job */
break;
diff --git a/tmux.1 b/tmux.1
index 63ae6436..86281194 100644
--- a/tmux.1
+++ b/tmux.1
@@ -3494,6 +3494,8 @@ does not wait for
.Ql #()
commands to finish; instead, the previous result from running the same command is used,
or a placeholder if the command has not been run before.
+If the command hasn't exited, the most recent line of output will be used, but the status
+line will not be updated more than once a second.
Commands are executed with the
.Nm
global environment set (see the
diff --git a/tmux.h b/tmux.h
index b84ba3cf..4b3385c6 100644
--- a/tmux.h
+++ b/tmux.h
@@ -592,6 +592,10 @@ struct hook {
};
/* Scheduled job. */
+struct job;
+typedef void (*job_update_cb) (struct job *);
+typedef void (*job_complete_cb) (struct job *);
+typedef void (*job_free_cb) (void *);
struct job {
enum {
JOB_RUNNING,
@@ -599,18 +603,19 @@ struct job {
JOB_CLOSED
} state;
- char *cmd;
- pid_t pid;
- int status;
+ char *cmd;
+ pid_t pid;
+ int status;
- int fd;
- struct bufferevent *event;
+ int fd;
+ struct bufferevent *event;
- void (*callbackfn)(struct job *);
- void (*freefn)(void *);
- void *data;
+ job_update_cb updatecb;
+ job_complete_cb completecb;
+ job_free_cb freecb;
+ void *data;
- LIST_ENTRY(job) lentry;
+ LIST_ENTRY(job) entry;
};
LIST_HEAD(joblist, job);
@@ -1605,10 +1610,10 @@ extern const struct options_table_entry options_table[];
/* job.c */
extern struct joblist all_jobs;
-struct job *job_run(const char *, struct session *, const char *,
- void (*)(struct job *), void (*)(void *), void *);
-void job_free(struct job *);
-void job_died(struct job *, int);
+struct job *job_run(const char *, struct session *, const char *,
+ job_update_cb, job_complete_cb, job_free_cb, void *);
+void job_free(struct job *);
+void job_died(struct job *, int);
/* environ.c */
struct environ *environ_create(void);
@@ -2119,7 +2124,7 @@ int window_pane_outside(struct window_pane *);
int window_pane_visible(struct window_pane *);
char *window_pane_search(struct window_pane *, const char *,
u_int *);
-char *window_printable_flags(struct session *, struct winlink *);
+const char *window_printable_flags(struct winlink *);
struct window_pane *window_pane_find_up(struct window_pane *);
struct window_pane *window_pane_find_down(struct window_pane *);
struct window_pane *window_pane_find_left(struct window_pane *);
diff --git a/window-copy.c b/window-copy.c
index 9b13926e..0896479a 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -1641,7 +1641,7 @@ window_copy_copy_pipe(struct window_pane *wp, struct session *s,
return;
expanded = format_single(NULL, arg, NULL, s, NULL, wp);
- job = job_run(expanded, s, NULL, NULL, NULL, NULL);
+ job = job_run(expanded, s, NULL, NULL, NULL, NULL, NULL);
bufferevent_write(job->event, buf, len);
free(expanded);
diff --git a/window.c b/window.c
index e7a0aa52..dc2fddbb 100644
--- a/window.c
+++ b/window.c
@@ -709,12 +709,12 @@ window_destroy_panes(struct window *w)
}
}
-/* Retuns the printable flags on a window, empty string if no flags set. */
-char *
-window_printable_flags(struct session *s, struct winlink *wl)
+const char *
+window_printable_flags(struct winlink *wl)
{
- char flags[32];
- int pos;
+ struct session *s = wl->session;
+ static char flags[32];
+ int pos;
pos = 0;
if (wl->flags & WINLINK_ACTIVITY)
@@ -732,7 +732,7 @@ window_printable_flags(struct session *s, struct winlink *wl)
if (wl->window->flags & WINDOW_ZOOMED)
flags[pos++] = 'Z';
flags[pos] = '\0';
- return (xstrdup(flags));
+ return (flags);
}
struct window_pane *