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 | } |