1 /*
2  * Copyright (c) 2014,2015 DeNA Co., Ltd., Kazuho Oku, Justin Zhu
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20  * IN THE SOFTWARE.
21  */
22 #ifndef h2o__memory_h
23 #define h2o__memory_h
24 
25 #ifdef __sun__
26 #include <alloca.h>
27 #endif
28 #include <assert.h>
29 #include <inttypes.h>
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 
36 #ifdef __cplusplus
37 extern "C" {
38 #endif
39 
40 #define H2O_STRUCT_FROM_MEMBER(s, m, p) ((s *)((char *)(p)-offsetof(s, m)))
41 #define H2O_ALIGNOF(type) (__alignof__(type))
42 
43 #if __GNUC__ >= 3
44 #define H2O_LIKELY(x) __builtin_expect(!!(x), 1)
45 #define H2O_UNLIKELY(x) __builtin_expect(!!(x), 0)
46 #else
47 #define H2O_LIKELY(x) (x)
48 #define H2O_UNLIKELY(x) (x)
49 #endif
50 
51 #ifdef __GNUC__
52 #define H2O_GNUC_VERSION ((__GNUC__ << 16) | (__GNUC_MINOR__ << 8) | __GNUC_PATCHLEVEL__)
53 #else
54 #define H2O_GNUC_VERSION 0
55 #endif
56 
57 #if __STDC_VERSION__ >= 201112L
58 #define H2O_NORETURN _Noreturn
59 #elif defined(__clang__) || defined(__GNUC__) && H2O_GNUC_VERSION >= 0x20500
60 // noreturn was not defined before gcc 2.5
61 #define H2O_NORETURN __attribute__((noreturn))
62 #else
63 #define H2O_NORETURN
64 #endif
65 
66 #if !defined(__clang__) && defined(__GNUC__) && H2O_GNUC_VERSION >= 0x40900
67 // returns_nonnull was seemingly not defined before gcc 4.9 (exists in 4.9.1 but not in 4.8.2)
68 #define H2O_RETURNS_NONNULL __attribute__((returns_nonnull))
69 #else
70 #define H2O_RETURNS_NONNULL
71 #endif
72 
73 #define H2O_TO__STR(n) #n
74 #define H2O_TO_STR(n) H2O_TO__STR(n)
75 
76 #define H2O_BUILD_ASSERT(condition) ((void)sizeof(char[2 * !!(!__builtin_constant_p(condition) || (condition)) - 1]))
77 
78 /**
79  * library users can use their own log method by define this macro
80  */
81 #ifndef h2o_error_printf
82 #define h2o_error_printf(...) fprintf(stderr, __VA_ARGS__)
83 #endif
84 
85 typedef struct st_h2o_buffer_prototype_t h2o_buffer_prototype_t;
86 
87 /**
88  * buffer structure compatible with iovec
89  */
90 typedef struct st_h2o_iovec_t {
91     char *base;
92     size_t len;
93 } h2o_iovec_t;
94 
95 typedef struct st_h2o_mem_recycle_t {
96     size_t max;
97     size_t cnt;
98     struct st_h2o_mem_recycle_chunk_t *_link;
99 } h2o_mem_recycle_t;
100 
101 struct st_h2o_mem_pool_shared_entry_t {
102     size_t refcnt;
103     void (*dispose)(void *);
104     char bytes[1];
105 };
106 
107 /**
108  * the memory pool
109  */
110 union un_h2o_mem_pool_chunk_t;
111 typedef struct st_h2o_mem_pool_t {
112     union un_h2o_mem_pool_chunk_t *chunks;
113     size_t chunk_offset;
114     struct st_h2o_mem_pool_shared_ref_t *shared_refs;
115     struct st_h2o_mem_pool_direct_t *directs;
116 } h2o_mem_pool_t;
117 
118 /**
119  * buffer used to store incoming / outgoing octets
120  */
121 typedef struct st_h2o_buffer_t {
122     /**
123      * when `bytes` != NULL (and therefore `size` != 0), the capacity of the buffer, or otherwise the minimum initial capacity in
124      * case of a prototype, or the desired next capacity if not a prototype.
125      */
126     size_t capacity;
127     /**
128      * amount of the data available
129      */
130     size_t size;
131     /**
132      * pointer to the start of the data (or NULL if is pointing to a prototype)
133      */
134     char *bytes;
135     /**
136      * prototype (or NULL if the instance is part of the prototype)
137      */
138     h2o_buffer_prototype_t *_prototype;
139     /**
140      * file descriptor (if not -1, h2o_buffer_t is a memory map of the contents of this file descriptor)
141      */
142     int _fd;
143     /**
144      * memory used to store data
145      */
146     char _buf[1];
147 } h2o_buffer_t;
148 
149 #define H2O_TMP_FILE_TEMPLATE_MAX 256
150 typedef struct st_h2o_buffer_mmap_settings_t {
151     size_t threshold;
152     char fn_template[H2O_TMP_FILE_TEMPLATE_MAX];
153 } h2o_buffer_mmap_settings_t;
154 
155 struct st_h2o_buffer_prototype_t {
156     h2o_buffer_t _initial_buf;
157     h2o_buffer_mmap_settings_t *mmap_settings;
158 };
159 
160 typedef struct st_h2o_doublebuffer_t {
161     h2o_buffer_t *buf;
162     unsigned char inflight : 1;
163     size_t _bytes_inflight;
164 } h2o_doublebuffer_t;
165 
166 #define H2O_VECTOR(type)                                                                                                           \
167     struct {                                                                                                                       \
168         type *entries;                                                                                                             \
169         size_t size;                                                                                                               \
170         size_t capacity;                                                                                                           \
171     }
172 
173 typedef H2O_VECTOR(void) h2o_vector_t;
174 typedef H2O_VECTOR(uint8_t) h2o_byte_vector_t;
175 typedef H2O_VECTOR(h2o_iovec_t) h2o_iovec_vector_t;
176 
177 extern void *(*volatile h2o_mem__set_secure)(void *, int, size_t);
178 
179 /**
180  * prints an error message and aborts
181  */
182 H2O_NORETURN void h2o__fatal(const char *file, int line, const char *msg, ...) __attribute__((format(printf, 3, 4)));
183 #ifndef h2o_fatal
184 #define h2o_fatal(...) h2o__fatal(__FILE__, __LINE__, __VA_ARGS__)
185 #endif
186 
187 void h2o_perror(const char *msg);
188 char *h2o_strerror_r(int err, char *buf, size_t len);
189 
190 /**
191  * A version of memcpy that can take a NULL @src to avoid UB
192  */
193 static void *h2o_memcpy(void *dst, const void *src, size_t n);
194 /**
195  * constructor for h2o_iovec_t
196  */
197 static h2o_iovec_t h2o_iovec_init(const void *base, size_t len);
198 /**
199  * wrapper of malloc; allocates given size of memory or dies if impossible
200  */
201 H2O_RETURNS_NONNULL static void *h2o_mem_alloc(size_t sz);
202 /**
203  * warpper of realloc; reallocs the given chunk or dies if impossible
204  */
205 static void *h2o_mem_realloc(void *oldp, size_t sz);
206 
207 /**
208  * allocates memory using the reusing allocator
209  */
210 void *h2o_mem_alloc_recycle(h2o_mem_recycle_t *allocator, size_t sz);
211 /**
212  * returns the memory to the reusing allocator
213  */
214 void h2o_mem_free_recycle(h2o_mem_recycle_t *allocator, void *p);
215 /**
216  * release all the memory chunks cached in input allocator to system
217  */
218 void h2o_mem_clear_recycle(h2o_mem_recycle_t *allocator, int full);
219 
220 /**
221  * initializes the memory pool.
222  */
223 void h2o_mem_init_pool(h2o_mem_pool_t *pool);
224 /**
225  * clears the memory pool.
226  * Applications may dispose the pool after calling the function or reuse it without calling h2o_mem_init_pool.
227  */
228 void h2o_mem_clear_pool(h2o_mem_pool_t *pool);
229 /**
230  * allocates given size of memory from the memory pool, or dies if impossible
231  */
232 #define h2o_mem_alloc_pool(pool, type, cnt) h2o_mem_alloc_pool_aligned(pool, H2O_ALIGNOF(type), sizeof(type) * (cnt))
233 /**
234  * allocates given size of memory from pool using given alignment
235  */
236 static void *h2o_mem_alloc_pool_aligned(h2o_mem_pool_t *pool, size_t alignment, size_t size);
237 void *h2o_mem__do_alloc_pool_aligned(h2o_mem_pool_t *pool, size_t alignment, size_t size);
238 /**
239  * allocates a ref-counted chunk of given size from the memory pool, or dies if impossible.
240  * The ref-count of the returned chunk is 1 regardless of whether or not the chunk is linked to a pool.
241  * @param pool pool to which the allocated chunk should be linked (or NULL to allocate an orphan chunk)
242  */
243 void *h2o_mem_alloc_shared(h2o_mem_pool_t *pool, size_t sz, void (*dispose)(void *));
244 /**
245  * links a ref-counted chunk to a memory pool.
246  * The ref-count of the chunk will be decremented when the pool is cleared.
247  * It is permitted to link a chunk more than once to a single pool.
248  */
249 void h2o_mem_link_shared(h2o_mem_pool_t *pool, void *p);
250 /**
251  * increments the reference count of a ref-counted chunk.
252  */
253 static void h2o_mem_addref_shared(void *p);
254 /**
255  * decrements the reference count of a ref-counted chunk.
256  * The chunk gets freed when the ref-count reaches zero.
257  */
258 static int h2o_mem_release_shared(void *p);
259 /**
260  * frees unused memory being pooled for recycling
261  */
262 void h2o_buffer_clear_recycle(int full);
263 /**
264  * initialize the buffer using given prototype.
265  */
266 static void h2o_buffer_init(h2o_buffer_t **buffer, h2o_buffer_prototype_t *prototype);
267 /**
268  * calls the appropriate function to free the resources associated with the buffer
269  */
270 void h2o_buffer__do_free(h2o_buffer_t *buffer);
271 /**
272  * disposes of the buffer
273  */
274 static void h2o_buffer_dispose(h2o_buffer_t **buffer);
275 /**
276  * allocates a buffer with h2o_buffer_try_reserve. aborts on allocation failure.
277  * @return buffer to which the next data should be stored
278  */
279 h2o_iovec_t h2o_buffer_reserve(h2o_buffer_t **inbuf, size_t min_guarantee);
280 /**
281  * allocates a buffer.
282  * @param inbuf - pointer to a pointer pointing to the structure (set *inbuf to NULL to allocate a new buffer)
283  * @param min_guarantee minimum number of additional bytes to reserve
284  * @return buffer to which the next data should be stored
285  * @note When called against a new buffer, the function returns a buffer twice the size of requested guarantee.  The function uses
286  * exponential backoff for already-allocated buffers.
287  */
288 h2o_iovec_t h2o_buffer_try_reserve(h2o_buffer_t **inbuf, size_t min_guarantee) __attribute__((warn_unused_result));
289 /**
290  * copies @len bytes from @src to @dst, calling h2o_buffer_reserve. aborts on allocation failure.
291  */
292 static void h2o_buffer_append(h2o_buffer_t **dst, const void *src, size_t len);
293 /**
294  * variant of h2o_buffer_append that does not abort on failure
295  * @return a boolean indicating if allocation has succeeded
296  */
297 static int h2o_buffer_try_append(h2o_buffer_t **dst, const void *src, size_t len) __attribute__((warn_unused_result));
298 /**
299  * throws away given size of the data from the buffer.
300  * @param delta number of octets to be drained from the buffer
301  */
302 void h2o_buffer_consume(h2o_buffer_t **inbuf, size_t delta);
303 /**
304  * throws away entire data being store in the buffer
305  * @param record_capacity if set to true, retains the current capacity of the buffer, and when memory reservation is requested the
306  *                        next time, allocates memory as large as the recorded capacity. Otherwise, memory would be reserved based
307  *                        on the value of `min_guarantee`, current size, and the prototype.
308  */
309 void h2o_buffer_consume_all(h2o_buffer_t **inbuf, int record_capacity);
310 /**
311  * resets the buffer prototype
312  */
313 static void h2o_buffer_set_prototype(h2o_buffer_t **buffer, h2o_buffer_prototype_t *prototype);
314 /**
315  * registers a buffer to memory pool, so that it would be freed when the pool is flushed.  Note that the buffer cannot be resized
316  * after it is linked.
317  */
318 static void h2o_buffer_link_to_pool(h2o_buffer_t *buffer, h2o_mem_pool_t *pool);
319 void h2o_buffer__dispose_linked(void *p);
320 /**
321  *
322  */
323 static void h2o_doublebuffer_init(h2o_doublebuffer_t *db, h2o_buffer_prototype_t *prototype);
324 /**
325  *
326  */
327 static void h2o_doublebuffer_dispose(h2o_doublebuffer_t *db);
328 /**
329  * Given a double buffer and a pointer to a buffer to which the caller is writing data, returns a vector containing data to be sent
330  * (e.g., by calling `h2o_send`).  `max_bytes` designates the maximum size of the vector to be returned.  When the double buffer is
331  * empty, `*receiving` is moved to the double buffer, and upon return `*receiving` will contain an empty buffer to which the caller
332  * should append new data.
333  */
334 static h2o_iovec_t h2o_doublebuffer_prepare(h2o_doublebuffer_t *db, h2o_buffer_t **receiving, size_t max_bytes);
335 /**
336  * Marks that empty data is inflight. This function can be called when making preparations to call `h2o_send` but when only the HTTP
337  * response header fields are available.
338  */
339 static void h2o_doublebuffer_prepare_empty(h2o_doublebuffer_t *db);
340 /**
341  * Consumes bytes being marked as inflight (by previous call to `h2o_doublebuffer_prepare`). The intended design pattern is to call
342  * this function and then the generator's `do_send` function in the `do_proceed` callback. See lib/handler/fastcgi.c.
343  */
344 static void h2o_doublebuffer_consume(h2o_doublebuffer_t *db);
345 /**
346  * grows the vector so that it could store at least new_capacity elements of given size (or dies if impossible).
347  * @param pool memory pool that the vector is using
348  * @param vector the vector
349  * @param element_size size of the elements stored in the vector
350  * @param new_capacity the capacity of the buffer after the function returns
351  */
352 #define h2o_vector_reserve(pool, vector, new_capacity)                                                                             \
353     h2o_vector__reserve((pool), (h2o_vector_t *)(void *)(vector), H2O_ALIGNOF((vector)->entries[0]), sizeof((vector)->entries[0]), \
354                         (new_capacity))
355 static void h2o_vector__reserve(h2o_mem_pool_t *pool, h2o_vector_t *vector, size_t alignment, size_t element_size,
356                                 size_t new_capacity);
357 void h2o_vector__expand(h2o_mem_pool_t *pool, h2o_vector_t *vector, size_t alignment, size_t element_size, size_t new_capacity);
358 /**
359  * erase the entry at given index from the vector
360  */
361 #define h2o_vector_erase(vector, index) h2o_vector__erase((h2o_vector_t *)(void *)(vector), sizeof((vector)->entries[0]), (index))
362 static void h2o_vector__erase(h2o_vector_t *vector, size_t element_size, size_t index);
363 
364 /**
365  * tests if target chunk (target_len bytes long) is equal to test chunk (test_len bytes long)
366  */
367 static int h2o_memis(const void *target, size_t target_len, const void *test, size_t test_len);
368 
369 /**
370  * variant of memchr that searches the string from tail
371  */
372 static void *h2o_memrchr(const void *s, int c, size_t n);
373 
374 /**
375  * secure memset
376  */
377 static void *h2o_mem_set_secure(void *b, int c, size_t len);
378 
379 /**
380  * swaps contents of memory
381  */
382 void h2o_mem_swap(void *x, void *y, size_t len);
383 
384 /**
385  * emits hexdump of given buffer to fp
386  */
387 void h2o_dump_memory(FILE *fp, const char *buf, size_t len);
388 
389 /**
390  * appends an element to a NULL-terminated list allocated using malloc
391  */
392 void h2o_append_to_null_terminated_list(void ***list, void *element);
393 
394 extern __thread h2o_mem_recycle_t h2o_mem_pool_allocator;
395 extern size_t h2o_mmap_errors;
396 
397 /* inline defs */
398 
h2o_memcpy(void * dst,const void * src,size_t n)399 inline void *h2o_memcpy(void *dst, const void *src, size_t n)
400 {
401     if (src != NULL)
402         return memcpy(dst, src, n);
403     else if (n != 0)
404         h2o_fatal("null pointer passed to memcpy");
405     return dst;
406 }
407 
h2o_iovec_init(const void * base,size_t len)408 inline h2o_iovec_t h2o_iovec_init(const void *base, size_t len)
409 {
410     /* intentionally declared to take a "const void*" since it may contain any type of data and since _some_ buffers are constant */
411     h2o_iovec_t buf;
412     buf.base = (char *)base;
413     buf.len = len;
414     return buf;
415 }
416 
h2o_mem_alloc(size_t sz)417 inline void *h2o_mem_alloc(size_t sz)
418 {
419     void *p = malloc(sz);
420     if (p == NULL)
421         h2o_fatal("no memory");
422     return p;
423 }
424 
h2o_mem_realloc(void * oldp,size_t sz)425 inline void *h2o_mem_realloc(void *oldp, size_t sz)
426 {
427     void *newp = realloc(oldp, sz);
428     if (newp == NULL) {
429         h2o_fatal("no memory");
430         return oldp;
431     }
432     return newp;
433 }
434 
h2o_mem_alloc_pool_aligned(h2o_mem_pool_t * pool,size_t alignment,size_t size)435 inline void *h2o_mem_alloc_pool_aligned(h2o_mem_pool_t *pool, size_t alignment, size_t size)
436 {
437     /* C11 6.2.8: "Every valid alignment value shall be a nonnegative integral power of two"; assert will be resolved at compile-
438      * time for performance-sensitive cases */
439     assert(alignment != 0 && (alignment & (alignment - 1)) == 0);
440     return h2o_mem__do_alloc_pool_aligned(pool, alignment, size);
441 }
442 
h2o_mem_addref_shared(void * p)443 inline void h2o_mem_addref_shared(void *p)
444 {
445     struct st_h2o_mem_pool_shared_entry_t *entry = H2O_STRUCT_FROM_MEMBER(struct st_h2o_mem_pool_shared_entry_t, bytes, p);
446     assert(entry->refcnt != 0);
447     ++entry->refcnt;
448 }
449 
h2o_mem_release_shared(void * p)450 inline int h2o_mem_release_shared(void *p)
451 {
452     struct st_h2o_mem_pool_shared_entry_t *entry = H2O_STRUCT_FROM_MEMBER(struct st_h2o_mem_pool_shared_entry_t, bytes, p);
453     assert(entry->refcnt != 0);
454     if (--entry->refcnt == 0) {
455         if (entry->dispose != NULL)
456             entry->dispose(entry->bytes);
457         free(entry);
458         return 1;
459     }
460     return 0;
461 }
462 
h2o_buffer_init(h2o_buffer_t ** buffer,h2o_buffer_prototype_t * prototype)463 inline void h2o_buffer_init(h2o_buffer_t **buffer, h2o_buffer_prototype_t *prototype)
464 {
465     *buffer = &prototype->_initial_buf;
466 }
467 
h2o_buffer_dispose(h2o_buffer_t ** _buffer)468 inline void h2o_buffer_dispose(h2o_buffer_t **_buffer)
469 {
470     h2o_buffer_t *buffer = *_buffer;
471     *_buffer = NULL;
472     if (buffer->_prototype != NULL)
473         h2o_buffer__do_free(buffer);
474 }
475 
h2o_buffer_set_prototype(h2o_buffer_t ** buffer,h2o_buffer_prototype_t * prototype)476 inline void h2o_buffer_set_prototype(h2o_buffer_t **buffer, h2o_buffer_prototype_t *prototype)
477 {
478     if ((*buffer)->_prototype != NULL)
479         (*buffer)->_prototype = prototype;
480     else
481         *buffer = &prototype->_initial_buf;
482 }
483 
h2o_buffer_link_to_pool(h2o_buffer_t * buffer,h2o_mem_pool_t * pool)484 inline void h2o_buffer_link_to_pool(h2o_buffer_t *buffer, h2o_mem_pool_t *pool)
485 {
486     h2o_buffer_t **slot = (h2o_buffer_t **)h2o_mem_alloc_shared(pool, sizeof(*slot), h2o_buffer__dispose_linked);
487     *slot = buffer;
488 }
489 
h2o_buffer_append(h2o_buffer_t ** dst,const void * src,size_t len)490 inline void h2o_buffer_append(h2o_buffer_t **dst, const void *src, size_t len)
491 {
492     h2o_iovec_t buf = h2o_buffer_reserve(dst, len);
493     h2o_memcpy(buf.base, src, len);
494     (*dst)->size += len;
495 }
496 
h2o_buffer_try_append(h2o_buffer_t ** dst,const void * src,size_t len)497 inline int h2o_buffer_try_append(h2o_buffer_t **dst, const void *src, size_t len)
498 {
499     h2o_iovec_t buf = h2o_buffer_try_reserve(dst, len);
500     if (buf.base == NULL)
501         return 0;
502     h2o_memcpy(buf.base, src, len);
503     (*dst)->size += len;
504     return 1;
505 }
506 
h2o_doublebuffer_init(h2o_doublebuffer_t * db,h2o_buffer_prototype_t * prototype)507 inline void h2o_doublebuffer_init(h2o_doublebuffer_t *db, h2o_buffer_prototype_t *prototype)
508 {
509     h2o_buffer_init(&db->buf, prototype);
510     db->inflight = 0;
511     db->_bytes_inflight = 0;
512 }
513 
h2o_doublebuffer_dispose(h2o_doublebuffer_t * db)514 inline void h2o_doublebuffer_dispose(h2o_doublebuffer_t *db)
515 {
516     h2o_buffer_dispose(&db->buf);
517 }
518 
h2o_doublebuffer_prepare(h2o_doublebuffer_t * db,h2o_buffer_t ** receiving,size_t max_bytes)519 inline h2o_iovec_t h2o_doublebuffer_prepare(h2o_doublebuffer_t *db, h2o_buffer_t **receiving, size_t max_bytes)
520 {
521     assert(!db->inflight);
522     assert(max_bytes != 0);
523 
524     if (db->buf->size == 0) {
525         if ((*receiving)->size == 0)
526             return h2o_iovec_init(NULL, 0);
527         /* swap buffers */
528         h2o_buffer_t *t = db->buf;
529         db->buf = *receiving;
530         *receiving = t;
531     }
532     if ((db->_bytes_inflight = db->buf->size) > max_bytes)
533         db->_bytes_inflight = max_bytes;
534     db->inflight = 1;
535     return h2o_iovec_init(db->buf->bytes, db->_bytes_inflight);
536 }
537 
h2o_doublebuffer_prepare_empty(h2o_doublebuffer_t * db)538 inline void h2o_doublebuffer_prepare_empty(h2o_doublebuffer_t *db)
539 {
540     assert(!db->inflight);
541     db->inflight = 1;
542 }
543 
h2o_doublebuffer_consume(h2o_doublebuffer_t * db)544 inline void h2o_doublebuffer_consume(h2o_doublebuffer_t *db)
545 {
546     assert(db->inflight);
547     db->inflight = 0;
548 
549     if (db->buf->size == db->_bytes_inflight) {
550         h2o_buffer_consume_all(&db->buf, 1);
551     } else {
552         h2o_buffer_consume(&db->buf, db->_bytes_inflight);
553     }
554     db->_bytes_inflight = 0;
555 }
556 
h2o_vector__reserve(h2o_mem_pool_t * pool,h2o_vector_t * vector,size_t alignment,size_t element_size,size_t new_capacity)557 inline void h2o_vector__reserve(h2o_mem_pool_t *pool, h2o_vector_t *vector, size_t alignment, size_t element_size,
558                                 size_t new_capacity)
559 {
560     if (vector->capacity < new_capacity) {
561         h2o_vector__expand(pool, vector, alignment, element_size, new_capacity);
562     }
563 }
564 
h2o_vector__erase(h2o_vector_t * vector,size_t element_size,size_t index)565 inline void h2o_vector__erase(h2o_vector_t *vector, size_t element_size, size_t index)
566 {
567     char *entries = (char *)vector->entries;
568     memmove(entries + element_size * index, entries + element_size * (index + 1), element_size * (vector->size - index - 1));
569     --vector->size;
570 }
571 
h2o_memis(const void * _target,size_t target_len,const void * _test,size_t test_len)572 inline int h2o_memis(const void *_target, size_t target_len, const void *_test, size_t test_len)
573 {
574     const char *target = (const char *)_target, *test = (const char *)_test;
575     if (target_len != test_len)
576         return 0;
577     if (target_len == 0)
578         return 1;
579     if (target[0] != test[0])
580         return 0;
581     return memcmp(target + 1, test + 1, test_len - 1) == 0;
582 }
583 
h2o_memrchr(const void * s,int c,size_t n)584 inline void *h2o_memrchr(const void *s, int c, size_t n)
585 {
586     if (n != 0) {
587         const char *p = (const char *)s + n;
588         do {
589             if (*--p == c)
590                 return (void *)p;
591         } while (p != s);
592     }
593     return NULL;
594 }
595 
h2o_mem_set_secure(void * b,int c,size_t len)596 inline void *h2o_mem_set_secure(void *b, int c, size_t len)
597 {
598     return h2o_mem__set_secure(b, c, len);
599 }
600 
601 #ifdef __cplusplus
602 }
603 #endif
604 
605 #endif
606