GCC Code Coverage Report


Directory: src/
File: src/worker.c
Date: 2026-09-28 11:53:39
Exec Total Coverage
Lines: 106 151 70.2%
Functions: 9 9 100.0%
Branches: 27 62 43.5%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2022 Egor Tensin <egor@tensin.name>
3 * This file is part of the "cimple" project.
4 * For details, see https://github.com/egor-tensin/cimple
5 * Distributed under the MIT License.
6 */
7
8 #include "worker.h"
9
10 #include "ci.h"
11 #include "command.h"
12 #include "compiler.h"
13 #include "const.h"
14 #include "event_loop.h"
15 #include "git.h"
16 #include "log.h"
17 #include "net.h"
18 #include "process.h"
19 #include "protocol.h"
20 #include "run_queue.h"
21 #include "signal.h"
22
23 #include <poll.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 struct worker {
28 struct settings* settings;
29
30 int stopping;
31
32 struct cmd_dispatcher* cmd_dispatcher;
33
34 struct event_loop* event_loop;
35 int signalfd;
36
37 struct run* run;
38 };
39
40 54 static struct settings* worker_settings_copy(const struct settings* src) {
41 54 struct settings* result = malloc(sizeof(*src));
42
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (!result) {
43 ✗ log_errno("malloc");
44 ✗ return NULL;
45 }
46
47 54 result->host = strdup(src->host);
48
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (!result->host) {
49 ✗ log_errno("strdup");
50 ✗ goto free_result;
51 }
52
53 54 result->port = strdup(src->port);
54
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (!result->port) {
55 ✗ log_errno("strdup");
56 ✗ goto free_host;
57 }
58
59 54 return result;
60
61 ✗ free_host:
62 ✗ free((void*)result->host);
63
64 ✗ free_result:
65 ✗ free(result);
66
67 ✗ return NULL;
68 }
69
70 54 static void worker_settings_destroy(struct settings* settings) {
71 54 free((void*)settings->port);
72 54 free((void*)settings->host);
73 54 free(settings);
74 54 }
75
76 54 static int worker_set_stopping(
77 UNUSED struct event_loop* loop,
78 UNUSED int fd,
79 UNUSED short revents,
80 void* _worker
81 ) {
82 54 struct worker* worker = (struct worker*)_worker;
83 54 worker->stopping = 1;
84 54 return 0;
85 }
86
87 9180 static int worker_handle_cmd_start_run(
88 const struct jsonrpc_request* request,
89 UNUSED struct jsonrpc_response** response,
90 void* _ctx
91 ) {
92 9180 struct cmd_conn_ctx* ctx = (struct cmd_conn_ctx*)_ctx;
93 9180 struct worker* worker = (struct worker*)ctx->arg;
94 9180 int ret = 0;
95
96 9180 ret = request_parse_start_run(request, &worker->run);
97
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
9180 if (ret < 0)
98 ✗ return ret;
99
100 9180 return ret;
101 }
102
103 static struct cmd_desc commands[] = {
104 {CMD_START_RUN, worker_handle_cmd_start_run},
105 };
106
107 static const size_t numof_commands = sizeof(commands) / sizeof(commands[0]);
108
109 54 int worker_create(struct worker** _worker, const struct settings* settings) {
110 54 int ret = 0;
111
112 54 struct worker* worker = malloc(sizeof(struct worker));
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (!worker) {
114 ✗ log_errno("malloc");
115 ✗ return -1;
116 }
117
118 54 worker->settings = worker_settings_copy(settings);
119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (!worker->settings) {
120 ✗ ret = -1;
121 ✗ goto free;
122 }
123
124 54 worker->stopping = 0;
125
126 54 ret = cmd_dispatcher_create(&worker->cmd_dispatcher, commands, numof_commands, worker);
127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (ret < 0)
128 ✗ goto free_settings;
129
130 54 ret = event_loop_create(&worker->event_loop);
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (ret < 0)
132 ✗ goto destroy_cmd_dispatcher;
133
134 54 ret = signalfd_create_sigterms();
135
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (ret < 0)
136 ✗ goto destroy_event_loop;
137 54 worker->signalfd = ret;
138
139 54 ret = event_loop_add(worker->event_loop, worker->signalfd, POLLIN, worker_set_stopping, worker);
140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (ret < 0)
141 ✗ goto close_signalfd;
142
143 54 ret = libgit_init();
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (ret < 0)
145 ✗ goto close_signalfd;
146
147 54 *_worker = worker;
148 54 return ret;
149
150 ✗ close_signalfd:
151 ✗ signalfd_destroy(worker->signalfd);
152
153 ✗ destroy_event_loop:
154 ✗ event_loop_destroy(worker->event_loop);
155
156 ✗ destroy_cmd_dispatcher:
157 ✗ cmd_dispatcher_destroy(worker->cmd_dispatcher);
158
159 ✗ free_settings:
160 ✗ worker_settings_destroy(worker->settings);
161
162 ✗ free:
163 ✗ free(worker);
164
165 ✗ return ret;
166 }
167
168 54 void worker_destroy(struct worker* worker) {
169
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
54 log("Shutting down\n");
170
171 54 libgit_shutdown();
172 54 signalfd_destroy(worker->signalfd);
173 54 event_loop_destroy(worker->event_loop);
174 54 cmd_dispatcher_destroy(worker->cmd_dispatcher);
175 54 worker_settings_destroy(worker->settings);
176 54 free(worker);
177 54 }
178
179 9180 static int worker_do_run(struct worker* worker) {
180 9180 int ret = 0;
181
182 9180 struct process_output* result = NULL;
183 9180 ret = process_output_create(&result);
184
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
9180 if (ret < 0)
185 ✗ return ret;
186
187 9180 ret = ci_run_git_repo(run_get_repo_url(worker->run), run_get_repo_rev(worker->run), result);
188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
9180 if (ret < 0) {
189 ✗ log_err("Run failed with an error\n");
190 ✗ goto free_output;
191 }
192
193 9180 process_output_dump(result);
194
195 9180 struct jsonrpc_request* finished_request = NULL;
196
197 9180 ret = request_create_finished_run(&finished_request, run_get_id(worker->run), result);
198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
9180 if (ret < 0)
199 ✗ goto free_output;
200
201 9180 ret = net_connect(worker->settings->host, worker->settings->port);
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
9180 if (ret < 0)
203 ✗ goto free_request;
204 9180 int fd = ret;
205
206 9180 ret = jsonrpc_request_send(finished_request, fd);
207
1/2
✓ Branch 0 taken 9180 times.
✗ Branch 1 not taken.
9180 if (ret < 0)
208 ✗ goto close_conn;
209
210 9180 close_conn:
211 9180 net_close(fd);
212
213 9180 free_request:
214 9180 jsonrpc_request_destroy(finished_request);
215
216 9180 free_output:
217 9180 process_output_destroy(result);
218
219 9180 run_destroy(worker->run);
220
221 9180 return ret;
222 }
223
224 9234 static int worker_get_run(struct worker* worker) {
225 9234 int ret = 0, fd = -1;
226
227 9234 ret = net_connect(worker->settings->host, worker->settings->port);
228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9234 times.
9234 if (ret < 0)
229 ✗ return ret;
230 9234 fd = ret;
231
232 9234 struct jsonrpc_request* new_worker_request = NULL;
233 9234 ret = request_create_new_worker(&new_worker_request);
234
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9234 times.
9234 if (ret < 0)
235 ✗ goto close;
236
237 9234 ret = jsonrpc_request_send(new_worker_request, fd);
238 9234 jsonrpc_request_destroy(new_worker_request);
239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9234 times.
9234 if (ret < 0)
240 ✗ goto close;
241
242 9234 ret = event_loop_add_once(
243 9234 worker->event_loop, fd, POLLIN, cmd_dispatcher_handle_event, worker->cmd_dispatcher
244 );
245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9234 times.
9234 if (ret < 0)
246 ✗ goto close;
247
248
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9234 times.
9234 log("Waiting for a new command\n");
249
250 9234 ret = event_loop_run(worker->event_loop);
251
1/2
✓ Branch 0 taken 9234 times.
✗ Branch 1 not taken.
9234 if (ret < 0)
252 ✗ goto close;
253
254 9234 close:
255 9234 net_close(fd);
256
257 9234 return ret;
258 }
259
260 54 int worker_main(struct worker* worker) {
261 54 int ret = 0;
262
263 while (1) {
264 9234 ret = worker_get_run(worker);
265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9234 times.
9234 if (ret < 0)
266 ✗ return ret;
267
268
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 9180 times.
9234 if (worker->stopping)
269 54 break;
270
271 9180 ret = worker_do_run(worker);
272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
9180 if (ret < 0)
273 ✗ return ret;
274 }
275
276 54 return ret;
277 }
278