Add a flag for jobs that shouldn't be freed after they've died and use it for

status jobs, then only kill those jobs when status-left, status-right or
set-titles-string is changed.

Fixes problems with changing options from inside #().
pull/1/head
Nicholas Marriott 2009-11-01 23:20:37 +00:00
parent 32299e4010
commit 2f813ef75d
8 changed files with 63 additions and 19 deletions

View File

@ -65,7 +65,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
if (ctx->curclient != NULL)
ctx->curclient->references++;
job = job_add(NULL, NULL,
job = job_add(NULL, 0, NULL,
data->arg, cmd_if_shell_callback, cmd_if_shell_free, cdata);
job_run(job);
@ -80,10 +80,8 @@ cmd_if_shell_callback(struct job *job)
struct cmd_list *cmdlist;
char *cause;
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) {
job_free(job); /* calls cmd_if_shell_free */
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
return;
}
if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) {
if (cause != NULL) {

View File

@ -65,7 +65,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
if (ctx->curclient != NULL)
ctx->curclient->references++;
job = job_add(NULL, NULL,
job = job_add(NULL, 0, NULL,
data->arg, cmd_run_shell_callback, cmd_run_shell_free, cdata);
job_run(job);
@ -117,8 +117,6 @@ cmd_run_shell_callback(struct job *job)
ctx->info(ctx, "%s", msg);
xfree(msg);
}
job_free(job); /* calls cmd_run_shell_free */
}
void

View File

@ -56,6 +56,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
struct tty_code *code;
struct tty_term_code_entry *ent;
struct utsname un;
struct job *job;
struct grid *gd;
struct grid_line *gl;
u_int i, j, k;
@ -178,5 +179,11 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
}
ctx->print(ctx, "%s", "");
ctx->print(ctx, "Jobs:");
SLIST_FOREACH(job, &all_jobs, lentry) {
ctx->print(ctx, "%s [fd=%d, pid=%d, status=%d, flags=0x%x]",
job->cmd, job->fd, job->pid, job->status, job->flags);
}
return (0);
}

View File

@ -108,7 +108,10 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
struct client *c;
struct options *oo;
const struct set_option_entry *entry, *opt;
struct jobs *jobs;
struct job *job, *nextjob;
u_int i;
int try_again;
if (data->chflags & CMD_CHFLAG('g'))
oo = &global_s_options;
@ -184,11 +187,34 @@ cmd_set_option_exec(struct cmd *self, struct cmd_ctx *ctx)
}
recalculate_sizes();
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL && c->session != NULL) {
job_tree_free(&c->status_jobs);
job_tree_init(&c->status_jobs);
/*
* Special-case: kill all persistent jobs if status-left, status-right
* or set-titles-string have changed. Persistent jobs are only used by
* the status line at the moment so this works XXX.
*/
if (strcmp(entry->name, "status-left") == 0 ||
strcmp(entry->name, "status-right") == 0 ||
strcmp(entry->name, "set-titles-string") == 0) {
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c == NULL || c->session == NULL)
continue;
jobs = &c->status_jobs;
do {
try_again = 0;
job = RB_ROOT(jobs);
while (job != NULL) {
nextjob = RB_NEXT(jobs, jobs, job);
if (job->flags & JOB_PERSIST) {
job_remove(jobs, job);
try_again = 1;
break;
}
job = nextjob;
}
} while (try_again);
server_redraw_client(c);
}
}

16
job.c
View File

@ -73,7 +73,7 @@ job_get(struct jobs *jobs, const char *cmd)
/* Add a job. */
struct job *
job_add(struct jobs *jobs, struct client *c, const char *cmd,
job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd,
void (*callbackfn)(struct job *), void (*freefn)(void *), void *data)
{
struct job *job;
@ -81,6 +81,7 @@ job_add(struct jobs *jobs, struct client *c, const char *cmd,
job = xmalloc(sizeof *job);
job->cmd = xstrdup(cmd);
job->pid = -1;
job->status = 0;
job->client = c;
@ -91,15 +92,24 @@ job_add(struct jobs *jobs, struct client *c, const char *cmd,
job->freefn = freefn;
job->data = data;
job->flags = JOB_DONE;
job->flags = flags|JOB_DONE;
if (jobs != NULL)
RB_INSERT(jobs, jobs, job);
SLIST_INSERT_HEAD(&all_jobs, job, lentry);
return (job);
}
/* Remove job from tree and free. */
void
job_remove(struct jobs *jobs, struct job *job)
{
if (jobs != NULL)
RB_REMOVE(jobs, jobs, job);
job_free(job);
}
/* Kill and free an individual job. */
void
job_free(struct job *job)

View File

@ -64,7 +64,10 @@ restart:
if (job->callbackfn != NULL) {
job->callbackfn(job);
goto restart; /* could be freed by callback */
if ((!job->flags & JOB_PERSIST)) {
job_free(job);
goto restart;
}
}
}
}

View File

@ -476,8 +476,8 @@ status_job(struct client *c, char **iptr)
job = job_get(&c->status_jobs, cmd);
if (job == NULL) {
job = job_add(
&c->status_jobs, c, cmd, status_job_callback, xfree, NULL);
job = job_add(&c->status_jobs,
JOB_PERSIST, c, cmd, status_job_callback, xfree, NULL);
job_run(job);
}
if (job->data == NULL)

4
tmux.h
View File

@ -669,6 +669,7 @@ struct job {
int flags;
#define JOB_DONE 0x1
#define JOB_PERSIST 0x2 /* don't free after callback */
RB_ENTRY(job) entry;
SLIST_ENTRY(job) lentry;
@ -1301,8 +1302,9 @@ RB_PROTOTYPE(jobs, job, entry, job_cmp);
void job_tree_init(struct jobs *);
void job_tree_free(struct jobs *);
struct job *job_get(struct jobs *, const char *);
struct job *job_add(struct jobs *, struct client *,
struct job *job_add(struct jobs *, int, struct client *,
const char *, void (*)(struct job *), void (*)(void *), void *);
void job_remove(struct jobs *, struct job *);
void job_free(struct job *);
int job_run(struct job *);
void job_kill(struct job *);