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