Mercurial > sci
comparison sciworkerd.c @ 0:f1de39079243
misc: initial import
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 07 Jun 2021 09:41:37 +0200 |
parents | |
children | 5afdb14df924 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f1de39079243 |
---|---|
1 #include <sys/queue.h> | |
2 #include <sys/types.h> | |
3 #include <sys/wait.h> | |
4 #include <assert.h> | |
5 #include <err.h> | |
6 #include <errno.h> | |
7 #include <fcntl.h> | |
8 #include <poll.h> | |
9 #include <signal.h> | |
10 #include <stdio.h> | |
11 #include <stdlib.h> | |
12 #include <string.h> | |
13 #include <unistd.h> | |
14 | |
15 #include "project.h" | |
16 #include "config.h" | |
17 #include "log.h" | |
18 #include "util.h" | |
19 | |
20 struct job { | |
21 pid_t child; | |
22 int running; | |
23 int pipe[2]; | |
24 char project[PROJECT_NAME_MAX]; | |
25 char out[SCI_JOB_OUTPUT_MAX]; | |
26 TAILQ_ENTRY(job) link; | |
27 }; | |
28 | |
29 struct fds { | |
30 struct pollfd *list; | |
31 size_t listsz; | |
32 }; | |
33 | |
34 struct result { | |
35 pid_t pid; | |
36 int status; | |
37 }; | |
38 | |
39 TAILQ_HEAD(jobs, job); | |
40 | |
41 static struct jobs running = TAILQ_HEAD_INITIALIZER(running); | |
42 static struct jobs queue = TAILQ_HEAD_INITIALIZER(queue); | |
43 static int sigpipe[2]; | |
44 | |
45 static struct job * | |
46 find(const char *project) | |
47 { | |
48 struct job *j; | |
49 | |
50 TAILQ_FOREACH(j, &running, link) | |
51 if (strcmp(j->project, project) == 0) | |
52 return j; | |
53 | |
54 return NULL; | |
55 } | |
56 | |
57 static struct job * | |
58 find_by_fd(int fd) | |
59 { | |
60 struct job *j; | |
61 | |
62 TAILQ_FOREACH(j, &running, link) | |
63 if (j->pipe[0] == fd) | |
64 return j; | |
65 | |
66 return NULL; | |
67 } | |
68 | |
69 static struct job * | |
70 find_by_pid(pid_t pid) | |
71 { | |
72 struct job *j; | |
73 | |
74 TAILQ_FOREACH(j, &running, link) | |
75 if (j->child == pid) | |
76 return j; | |
77 | |
78 return NULL; | |
79 } | |
80 | |
81 static int | |
82 spawn(const char *project, const char *script) | |
83 { | |
84 struct job *j; | |
85 | |
86 if (find(project)) | |
87 return -1; | |
88 | |
89 j = util_calloc(1, sizeof (*j)); | |
90 j->pipe[0] = j->pipe[1] = -1; | |
91 j->running = 1; | |
92 strlcpy(j->project, project, sizeof (j->project)); | |
93 | |
94 if (pipe(j->pipe) < 0) | |
95 goto cleanup; | |
96 | |
97 switch ((j->child = fork())) { | |
98 case -1: | |
99 goto cleanup; | |
100 case 0: | |
101 /* Child. */ | |
102 dup2(j->pipe[1], STDOUT_FILENO); | |
103 dup2(j->pipe[1], STDERR_FILENO); | |
104 close(j->pipe[0]); | |
105 close(j->pipe[1]); | |
106 | |
107 if (execl(script, script, NULL) < 0) | |
108 exit(0); | |
109 break; | |
110 default: | |
111 /* Parent */ | |
112 TAILQ_INSERT_TAIL(&running, j, link); | |
113 break; | |
114 } | |
115 | |
116 return 0; | |
117 | |
118 cleanup: | |
119 if (j->pipe[0] != -1) | |
120 close(j->pipe[0]); | |
121 if (j->pipe[1] != -1) | |
122 close(j->pipe[1]); | |
123 | |
124 free(j); | |
125 | |
126 return -1; | |
127 } | |
128 | |
129 static void | |
130 complete(int signum, siginfo_t *sinfo, void *ctx) | |
131 { | |
132 (void)ctx; | |
133 (void)signum; | |
134 | |
135 struct result r; | |
136 | |
137 if (sinfo->si_code != CLD_EXITED) | |
138 return; | |
139 | |
140 r.pid = sinfo->si_pid; | |
141 r.status = 0; | |
142 | |
143 if (waitpid(sinfo->si_pid, &r.status, 0) < 0) { | |
144 log_warn("waitpid: %s", strerror(errno)); | |
145 return; | |
146 } | |
147 | |
148 /* | |
149 * Signal may happen at any time from any thread so we can't use | |
150 * mutexes so use the good old self-pipe trick. Yes, signals are | |
151 * probably the most fundamental broken UNIX feature. | |
152 */ | |
153 if (write(sigpipe[1], &r, sizeof (r)) < 0) | |
154 err(1, "write"); | |
155 } | |
156 | |
157 static void | |
158 init(void) | |
159 { | |
160 struct sigaction sa; | |
161 int flags; | |
162 | |
163 sa.sa_flags = SA_SIGINFO; | |
164 sa.sa_sigaction = complete; | |
165 sigemptyset(&sa.sa_mask); | |
166 | |
167 if (sigaction(SIGCHLD, &sa, NULL) < 0) | |
168 err(1, "sigaction"); | |
169 | |
170 log_open("sciworkerd"); | |
171 | |
172 if (pipe(sigpipe) < 0) | |
173 err(1, "pipe"); | |
174 if ((flags = fcntl(sigpipe[1], F_GETFL, 0)) < 0 || | |
175 fcntl(sigpipe[1], F_SETFL, flags | O_NONBLOCK) < 0) | |
176 err(1, "fcntl"); | |
177 } | |
178 | |
179 static struct fds | |
180 prepare(void) | |
181 { | |
182 struct fds fds = {0}; | |
183 struct job *j; | |
184 size_t i = 1; | |
185 | |
186 TAILQ_FOREACH(j, &running, link) | |
187 fds.listsz++; | |
188 | |
189 fds.list = util_calloc(++fds.listsz, sizeof (*fds.list)); | |
190 fds.list[0].fd = sigpipe[0]; | |
191 fds.list[0].events = POLLIN; | |
192 | |
193 TAILQ_FOREACH(j, &running, link) { | |
194 fds.list[i].fd = j->pipe[0]; | |
195 fds.list[i++].events = POLLIN | POLLPRI; | |
196 } | |
197 | |
198 return fds; | |
199 } | |
200 | |
201 static void | |
202 finished(pid_t pid) | |
203 { | |
204 struct job *job; | |
205 | |
206 if (!(job = find_by_pid(pid))) | |
207 return; | |
208 | |
209 /* TODO: send response. */ | |
210 | |
211 TAILQ_REMOVE(&running, job, link); | |
212 free(job); | |
213 } | |
214 | |
215 static void | |
216 run(void) | |
217 { | |
218 struct fds fds; | |
219 struct result r; | |
220 struct job *job; | |
221 char buf[BUFSIZ]; | |
222 ssize_t nr; | |
223 | |
224 fds = prepare(); | |
225 | |
226 if (poll(fds.list, fds.listsz, -1) < 0 && errno != EINTR) | |
227 err(1, "poll"); | |
228 | |
229 for (size_t i = 1; i < fds.listsz; ++i) { | |
230 if (fds.list[i].revents == 0) | |
231 continue; | |
232 if (!(job = find_by_fd(fds.list[i].fd))) | |
233 continue; | |
234 | |
235 if ((nr = read(fds.list[i].fd, buf, sizeof (buf) - 1)) <= 0) { | |
236 finished(job->child); | |
237 } else { | |
238 buf[nr] = 0; | |
239 strlcat(job->out, buf, sizeof (job->out)); | |
240 } | |
241 } | |
242 | |
243 if (fds.list->revents) { | |
244 r.pid = 0; | |
245 r.status = 0; | |
246 | |
247 if (read(sigpipe[0], &r, sizeof (r)) <= 0 && errno != EINTR) | |
248 err(1, "read"); | |
249 | |
250 finished(r.pid); | |
251 } | |
252 } | |
253 | |
254 int | |
255 main(int argc, char **argv) | |
256 { | |
257 (void)argc; | |
258 (void)argv; | |
259 | |
260 init(); | |
261 | |
262 for (;;) | |
263 run(); | |
264 } |