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