5 #include <sys/resource.h>
13 #include <ccan/lbalance/lbalance.h>
14 #include <ccan/tlist/tlist.h>
15 #include <ccan/grab_file/grab_file.h>
16 #include <ccan/time/time.h>
17 #include <ccan/talloc/talloc.h>
19 static struct lbalance *lb;
20 TLIST_TYPE(command, struct command);
21 static struct tlist_command pending = TLIST_INIT(pending);
22 static struct tlist_command running = TLIST_INIT(running);
23 static unsigned int num_running = 0;
24 static struct tlist_command done = TLIST_INIT(done);
27 struct list_node list;
32 struct lbalance_task *task;
39 static void killme(int sig)
41 kill(-getpid(), SIGKILL);
44 static void run_more(void)
48 while (num_running < lbalance_target(lb)) {
51 c = tlist_top(&pending, list);
57 err(1, "Pipe failed");
60 err(1, "Fork failed");
62 struct itimerval itim;
64 if (dup2(p[1], STDOUT_FILENO) != STDOUT_FILENO
65 || dup2(p[1], STDERR_FILENO) != STDERR_FILENO
67 || close(STDIN_FILENO) != 0
68 || open("/dev/null", O_RDONLY) != STDIN_FILENO)
71 signal(SIGALRM, killme);
72 itim.it_interval.tv_sec = itim.it_interval.tv_usec = 0;
73 itim.it_value = timespec_to_timeval(time_from_msec(c->time_ms));
74 setitimer(ITIMER_REAL, &itim, NULL);
76 c->status = system(c->command);
77 if (WIFEXITED(c->status))
78 exit(WEXITSTATUS(c->status));
79 /* Here's a hint... */
80 exit(128 + WTERMSIG(c->status));
84 printf("Running async: %s => %i\n", c->command, c->pid);
88 c->task = lbalance_task_new(lb);
89 tlist_del_from(&pending, c, list);
90 tlist_add_tail(&running, c, list);
95 static int destroy_command(struct command *command)
97 if (!command->done && command->pid) {
98 kill(-command->pid, SIGKILL);
99 close(command->output_fd);
103 tlist_del(command, list);
107 void run_command_async(const void *ctx, unsigned int time_ms,
108 const char *fmt, ...)
110 struct command *command;
118 command = talloc(ctx, struct command);
120 command->time_ms = time_ms;
122 command->output = talloc_strdup(command, "");
124 command->command = talloc_vasprintf(command, fmt, ap);
126 tlist_add_tail(&pending, command, list);
127 command->done = false;
128 talloc_set_destructor(command, destroy_command);
133 static void reap_output(void)
136 struct command *c, *next;
141 tlist_for_each(&running, c, list) {
142 FD_SET(c->output_fd, &in);
143 if (c->output_fd > max_fd)
144 max_fd = c->output_fd;
147 if (select(max_fd+1, &in, NULL, NULL, NULL) < 0)
148 err(1, "select failed");
150 tlist_for_each_safe(&running, c, next, list) {
151 if (FD_ISSET(c->output_fd, &in)) {
153 /* This length includes nul terminator! */
154 old_len = talloc_array_length(c->output);
155 c->output = talloc_realloc(c, c->output, char,
157 len = read(c->output_fd, c->output + old_len - 1, 1024);
159 err(1, "Reading from async command");
160 c->output = talloc_realloc(c, c->output, char,
162 c->output[old_len + len - 1] = '\0';
165 wait4(c->pid, &c->status, 0, &ru);
167 printf("Finished async %i: %s %u\n",
171 : "killed by signal",
173 ? WEXITSTATUS(c->status)
174 : WTERMSIG(c->status));
175 lbalance_task_free(c->task, &ru);
179 tlist_del_from(&running, c, list);
180 tlist_add_tail(&done, c, list);
187 void *collect_command(bool *ok, char **output)
192 while ((c = tlist_top(&done, list)) == NULL) {
193 if (tlist_empty(&pending) && tlist_empty(&running))
199 *ok = (WIFEXITED(c->status) && WEXITSTATUS(c->status) == 0);
201 *output = talloc_steal(ctx, c->output);
206 /* Compile and link single C file, with object files, async. */
207 void compile_and_link_async(const void *ctx, unsigned int time_ms,
208 const char *cfile, const char *ccandir,
209 const char *objs, const char *compiler,
211 const char *libs, const char *outfile)
214 printf("Compiling and linking (async) %s\n", outfile);
215 run_command_async(ctx, time_ms,
216 "%s %s -I%s -o %s %s %s %s",
218 ccandir, outfile, cfile, objs, libs);