Coverage Report

Created: 2025-11-24 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/unit/src/nxt_buf.c
Line
Count
Source
1
2
/*
3
 * Copyright (C) Igor Sysoev
4
 * Copyright (C) NGINX, Inc.
5
 */
6
7
#include <nxt_main.h>
8
9
10
static void nxt_buf_completion(nxt_task_t *task, void *obj, void *data);
11
static void nxt_buf_ts_completion(nxt_task_t *task, void *obj, void *data);
12
13
14
typedef struct {
15
    nxt_work_t          work;
16
    nxt_event_engine_t  *engine;
17
} nxt_buf_ts_t;
18
19
20
void
21
nxt_buf_mem_init(nxt_buf_t *b, void *start, size_t size)
22
0
{
23
0
    b->mem.start = start;
24
0
    b->mem.pos = start;
25
0
    b->mem.free = start;
26
0
    b->mem.end = nxt_pointer_to(start, size);
27
0
}
28
29
30
nxt_buf_t *
31
nxt_buf_mem_alloc(nxt_mp_t *mp, size_t size, nxt_uint_t flags)
32
0
{
33
0
    nxt_buf_t  *b;
34
35
0
    b = nxt_mp_alloc(mp, NXT_BUF_MEM_SIZE + size);
36
0
    if (nxt_slow_path(b == NULL)) {
37
0
        return NULL;
38
0
    }
39
40
0
    nxt_memzero(b, NXT_BUF_MEM_SIZE);
41
42
0
    b->data = mp;
43
0
    b->completion_handler = nxt_buf_completion;
44
45
0
    if (size != 0) {
46
0
        b->mem.start = nxt_pointer_to(b, NXT_BUF_MEM_SIZE);
47
0
        b->mem.pos = b->mem.start;
48
0
        b->mem.free = b->mem.start;
49
0
        b->mem.end = b->mem.start + size;
50
0
    }
51
52
0
    return b;
53
0
}
54
55
56
nxt_buf_t *
57
nxt_buf_mem_ts_alloc(nxt_task_t *task, nxt_mp_t *mp, size_t size)
58
0
{
59
0
    nxt_buf_t     *b;
60
0
    nxt_buf_ts_t  *ts;
61
62
0
    b = nxt_mp_alloc(mp, NXT_BUF_MEM_SIZE + sizeof(nxt_buf_ts_t) + size);
63
0
    if (nxt_slow_path(b == NULL)) {
64
0
        return NULL;
65
0
    }
66
67
0
    nxt_mp_retain(mp);
68
69
0
    nxt_memzero(b, NXT_BUF_MEM_SIZE + sizeof(nxt_buf_ts_t));
70
71
0
    b->data = mp;
72
0
    b->completion_handler = nxt_buf_ts_completion;
73
0
    b->is_ts = 1;
74
75
0
    if (size != 0) {
76
0
        b->mem.start = nxt_pointer_to(b, NXT_BUF_MEM_SIZE
77
0
                                         + sizeof(nxt_buf_ts_t));
78
0
        b->mem.pos = b->mem.start;
79
0
        b->mem.free = b->mem.start;
80
0
        b->mem.end = b->mem.start + size;
81
0
    }
82
83
0
    ts = nxt_pointer_to(b, NXT_BUF_MEM_SIZE);
84
0
    ts->engine = task->thread->engine;
85
86
0
    ts->work.handler = nxt_buf_ts_completion;
87
0
    ts->work.task = task;
88
0
    ts->work.obj = b;
89
0
    ts->work.data = b->parent;
90
91
0
    return b;
92
0
}
93
94
95
nxt_buf_t *
96
nxt_buf_file_alloc(nxt_mp_t *mp, size_t size, nxt_uint_t flags)
97
0
{
98
0
    nxt_buf_t  *b;
99
100
0
    b = nxt_mp_alloc(mp, NXT_BUF_FILE_SIZE + size);
101
0
    if (nxt_slow_path(b == NULL)) {
102
0
        return NULL;
103
0
    }
104
105
0
    nxt_memzero(b, NXT_BUF_FILE_SIZE);
106
107
0
    b->data = mp;
108
0
    b->completion_handler = nxt_buf_completion;
109
0
    nxt_buf_set_file(b);
110
111
0
    if (size != 0) {
112
0
        b->mem.start = nxt_pointer_to(b, NXT_BUF_FILE_SIZE);
113
0
        b->mem.pos = b->mem.start;
114
0
        b->mem.free = b->mem.start;
115
0
        b->mem.end = b->mem.start + size;
116
0
    }
117
118
0
    return b;
119
0
}
120
121
122
nxt_buf_t *
123
nxt_buf_mmap_alloc(nxt_mp_t *mp, size_t size)
124
0
{
125
0
    nxt_buf_t  *b;
126
127
0
    b = nxt_mp_zalloc(mp, NXT_BUF_MMAP_SIZE);
128
129
0
    if (nxt_fast_path(b != NULL)) {
130
0
        b->data = mp;
131
0
        b->completion_handler = nxt_buf_completion;
132
133
0
        nxt_buf_set_file(b);
134
0
        nxt_buf_set_mmap(b);
135
0
        nxt_buf_mem_set_size(&b->mem, size);
136
0
    }
137
138
0
    return b;
139
0
}
140
141
142
nxt_buf_t *
143
nxt_buf_sync_alloc(nxt_mp_t *mp, nxt_uint_t flags)
144
0
{
145
0
    nxt_buf_t  *b;
146
147
0
    b = nxt_mp_zalloc(mp, NXT_BUF_MEM_SIZE);
148
149
0
    if (nxt_fast_path(b != NULL)) {
150
0
        b->data = mp;
151
0
        b->completion_handler = nxt_buf_completion;
152
153
0
        nxt_buf_set_sync(b);
154
0
        b->is_nobuf = ((flags & NXT_BUF_SYNC_NOBUF) != 0);
155
0
        b->is_flush = ((flags & NXT_BUF_SYNC_FLUSH) != 0);
156
0
        b->is_last = ((flags & NXT_BUF_SYNC_LAST) != 0);
157
0
    }
158
159
0
    return b;
160
0
}
161
162
163
void
164
nxt_buf_chain_add(nxt_buf_t **head, nxt_buf_t *in)
165
0
{
166
0
    nxt_buf_t  *b, **prev;
167
168
0
    prev = head;
169
170
0
    for (b = *head; b != NULL; b = b->next) {
171
0
        prev = &b->next;
172
0
    }
173
174
0
    *prev = in;
175
0
}
176
177
178
size_t
179
nxt_buf_chain_length(nxt_buf_t *b)
180
0
{
181
0
    size_t  length;
182
183
0
    length = 0;
184
185
0
    while (b != NULL) {
186
0
        if (!nxt_buf_is_sync(b)) {
187
0
            length += b->mem.free - b->mem.pos;
188
0
        }
189
190
0
        b = b->next;
191
0
    }
192
193
0
    return length;
194
0
}
195
196
197
static void
198
nxt_buf_completion(nxt_task_t *task, void *obj, void *data)
199
0
{
200
0
    nxt_mp_t   *mp;
201
0
    nxt_buf_t  *b, *next, *parent;
202
203
0
    b = obj;
204
205
0
    nxt_debug(task, "buf completion: %p %p", b, b->mem.start);
206
207
0
    nxt_assert(data == b->parent);
208
209
0
    do {
210
0
        next = b->next;
211
0
        parent = b->parent;
212
0
        mp = b->data;
213
214
0
        nxt_mp_free(mp, b);
215
216
0
        nxt_buf_parent_completion(task, parent);
217
218
0
        b = next;
219
0
    } while (b != NULL);
220
0
}
221
222
223
void
224
nxt_buf_parent_completion(nxt_task_t *task, nxt_buf_t *parent)
225
0
{
226
0
    if (parent != NULL) {
227
0
        nxt_debug(task, "parent retain:%uD", parent->retain);
228
229
0
        parent->retain--;
230
231
0
        if (parent->retain == 0) {
232
0
            parent->mem.pos = parent->mem.free;
233
234
0
            parent->completion_handler(task, parent, parent->parent);
235
0
        }
236
0
    }
237
0
}
238
239
240
nxt_int_t
241
nxt_buf_ts_handle(nxt_task_t *task, void *obj, void *data)
242
0
{
243
0
    nxt_buf_t     *b;
244
0
    nxt_buf_ts_t  *ts;
245
246
0
    b = obj;
247
248
0
    nxt_assert(b->is_ts != 0);
249
250
0
    ts = nxt_pointer_to(b, NXT_BUF_MEM_SIZE);
251
252
0
    if (ts->engine != task->thread->engine) {
253
254
0
        nxt_debug(task, "buf ts: %p current engine is %p, expected %p",
255
0
                  b, task->thread->engine, ts->engine);
256
257
0
        ts->work.handler = b->completion_handler;
258
0
        ts->work.obj = obj;
259
0
        ts->work.data = data;
260
261
0
        nxt_event_engine_post(ts->engine, &ts->work);
262
263
0
        return 1;
264
0
    }
265
266
0
    return 0;
267
0
}
268
269
270
static void
271
nxt_buf_ts_completion(nxt_task_t *task, void *obj, void *data)
272
0
{
273
0
    nxt_mp_t   *mp;
274
0
    nxt_buf_t  *b, *next, *parent;
275
276
0
    b = obj;
277
278
0
    if (nxt_buf_ts_handle(task, obj, data)) {
279
0
        return;
280
0
    }
281
282
0
    nxt_debug(task, "buf ts completion: %p %p", b, b->mem.start);
283
284
0
    nxt_assert(data == b->parent);
285
286
0
    do {
287
0
        next = b->next;
288
0
        parent = b->parent;
289
0
        mp = b->data;
290
291
0
        nxt_mp_free(mp, b);
292
0
        nxt_mp_release(mp);
293
294
0
        nxt_buf_parent_completion(task, parent);
295
296
0
        b = next;
297
0
    } while (b != NULL);
298
0
}
299
300
301
nxt_buf_t *
302
nxt_buf_make_plain(nxt_mp_t *mp, nxt_buf_t *src, size_t size)
303
0
{
304
0
    nxt_buf_t  *b, *i;
305
306
0
    if (nxt_slow_path(size == 0)) {
307
0
        for (i = src; i != NULL; i = i->next) {
308
0
            size += nxt_buf_used_size(i);
309
0
        }
310
0
    }
311
312
0
    b = nxt_buf_mem_alloc(mp, size, 0);
313
314
0
    if (nxt_slow_path(b == NULL)) {
315
0
        return NULL;
316
0
    }
317
318
0
    for (i = src; i != NULL; i = i->next) {
319
0
        if (nxt_slow_path(nxt_buf_mem_free_size(&b->mem)
320
0
                          < nxt_buf_used_size(i)))
321
0
        {
322
0
            break;
323
0
        }
324
325
0
        b->mem.free = nxt_cpymem(b->mem.free, i->mem.pos, nxt_buf_used_size(i));
326
0
    }
327
328
0
    return b;
329
0
}