Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam 2017-04-20 12:01:14 +01:00
commit 48371216df
10 changed files with 119 additions and 64 deletions

View File

@ -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'))

View File

@ -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);

View File

@ -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;

View File

@ -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. */

49
job.c
View File

@ -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;

View File

@ -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;

2
tmux.1
View File

@ -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

33
tmux.h
View File

@ -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 *);

View File

@ -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);

View File

@ -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 *