• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

saitoha / libsixel / 19706436485

26 Nov 2025 02:03PM UTC coverage: 41.224% (-1.3%) from 42.549%
19706436485

push

github

saitoha
build: fix build error when building with --disable-threads

9701 of 33876 branches covered (28.64%)

5 of 5 new or added lines in 1 file covered. (100.0%)

196 existing lines in 19 files now uncovered.

12873 of 31227 relevant lines covered (41.22%)

665886.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

24.11
/src/parallel-log.c
1
/*
2
 * SPDX-License-Identifier: MIT
3
 *
4
 * Copyright (c) 2025 libsixel developers. See `AUTHORS`.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
 * SOFTWARE.
23
 */
24

25
#include "config.h"
26

27
#include <stdarg.h>
28
#include <stdint.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <string.h>
32

33
#ifndef _WIN32
34
#include <pthread.h>
35
#endif
36

37
#include "assessment.h"
38
#include "parallel-log.h"
39

40
static sixel_parallel_logger_t *g_parallel_logger_active;
41
static int g_parallel_logger_refcount;
42

43
static unsigned long long
44
sixel_parallel_logger_thread_id(void)
×
45
{
46
#ifndef _WIN32
47
    return (unsigned long long)(uintptr_t)pthread_self();
×
48
#else
49
    return 0ULL;
50
#endif
51
}
52

53
static void
54
sixel_parallel_logger_escape(char const *message, char *buffer, size_t size)
×
55
{
56
    size_t i;
57
    size_t written;
58

59
    if (buffer == NULL || size == 0) {
×
60
        return;
×
61
    }
62
    buffer[0] = '\0';
×
63
    if (message == NULL) {
×
64
        return;
×
65
    }
66
    written = 0;
×
67
    for (i = 0; message[i] != '\0' && written + 2 < size; ++i) {
×
68
        if (message[i] == '\"' || message[i] == '\\') {
×
69
            buffer[written++] = '\\';
×
70
            if (written + 1 >= size) {
×
71
                break;
×
72
            }
73
        }
74
        buffer[written++] = message[i];
×
75
    }
76
    buffer[written] = '\0';
×
77
}
78

79
void
80
sixel_parallel_logger_init(sixel_parallel_logger_t *logger)
2,182✔
81
{
82
    if (logger == NULL) {
2,182!
83
        return;
×
84
    }
85
    logger->delegate = NULL;
2,182✔
86
    logger->file = NULL;
2,182✔
87
    logger->mutex_ready = 0;
2,182✔
88
    logger->active = 0;
2,182✔
89
    logger->started_at = 0.0;
2,182✔
90
}
91

92
void
93
sixel_parallel_logger_close(sixel_parallel_logger_t *logger)
150✔
94
{
95
    if (logger == NULL) {
150!
96
        return;
×
97
    }
98
    if (logger->delegate != NULL) {
150!
99
        if (logger->delegate == g_parallel_logger_active &&
×
100
                g_parallel_logger_refcount > 0) {
×
101
            --g_parallel_logger_refcount;
×
102
            if (g_parallel_logger_refcount != 0) {
×
103
                logger->delegate = NULL;
×
104
                logger->active = 0;
×
105
                return;
×
106
            }
107
            logger = logger->delegate;
×
108
            logger->delegate = NULL;
×
109
        } else {
110
            logger->delegate = NULL;
×
111
            logger->active = 0;
×
112
            return;
×
113
        }
114
    }
115
    if (logger == g_parallel_logger_active && g_parallel_logger_refcount > 1) {
150!
116
        --g_parallel_logger_refcount;
×
117
        return;
×
118
    }
119
    if (logger->mutex_ready) {
150!
120
#if SIXEL_ENABLE_THREADS
121
        sixel_mutex_destroy(&logger->mutex);
×
122
#endif  /* SIXEL_ENABLE_THREADS */
UNCOV
123
        logger->mutex_ready = 0;
×
124
    }
125
    if (logger->file != NULL) {
150!
126
        fclose(logger->file);
×
127
        logger->file = NULL;
×
128
    }
129
    if (logger == g_parallel_logger_active && g_parallel_logger_refcount > 0) {
150!
130
        g_parallel_logger_refcount = 0;
×
131
        g_parallel_logger_active = NULL;
×
132
    }
133
    logger->active = 0;
150✔
134
}
135

136
SIXELSTATUS
137
sixel_parallel_logger_open(sixel_parallel_logger_t *logger, char const *path)
×
138
{
139
    if (logger == NULL) {
×
140
        return SIXEL_BAD_ARGUMENT;
×
141
    }
142
    if (path == NULL || path[0] == '\0') {
×
143
        return SIXEL_OK;
×
144
    }
145
    logger->file = fopen(path, "w");
×
146
    if (logger->file == NULL) {
×
147
        return SIXEL_RUNTIME_ERROR;
×
148
    }
149
#if SIXEL_ENABLE_THREADS
150
    if (sixel_mutex_init(&logger->mutex) != 0) {
×
151
        fclose(logger->file);
×
152
        logger->file = NULL;
×
153
        return SIXEL_RUNTIME_ERROR;
×
154
    }
155
#endif  /* SIXEL_ENABLE_THREADS */
156
    logger->mutex_ready = 1;
×
157
    logger->active = 1;
×
158
    logger->started_at = sixel_assessment_timer_now();
×
159
    setvbuf(logger->file, NULL, _IOLBF, 0);
×
160
    g_parallel_logger_active = logger;
×
161
    g_parallel_logger_refcount = 1;
×
162
    return SIXEL_OK;
×
163
}
164

165
SIXELSTATUS
166
sixel_parallel_logger_prepare_env(sixel_parallel_logger_t *logger)
940✔
167
{
168
    char const *path;
169
    SIXELSTATUS status;
170

171
    if (logger == NULL) {
940!
172
        return SIXEL_BAD_ARGUMENT;
×
173
    }
174

175
    /*
176
     * Reuse an already opened logger so the timeline is continuous.  Some
177
     * call sites share a logger instance across serial and pipeline phases;
178
     * reopening would truncate the file and reset timestamps, hiding early
179
     * stages from the timeline. Share the sink via a lightweight delegate
180
     * pointer instead of copying mutex state.
181
     */
182
    if (g_parallel_logger_active != NULL &&
940!
183
            g_parallel_logger_active->active &&
×
184
            g_parallel_logger_active->mutex_ready) {
×
185
        sixel_parallel_logger_init(logger);
×
186
        logger->delegate = g_parallel_logger_active;
×
187
        logger->active = g_parallel_logger_active->active;
×
188
        logger->started_at = g_parallel_logger_active->started_at;
×
189
        ++g_parallel_logger_refcount;
×
190
        return SIXEL_OK;
×
191
    }
192

193
    sixel_parallel_logger_init(logger);
940✔
194
    path = getenv("SIXEL_PARALLEL_LOG_PATH");
940✔
195
    if (path == NULL || path[0] == '\0') {
940!
196
        return SIXEL_OK;
940✔
197
    }
198
    status = sixel_parallel_logger_open(logger, path);
×
199
    if (SIXEL_FAILED(status)) {
×
200
        sixel_parallel_logger_close(logger);
×
201
    }
202

203
    return status;
×
204
}
205

206
void
207
sixel_parallel_logger_logf(sixel_parallel_logger_t *logger,
300✔
208
                           char const *role,
209
                           char const *worker,
210
                           char const *event,
211
                           int job_id,
212
                           int row_index,
213
                           int y0,
214
                           int y1,
215
                           int in0,
216
                           int in1,
217
                           char const *fmt,
218
                           ...)
219
{
220
    sixel_parallel_logger_t *target;
221
    char message[256];
222
    char escaped[512];
223
    va_list args;
224
    double timestamp;
225

226
    target = logger;
300✔
227
    if (logger != NULL && logger->delegate != NULL) {
300!
228
        target = logger->delegate;
×
229
    }
230
    if (target == NULL || !target->active || target->file == NULL
300!
231
            || !target->mutex_ready) {
×
232
        return;
300✔
233
    }
234

235
    va_start(args, fmt);
×
236
    if (fmt != NULL) {
×
237
#if defined(__clang__)
238
#pragma clang diagnostic push
239
#pragma clang diagnostic ignored "-Wformat-nonliteral"
240
#elif defined(__GNUC__)
241
#pragma GCC diagnostic push
242
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
243
#endif
244
        /*
245
         * The format strings are defined in our code paths.  Suppress the
246
         * nonliteral warning so we can forward variadic arguments safely.
247
         */
248
        (void)vsnprintf(message, sizeof(message), fmt, args);
×
249
#if defined(__clang__)
250
#pragma clang diagnostic pop
251
#elif defined(__GNUC__)
252
#pragma GCC diagnostic pop
253
#endif
254
    } else {
255
        message[0] = '\0';
×
256
    }
257
    va_end(args);
×
258

259
    sixel_parallel_logger_escape(message, escaped, sizeof(escaped));
×
260

261
#if SIXEL_ENABLE_THREADS
262
    sixel_mutex_lock(&target->mutex);
×
263
#endif  /* SIXEL_ENABLE_THREADS */
264
    timestamp = sixel_assessment_timer_now() - target->started_at;
×
265
    if (timestamp < 0.0) {
×
266
        timestamp = 0.0;
×
267
    }
268
    fprintf(target->file,
×
269
            "{\"ts\":%.6f,\"thread\":%llu,\"worker\":\"%s\","\
270
            "\"role\":\"%s\",\"event\":\"%s\",\"job\":%d,"\
271
            "\"row\":%d,\"y0\":%d,\"y1\":%d,\"in0\":%d,\"in1\":%d,"\
272
            "\"message\":\"%s\"}\n",
273
            timestamp,
274
            sixel_parallel_logger_thread_id(),
275
            worker != NULL ? worker : "",
×
276
            role != NULL ? role : "",
×
277
            event != NULL ? event : "",
×
278
            job_id,
279
            row_index,
280
            y0,
281
            y1,
282
            in0,
283
            in1,
284
            escaped);
285
    fflush(target->file);
×
286
#if SIXEL_ENABLE_THREADS
UNCOV
287
    sixel_mutex_unlock(&target->mutex);
×
288
#endif  /* SIXEL_ENABLE_THREADS */
289
}
290

291
/* emacs Local Variables:      */
292
/* emacs mode: c               */
293
/* emacs tab-width: 4          */
294
/* emacs indent-tabs-mode: nil */
295
/* emacs c-basic-offset: 4     */
296
/* emacs End:                  */
297
/* vim: set expandtab ts=4 sts=4 sw=4 : */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc