From cdbb1115186dce5eb4a0622696d22d8beeca6140 Mon Sep 17 00:00:00 2001 From: egor-tensin Date: Thu, 15 Oct 2026 11:02:19 +0000 Subject: Deploying to gh-pages from @ egor-tensin/cimple@92c4b4cd3c0b6dbdba1cd4ca286d3defa3af2097 🚀 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ....base64.c.6cc41135837c80527c8f246c27adf87e.html | 556 +++ ...dex.buf.c.ed8381695b8bbc07634acc8fcf3aab27.html | 461 +++ ...ndex.ci.c.aafc6aa1373a4054fe8dceca1e5a2cd2.html | 874 ++++ ....client.c.7eeddcdb2bd1344daca0a340abd305ae.html | 1034 +++++ ...nt_main.c.0ff1a98449e6ae22cf540fe28921fa2d.html | 793 ++++ ...md_line.c.fc55483624faae9ff92546137d095857.html | 608 +++ ...command.c.d26991ef13eb41283f88bf34125ef986.html | 1877 +++++++++ coverage/index.css | 603 +++ ...nt_loop.c.037d09258818a0617a2d29f47e2b5064.html | 1950 +++++++++ ...ex.file.c.0cc24881e570d19e625204519d50254f.html | 1336 ++++++ coverage/index.functions.html | 377 ++ ...dex.git.c.ecafe65200a95f92fc10a3095d9e5f09.html | 966 +++++ coverage/index.html | 546 +++ ...ex.json.c.9fe0913c76249e448eec3131d7e8b263.html | 2300 +++++++++++ ...son_rpc.c.2aeccc6679171fb423f72eef95ec01c0.html | 4327 ++++++++++++++++++++ ...dex.log.c.47179e5db7ed3f2db741c99372ba24f3.html | 481 +++ ...dex.net.c.37012fce13860cefc5963f57e0f36732.html | 2089 ++++++++++ ...process.c.52f9324f34485af6c2c0f7cc7bbf5f8b.html | 1332 ++++++ ...rotocol.c.4964764a2e677a55c2f4207a995c3ce7.html | 1853 +++++++++ ...n_queue.c.fdfaa39d71447cf1e7d01ff206bd91e5.html | 1578 +++++++ ....server.c.0235f01a49d01b35e981a41f59a9d2d6.html | 4033 ++++++++++++++++++ ...er_main.c.3ca591a47eaf0cc37ef7579efe6031fe.html | 772 ++++ ....signal.c.71d63611c8a63e0778dd598afad76dfd.html | 716 ++++ ....sqlite.c.13cf77e7262c599539f10e3be0248b3e.html | 2357 +++++++++++ ...storage.c.96d197609feea4b630e7b775fb18af81.html | 1032 +++++ ..._sqlite.c.b44f7f73d467be85cd4227a40c11d12a.html | 4270 +++++++++++++++++++ ....string.c.2a75186e465ffeac1b306a350f4a56f8.html | 479 +++ ..._server.c.68fbb5aebb39dbc263f5110d228c9b35.html | 2304 +++++++++++ ....worker.c.4cbdfac39be7d0330fdfd94f65ce9ea9.html | 2236 ++++++++++ ...er_main.c.3e96ea0429977547c8b5eee564591fe0.html | 772 ++++ ...r_queue.c.aeb7258cd8f695c41a9aa8634701b38c.html | 647 +++ 31 files changed, 45559 insertions(+) create mode 100644 coverage/index.base64.c.6cc41135837c80527c8f246c27adf87e.html create mode 100644 coverage/index.buf.c.ed8381695b8bbc07634acc8fcf3aab27.html create mode 100644 coverage/index.ci.c.aafc6aa1373a4054fe8dceca1e5a2cd2.html create mode 100644 coverage/index.client.c.7eeddcdb2bd1344daca0a340abd305ae.html create mode 100644 coverage/index.client_main.c.0ff1a98449e6ae22cf540fe28921fa2d.html create mode 100644 coverage/index.cmd_line.c.fc55483624faae9ff92546137d095857.html create mode 100644 coverage/index.command.c.d26991ef13eb41283f88bf34125ef986.html create mode 100644 coverage/index.css create mode 100644 coverage/index.event_loop.c.037d09258818a0617a2d29f47e2b5064.html create mode 100644 coverage/index.file.c.0cc24881e570d19e625204519d50254f.html create mode 100644 coverage/index.functions.html create mode 100644 coverage/index.git.c.ecafe65200a95f92fc10a3095d9e5f09.html create mode 100644 coverage/index.html create mode 100644 coverage/index.json.c.9fe0913c76249e448eec3131d7e8b263.html create mode 100644 coverage/index.json_rpc.c.2aeccc6679171fb423f72eef95ec01c0.html create mode 100644 coverage/index.log.c.47179e5db7ed3f2db741c99372ba24f3.html create mode 100644 coverage/index.net.c.37012fce13860cefc5963f57e0f36732.html create mode 100644 coverage/index.process.c.52f9324f34485af6c2c0f7cc7bbf5f8b.html create mode 100644 coverage/index.protocol.c.4964764a2e677a55c2f4207a995c3ce7.html create mode 100644 coverage/index.run_queue.c.fdfaa39d71447cf1e7d01ff206bd91e5.html create mode 100644 coverage/index.server.c.0235f01a49d01b35e981a41f59a9d2d6.html create mode 100644 coverage/index.server_main.c.3ca591a47eaf0cc37ef7579efe6031fe.html create mode 100644 coverage/index.signal.c.71d63611c8a63e0778dd598afad76dfd.html create mode 100644 coverage/index.sqlite.c.13cf77e7262c599539f10e3be0248b3e.html create mode 100644 coverage/index.storage.c.96d197609feea4b630e7b775fb18af81.html create mode 100644 coverage/index.storage_sqlite.c.b44f7f73d467be85cd4227a40c11d12a.html create mode 100644 coverage/index.string.c.2a75186e465ffeac1b306a350f4a56f8.html create mode 100644 coverage/index.tcp_server.c.68fbb5aebb39dbc263f5110d228c9b35.html create mode 100644 coverage/index.worker.c.4cbdfac39be7d0330fdfd94f65ce9ea9.html create mode 100644 coverage/index.worker_main.c.3e96ea0429977547c8b5eee564591fe0.html create mode 100644 coverage/index.worker_queue.c.aeb7258cd8f695c41a9aa8634701b38c.html (limited to 'coverage') diff --git a/coverage/index.base64.c.6cc41135837c80527c8f246c27adf87e.html b/coverage/index.base64.c.6cc41135837c80527c8f246c27adf87e.html new file mode 100644 index 0000000..7c8753f --- /dev/null +++ b/coverage/index.base64.c.6cc41135837c80527c8f246c27adf87e.html @@ -0,0 +1,556 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/base64.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:182766.7%
Functions:22100.0%
Branches:31225.0%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
1 + /*
2 + * Copyright (c) 2023 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 "base64.h"
9 +
10 + #include "log.h"
11 +
12 + #include <sodium.h>
13 +
14 + #include <stddef.h>
15 + #include <stdlib.h>
16 + #include <string.h>
17 +
18 + static const int base64_variant = sodium_base64_VARIANT_ORIGINAL;
19 +
20 + 9180int base64_encode(const unsigned char* src, size_t src_len, char** _dst) {
21 + 9180 const size_t dst_len = sodium_base64_encoded_len(src_len, base64_variant);
22 +
23 + 9180 char* dst = calloc(dst_len, 1);
24 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (!dst) {
25 + ✗ log_errno("calloc");
26 + ✗ return -1;
27 + }
28 +
29 + 9180 sodium_bin2base64(dst, dst_len, src, src_len, base64_variant);
30 +
31 + 9180 *_dst = dst;
32 + 9180 return 0;
33 + }
34 +
35 + 9180int base64_decode(const char* src, unsigned char** _dst, size_t* _dst_len) {
36 + 9180 const size_t src_len = strlen(src);
37 + 9180 const size_t dst_max_len = src_len / 4 * 3;
38 + 9180 size_t dst_len = 0;
39 +
40 + 9180 unsigned char* dst = calloc(dst_max_len, 1);
41 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (!dst) {
42 + ✗ log_errno("calloc");
43 + ✗ return -1;
44 + }
45 +
46 + int ret =
47 + 9180 sodium_base642bin(dst, dst_max_len, src, src_len, NULL, &dst_len, NULL, base64_variant);
48 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0) {
49 + ✗ log_err("Couldn't parse base64-encoded string\n");
50 + ✗ goto free;
51 + }
52 +
53 + 9180 *_dst = dst;
54 + 9180 *_dst_len = dst_len;
55 + 9180 return ret;
56 +
57 + ✗free:
58 + ✗ free(dst);
59 +
60 + ✗ return ret;
61 + }
62 +
+
+
+
+ + + + diff --git a/coverage/index.buf.c.ed8381695b8bbc07634acc8fcf3aab27.html b/coverage/index.buf.c.ed8381695b8bbc07634acc8fcf3aab27.html new file mode 100644 index 0000000..d8c8e56 --- /dev/null +++ b/coverage/index.buf.c.ed8381695b8bbc07634acc8fcf3aab27.html @@ -0,0 +1,461 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/buf.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:161888.9%
Functions:55100.0%
Branches:1425.0%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
1 + /*
2 + * Copyright (c) 2023 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 "buf.h"
9 +
10 + #include "log.h"
11 +
12 + #include <stdint.h>
13 + #include <stdlib.h>
14 + #include <string.h>
15 +
16 + struct buf {
17 + uint32_t size;
18 + const void* data;
19 + };
20 +
21 + 92012int buf_create(struct buf** _buf, const void* data, uint32_t size) {
22 + 92012 struct buf* buf = malloc(sizeof(struct buf));
23 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 92012 times.
+
+
+
92012 if (!buf) {
24 + ✗ log_errno("malloc");
25 + ✗ return -1;
26 + }
27 +
28 + 92012 buf->data = data;
29 + 92012 buf->size = size;
30 +
31 + 92012 *_buf = buf;
32 + 92012 return 0;
33 + }
34 +
35 + 46006int buf_create_from_string(struct buf** buf, const char* str) {
36 + 46006 return buf_create(buf, str, strlen(str) + 1);
37 + }
38 +
39 + 92012void buf_destroy(struct buf* buf) {
40 + 92012 free(buf);
41 + 92012}
42 +
43 + 92012uint32_t buf_get_size(const struct buf* buf) {
44 + 92012 return buf->size;
45 + }
46 +
47 + 138018const void* buf_get_data(const struct buf* buf) {
48 + 138018 return buf->data;
49 + }
50 +
+
+
+
+ + + + diff --git a/coverage/index.ci.c.aafc6aa1373a4054fe8dceca1e5a2cd2.html b/coverage/index.ci.c.aafc6aa1373a4054fe8dceca1e5a2cd2.html new file mode 100644 index 0000000..e93596a --- /dev/null +++ b/coverage/index.ci.c.aafc6aa1373a4054fe8dceca1e5a2cd2.html @@ -0,0 +1,874 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/ci.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:374778.7%
Functions:55100.0%
Branches:91850.0%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "ci.h"
9 +
10 + #include "file.h"
11 + #include "git.h"
12 + #include "log.h"
13 + #include "process.h"
14 +
15 + #include <git2.h>
16 +
17 + #include <stddef.h>
18 + #include <stdlib.h>
19 +
20 + static const char* ci_scripts[] = {
21 + "./.ci.sh",
22 + "./.ci",
23 + "./ci.sh",
24 + "./ci",
25 + NULL,
26 + };
27 +
28 + static const char* ci_env[] = {
29 + "CI=y",
30 + "CIMPLE=y",
31 + NULL,
32 + };
33 +
34 + 9180static int ci_run_script(const char* script, struct process_output* result) {
35 + 9180 const char* args[] = {script, NULL};
36 + 9180 return process_execute_and_capture(args, ci_env, result);
37 + }
38 +
39 + 9180int ci_run(struct process_output* result) {
40 +
+ 1/2 +
+
✓ Branch 0 taken 36720 times.
+
✗ Branch 1 not taken.
+
+
+
36720 for (const char** script = ci_scripts; *script; ++script) {
41 +
+ 2/2 +
+
✓ Branch 1 taken 27540 times.
+
✓ Branch 2 taken 9180 times.
+
+
+
36720 if (!file_exists(*script))
42 + 27540 continue;
43 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 log("Going to run: %s\n", *script);
44 + 9180 return ci_run_script(*script, result);
45 + }
46 +
47 + ✗ log("Couldn't find any CI scripts to run\n");
48 + ✗ return -1;
49 + }
50 +
51 + 9180static void ci_cleanup_git_repo(git_repository* repo) {
52 + 9180 rm_rf(git_repository_workdir(repo));
53 + 9180 libgit_repository_free(repo);
54 + 9180}
55 +
56 + 9180static int ci_prepare_git_repo(git_repository** repo, const char* url, const char* rev) {
57 + 9180 int ret = 0;
58 +
59 + 9180 ret = libgit_clone_to_tmp(repo, url);
60 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
61 + ✗ return ret;
62 +
63 + 9180 ret = libgit_checkout(*repo, rev);
64 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
65 + ✗ goto cleanup_repo;
66 +
67 + 9180 return ret;
68 +
69 + ✗cleanup_repo:
70 + ✗ ci_cleanup_git_repo(*repo);
71 +
72 + ✗ return ret;
73 + }
74 +
75 + 9180int ci_run_git_repo(const char* url, const char* rev, struct process_output* output) {
76 + 9180 char* oldpwd = NULL;
77 + 9180 git_repository* repo = NULL;
78 + 9180 int ret = 0;
79 +
80 + 9180 ret = ci_prepare_git_repo(&repo, url, rev);
81 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
82 + ✗ goto exit;
83 +
84 + 9180 ret = chdir_wrapper(git_repository_workdir(repo), &oldpwd);
85 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
86 + ✗ goto free_repo;
87 +
88 + 9180 ret = ci_run(output);
89 +
+ 1/2 +
+
✓ Branch 0 taken 9180 times.
+
✗ Branch 1 not taken.
+
+
+
9180 if (ret < 0)
90 + ✗ goto oldpwd;
91 +
92 + 9180oldpwd:
93 + 9180 chdir_wrapper(oldpwd, NULL);
94 + 9180 free(oldpwd);
95 +
96 + 9180free_repo:
97 + 9180 ci_cleanup_git_repo(repo);
98 +
99 + 9180exit:
100 + 9180 return ret;
101 + }
102 +
+
+
+
+ + + + diff --git a/coverage/index.client.c.7eeddcdb2bd1344daca0a340abd305ae.html b/coverage/index.client.c.7eeddcdb2bd1344daca0a340abd305ae.html new file mode 100644 index 0000000..3cdd697 --- /dev/null +++ b/coverage/index.client.c.7eeddcdb2bd1344daca0a340abd305ae.html @@ -0,0 +1,1034 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/client.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:506280.6%
Functions:44100.0%
Branches:173056.7%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "client.h"
9 +
10 + #include "cmd_line.h"
11 + #include "compiler.h"
12 + #include "const.h"
13 + #include "json_rpc.h"
14 + #include "log.h"
15 + #include "net.h"
16 + #include "protocol.h"
17 + #include "run_queue.h"
18 +
19 + #include <stdlib.h>
20 + #include <string.h>
21 +
22 + struct client {
23 + int dummy;
24 + };
25 +
26 + 9208int client_create(struct client** _client) {
27 + 9208 int ret = 0;
28 +
29 + 9208 struct client* client = malloc(sizeof(struct client));
30 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9208 times.
+
+
+
9208 if (!client) {
31 + ✗ log_errno("malloc");
32 + ✗ return -1;
33 + }
34 +
35 + 9208 *_client = client;
36 + 9208 return ret;
37 + }
38 +
39 + 9206void client_destroy(struct client* client) {
40 + 9206 free(client);
41 + 9206}
42 +
43 + 9208static int make_request(struct jsonrpc_request** request, int argc, const char** argv) {
44 +
+ 2/2 +
+
✓ Branch 0 taken 1 times.
+
✓ Branch 1 taken 9207 times.
+
+
+
9208 if (argc < 1) {
45 + 1 exit_with_usage_err("no action specified");
46 + ✗ return -1;
47 + }
48 +
49 +
+ 2/2 +
+
✓ Branch 0 taken 9180 times.
+
✓ Branch 1 taken 27 times.
+
+
+
9207 if (!strcmp(argv[0], CMD_QUEUE_RUN)) {
50 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (argc != 3)
51 + ✗ return -1;
52 +
53 + 9180 struct run* run = NULL;
54 + 9180 int ret = run_queued(&run, argv[1], argv[2]);
55 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
56 + ✗ return ret;
57 +
58 + 9180 ret = request_create_queue_run(request, run);
59 + 9180 run_destroy(run);
60 + 9180 return ret;
61 +
+ 2/2 +
+
✓ Branch 0 taken 26 times.
+
✓ Branch 1 taken 1 times.
+
+
+
27 } else if (!strcmp(argv[0], CMD_GET_RUNS)) {
62 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 26 times.
+
+
+
26 if (argc != 1)
63 + ✗ return -1;
64 + 26 return request_create_get_runs(request);
65 + }
66 +
67 + 1 return -1;
68 + }
69 +
70 + 9208int client_main(
71 + UNUSED const struct client* client,
72 + const struct settings* settings,
73 + int argc,
74 + const char** argv
75 + ) {
76 + 9208 int ret = 0;
77 +
78 + 9208 struct jsonrpc_request* request = NULL;
79 + 9208 ret = make_request(&request, argc, argv);
80 +
+ 2/2 +
+
✓ Branch 0 taken 1 times.
+
✓ Branch 1 taken 9206 times.
+
+
+
9207 if (ret < 0) {
81 + 1 exit_with_usage_err("invalid request");
82 + ✗ return ret;
83 + }
84 +
85 + 9206 ret = net_connect(settings->host, settings->port);
86 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
87 + ✗ goto free_request;
88 + 9206 int fd = ret;
89 +
90 + 9206 ret = jsonrpc_request_send(request, fd);
91 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
92 + ✗ goto close;
93 +
94 + 9206 struct jsonrpc_response* response = NULL;
95 + 9206 ret = jsonrpc_response_recv(&response, fd);
96 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
97 + ✗ goto close;
98 +
99 + 9206 const char* response_str = jsonrpc_response_to_string(response);
100 +
+ 1/2 +
+
✓ Branch 0 taken 9206 times.
+
✗ Branch 1 not taken.
+
+
+
9206 if (response_str) {
101 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9206 times.
+
+
+
9206 if (jsonrpc_response_is_error(response))
102 + ✗ ret = -1;
103 + 9206 printf("%s", response_str);
104 + } else {
105 + ✗ log_err("no response\n");
106 + }
107 + 9206 goto free_response;
108 +
109 + 9206free_response:
110 + 9206 jsonrpc_response_destroy(response);
111 +
112 + 9206close:
113 + 9206 net_close(fd);
114 +
115 + 9206free_request:
116 + 9206 jsonrpc_request_destroy(request);
117 +
118 + 9206 return ret;
119 + }
120 +
+
+
+
+ + + + diff --git a/coverage/index.client_main.c.0ff1a98449e6ae22cf540fe28921fa2d.html b/coverage/index.client_main.c.0ff1a98449e6ae22cf540fe28921fa2d.html new file mode 100644 index 0000000..2ff855a --- /dev/null +++ b/coverage/index.client_main.c.0ff1a98449e6ae22cf540fe28921fa2d.html @@ -0,0 +1,793 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/client_main.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:344379.1%
Functions:44100.0%
Branches:101471.4%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "client.h"
9 + #include "cmd_line.h"
10 + #include "const.h"
11 + #include "log.h"
12 +
13 + #include <getopt.h>
14 + #include <unistd.h>
15 +
16 + 9214static struct settings default_settings(void) {
17 + 9214 struct settings settings = {
18 + .host = default_host,
19 + .port = default_port,
20 + };
21 + 9214 return settings;
22 + }
23 +
24 + 6const char* get_usage_string(void) {
25 + 6 return "[-h|--help] [-V|--version] [-v|--verbose] [-H|--host HOST] [-p|--port PORT] ACTION [ARG...]\n\
26 + \n\
27 + available actions:\n\
28 + \t" CMD_QUEUE_RUN " URL REV - schedule a CI run of repository at URL, revision REV";
29 + }
30 +
31 + 9214static int parse_settings(struct settings* settings, int argc, char* argv[]) {
32 + int opt, longind;
33 +
34 + 9214 *settings = default_settings();
35 +
36 + static struct option long_options[] = {
37 + {"help", no_argument, 0, 'h'},
38 + {"version", no_argument, 0, 'V'},
39 + {"verbose", no_argument, 0, 'v'},
40 + {"host", required_argument, 0, 'H'},
41 + {"port", required_argument, 0, 'p'},
42 + {0, 0, 0, 0},
43 + };
44 +
45 +
+ 2/2 +
+
✓ Branch 1 taken 18422 times.
+
✓ Branch 2 taken 9208 times.
+
+
+
27630 while ((opt = getopt_long(argc, argv, "hVvH:p:", long_options, &longind)) != -1) {
46 +
+ 5/6 +
+
✓ Branch 0 taken 2 times.
+
✓ Branch 1 taken 2 times.
+
✗ Branch 2 not taken.
+
✓ Branch 3 taken 9208 times.
+
✓ Branch 4 taken 9208 times.
+
✓ Branch 5 taken 2 times.
+
+
+
18422 switch (opt) {
47 + 2 case 'h':
48 + 2 exit_with_usage(0);
49 + ✗ break;
50 + 2 case 'V':
51 + 2 exit_with_version();
52 + ✗ break;
53 + ✗ case 'v':
54 + ✗ g_log_lvl = LOG_LVL_DEBUG;
55 + ✗ break;
56 + 9208 case 'H':
57 + 9208 settings->host = optarg;
58 + 9208 break;
59 + 9208 case 'p':
60 + 9208 settings->port = optarg;
61 + 9208 break;
62 + 2 default:
63 + 2 exit_with_usage(1);
64 + ✗ break;
65 + }
66 + }
67 +
68 + 9208 return 0;
69 + }
70 +
71 + 9214int main(int argc, char* argv[]) {
72 + struct settings settings;
73 + 9214 struct client* client = NULL;
74 + 9214 int ret = 0;
75 +
76 + 9214 ret = parse_settings(&settings, argc, argv);
77 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9208 times.
+
+
+
9208 if (ret < 0)
78 + ✗ return ret;
79 +
80 + 9208 ret = client_create(&client);
81 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9208 times.
+
+
+
9208 if (ret < 0)
82 + ✗ return ret;
83 +
84 + 9208 ret = client_main(client, &settings, argc - optind, (const char**)argv + optind);
85 +
+ 1/2 +
+
✓ Branch 0 taken 9206 times.
+
✗ Branch 1 not taken.
+
+
+
9206 if (ret < 0)
86 + ✗ goto destroy_client;
87 +
88 + 9206destroy_client:
89 + 9206 client_destroy(client);
90 +
91 + 9206 return ret;
92 + }
93 +
+
+
+
+ + + + diff --git a/coverage/index.cmd_line.c.fc55483624faae9ff92546137d095857.html b/coverage/index.cmd_line.c.fc55483624faae9ff92546137d095857.html new file mode 100644 index 0000000..2f792f0 --- /dev/null +++ b/coverage/index.cmd_line.c.fc55483624faae9ff92546137d095857.html @@ -0,0 +1,608 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/cmd_line.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:283287.5%
Functions:55100.0%
Branches:71450.0%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
1 + /*
2 + * Copyright (c) 2023 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 "cmd_line.h"
9 +
10 + #include "const.h"
11 + #include "file.h"
12 + #include "log.h"
13 +
14 + #include <stdio.h>
15 + #include <stdlib.h>
16 + #include <string.h>
17 +
18 + 20static char* get_current_binary_path(void) {
19 + 20 return readlink_wrapper("/proc/self/exe");
20 + }
21 +
22 + 20static char* get_current_binary_name(void) {
23 + 20 char* path = get_current_binary_path();
24 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 20 times.
+
+
+
20 if (!path)
25 + ✗ return NULL;
26 +
27 + 20 char* name = basename(path);
28 +
29 + 20 char* result = strdup(name);
30 +
+ 1/2 +
+
✓ Branch 0 taken 20 times.
+
✗ Branch 1 not taken.
+
+
+
20 if (!result) {
31 + ✗ log_errno("strdup");
32 + ✗ goto free_path;
33 + }
34 +
35 + 20free_path:
36 + 20 free(path);
37 +
38 + 20 return result;
39 + }
40 +
41 + 14void exit_with_usage(int ec) {
42 + 14 FILE* dest = stdout;
43 +
+ 2/2 +
+
✓ Branch 0 taken 8 times.
+
✓ Branch 1 taken 6 times.
+
+
+
14 if (ec)
44 + 8 dest = stderr;
45 +
46 + 14 char* binary = get_current_binary_name();
47 +
48 +
+ 1/2 +
+
✓ Branch 1 taken 14 times.
+
✗ Branch 2 not taken.
+
+
+
14 fprintf(dest, "usage: %s %s\n", binary ? binary : "prog", get_usage_string());
49 + 14 free(binary);
50 + 14 exit(ec);
51 + }
52 +
53 + 2void exit_with_usage_err(const char* msg) {
54 +
+ 1/2 +
+
✓ Branch 0 taken 2 times.
+
✗ Branch 1 not taken.
+
+
+
2 if (msg)
55 + 2 fprintf(stderr, "usage error: %s\n", msg);
56 + 2 exit_with_usage(1);
57 + ✗}
58 +
59 + 6void exit_with_version(void) {
60 + 6 char* binary = get_current_binary_name();
61 +
62 +
+ 1/2 +
+
✓ Branch 0 taken 6 times.
+
✗ Branch 1 not taken.
+
+
+
6 printf("%s v%s (%s)\n", binary ? binary : "prog", project_version, project_rev);
63 + 6 free(binary);
64 + 6 exit(0);
65 + }
66 +
+
+
+
+ + + + diff --git a/coverage/index.command.c.d26991ef13eb41283f88bf34125ef986.html b/coverage/index.command.c.d26991ef13eb41283f88bf34125ef986.html new file mode 100644 index 0000000..3d7214f --- /dev/null +++ b/coverage/index.command.c.d26991ef13eb41283f88bf34125ef986.html @@ -0,0 +1,1877 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/command.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:8912074.2%
Functions:111291.7%
Branches:336650.0%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
1 + /*
2 + * Copyright (c) 2023 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 "command.h"
9 +
10 + #include "compiler.h"
11 + #include "event_loop.h"
12 + #include "json_rpc.h"
13 + #include "log.h"
14 +
15 + #include <poll.h>
16 + #include <stdlib.h>
17 + #include <string.h>
18 +
19 + struct cmd_dispatcher {
20 + struct cmd_desc* cmds;
21 + size_t numof_cmds;
22 + void* ctx;
23 + };
24 +
25 + 170static int copy_cmd(struct cmd_desc* dest, const struct cmd_desc* src) {
26 + 170 dest->name = strdup(src->name);
27 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 170 times.
+
+
+
170 if (!dest->name) {
28 + ✗ log_errno("strdup");
29 + ✗ return -1;
30 + }
31 + 170 dest->handler = src->handler;
32 + 170 return 0;
33 + }
34 +
35 + 170static void free_cmd(struct cmd_desc* desc) {
36 + 170 free(desc->name);
37 + 170}
38 +
39 + 83static int copy_cmds(struct cmd_desc* dest, const struct cmd_desc* src, size_t numof_cmds) {
40 + 83 size_t numof_copied = 0;
41 + 83 int ret = 0;
42 +
43 +
+ 2/2 +
+
✓ Branch 0 taken 170 times.
+
✓ Branch 1 taken 83 times.
+
+
+
253 for (numof_copied = 0; numof_copied < numof_cmds; ++numof_copied) {
44 + 170 ret = copy_cmd(&dest[numof_copied], &src[numof_copied]);
45 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 170 times.
+
+
+
170 if (ret < 0)
46 + ✗ goto free;
47 + }
48 +
49 + 83 return 0;
50 +
51 + ✗free:
52 + ✗ for (size_t i = 0; i < numof_copied; ++i)
53 + ✗ free_cmd(&dest[numof_copied]);
54 +
55 + ✗ return -1;
56 + }
57 +
58 + 83static void free_cmds(struct cmd_desc* cmds, size_t numof_cmds) {
59 +
+ 2/2 +
+
✓ Branch 0 taken 170 times.
+
✓ Branch 1 taken 83 times.
+
+
+
253 for (size_t i = 0; i < numof_cmds; ++i)
60 + 170 free_cmd(&cmds[i]);
61 + 83}
62 +
63 + 83int cmd_dispatcher_create(
64 + struct cmd_dispatcher** _dispatcher,
65 + struct cmd_desc* cmds,
66 + size_t numof_cmds,
67 + void* ctx
68 + ) {
69 + 83 int ret = 0;
70 +
71 + 83 struct cmd_dispatcher* dispatcher = malloc(sizeof(struct cmd_dispatcher));
72 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 83 times.
+
+
+
83 if (!dispatcher) {
73 + ✗ log_errno("malloc");
74 + ✗ return -1;
75 + }
76 +
77 + 83 dispatcher->ctx = ctx;
78 +
79 + 83 dispatcher->cmds = malloc(sizeof(struct cmd_desc) * numof_cmds);
80 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 83 times.
+
+
+
83 if (!dispatcher->cmds) {
81 + ✗ log_errno("malloc");
82 + ✗ goto free;
83 + }
84 + 83 dispatcher->numof_cmds = numof_cmds;
85 +
86 + 83 ret = copy_cmds(dispatcher->cmds, cmds, numof_cmds);
87 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 83 times.
+
+
+
83 if (ret < 0)
88 + ✗ goto free_cmds;
89 +
90 + 83 *_dispatcher = dispatcher;
91 + 83 return 0;
92 +
93 + ✗free_cmds:
94 + ✗ free(dispatcher->cmds);
95 +
96 + ✗free:
97 + ✗ free(dispatcher);
98 +
99 + ✗ return -1;
100 + }
101 +
102 + 83void cmd_dispatcher_destroy(struct cmd_dispatcher* dispatcher) {
103 + 83 free_cmds(dispatcher->cmds, dispatcher->numof_cmds);
104 + 83 free(dispatcher->cmds);
105 + 83 free(dispatcher);
106 + 83}
107 +
108 + 36800static int cmd_dispatcher_handle_internal(
109 + const struct cmd_dispatcher* dispatcher,
110 + const struct jsonrpc_request* request,
111 + struct jsonrpc_response** result,
112 + void* arg
113 + ) {
114 + 36800 const char* actual_cmd = jsonrpc_request_get_method(request);
115 +
116 +
+ 1/2 +
+
✓ Branch 0 taken 64418 times.
+
✗ Branch 1 not taken.
+
+
+
64418 for (size_t i = 0; i < dispatcher->numof_cmds; ++i) {
117 + 64418 struct cmd_desc* cmd = &dispatcher->cmds[i];
118 +
119 +
+ 2/2 +
+
✓ Branch 0 taken 27618 times.
+
✓ Branch 1 taken 36800 times.
+
+
+
64418 if (strcmp(cmd->name, actual_cmd))
120 + 27618 continue;
121 +
122 + 36800 return cmd->handler(request, result, arg);
123 + }
124 +
125 + ✗ log_err("Received an unknown command: %s\n", actual_cmd);
126 + ✗ return -1;
127 + }
128 +
129 + ✗int cmd_dispatcher_handle(
130 + const struct cmd_dispatcher* dispatcher,
131 + const struct jsonrpc_request* command,
132 + struct jsonrpc_response** result
133 + ) {
134 + ✗ return cmd_dispatcher_handle_internal(dispatcher, command, result, dispatcher->ctx);
135 + }
136 +
137 + 36800static struct cmd_conn_ctx* make_conn_ctx(int fd, void* arg) {
138 + 36800 struct cmd_conn_ctx* ctx = malloc(sizeof(struct cmd_conn_ctx));
139 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (!ctx) {
140 + ✗ log_errno("malloc");
141 + ✗ return NULL;
142 + }
143 +
144 + 36800 ctx->fd = fd;
145 + 36800 ctx->arg = arg;
146 +
147 + 36800 return ctx;
148 + }
149 +
150 + 36800static int cmd_dispatcher_handle_conn_internal(int conn_fd, struct cmd_dispatcher* dispatcher) {
151 + 36800 int ret = 0;
152 +
153 + 36800 struct cmd_conn_ctx* new_ctx = make_conn_ctx(conn_fd, dispatcher->ctx);
154 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (!new_ctx)
155 + ✗ return -1;
156 +
157 + 36800 struct jsonrpc_request* request = NULL;
158 + 36800 ret = jsonrpc_request_recv(&request, conn_fd);
159 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (ret < 0)
160 + ✗ goto free_ctx;
161 +
162 + 36800 const int requires_response = !jsonrpc_request_is_notification(request);
163 +
164 + 36800 struct jsonrpc_response* default_response = NULL;
165 +
+ 2/2 +
+
✓ Branch 0 taken 9206 times.
+
✓ Branch 1 taken 27594 times.
+
+
+
36800 if (requires_response) {
166 + 9206 ret = jsonrpc_response_create(&default_response, request, NULL);
167 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
168 + ✗ goto free_request;
169 + }
170 +
171 + 36800 struct jsonrpc_response* default_error = NULL;
172 +
+ 2/2 +
+
✓ Branch 0 taken 9206 times.
+
✓ Branch 1 taken 27594 times.
+
+
+
36800 if (requires_response) {
173 + 9206 ret = jsonrpc_error_create(&default_error, request, -1, "An error occured");
174 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
175 + ✗ goto free_default_response;
176 + }
177 +
178 + 36800 struct jsonrpc_response* response = NULL;
179 + 36800 ret = cmd_dispatcher_handle_internal(dispatcher, request, &response, new_ctx);
180 +
181 +
+ 2/2 +
+
✓ Branch 0 taken 9206 times.
+
✓ Branch 1 taken 27594 times.
+
+
+
36800 if (requires_response) {
182 + 9206 struct jsonrpc_response* actual_response = response;
183 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (!actual_response) {
184 + ✗ actual_response = ret < 0 ? default_error : default_response;
185 + }
186 +
+ 1/4 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
✗ Branch 3 not taken.
+
✗ Branch 4 not taken.
+
+
+
9206 if (ret < 0 && !jsonrpc_response_is_error(actual_response)) {
187 + ✗ actual_response = default_error;
188 + }
189 +
+ 1/2 +
+
✓ Branch 1 taken 9206 times.
+
✗ Branch 2 not taken.
+
+
+
9206 ret = jsonrpc_response_send(actual_response, conn_fd) < 0 ? -1 : ret;
190 + }
191 +
192 +
+ 2/2 +
+
✓ Branch 0 taken 9206 times.
+
✓ Branch 1 taken 27594 times.
+
+
+
36800 if (response)
193 + 9206 jsonrpc_response_destroy(response);
194 +
195 +
+ 2/2 +
+
✓ Branch 0 taken 27594 times.
+
✓ Branch 1 taken 9206 times.
+
+
+
36800 if (default_error)
196 + 9206 jsonrpc_response_destroy(default_error);
197 +
198 + 27594free_default_response:
199 +
+ 2/2 +
+
✓ Branch 0 taken 27594 times.
+
✓ Branch 1 taken 9206 times.
+
+
+
36800 if (default_response)
200 + 9206 jsonrpc_response_destroy(default_response);
201 +
202 + 27594free_request:
203 + 36800 jsonrpc_request_destroy(request);
204 +
205 + 36800free_ctx:
206 + 36800 free(new_ctx);
207 +
208 + 36800 return ret;
209 + }
210 +
211 + 27620int cmd_dispatcher_handle_conn(int conn_fd, void* _dispatcher) {
212 + 27620 return cmd_dispatcher_handle_conn_internal(conn_fd, (struct cmd_dispatcher*)_dispatcher);
213 + }
214 +
215 + 9180int cmd_dispatcher_handle_event(
216 + UNUSED struct event_loop* loop,
217 + int fd,
218 + short revents,
219 + void* _dispatcher
220 + ) {
221 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (!(revents & POLLIN)) {
222 + ✗ log_err("Descriptor %d is not readable\n", fd);
223 + ✗ return -1;
224 + }
225 +
226 + 9180 return cmd_dispatcher_handle_conn_internal(fd, (struct cmd_dispatcher*)_dispatcher);
227 + }
228 +
+
+
+
+ + + + diff --git a/coverage/index.css b/coverage/index.css new file mode 100644 index 0000000..6b6c4e9 --- /dev/null +++ b/coverage/index.css @@ -0,0 +1,603 @@ +:root { + font-family: sans-serif; + --tab_size: 4; +} + +.theme-green, .theme-blue { + --unknown_color: lightgray; + --low_color: #FF6666; + --medium_color: #F9FD63; + --partial_covered_color: var(--medium_color); + --uncovered_color: #FF8C8C; + --warning_color: orangered; + --notTakenBranch_color: red; + --uncheckedDecision_color: darkorange; + --notTakenDecision_color: red; + --notInvokedCall_color: red; + --excluded_color: rgb(255, 241, 229); +} + +.theme-green { + --high_color: #85E485; + --covered_color: #85E485; + --takenBranch_color: green; + --takenDecision_color: green; + --invokedCall_color: green; +} + +.theme-blue { + --high_color: #66B4FF; + --covered_color: #66B4Ff; + --takenBranch_color: blue; + --takenDecision_color: blue; + --invokedCall_color: blue; +} + +body +{ + color: #000000; + background-color: #FFFFFF; +} + +h1 +{ + text-align: center; + margin: 0; + padding-bottom: 10px; + font-size: 20pt; + font-weight: bold; +} + +hr +{ + background-color: navy; + height: 2px; + border: 0; +} + +/* Link formats: use maroon w/underlines */ +a:link +{ + color: navy; + text-decoration: underline; +} +a:visited +{ + color: maroon; + text-decoration: underline; +} + +/*** Summary formats ***/ + +.summary +{ + display: flex; + flex-flow: row wrap; + max-width: 100%; + justify-content: flex-start; +} + +.summary > table +{ + flex: 1 0 7em; + border: 0; +} + +.summary > :last-child { + margin-left: auto; +} + +table.legend +{ + color: black; + display: flex; + flex-flow: row wrap; + justify-content: flex-start; +} + +table.legend th[scope=row] +{ + font-weight: normal; + text-align: right; + white-space: nowrap; +} + +table.legend td +{ + color: blue; + text-align: left; + white-space: nowrap; + padding-left: 5px; +} + +table.legend td.legend +{ + color: black; + font-size: 80%; +} + +table.legend td.warning_text +{ + color: var(--warning_color); +} + +table.coverage td, +table.coverage th +{ + text-align: right; + color: black; + font-weight: normal; + white-space: nowrap; + padding-left: 5px; + padding-right: 4px; +} + +table.coverage td +{ + background-color: LightSteelBlue; +} + +table.coverage th[scope=row] +{ + color: black; + font-weight: normal; + white-space: nowrap; +} + +table.coverage th[scope=col] +{ + color: blue; + font-weight: normal; + white-space: nowrap; +} + +table.legend span +{ + margin-right: 4px; + padding: 2px; +} + +table.legend span.coverage-unknown, +table.legend span.coverage-none, +table.legend span.coverage-low, +table.legend span.coverage-medium, +table.legend span.coverage-high +{ + padding-left: 3px; + padding-right: 3px; +} + +table.legend span.coverage-unknown, +table.coverage td.coverage-unknown, +table.file-list td.coverage-unknow +{ + background-color: var(--unknown_color) !important; +} + +table.legend span.coverage-none, +table.legend span.coverage-low, +table.coverage td.coverage-none, +table.coverage td.coverage-low, +table.file-list td.coverage-none, +table.file-list td.coverage-low +{ + background-color: var(--low_color) !important; +} + +table.legend span.coverage-medium, +table.coverage td.coverage-medium, +table.file-list td.coverage-medium +{ + background-color: var(--medium_color) !important; +} + +table.legend span.coverage-high, +table.coverage td.coverage-high, +table.file-list td.coverage-high +{ + background-color: var(--high_color) !important; +} +/*** End of Summary formats ***/ +/*** Meter formats ***/ + +/* Common */ +meter { + -moz-appearance: none; + + width: 30vw; + min-width: 4em; + max-width: 15em; + height: 0.75em; + padding: 0; + vertical-align: baseline; + margin-top: 3px; + /* Outer background for Mozilla */ + background: none; + background-color: whitesmoke; +} + +/* Webkit */ + +meter::-webkit-meter-bar { + /* Outer background for Webkit */ + background: none; + background-color: whitesmoke; + height: 0.75em; + border-radius: 0px; +} + +meter::-webkit-meter-optimum-value, +meter::-webkit-meter-suboptimum-value, +meter::-webkit-meter-even-less-good-value +{ + /* Inner shadow for Webkit */ + border: solid 1px black; +} + +meter.coverage-none::-webkit-meter-optimum-value, +meter.coverage-low::-webkit-meter-optimum-value +{ + background: var(--low_color); +} + +meter.coverage-medium::-webkit-meter-optimum-value +{ + background: var(--medium_color); +} + +meter.coverage-high::-webkit-meter-optimum-value +{ + background: var(--high_color); +} + +/* Mozilla */ + +meter::-moz-meter-bar +{ + box-sizing: border-box; +} + +meter:-moz-meter-optimum::-moz-meter-bar, +meter:-moz-meter-sub-optimum::-moz-meter-bar, +meter:-moz-meter-sub-sub-optimum::-moz-meter-bar +{ + /* Inner shadow for Mozilla */ + border: solid 1px black; +} + +meter.coverage-none:-moz-meter-optimum::-moz-meter-bar, +meter.coverage-low:-moz-meter-optimum::-moz-meter-bar +{ + background: var(--low_color); +} + +meter.coverage-medium:-moz-meter-optimum::-moz-meter-bar +{ + background: var(--medium_color); +} + +meter.coverage-high:-moz-meter-optimum::-moz-meter-bar +{ + background: var(--high_color); +} + +/*** End of Meter formats ***/ +.file-list td, .file-list th { + padding: 0 10px; + font-weight: bold; +} + +.file-list th[scope^=col] +{ + text-align: center; + color: white; + background-color: SteelBlue; + font-size: 120%; +} + +.file-list th[scope=row] +{ + text-align: left; + color: black; + font-family: monospace; + font-weight: bold; + font-size: 110%; +} + +.file-list tr > td, +.file-list tr > th { + background: aliceblue; +} + +.file-list tr:nth-child(even) > td, +.file-list tr:nth-child(even) > th { + background: LightSteelBlue +} + +.file-list tr:hover > td, +.file-list tr:hover > th[scope=row] +{ + background-color: #ddd; +} +td.CoverValue +{ + text-align: right; + white-space: nowrap; +} + +td.coveredLine, +span.coveredLine +{ + background-color: var(--covered_color) !important; +} + +td.partialCoveredLine, +span.partialCoveredLine +{ + background-color: var(--partial_covered_color) !important; +} + +td.uncoveredLine, +span.uncoveredLine +{ + background-color: var(--uncovered_color) !important; +} + +td.excludedLine, +span.excludedLine +{ + background-color: var(--excluded_color) !important; +} + +.linebranch, .linedecision, .linecall, .linecount +{ + font-family: monospace; + border-right: 1px gray solid; + background-color: lightgray; + text-align: right; +} + + +.linebranchDetails, .linedecisionDetails, .linecallDetails +{ + position: relative; +} +.linebranchSummary, .linedecisionSummary, .linecallSummary +{ + cursor: help; +} +.linebranchContents, .linedecisionContents, .linecallContents +{ + font-family: sans-serif; + font-size: small; + text-align: left; + position: absolute; + width: 15em; + padding: 1em; + background: white; + border: solid gray 1px; + box-shadow: 5px 5px 10px gray; + z-index: 1; /* show in front of the table entries */ +} + +.takenBranch +{ + color: var(--takenBranch_color) !important; +} + +.notTakenBranch +{ + color: var(--notTakenBranch_color) !important; +} + +.takenDecision +{ + color: var(--takenDecision_color) !important; +} + +.notTakenDecision +{ + color: var(--notTakenDecision_color) !important; +} + +.uncheckedDecision +{ + color: var(--uncheckedDecision_color) !important; +} + +.invokedCall +{ + color: var(--invokedCall_color) !important; +} + +.notInvokedCall +{ + color: var(--notInvokedCall_color) !important; +} + +.src +{ + padding-left: 12px; + text-align: left; + + font-family: monospace; + white-space: pre; + + tab-size: var(--tab_size); + -moz-tab-size: var(--tab_size); +} + +span.takenBranch, +span.notTakenBranch, +span.takenDecision, +span.notTakenDecision, +span.uncheckedDecision +{ + font-family: monospace; + font-weight: bold; +} + +pre +{ + height : 15px; + margin-top: 0; + margin-bottom: 0; +} + +.listOfFunctions td, .listOfFunctions th { + padding: 0 10px; +} +.listOfFunctions th +{ + text-align: center; + color: white; + background-color: SteelBlue; +} +.listOfFunctions tr > td { + background: aliceblue; +} +.listOfFunctions tr:nth-child(even) > td { + background: LightSteelBlue +} +.listOfFunctions tr:hover > td +{ + background-color: #ddd; +} +.listOfFunctions tr > td > a +{ + text-decoration: none; + color: inherit; +} + +.source-line +{ + height : 15px; + margin-top: 0; + margin-bottom: 0; +} + +.lineno +{ + background-color: #EFE383; + border-right: 1px solid #BBB15F; + text-align: right; + unicode-bidi: embed; + font-family: monospace; + white-space: pre; +} + +.lineno > a +{ + text-decoration: none; + color: inherit; +} + +.file-list +{ + margin: 1em auto; + border: 0; + border-spacing: 1px; +} + +.file-source table +{ + border-spacing: 0; +} + +.file-source table td, +.file-source table th +{ + padding: 1px 10px; +} + +.file-source table th +{ + font-family: monospace; + font-weight: bold; +} + +.file-source table td:last-child +{ + width: 100%; +} +footer +{ + text-align: center; + padding-top: 3px; +} + +/* pygments syntax highlighting */ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.hll { background-color: #ffffcc } +.c { color: #3D7B7B; font-style: italic } /* Comment */ +.err { border: 1px solid #FF0000 } /* Error */ +.k { color: #008000; font-weight: bold } /* Keyword */ +.o { color: #666666 } /* Operator */ +.ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.cp { color: #9C6500 } /* Comment.Preproc */ +.cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.gd { color: #A00000 } /* Generic.Deleted */ +.ge { font-style: italic } /* Generic.Emph */ +.ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.gr { color: #E40000 } /* Generic.Error */ +.gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.gi { color: #008400 } /* Generic.Inserted */ +.go { color: #717171 } /* Generic.Output */ +.gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.gs { font-weight: bold } /* Generic.Strong */ +.gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.gt { color: #0044DD } /* Generic.Traceback */ +.kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.kp { color: #008000 } /* Keyword.Pseudo */ +.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.kt { color: #B00040 } /* Keyword.Type */ +.m { color: #666666 } /* Literal.Number */ +.s { color: #BA2121 } /* Literal.String */ +.na { color: #687822 } /* Name.Attribute */ +.nb { color: #008000 } /* Name.Builtin */ +.nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.no { color: #880000 } /* Name.Constant */ +.nd { color: #AA22FF } /* Name.Decorator */ +.ni { color: #717171; font-weight: bold } /* Name.Entity */ +.ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.nf { color: #0000FF } /* Name.Function */ +.nl { color: #767600 } /* Name.Label */ +.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.nt { color: #008000; font-weight: bold } /* Name.Tag */ +.nv { color: #19177C } /* Name.Variable */ +.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.w { color: #bbbbbb } /* Text.Whitespace */ +.mb { color: #666666 } /* Literal.Number.Bin */ +.mf { color: #666666 } /* Literal.Number.Float */ +.mh { color: #666666 } /* Literal.Number.Hex */ +.mi { color: #666666 } /* Literal.Number.Integer */ +.mo { color: #666666 } /* Literal.Number.Oct */ +.sa { color: #BA2121 } /* Literal.String.Affix */ +.sb { color: #BA2121 } /* Literal.String.Backtick */ +.sc { color: #BA2121 } /* Literal.String.Char */ +.dl { color: #BA2121 } /* Literal.String.Delimiter */ +.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.s2 { color: #BA2121 } /* Literal.String.Double */ +.se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.sh { color: #BA2121 } /* Literal.String.Heredoc */ +.si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.sx { color: #008000 } /* Literal.String.Other */ +.sr { color: #A45A77 } /* Literal.String.Regex */ +.s1 { color: #BA2121 } /* Literal.String.Single */ +.ss { color: #19177C } /* Literal.String.Symbol */ +.bp { color: #008000 } /* Name.Builtin.Pseudo */ +.fm { color: #0000FF } /* Name.Function.Magic */ +.vc { color: #19177C } /* Name.Variable.Class */ +.vg { color: #19177C } /* Name.Variable.Global */ +.vi { color: #19177C } /* Name.Variable.Instance */ +.vm { color: #19177C } /* Name.Variable.Magic */ +.il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/coverage/index.event_loop.c.037d09258818a0617a2d29f47e2b5064.html b/coverage/index.event_loop.c.037d09258818a0617a2d29f47e2b5064.html new file mode 100644 index 0000000..f34fcb1 --- /dev/null +++ b/coverage/index.event_loop.c.037d09258818a0617a2d29f47e2b5064.html @@ -0,0 +1,1950 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/event_loop.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:11113184.7%
Functions:1414100.0%
Branches:397651.3%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
1 + /*
2 + * Copyright (c) 2023 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 "event_loop.h"
9 +
10 + #include "log.h"
11 + #include "string.h"
12 +
13 + #include <poll.h>
14 + #include <stddef.h>
15 + #include <stdlib.h>
16 + #include <sys/queue.h>
17 +
18 + SIMPLEQ_HEAD(event_fd_queue, event_fd);
19 +
20 + struct event_fd {
21 + int fd;
22 + short events;
23 + event_handler handler;
24 + void* arg;
25 + int once;
26 +
27 + SIMPLEQ_ENTRY(event_fd) entries;
28 + };
29 +
30 + 36966static struct event_fd* event_fd_create(int fd, short events, event_handler handler, void* arg) {
31 + 36966 struct event_fd* res = calloc(1, sizeof(struct event_fd));
32 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36966 times.
+
+
+
36966 if (!res) {
33 + ✗ log_errno("calloc");
34 + ✗ return NULL;
35 + }
36 +
37 + 36966 res->fd = fd;
38 + 36966 res->events = events;
39 + 36966 res->handler = handler;
40 + 36966 res->arg = arg;
41 + 36966 res->once = 0;
42 +
43 + 36966 return res;
44 + }
45 +
46 + 36966static void event_fd_destroy(struct event_fd* entry) {
47 + 36966 free(entry);
48 + 36966}
49 +
50 + 83static void event_fd_queue_create(struct event_fd_queue* queue) {
51 + 83 SIMPLEQ_INIT(queue);
52 + 83}
53 +
54 + 83static void event_fd_queue_destroy(struct event_fd_queue* queue) {
55 + 83 struct event_fd* entry1 = SIMPLEQ_FIRST(queue);
56 +
+ 2/2 +
+
✓ Branch 0 taken 166 times.
+
✓ Branch 1 taken 83 times.
+
+
+
249 while (entry1) {
57 + 166 struct event_fd* entry2 = SIMPLEQ_NEXT(entry1, entries);
58 + 166 event_fd_destroy(entry1);
59 + 166 entry1 = entry2;
60 + }
61 + 83 SIMPLEQ_INIT(queue);
62 + 83}
63 +
64 + struct event_loop {
65 + nfds_t nfds;
66 + struct event_fd_queue entries;
67 + };
68 +
69 + 83int event_loop_create(struct event_loop** _loop) {
70 + 83 int ret = 0;
71 +
72 + 83 struct event_loop* loop = calloc(1, sizeof(struct event_loop));
73 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 83 times.
+
+
+
83 if (!loop) {
74 + ✗ log_errno("calloc");
75 + ✗ return -1;
76 + }
77 + 83 *_loop = loop;
78 +
79 + 83 event_fd_queue_create(&loop->entries);
80 +
81 + 83 return ret;
82 + }
83 +
84 + 83void event_loop_destroy(struct event_loop* loop) {
85 + 83 event_fd_queue_destroy(&loop->entries);
86 + 83 free(loop);
87 + 83}
88 +
89 + 36966static void event_loop_add_internal(struct event_loop* loop, struct event_fd* entry) {
90 +
+ 1/2 +
+
✓ Branch 1 taken 36966 times.
+
✗ Branch 2 not taken.
+
+
+
36966 log_debug("Adding descriptor %d to event loop\n", entry->fd);
91 +
92 + 36966 nfds_t nfds = loop->nfds + 1;
93 + 36966 SIMPLEQ_INSERT_TAIL(&loop->entries, entry, entries);
94 + 36966 loop->nfds = nfds;
95 + 36966}
96 +
97 + 112int event_loop_add(
98 + struct event_loop* loop,
99 + int fd,
100 + short events,
101 + event_handler handler,
102 + void* arg
103 + ) {
104 + 112 struct event_fd* entry = event_fd_create(fd, events, handler, arg);
105 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 112 times.
+
+
+
112 if (!entry)
106 + ✗ return -1;
107 + 112 event_loop_add_internal(loop, entry);
108 + 112 return 0;
109 + }
110 +
111 + 36854int event_loop_add_once(
112 + struct event_loop* loop,
113 + int fd,
114 + short events,
115 + event_handler handler,
116 + void* arg
117 + ) {
118 + 36854 struct event_fd* entry = event_fd_create(fd, events, handler, arg);
119 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36854 times.
+
+
+
36854 if (!entry)
120 + ✗ return -1;
121 + 36854 entry->once = 1;
122 + 36854 event_loop_add_internal(loop, entry);
123 + 36854 return 0;
124 + }
125 +
126 + 36800static void event_loop_remove(struct event_loop* loop, struct event_fd* entry) {
127 +
+ 1/2 +
+
✓ Branch 1 taken 36800 times.
+
✗ Branch 2 not taken.
+
+
+
36800 log_debug("Removing descriptor %d from event loop\n", entry->fd);
128 +
129 +
+ 5/8 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
✗ Branch 2 not taken.
+
✗ Branch 3 not taken.
+
✓ Branch 4 taken 48062 times.
+
✓ Branch 5 taken 36800 times.
+
✓ Branch 6 taken 26384 times.
+
✓ Branch 7 taken 10416 times.
+
+
+
84862 SIMPLEQ_REMOVE(&loop->entries, entry, event_fd, entries);
130 + 36800 event_fd_destroy(entry);
131 + 36800 --loop->nfds;
132 + 36800}
133 +
134 + 295315static char* append_event(char* buf, size_t sz, char* ptr, const char* event) {
135 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 295315 times.
+
+
+
295315 if (ptr > buf)
136 + ✗ ptr = string_append(ptr, buf + sz, ",");
137 + 295315 return string_append(ptr, buf + sz, event);
138 + }
139 +
140 + 295315static char* events_to_string(short events) {
141 + 295315 const size_t sz = 128;
142 + 295315 char* buf = calloc(1, sz);
143 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 295315 times.
+
+
+
295315 if (!buf)
144 + ✗ return NULL;
145 +
146 + 295315 char* ptr = buf;
147 +
148 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 295315 times.
+
+
+
295315 if (events & POLLNVAL)
149 + ✗ ptr = append_event(buf, sz, ptr, "POLLNVAL");
150 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 295315 times.
+
+
+
295315 if (events & POLLERR)
151 + ✗ ptr = append_event(buf, sz, ptr, "POLLERR");
152 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 295315 times.
+
+
+
295315 if (events & POLLHUP)
153 + ✗ ptr = append_event(buf, sz, ptr, "POLLHUP");
154 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 295315 times.
+
+
+
295315 if (events & POLLRDHUP)
155 + ✗ ptr = append_event(buf, sz, ptr, "POLLRDHUP");
156 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 295315 times.
+
+
+
295315 if (events & POLLPRI)
157 + ✗ ptr = append_event(buf, sz, ptr, "POLLPRI");
158 +
+ 1/2 +
+
✓ Branch 0 taken 295315 times.
+
✗ Branch 1 not taken.
+
+
+
295315 if (events & POLLIN)
159 + 295315 ptr = append_event(buf, sz, ptr, "POLLIN");
160 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 295315 times.
+
+
+
295315 if (events & POLLOUT)
161 + ✗ ptr = append_event(buf, sz, ptr, "POLLOUT");
162 +
163 + 295315 return buf;
164 + }
165 +
166 + 62548static struct pollfd* make_pollfds(const struct event_loop* loop) {
167 + 62548 struct pollfd* fds = calloc(loop->nfds, sizeof(struct pollfd));
168 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 62548 times.
+
+
+
62548 if (!fds) {
169 + ✗ log_errno("calloc");
170 + ✗ return NULL;
171 + }
172 +
173 + 62548 struct event_fd* entry = SIMPLEQ_FIRST(&loop->entries);
174 +
+ 2/2 +
+
✓ Branch 0 taken 230812 times.
+
✓ Branch 1 taken 62548 times.
+
+
+
293360 for (nfds_t i = 0; i < loop->nfds; ++i, entry = SIMPLEQ_NEXT(entry, entries)) {
175 + 230812 fds[i].fd = entry->fd;
176 + 230812 fds[i].events = entry->events;
177 + }
178 +
179 +
+ 1/2 +
+
✓ Branch 1 taken 62548 times.
+
✗ Branch 2 not taken.
+
+
+
62548 log_debug("Descriptors:\n");
180 +
+ 2/2 +
+
✓ Branch 0 taken 230812 times.
+
✓ Branch 1 taken 62548 times.
+
+
+
293360 for (nfds_t i = 0; i < loop->nfds; ++i) {
181 + 230812 char* events = events_to_string(fds[i].events);
182 +
+ 1/4 +
+
✓ Branch 1 taken 230812 times.
+
✗ Branch 2 not taken.
+
✗ Branch 3 not taken.
+
✗ Branch 4 not taken.
+
+
+
230812 log_debug(" %d (%s)\n", fds[i].fd, events ? events : "");
183 + 230812 free(events);
184 + }
185 +
186 + 62548 return fds;
187 + }
188 +
189 + 62548int event_loop_run(struct event_loop* loop) {
190 + /* Cache the number of event descriptors so that event handlers can
191 + * append new ones. */
192 + 62548 const nfds_t nfds = loop->nfds;
193 +
194 + 62548 struct pollfd* fds = make_pollfds(loop);
195 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 62548 times.
+
+
+
62548 if (!fds)
196 + ✗ return -1;
197 +
198 + 62548 int ret = poll(fds, nfds, -1);
199 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 62548 times.
+
+
+
62548 if (ret < 0) {
200 + ✗ log_errno("poll");
201 + ✗ return ret;
202 + }
203 + 62548 ret = 0;
204 +
205 + 62548 struct event_fd* entry = SIMPLEQ_FIRST(&loop->entries);
206 +
+ 2/2 +
+
✓ Branch 0 taken 230812 times.
+
✓ Branch 1 taken 62548 times.
+
+
+
293360 for (nfds_t i = 0; i < nfds; ++i) {
207 + 230812 struct event_fd* next = SIMPLEQ_NEXT(entry, entries);
208 +
209 +
+ 2/2 +
+
✓ Branch 0 taken 166309 times.
+
✓ Branch 1 taken 64503 times.
+
+
+
230812 if (!fds[i].revents)
210 + 166309 goto next;
211 +
212 + 64503 char* events = events_to_string(fds[i].revents);
213 +
+ 1/4 +
+
✓ Branch 1 taken 64503 times.
+
✗ Branch 2 not taken.
+
✗ Branch 3 not taken.
+
✗ Branch 4 not taken.
+
+
+
64503 log_debug("Descriptor %d is ready: %s\n", fds[i].fd, events ? events : "");
214 + 64503 free(events);
215 +
216 + /* Execute all handlers but notice if any of them fail. */
217 + 64503 const int handler_ret = entry->handler(loop, fds[i].fd, fds[i].revents, entry->arg);
218 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 64503 times.
+
+
+
64503 if (handler_ret < 0)
219 + ✗ ret = handler_ret;
220 +
221 +
+ 2/2 +
+
✓ Branch 0 taken 27703 times.
+
✓ Branch 1 taken 36800 times.
+
+
+
64503 if (entry->once)
222 + 36800 event_loop_remove(loop, entry);
223 +
224 + 27703 next:
225 + 230812 entry = next;
226 + 230812 continue;
227 + }
228 +
229 + 62548 free(fds);
230 + 62548 return ret;
231 + }
232 +
+
+
+
+ + + + diff --git a/coverage/index.file.c.0cc24881e570d19e625204519d50254f.html b/coverage/index.file.c.0cc24881e570d19e625204519d50254f.html new file mode 100644 index 0000000..8a33bea --- /dev/null +++ b/coverage/index.file.c.0cc24881e570d19e625204519d50254f.html @@ -0,0 +1,1336 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/file.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:568466.7%
Functions:88100.0%
Branches:205238.5%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "file.h"
9 +
10 + #include "compiler.h"
11 + #include "log.h"
12 +
13 + #include <fcntl.h>
14 + #include <ftw.h>
15 + #include <stdio.h>
16 + #include <stdlib.h>
17 + #include <sys/stat.h>
18 + #include <unistd.h>
19 +
20 + 403658static int unlink_cb(
21 + const char* fpath,
22 + UNUSED const struct stat* sb,
23 + UNUSED int typeflag,
24 + UNUSED struct FTW* ftwbuf
25 + ) {
26 + 403658 int ret = 0;
27 +
28 + 403658 ret = remove(fpath);
29 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 403658 times.
+
+
+
403658 if (ret < 0) {
30 + ✗ log_errno("remove");
31 + ✗ return ret;
32 + }
33 +
34 + 403658 return ret;
35 + }
36 +
37 + 9180int rm_rf(const char* dir) {
38 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 log("Recursively removing directory: %s\n", dir);
39 + 9180 return nftw(dir, unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
40 + }
41 +
42 + 18360int chdir_wrapper(const char* dir, char** old) {
43 + 18360 int ret = 0;
44 +
45 +
+ 2/2 +
+
✓ Branch 0 taken 9180 times.
+
✓ Branch 1 taken 9180 times.
+
+
+
18360 if (old) {
46 + 9180 *old = get_current_dir_name();
47 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (!*old) {
48 + ✗ log_errno("get_current_dir_name");
49 + ✗ return -1;
50 + }
51 + }
52 +
53 + 18360 ret = chdir(dir);
54 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 18360 times.
+
+
+
18360 if (ret < 0) {
55 + ✗ log_errno("chdir");
56 + ✗ goto free_old;
57 + }
58 +
59 + 18360 return ret;
60 +
61 + ✗free_old:
62 + ✗ if (old)
63 + ✗ free(*old);
64 +
65 + ✗ return ret;
66 + }
67 +
68 + 20char* readlink_wrapper(const char* path) {
69 + 20 size_t current_size = 256;
70 + 20 char* buf = NULL;
71 +
72 + ✗ while (1) {
73 + 20 char* tmp_buf = realloc(buf, current_size);
74 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 20 times.
+
+
+
20 if (!tmp_buf) {
75 + ✗ log_errno("realloc");
76 + ✗ goto free;
77 + }
78 + 20 buf = tmp_buf;
79 +
80 + 20 ssize_t res = readlink(path, buf, current_size);
81 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 20 times.
+
+
+
20 if (res < 0) {
82 + ✗ log_errno("readlink");
83 + ✗ goto free;
84 + }
85 +
86 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 20 times.
+
+
+
20 if ((size_t)res == current_size) {
87 + ✗ current_size *= 2;
88 + ✗ continue;
89 + }
90 +
91 + 20 buf[res] = '\0';
92 + 20 break;
93 + }
94 +
95 + 20 return buf;
96 +
97 + ✗free:
98 + ✗ free(buf);
99 +
100 + ✗ return NULL;
101 + }
102 +
103 + 9234int file_dup(int fd) {
104 + 9234 int ret = 0;
105 +
106 + 9234 ret = fcntl(fd, F_DUPFD_CLOEXEC, 0);
107 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9234 times.
+
+
+
9234 if (ret < 0) {
108 + ✗ log_errno("fcntl");
109 + ✗ return ret;
110 + }
111 +
112 + 9234 return ret;
113 + }
114 +
115 + 110566void file_close(int fd) {
116 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 110566 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
110566 log_errno_if(close(fd), "close");
117 + 110566}
118 +
119 + 36720int file_exists(const char* path) {
120 + struct stat stat;
121 + 36720 int ret = lstat(path, &stat);
122 +
+ 3/4 +
+
✓ Branch 0 taken 9180 times.
+
✓ Branch 1 taken 27540 times.
+
✓ Branch 2 taken 9180 times.
+
✗ Branch 3 not taken.
+
+
+
36720 return !ret && S_ISREG(stat.st_mode);
123 + }
124 +
125 + 9180int file_read(int fd, unsigned char** _contents, size_t* _size) {
126 + 9180 size_t alloc_size = 256;
127 + 9180 unsigned char* contents = NULL;
128 + 9180 size_t size = 0;
129 +
130 + 184003 while (1) {
131 + 193183 unsigned char* tmp_contents = realloc(contents, alloc_size);
132 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 193183 times.
+
+
+
193183 if (!tmp_contents) {
133 + ✗ log_errno("realloc");
134 + ✗ free(contents);
135 + ✗ return -1;
136 + }
137 + 193183 contents = tmp_contents;
138 +
139 + 193183 ssize_t read_size = read(fd, contents + size, alloc_size - size);
140 +
141 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 193183 times.
+
+
+
193183 if (read_size < 0) {
142 + ✗ log_errno("read");
143 + ✗ free(contents);
144 + ✗ return read_size;
145 + }
146 +
147 +
+ 2/2 +
+
✓ Branch 0 taken 9180 times.
+
✓ Branch 1 taken 184003 times.
+
+
+
193183 if (!read_size) {
148 + 9180 *_contents = contents;
149 + 9180 *_size = size;
150 + 9180 return 0;
151 + }
152 +
153 + 184003 size += read_size;
154 +
155 +
+ 2/2 +
+
✓ Branch 0 taken 49896 times.
+
✓ Branch 1 taken 134107 times.
+
+
+
184003 if (size == alloc_size) {
156 + 49896 alloc_size *= 2;
157 + }
158 + }
159 + }
160 +
+
+
+
+ + + + diff --git a/coverage/index.functions.html b/coverage/index.functions.html new file mode 100644 index 0000000..f9464c8 --- /dev/null +++ b/coverage/index.functions.html @@ -0,0 +1,377 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + +
Directory:src/
Date:2026-10-15 10:49:27
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:2021284571.0%
Functions:28129495.6%
Branches:560140939.7%
+
+
+ +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Function (File:Line)Call countBlock coverage
append_event (src/event_loop.c:134)called 295315 times, returned 295315 times75.0%
base64_decode (src/base64.c:35)called 9180 times, returned 9180 times26.0%
base64_encode (src/base64.c:20)called 9180 times, returned 9180 times38.0%
buf_create (src/buf.c:21)called 92012 times, returned 92012 times27.0%
buf_create_from_string (src/buf.c:35)called 46006 times, returned 46006 times100.0%
buf_destroy (src/buf.c:39)called 92012 times, returned 92012 times100.0%
buf_get_data (src/buf.c:47)called 138018 times, returned 138018 times100.0%
buf_get_size (src/buf.c:43)called 92012 times, returned 92012 times100.0%
chdir_wrapper (src/file.c:42)called 18360 times, returned 18360 times27.0%
ci_cleanup_git_repo (src/ci.c:51)called 9180 times, returned 9180 times100.0%
ci_prepare_git_repo (src/ci.c:56)called 9180 times, returned 9180 times60.0%
ci_run (src/ci.c:39)called 9180 times, returned 9180 times63.0%
ci_run_git_repo (src/ci.c:75)called 9180 times, returned 9180 times81.0%
ci_run_script (src/ci.c:34)called 9180 times, returned 9180 times100.0%
client_create (src/client.c:26)called 9208 times, returned 9208 times27.0%
client_create (src/tcp_server.c:157)called 27620 times, returned 27620 times24.0%
client_create_thread (src/tcp_server.c:133)called 27620 times, returned 27620 times50.0%
client_destroy (src/client.c:39)called 9206 times, returned 9206 times100.0%
client_destroy (src/tcp_server.c:87)called 27620 times, returned 27620 times62.0%
client_destroy_handler (src/tcp_server.c:97)called 27620 times, returned 27620 times75.0%
client_main (src/client.c:70)called 9208 times, returned 9208 times64.0%
client_queue_create (src/tcp_server.c:202)called 29 times, returned 29 times100.0%
client_queue_destroy (src/tcp_server.c:206)called 29 times, returned 29 times60.0%
client_thread_func (src/tcp_server.c:110)called 27620 times, returned 27620 times54.0%
cmd_dispatcher_create (src/command.c:63)called 83 times, returned 83 times24.0%
cmd_dispatcher_destroy (src/command.c:102)called 83 times, returned 83 times100.0%
cmd_dispatcher_handle (src/command.c:129)not called0.0%
cmd_dispatcher_handle_conn (src/command.c:211)called 27620 times, returned 27620 times100.0%
cmd_dispatcher_handle_conn_internal (src/command.c:150)called 36800 times, returned 36800 times72.0%
cmd_dispatcher_handle_event (src/command.c:215)called 9180 times, returned 9180 times27.0%
cmd_dispatcher_handle_internal (src/command.c:108)called 36800 times, returned 36800 times50.0%
copy_cmd (src/command.c:25)called 170 times, returned 170 times33.0%
copy_cmds (src/command.c:39)called 83 times, returned 83 times54.0%
default_settings (src/client_main.c:16)called 9214 times, returned 9214 times100.0%
default_settings (src/server_main.c:16)called 35 times, returned 35 times100.0%
default_settings (src/worker_main.c:16)called 60 times, returned 60 times100.0%
event_fd_create (src/event_loop.c:30)called 36966 times, returned 36966 times27.0%
event_fd_destroy (src/event_loop.c:46)called 36966 times, returned 36966 times100.0%
event_fd_queue_create (src/event_loop.c:50)called 83 times, returned 83 times100.0%
event_fd_queue_destroy (src/event_loop.c:54)called 83 times, returned 83 times100.0%
event_loop_add (src/event_loop.c:97)called 112 times, returned 112 times83.0%
event_loop_add_internal (src/event_loop.c:89)called 36966 times, returned 36966 times67.0%
event_loop_add_once (src/event_loop.c:111)called 36854 times, returned 36854 times83.0%
event_loop_create (src/event_loop.c:69)called 83 times, returned 83 times33.0%
event_loop_destroy (src/event_loop.c:84)called 83 times, returned 83 times100.0%
event_loop_remove (src/event_loop.c:126)called 36800 times, returned 36800 times73.0%
event_loop_run (src/event_loop.c:189)called 62548 times, returned 62548 times58.0%
events_to_string (src/event_loop.c:140)called 295315 times, returned 295315 times61.0%
exec_child (src/process.c:18)not called0.0%
exit_with_usage (src/cmd_line.c:41)called 14 times, returned 0 time89.0%
exit_with_usage_err (src/cmd_line.c:53)called 2 times, returned 0 time100.0%
exit_with_version (src/cmd_line.c:59)called 6 times, returned 0 time83.0%
file_close (src/file.c:115)called 110566 times, returned 110566 times30.0%
file_dup (src/file.c:103)called 9234 times, returned 9234 times33.0%
file_exists (src/file.c:119)called 36720 times, returned 36720 times100.0%
file_read (src/file.c:125)called 9180 times, returned 9180 times38.0%
free_cmd (src/command.c:35)called 170 times, returned 170 times100.0%
free_cmds (src/command.c:58)called 83 times, returned 83 times100.0%
get_api (src/storage.c:57)called 18502 times, returned 18502 times36.0%
get_current_binary_name (src/cmd_line.c:22)called 20 times, returned 20 times47.0%
get_current_binary_path (src/cmd_line.c:18)called 20 times, returned 20 times100.0%
get_usage_string (src/client_main.c:24)called 6 times, returned 6 times100.0%
get_usage_string (src/server_main.c:24)called 4 times, returned 4 times100.0%
get_usage_string (src/worker_main.c:24)called 4 times, returned 4 times100.0%
jsonrpc_check_error (src/json_rpc.c:139)not called0.0%
jsonrpc_check_id (src/json_rpc.c:69)called 46006 times, returned 46006 times50.0%
jsonrpc_check_id_type (src/json_rpc.c:61)called 18412 times, returned 18412 times43.0%
jsonrpc_check_method (src/json_rpc.c:91)called 36800 times, returned 36800 times100.0%
jsonrpc_check_params (src/json_rpc.c:110)called 36800 times, returned 36800 times89.0%
jsonrpc_check_params_type (src/json_rpc.c:101)called 27540 times, returned 27540 times29.0%
jsonrpc_check_result_or_error (src/json_rpc.c:166)called 9206 times, returned 9206 times35.0%
jsonrpc_check_version (src/json_rpc.c:35)called 46006 times, returned 46006 times40.0%
jsonrpc_error_create (src/json_rpc.c:461)called 9206 times, returned 9206 times65.0%
jsonrpc_generate_request_id (src/json_rpc.c:57)called 9206 times, returned 9206 times100.0%
jsonrpc_notification_create (src/json_rpc.c:245)called 27594 times, returned 27594 times100.0%
jsonrpc_request_create (src/json_rpc.c:231)called 9206 times, returned 9206 times100.0%
jsonrpc_request_create_internal (src/json_rpc.c:181)called 36800 times, returned 36800 times45.0%
jsonrpc_request_create_params (src/json_rpc.c:317)called 73440 times, returned 73440 times76.0%
jsonrpc_request_destroy (src/json_rpc.c:240)called 73600 times, returned 73600 times100.0%
jsonrpc_request_from_json (src/json_rpc.c:257)called 36800 times, returned 36800 times48.0%
jsonrpc_request_get_method (src/json_rpc.c:307)called 36800 times, returned 36800 times83.0%
jsonrpc_request_get_param_int (src/json_rpc.c:366)called 27540 times, returned 27540 times83.0%
jsonrpc_request_get_param_string (src/json_rpc.c:343)called 45900 times, returned 45900 times83.0%
jsonrpc_request_is_notification (src/json_rpc.c:253)called 36800 times, returned 36800 times100.0%
jsonrpc_request_recv (src/json_rpc.c:288)called 36800 times, returned 36800 times35.0%
jsonrpc_request_send (src/json_rpc.c:284)called 36800 times, returned 36800 times100.0%
jsonrpc_request_set_param_int (src/json_rpc.c:378)called 27540 times, returned 27540 times80.0%
jsonrpc_request_set_param_string (src/json_rpc.c:355)called 45900 times, returned 45900 times80.0%
jsonrpc_response_create (src/json_rpc.c:448)called 18412 times, returned 18412 times100.0%
jsonrpc_response_create_internal (src/json_rpc.c:393)called 27618 times, returned 27618 times50.0%
jsonrpc_response_destroy (src/json_rpc.c:456)called 36824 times, returned 36824 times100.0%
jsonrpc_response_from_json (src/json_rpc.c:497)called 9206 times, returned 9206 times45.0%
jsonrpc_response_is_error (src/json_rpc.c:493)called 9206 times, returned 9206 times100.0%
jsonrpc_response_recv (src/json_rpc.c:528)called 9206 times, returned 9206 times35.0%
jsonrpc_response_send (src/json_rpc.c:524)called 9206 times, returned 9206 times100.0%
jsonrpc_response_to_string (src/json_rpc.c:389)called 9206 times, returned 9206 times100.0%
jsonrpc_set_id (src/json_rpc.c:87)called 9206 times, returned 9206 times100.0%
jsonrpc_set_method (src/json_rpc.c:97)called 36800 times, returned 36800 times100.0%
jsonrpc_set_params (src/json_rpc.c:124)not called0.0%
jsonrpc_set_version (src/json_rpc.c:51)called 64418 times, returned 64418 times100.0%
libgit_checkout (src/git.c:76)called 9180 times, returned 9180 times25.0%
libgit_clone (src/git.c:39)called 9180 times, returned 9180 times29.0%
libgit_clone_to_tmp (src/git.c:61)called 9180 times, returned 9180 times38.0%
libgit_init (src/git.c:23)called 54 times, returned 54 times24.0%
libgit_repository_free (src/git.c:72)called 9180 times, returned 9180 times100.0%
libgit_shutdown (src/git.c:35)called 54 times, returned 54 times100.0%
libjson_append (src/json.c:281)called 9180 times, returned 9180 times33.0%
libjson_clone (src/json.c:61)called 27618 times, returned 27618 times78.0%
libjson_free (src/json.c:27)called 110424 times, returned 110424 times100.0%
libjson_from_string (src/json.c:48)called 46006 times, returned 46006 times24.0%
libjson_get (src/json.c:139)called 385956 times, returned 385956 times33.0%
libjson_get_int (src/json.c:164)called 27540 times, returned 27540 times35.0%
libjson_get_string (src/json.c:148)called 165506 times, returned 165506 times47.0%
libjson_has (src/json.c:135)called 606620 times, returned 606620 times100.0%
libjson_new_array (src/json.c:125)called 26 times, returned 26 times33.0%
libjson_new_object (src/json.c:115)called 110344 times, returned 110344 times33.0%
libjson_recv (src/json.c:95)called 46006 times, returned 46006 times85.0%
libjson_send (src/json.c:78)called 46006 times, returned 46006 times82.0%
libjson_set (src/json.c:252)called 55158 times, returned 55158 times100.0%
libjson_set_const_key (src/json.c:269)called 27618 times, returned 27618 times100.0%
libjson_set_int (src/json.c:260)called 27540 times, returned 27540 times100.0%
libjson_set_int_const_key (src/json.c:277)called 36772 times, returned 36772 times100.0%
libjson_set_int_internal (src/json.c:228)called 64312 times, returned 64312 times35.0%
libjson_set_internal (src/json.c:187)called 321772 times, returned 321772 times33.0%
libjson_set_string (src/json.c:256)called 45900 times, returned 45900 times100.0%
libjson_set_string_const_key (src/json.c:273)called 128784 times, returned 128784 times100.0%
libjson_set_string_internal (src/json.c:204)called 174684 times, returned 174684 times35.0%
libjson_to_string (src/json.c:40)called 46006 times, returned 46006 times100.0%
libjson_to_string_internal (src/json.c:31)called 55212 times, returned 55212 times33.0%
libjson_to_string_pretty (src/json.c:44)called 9206 times, returned 9206 times100.0%
log_entry_end (src/log.c:48)called 182141 times, returned 182141 times100.0%
log_entry_start (src/log.c:39)called 696630 times, returned 696630 times100.0%
log_prefix_thread_id (src/log.c:35)called 182141 times, returned 182141 times100.0%
log_prefix_timestamp (src/log.c:17)called 182141 times, returned 182141 times70.0%
main (src/client_main.c:71)called 9214 times, returned 9214 times79.0%
main (src/server_main.c:68)called 35 times, returned 29 times79.0%
main (src/worker_main.c:68)called 60 times, returned 54 times79.0%
make_conn_ctx (src/command.c:137)called 36800 times, returned 36800 times27.0%
make_pollfds (src/event_loop.c:166)called 62548 times, returned 62548 times52.0%
make_request (src/client.c:43)called 9208 times, returned 9208 times80.0%
net_accept (src/net.c:95)called 27620 times, returned 27620 times33.0%
net_bind (src/net.c:24)called 29 times, returned 29 times26.0%
net_close (src/net.c:152)called 64503 times, returned 64503 times100.0%
net_connect (src/net.c:108)called 27620 times, returned 27620 times29.0%
net_recv (src/net.c:181)called 92012 times, returned 92012 times35.0%
net_recv_buf (src/net.c:220)called 46006 times, returned 46006 times27.0%
net_send (src/net.c:168)called 92012 times, returned 92012 times88.0%
net_send_buf (src/net.c:205)called 46006 times, returned 46006 times83.0%
net_send_part (src/net.c:156)called 92012 times, returned 92012 times33.0%
numof_apis (src/storage.c:53)called 18502 times, returned 18502 times100.0%
parse_settings (src/client_main.c:31)called 9214 times, returned 9214 times76.0%
parse_settings (src/server_main.c:28)called 35 times, returned 29 times76.0%
parse_settings (src/worker_main.c:28)called 60 times, returned 54 times76.0%
prepared_stmt_destroy (src/storage_sqlite.c:82)called 174 times, returned 174 times33.0%
prepared_stmt_init (src/storage_sqlite.c:61)called 174 times, returned 174 times23.0%
prepared_stmt_lock (src/storage_sqlite.c:87)called 36775 times, returned 36775 times33.0%
prepared_stmt_unlock (src/storage_sqlite.c:96)called 36775 times, returned 36775 times27.0%
process_execute (src/process.c:60)not called0.0%
process_execute_and_capture (src/process.c:93)called 9180 times, returned 9180 times43.0%
process_output_create (src/process.c:140)called 18360 times, returned 18360 times27.0%
process_output_destroy (src/process.c:155)called 18360 times, returned 18360 times100.0%
process_output_dump (src/process.c:160)called 9180 times, returned 9180 times82.0%
readlink_wrapper (src/file.c:68)called 20 times, returned 20 times30.0%
redirect_and_exec_child (src/process.c:73)not called0.0%
request_create_finished_run (src/protocol.c:117)called 9180 times, returned 9180 times65.0%
request_create_get_runs (src/protocol.c:194)called 26 times, returned 26 times100.0%
request_create_new_worker (src/protocol.c:62)called 9234 times, returned 9234 times100.0%
request_create_queue_run (src/protocol.c:26)called 9180 times, returned 9180 times69.0%
request_create_start_run (src/protocol.c:70)called 9180 times, returned 9180 times68.0%
request_parse_finished_run (src/protocol.c:152)called 9180 times, returned 9180 times65.0%
request_parse_get_runs (src/protocol.c:198)called 26 times, returned 26 times100.0%
request_parse_new_worker (src/protocol.c:66)not called0.0%
request_parse_queue_run (src/protocol.c:47)called 9180 times, returned 9180 times78.0%
request_parse_start_run (src/protocol.c:94)called 9180 times, returned 9180 times75.0%
response_create_get_runs (src/protocol.c:202)called 26 times, returned 26 times64.0%
rm_rf (src/file.c:37)called 9180 times, returned 9180 times86.0%
run_created (src/run_queue.c:84)called 9180 times, returned 9180 times100.0%
run_destroy (src/run_queue.c:74)called 36720 times, returned 36720 times100.0%
run_get_id (src/run_queue.c:117)called 45900 times, returned 45900 times100.0%
run_get_repo_rev (src/run_queue.c:125)called 36720 times, returned 36720 times100.0%
run_get_repo_url (src/run_queue.c:121)called 64260 times, returned 64260 times100.0%
run_new (src/run_queue.c:29)called 36720 times, returned 36720 times21.0%
run_queue_add_first (src/run_queue.c:182)not called0.0%
run_queue_add_last (src/run_queue.c:186)called 18360 times, returned 18360 times100.0%
run_queue_create (src/run_queue.c:133)called 55 times, returned 55 times100.0%
run_queue_destroy (src/run_queue.c:137)called 55 times, returned 55 times100.0%
run_queue_is_empty (src/run_queue.c:178)called 27393 times, returned 27393 times100.0%
run_queue_remove_first (src/run_queue.c:190)called 9180 times, returned 9180 times100.0%
run_queue_to_json (src/run_queue.c:147)called 26 times, returned 26 times63.0%
run_queued (src/run_queue.c:80)called 18360 times, returned 18360 times100.0%
run_set_id (src/run_queue.c:129)called 9180 times, returned 9180 times100.0%
run_to_json (src/run_queue.c:88)called 9180 times, returned 9180 times65.0%
server_assign_run (src/server.c:159)called 9180 times, returned 9180 times70.0%
server_create (src/server.c:363)called 29 times, returned 29 times29.0%
server_destroy (src/server.c:471)called 29 times, returned 29 times42.0%
server_enqueue_run (src/server.c:121)called 9180 times, returned 9180 times86.0%
server_enqueue_worker (src/server.c:102)called 9234 times, returned 9234 times86.0%
server_handle_cmd_finished_run (src/server.c:293)called 9180 times, returned 9180 times55.0%
server_handle_cmd_get_runs (src/server.c:323)called 26 times, returned 26 times52.0%
server_handle_cmd_new_worker (src/server.c:223)called 9234 times, returned 9234 times60.0%
server_handle_cmd_queue_run (src/server.c:258)called 9180 times, returned 9180 times56.0%
server_has_runs (src/server.c:117)called 27393 times, returned 27393 times100.0%
server_has_workers (src/server.c:98)called 27178 times, returned 27178 times100.0%
server_listen_thread (src/server.c:487)called 29 times, returned 29 times85.0%
server_lock (src/server.c:52)called 18472 times, returned 18472 times33.0%
server_main (src/server.c:501)called 29 times, returned 29 times100.0%
server_main_thread (src/server.c:197)called 29 times, returned 29 times86.0%
server_notify (src/server.c:74)called 18443 times, returned 18443 times27.0%
server_ready_for_action (src/server.c:143)called 27422 times, returned 27422 times100.0%
server_set_stopping (src/server.c:78)called 29 times, returned 29 times86.0%
server_unlock (src/server.c:61)called 18472 times, returned 18472 times27.0%
server_wait (src/server.c:65)called 18213 times, returned 18213 times33.0%
server_wait_for_action (src/server.c:147)called 9209 times, returned 9209 times89.0%
signal_block_all (src/signal.c:41)called 27620 times, returned 27620 times100.0%
signal_block_sigterms (src/signal.c:47)called 27620 times, returned 27620 times100.0%
signal_set_mask (src/signal.c:37)called 27620 times, returned 27620 times100.0%
signal_set_mask_internal (src/signal.c:25)called 82943 times, returned 82943 times33.0%
signalfd_create (src/signal.c:53)called 83 times, returned 83 times64.0%
signalfd_create_sigterms (src/signal.c:74)called 83 times, returned 83 times100.0%
signalfd_destroy (src/signal.c:80)called 83 times, returned 83 times100.0%
sigterms_mask (src/signal.c:19)called 27703 times, returned 27703 times100.0%
sqlite_bind_blob (src/sqlite.c:224)called 9180 times, returned 9180 times31.0%
sqlite_bind_int (src/sqlite.c:200)called 45929 times, returned 45929 times31.0%
sqlite_bind_text (src/sqlite.c:212)called 27540 times, returned 27540 times31.0%
sqlite_close (src/sqlite.c:71)called 29 times, returned 29 times25.0%
sqlite_column_blob (src/sqlite.c:171)not called0.0%
sqlite_column_int (src/sqlite.c:138)called 45929 times, returned 45929 times100.0%
sqlite_column_text (src/sqlite.c:142)called 18360 times, returned 18360 times22.0%
sqlite_destroy (src/sqlite.c:45)called 29 times, returned 29 times25.0%
sqlite_exec (src/sqlite.c:75)called 58 times, returned 58 times31.0%
sqlite_exec_as_transaction (src/sqlite.c:236)called 29 times, returned 29 times38.0%
sqlite_exec_log_result (src/sqlite.c:87)not called0.0%
sqlite_finalize (src/sqlite.c:117)called 203 times, returned 203 times25.0%
sqlite_get_user_version (src/sqlite.c:260)called 29 times, returned 29 times40.0%
sqlite_init (src/sqlite.c:33)called 29 times, returned 29 times31.0%
sqlite_open (src/sqlite.c:49)called 29 times, returned 29 times31.0%
sqlite_open_ro (src/sqlite.c:66)not called0.0%
sqlite_open_rw (src/sqlite.c:61)called 29 times, returned 29 times100.0%
sqlite_prepare (src/sqlite.c:100)called 203 times, returned 203 times31.0%
sqlite_reset (src/sqlite.c:112)called 36775 times, returned 36775 times22.0%
sqlite_set_foreign_keys (src/sqlite.c:294)called 29 times, returned 29 times100.0%
sqlite_step (src/sqlite.c:121)called 45984 times, returned 45984 times36.0%
storage_create (src/storage.c:77)called 29 times, returned 29 times75.0%
storage_destroy (src/storage.c:89)called 29 times, returned 29 times80.0%
storage_get_run_queue (src/storage.c:117)called 29 times, returned 29 times80.0%
storage_get_runs (src/storage.c:110)called 26 times, returned 26 times80.0%
storage_run_create (src/storage.c:96)called 9180 times, returned 9180 times80.0%
storage_run_finished (src/storage.c:103)called 9180 times, returned 9180 times80.0%
storage_settings_destroy (src/storage.c:70)called 29 times, returned 29 times80.0%
storage_sqlite_create (src/storage_sqlite.c:250)called 29 times, returned 29 times48.0%
storage_sqlite_destroy (src/storage_sqlite.c:287)called 29 times, returned 29 times100.0%
storage_sqlite_finalize_statements (src/storage_sqlite.c:241)called 29 times, returned 29 times100.0%
storage_sqlite_find_repo (src/storage_sqlite.c:294)called 9180 times, returned 9180 times76.0%
storage_sqlite_get_run_queue (src/storage_sqlite.c:508)called 29 times, returned 29 times79.0%
storage_sqlite_get_runs (src/storage_sqlite.c:490)called 26 times, returned 26 times82.0%
storage_sqlite_insert_repo (src/storage_sqlite.c:321)called 9180 times, returned 9180 times75.0%
storage_sqlite_insert_run (src/storage_sqlite.c:345)called 9180 times, returned 9180 times57.0%
storage_sqlite_prepare_statements (src/storage_sqlite.c:191)called 29 times, returned 29 times54.0%
storage_sqlite_row_to_run (src/storage_sqlite.c:429)called 9180 times, returned 9180 times81.0%
storage_sqlite_rows_to_runs (src/storage_sqlite.c:461)called 55 times, returned 55 times67.0%
storage_sqlite_run_create (src/storage_sqlite.c:381)called 9180 times, returned 9180 times75.0%
storage_sqlite_run_finished (src/storage_sqlite.c:395)called 9180 times, returned 9180 times74.0%
storage_sqlite_settings_create (src/storage_sqlite.c:28)called 29 times, returned 29 times23.0%
storage_sqlite_settings_destroy (src/storage_sqlite.c:51)called 29 times, returned 29 times100.0%
storage_sqlite_setup (src/storage_sqlite.c:177)called 29 times, returned 29 times75.0%
storage_sqlite_upgrade (src/storage_sqlite.c:152)called 29 times, returned 29 times47.0%
storage_sqlite_upgrade_from_to (src/storage_sqlite.c:137)called 29 times, returned 29 times55.0%
storage_sqlite_upgrade_to (src/storage_sqlite.c:111)called 29 times, returned 29 times38.0%
string_append (src/string.c:18)called 295315 times, returned 295315 times67.0%
string_to_int (src/string.c:32)not called0.0%
tcp_server_accept (src/tcp_server.c:273)called 27620 times, returned 27620 times60.0%
tcp_server_accept_handler (src/tcp_server.c:215)called 27620 times, returned 27620 times100.0%
tcp_server_create (src/tcp_server.c:225)called 29 times, returned 29 times40.0%
tcp_server_destroy (src/tcp_server.c:267)called 29 times, returned 29 times100.0%
unlink_cb (src/file.c:20)called 403658 times, returned 403658 times33.0%
wait_for_child (src/process.c:33)called 9180 times, returned 9180 times36.0%
worker_create (src/worker.c:109)called 54 times, returned 54 times44.0%
worker_create (src/worker_queue.c:21)called 9234 times, returned 9234 times27.0%
worker_destroy (src/worker.c:168)called 54 times, returned 54 times91.0%
worker_destroy (src/worker_queue.c:34)called 9234 times, returned 9234 times100.0%
worker_do_run (src/worker.c:179)called 9180 times, returned 9180 times65.0%
worker_get_fd (src/worker_queue.c:39)called 36774 times, returned 36774 times100.0%
worker_get_run (src/worker.c:224)called 9234 times, returned 9234 times77.0%
worker_handle_cmd_start_run (src/worker.c:87)called 9180 times, returned 9180 times80.0%
worker_main (src/worker.c:260)called 54 times, returned 54 times83.0%
worker_queue_add_first (src/worker_queue.c:61)not called0.0%
worker_queue_add_last (src/worker_queue.c:65)called 9234 times, returned 9234 times100.0%
worker_queue_create (src/worker_queue.c:43)called 29 times, returned 29 times100.0%
worker_queue_destroy (src/worker_queue.c:47)called 29 times, returned 29 times100.0%
worker_queue_is_empty (src/worker_queue.c:57)called 27178 times, returned 27178 times100.0%
worker_queue_remove_first (src/worker_queue.c:69)called 9180 times, returned 9180 times100.0%
worker_set_stopping (src/worker.c:76)called 54 times, returned 54 times100.0%
worker_settings_copy (src/worker.c:40)called 54 times, returned 54 times21.0%
worker_settings_destroy (src/worker.c:70)called 54 times, returned 54 times100.0%
+ +
+
+ + + + diff --git a/coverage/index.git.c.ecafe65200a95f92fc10a3095d9e5f09.html b/coverage/index.git.c.ecafe65200a95f92fc10a3095d9e5f09.html new file mode 100644 index 0000000..092b3f0 --- /dev/null +++ b/coverage/index.git.c.ecafe65200a95f92fc10a3095d9e5f09.html @@ -0,0 +1,966 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/git.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:395570.9%
Functions:66100.0%
Branches:106415.6%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "git.h"
9 +
10 + #include "log.h"
11 +
12 + #include <git2.h>
13 +
14 + #include <stdlib.h>
15 +
16 + #define git_log_err(fn) \
17 + do { \
18 + const git_error* error = git_error_last(); \
19 + const char* msg = error && error->message ? error->message : "???"; \
20 + log_err("%s: %s\n", fn, msg); \
21 + } while (0)
22 +
23 + 54int libgit_init(void) {
24 + 54 int ret = 0;
25 +
26 + 54 ret = git_libgit2_init();
27 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 54 times.
+
+
+
54 if (ret < 0) {
28 + ✗ git_log_err("git_libgit2_init");
29 + ✗ return ret;
30 + }
31 +
32 + 54 return 0;
33 + }
34 +
35 + 54void libgit_shutdown(void) {
36 + 54 git_libgit2_shutdown();
37 + 54}
38 +
39 + 9180int libgit_clone(git_repository** repo, const char* url, const char* dir) {
40 + git_clone_options opts;
41 + 9180 int ret = 0;
42 +
43 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 log("Cloning git repository from %s to %s\n", url, dir);
44 +
45 + 9180 ret = git_clone_options_init(&opts, GIT_CLONE_OPTIONS_VERSION);
46 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0) {
47 + ✗ git_log_err("git_clone_options_init");
48 + ✗ return ret;
49 + }
50 + 9180 opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
51 +
52 + 9180 ret = git_clone(repo, url, dir, &opts);
53 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0) {
54 + ✗ git_log_err("git_clone");
55 + ✗ return ret;
56 + }
57 +
58 + 9180 return 0;
59 + }
60 +
61 + 9180int libgit_clone_to_tmp(git_repository** repo, const char* url) {
62 + 9180 char dir[] = "/tmp/git.XXXXXX";
63 +
64 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 if (!mkdtemp(dir)) {
65 + ✗ log_errno("mkdtemp");
66 + ✗ return -1;
67 + }
68 +
69 + 9180 return libgit_clone(repo, url, dir);
70 + }
71 +
72 + 9180void libgit_repository_free(git_repository* repo) {
73 + 9180 git_repository_free(repo);
74 + 9180}
75 +
76 + 9180int libgit_checkout(git_repository* repo, const char* rev) {
77 + git_checkout_options opts;
78 + git_object* obj;
79 + 9180 int ret = 0;
80 +
81 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 log("Checking out revision %s\n", rev);
82 +
83 + 9180 ret = git_revparse_single(&obj, repo, rev);
84 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0) {
85 + ✗ git_log_err("git_revparse_single");
86 + ✗ return ret;
87 + }
88 +
89 + 9180 ret = git_checkout_options_init(&opts, GIT_CHECKOUT_OPTIONS_VERSION);
90 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0) {
91 + ✗ git_log_err("git_checkout_options_init");
92 + ✗ goto free_obj;
93 + }
94 + 9180 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
95 +
96 + 9180 ret = git_checkout_tree(repo, obj, &opts);
97 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0) {
98 + ✗ git_log_err("git_checkout_tree");
99 + ✗ goto free_obj;
100 + }
101 +
102 + 9180 ret = git_repository_set_head_detached(repo, git_object_id(obj));
103 +
+ 1/2 +
+
✓ Branch 0 taken 9180 times.
+
✗ Branch 1 not taken.
+
+
+
9180 if (ret < 0) {
104 + ✗ git_log_err("git_repository_set_head_detached");
105 + ✗ goto free_obj;
106 + }
107 +
108 + 9180free_obj:
109 + 9180 git_object_free(obj);
110 +
111 + 9180 return ret;
112 + }
113 +
+
+
+
+ + + + diff --git a/coverage/index.html b/coverage/index.html new file mode 100644 index 0000000..fbe5a53 --- /dev/null +++ b/coverage/index.html @@ -0,0 +1,546 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
Date:2026-10-15 10:49:27
Coverage: + low: ≥ 0% + medium: ≥ 75.0% + high: ≥ 90.0% +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:2021284571.0%
Functions:28129495.6%
Branches:560140939.7%
+
+
+ +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileLinesFunctionsBranches
+ base64.c + + 66.7 + 66.7%18 / 27100.0%2 / 225.0%3 / 12
+ buf.c + + 88.9 + 88.9%16 / 18100.0%5 / 525.0%1 / 4
+ ci.c + + 78.7 + 78.7%37 / 47100.0%5 / 550.0%9 / 18
+ client.c + + 80.6 + 80.6%50 / 62100.0%4 / 456.7%17 / 30
+ client_main.c + + 79.1 + 79.1%34 / 43100.0%4 / 471.4%10 / 14
+ cmd_line.c + + 87.5 + 87.5%28 / 32100.0%5 / 550.0%7 / 14
+ command.c + + 74.2 + 74.2%89 / 12091.7%11 / 1250.0%33 / 66
+ event_loop.c + + 84.7 + 84.7%111 / 131100.0%14 / 1451.3%39 / 76
+ file.c + + 66.7 + 66.7%56 / 84100.0%8 / 838.5%20 / 52
+ git.c + + 70.9 + 70.9%39 / 55100.0%6 / 615.6%10 / 64
+ json.c + + 73.2 + 73.2%112 / 153100.0%24 / 2431.4%22 / 70
+ json_rpc.c + + 65.7 + 65.7%201 / 30694.4%34 / 3639.7%58 / 146
+ log.c + + 91.7 + 91.7%22 / 24100.0%4 / 466.7%4 / 6
+ net.c + + 62.6 + 62.6%87 / 139100.0%9 / 932.6%30 / 92
+ process.c + + 48.8 + 48.8%41 / 8462.5%5 / 823.1%12 / 52
+ protocol.c + + 68.7 + 68.7%90 / 13190.9%10 / 1150.0%24 / 48
+ run_queue.c + + 73.0 + 73.0%81 / 11193.8%15 / 1647.2%17 / 36
+ server.c + + 71.8 + 71.8%196 / 273100.0%21 / 2141.8%61 / 146
+ server_main.c + + 79.1 + 79.1%34 / 43100.0%4 / 471.4%10 / 14
+ signal.c + + 81.6 + 81.6%31 / 38100.0%8 / 850.0%5 / 10
+ sqlite.c + + 62.3 + 62.3%101 / 16285.7%18 / 2122.1%21 / 95
+ storage.c + + 75.5 + 75.5%37 / 49100.0%9 / 945.0%9 / 20
+ storage_sqlite.c + + 72.5 + 72.5%245 / 338100.0%23 / 2342.3%66 / 156
+ string.c + + 27.3 + 27.3%6 / 2250.0%1 / 218.8%3 / 16
+ tcp_server.c + + 71.3 + 71.3%87 / 122100.0%11 / 1140.9%27 / 66
+ worker.c + + 70.2 + 70.2%106 / 151100.0%9 / 943.5%27 / 62
+ worker_main.c + + 79.1 + 79.1%34 / 43100.0%4 / 471.4%10 / 14
+ worker_queue.c + + 86.5 + 86.5%32 / 3788.9%8 / 950.0%5 / 10
+
+
+ + + + diff --git a/coverage/index.json.c.9fe0913c76249e448eec3131d7e8b263.html b/coverage/index.json.c.9fe0913c76249e448eec3131d7e8b263.html new file mode 100644 index 0000000..187f009 --- /dev/null +++ b/coverage/index.json.c.9fe0913c76249e448eec3131d7e8b263.html @@ -0,0 +1,2300 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/json.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:11215373.2%
Functions:2424100.0%
Branches:227031.4%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
1 + /*
2 + * Copyright (c) 2023 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 "json.h"
9 +
10 + #include "buf.h"
11 + #include "log.h"
12 + #include "net.h"
13 +
14 + #include <json-c/json_object.h>
15 + #include <json-c/json_tokener.h>
16 +
17 + #include <errno.h>
18 + #include <stdint.h>
19 + #include <stdlib.h>
20 + #include <string.h>
21 +
22 + #define libjson_errno(fn) \
23 + do { \
24 + log_err("JSON: %s failed\n", fn); \
25 + } while (0)
26 +
27 + 110424void libjson_free(struct json_object* obj) {
28 + 110424 json_object_put(obj);
29 + 110424}
30 +
31 + 55212static const char* libjson_to_string_internal(struct json_object* obj, int flags) {
32 + 55212 const char* result = json_object_to_json_string_ext(obj, flags);
33 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 55212 times.
+
+
+
55212 if (!result) {
34 + ✗ libjson_errno("json_object_to_json_string");
35 + ✗ return NULL;
36 + }
37 + 55212 return result;
38 + }
39 +
40 + 46006const char* libjson_to_string(struct json_object* obj) {
41 + 46006 return libjson_to_string_internal(obj, JSON_C_TO_STRING_SPACED);
42 + }
43 +
44 + 9206const char* libjson_to_string_pretty(struct json_object* obj) {
45 + 9206 return libjson_to_string_internal(obj, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY);
46 + }
47 +
48 + 46006struct json_object* libjson_from_string(const char* src) {
49 + enum json_tokener_error error;
50 +
51 + 46006 struct json_object* result = json_tokener_parse_verbose(src, &error);
52 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 46006 times.
+
+
+
46006 if (!result) {
53 + ✗ libjson_errno("json_tokener_parse_verbose");
54 + ✗ log_err("JSON: parsing failed: %s\n", json_tokener_error_desc(error));
55 + ✗ return NULL;
56 + }
57 +
58 + 46006 return result;
59 + }
60 +
61 + 27618int libjson_clone(const struct json_object* obj, const char* key, struct json_object** _value) {
62 + 27618 int ret = 0;
63 +
64 + 27618 struct json_object* old_value = NULL;
65 + 27618 ret = libjson_get(obj, key, &old_value);
66 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27618 times.
+
+
+
27618 if (ret < 0)
67 + ✗ return ret;
68 +
69 + 27618 struct json_object* new_value = NULL;
70 + 27618 ret = json_object_deep_copy(old_value, &new_value, NULL);
71 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27618 times.
+
+
+
27618 if (ret < 0)
72 + ✗ return ret;
73 +
74 + 27618 *_value = new_value;
75 + 27618 return ret;
76 + }
77 +
78 + 46006int libjson_send(struct json_object* obj, int fd) {
79 + 46006 int ret = 0;
80 +
81 + 46006 const char* str = libjson_to_string(obj);
82 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 46006 times.
+
+
+
46006 if (!str)
83 + ✗ return -1;
84 +
85 + 46006 struct buf* buf = NULL;
86 + 46006 ret = buf_create_from_string(&buf, str);
87 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 46006 times.
+
+
+
46006 if (ret < 0)
88 + ✗ return ret;
89 +
90 + 46006 ret = net_send_buf(fd, buf);
91 + 46006 buf_destroy(buf);
92 + 46006 return ret;
93 + }
94 +
95 + 46006struct json_object* libjson_recv(int fd) {
96 + 46006 struct json_object* result = NULL;
97 + 46006 int ret = 0;
98 +
99 + 46006 struct buf* buf = NULL;
100 + 46006 ret = net_recv_buf(fd, &buf);
101 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 46006 times.
+
+
+
46006 if (ret < 0)
102 + ✗ return NULL;
103 +
104 + 46006 result = libjson_from_string((const char*)buf_get_data(buf));
105 +
+ 1/2 +
+
✓ Branch 0 taken 46006 times.
+
✗ Branch 1 not taken.
+
+
+
46006 if (!result)
106 + ✗ goto destroy_buf;
107 +
108 + 46006destroy_buf:
109 + 46006 free((void*)buf_get_data(buf));
110 + 46006 buf_destroy(buf);
111 +
112 + 46006 return result;
113 + }
114 +
115 + 110344int libjson_new_object(struct json_object** _obj) {
116 + 110344 struct json_object* obj = json_object_new_object();
117 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 110344 times.
+
+
+
110344 if (!obj) {
118 + ✗ libjson_errno("json_object_new_object");
119 + ✗ return -1;
120 + }
121 + 110344 *_obj = obj;
122 + 110344 return 0;
123 + }
124 +
125 + 26int libjson_new_array(struct json_object** _arr) {
126 + 26 struct json_object* arr = json_object_new_array();
127 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 26 times.
+
+
+
26 if (!arr) {
128 + ✗ libjson_errno("json_object_new_array");
129 + ✗ return -1;
130 + }
131 + 26 *_arr = arr;
132 + 26 return 0;
133 + }
134 +
135 + 606620int libjson_has(const struct json_object* obj, const char* key) {
136 + 606620 return json_object_object_get_ex(obj, key, NULL);
137 + }
138 +
139 + 385956int libjson_get(const struct json_object* obj, const char* key, struct json_object** value) {
140 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 385956 times.
+
+
+
385956 if (!libjson_has(obj, key)) {
141 + ✗ log_err("JSON: key is missing: %s\n", key);
142 + ✗ return -1;
143 + }
144 +
145 + 385956 return json_object_object_get_ex(obj, key, value);
146 + }
147 +
148 + 165506int libjson_get_string(const struct json_object* obj, const char* key, const char** _value) {
149 + 165506 struct json_object* value = NULL;
150 +
151 + 165506 int ret = libjson_get(obj, key, &value);
152 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 165506 times.
+
+
+
165506 if (ret < 0)
153 + ✗ return ret;
154 +
155 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 165506 times.
+
+
+
165506 if (!json_object_is_type(value, json_type_string)) {
156 + ✗ log_err("JSON: key is not a string: %s\n", key);
157 + ✗ return -1;
158 + }
159 +
160 + 165506 *_value = json_object_get_string(value);
161 + 165506 return 0;
162 + }
163 +
164 + 27540int libjson_get_int(const struct json_object* obj, const char* key, int64_t* _value) {
165 + 27540 struct json_object* value = NULL;
166 +
167 + 27540 int ret = libjson_get(obj, key, &value);
168 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27540 times.
+
+
+
27540 if (ret < 0)
169 + ✗ return ret;
170 +
171 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 27540 times.
+
+
+
27540 if (!json_object_is_type(value, json_type_int)) {
172 + ✗ log_err("JSON: key is not an integer: %s\n", key);
173 + ✗ return -1;
174 + }
175 +
176 + 27540 errno = 0;
177 + 27540 int64_t tmp = json_object_get_int64(value);
178 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27540 times.
+
+
+
27540 if (errno) {
179 + ✗ log_err("JSON: failed to parse integer from key: %s\n", key);
180 + ✗ return -1;
181 + }
182 +
183 + 27540 *_value = tmp;
184 + 27540 return 0;
185 + }
186 +
187 + 321772static int libjson_set_internal(
188 + struct json_object* obj,
189 + const char* key,
190 + struct json_object* value,
191 + unsigned flags
192 + ) {
193 + 321772 int ret = 0;
194 +
195 + 321772 ret = json_object_object_add_ex(obj, key, value, flags);
196 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 321772 times.
+
+
+
321772 if (ret < 0) {
197 + ✗ libjson_errno("json_object_object_add_ex");
198 + ✗ return ret;
199 + }
200 +
201 + 321772 return 0;
202 + }
203 +
204 + 174684static int libjson_set_string_internal(
205 + struct json_object* obj,
206 + const char* key,
207 + const char* _value,
208 + unsigned flags
209 + ) {
210 + 174684 struct json_object* value = json_object_new_string(_value);
211 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 174684 times.
+
+
+
174684 if (!value) {
212 + ✗ libjson_errno("json_object_new_string");
213 + ✗ return -1;
214 + }
215 +
216 + 174684 int ret = libjson_set_internal(obj, key, value, flags);
217 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 174684 times.
+
+
+
174684 if (ret < 0)
218 + ✗ goto free_value;
219 +
220 + 174684 return ret;
221 +
222 + ✗free_value:
223 + ✗ json_object_put(value);
224 +
225 + ✗ return ret;
226 + }
227 +
228 + 64312static int libjson_set_int_internal(
229 + struct json_object* obj,
230 + const char* key,
231 + int64_t _value,
232 + unsigned flags
233 + ) {
234 + 64312 struct json_object* value = json_object_new_int64(_value);
235 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 64312 times.
+
+
+
64312 if (!value) {
236 + ✗ libjson_errno("json_object_new_int");
237 + ✗ return -1;
238 + }
239 +
240 + 64312 int ret = libjson_set_internal(obj, key, value, flags);
241 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 64312 times.
+
+
+
64312 if (ret < 0)
242 + ✗ goto free_value;
243 +
244 + 64312 return ret;
245 +
246 + ✗free_value:
247 + ✗ json_object_put(value);
248 +
249 + ✗ return ret;
250 + }
251 +
252 + 55158int libjson_set(struct json_object* obj, const char* key, struct json_object* value) {
253 + 55158 return libjson_set_internal(obj, key, value, 0);
254 + }
255 +
256 + 45900int libjson_set_string(struct json_object* obj, const char* key, const char* value) {
257 + 45900 return libjson_set_string_internal(obj, key, value, 0);
258 + }
259 +
260 + 27540int libjson_set_int(struct json_object* obj, const char* key, int64_t value) {
261 + 27540 return libjson_set_int_internal(obj, key, value, 0);
262 + }
263 +
264 + #ifndef JSON_C_OBJECT_ADD_CONSTANT_KEY
265 + #define JSON_C_OBJECT_ADD_CONSTANT_KEY JSON_C_OBJECT_KEY_IS_CONSTANT
266 + #endif
267 + static const unsigned json_const_key_flags = JSON_C_OBJECT_ADD_CONSTANT_KEY;
268 +
269 + 27618int libjson_set_const_key(struct json_object* obj, const char* key, struct json_object* value) {
270 + 27618 return libjson_set_internal(obj, key, value, json_const_key_flags);
271 + }
272 +
273 + 128784int libjson_set_string_const_key(struct json_object* obj, const char* key, const char* value) {
274 + 128784 return libjson_set_string_internal(obj, key, value, json_const_key_flags);
275 + }
276 +
277 + 36772int libjson_set_int_const_key(struct json_object* obj, const char* key, int64_t value) {
278 + 36772 return libjson_set_int_internal(obj, key, value, json_const_key_flags);
279 + }
280 +
281 + 9180int libjson_append(struct json_object* arr, struct json_object* elem) {
282 + 9180 int ret = json_object_array_add(arr, elem);
283 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0) {
284 + ✗ libjson_errno("json_object_array_add");
285 + ✗ return ret;
286 + }
287 + 9180 return ret;
288 + }
289 +
+
+
+
+ + + + diff --git a/coverage/index.json_rpc.c.2aeccc6679171fb423f72eef95ec01c0.html b/coverage/index.json_rpc.c.2aeccc6679171fb423f72eef95ec01c0.html new file mode 100644 index 0000000..c17cba3 --- /dev/null +++ b/coverage/index.json_rpc.c.2aeccc6679171fb423f72eef95ec01c0.html @@ -0,0 +1,4327 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/json_rpc.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:20130665.7%
Functions:343694.4%
Branches:5814639.7%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
1 + /*
2 + * Copyright (c) 2023 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 "json_rpc.h"
9 +
10 + #include "json.h"
11 + #include "log.h"
12 +
13 + #include <json-c/json_object.h>
14 +
15 + #include <stdatomic.h>
16 + #include <stdint.h>
17 + #include <stdlib.h>
18 + #include <string.h>
19 +
20 + struct jsonrpc_request {
21 + struct json_object* impl;
22 + };
23 +
24 + struct jsonrpc_response {
25 + struct json_object* impl;
26 + };
27 +
28 + static const char* const jsonrpc_key_version = "jsonrpc";
29 + static const char* const jsonrpc_key_id = "id";
30 + static const char* const jsonrpc_key_method = "method";
31 + static const char* const jsonrpc_key_params = "params";
32 +
33 + static const char* const jsonrpc_value_version = "2.0";
34 +
35 + 46006static int jsonrpc_check_version(struct json_object* obj) {
36 + 46006 const char* key = jsonrpc_key_version;
37 + 46006 const char* version = NULL;
38 +
39 + 46006 int ret = libjson_get_string(obj, key, &version);
40 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 46006 times.
+
+
+
46006 if (ret < 0)
41 + ✗ return ret;
42 +
43 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 46006 times.
+
+
+
46006 if (strcmp(version, jsonrpc_value_version)) {
44 + ✗ log_err("JSON-RPC: invalid '%s' value: %s\n", key, version);
45 + ✗ return -1;
46 + }
47 +
48 + 46006 return 0;
49 + }
50 +
51 + 64418static int jsonrpc_set_version(struct json_object* obj) {
52 + 64418 return libjson_set_string_const_key(obj, jsonrpc_key_version, jsonrpc_value_version);
53 + }
54 +
55 + static _Atomic int jsonrpc_id_counter = 1;
56 +
57 + 9206int jsonrpc_generate_request_id(void) {
58 + 9206 return jsonrpc_id_counter++;
59 + }
60 +
61 + 18412static int jsonrpc_check_id_type(struct json_object* id) {
62 +
+ 2/4 +
+
✓ Branch 1 taken 18412 times.
+
✗ Branch 2 not taken.
+
✗ Branch 4 not taken.
+
✓ Branch 5 taken 18412 times.
+
+
+
18412 if (!json_object_is_type(id, json_type_string) && !json_object_is_type(id, json_type_int)) {
63 + ✗ log_err("JSON-RPC: key '%s' must be either an integer or a string\n", jsonrpc_key_id);
64 + ✗ return -1;
65 + }
66 + 18412 return 0;
67 + }
68 +
69 + 46006static int jsonrpc_check_id(struct json_object* obj, int required) {
70 + 46006 const char* key = jsonrpc_key_id;
71 +
72 +
+ 2/2 +
+
✓ Branch 1 taken 27594 times.
+
✓ Branch 2 taken 18412 times.
+
+
+
46006 if (!libjson_has(obj, key)) {
73 +
+ 1/2 +
+
✓ Branch 0 taken 27594 times.
+
✗ Branch 1 not taken.
+
+
+
27594 if (!required)
74 + 27594 return 0;
75 + ✗ log_err("JSON-RPC: key is missing: %s\n", key);
76 + ✗ return -1;
77 + }
78 +
79 + 18412 struct json_object* id = NULL;
80 +
81 + 18412 int ret = libjson_get(obj, key, &id);
82 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 18412 times.
+
+
+
18412 if (ret < 0)
83 + ✗ return ret;
84 + 18412 return jsonrpc_check_id_type(id);
85 + }
86 +
87 + 9206static int jsonrpc_set_id(struct json_object* obj, int id) {
88 + 9206 return libjson_set_int_const_key(obj, jsonrpc_key_id, id);
89 + }
90 +
91 + 36800static int jsonrpc_check_method(struct json_object* obj) {
92 + 36800 const char* key = jsonrpc_key_method;
93 + 36800 const char* method = NULL;
94 + 36800 return libjson_get_string(obj, key, &method);
95 + }
96 +
97 + 36800static int jsonrpc_set_method(struct json_object* obj, const char* method) {
98 + 36800 return libjson_set_string_const_key(obj, jsonrpc_key_method, method);
99 + }
100 +
101 + 27540static int jsonrpc_check_params_type(struct json_object* params) {
102 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 27540 times.
+
✗ Branch 3 not taken.
+
✗ Branch 4 not taken.
+
+
+
27540 if (!json_object_is_type(params, json_type_object) &&
103 + ✗ !json_object_is_type(params, json_type_array)) {
104 + ✗ log_err("JSON-RPC: key '%s' must be either an object or an array\n", jsonrpc_key_params);
105 + ✗ return -1;
106 + }
107 + 27540 return 0;
108 + }
109 +
110 + 36800static int jsonrpc_check_params(struct json_object* obj) {
111 + 36800 const char* key = jsonrpc_key_params;
112 +
113 +
+ 2/2 +
+
✓ Branch 1 taken 9260 times.
+
✓ Branch 2 taken 27540 times.
+
+
+
36800 if (!libjson_has(obj, key))
114 + 9260 return 0;
115 +
116 + 27540 struct json_object* params = NULL;
117 +
118 + 27540 int ret = libjson_get(obj, key, &params);
119 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27540 times.
+
+
+
27540 if (ret < 0)
120 + ✗ return ret;
121 + 27540 return jsonrpc_check_params_type(params);
122 + }
123 +
124 + ✗static int jsonrpc_set_params(struct json_object* obj, struct json_object* params) {
125 + ✗ const char* key = jsonrpc_key_params;
126 +
127 + ✗ int ret = jsonrpc_check_params_type(params);
128 + ✗ if (ret < 0)
129 + ✗ return ret;
130 + ✗ return libjson_set_const_key(obj, key, params);
131 + }
132 +
133 + static const char* const jsonrpc_key_result = "result";
134 + static const char* const jsonrpc_key_error = "error";
135 +
136 + static const char* const jsonrpc_key_code = "code";
137 + static const char* const jsonrpc_key_message = "message";
138 +
139 + ✗static int jsonrpc_check_error(struct json_object* obj) {
140 + ✗ const char* key = jsonrpc_key_error;
141 + ✗ struct json_object* error = NULL;
142 +
143 + ✗ int ret = libjson_get(obj, key, &error);
144 + ✗ if (ret < 0)
145 + ✗ return ret;
146 +
147 + ✗ int64_t code = -1;
148 +
149 + ✗ ret = libjson_get_int(error, jsonrpc_key_code, &code);
150 + ✗ if (ret < 0) {
151 + ✗ log_err("JSON-RPC: key is missing or not an integer: %s\n", jsonrpc_key_code);
152 + ✗ return -1;
153 + }
154 +
155 + ✗ const char* message = NULL;
156 +
157 + ✗ ret = libjson_get_string(error, jsonrpc_key_message, &message);
158 + ✗ if (ret < 0) {
159 + ✗ log_err("JSON-RPC: key is missing or not a string: %s\n", jsonrpc_key_message);
160 + ✗ return -1;
161 + }
162 +
163 + ✗ return ret;
164 + }
165 +
166 + 9206static int jsonrpc_check_result_or_error(struct json_object* obj) {
167 + 9206 const char* key_result = jsonrpc_key_result;
168 + 9206 const char* key_error = jsonrpc_key_error;
169 +
170 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9206 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
9206 if (!libjson_has(obj, key_result) && !libjson_has(obj, key_error)) {
171 + ✗ log_err("JSON-RPC: either '%s' or '%s' must be present\n", key_result, key_error);
172 + ✗ return -1;
173 + }
174 +
175 +
+ 1/2 +
+
✓ Branch 1 taken 9206 times.
+
✗ Branch 2 not taken.
+
+
+
9206 if (libjson_has(obj, key_result))
176 + 9206 return 0;
177 +
178 + ✗ return jsonrpc_check_error(obj);
179 + }
180 +
181 + 36800static int jsonrpc_request_create_internal(
182 + struct jsonrpc_request** _request,
183 + int* id,
184 + const char* method,
185 + struct json_object* params
186 + ) {
187 + 36800 int ret = 0;
188 +
189 + 36800 struct jsonrpc_request* request = malloc(sizeof(struct jsonrpc_request));
190 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (!request) {
191 + ✗ log_errno("malloc");
192 + ✗ ret = -1;
193 + ✗ goto exit;
194 + }
195 +
196 + 36800 ret = libjson_new_object(&request->impl);
197 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (ret < 0)
198 + ✗ goto free;
199 +
200 + 36800 ret = jsonrpc_set_version(request->impl);
201 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (ret < 0)
202 + ✗ goto free_impl;
203 +
204 +
+ 2/2 +
+
✓ Branch 0 taken 9206 times.
+
✓ Branch 1 taken 27594 times.
+
+
+
36800 if (id) {
205 + 9206 ret = jsonrpc_set_id(request->impl, *id);
206 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
207 + ✗ goto free_impl;
208 + }
209 +
210 + 36800 ret = jsonrpc_set_method(request->impl, method);
211 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (ret < 0)
212 + ✗ goto free_impl;
213 +
214 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (params) {
215 + ✗ ret = jsonrpc_set_params(request->impl, params);
216 + ✗ if (ret < 0)
217 + ✗ goto free_impl;
218 + }
219 +
220 + 36800 *_request = request;
221 + 36800 goto exit;
222 +
223 + ✗free_impl:
224 + ✗ libjson_free(request->impl);
225 + ✗free:
226 + ✗ free(request);
227 + 36800exit:
228 + 36800 return ret;
229 + }
230 +
231 + 9206int jsonrpc_request_create(
232 + struct jsonrpc_request** _request,
233 + int id,
234 + const char* method,
235 + struct json_object* params
236 + ) {
237 + 9206 return jsonrpc_request_create_internal(_request, &id, method, params);
238 + }
239 +
240 + 73600void jsonrpc_request_destroy(struct jsonrpc_request* request) {
241 + 73600 libjson_free(request->impl);
242 + 73600 free(request);
243 + 73600}
244 +
245 + 27594int jsonrpc_notification_create(
246 + struct jsonrpc_request** _request,
247 + const char* method,
248 + struct json_object* params
249 + ) {
250 + 27594 return jsonrpc_request_create_internal(_request, NULL, method, params);
251 + }
252 +
253 + 36800int jsonrpc_request_is_notification(const struct jsonrpc_request* request) {
254 + 36800 return !libjson_has(request->impl, jsonrpc_key_id);
255 + }
256 +
257 + 36800static int jsonrpc_request_from_json(struct jsonrpc_request** _request, struct json_object* impl) {
258 + 36800 int ret = 0;
259 +
260 + 36800 ret = jsonrpc_check_version(impl);
261 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (ret < 0)
262 + ✗ return ret;
263 + 36800 ret = jsonrpc_check_id(impl, 0);
264 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (ret < 0)
265 + ✗ return ret;
266 + 36800 ret = jsonrpc_check_method(impl);
267 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (ret < 0)
268 + ✗ return ret;
269 + 36800 ret = jsonrpc_check_params(impl);
270 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (ret < 0)
271 + ✗ return ret;
272 +
273 + 36800 struct jsonrpc_request* request = malloc(sizeof(struct jsonrpc_request));
274 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (!request) {
275 + ✗ log_errno("malloc");
276 + ✗ return -1;
277 + }
278 + 36800 request->impl = impl;
279 +
280 + 36800 *_request = request;
281 + 36800 return ret;
282 + }
283 +
284 + 36800int jsonrpc_request_send(const struct jsonrpc_request* request, int fd) {
285 + 36800 return libjson_send(request->impl, fd);
286 + }
287 +
288 + 36800int jsonrpc_request_recv(struct jsonrpc_request** request, int fd) {
289 + 36800 struct json_object* impl = libjson_recv(fd);
290 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (!impl) {
291 + ✗ log_err("JSON-RPC: failed to receive request\n");
292 + ✗ return -1;
293 + }
294 +
295 + 36800 int ret = jsonrpc_request_from_json(request, impl);
296 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (ret < 0)
297 + ✗ goto free_impl;
298 +
299 + 36800 return ret;
300 +
301 + ✗free_impl:
302 + ✗ libjson_free(impl);
303 +
304 + ✗ return ret;
305 + }
306 +
307 + 36800const char* jsonrpc_request_get_method(const struct jsonrpc_request* request) {
308 + 36800 const char* method = NULL;
309 + 36800 int ret = libjson_get_string(request->impl, jsonrpc_key_method, &method);
310 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36800 times.
+
+
+
36800 if (ret < 0) {
311 + /* Should never happen. */
312 + ✗ return NULL;
313 + }
314 + 36800 return method;
315 + }
316 +
317 + 73440static struct json_object* jsonrpc_request_create_params(struct jsonrpc_request* request) {
318 + 73440 int ret = 0;
319 + 73440 const char* const key = jsonrpc_key_params;
320 +
321 +
+ 2/2 +
+
✓ Branch 1 taken 27540 times.
+
✓ Branch 2 taken 45900 times.
+
+
+
73440 if (!libjson_has(request->impl, key)) {
322 + 27540 struct json_object* params = NULL;
323 +
324 + 27540 ret = libjson_new_object(&params);
325 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27540 times.
+
+
+
27540 if (ret < 0)
326 + ✗ return NULL;
327 +
328 + 27540 ret = libjson_set(request->impl, key, params);
329 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27540 times.
+
+
+
27540 if (ret < 0) {
330 + ✗ libjson_free(params);
331 + ✗ return NULL;
332 + }
333 + 27540 return params;
334 + }
335 +
336 + 45900 struct json_object* params = NULL;
337 + 45900 ret = libjson_get(request->impl, key, &params);
338 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 45900 times.
+
+
+
45900 if (ret < 0)
339 + ✗ return NULL;
340 + 45900 return params;
341 + }
342 +
343 + 45900int jsonrpc_request_get_param_string(
344 + const struct jsonrpc_request* request,
345 + const char* name,
346 + const char** value
347 + ) {
348 + 45900 struct json_object* params = NULL;
349 + 45900 int ret = libjson_get(request->impl, jsonrpc_key_params, &params);
350 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 45900 times.
+
+
+
45900 if (ret < 0)
351 + ✗ return ret;
352 + 45900 return libjson_get_string(params, name, value);
353 + }
354 +
355 + 45900int jsonrpc_request_set_param_string(
356 + struct jsonrpc_request* request,
357 + const char* name,
358 + const char* value
359 + ) {
360 + 45900 struct json_object* params = jsonrpc_request_create_params(request);
361 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 45900 times.
+
+
+
45900 if (!params)
362 + ✗ return -1;
363 + 45900 return libjson_set_string(params, name, value);
364 + }
365 +
366 + 27540int jsonrpc_request_get_param_int(
367 + const struct jsonrpc_request* request,
368 + const char* name,
369 + int64_t* value
370 + ) {
371 + 27540 struct json_object* params = NULL;
372 + 27540 int ret = libjson_get(request->impl, jsonrpc_key_params, &params);
373 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27540 times.
+
+
+
27540 if (ret < 0)
374 + ✗ return ret;
375 + 27540 return libjson_get_int(params, name, value);
376 + }
377 +
378 + 27540int jsonrpc_request_set_param_int(
379 + struct jsonrpc_request* request,
380 + const char* name,
381 + int64_t value
382 + ) {
383 + 27540 struct json_object* params = jsonrpc_request_create_params(request);
384 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27540 times.
+
+
+
27540 if (!params)
385 + ✗ return -1;
386 + 27540 return libjson_set_int(params, name, value);
387 + }
388 +
389 + 9206const char* jsonrpc_response_to_string(const struct jsonrpc_response* response) {
390 + 9206 return libjson_to_string_pretty(response->impl);
391 + }
392 +
393 + 27618int jsonrpc_response_create_internal(
394 + struct jsonrpc_response** _response,
395 + const struct jsonrpc_request* request,
396 + struct json_object* result,
397 + struct json_object* error
398 + ) {
399 + 27618 int ret = 0;
400 +
401 + 27618 struct jsonrpc_response* response = malloc(sizeof(struct jsonrpc_response));
402 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27618 times.
+
+
+
27618 if (!response) {
403 + ✗ log_errno("malloc");
404 + ✗ ret = -1;
405 + ✗ goto exit;
406 + }
407 +
408 + 27618 ret = libjson_new_object(&response->impl);
409 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27618 times.
+
+
+
27618 if (ret < 0)
410 + ✗ goto free;
411 +
412 + 27618 ret = jsonrpc_set_version(response->impl);
413 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27618 times.
+
+
+
27618 if (ret < 0)
414 + ✗ goto free_impl;
415 +
416 + 27618 struct json_object* id = NULL;
417 + 27618 ret = libjson_clone(request->impl, jsonrpc_key_id, &id);
418 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27618 times.
+
+
+
27618 if (ret < 0)
419 + ✗ goto free_impl;
420 +
421 + 27618 ret = libjson_set(response->impl, jsonrpc_key_id, id);
422 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27618 times.
+
+
+
27618 if (ret < 0) {
423 + ✗ libjson_free(id);
424 + ✗ goto free_impl;
425 + }
426 +
427 +
+ 2/2 +
+
✓ Branch 0 taken 9206 times.
+
✓ Branch 1 taken 18412 times.
+
+
+
27618 if (error) {
428 + 9206 ret = libjson_set_const_key(response->impl, jsonrpc_key_error, error);
429 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
430 + ✗ goto free_impl;
431 + } else {
432 + 18412 ret = libjson_set_const_key(response->impl, jsonrpc_key_result, result);
433 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 18412 times.
+
+
+
18412 if (ret < 0)
434 + ✗ goto free_impl;
435 + }
436 +
437 + 27618 *_response = response;
438 + 27618 goto exit;
439 +
440 + ✗free_impl:
441 + ✗ libjson_free(response->impl);
442 + ✗free:
443 + ✗ free(response);
444 + 27618exit:
445 + 27618 return ret;
446 + }
447 +
448 + 18412int jsonrpc_response_create(
449 + struct jsonrpc_response** response,
450 + const struct jsonrpc_request* request,
451 + struct json_object* result
452 + ) {
453 + 18412 return jsonrpc_response_create_internal(response, request, result, NULL);
454 + }
455 +
456 + 36824void jsonrpc_response_destroy(struct jsonrpc_response* response) {
457 + 36824 libjson_free(response->impl);
458 + 36824 free(response);
459 + 36824}
460 +
461 + 9206int jsonrpc_error_create(
462 + struct jsonrpc_response** response,
463 + struct jsonrpc_request* request,
464 + int code,
465 + const char* message
466 + ) {
467 + 9206 int ret = 0;
468 + 9206 struct json_object* error = NULL;
469 +
470 + 9206 ret = libjson_new_object(&error);
471 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
472 + ✗ return ret;
473 +
474 + 9206 ret = libjson_set_int_const_key(error, jsonrpc_key_code, code);
475 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
476 + ✗ goto free;
477 + 9206 ret = libjson_set_string_const_key(error, jsonrpc_key_message, message);
478 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
479 + ✗ goto free;
480 +
481 + 9206 ret = jsonrpc_response_create_internal(response, request, NULL, error);
482 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
483 + ✗ goto free;
484 +
485 + 9206 return ret;
486 +
487 + ✗free:
488 + ✗ libjson_free(error);
489 +
490 + ✗ return ret;
491 + }
492 +
493 + 9206int jsonrpc_response_is_error(const struct jsonrpc_response* response) {
494 + 9206 return libjson_has(response->impl, jsonrpc_key_error);
495 + }
496 +
497 + 9206static int jsonrpc_response_from_json(
498 + struct jsonrpc_response** _response,
499 + struct json_object* impl
500 + ) {
501 + 9206 int ret = 0;
502 +
503 + 9206 ret = jsonrpc_check_version(impl);
504 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
505 + ✗ return ret;
506 + 9206 ret = jsonrpc_check_id(impl, 1);
507 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
508 + ✗ return ret;
509 + 9206 ret = jsonrpc_check_result_or_error(impl);
510 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
511 + ✗ return ret;
512 +
513 + 9206 struct jsonrpc_response* response = malloc(sizeof(struct jsonrpc_response));
514 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (!response) {
515 + ✗ log_errno("malloc");
516 + ✗ return -1;
517 + }
518 + 9206 response->impl = impl;
519 +
520 + 9206 *_response = response;
521 + 9206 return ret;
522 + }
523 +
524 + 9206int jsonrpc_response_send(const struct jsonrpc_response* response, int fd) {
525 + 9206 return libjson_send(response->impl, fd);
526 + }
527 +
528 + 9206int jsonrpc_response_recv(struct jsonrpc_response** response, int fd) {
529 + 9206 struct json_object* impl = libjson_recv(fd);
530 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (!impl) {
531 + ✗ log_err("JSON-RPC: failed to receive response\n");
532 + ✗ return -1;
533 + }
534 +
535 + 9206 int ret = jsonrpc_response_from_json(response, impl);
536 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9206 times.
+
+
+
9206 if (ret < 0)
537 + ✗ goto free_impl;
538 +
539 + 9206 return ret;
540 +
541 + ✗free_impl:
542 + ✗ libjson_free(impl);
543 +
544 + ✗ return ret;
545 + }
546 +
+
+
+
+ + + + diff --git a/coverage/index.log.c.47179e5db7ed3f2db741c99372ba24f3.html b/coverage/index.log.c.47179e5db7ed3f2db741c99372ba24f3.html new file mode 100644 index 0000000..210d6fe --- /dev/null +++ b/coverage/index.log.c.47179e5db7ed3f2db741c99372ba24f3.html @@ -0,0 +1,481 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/log.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:222491.7%
Functions:44100.0%
Branches:4666.7%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
1 + /*
2 + * Copyright (c) 2023 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 "log.h"
9 +
10 + #include <stdio.h>
11 + #include <sys/time.h>
12 + #include <time.h>
13 + #include <unistd.h>
14 +
15 + int g_log_lvl = LOG_LVL_INFO;
16 +
17 + 182141static inline void log_prefix_timestamp(FILE* dest) {
18 + struct timeval tv;
19 + struct tm tm;
20 + char buf[64];
21 + 182141 size_t used = 0;
22 +
23 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 182141 times.
+
+
+
182141 if (gettimeofday(&tv, NULL) < 0)
24 + ✗ return;
25 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 182141 times.
+
+
+
182141 if (!gmtime_r(&tv.tv_sec, &tm))
26 + ✗ return;
27 +
28 + 182141 buf[0] = '\0';
29 + 182141 used += strftime(buf + used, sizeof(buf) - used, "%F %T", &tm);
30 + 182141 long long msec = (long long)tv.tv_usec / 1000;
31 + 182141 used += snprintf(buf + used, sizeof(buf) - used, ".%03lld | ", msec);
32 + 182141 fprintf(dest, "%s", buf);
33 + }
34 +
35 + 182141static inline void log_prefix_thread_id(FILE* dest) {
36 + 182141 fprintf(dest, "%d | ", gettid());
37 + 182141}
38 +
39 + 696630int log_entry_start(int lvl, FILE* dest) {
40 +
+ 2/2 +
+
✓ Branch 0 taken 514489 times.
+
✓ Branch 1 taken 182141 times.
+
+
+
696630 if (lvl < g_log_lvl)
41 + 514489 return 0;
42 + 182141 flockfile(dest);
43 + 182141 log_prefix_timestamp(dest);
44 + 182141 log_prefix_thread_id(dest);
45 + 182141 return 1;
46 + }
47 +
48 + 182141void log_entry_end(FILE* dest) {
49 + 182141 funlockfile(dest);
50 + 182141}
51 +
+
+
+
+ + + + diff --git a/coverage/index.net.c.37012fce13860cefc5963f57e0f36732.html b/coverage/index.net.c.37012fce13860cefc5963f57e0f36732.html new file mode 100644 index 0000000..dea3d33 --- /dev/null +++ b/coverage/index.net.c.37012fce13860cefc5963f57e0f36732.html @@ -0,0 +1,2089 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/net.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:8713962.6%
Functions:99100.0%
Branches:309232.6%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "net.h"
9 +
10 + #include "buf.h"
11 + #include "file.h"
12 + #include "log.h"
13 +
14 + #include <netdb.h>
15 + #include <stdint.h>
16 + #include <stdlib.h>
17 + #include <string.h>
18 + #include <sys/socket.h>
19 + #include <sys/types.h>
20 + #include <unistd.h>
21 +
22 + #define gai_log_errno(ec) log_err("getaddrinfo: %s\n", gai_strerror(ec))
23 +
24 + 29int net_bind(const char* port) {
25 + static const int flags = SOCK_CLOEXEC;
26 + 29 struct addrinfo *result = NULL, *it = NULL;
27 + struct addrinfo hints;
28 + 29 int socket_fd = -1, ret = 0;
29 +
30 + 29 memset(&hints, 0, sizeof(hints));
31 + 29 hints.ai_family = AF_INET6;
32 + 29 hints.ai_socktype = SOCK_STREAM;
33 + 29 hints.ai_flags = AI_PASSIVE;
34 +
35 + 29 ret = getaddrinfo(NULL, port, &hints, &result);
36 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret) {
37 + ✗ gai_log_errno(ret);
38 + ✗ return -1;
39 + }
40 +
41 +
+ 1/2 +
+
✓ Branch 0 taken 29 times.
+
✗ Branch 1 not taken.
+
+
+
29 for (it = result; it; it = it->ai_next) {
42 + 29 socket_fd = socket(it->ai_family, it->ai_socktype | flags, it->ai_protocol);
43 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (socket_fd < 0) {
44 + ✗ log_errno("socket");
45 + ✗ continue;
46 + }
47 +
48 + static const int yes = 1;
49 + static const int no = 0;
50 +
51 +
+ 1/2 +
+
✓ Branch 0 taken 29 times.
+
✗ Branch 1 not taken.
+
+
+
29 if (it->ai_family == AF_INET6) {
52 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
+
+
29 if (setsockopt(socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)) < 0) {
53 + ✗ log_errno("setsockopt");
54 + ✗ goto close_socket;
55 + }
56 + }
57 +
58 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
+
+
29 if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
59 + ✗ log_errno("setsockopt");
60 + ✗ goto close_socket;
61 + }
62 +
63 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
+
+
29 if (bind(socket_fd, it->ai_addr, it->ai_addrlen) < 0) {
64 + ✗ log_errno("bind");
65 + ✗ goto close_socket;
66 + }
67 +
68 + 29 break;
69 +
70 + ✗ close_socket:
71 + ✗ net_close(socket_fd);
72 + }
73 +
74 + 29 freeaddrinfo(result);
75 +
76 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!it) {
77 + ✗ log_err("Couldn't bind to port %s\n", port);
78 + ✗ return -1;
79 + }
80 +
81 + 29 ret = listen(socket_fd, 4096);
82 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0) {
83 + ✗ log_errno("listen");
84 + ✗ goto fail;
85 + }
86 +
87 + 29 return socket_fd;
88 +
89 + ✗fail:
90 + ✗ net_close(socket_fd);
91 +
92 + ✗ return ret;
93 + }
94 +
95 + 27620int net_accept(int fd) {
96 + static const int flags = SOCK_CLOEXEC;
97 + 27620 int ret = 0;
98 +
99 + 27620 ret = accept4(fd, NULL, NULL, flags);
100 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27620 times.
+
+
+
27620 if (ret < 0) {
101 + ✗ log_errno("accept4");
102 + ✗ return ret;
103 + }
104 +
105 + 27620 return ret;
106 + }
107 +
108 + 27620int net_connect(const char* host, const char* port) {
109 + static const int flags = SOCK_CLOEXEC;
110 + 27620 struct addrinfo *result = NULL, *it = NULL;
111 + struct addrinfo hints;
112 + 27620 int socket_fd = -1, ret = 0;
113 +
114 + 27620 memset(&hints, 0, sizeof(hints));
115 + 27620 hints.ai_family = AF_UNSPEC;
116 + 27620 hints.ai_socktype = SOCK_STREAM;
117 +
118 + 27620 ret = getaddrinfo(host, port, &hints, &result);
119 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27620 times.
+
+
+
27620 if (ret) {
120 + ✗ gai_log_errno(ret);
121 + ✗ return -1;
122 + }
123 +
124 +
+ 1/2 +
+
✓ Branch 0 taken 27620 times.
+
✗ Branch 1 not taken.
+
+
+
27620 for (it = result; it; it = it->ai_next) {
125 + 27620 socket_fd = socket(it->ai_family, it->ai_socktype | flags, it->ai_protocol);
126 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27620 times.
+
+
+
27620 if (socket_fd < 0) {
127 + ✗ log_errno("socket");
128 + ✗ continue;
129 + }
130 +
131 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 27620 times.
+
+
+
27620 if (connect(socket_fd, it->ai_addr, it->ai_addrlen) < 0) {
132 + ✗ log_errno("connect");
133 + ✗ goto close_socket;
134 + }
135 +
136 + 27620 break;
137 +
138 + ✗ close_socket:
139 + ✗ net_close(socket_fd);
140 + }
141 +
142 + 27620 freeaddrinfo(result);
143 +
144 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27620 times.
+
+
+
27620 if (!it) {
145 + ✗ log_err("Couldn't connect to host %s, port %s\n", host, port);
146 + ✗ return -1;
147 + }
148 +
149 + 27620 return socket_fd;
150 + }
151 +
152 + 64503void net_close(int fd) {
153 + 64503 file_close(fd);
154 + 64503}
155 +
156 + 92012static ssize_t net_send_part(int fd, const void* buf, size_t size) {
157 + static const int flags = MSG_NOSIGNAL;
158 +
159 + 92012 ssize_t ret = send(fd, buf, size, flags);
160 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 92012 times.
+
+
+
92012 if (ret < 0) {
161 + ✗ log_errno("send");
162 + ✗ return -1;
163 + }
164 +
165 + 92012 return ret;
166 + }
167 +
168 + 92012int net_send(int fd, const void* buf, size_t size) {
169 + 92012 size_t sent_total = 0;
170 +
171 +
+ 2/2 +
+
✓ Branch 0 taken 92012 times.
+
✓ Branch 1 taken 92012 times.
+
+
+
184024 while (sent_total < size) {
172 + 92012 ssize_t sent_now = net_send_part(fd, (const char*)buf + sent_total, size - sent_total);
173 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 92012 times.
+
+
+
92012 if (sent_now < 0)
174 + ✗ return -1;
175 + 92012 sent_total += sent_now;
176 + }
177 +
178 + 92012 return 0;
179 + }
180 +
181 + 92012int net_recv(int fd, void* buf, size_t size) {
182 + 92012 ssize_t read_total = 0;
183 +
184 +
+ 2/2 +
+
✓ Branch 0 taken 116422 times.
+
✓ Branch 1 taken 92012 times.
+
+
+
208434 while ((size_t)read_total < size) {
185 + 116422 ssize_t read_now = read(fd, (unsigned char*)buf + read_total, size - read_total);
186 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 116422 times.
+
+
+
116422 if (!read_now)
187 + ✗ break;
188 +
189 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 116422 times.
+
+
+
116422 if (read_now < 0) {
190 + ✗ log_errno("read");
191 + ✗ return -1;
192 + }
193 +
194 + 116422 read_total += read_now;
195 + }
196 +
197 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 92012 times.
+
+
+
92012 if ((size_t)read_total < size) {
198 + ✗ log_err("Received only %zd bytes out of %zu\n", read_total, size);
199 + ✗ return -1;
200 + }
201 +
202 + 92012 return 0;
203 + }
204 +
205 + 46006int net_send_buf(int fd, const struct buf* buf) {
206 + 46006 int ret = 0;
207 +
208 + 46006 uint32_t size = htonl(buf_get_size(buf));
209 + 46006 ret = net_send(fd, &size, sizeof(size));
210 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 46006 times.
+
+
+
46006 if (ret < 0)
211 + ✗ return ret;
212 +
213 + 46006 ret = net_send(fd, buf_get_data(buf), buf_get_size(buf));
214 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 46006 times.
+
+
+
46006 if (ret < 0)
215 + ✗ return ret;
216 +
217 + 46006 return ret;
218 + }
219 +
220 + 46006int net_recv_buf(int fd, struct buf** buf) {
221 + 46006 uint32_t size = 0;
222 + 46006 int ret = 0;
223 +
224 + 46006 ret = net_recv(fd, &size, sizeof(size));
225 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 46006 times.
+
+
+
46006 if (ret < 0) {
226 + ✗ log_err("Couldn't read buffer size\n");
227 + ✗ goto fail;
228 + }
229 + 46006 size = ntohl(size);
230 +
231 + 46006 void* data = malloc(size);
232 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 46006 times.
+
+
+
46006 if (!data) {
233 + ✗ log_errno("malloc");
234 + ✗ goto fail;
235 + }
236 +
237 + 46006 ret = net_recv(fd, data, size);
238 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 46006 times.
+
+
+
46006 if (ret < 0) {
239 + ✗ log_err("Couldn't read buffer\n");
240 + ✗ goto free_data;
241 + }
242 +
243 + 46006 ret = buf_create(buf, data, size);
244 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 46006 times.
+
+
+
46006 if (ret < 0)
245 + ✗ goto free_data;
246 +
247 + 46006 return ret;
248 +
249 + ✗free_data:
250 + ✗ free(data);
251 +
252 + ✗fail:
253 + ✗ return -1;
254 + }
255 +
+
+
+
+ + + + diff --git a/coverage/index.process.c.52f9324f34485af6c2c0f7cc7bbf5f8b.html b/coverage/index.process.c.52f9324f34485af6c2c0f7cc7bbf5f8b.html new file mode 100644 index 0000000..fca98f9 --- /dev/null +++ b/coverage/index.process.c.52f9324f34485af6c2c0f7cc7bbf5f8b.html @@ -0,0 +1,1332 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/process.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:418448.8%
Functions:5862.5%
Branches:125223.1%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "process.h"
9 +
10 + #include "file.h"
11 + #include "log.h"
12 +
13 + #include <fcntl.h>
14 + #include <stdlib.h>
15 + #include <sys/wait.h>
16 + #include <unistd.h>
17 +
18 + ✗static int exec_child(const char* args[], const char* envp[]) {
19 + static const char* default_envp[] = {NULL};
20 +
21 + ✗ if (!envp)
22 + ✗ envp = default_envp;
23 +
24 + ✗ int ret = execvpe(args[0], (char* const*)args, (char* const*)envp);
25 + ✗ if (ret < 0) {
26 + ✗ log_errno("execvpe");
27 + ✗ return ret;
28 + }
29 +
30 + ✗ return ret;
31 + }
32 +
33 + 9180static int wait_for_child(pid_t pid, int* ec) {
34 + int status;
35 +
36 + 9180 pid_t ret = waitpid(pid, &status, __WNOTHREAD);
37 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0) {
38 + ✗ log_errno("waitpid");
39 + ✗ return ret;
40 + }
41 +
42 + /* The child process reports the lowest 8 bits of its exit code, which
43 + * are treated as an unsigned integer on Linux.
44 + *
45 + * If it was killed by a signal, indicate that by negating the signal
46 + * number. */
47 +
48 +
+ 2/2 +
+
✓ Branch 0 taken 9144 times.
+
✓ Branch 1 taken 36 times.
+
+
+
9180 if (WIFEXITED(status)) {
49 + 9144 *ec = WEXITSTATUS(status);
50 +
+ 1/2 +
+
✓ Branch 0 taken 36 times.
+
✗ Branch 1 not taken.
+
+
+
36 } else if (WIFSIGNALED(status)) {
51 + 36 *ec = -WTERMSIG(status);
52 + } else {
53 + ✗ log_err("This shouldn't happen: %d\n", status);
54 + ✗ *ec = 1;
55 + }
56 +
57 + 9180 return 0;
58 + }
59 +
60 + ✗int process_execute(const char* args[], const char* envp[], int* ec) {
61 + ✗ pid_t child_pid = fork();
62 + ✗ if (child_pid < 0) {
63 + ✗ log_errno("fork");
64 + ✗ return child_pid;
65 + }
66 +
67 + ✗ if (!child_pid)
68 + ✗ exit(exec_child(args, envp));
69 +
70 + ✗ return wait_for_child(child_pid, ec);
71 + }
72 +
73 + ✗static int redirect_and_exec_child(int pipe_fds[2], const char* args[], const char* envp[]) {
74 + ✗ int ret = 0;
75 +
76 + ✗ file_close(pipe_fds[0]);
77 +
78 + ✗ ret = dup2(pipe_fds[1], STDOUT_FILENO);
79 + ✗ if (ret < 0) {
80 + ✗ log_errno("dup2");
81 + ✗ return ret;
82 + }
83 +
84 + ✗ ret = dup2(pipe_fds[1], STDERR_FILENO);
85 + ✗ if (ret < 0) {
86 + ✗ log_errno("dup2");
87 + ✗ return ret;
88 + }
89 +
90 + ✗ return exec_child(args, envp);
91 + }
92 +
93 + 9180int process_execute_and_capture(
94 + const char* args[],
95 + const char* envp[],
96 + struct process_output* result
97 + ) {
98 + static const int flags = O_CLOEXEC;
99 + int pipe_fds[2];
100 + 9180 int ret = 0;
101 +
102 + 9180 ret = pipe2(pipe_fds, flags);
103 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0) {
104 + ✗ log_errno("pipe2");
105 + ✗ return -1;
106 + }
107 +
108 + 9180 pid_t child_pid = fork();
109 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (child_pid < 0) {
110 + ✗ log_errno("fork");
111 + ✗ goto close_pipe;
112 + }
113 +
114 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (!child_pid)
115 + ✗ exit(redirect_and_exec_child(pipe_fds, args, envp));
116 +
117 + 9180 file_close(pipe_fds[1]);
118 +
119 + 9180 ret = file_read(pipe_fds[0], &result->data, &result->data_size);
120 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
121 + ✗ goto close_pipe;
122 +
123 + 9180 ret = wait_for_child(child_pid, &result->ec);
124 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
125 + ✗ goto free_data;
126 +
127 + 9180 goto close_pipe;
128 +
129 + ✗free_data:
130 + ✗ free(result->data);
131 +
132 + 9180close_pipe:
133 + 9180 file_close(pipe_fds[0]);
134 + /* No errno checking here, we might've already closed the write end. */
135 + 9180 close(pipe_fds[1]);
136 +
137 + 9180 return ret;
138 + }
139 +
140 + 18360int process_output_create(struct process_output** _output) {
141 + 18360 struct process_output* output = calloc(1, sizeof(struct process_output));
142 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 18360 times.
+
+
+
18360 if (!output) {
143 + ✗ log_errno("calloc");
144 + ✗ return -1;
145 + }
146 +
147 + 18360 output->ec = 0;
148 + 18360 output->data = NULL;
149 + 18360 output->data_size = 0;
150 +
151 + 18360 *_output = output;
152 + 18360 return 0;
153 + }
154 +
155 + 18360void process_output_destroy(struct process_output* output) {
156 + 18360 free(output->data);
157 + 18360 free(output);
158 + 18360}
159 +
160 + 9180void process_output_dump(const struct process_output* output) {
161 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 log("Process exit code: %d\n", output->ec);
162 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 log("Process output: %zu bytes\n", output->data_size);
163 + 9180}
164 +
+
+
+
+ + + + diff --git a/coverage/index.protocol.c.4964764a2e677a55c2f4207a995c3ce7.html b/coverage/index.protocol.c.4964764a2e677a55c2f4207a995c3ce7.html new file mode 100644 index 0000000..666088a --- /dev/null +++ b/coverage/index.protocol.c.4964764a2e677a55c2f4207a995c3ce7.html @@ -0,0 +1,1853 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/protocol.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:9013168.7%
Functions:101190.9%
Branches:244850.0%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
1 + /*
2 + * Copyright (c) 2023 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 "protocol.h"
9 +
10 + #include "base64.h"
11 + #include "compiler.h"
12 + #include "const.h"
13 + #include "json.h"
14 + #include "json_rpc.h"
15 + #include "process.h"
16 + #include "run_queue.h"
17 +
18 + #include <stddef.h>
19 + #include <stdint.h>
20 + #include <stdlib.h>
21 +
22 + static const char* const run_key_id = "id";
23 + static const char* const run_key_url = "url";
24 + static const char* const run_key_rev = "rev";
25 +
26 + 9180int request_create_queue_run(struct jsonrpc_request** request, const struct run* run) {
27 + 9180 int ret = 0;
28 +
29 + 9180 ret = jsonrpc_request_create(request, jsonrpc_generate_request_id(), CMD_QUEUE_RUN, NULL);
30 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
31 + ✗ return ret;
32 + 9180 ret = jsonrpc_request_set_param_string(*request, run_key_url, run_get_repo_url(run));
33 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
34 + ✗ goto free_request;
35 + 9180 ret = jsonrpc_request_set_param_string(*request, run_key_rev, run_get_repo_rev(run));
36 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
37 + ✗ goto free_request;
38 +
39 + 9180 return ret;
40 +
41 + ✗free_request:
42 + ✗ jsonrpc_request_destroy(*request);
43 +
44 + ✗ return ret;
45 + }
46 +
47 + 9180int request_parse_queue_run(const struct jsonrpc_request* request, struct run** run) {
48 + 9180 int ret = 0;
49 +
50 + 9180 const char* url = NULL;
51 + 9180 ret = jsonrpc_request_get_param_string(request, run_key_url, &url);
52 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
53 + ✗ return ret;
54 + 9180 const char* rev = NULL;
55 + 9180 ret = jsonrpc_request_get_param_string(request, run_key_rev, &rev);
56 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
57 + ✗ return ret;
58 +
59 + 9180 return run_queued(run, url, rev);
60 + }
61 +
62 + 9234int request_create_new_worker(struct jsonrpc_request** request) {
63 + 9234 return jsonrpc_notification_create(request, CMD_NEW_WORKER, NULL);
64 + }
65 +
66 + ✗int request_parse_new_worker(UNUSED const struct jsonrpc_request* request) {
67 + ✗ return 0;
68 + }
69 +
70 + 9180int request_create_start_run(struct jsonrpc_request** request, const struct run* run) {
71 + 9180 int ret = 0;
72 +
73 + 9180 ret = jsonrpc_notification_create(request, CMD_START_RUN, NULL);
74 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
75 + ✗ return ret;
76 + 9180 ret = jsonrpc_request_set_param_int(*request, run_key_id, run_get_id(run));
77 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
78 + ✗ goto free_request;
79 + 9180 ret = jsonrpc_request_set_param_string(*request, run_key_url, run_get_repo_url(run));
80 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
81 + ✗ goto free_request;
82 + 9180 ret = jsonrpc_request_set_param_string(*request, run_key_rev, run_get_repo_rev(run));
83 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
84 + ✗ goto free_request;
85 +
86 + 9180 return ret;
87 +
88 + ✗free_request:
89 + ✗ jsonrpc_request_destroy(*request);
90 +
91 + ✗ return ret;
92 + }
93 +
94 + 9180int request_parse_start_run(const struct jsonrpc_request* request, struct run** run) {
95 + 9180 int ret = 0;
96 +
97 + 9180 int64_t id = 0;
98 + 9180 ret = jsonrpc_request_get_param_int(request, run_key_id, &id);
99 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
100 + ✗ return ret;
101 + 9180 const char* url = NULL;
102 + 9180 ret = jsonrpc_request_get_param_string(request, run_key_url, &url);
103 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
104 + ✗ return ret;
105 + 9180 const char* rev = NULL;
106 + 9180 ret = jsonrpc_request_get_param_string(request, run_key_rev, &rev);
107 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
108 + ✗ return ret;
109 +
110 + 9180 return run_created(run, (int)id, url, rev);
111 + }
112 +
113 + static const char* const finished_key_run_id = "run_id";
114 + static const char* const finished_key_ec = "exit_code";
115 + static const char* const finished_key_data = "output";
116 +
117 + 9180int request_create_finished_run(
118 + struct jsonrpc_request** request,
119 + int run_id,
120 + const struct process_output* output
121 + ) {
122 + 9180 int ret = 0;
123 +
124 + 9180 ret = jsonrpc_notification_create(request, CMD_FINISHED_RUN, NULL);
125 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
126 + ✗ return ret;
127 + 9180 ret = jsonrpc_request_set_param_int(*request, finished_key_run_id, run_id);
128 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
129 + ✗ goto free_request;
130 + 9180 ret = jsonrpc_request_set_param_int(*request, finished_key_ec, output->ec);
131 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
132 + ✗ goto free_request;
133 +
134 + 9180 char* b64data = NULL;
135 + 9180 ret = base64_encode(output->data, output->data_size, &b64data);
136 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
137 + ✗ goto free_request;
138 +
139 + 9180 ret = jsonrpc_request_set_param_string(*request, finished_key_data, b64data);
140 + 9180 free(b64data);
141 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
142 + ✗ goto free_request;
143 +
144 + 9180 return ret;
145 +
146 + ✗free_request:
147 + ✗ jsonrpc_request_destroy(*request);
148 +
149 + ✗ return ret;
150 + }
151 +
152 + 9180int request_parse_finished_run(
153 + const struct jsonrpc_request* request,
154 + int* _run_id,
155 + struct process_output** _output
156 + ) {
157 + 9180 int ret = 0;
158 +
159 + 9180 struct process_output* output = NULL;
160 + 9180 ret = process_output_create(&output);
161 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
162 + ✗ return ret;
163 +
164 + 9180 int64_t run_id = 0;
165 + 9180 ret = jsonrpc_request_get_param_int(request, finished_key_run_id, &run_id);
166 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
167 + ✗ goto free_output;
168 +
169 + 9180 int64_t ec = -1;
170 + 9180 ret = jsonrpc_request_get_param_int(request, finished_key_ec, &ec);
171 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
172 + ✗ goto free_output;
173 + 9180 output->ec = (int)ec;
174 +
175 + 9180 const char* b64data = NULL;
176 + 9180 ret = jsonrpc_request_get_param_string(request, finished_key_data, &b64data);
177 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
178 + ✗ goto free_output;
179 +
180 + 9180 ret = base64_decode(b64data, &output->data, &output->data_size);
181 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
182 + ✗ goto free_output;
183 +
184 + 9180 *_run_id = (int)run_id;
185 + 9180 *_output = output;
186 + 9180 return ret;
187 +
188 + ✗free_output:
189 + ✗ process_output_destroy(output);
190 +
191 + ✗ return ret;
192 + }
193 +
194 + 26int request_create_get_runs(struct jsonrpc_request** request) {
195 + 26 return jsonrpc_request_create(request, jsonrpc_generate_request_id(), CMD_GET_RUNS, NULL);
196 + }
197 +
198 + 26int request_parse_get_runs(UNUSED const struct jsonrpc_request* request) {
199 + 26 return 0;
200 + }
201 +
202 + 26int response_create_get_runs(
203 + struct jsonrpc_response** response,
204 + const struct jsonrpc_request* request,
205 + const struct run_queue* runs
206 + ) {
207 + 26 struct json_object* runs_json = NULL;
208 + 26 int ret = 0;
209 +
210 + 26 ret = run_queue_to_json(runs, &runs_json);
211 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 26 times.
+
+
+
26 if (ret < 0)
212 + ✗ return ret;
213 +
214 + 26 ret = jsonrpc_response_create(response, request, runs_json);
215 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 26 times.
+
+
+
26 if (ret < 0)
216 + ✗ goto free_json;
217 +
218 + 26 return ret;
219 +
220 + ✗free_json:
221 + ✗ libjson_free(runs_json);
222 +
223 + ✗ return ret;
224 + }
225 +
+
+
+
+ + + + diff --git a/coverage/index.run_queue.c.fdfaa39d71447cf1e7d01ff206bd91e5.html b/coverage/index.run_queue.c.fdfaa39d71447cf1e7d01ff206bd91e5.html new file mode 100644 index 0000000..0dc77ab --- /dev/null +++ b/coverage/index.run_queue.c.fdfaa39d71447cf1e7d01ff206bd91e5.html @@ -0,0 +1,1578 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/run_queue.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:8111173.0%
Functions:151693.8%
Branches:173647.2%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "run_queue.h"
9 +
10 + #include "json.h"
11 + #include "log.h"
12 +
13 + #include <json-c/json_object.h>
14 +
15 + #include <stdlib.h>
16 + #include <string.h>
17 + #include <sys/queue.h>
18 +
19 + struct run {
20 + int id;
21 + char* repo_url;
22 + char* repo_rev;
23 + int status;
24 + int exit_code;
25 +
26 + SIMPLEQ_ENTRY(run) entries;
27 + };
28 +
29 + 36720int run_new(
30 + struct run** _entry,
31 + int id,
32 + const char* _repo_url,
33 + const char* _repo_rev,
34 + enum run_status status,
35 + int exit_code
36 + ) {
37 + 36720 struct run* entry = malloc(sizeof(struct run));
38 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36720 times.
+
+
+
36720 if (!entry) {
39 + ✗ log_errno("malloc");
40 + ✗ goto fail;
41 + }
42 +
43 + 36720 char* repo_url = strdup(_repo_url);
44 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36720 times.
+
+
+
36720 if (!repo_url) {
45 + ✗ log_errno("strdup");
46 + ✗ goto free_entry;
47 + }
48 +
49 + 36720 char* repo_rev = strdup(_repo_rev);
50 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36720 times.
+
+
+
36720 if (!repo_rev) {
51 + ✗ log_errno("strdup");
52 + ✗ goto free_repo_url;
53 + }
54 +
55 + 36720 entry->id = id;
56 + 36720 entry->repo_url = repo_url;
57 + 36720 entry->repo_rev = repo_rev;
58 + 36720 entry->status = status;
59 + 36720 entry->exit_code = exit_code;
60 +
61 + 36720 *_entry = entry;
62 + 36720 return 0;
63 +
64 + ✗free_repo_url:
65 + ✗ free(repo_url);
66 +
67 + ✗free_entry:
68 + ✗ free(entry);
69 +
70 + ✗fail:
71 + ✗ return -1;
72 + }
73 +
74 + 36720void run_destroy(struct run* entry) {
75 + 36720 free(entry->repo_rev);
76 + 36720 free(entry->repo_url);
77 + 36720 free(entry);
78 + 36720}
79 +
80 + 18360int run_queued(struct run** entry, const char* repo_url, const char* repo_rev) {
81 + 18360 return run_new(entry, -1, repo_url, repo_rev, RUN_STATUS_CREATED, -1);
82 + }
83 +
84 + 9180int run_created(struct run** entry, int id, const char* repo_url, const char* repo_rev) {
85 + 9180 return run_new(entry, id, repo_url, repo_rev, RUN_STATUS_CREATED, -1);
86 + }
87 +
88 + 9180int run_to_json(const struct run* entry, struct json_object** _json) {
89 + 9180 struct json_object* json = NULL;
90 + 9180 int ret = 0;
91 +
92 + 9180 ret = libjson_new_object(&json);
93 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
94 + ✗ return -1;
95 + 9180 ret = libjson_set_int_const_key(json, "id", entry->id);
96 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
97 + ✗ goto free;
98 + 9180 ret = libjson_set_int_const_key(json, "exit_code", entry->exit_code);
99 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
100 + ✗ goto free;
101 + 9180 ret = libjson_set_string_const_key(json, "repo_url", entry->repo_url);
102 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
103 + ✗ goto free;
104 + 9180 ret = libjson_set_string_const_key(json, "repo_rev", entry->repo_rev);
105 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
106 + ✗ goto free;
107 +
108 + 9180 *_json = json;
109 + 9180 return ret;
110 +
111 + ✗free:
112 + ✗ libjson_free(json);
113 +
114 + ✗ return ret;
115 + }
116 +
117 + 45900int run_get_id(const struct run* entry) {
118 + 45900 return entry->id;
119 + }
120 +
121 + 64260const char* run_get_repo_url(const struct run* entry) {
122 + 64260 return entry->repo_url;
123 + }
124 +
125 + 36720const char* run_get_repo_rev(const struct run* entry) {
126 + 36720 return entry->repo_rev;
127 + }
128 +
129 + 9180void run_set_id(struct run* entry, int id) {
130 + 9180 entry->id = id;
131 + 9180}
132 +
133 + 55void run_queue_create(struct run_queue* queue) {
134 + 55 SIMPLEQ_INIT(queue);
135 + 55}
136 +
137 + 55void run_queue_destroy(struct run_queue* queue) {
138 + 55 struct run* entry1 = SIMPLEQ_FIRST(queue);
139 +
+ 2/2 +
+
✓ Branch 0 taken 9180 times.
+
✓ Branch 1 taken 55 times.
+
+
+
9235 while (entry1) {
140 + 9180 struct run* entry2 = SIMPLEQ_NEXT(entry1, entries);
141 + 9180 run_destroy(entry1);
142 + 9180 entry1 = entry2;
143 + }
144 + 55 SIMPLEQ_INIT(queue);
145 + 55}
146 +
147 + 26int run_queue_to_json(const struct run_queue* queue, struct json_object** _json) {
148 + 26 struct json_object* json = NULL;
149 + 26 int ret = 0;
150 +
151 + 26 ret = libjson_new_array(&json);
152 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 26 times.
+
+
+
26 if (ret < 0)
153 + ✗ return ret;
154 +
155 + 26 struct run* entry = NULL;
156 +
+ 2/2 +
+
✓ Branch 0 taken 9180 times.
+
✓ Branch 1 taken 26 times.
+
+
+
9206 SIMPLEQ_FOREACH(entry, queue, entries) {
157 + 9180 struct json_object* entry_json = NULL;
158 + 9180 ret = run_to_json(entry, &entry_json);
159 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
160 + ✗ goto free;
161 +
162 + 9180 ret = libjson_append(json, entry_json);
163 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0) {
164 + ✗ libjson_free(entry_json);
165 + ✗ goto free;
166 + }
167 + }
168 +
169 + 26 *_json = json;
170 + 26 return ret;
171 +
172 + ✗free:
173 + ✗ libjson_free(json);
174 +
175 + ✗ return ret;
176 + }
177 +
178 + 27393int run_queue_is_empty(const struct run_queue* queue) {
179 + 27393 return SIMPLEQ_EMPTY(queue);
180 + }
181 +
182 + ✗void run_queue_add_first(struct run_queue* queue, struct run* entry) {
183 + ✗ SIMPLEQ_INSERT_HEAD(queue, entry, entries);
184 + ✗}
185 +
186 + 18360void run_queue_add_last(struct run_queue* queue, struct run* entry) {
187 + 18360 SIMPLEQ_INSERT_TAIL(queue, entry, entries);
188 + 18360}
189 +
190 + 9180struct run* run_queue_remove_first(struct run_queue* queue) {
191 + 9180 struct run* entry = SIMPLEQ_FIRST(queue);
192 +
+ 2/2 +
+
✓ Branch 0 taken 77 times.
+
✓ Branch 1 taken 9103 times.
+
+
+
9180 SIMPLEQ_REMOVE_HEAD(queue, entries);
193 + 9180 return entry;
194 + }
195 +
+
+
+
+ + + + diff --git a/coverage/index.server.c.0235f01a49d01b35e981a41f59a9d2d6.html b/coverage/index.server.c.0235f01a49d01b35e981a41f59a9d2d6.html new file mode 100644 index 0000000..2d3dcee --- /dev/null +++ b/coverage/index.server.c.0235f01a49d01b35e981a41f59a9d2d6.html @@ -0,0 +1,4033 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/server.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:19627371.8%
Functions:2121100.0%
Branches:6114641.8%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "server.h"
9 +
10 + #include "command.h"
11 + #include "compiler.h"
12 + #include "const.h"
13 + #include "event_loop.h"
14 + #include "file.h"
15 + #include "json_rpc.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 + #include "storage.h"
23 + #include "storage_sqlite.h"
24 + #include "tcp_server.h"
25 + #include "worker_queue.h"
26 +
27 + #include <poll.h>
28 + #include <pthread.h>
29 + #include <stdlib.h>
30 +
31 + struct server {
32 + pthread_mutex_t server_mtx;
33 + pthread_cond_t server_cv;
34 +
35 + int stopping;
36 +
37 + struct cmd_dispatcher* cmd_dispatcher;
38 +
39 + struct event_loop* event_loop;
40 + int signalfd;
41 +
42 + struct worker_queue worker_queue;
43 + struct run_queue run_queue;
44 +
45 + struct storage storage;
46 +
47 + pthread_t main_thread;
48 +
49 + struct tcp_server* tcp_server;
50 + };
51 +
52 + 18472static int server_lock(struct server* server) {
53 + 18472 int ret = pthread_mutex_lock(&server->server_mtx);
54 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 18472 times.
+
+
+
18472 if (ret) {
55 + ✗ pthread_errno(ret, "pthread_mutex_lock");
56 + ✗ return ret;
57 + }
58 + 18472 return ret;
59 + }
60 +
61 + 18472static void server_unlock(struct server* server) {
62 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 18472 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
18472 pthread_errno_if(pthread_mutex_unlock(&server->server_mtx), "pthread_mutex_unlock");
63 + 18472}
64 +
65 + 18213static int server_wait(struct server* server) {
66 + 18213 int ret = pthread_cond_wait(&server->server_cv, &server->server_mtx);
67 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 18213 times.
+
+
+
18213 if (ret) {
68 + ✗ pthread_errno(ret, "pthread_cond_wait");
69 + ✗ return ret;
70 + }
71 + 18213 return ret;
72 + }
73 +
74 + 18443static void server_notify(struct server* server) {
75 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 18443 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
18443 pthread_errno_if(pthread_cond_signal(&server->server_cv), "pthread_cond_signal");
76 + 18443}
77 +
78 + 29static int server_set_stopping(
79 + UNUSED struct event_loop* loop,
80 + UNUSED int fd,
81 + UNUSED short revents,
82 + void* _server
83 + ) {
84 + 29 struct server* server = (struct server*)_server;
85 + 29 int ret = 0;
86 +
87 + 29 ret = server_lock(server);
88 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
89 + ✗ return ret;
90 +
91 + 29 server->stopping = 1;
92 +
93 + 29 server_notify(server);
94 + 29 server_unlock(server);
95 + 29 return ret;
96 + }
97 +
98 + 27178static int server_has_workers(const struct server* server) {
99 + 27178 return !worker_queue_is_empty(&server->worker_queue);
100 + }
101 +
102 + 9234static int server_enqueue_worker(struct server* server, struct worker* worker) {
103 + 9234 int ret = 0;
104 +
105 + 9234 ret = server_lock(server);
106 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9234 times.
+
+
+
9234 if (ret < 0)
107 + ✗ return ret;
108 +
109 + 9234 worker_queue_add_last(&server->worker_queue, worker);
110 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9234 times.
+
+
+
9234 log("Added a new worker %d to the queue\n", worker_get_fd(worker));
111 +
112 + 9234 server_notify(server);
113 + 9234 server_unlock(server);
114 + 9234 return ret;
115 + }
116 +
117 + 27393static int server_has_runs(const struct server* server) {
118 + 27393 return !run_queue_is_empty(&server->run_queue);
119 + }
120 +
121 + 9180static int server_enqueue_run(struct server* server, struct run* run) {
122 + 9180 int ret = 0;
123 +
124 + 9180 ret = storage_run_create(&server->storage, run_get_repo_url(run), run_get_repo_rev(run));
125 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
126 + ✗ return ret;
127 + 9180 run_set_id(run, ret);
128 +
129 + 9180 ret = server_lock(server);
130 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
131 + ✗ return ret;
132 +
133 + 9180 run_queue_add_last(&server->run_queue, run);
134 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 log("Added a new run %d for repository %s to the queue\n",
135 + run_get_id(run),
136 + run_get_repo_url(run));
137 +
138 + 9180 server_notify(server);
139 + 9180 server_unlock(server);
140 + 9180 return ret;
141 + }
142 +
143 + 27422static int server_ready_for_action(const struct server* server) {
144 +
+ 6/6 +
+
✓ Branch 0 taken 27393 times.
+
✓ Branch 1 taken 29 times.
+
✓ Branch 3 taken 27178 times.
+
✓ Branch 4 taken 215 times.
+
✓ Branch 6 taken 9180 times.
+
✓ Branch 7 taken 17998 times.
+
+
+
27422 return server->stopping || (server_has_runs(server) && server_has_workers(server));
145 + }
146 +
147 + 9209static int server_wait_for_action(struct server* server) {
148 + 9209 int ret = 0;
149 +
150 +
+ 2/2 +
+
✓ Branch 1 taken 18213 times.
+
✓ Branch 2 taken 9209 times.
+
+
+
27422 while (!server_ready_for_action(server)) {
151 + 18213 ret = server_wait(server);
152 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 18213 times.
+
+
+
18213 if (ret < 0)
153 + ✗ return ret;
154 + }
155 +
156 + 9209 return ret;
157 + }
158 +
159 + 9180static void server_assign_run(struct server* server) {
160 + 9180 struct run* run = run_queue_remove_first(&server->run_queue);
161 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 log("Removed run %d for repository %s from the queue\n",
162 + run_get_id(run),
163 + run_get_repo_url(run));
164 +
165 + 9180 struct worker* worker = worker_queue_remove_first(&server->worker_queue);
166 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 log("Removed worker %d from the queue\n", worker_get_fd(worker));
167 +
168 + 9180 struct jsonrpc_request* start_request = NULL;
169 + 9180 int ret = 0;
170 +
171 + 9180 ret = request_create_start_run(&start_request, run);
172 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
173 + ✗ goto exit;
174 +
175 + 9180 ret = jsonrpc_request_send(start_request, worker_get_fd(worker));
176 + 9180 jsonrpc_request_destroy(start_request);
177 +
+ 1/2 +
+
✓ Branch 0 taken 9180 times.
+
✗ Branch 1 not taken.
+
+
+
9180 if (ret < 0)
178 + ✗ goto exit;
179 +
180 + 9180exit:
181 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0) {
182 + ✗ log("Failed to assign run for repository %s to worker %d, requeueing\n",
183 + run_get_repo_url(run),
184 + worker_get_fd(worker));
185 + ✗ run_queue_add_first(&server->run_queue, run);
186 + } else {
187 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 log("Assigned run %d for repository %s to worker %d\n",
188 + run_get_id(run),
189 + run_get_repo_url(run),
190 + worker_get_fd(worker));
191 + 9180 run_destroy(run);
192 + }
193 +
194 + 9180 worker_destroy(worker);
195 + 9180}
196 +
197 + 29static void* server_main_thread(void* _server) {
198 + 29 struct server* server = (struct server*)_server;
199 + 29 int ret = 0;
200 +
201 + 29 ret = server_lock(server);
202 +
+ 1/2 +
+
✓ Branch 0 taken 29 times.
+
✗ Branch 1 not taken.
+
+
+
29 if (ret < 0)
203 + ✗ goto exit;
204 +
205 + while (1) {
206 + 9209 ret = server_wait_for_action(server);
207 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9209 times.
+
+
+
9209 if (ret < 0)
208 + ✗ goto unlock;
209 +
210 +
+ 2/2 +
+
✓ Branch 0 taken 29 times.
+
✓ Branch 1 taken 9180 times.
+
+
+
9209 if (server->stopping)
211 + 29 goto unlock;
212 +
213 + 9180 server_assign_run(server);
214 + }
215 +
216 + 29unlock:
217 + 29 server_unlock(server);
218 +
219 + 29exit:
220 + 29 return NULL;
221 + }
222 +
223 + 9234static int server_handle_cmd_new_worker(
224 + UNUSED const struct jsonrpc_request* request,
225 + UNUSED struct jsonrpc_response** response,
226 + void* _ctx
227 + ) {
228 + 9234 struct cmd_conn_ctx* ctx = (struct cmd_conn_ctx*)_ctx;
229 + 9234 struct server* server = (struct server*)ctx->arg;
230 + 9234 int ret = 0;
231 +
232 + 9234 ret = file_dup(ctx->fd);
233 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9234 times.
+
+
+
9234 if (ret < 0)
234 + ✗ return ret;
235 +
236 + 9234 const int fd = ret;
237 + 9234 struct worker* worker = NULL;
238 +
239 + 9234 ret = worker_create(&worker, fd);
240 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9234 times.
+
+
+
9234 if (ret < 0)
241 + ✗ goto close;
242 +
243 + 9234 ret = server_enqueue_worker(server, worker);
244 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9234 times.
+
+
+
9234 if (ret < 0)
245 + ✗ goto destroy_worker;
246 +
247 + 9234 return ret;
248 +
249 + ✗destroy_worker:
250 + ✗ worker_destroy(worker);
251 +
252 + ✗close:
253 + ✗ net_close(fd);
254 +
255 + ✗ return ret;
256 + }
257 +
258 + 9180static int server_handle_cmd_queue_run(
259 + const struct jsonrpc_request* request,
260 + struct jsonrpc_response** response,
261 + void* _ctx
262 + ) {
263 + 9180 struct cmd_conn_ctx* ctx = (struct cmd_conn_ctx*)_ctx;
264 + 9180 struct server* server = (struct server*)ctx->arg;
265 + 9180 int ret = 0;
266 +
267 + 9180 struct run* run = NULL;
268 +
269 + 9180 ret = request_parse_queue_run(request, &run);
270 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
271 + ✗ return ret;
272 +
273 + 9180 ret = jsonrpc_response_create(response, request, NULL);
274 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
275 + ✗ goto destroy_run;
276 +
277 + 9180 ret = server_enqueue_run(server, run);
278 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
279 + ✗ goto free_response;
280 +
281 + 9180 return ret;
282 +
283 + ✗free_response:
284 + ✗ jsonrpc_response_destroy(*response);
285 + ✗ *response = NULL;
286 +
287 + ✗destroy_run:
288 + ✗ run_destroy(run);
289 +
290 + ✗ return ret;
291 + }
292 +
293 + 9180static int server_handle_cmd_finished_run(
294 + const struct jsonrpc_request* request,
295 + UNUSED struct jsonrpc_response** response,
296 + void* _ctx
297 + ) {
298 + 9180 struct cmd_conn_ctx* ctx = (struct cmd_conn_ctx*)_ctx;
299 + 9180 struct server* server = (struct server*)ctx->arg;
300 + 9180 int ret = 0;
301 +
302 + 9180 int run_id = 0;
303 + struct process_output* output;
304 +
305 + 9180 ret = request_parse_finished_run(request, &run_id, &output);
306 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
307 + ✗ return ret;
308 +
309 + 9180 ret = storage_run_finished(&server->storage, run_id, output);
310 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0) {
311 + ✗ log_err("Failed to mark run %d as finished\n", run_id);
312 + ✗ goto free_output;
313 + }
314 +
315 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 log("Marked run %d as finished\n", run_id);
316 +
317 + 9180free_output:
318 + 9180 process_output_destroy(output);
319 +
320 + 9180 return ret;
321 + }
322 +
323 + 26static int server_handle_cmd_get_runs(
324 + const struct jsonrpc_request* request,
325 + struct jsonrpc_response** response,
326 + void* _ctx
327 + ) {
328 + 26 struct cmd_conn_ctx* ctx = (struct cmd_conn_ctx*)_ctx;
329 + 26 struct server* server = (struct server*)ctx->arg;
330 + 26 int ret = 0;
331 +
332 + 26 ret = request_parse_get_runs(request);
333 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 26 times.
+
+
+
26 if (ret < 0)
334 + ✗ return ret;
335 +
336 + struct run_queue runs;
337 +
338 + 26 ret = storage_get_runs(&server->storage, &runs);
339 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 26 times.
+
+
+
26 if (ret < 0) {
340 + ✗ log_err("Failed to fetch runs\n");
341 + ✗ return ret;
342 + }
343 +
344 + 26 ret = response_create_get_runs(response, request, &runs);
345 +
+ 1/2 +
+
✓ Branch 0 taken 26 times.
+
✗ Branch 1 not taken.
+
+
+
26 if (ret < 0)
346 + ✗ goto destroy_runs;
347 +
348 + 26destroy_runs:
349 + 26 run_queue_destroy(&runs);
350 +
351 + 26 return ret;
352 + }
353 +
354 + static struct cmd_desc commands[] = {
355 + {CMD_NEW_WORKER, server_handle_cmd_new_worker},
356 + {CMD_QUEUE_RUN, server_handle_cmd_queue_run},
357 + {CMD_FINISHED_RUN, server_handle_cmd_finished_run},
358 + {CMD_GET_RUNS, server_handle_cmd_get_runs},
359 + };
360 +
361 + static const size_t numof_commands = sizeof(commands) / sizeof(commands[0]);
362 +
363 + 29int server_create(struct server** _server, const struct settings* settings) {
364 + struct storage_settings storage_settings;
365 + 29 int ret = 0;
366 +
367 + 29 struct server* server = malloc(sizeof(struct server));
368 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!server) {
369 + ✗ log_errno("malloc");
370 + ✗ return -1;
371 + }
372 +
373 + 29 ret = pthread_mutex_init(&server->server_mtx, NULL);
374 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret) {
375 + ✗ pthread_errno(ret, "pthread_mutex_init");
376 + ✗ goto free;
377 + }
378 +
379 + 29 ret = pthread_cond_init(&server->server_cv, NULL);
380 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret) {
381 + ✗ pthread_errno(ret, "pthread_cond_init");
382 + ✗ goto destroy_mtx;
383 + }
384 +
385 + 29 server->stopping = 0;
386 +
387 + 29 ret = cmd_dispatcher_create(&server->cmd_dispatcher, commands, numof_commands, server);
388 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
389 + ✗ goto destroy_cv;
390 +
391 + 29 ret = event_loop_create(&server->event_loop);
392 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
393 + ✗ goto destroy_cmd_dispatcher;
394 +
395 + 29 ret = signalfd_create_sigterms();
396 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
397 + ✗ goto destroy_event_loop;
398 + 29 server->signalfd = ret;
399 +
400 + 29 ret = event_loop_add(server->event_loop, server->signalfd, POLLIN, server_set_stopping, server);
401 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
402 + ✗ goto close_signalfd;
403 +
404 + 29 worker_queue_create(&server->worker_queue);
405 +
406 + 29 ret = storage_sqlite_settings_create(&storage_settings, settings->sqlite_path);
407 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
408 + ✗ goto destroy_worker_queue;
409 +
410 + 29 ret = storage_create(&server->storage, &storage_settings);
411 + 29 storage_settings_destroy(&storage_settings);
412 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
413 + ✗ goto destroy_worker_queue;
414 +
415 + 29 ret = storage_get_run_queue(&server->storage, &server->run_queue);
416 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
417 + ✗ goto destroy_storage;
418 +
419 + 29 ret = tcp_server_create(
420 + &server->tcp_server,
421 + server->event_loop,
422 + 29 settings->port,
423 + cmd_dispatcher_handle_conn,
424 + 29 server->cmd_dispatcher
425 + );
426 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
427 + ✗ goto destroy_run_queue;
428 +
429 + 29 ret = pthread_create(&server->main_thread, NULL, server_main_thread, server);
430 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret) {
431 + ✗ pthread_errno(ret, "pthread_create");
432 + ✗ goto destroy_tcp_server;
433 + }
434 +
435 + 29 *_server = server;
436 + 29 return ret;
437 +
438 + ✗destroy_tcp_server:
439 + ✗ tcp_server_destroy(server->tcp_server);
440 +
441 + ✗destroy_run_queue:
442 + ✗ run_queue_destroy(&server->run_queue);
443 +
444 + ✗destroy_storage:
445 + ✗ storage_destroy(&server->storage);
446 +
447 + ✗destroy_worker_queue:
448 + ✗ worker_queue_destroy(&server->worker_queue);
449 +
450 + ✗close_signalfd:
451 + ✗ signalfd_destroy(server->signalfd);
452 +
453 + ✗destroy_event_loop:
454 + ✗ event_loop_destroy(server->event_loop);
455 +
456 + ✗destroy_cmd_dispatcher:
457 + ✗ cmd_dispatcher_destroy(server->cmd_dispatcher);
458 +
459 + ✗destroy_cv:
460 + ✗ pthread_errno_if(pthread_cond_destroy(&server->server_cv), "pthread_cond_destroy");
461 +
462 + ✗destroy_mtx:
463 + ✗ pthread_errno_if(pthread_mutex_destroy(&server->server_mtx), "pthread_mutex_destroy");
464 +
465 + ✗free:
466 + ✗ free(server);
467 +
468 + ✗ return ret;
469 + }
470 +
471 + 29void server_destroy(struct server* server) {
472 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
+
+
29 log("Shutting down\n");
473 +
474 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
29 pthread_errno_if(pthread_join(server->main_thread, NULL), "pthread_join");
475 + 29 tcp_server_destroy(server->tcp_server);
476 + 29 storage_destroy(&server->storage);
477 + 29 run_queue_destroy(&server->run_queue);
478 + 29 worker_queue_destroy(&server->worker_queue);
479 + 29 signalfd_destroy(server->signalfd);
480 + 29 event_loop_destroy(server->event_loop);
481 + 29 cmd_dispatcher_destroy(server->cmd_dispatcher);
482 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
29 pthread_errno_if(pthread_cond_destroy(&server->server_cv), "pthread_cond_destroy");
483 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
29 pthread_errno_if(pthread_mutex_destroy(&server->server_mtx), "pthread_mutex_destroy");
484 + 29 free(server);
485 + 29}
486 +
487 + 29static int server_listen_thread(struct server* server) {
488 + 29 int ret = 0;
489 +
490 +
+ 2/2 +
+
✓ Branch 0 taken 53314 times.
+
✓ Branch 1 taken 29 times.
+
+
+
53343 while (!server->stopping) {
491 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 53314 times.
+
+
+
53314 log("Waiting for new connections\n");
492 +
493 + 53314 ret = event_loop_run(server->event_loop);
494 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 53314 times.
+
+
+
53314 if (ret < 0)
495 + ✗ return ret;
496 + }
497 +
498 + 29 return 0;
499 + }
500 +
501 + 29int server_main(struct server* server) {
502 + 29 return server_listen_thread(server);
503 + }
504 +
+
+
+
+ + + + diff --git a/coverage/index.server_main.c.3ca591a47eaf0cc37ef7579efe6031fe.html b/coverage/index.server_main.c.3ca591a47eaf0cc37ef7579efe6031fe.html new file mode 100644 index 0000000..e2d243d --- /dev/null +++ b/coverage/index.server_main.c.3ca591a47eaf0cc37ef7579efe6031fe.html @@ -0,0 +1,772 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/server_main.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:344379.1%
Functions:44100.0%
Branches:101471.4%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "cmd_line.h"
9 + #include "const.h"
10 + #include "log.h"
11 + #include "server.h"
12 +
13 + #include <getopt.h>
14 + #include <unistd.h>
15 +
16 + 35static struct settings default_settings(void) {
17 + 35 struct settings settings = {
18 + .port = default_port,
19 + .sqlite_path = default_sqlite_path,
20 + };
21 + 35 return settings;
22 + }
23 +
24 + 4const char* get_usage_string(void) {
25 + 4 return "[-h|--help] [-V|--version] [-v|--verbose] [-p|--port PORT] [-s|--sqlite PATH]";
26 + }
27 +
28 + 35static int parse_settings(struct settings* settings, int argc, char* argv[]) {
29 + int opt, longind;
30 +
31 + 35 *settings = default_settings();
32 +
33 + static struct option long_options[] = {
34 + {"help", no_argument, 0, 'h'},
35 + {"version", no_argument, 0, 'V'},
36 + {"verbose", no_argument, 0, 'v'},
37 + {"port", required_argument, 0, 'p'},
38 + {"sqlite", required_argument, 0, 's'},
39 + {0, 0, 0, 0},
40 + };
41 +
42 +
+ 2/2 +
+
✓ Branch 1 taken 64 times.
+
✓ Branch 2 taken 29 times.
+
+
+
93 while ((opt = getopt_long(argc, argv, "hVvp:s:", long_options, &longind)) != -1) {
43 +
+ 5/6 +
+
✓ Branch 0 taken 2 times.
+
✓ Branch 1 taken 2 times.
+
✗ Branch 2 not taken.
+
✓ Branch 3 taken 29 times.
+
✓ Branch 4 taken 29 times.
+
✓ Branch 5 taken 2 times.
+
+
+
64 switch (opt) {
44 + 2 case 'h':
45 + 2 exit_with_usage(0);
46 + ✗ break;
47 + 2 case 'V':
48 + 2 exit_with_version();
49 + ✗ break;
50 + ✗ case 'v':
51 + ✗ g_log_lvl = LOG_LVL_DEBUG;
52 + ✗ break;
53 + 29 case 'p':
54 + 29 settings->port = optarg;
55 + 29 break;
56 + 29 case 's':
57 + 29 settings->sqlite_path = optarg;
58 + 29 break;
59 + 2 default:
60 + 2 exit_with_usage(1);
61 + ✗ break;
62 + }
63 + }
64 +
65 + 29 return 0;
66 + }
67 +
68 + 35int main(int argc, char* argv[]) {
69 + struct settings settings;
70 + 35 struct server* server = NULL;
71 + 35 int ret = 0;
72 +
73 + 35 ret = parse_settings(&settings, argc, argv);
74 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
75 + ✗ return ret;
76 +
77 + 29 ret = server_create(&server, &settings);
78 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
79 + ✗ return ret;
80 +
81 + 29 ret = server_main(server);
82 +
+ 1/2 +
+
✓ Branch 0 taken 29 times.
+
✗ Branch 1 not taken.
+
+
+
29 if (ret < 0)
83 + ✗ goto destroy_server;
84 +
85 + 29destroy_server:
86 + 29 server_destroy(server);
87 +
88 + 29 return ret;
89 + }
90 +
+
+
+
+ + + + diff --git a/coverage/index.signal.c.71d63611c8a63e0778dd598afad76dfd.html b/coverage/index.signal.c.71d63611c8a63e0778dd598afad76dfd.html new file mode 100644 index 0000000..e5a227e --- /dev/null +++ b/coverage/index.signal.c.71d63611c8a63e0778dd598afad76dfd.html @@ -0,0 +1,716 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/signal.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:313881.6%
Functions:88100.0%
Branches:51050.0%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "signal.h"
9 +
10 + #include "file.h"
11 + #include "log.h"
12 +
13 + #include <signal.h>
14 + #include <stddef.h>
15 + #include <sys/signalfd.h>
16 +
17 + static int sigterm_signals[] = {SIGINT, SIGTERM, SIGQUIT};
18 +
19 + 27703static void sigterms_mask(sigset_t* set) {
20 + 27703 sigemptyset(set);
21 +
+ 2/2 +
+
✓ Branch 0 taken 83109 times.
+
✓ Branch 1 taken 27703 times.
+
+
+
110812 for (size_t i = 0; i < sizeof(sigterm_signals) / sizeof(sigterm_signals[0]); ++i)
22 + 83109 sigaddset(set, sigterm_signals[i]);
23 + 27703}
24 +
25 + 82943static int signal_set_mask_internal(const sigset_t* new, sigset_t* old) {
26 + 82943 int ret = 0;
27 +
28 + 82943 ret = pthread_sigmask(SIG_SETMASK, new, old);
29 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 82943 times.
+
+
+
82943 if (ret) {
30 + ✗ pthread_errno(ret, "pthread_sigmask");
31 + ✗ return ret;
32 + }
33 +
34 + 82943 return ret;
35 + }
36 +
37 + 27620int signal_set_mask(const sigset_t* new) {
38 + 27620 return signal_set_mask_internal(new, NULL);
39 + }
40 +
41 + 27620int signal_block_all(sigset_t* old) {
42 + sigset_t new;
43 + 27620 sigfillset(&new);
44 + 27620 return signal_set_mask_internal(&new, old);
45 + }
46 +
47 + 27620int signal_block_sigterms(void) {
48 + sigset_t set;
49 + 27620 sigterms_mask(&set);
50 + 27620 return signal_set_mask_internal(&set, NULL);
51 + }
52 +
53 + 83int signalfd_create(const sigset_t* set) {
54 + static const int flags = SFD_CLOEXEC;
55 + sigset_t old;
56 + 83 int ret = 0;
57 +
58 + 83 ret = signal_set_mask_internal(set, &old);
59 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 83 times.
+
+
+
83 if (ret < 0)
60 + ✗ return ret;
61 +
62 + 83 ret = signalfd(-1, set, flags);
63 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 83 times.
+
+
+
83 if (ret < 0)
64 + ✗ goto restore;
65 +
66 + 83 return ret;
67 +
68 + ✗restore:
69 + ✗ signal_set_mask_internal(&old, NULL);
70 +
71 + ✗ return ret;
72 + }
73 +
74 + 83int signalfd_create_sigterms(void) {
75 + sigset_t set;
76 + 83 sigterms_mask(&set);
77 + 83 return signalfd_create(&set);
78 + }
79 +
80 + 83void signalfd_destroy(int fd) {
81 + 83 file_close(fd);
82 + 83}
83 +
+
+
+
+ + + + diff --git a/coverage/index.sqlite.c.13cf77e7262c599539f10e3be0248b3e.html b/coverage/index.sqlite.c.13cf77e7262c599539f10e3be0248b3e.html new file mode 100644 index 0000000..f072b05 --- /dev/null +++ b/coverage/index.sqlite.c.13cf77e7262c599539f10e3be0248b3e.html @@ -0,0 +1,2357 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/sqlite.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:10116262.3%
Functions:182185.7%
Branches:219522.1%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "sqlite.h"
9 +
10 + #include "compiler.h"
11 + #include "log.h"
12 +
13 + #include <sqlite3.h>
14 +
15 + #include <stddef.h>
16 + #include <stdio.h>
17 + #include <stdlib.h>
18 + #include <string.h>
19 +
20 + #define sqlite_errno(var, fn) \
21 + do { \
22 + log_err("%s: %s\n", fn, sqlite3_errstr(var)); \
23 + var = -var; \
24 + } while (0)
25 +
26 + #define sqlite_errno_if(expr, fn) \
27 + do { \
28 + int CONCAT(ret, __LINE__) = expr; \
29 + if (CONCAT(ret, __LINE__)) \
30 + sqlite_errno(CONCAT(ret, __LINE__), fn); \
31 + } while (0)
32 +
33 + 29int sqlite_init(void) {
34 + 29 int ret = 0;
35 +
36 + 29 ret = sqlite3_initialize();
37 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret) {
38 + ✗ sqlite_errno(ret, "sqlite3_initialize");
39 + ✗ return ret;
40 + }
41 +
42 + 29 return ret;
43 + }
44 +
45 + 29void sqlite_destroy(void) {
46 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
29 sqlite_errno_if(sqlite3_shutdown(), "sqlite3_shutdown");
47 + 29}
48 +
49 + 29static int sqlite_open(const char* path, sqlite3** db, int flags) {
50 + 29 int ret = 0;
51 +
52 + 29 ret = sqlite3_open_v2(path, db, flags, NULL);
53 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret) {
54 + ✗ sqlite_errno(ret, "sqlite3_open_v2");
55 + ✗ return ret;
56 + }
57 +
58 + 29 return ret;
59 + }
60 +
61 + 29int sqlite_open_rw(const char* path, sqlite3** db) {
62 + static const int flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE;
63 + 29 return sqlite_open(path, db, flags);
64 + }
65 +
66 + ✗int sqlite_open_ro(const char* path, sqlite3** db) {
67 + static const int flags = SQLITE_OPEN_READONLY;
68 + ✗ return sqlite_open(path, db, flags);
69 + }
70 +
71 + 29void sqlite_close(sqlite3* db) {
72 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
29 sqlite_errno_if(sqlite3_close(db), "sqlite3_close");
73 + 29}
74 +
75 + 58int sqlite_exec(sqlite3* db, const char* stmt, sqlite3_callback callback, void* arg) {
76 + 58 int ret = 0;
77 +
78 + 58 ret = sqlite3_exec(db, stmt, callback, arg, NULL);
79 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 58 times.
+
+
+
58 if (ret) {
80 + ✗ sqlite_errno(ret, "sqlite3_exec");
81 + ✗ return ret;
82 + }
83 +
84 + 58 return ret;
85 + }
86 +
87 + ✗int sqlite_exec_log_result(
88 + UNUSED void* arg,
89 + int numof_columns,
90 + char** values,
91 + char** column_names
92 + ) {
93 + ✗ log("Row:\n");
94 + ✗ for (int i = 0; i < numof_columns; ++i) {
95 + ✗ log("\t%s: %s\n", column_names[i], values[i]);
96 + }
97 + ✗ return 0;
98 + }
99 +
100 + 203int sqlite_prepare(sqlite3* db, const char* stmt, sqlite3_stmt** result) {
101 + 203 int ret = 0;
102 +
103 + 203 ret = sqlite3_prepare_v2(db, stmt, -1, result, NULL);
104 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 203 times.
+
+
+
203 if (ret) {
105 + ✗ sqlite_errno(ret, "sqlite3_prepare_v2");
106 + ✗ return ret;
107 + }
108 +
109 + 203 return ret;
110 + }
111 +
112 + 36775void sqlite_reset(sqlite3_stmt* stmt) {
113 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 36775 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
36775 sqlite_errno_if(sqlite3_reset(stmt), "sqlite3_reset");
114 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 36775 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
36775 sqlite_errno_if(sqlite3_clear_bindings(stmt), "sqlite3_clear_bindings");
115 + 36775}
116 +
117 + 203void sqlite_finalize(sqlite3_stmt* stmt) {
118 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 203 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
203 sqlite_errno_if(sqlite3_finalize(stmt), "sqlite3_finalize");
119 + 203}
120 +
121 + 45984int sqlite_step(sqlite3_stmt* stmt) {
122 + 45984 int ret = 0;
123 +
124 + 45984 ret = sqlite3_step(stmt);
125 +
126 +
+ 2/3 +
+
✓ Branch 0 taken 27569 times.
+
✓ Branch 1 taken 18415 times.
+
✗ Branch 2 not taken.
+
+
+
45984 switch (ret) {
127 + 27569 case SQLITE_ROW:
128 + 27569 return 1;
129 + 18415 case SQLITE_DONE:
130 + 18415 return 0;
131 +
132 + ✗ default:
133 + ✗ sqlite_errno(ret, "sqlite3_step");
134 + ✗ return ret;
135 + }
136 + }
137 +
138 + 45929int sqlite_column_int(sqlite3_stmt* stmt, int index) {
139 + 45929 return sqlite3_column_int(stmt, index);
140 + }
141 +
142 + 18360int sqlite_column_text(sqlite3_stmt* stmt, int index, char** _result) {
143 + 18360 int ret = 0;
144 +
145 + 18360 const unsigned char* value = sqlite3_column_text(stmt, index);
146 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 18360 times.
+
+
+
18360 if (!value) {
147 + ✗ ret = sqlite3_errcode(sqlite3_db_handle(stmt));
148 + ✗ if (ret) {
149 + ✗ sqlite_errno(ret, "sqlite3_column_text");
150 + ✗ return ret;
151 + }
152 +
153 + ✗ *_result = NULL;
154 + ✗ return 0;
155 + }
156 +
157 + 18360 ret = sqlite3_column_bytes(stmt, index);
158 + 18360 size_t nb = (size_t)ret;
159 +
160 + 18360 char* result = calloc(nb + 1, 1);
161 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 18360 times.
+
+
+
18360 if (!result) {
162 + ✗ log_errno("calloc");
163 + ✗ return -1;
164 + }
165 + 18360 memcpy(result, value, nb);
166 +
167 + 18360 *_result = result;
168 + 18360 return 0;
169 + }
170 +
171 + ✗int sqlite_column_blob(sqlite3_stmt* stmt, int index, unsigned char** _result) {
172 + ✗ int ret = 0;
173 +
174 + ✗ const unsigned char* value = sqlite3_column_blob(stmt, index);
175 + ✗ if (!value) {
176 + ✗ ret = sqlite3_errcode(sqlite3_db_handle(stmt));
177 + ✗ if (ret) {
178 + ✗ sqlite_errno(ret, "sqlite3_column_text");
179 + ✗ return ret;
180 + }
181 +
182 + ✗ *_result = NULL;
183 + ✗ return 0;
184 + }
185 +
186 + ✗ ret = sqlite3_column_bytes(stmt, index);
187 + ✗ size_t nb = (size_t)ret;
188 +
189 + ✗ unsigned char* result = malloc(nb);
190 + ✗ if (!result) {
191 + ✗ log_errno("malloc");
192 + ✗ return -1;
193 + }
194 + ✗ memcpy(result, value, nb);
195 +
196 + ✗ *_result = result;
197 + ✗ return 0;
198 + }
199 +
200 + 45929int sqlite_bind_int(sqlite3_stmt* stmt, int index, int value) {
201 + 45929 int ret = 0;
202 +
203 + 45929 ret = sqlite3_bind_int(stmt, index, value);
204 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 45929 times.
+
+
+
45929 if (ret) {
205 + ✗ sqlite_errno(ret, "sqlite3_bind_int");
206 + ✗ return ret;
207 + }
208 +
209 + 45929 return ret;
210 + }
211 +
212 + 27540int sqlite_bind_text(sqlite3_stmt* stmt, int index, const char* value) {
213 + 27540 int ret = 0;
214 +
215 + 27540 ret = sqlite3_bind_text(stmt, index, value, -1, SQLITE_STATIC);
216 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27540 times.
+
+
+
27540 if (ret) {
217 + ✗ sqlite_errno(ret, "sqlite3_bind_text");
218 + ✗ return ret;
219 + }
220 +
221 + 27540 return ret;
222 + }
223 +
224 + 9180int sqlite_bind_blob(sqlite3_stmt* stmt, int index, unsigned char* value, size_t nb) {
225 + 9180 int ret = 0;
226 +
227 + 9180 ret = sqlite3_bind_blob64(stmt, index, value, nb, SQLITE_STATIC);
228 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret) {
229 + ✗ sqlite_errno(ret, "sqlite3_bind_blob64");
230 + ✗ return ret;
231 + }
232 +
233 + 9180 return ret;
234 + }
235 +
236 + 29int sqlite_exec_as_transaction(sqlite3* db, const char* stmt) {
237 + static const char* const fmt = "BEGIN; %s COMMIT;";
238 + 29 int ret = 0;
239 +
240 + 29 ret = snprintf(NULL, 0, fmt, stmt);
241 + 29 size_t nb = (size_t)ret + 1;
242 + 29 ret = 0;
243 +
244 + 29 char* full_stmt = malloc(nb);
245 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!full_stmt) {
246 + ✗ log_errno("malloc");
247 + ✗ return -1;
248 + }
249 + 29 snprintf(full_stmt, nb, fmt, stmt);
250 +
251 + 29 ret = sqlite_exec(db, stmt, NULL, NULL);
252 + 29 goto free;
253 +
254 + 29free:
255 + 29 free(full_stmt);
256 +
257 + 29 return ret;
258 + }
259 +
260 + 29int sqlite_get_user_version(sqlite3* db, unsigned int* output) {
261 + static const char* const sql = "PRAGMA user_version;";
262 +
263 + 29 sqlite3_stmt* stmt = NULL;
264 + 29 int result = -1, ret = 0;
265 +
266 + 29 ret = sqlite_prepare(db, sql, &stmt);
267 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
268 + ✗ return ret;
269 + 29 ret = sqlite_step(stmt);
270 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
271 + ✗ goto finalize;
272 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!ret) {
273 + ✗ ret = -1;
274 + ✗ log_err("Failed to read database version\n");
275 + ✗ goto finalize;
276 + }
277 +
278 + 29 result = sqlite_column_int(stmt, 0);
279 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (result < 0) {
280 + ✗ log_err("Invalid database version: %d\n", result);
281 + ✗ ret = -1;
282 + ✗ goto finalize;
283 + }
284 + 29 *output = (unsigned int)result;
285 +
286 + 29 goto finalize;
287 +
288 + 29finalize:
289 + 29 sqlite_finalize(stmt);
290 +
291 + 29 return ret;
292 + }
293 +
294 + 29int sqlite_set_foreign_keys(sqlite3* db) {
295 + static const char* const sql = "PRAGMA foreign_keys = ON;";
296 + 29 return sqlite_exec(db, sql, NULL, NULL);
297 + }
298 +
+
+
+
+ + + + diff --git a/coverage/index.storage.c.96d197609feea4b630e7b775fb18af81.html b/coverage/index.storage.c.96d197609feea4b630e7b775fb18af81.html new file mode 100644 index 0000000..2b2e556 --- /dev/null +++ b/coverage/index.storage.c.96d197609feea4b630e7b775fb18af81.html @@ -0,0 +1,1032 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/storage.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:374975.5%
Functions:99100.0%
Branches:92045.0%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "storage.h"
9 +
10 + #include "log.h"
11 + #include "process.h"
12 + #include "run_queue.h"
13 + #include "storage_sqlite.h"
14 +
15 + #include <stddef.h>
16 +
17 + typedef void (*storage_settings_destroy_t)(const struct storage_settings*);
18 + typedef int (*storage_create_t)(struct storage*, const struct storage_settings*);
19 + typedef void (*storage_destroy_t)(struct storage*);
20 +
21 + typedef int (*storage_run_create_t)(struct storage*, const char* repo_url, const char* rev);
22 + typedef int (*storage_run_finished_t)(struct storage*, int repo_id, const struct process_output*);
23 +
24 + typedef int (*storage_get_runs_t)(struct storage*, struct run_queue*);
25 + typedef storage_get_runs_t storage_get_run_queue_t;
26 +
27 + struct storage_api {
28 + storage_settings_destroy_t destroy_settings;
29 + storage_create_t create;
30 + storage_destroy_t destroy;
31 +
32 + storage_run_create_t run_create;
33 + storage_run_finished_t run_finished;
34 +
35 + storage_get_runs_t get_runs;
36 + storage_get_run_queue_t get_run_queue;
37 + };
38 +
39 + static const struct storage_api apis[] = {
40 + {
41 + storage_sqlite_settings_destroy,
42 + storage_sqlite_create,
43 + storage_sqlite_destroy,
44 +
45 + storage_sqlite_run_create,
46 + storage_sqlite_run_finished,
47 +
48 + storage_sqlite_get_runs,
49 + storage_sqlite_get_run_queue,
50 + },
51 + };
52 +
53 + 18502static size_t numof_apis(void) {
54 + 18502 return sizeof(apis) / sizeof(apis[0]);
55 + }
56 +
57 + 18502static const struct storage_api* get_api(enum storage_type type) {
58 + if (type < 0)
59 + goto invalid_type;
60 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 18502 times.
+
+
+
18502 if ((size_t)type > numof_apis())
61 + ✗ goto invalid_type;
62 +
63 + 18502 return &apis[type];
64 +
65 + ✗invalid_type:
66 + ✗ log_err("Unsupported storage type: %d\n", type);
67 + ✗ return NULL;
68 + }
69 +
70 + 29void storage_settings_destroy(const struct storage_settings* settings) {
71 + 29 const struct storage_api* api = get_api(settings->type);
72 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!api)
73 + ✗ return;
74 + 29 api->destroy_settings(settings);
75 + }
76 +
77 + 29int storage_create(struct storage* storage, const struct storage_settings* settings) {
78 + 29 int ret = 0;
79 + 29 const struct storage_api* api = get_api(settings->type);
80 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!api)
81 + ✗ return -1;
82 + 29 ret = api->create(storage, settings);
83 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
84 + ✗ return ret;
85 + 29 storage->type = settings->type;
86 + 29 return ret;
87 + }
88 +
89 + 29void storage_destroy(struct storage* storage) {
90 + 29 const struct storage_api* api = get_api(storage->type);
91 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!api)
92 + ✗ return;
93 + 29 api->destroy(storage);
94 + }
95 +
96 + 9180int storage_run_create(struct storage* storage, const char* repo_url, const char* rev) {
97 + 9180 const struct storage_api* api = get_api(storage->type);
98 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (!api)
99 + ✗ return -1;
100 + 9180 return api->run_create(storage, repo_url, rev);
101 + }
102 +
103 + 9180int storage_run_finished(struct storage* storage, int run_id, const struct process_output* output) {
104 + 9180 const struct storage_api* api = get_api(storage->type);
105 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (!api)
106 + ✗ return -1;
107 + 9180 return api->run_finished(storage, run_id, output);
108 + }
109 +
110 + 26int storage_get_runs(struct storage* storage, struct run_queue* queue) {
111 + 26 const struct storage_api* api = get_api(storage->type);
112 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 26 times.
+
+
+
26 if (!api)
113 + ✗ return -1;
114 + 26 return api->get_runs(storage, queue);
115 + }
116 +
117 + 29int storage_get_run_queue(struct storage* storage, struct run_queue* queue) {
118 + 29 const struct storage_api* api = get_api(storage->type);
119 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!api)
120 + ✗ return -1;
121 + 29 return api->get_run_queue(storage, queue);
122 + }
123 +
+
+
+
+ + + + diff --git a/coverage/index.storage_sqlite.c.b44f7f73d467be85cd4227a40c11d12a.html b/coverage/index.storage_sqlite.c.b44f7f73d467be85cd4227a40c11d12a.html new file mode 100644 index 0000000..8c2f7d1 --- /dev/null +++ b/coverage/index.storage_sqlite.c.b44f7f73d467be85cd4227a40c11d12a.html @@ -0,0 +1,4270 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/storage_sqlite.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:24533872.5%
Functions:2323100.0%
Branches:6615642.3%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "storage_sqlite.h"
9 +
10 + #include "log.h"
11 + #include "process.h"
12 + #include "run_queue.h"
13 + #include "sql/sqlite_sql.h"
14 + #include "sqlite.h"
15 + #include "storage.h"
16 +
17 + #include <sqlite3.h>
18 +
19 + #include <pthread.h>
20 + #include <stdio.h>
21 + #include <stdlib.h>
22 + #include <string.h>
23 +
24 + struct storage_sqlite_settings {
25 + char* path;
26 + };
27 +
28 + 29int storage_sqlite_settings_create(struct storage_settings* settings, const char* path) {
29 + 29 struct storage_sqlite_settings* sqlite = malloc(sizeof(struct storage_sqlite_settings));
30 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!sqlite) {
31 + ✗ log_errno("malloc");
32 + ✗ return -1;
33 + }
34 +
35 + 29 sqlite->path = strdup(path);
36 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!sqlite->path) {
37 + ✗ log_errno("strdup");
38 + ✗ goto free;
39 + }
40 +
41 + 29 settings->type = STORAGE_TYPE_SQLITE;
42 + 29 settings->sqlite = sqlite;
43 + 29 return 0;
44 +
45 + ✗free:
46 + ✗ free(sqlite);
47 +
48 + ✗ return -1;
49 + }
50 +
51 + 29void storage_sqlite_settings_destroy(const struct storage_settings* settings) {
52 + 29 free(settings->sqlite->path);
53 + 29 free(settings->sqlite);
54 + 29}
55 +
56 + struct prepared_stmt {
57 + pthread_mutex_t mtx;
58 + sqlite3_stmt* impl;
59 + };
60 +
61 + 174static int prepared_stmt_init(struct prepared_stmt* stmt, sqlite3* db, const char* sql) {
62 + 174 int ret = 0;
63 +
64 + 174 ret = pthread_mutex_init(&stmt->mtx, NULL);
65 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 174 times.
+
+
+
174 if (ret) {
66 + ✗ pthread_errno(ret, "pthread_mutex_init");
67 + ✗ return ret;
68 + }
69 +
70 + 174 ret = sqlite_prepare(db, sql, &stmt->impl);
71 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 174 times.
+
+
+
174 if (ret < 0)
72 + ✗ goto destroy_mtx;
73 +
74 + 174 return ret;
75 +
76 + ✗destroy_mtx:
77 + ✗ pthread_errno_if(pthread_mutex_destroy(&stmt->mtx), "pthread_mutex_destroy");
78 +
79 + ✗ return ret;
80 + }
81 +
82 + 174static void prepared_stmt_destroy(struct prepared_stmt* stmt) {
83 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 174 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
174 pthread_errno_if(pthread_mutex_destroy(&stmt->mtx), "pthread_mutex_destroy");
84 + 174 sqlite_finalize(stmt->impl);
85 + 174}
86 +
87 + 36775static int prepared_stmt_lock(struct prepared_stmt* stmt) {
88 + 36775 int ret = pthread_mutex_lock(&stmt->mtx);
89 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 36775 times.
+
+
+
36775 if (ret) {
90 + ✗ pthread_errno(ret, "pthread_mutex_unlock");
91 + ✗ return ret;
92 + }
93 + 36775 return ret;
94 + }
95 +
96 + 36775static void prepared_stmt_unlock(struct prepared_stmt* stmt) {
97 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 36775 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
36775 pthread_errno_if(pthread_mutex_unlock(&stmt->mtx), "pthread_mutex_unlock");
98 + 36775}
99 +
100 + struct storage_sqlite {
101 + sqlite3* db;
102 +
103 + struct prepared_stmt stmt_repo_find;
104 + struct prepared_stmt stmt_repo_insert;
105 + struct prepared_stmt stmt_run_insert;
106 + struct prepared_stmt stmt_run_finished;
107 + struct prepared_stmt stmt_get_runs;
108 + struct prepared_stmt stmt_get_run_queue;
109 + };
110 +
111 + 29static int storage_sqlite_upgrade_to(struct storage_sqlite* storage, size_t version) {
112 + static const char* const fmt = "%s PRAGMA user_version = %zu;";
113 +
114 + 29 const char* script = sqlite_schemas[version];
115 + 29 int ret = 0;
116 +
117 + 29 ret = snprintf(NULL, 0, fmt, script, version + 1);
118 + 29 size_t nb = (size_t)ret + 1;
119 + 29 ret = 0;
120 +
121 + 29 char* full_script = malloc(nb);
122 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!full_script) {
123 + ✗ log_errno("malloc");
124 + ✗ return -1;
125 + }
126 + 29 snprintf(full_script, nb, fmt, script, version + 1);
127 +
128 + 29 ret = sqlite_exec_as_transaction(storage->db, full_script);
129 + 29 goto free;
130 +
131 + 29free:
132 + 29 free(full_script);
133 +
134 + 29 return ret;
135 + }
136 +
137 + 29static int storage_sqlite_upgrade_from_to(struct storage_sqlite* storage, size_t from, size_t to) {
138 + 29 int ret = 0;
139 +
140 +
+ 2/2 +
+
✓ Branch 0 taken 29 times.
+
✓ Branch 1 taken 29 times.
+
+
+
58 for (size_t i = from; i < to; ++i) {
141 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
+
+
29 log("Upgrading SQLite database from version %zu to version %zu\n", i, i + 1);
142 + 29 ret = storage_sqlite_upgrade_to(storage, i);
143 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0) {
144 + ✗ log_err("Failed to upgrade to version %zu\n", i + 1);
145 + ✗ return ret;
146 + }
147 + }
148 +
149 + 29 return ret;
150 + }
151 +
152 + 29static int storage_sqlite_upgrade(struct storage_sqlite* storage) {
153 + 29 unsigned int current_version = 0;
154 + 29 int ret = 0;
155 +
156 + 29 ret = sqlite_get_user_version(storage->db, &current_version);
157 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
158 + ✗ return ret;
159 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
+
+
29 log("SQLite database version: %u\n", current_version);
160 +
161 + 29 size_t newest_version = sizeof(sqlite_schemas) / sizeof(sqlite_schemas[0]);
162 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
+
+
29 log("Newest database version: %zu\n", newest_version);
163 +
164 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (current_version > newest_version) {
165 + ✗ log_err("Unknown database version: %u\n", current_version);
166 + ✗ return -1;
167 + }
168 +
169 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (current_version == newest_version) {
170 + ✗ log("SQLite database already at the newest version\n");
171 + ✗ return 0;
172 + }
173 +
174 + 29 return storage_sqlite_upgrade_from_to(storage, current_version, newest_version);
175 + }
176 +
177 + 29static int storage_sqlite_setup(struct storage_sqlite* storage) {
178 + 29 int ret = 0;
179 +
180 + 29 ret = sqlite_set_foreign_keys(storage->db);
181 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
182 + ✗ return ret;
183 +
184 + 29 ret = storage_sqlite_upgrade(storage);
185 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
186 + ✗ return ret;
187 +
188 + 29 return ret;
189 + }
190 +
191 + 29static int storage_sqlite_prepare_statements(struct storage_sqlite* storage) {
192 + static const char* const fmt_repo_find = "SELECT id FROM cimple_repos WHERE url = ?;";
193 + static const char* const fmt_repo_insert =
194 + "INSERT INTO cimple_repos(url) VALUES (?) ON CONFLICT(url) DO NOTHING;";
195 + static const char* const fmt_run_insert =
196 + "INSERT INTO cimple_runs(status, exit_code, output, repo_id, repo_rev) VALUES (?, -1, x'', ?, ?) RETURNING id;";
197 + static const char* const fmt_run_finished =
198 + "UPDATE cimple_runs SET status = ?, exit_code = ?, output = ? WHERE id = ?;";
199 + static const char* const fmt_get_runs =
200 + "SELECT id, status, exit_code, repo_url, repo_rev FROM cimple_runs_view ORDER BY id DESC";
201 + static const char* const fmt_get_run_queue =
202 + "SELECT id, status, exit_code, repo_url, repo_rev FROM cimple_runs_view WHERE status = ? ORDER BY id;";
203 +
204 + 29 int ret = 0;
205 +
206 + 29 ret = prepared_stmt_init(&storage->stmt_repo_find, storage->db, fmt_repo_find);
207 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
208 + ✗ return ret;
209 + 29 ret = prepared_stmt_init(&storage->stmt_repo_insert, storage->db, fmt_repo_insert);
210 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
211 + ✗ goto finalize_repo_find;
212 + 29 ret = prepared_stmt_init(&storage->stmt_run_insert, storage->db, fmt_run_insert);
213 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
214 + ✗ goto finalize_repo_insert;
215 + 29 ret = prepared_stmt_init(&storage->stmt_run_finished, storage->db, fmt_run_finished);
216 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
217 + ✗ goto finalize_run_insert;
218 + 29 ret = prepared_stmt_init(&storage->stmt_get_runs, storage->db, fmt_get_runs);
219 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
220 + ✗ goto finalize_run_finished;
221 + 29 ret = prepared_stmt_init(&storage->stmt_get_run_queue, storage->db, fmt_get_run_queue);
222 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
223 + ✗ goto finalize_get_runs;
224 +
225 + 29 return ret;
226 +
227 + ✗finalize_get_runs:
228 + ✗ prepared_stmt_destroy(&storage->stmt_get_runs);
229 + ✗finalize_run_finished:
230 + ✗ prepared_stmt_destroy(&storage->stmt_run_finished);
231 + ✗finalize_run_insert:
232 + ✗ prepared_stmt_destroy(&storage->stmt_run_insert);
233 + ✗finalize_repo_insert:
234 + ✗ prepared_stmt_destroy(&storage->stmt_repo_insert);
235 + ✗finalize_repo_find:
236 + ✗ prepared_stmt_destroy(&storage->stmt_repo_find);
237 +
238 + ✗ return ret;
239 + }
240 +
241 + 29static void storage_sqlite_finalize_statements(struct storage_sqlite* storage) {
242 + 29 prepared_stmt_destroy(&storage->stmt_get_run_queue);
243 + 29 prepared_stmt_destroy(&storage->stmt_get_runs);
244 + 29 prepared_stmt_destroy(&storage->stmt_run_finished);
245 + 29 prepared_stmt_destroy(&storage->stmt_run_insert);
246 + 29 prepared_stmt_destroy(&storage->stmt_repo_insert);
247 + 29 prepared_stmt_destroy(&storage->stmt_repo_find);
248 + 29}
249 +
250 + 29int storage_sqlite_create(struct storage* storage, const struct storage_settings* settings) {
251 + 29 int ret = 0;
252 +
253 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 29 times.
+
+
+
29 log("Using SQLite database at %s\n", settings->sqlite->path);
254 +
255 + 29 struct storage_sqlite* sqlite = malloc(sizeof(struct storage_sqlite));
256 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!sqlite) {
257 + ✗ log_errno("malloc");
258 + ✗ return -1;
259 + }
260 +
261 + 29 ret = sqlite_init();
262 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
263 + ✗ goto free;
264 + 29 ret = sqlite_open_rw(settings->sqlite->path, &sqlite->db);
265 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
266 + ✗ goto destroy;
267 + 29 ret = storage_sqlite_setup(sqlite);
268 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
269 + ✗ goto close;
270 + 29 ret = storage_sqlite_prepare_statements(sqlite);
271 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
272 + ✗ goto close;
273 +
274 + 29 storage->sqlite = sqlite;
275 + 29 return ret;
276 +
277 + ✗close:
278 + ✗ sqlite_close(storage->sqlite->db);
279 + ✗destroy:
280 + ✗ sqlite_destroy();
281 + ✗free:
282 + ✗ free(sqlite);
283 +
284 + ✗ return ret;
285 + }
286 +
287 + 29void storage_sqlite_destroy(struct storage* storage) {
288 + 29 storage_sqlite_finalize_statements(storage->sqlite);
289 + 29 sqlite_close(storage->sqlite->db);
290 + 29 sqlite_destroy();
291 + 29 free(storage->sqlite);
292 + 29}
293 +
294 + 9180static int storage_sqlite_find_repo(struct storage_sqlite* storage, const char* url) {
295 + 9180 struct prepared_stmt* stmt = &storage->stmt_repo_find;
296 + 9180 int ret = 0;
297 +
298 + 9180 ret = prepared_stmt_lock(stmt);
299 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
300 + ✗ return ret;
301 + 9180 ret = sqlite_bind_text(stmt->impl, 1, url);
302 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
303 + ✗ goto reset;
304 + 9180 ret = sqlite_step(stmt->impl);
305 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
306 + ✗ goto reset;
307 +
308 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (!ret)
309 + ✗ goto reset;
310 +
311 + 9180 ret = sqlite_column_int(stmt->impl, 0);
312 + 9180 goto reset;
313 +
314 + 9180reset:
315 + 9180 sqlite_reset(stmt->impl);
316 + 9180 prepared_stmt_unlock(stmt);
317 +
318 + 9180 return ret;
319 + }
320 +
321 + 9180static int storage_sqlite_insert_repo(struct storage_sqlite* storage, const char* url) {
322 + 9180 struct prepared_stmt* stmt = &storage->stmt_repo_insert;
323 + 9180 int ret = 0;
324 +
325 + 9180 ret = prepared_stmt_lock(stmt);
326 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
327 + ✗ return ret;
328 + 9180 ret = sqlite_bind_text(stmt->impl, 1, url);
329 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
330 + ✗ goto reset;
331 + 9180 ret = sqlite_step(stmt->impl);
332 +
+ 1/2 +
+
✓ Branch 0 taken 9180 times.
+
✗ Branch 1 not taken.
+
+
+
9180 if (ret < 0)
333 + ✗ goto reset;
334 +
335 + 9180reset:
336 + 9180 sqlite_reset(stmt->impl);
337 + 9180 prepared_stmt_unlock(stmt);
338 +
339 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
340 + ✗ return ret;
341 +
342 + 9180 return storage_sqlite_find_repo(storage, url);
343 + }
344 +
345 + 9180static int storage_sqlite_insert_run(struct storage_sqlite* storage, int repo_id, const char* rev) {
346 + 9180 struct prepared_stmt* stmt = &storage->stmt_run_insert;
347 + 9180 int ret = 0;
348 +
349 + 9180 ret = prepared_stmt_lock(stmt);
350 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
351 + ✗ return ret;
352 + 9180 ret = sqlite_bind_int(stmt->impl, 1, RUN_STATUS_CREATED);
353 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
354 + ✗ goto reset;
355 + 9180 ret = sqlite_bind_int(stmt->impl, 2, repo_id);
356 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
357 + ✗ goto reset;
358 + 9180 ret = sqlite_bind_text(stmt->impl, 3, rev);
359 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
360 + ✗ goto reset;
361 + 9180 ret = sqlite_step(stmt->impl);
362 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
363 + ✗ goto reset;
364 +
365 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (!ret) {
366 + ✗ ret = -1;
367 + ✗ log_err("Failed to insert a run\n");
368 + ✗ goto reset;
369 + }
370 +
371 + 9180 ret = sqlite_column_int(stmt->impl, 0);
372 + 9180 goto reset;
373 +
374 + 9180reset:
375 + 9180 sqlite_reset(stmt->impl);
376 + 9180 prepared_stmt_unlock(stmt);
377 +
378 + 9180 return ret;
379 + }
380 +
381 + 9180int storage_sqlite_run_create(struct storage* storage, const char* repo_url, const char* rev) {
382 + 9180 int ret = 0;
383 +
384 + 9180 ret = storage_sqlite_insert_repo(storage->sqlite, repo_url);
385 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
386 + ✗ return ret;
387 +
388 + 9180 ret = storage_sqlite_insert_run(storage->sqlite, ret, rev);
389 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
390 + ✗ return ret;
391 +
392 + 9180 return ret;
393 + }
394 +
395 + 9180int storage_sqlite_run_finished(
396 + struct storage* storage,
397 + int run_id,
398 + const struct process_output* output
399 + ) {
400 + 9180 struct prepared_stmt* stmt = &storage->sqlite->stmt_run_finished;
401 + 9180 int ret = 0;
402 +
403 + 9180 ret = prepared_stmt_lock(stmt);
404 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
405 + ✗ return ret;
406 + 9180 ret = sqlite_bind_int(stmt->impl, 1, RUN_STATUS_FINISHED);
407 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
408 + ✗ goto reset;
409 + 9180 ret = sqlite_bind_int(stmt->impl, 2, output->ec);
410 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
411 + ✗ goto reset;
412 + 9180 ret = sqlite_bind_blob(stmt->impl, 3, output->data, output->data_size);
413 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
414 + ✗ goto reset;
415 + 9180 ret = sqlite_bind_int(stmt->impl, 4, run_id);
416 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
417 + ✗ goto reset;
418 + 9180 ret = sqlite_step(stmt->impl);
419 +
+ 1/2 +
+
✓ Branch 0 taken 9180 times.
+
✗ Branch 1 not taken.
+
+
+
9180 if (ret < 0)
420 + ✗ goto reset;
421 +
422 + 9180reset:
423 + 9180 sqlite_reset(stmt->impl);
424 + 9180 prepared_stmt_unlock(stmt);
425 +
426 + 9180 return ret;
427 + }
428 +
429 + 9180static int storage_sqlite_row_to_run(struct sqlite3_stmt* stmt, struct run** run) {
430 + 9180 int ret = 0;
431 +
432 + 9180 int id = sqlite_column_int(stmt, 0);
433 + 9180 int status = sqlite_column_int(stmt, 1);
434 + 9180 int exit_code = sqlite_column_int(stmt, 2);
435 +
436 + 9180 char* url = NULL;
437 + 9180 ret = sqlite_column_text(stmt, 3, &url);
438 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
439 + ✗ return ret;
440 +
441 + 9180 char* rev = NULL;
442 + 9180 ret = sqlite_column_text(stmt, 4, &rev);
443 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
444 + ✗ goto free_url;
445 +
446 + 9180 ret = run_new(run, id, url, rev, status, exit_code);
447 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
448 + ✗ goto free_rev;
449 +
450 +
+ 1/2 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 9180 times.
+
+
+
9180 log("Adding run %d for repository %s to the queue\n", id, url);
451 +
452 + 9180free_rev:
453 + 9180 free(rev);
454 +
455 + 9180free_url:
456 + 9180 free(url);
457 +
458 + 9180 return ret;
459 + }
460 +
461 + 55static int storage_sqlite_rows_to_runs(struct sqlite3_stmt* stmt, struct run_queue* queue) {
462 + 55 int ret = 0;
463 +
464 + 55 run_queue_create(queue);
465 +
466 + 9180 while (1) {
467 + 9235 ret = sqlite_step(stmt);
468 +
+ 2/2 +
+
✓ Branch 0 taken 55 times.
+
✓ Branch 1 taken 9180 times.
+
+
+
9235 if (!ret)
469 + 55 break;
470 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
471 + ✗ goto run_queue_destroy;
472 +
473 + 9180 struct run* run = NULL;
474 +
475 + 9180 ret = storage_sqlite_row_to_run(stmt, &run);
476 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9180 times.
+
+
+
9180 if (ret < 0)
477 + ✗ goto run_queue_destroy;
478 +
479 + 9180 run_queue_add_last(queue, run);
480 + }
481 +
482 + 55 return ret;
483 +
484 + ✗run_queue_destroy:
485 + ✗ run_queue_destroy(queue);
486 +
487 + ✗ return ret;
488 + }
489 +
490 + 26int storage_sqlite_get_runs(struct storage* storage, struct run_queue* queue) {
491 + 26 struct prepared_stmt* stmt = &storage->sqlite->stmt_get_runs;
492 + 26 int ret = 0;
493 +
494 + 26 ret = prepared_stmt_lock(stmt);
495 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 26 times.
+
+
+
26 if (ret < 0)
496 + ✗ return ret;
497 + 26 ret = storage_sqlite_rows_to_runs(stmt->impl, queue);
498 +
+ 1/2 +
+
✓ Branch 0 taken 26 times.
+
✗ Branch 1 not taken.
+
+
+
26 if (ret < 0)
499 + ✗ goto reset;
500 +
501 + 26reset:
502 + 26 sqlite_reset(stmt->impl);
503 + 26 prepared_stmt_unlock(stmt);
504 +
505 + 26 return ret;
506 + }
507 +
508 + 29int storage_sqlite_get_run_queue(struct storage* storage, struct run_queue* queue) {
509 + 29 struct prepared_stmt* stmt = &storage->sqlite->stmt_get_run_queue;
510 + 29 int ret = 0;
511 +
512 + 29 ret = prepared_stmt_lock(stmt);
513 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
514 + ✗ return ret;
515 + 29 ret = sqlite_bind_int(stmt->impl, 1, RUN_STATUS_CREATED);
516 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
517 + ✗ goto reset;
518 + 29 ret = storage_sqlite_rows_to_runs(stmt->impl, queue);
519 +
+ 1/2 +
+
✓ Branch 0 taken 29 times.
+
✗ Branch 1 not taken.
+
+
+
29 if (ret < 0)
520 + ✗ goto reset;
521 +
522 + 29reset:
523 + 29 sqlite_reset(stmt->impl);
524 + 29 prepared_stmt_unlock(stmt);
525 +
526 + 29 return ret;
527 + }
528 +
+
+
+
+ + + + diff --git a/coverage/index.string.c.2a75186e465ffeac1b306a350f4a56f8.html b/coverage/index.string.c.2a75186e465ffeac1b306a350f4a56f8.html new file mode 100644 index 0000000..e7b148e --- /dev/null +++ b/coverage/index.string.c.2a75186e465ffeac1b306a350f4a56f8.html @@ -0,0 +1,479 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/string.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:62227.3%
Functions:1250.0%
Branches:31618.8%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
1 + /*
2 + * Copyright (c) 2023 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 "string.h"
9 +
10 + #include "log.h"
11 +
12 + #include <errno.h>
13 + #include <stdlib.h>
14 + #include <string.h>
15 +
16 + /* glibc calls this stpecpy; it's not provided by glibc; however, it does
17 + * provide a possible implementation in string_copying(7), which I copied from. */
18 + 295315char* string_append(char* dst, char* end, const char* src) {
19 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 295315 times.
+
+
+
295315 if (!dst)
20 + ✗ return NULL;
21 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 295315 times.
+
+
+
295315 if (dst == end)
22 + ✗ return end;
23 +
24 + 295315 char* p = memccpy(dst, src, '\0', end - dst);
25 +
+ 1/2 +
+
✓ Branch 0 taken 295315 times.
+
✗ Branch 1 not taken.
+
+
+
295315 if (p)
26 + 295315 return p - 1;
27 +
28 + ✗ end[-1] = '\0';
29 + ✗ return end;
30 + }
31 +
32 + ✗int string_to_int(const char* src, int* result) {
33 + ✗ char* endptr = NULL;
34 +
35 + ✗ errno = 0;
36 + ✗ long ret = strtol(src, &endptr, 10);
37 +
38 + ✗ if (errno) {
39 + ✗ log_errno("strtol");
40 + ✗ return -1;
41 + }
42 +
43 + ✗ if (endptr == src || *endptr != '\0') {
44 + ✗ log_err("Invalid number: %s\n", src);
45 + ✗ return -1;
46 + }
47 +
48 + ✗ *result = (int)ret;
49 + ✗ return 0;
50 + }
51 +
+
+
+
+ + + + diff --git a/coverage/index.tcp_server.c.68fbb5aebb39dbc263f5110d228c9b35.html b/coverage/index.tcp_server.c.68fbb5aebb39dbc263f5110d228c9b35.html new file mode 100644 index 0000000..1279471 --- /dev/null +++ b/coverage/index.tcp_server.c.68fbb5aebb39dbc263f5110d228c9b35.html @@ -0,0 +1,2304 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/tcp_server.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:8712271.3%
Functions:1111100.0%
Branches:276640.9%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "tcp_server.h"
9 +
10 + #include "compiler.h"
11 + #include "event_loop.h"
12 + #include "file.h"
13 + #include "log.h"
14 + #include "net.h"
15 + #include "signal.h"
16 +
17 + #include <poll.h>
18 + #include <pthread.h>
19 + #include <signal.h>
20 + #include <stdlib.h>
21 + #include <sys/eventfd.h>
22 + #include <sys/queue.h>
23 + #include <unistd.h>
24 +
25 + /*
26 + * This is a simple threaded TCP server implementation. Each client is handled
27 + * in a separate thread.
28 + *
29 + * It used to be much simpler; basically, we have two types of client
30 + * connections: those made by cimple-worker and cimple-client respectively.
31 + * cimple-server would keep track of cimple-worker threads/connections, and
32 + * clean them up when assigning tasks/on shutdown.
33 + *
34 + * What about cimple-client connections though? I struggled to come up with a
35 + * scheme that would allow cimple-server to clean them up gracefully. When
36 + * would it do the cleanup even? I didn't want to do it on shutdown, since
37 + * there would be potentially a lot of them.
38 + *
39 + * One solution is to make client threads detached. This is a common advise;
40 + * I really don't understand the merit of this approach though. Client threads
41 + * actively work on shared data, take locks, etc. Data corruption is very
42 + * likely after the main thread exits and all the rest are killed.
43 + *
44 + * Another approach is pre-threading; we make a number of threads beforehand
45 + * and handle all client connections; I view this approach as limiting in
46 + * principle; probably that's foolish of me.
47 + *
48 + * Finally, I cannot bring myself to do non-blocking I/O. I honestly fear the
49 + * amount of work it would require to maintain read buffers, etc.
50 + *
51 + * So I came up with this convoluted scheme. The TCP server adds the listening
52 + * socket to the event loop, as before. Each client thread makes an eventfd
53 + * descriptor that it writes to when it's about to finish. The eventfd
54 + * descriptor is added to the event loop; once it's readable, we clean up the
55 + * client thread quickly from the main event loop thread. The TCP server itself
56 + * keeps track of client threads; on shutdown, it cleans up those still working.
57 + *
58 + * I'm _really_ not sure about this approach, it seems fishy as hell; I guess,
59 + * we'll see.
60 + */
61 +
62 + struct client {
63 + struct tcp_server* server;
64 + int conn_fd;
65 +
66 + int cleanup_fd;
67 +
68 + pid_t tid;
69 + pthread_t thread;
70 +
71 + SIMPLEQ_ENTRY(client) entries;
72 + };
73 +
74 + SIMPLEQ_HEAD(client_queue, client);
75 +
76 + struct tcp_server {
77 + struct event_loop* loop;
78 +
79 + tcp_server_conn_handler conn_handler;
80 + void* conn_handler_arg;
81 +
82 + struct client_queue client_queue;
83 +
84 + int accept_fd;
85 + };
86 +
87 + 27620static void client_destroy(struct client* client) {
88 +
+ 1/2 +
+
✓ Branch 1 taken 27620 times.
+
✗ Branch 2 not taken.
+
+
+
27620 log_debug("Cleaning up client thread %d\n", client->tid);
89 +
90 +
+ 8/8 +
+
✓ Branch 0 taken 14830 times.
+
✓ Branch 1 taken 12790 times.
+
✓ Branch 2 taken 7697 times.
+
✓ Branch 3 taken 7133 times.
+
✓ Branch 4 taken 7652 times.
+
✓ Branch 5 taken 12790 times.
+
✓ Branch 6 taken 9507 times.
+
✓ Branch 7 taken 3283 times.
+
+
+
35272 SIMPLEQ_REMOVE(&client->server->client_queue, client, client, entries);
91 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 27620 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
27620 pthread_errno_if(pthread_join(client->thread, NULL), "pthread_join");
92 + 27620 file_close(client->cleanup_fd);
93 + 27620 net_close(client->conn_fd);
94 + 27620 free(client);
95 + 27620}
96 +
97 + 27620static int client_destroy_handler(
98 + UNUSED struct event_loop* loop,
99 + UNUSED int fd,
100 + UNUSED short revents,
101 + void* _client
102 + ) {
103 + 27620 struct client* client = (struct client*)_client;
104 +
+ 1/2 +
+
✓ Branch 1 taken 27620 times.
+
✗ Branch 2 not taken.
+
+
+
27620 log_debug("Client thread %d indicated that it's done\n", client->tid);
105 +
106 + 27620 client_destroy(client);
107 + 27620 return 0;
108 + }
109 +
110 + 27620static void* client_thread_func(void* _client) {
111 + 27620 struct client* client = (struct client*)_client;
112 + 27620 int ret = 0;
113 +
114 + 27620 client->tid = gettid();
115 +
+ 1/2 +
+
✓ Branch 1 taken 27620 times.
+
✗ Branch 2 not taken.
+
+
+
27620 log_debug("New client thread thread %d has started\n", client->tid);
116 +
117 + /* Let the client thread handle its signals except those that should be
118 + * handled in the main thread. */
119 + 27620 ret = signal_block_sigterms();
120 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27620 times.
+
+
+
27620 if (ret < 0)
121 + ✗ goto cleanup;
122 +
123 + 27620 ret = client->server->conn_handler(client->conn_fd, client->server->conn_handler_arg);
124 +
+ 1/2 +
+
✓ Branch 0 taken 27620 times.
+
✗ Branch 1 not taken.
+
+
+
27620 if (ret < 0)
125 + ✗ goto cleanup;
126 +
127 + 27620cleanup:
128 +
+ 1/4 +
+
✗ Branch 1 not taken.
+
✓ Branch 2 taken 27620 times.
+
✗ Branch 4 not taken.
+
✗ Branch 5 not taken.
+
+
+
27620 log_errno_if(eventfd_write(client->cleanup_fd, 1), "eventfd_write");
129 +
130 + 27620 return NULL;
131 + }
132 +
133 + 27620static int client_create_thread(struct client* client) {
134 + sigset_t old_mask;
135 + 27620 int ret = 0;
136 +
137 + /* Block all signals (we'll unblock them later); the client thread will
138 + * have all signals blocked initially. This allows the main thread to
139 + * handle SIGINT/SIGTERM/etc. */
140 + 27620 ret = signal_block_all(&old_mask);
141 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27620 times.
+
+
+
27620 if (ret < 0)
142 + ✗ return ret;
143 +
144 + 27620 ret = pthread_create(&client->thread, NULL, client_thread_func, client);
145 +
+ 1/2 +
+
✓ Branch 0 taken 27620 times.
+
✗ Branch 1 not taken.
+
+
+
27620 if (ret) {
146 + ✗ pthread_errno(ret, "pthread_create");
147 + ✗ goto restore_mask;
148 + }
149 +
150 + 27620restore_mask:
151 + /* Restore the previously-enabled signals for handling in the main thread. */
152 + 27620 signal_set_mask(&old_mask);
153 +
154 + 27620 return ret;
155 + }
156 +
157 + 27620static int client_create(struct tcp_server* server, int conn_fd) {
158 + 27620 int ret = 0;
159 +
160 + 27620 struct client* client = calloc(1, sizeof(struct client));
161 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27620 times.
+
+
+
27620 if (!client) {
162 + ✗ log_errno("calloc");
163 + ✗ return -1;
164 + }
165 +
166 + 27620 client->server = server;
167 + 27620 client->conn_fd = conn_fd;
168 +
169 + 27620 ret = eventfd(0, EFD_CLOEXEC);
170 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27620 times.
+
+
+
27620 if (ret < 0) {
171 + ✗ log_errno("eventfd");
172 + ✗ goto free;
173 + }
174 + 27620 client->cleanup_fd = ret;
175 +
176 + 27620 ret = event_loop_add_once(
177 + server->loop, client->cleanup_fd, POLLIN, client_destroy_handler, client
178 + );
179 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27620 times.
+
+
+
27620 if (ret < 0)
180 + ✗ goto close_cleanup_fd;
181 +
182 + 27620 SIMPLEQ_INSERT_TAIL(&server->client_queue, client, entries);
183 +
184 + 27620 ret = client_create_thread(client);
185 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27620 times.
+
+
+
27620 if (ret < 0)
186 + ✗ goto remove_from_client_queue;
187 +
188 + 27620 return ret;
189 +
190 + ✗remove_from_client_queue:
191 + ✗ SIMPLEQ_REMOVE(&server->client_queue, client, client, entries);
192 +
193 + ✗close_cleanup_fd:
194 + ✗ file_close(client->cleanup_fd);
195 +
196 + ✗free:
197 + ✗ free(client);
198 +
199 + ✗ return ret;
200 + }
201 +
202 + 29static void client_queue_create(struct client_queue* client_queue) {
203 + 29 SIMPLEQ_INIT(client_queue);
204 + 29}
205 +
206 + 29static void client_queue_destroy(struct client_queue* client_queue) {
207 + 29 struct client* entry1 = SIMPLEQ_FIRST(client_queue);
208 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 while (entry1) {
209 + ✗ struct client* entry2 = SIMPLEQ_NEXT(entry1, entries);
210 + ✗ client_destroy(entry1);
211 + ✗ entry1 = entry2;
212 + }
213 + 29}
214 +
215 + 27620static int tcp_server_accept_handler(
216 + UNUSED struct event_loop* loop,
217 + UNUSED int fd,
218 + UNUSED short revents,
219 + void* _server
220 + ) {
221 + 27620 struct tcp_server* server = (struct tcp_server*)_server;
222 + 27620 return tcp_server_accept(server);
223 + }
224 +
225 + 29int tcp_server_create(
226 + struct tcp_server** _server,
227 + struct event_loop* loop,
228 + const char* port,
229 + tcp_server_conn_handler conn_handler,
230 + void* conn_handler_arg
231 + ) {
232 + 29 int ret = 0;
233 +
234 + 29 struct tcp_server* server = calloc(1, sizeof(struct tcp_server));
235 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (!server) {
236 + ✗ log_errno("calloc");
237 + ✗ return -1;
238 + }
239 +
240 + 29 server->loop = loop;
241 +
242 + 29 server->conn_handler = conn_handler;
243 + 29 server->conn_handler_arg = conn_handler_arg;
244 +
245 + 29 client_queue_create(&server->client_queue);
246 +
247 + 29 ret = net_bind(port);
248 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
249 + ✗ goto free;
250 + 29 server->accept_fd = ret;
251 +
252 + 29 ret = event_loop_add(loop, server->accept_fd, POLLIN, tcp_server_accept_handler, server);
253 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 29 times.
+
+
+
29 if (ret < 0)
254 + ✗ goto close;
255 +
256 + 29 *_server = server;
257 + 29 return ret;
258 +
259 + ✗close:
260 + ✗ net_close(server->accept_fd);
261 + ✗free:
262 + ✗ free(server);
263 +
264 + ✗ return ret;
265 + }
266 +
267 + 29void tcp_server_destroy(struct tcp_server* server) {
268 + 29 net_close(server->accept_fd);
269 + 29 client_queue_destroy(&server->client_queue);
270 + 29 free(server);
271 + 29}
272 +
273 + 27620int tcp_server_accept(struct tcp_server* server) {
274 + 27620 int conn_fd = -1, ret = 0;
275 +
276 + 27620 ret = net_accept(server->accept_fd);
277 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27620 times.
+
+
+
27620 if (ret < 0)
278 + ✗ return ret;
279 + 27620 conn_fd = ret;
280 +
281 + 27620 ret = client_create(server, conn_fd);
282 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 27620 times.
+
+
+
27620 if (ret < 0)
283 + ✗ goto close_conn;
284 +
285 + 27620 return ret;
286 +
287 + ✗close_conn:
288 + ✗ net_close(conn_fd);
289 +
290 + ✗ return ret;
291 + }
292 +
+
+
+
+ + + + diff --git a/coverage/index.worker.c.4cbdfac39be7d0330fdfd94f65ce9ea9.html b/coverage/index.worker.c.4cbdfac39be7d0330fdfd94f65ce9ea9.html new file mode 100644 index 0000000..a0365cb --- /dev/null +++ b/coverage/index.worker.c.4cbdfac39be7d0330fdfd94f65ce9ea9.html @@ -0,0 +1,2236 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/worker.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:10615170.2%
Functions:99100.0%
Branches:276243.5%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 + 54static 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 + 54static 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 + 54static 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 + 9180static 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 + 54int 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 + 54void 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 + 9180static 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 + 9180close_conn:
211 + 9180 net_close(fd);
212 +
213 + 9180free_request:
214 + 9180 jsonrpc_request_destroy(finished_request);
215 +
216 + 9180free_output:
217 + 9180 process_output_destroy(result);
218 +
219 + 9180 run_destroy(worker->run);
220 +
221 + 9180 return ret;
222 + }
223 +
224 + 9234static 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 + 9234close:
255 + 9234 net_close(fd);
256 +
257 + 9234 return ret;
258 + }
259 +
260 + 54int 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 +
+
+
+
+ + + + diff --git a/coverage/index.worker_main.c.3e96ea0429977547c8b5eee564591fe0.html b/coverage/index.worker_main.c.3e96ea0429977547c8b5eee564591fe0.html new file mode 100644 index 0000000..fb4403f --- /dev/null +++ b/coverage/index.worker_main.c.3e96ea0429977547c8b5eee564591fe0.html @@ -0,0 +1,772 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/worker_main.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:344379.1%
Functions:44100.0%
Branches:101471.4%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
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 "cmd_line.h"
9 + #include "const.h"
10 + #include "log.h"
11 + #include "worker.h"
12 +
13 + #include <getopt.h>
14 + #include <unistd.h>
15 +
16 + 60static struct settings default_settings(void) {
17 + 60 struct settings settings = {
18 + .host = default_host,
19 + .port = default_port,
20 + };
21 + 60 return settings;
22 + }
23 +
24 + 4const char* get_usage_string(void) {
25 + 4 return "[-h|--help] [-V|--version] [-v|--verbose] [-H|--host HOST] [-p|--port PORT]";
26 + }
27 +
28 + 60static int parse_settings(struct settings* settings, int argc, char* argv[]) {
29 + int opt, longind;
30 +
31 + 60 *settings = default_settings();
32 +
33 + static struct option long_options[] = {
34 + {"help", no_argument, 0, 'h'},
35 + {"version", no_argument, 0, 'V'},
36 + {"verbose", no_argument, 0, 'v'},
37 + {"host", required_argument, 0, 'H'},
38 + {"port", required_argument, 0, 'p'},
39 + {0, 0, 0, 0},
40 + };
41 +
42 +
+ 2/2 +
+
✓ Branch 1 taken 114 times.
+
✓ Branch 2 taken 54 times.
+
+
+
168 while ((opt = getopt_long(argc, argv, "hVvH:p:", long_options, &longind)) != -1) {
43 +
+ 5/6 +
+
✓ Branch 0 taken 2 times.
+
✓ Branch 1 taken 2 times.
+
✗ Branch 2 not taken.
+
✓ Branch 3 taken 54 times.
+
✓ Branch 4 taken 54 times.
+
✓ Branch 5 taken 2 times.
+
+
+
114 switch (opt) {
44 + 2 case 'h':
45 + 2 exit_with_usage(0);
46 + ✗ break;
47 + 2 case 'V':
48 + 2 exit_with_version();
49 + ✗ break;
50 + ✗ case 'v':
51 + ✗ g_log_lvl = LOG_LVL_DEBUG;
52 + ✗ break;
53 + 54 case 'H':
54 + 54 settings->host = optarg;
55 + 54 break;
56 + 54 case 'p':
57 + 54 settings->port = optarg;
58 + 54 break;
59 + 2 default:
60 + 2 exit_with_usage(1);
61 + ✗ break;
62 + }
63 + }
64 +
65 + 54 return 0;
66 + }
67 +
68 + 60int main(int argc, char* argv[]) {
69 + struct settings settings;
70 + 60 struct worker* worker = NULL;
71 + 60 int ret = 0;
72 +
73 + 60 ret = parse_settings(&settings, argc, argv);
74 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 54 times.
+
+
+
54 if (ret < 0)
75 + ✗ return ret;
76 +
77 + 54 ret = worker_create(&worker, &settings);
78 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 54 times.
+
+
+
54 if (ret < 0)
79 + ✗ return ret;
80 +
81 + 54 ret = worker_main(worker);
82 +
+ 1/2 +
+
✓ Branch 0 taken 54 times.
+
✗ Branch 1 not taken.
+
+
+
54 if (ret < 0)
83 + ✗ goto destroy_worker;
84 +
85 + 54destroy_worker:
86 + 54 worker_destroy(worker);
87 +
88 + 54 return ret;
89 + }
90 +
+
+
+
+ + + + diff --git a/coverage/index.worker_queue.c.aeb7258cd8f695c41a9aa8634701b38c.html b/coverage/index.worker_queue.c.aeb7258cd8f695c41a9aa8634701b38c.html new file mode 100644 index 0000000..1b87f72 --- /dev/null +++ b/coverage/index.worker_queue.c.aeb7258cd8f695c41a9aa8634701b38c.html @@ -0,0 +1,647 @@ + + + + + + GCC Code Coverage Report + + + + + +
+

GCC Code Coverage Report

+ +
+ +
+
+ + + + + + + + + + + + + +
Directory:src/
File:src/worker_queue.c
Date:2026-10-15 10:49:27
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExecTotalCoverage
Lines:323786.5%
Functions:8988.9%
Branches:51050.0%
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LineBranchExecSource
1 + /*
2 + * Copyright (c) 2023 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_queue.h"
9 +
10 + #include "log.h"
11 + #include "net.h"
12 +
13 + #include <stdlib.h>
14 + #include <sys/queue.h>
15 +
16 + struct worker {
17 + int fd;
18 + SIMPLEQ_ENTRY(worker) entries;
19 + };
20 +
21 + 9234int worker_create(struct worker** _entry, int fd) {
22 + 9234 struct worker* entry = malloc(sizeof(struct worker));
23 +
+ 1/2 +
+
✗ Branch 0 not taken.
+
✓ Branch 1 taken 9234 times.
+
+
+
9234 if (!entry) {
24 + ✗ log_errno("malloc");
25 + ✗ return -1;
26 + }
27 +
28 + 9234 entry->fd = fd;
29 +
30 + 9234 *_entry = entry;
31 + 9234 return 0;
32 + }
33 +
34 + 9234void worker_destroy(struct worker* entry) {
35 + 9234 net_close(entry->fd);
36 + 9234 free(entry);
37 + 9234}
38 +
39 + 36774int worker_get_fd(const struct worker* entry) {
40 + 36774 return entry->fd;
41 + }
42 +
43 + 29void worker_queue_create(struct worker_queue* queue) {
44 + 29 SIMPLEQ_INIT(queue);
45 + 29}
46 +
47 + 29void worker_queue_destroy(struct worker_queue* queue) {
48 + 29 struct worker* entry1 = SIMPLEQ_FIRST(queue);
49 +
+ 2/2 +
+
✓ Branch 0 taken 54 times.
+
✓ Branch 1 taken 29 times.
+
+
+
83 while (entry1) {
50 + 54 struct worker* entry2 = SIMPLEQ_NEXT(entry1, entries);
51 + 54 worker_destroy(entry1);
52 + 54 entry1 = entry2;
53 + }
54 + 29 SIMPLEQ_INIT(queue);
55 + 29}
56 +
57 + 27178int worker_queue_is_empty(const struct worker_queue* queue) {
58 + 27178 return SIMPLEQ_EMPTY(queue);
59 + }
60 +
61 + ✗void worker_queue_add_first(struct worker_queue* queue, struct worker* entry) {
62 + ✗ SIMPLEQ_INSERT_HEAD(queue, entry, entries);
63 + ✗}
64 +
65 + 9234void worker_queue_add_last(struct worker_queue* queue, struct worker* entry) {
66 + 9234 SIMPLEQ_INSERT_TAIL(queue, entry, entries);
67 + 9234}
68 +
69 + 9180struct worker* worker_queue_remove_first(struct worker_queue* queue) {
70 + 9180 struct worker* entry = SIMPLEQ_FIRST(queue);
71 +
+ 2/2 +
+
✓ Branch 0 taken 9067 times.
+
✓ Branch 1 taken 113 times.
+
+
+
9180 SIMPLEQ_REMOVE_HEAD(queue, entries);
72 + 9180 return entry;
73 + }
74 +
+
+
+
+ + + + -- cgit v1.3