summaryrefslogtreecommitdiffstats
path: root/job.c
diff options
context:
space:
mode:
authorTiago Cunha <tcunha@gmx.com>2011-02-15 15:20:03 +0000
committerTiago Cunha <tcunha@gmx.com>2011-02-15 15:20:03 +0000
commit3d7b8105e1385c835cf0660797fe70198097e73d (patch)
tree2e5cade8fbdbc0ce2ac112b1800224710f197af1 /job.c
parent3b56ebce6dd4077f6527843cfc1da63614605875 (diff)
Sync OpenBSD patchset 855:
Simplify the way jobs work and drop the persist type, so all jobs are fire-and-forget. Status jobs now managed with two trees of output (new and old), rather than storing the output in the jobs themselves. When the status line is processed any jobs which don't appear in the new tree are started and the output from the old tree displayed. When a job finishes it updates the new tree with its output and that is used for any subsequent redraws. When the status interval expires, the new tree is moved to the old so that all jobs are run again. This fixes the "#(echo %H:%M:%S)" problem which would lead to thousands of identical persistent jobs and high memory use (this can still be achieved by adding "sleep 30" but that is much less likely to happen by accident).
Diffstat (limited to 'job.c')
-rw-r--r--job.c207
1 files changed, 67 insertions, 140 deletions
diff --git a/job.c b/job.c
index 996bbdd4..3746f22c 100644
--- a/job.c
+++ b/job.c
@@ -1,4 +1,4 @@
-/* $Id: job.c,v 1.22 2011-02-15 15:12:28 tcunha Exp $ */
+/* $Id: job.c,v 1.23 2011-02-15 15:20:03 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -30,129 +30,32 @@
* output.
*/
-/* All jobs list. */
-struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
-
-RB_GENERATE(jobs, job, entry, job_cmp);
-
void job_callback(struct bufferevent *, short, void *);
-int
-job_cmp(struct job *job1, struct job *job2)
-{
- return (strcmp(job1->cmd, job2->cmd));
-}
-
-/* Initialise job tree. */
-void
-job_tree_init(struct jobs *jobs)
-{
- RB_INIT(jobs);
-}
-
-/* Destroy a job tree. */
-void
-job_tree_free(struct jobs *jobs)
-{
- struct job *job;
-
- while (!RB_EMPTY(jobs)) {
- job = RB_ROOT(jobs);
- RB_REMOVE(jobs, jobs, job);
- job_free(job);
- }
-}
-
-/* Find a job and return it. */
-struct job *
-job_get(struct jobs *jobs, const char *cmd)
-{
- struct job job;
-
- job.cmd = (char *) cmd;
- return (RB_FIND(jobs, jobs, &job));
-}
+/* All jobs list. */
+struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
-/* Add a job. */
+/* Start a job running, if it isn't already. */
struct job *
-job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd,
+job_run(const char *cmd,
void (*callbackfn)(struct job *), void (*freefn)(void *), void *data)
{
struct job *job;
-
- job = xmalloc(sizeof *job);
- job->cmd = xstrdup(cmd);
- job->pid = -1;
- job->status = 0;
-
- job->client = c;
-
- job->fd = -1;
- job->event = NULL;
-
- job->callbackfn = callbackfn;
- job->freefn = freefn;
- job->data = data;
-
- job->flags = flags;
-
- if (jobs != NULL)
- RB_INSERT(jobs, jobs, job);
- LIST_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)
-{
- job_kill(job);
-
- LIST_REMOVE(job, lentry);
- xfree(job->cmd);
-
- if (job->freefn != NULL && job->data != NULL)
- job->freefn(job->data);
-
- if (job->fd != -1)
- close(job->fd);
- if (job->event != NULL)
- bufferevent_free(job->event);
-
- xfree(job);
-}
-
-/* Start a job running, if it isn't already. */
-int
-job_run(struct job *job)
-{
- struct environ env;
- int nullfd, out[2];
-
- if (job->fd != -1 || job->pid != -1)
- return (0);
+ struct environ env;
+ pid_t pid;
+ int nullfd, out[2];
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0)
- return (-1);
+ return (NULL);
environ_init(&env);
environ_copy(&global_environ, &env);
server_fill_environ(NULL, &env);
- switch (job->pid = fork()) {
+ switch (pid = fork()) {
case -1:
environ_free(&env);
- return (-1);
+ return (NULL);
case 0: /* child */
clear_signals(1);
@@ -177,23 +80,55 @@ job_run(struct job *job)
closefrom(STDERR_FILENO + 1);
- execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL);
+ execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
fatal("execl failed");
- default: /* parent */
- environ_free(&env);
- close(out[1]);
+ }
- job->fd = out[0];
- setblocking(job->fd, 0);
+ /* parent */
+ environ_free(&env);
+ close(out[1]);
- if (job->event != NULL)
- bufferevent_free(job->event);
- job->event =
- bufferevent_new(job->fd, NULL, NULL, job_callback, job);
- bufferevent_enable(job->event, EV_READ);
+ job = xmalloc(sizeof *job);
+ job->cmd = xstrdup(cmd);
+ job->pid = pid;
+ job->status = 0;
- return (0);
- }
+ LIST_INSERT_HEAD(&all_jobs, job, lentry);
+
+ job->callbackfn = callbackfn;
+ job->freefn = freefn;
+ job->data = data;
+
+ job->fd = out[0];
+ setblocking(job->fd, 0);
+
+ job->event = bufferevent_new(job->fd, NULL, NULL, job_callback, job);
+ bufferevent_enable(job->event, EV_READ);
+
+ log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
+ return (job);
+}
+
+/* Kill and free an individual job. */
+void
+job_free(struct job *job)
+{
+ log_debug("free job %p: %s", job, job->cmd);
+
+ LIST_REMOVE(job, lentry);
+ xfree(job->cmd);
+
+ if (job->freefn != NULL && job->data != NULL)
+ job->freefn(job->data);
+
+ if (job->pid != -1)
+ kill(job->pid, SIGTERM);
+ if (job->fd != -1)
+ close(job->fd);
+ if (job->event != NULL)
+ bufferevent_free(job->event);
+
+ xfree(job);
}
/* Job buffer error callback. */
@@ -203,15 +138,16 @@ job_callback(unused struct bufferevent *bufev, unused short events, void *data)
{
struct job *job = data;
- bufferevent_disable(job->event, EV_READ);
- close(job->fd);
- job->fd = -1;
+ log_debug("job error %p: %s, pid %ld", job, job->cmd, (long) job->pid);
if (job->pid == -1) {
if (job->callbackfn != NULL)
job->callbackfn(job);
- if ((!job->flags & JOB_PERSIST))
- job_free(job);
+ job_free(job);
+ } else {
+ bufferevent_disable(job->event, EV_READ);
+ close(job->fd);
+ job->fd = -1;
}
}
@@ -219,23 +155,14 @@ job_callback(unused struct bufferevent *bufev, unused short events, void *data)
void
job_died(struct job *job, int status)
{
+ log_debug("job died %p: %s, pid %ld", job, job->cmd, (long) job->pid);
+
job->status = status;
- job->pid = -1;
if (job->fd == -1) {
if (job->callbackfn != NULL)
job->callbackfn(job);
- if ((!job->flags & JOB_PERSIST))
- job_free(job);
- }
-}
-
-/* Kill a job. */
-void
-job_kill(struct job *job)
-{
- if (job->pid == -1)
- return;
- kill(job->pid, SIGTERM);
- job->pid = -1;
+ job_free(job);
+ } else
+ job->pid = -1;
}