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