1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7 #ifndef _NXT_BUF_H_INCLUDED_
8 #define _NXT_BUF_H_INCLUDED_
9
10
11 /*
12 * There are four types of buffers. They are different sizes, so they
13 * should be allocated by appropriate nxt_buf_XXX_alloc() function.
14 *
15 * 1) Memory-only buffers, their size is less than nxt_buf_t size, it
16 * is equal to offsetof(nxt_buf_t, file_pos), that is it is nxt_buf_t
17 * without file and mmap part. The buffers are frequently used, so
18 * the reduction allows to save 20-32 bytes depending on platform.
19 *
20 * 2) Memory/file buffers, on Unix their size is exactly nxt_buf_t size,
21 * since nxt_mem_map_file_ctx_t() is empty macro. On Windows the size
22 * equals offsetof(nxt_buf_t, mmap), that is it is nxt_buf_t without
23 * memory map context part. The buffers can contain both memory and
24 * file pointers at once, or only memory or file pointers.
25 *
26 * 3) Memory mapped buffers are similar to the memory/file buffers. Their
27 * size is exactly nxt_buf_t size. The buffers can contain both memory
28 * and file pointers at once, or only memory or file pointers. If a
29 * buffer is not currently mapped in memory, its mapping size is stored
30 * in the mem.end field and available via nxt_buf_mem_size() macro.
31 *
32 * 4) Sync buffers, their size is the same size as memory-only buffers
33 * size. A sync buffer can be smaller but for memory pool cache
34 * purpose it is better to allocate it as frequently used memory-only
35 * buffer. The buffers are used to synchronize pipeline processing
36 * completion, because data buffers in the pipeline can be completed
37 * and freed before their final output will even be passed to a peer.
38 * For this purpose a sync buffer is allocated with the stop flag which
39 * stops buffer chain completion processing on the sync buffer in
40 * nxt_sendbuf_update() and nxt_sendbuf_completion().
41 * Clearing the stop flag allows to continue completion processing.
42 *
43 * The last flag means the end of the output and must be set only
44 * in a sync buffer. The last flag is not permitted in memory and
45 * file buffers since it requires special handling while conversion
46 * one buffer to another.
47 *
48 * The nxt_buf_used_size() macro treats a sync buffer as a memory-only
49 * buffer which has NULL pointers, thus the buffer content size is zero.
50 * If allocated size of sync buffer would be lesser than memory-only
51 * buffer, then the special memory flag would be required because
52 * currently presence of memory part is indicated by non-NULL pointer
53 * to a content in memory.
54 *
55 * All types of buffers can have the flush flag that means the buffer
56 * should be sent as much as possible.
57 */
58
59 typedef struct {
60 u_char *pos;
61 u_char *free;
62 u_char *start;
63 u_char *end;
64 } nxt_buf_mem_t;
65
66
67 struct nxt_buf_s {
68 void *data;
69 nxt_work_handler_t completion_handler;
70 void *parent;
71
72 /*
73 * The next link, flags, and nxt_buf_mem_t should
74 * reside together to improve cache locality.
75 */
76 nxt_buf_t *next;
77
78 uint32_t retain;
79
80 uint8_t cache_hint;
81
82 uint8_t is_file:1;
83 uint8_t is_mmap:1;
84 uint8_t is_port_mmap:1;
85 uint8_t is_sync:1;
86 uint8_t is_nobuf:1;
87 uint8_t is_flush:1;
88 uint8_t is_last:1;
89 uint8_t is_port_mmap_sent:1;
90 uint8_t is_ts:1;
91
92 nxt_buf_mem_t mem;
93
94 /* The file and mmap parts are not allocated by nxt_buf_mem_alloc(). */
95 nxt_file_t *file;
96 nxt_off_t file_pos;
97 nxt_off_t file_end;
98
99 /* The mmap part is not allocated by nxt_buf_file_alloc(). */
100 nxt_mem_map_file_ctx_t (mmap)
101 };
102
103
104 #define NXT_BUF_SYNC_SIZE offsetof(nxt_buf_t, mem.free)
105 #define NXT_BUF_MEM_SIZE offsetof(nxt_buf_t, file)
106 #define NXT_BUF_FILE_SIZE sizeof(nxt_buf_t)
107 #define NXT_BUF_MMAP_SIZE NXT_BUF_FILE_SIZE
108 #define NXT_BUF_PORT_MMAP_SIZE NXT_BUF_MEM_SIZE
109
110
111 #define NXT_BUF_SYNC_NOBUF 1
112 #define NXT_BUF_SYNC_FLUSH 2
113 #define NXT_BUF_SYNC_LAST 4
114
115
116 #define \
117 nxt_buf_is_mem(b) \
118 ((b)->mem.pos != NULL)
119
120
121 #define \
122 nxt_buf_is_file(b) \
123 ((b)->is_file)
124
125 #define \
126 nxt_buf_set_file(b) \
127 (b)->is_file = 1
128
129 #define \
130 nxt_buf_clear_file(b) \
131 (b)->is_file = 0
132
133
134 #define \
135 nxt_buf_is_mmap(b) \
136 ((b)->is_mmap)
137
138 #define \
139 nxt_buf_set_mmap(b) \
140 (b)->is_mmap = 1
141
142 #define \
143 nxt_buf_clear_mmap(b) \
144 (b)->is_mmap = 0
145
146
147 #define \
148 nxt_buf_is_port_mmap(b) \
149 ((b)->is_port_mmap)
150
151 #define \
152 nxt_buf_set_port_mmap(b) \
153 (b)->is_port_mmap = 1
154
155 #define \
156 nxt_buf_clear_port_mmap(b) \
157 (b)->is_port_mmap = 0
158
159
160 #define \
161 nxt_buf_is_sync(b) \
162 ((b)->is_sync)
163
164 #define \
165 nxt_buf_set_sync(b) \
166 (b)->is_sync = 1
167
168 #define \
169 nxt_buf_clear_sync(b) \
170 (b)->is_sync = 0
171
172
173 #define \
174 nxt_buf_is_nobuf(b) \
175 ((b)->is_nobuf)
176
177 #define \
178 nxt_buf_set_nobuf(b) \
179 (b)->is_nobuf = 1
180
181 #define \
182 nxt_buf_clear_nobuf(b) \
183 (b)->is_nobuf = 0
184
185
186 #define \
187 nxt_buf_is_flush(b) \
188 ((b)->is_flush)
189
190 #define \
191 nxt_buf_set_flush(b) \
192 (b)->is_flush = 1
193
194 #define \
195 nxt_buf_clear_flush(b) \
196 (b)->is_flush = 0
197
198
199 #define \
200 nxt_buf_is_last(b) \
201 ((b)->is_last)
202
203 #define \
204 nxt_buf_set_last(b) \
205 (b)->is_last = 1
206
207 #define \
208 nxt_buf_clear_last(b) \
209 (b)->is_last = 0
210
211
212 #define \
213 nxt_buf_mem_set_size(bm, size) \
214 do { \
215 (bm)->start = 0; \
216 (bm)->end = (void *) size; \
217 } while (0)
218
219
220 #define \
221 nxt_buf_mem_size(bm) \
222 ((bm)->end - (bm)->start)
223
224
225 #define \
226 nxt_buf_mem_used_size(bm) \
227 ((bm)->free - (bm)->pos)
228
229
230 #define \
231 nxt_buf_mem_free_size(bm) \
232 ((bm)->end - (bm)->free)
233
234
235 #define \
236 nxt_buf_used_size(b) \
237 (nxt_buf_is_file(b) ? (b)->file_end - (b)->file_pos: \
238 nxt_buf_mem_used_size(&(b)->mem))
239
240
241 NXT_EXPORT void nxt_buf_mem_init(nxt_buf_t *b, void *start, size_t size);
242 NXT_EXPORT nxt_buf_t *nxt_buf_mem_alloc(nxt_mp_t *mp, size_t size,
243 nxt_uint_t flags);
244 NXT_EXPORT nxt_buf_t *nxt_buf_mem_ts_alloc(nxt_task_t *task, nxt_mp_t *mp,
245 size_t size);
246 NXT_EXPORT nxt_buf_t *nxt_buf_file_alloc(nxt_mp_t *mp, size_t size,
247 nxt_uint_t flags);
248 NXT_EXPORT nxt_buf_t *nxt_buf_mmap_alloc(nxt_mp_t *mp, size_t size);
249 NXT_EXPORT nxt_buf_t *nxt_buf_sync_alloc(nxt_mp_t *mp, nxt_uint_t flags);
250
251 NXT_EXPORT nxt_int_t nxt_buf_ts_handle(nxt_task_t *task, void *obj, void *data);
252
253 NXT_EXPORT void nxt_buf_parent_completion(nxt_task_t *task, nxt_buf_t *parent);
254 NXT_EXPORT nxt_buf_t *nxt_buf_make_plain(nxt_mp_t *mp, nxt_buf_t *src,
255 size_t size);
256
257 nxt_inline nxt_buf_t *
nxt_buf_chk_make_plain(nxt_mp_t * mp,nxt_buf_t * src,size_t size)258 nxt_buf_chk_make_plain(nxt_mp_t *mp, nxt_buf_t *src, size_t size)
259 {
260 if (nxt_slow_path(src != NULL && src->next != NULL)) {
261 return nxt_buf_make_plain(mp, src, size);
262 }
263
264 return src;
265 }
266
267 #define \
268 nxt_buf_free(mp, b) \
269 nxt_mp_free((mp), (b))
270
271
272 NXT_EXPORT void nxt_buf_chain_add(nxt_buf_t **head, nxt_buf_t *in);
273 NXT_EXPORT size_t nxt_buf_chain_length(nxt_buf_t *b);
274
275 nxt_inline nxt_buf_t *
nxt_buf_cpy(nxt_buf_t * b,const void * src,size_t length)276 nxt_buf_cpy(nxt_buf_t *b, const void *src, size_t length)
277 {
278 nxt_memcpy(b->mem.free, src, length);
279 b->mem.free += length;
280
281 return b;
282 }
283
284 nxt_inline nxt_buf_t *
nxt_buf_cpystr(nxt_buf_t * b,const nxt_str_t * str)285 nxt_buf_cpystr(nxt_buf_t *b, const nxt_str_t *str)
286 {
287 return nxt_buf_cpy(b, str->start, str->length);
288 }
289
290
291 nxt_inline void
nxt_buf_dummy_completion(nxt_task_t * task,void * obj,void * data)292 nxt_buf_dummy_completion(nxt_task_t *task, void *obj, void *data)
293 {
294 }
295
296
297 #endif /* _NXT_BUF_H_INCLIDED_ */
298