12c593315Sopenharmony_ci/* 22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library 32c593315Sopenharmony_ci * 42c593315Sopenharmony_ci * Copyright (c) 2016 Tatsuhiro Tsujikawa 52c593315Sopenharmony_ci * 62c593315Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining 72c593315Sopenharmony_ci * a copy of this software and associated documentation files (the 82c593315Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 92c593315Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 102c593315Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to 112c593315Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 122c593315Sopenharmony_ci * the following conditions: 132c593315Sopenharmony_ci * 142c593315Sopenharmony_ci * The above copyright notice and this permission notice shall be 152c593315Sopenharmony_ci * included in all copies or substantial portions of the Software. 162c593315Sopenharmony_ci * 172c593315Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 182c593315Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 192c593315Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 202c593315Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 212c593315Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 222c593315Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 232c593315Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 242c593315Sopenharmony_ci */ 252c593315Sopenharmony_ci#ifndef ALLOCATOR_H 262c593315Sopenharmony_ci#define ALLOCATOR_H 272c593315Sopenharmony_ci 282c593315Sopenharmony_ci#include "nghttp2_config.h" 292c593315Sopenharmony_ci 302c593315Sopenharmony_ci#ifndef _WIN32 312c593315Sopenharmony_ci# include <sys/uio.h> 322c593315Sopenharmony_ci#endif // !_WIN32 332c593315Sopenharmony_ci 342c593315Sopenharmony_ci#include <cassert> 352c593315Sopenharmony_ci#include <utility> 362c593315Sopenharmony_ci 372c593315Sopenharmony_ci#include "template.h" 382c593315Sopenharmony_ci 392c593315Sopenharmony_cinamespace nghttp2 { 402c593315Sopenharmony_ci 412c593315Sopenharmony_cistruct MemBlock { 422c593315Sopenharmony_ci // The next MemBlock to chain them. This is for book keeping 432c593315Sopenharmony_ci // purpose to free them later. 442c593315Sopenharmony_ci MemBlock *next; 452c593315Sopenharmony_ci // begin is the pointer to the beginning of buffer. last is the 462c593315Sopenharmony_ci // location of next write. end is the one beyond of the end of the 472c593315Sopenharmony_ci // buffer. 482c593315Sopenharmony_ci uint8_t *begin, *last, *end; 492c593315Sopenharmony_ci}; 502c593315Sopenharmony_ci 512c593315Sopenharmony_ci// BlockAllocator allocates memory block with given size at once, and 522c593315Sopenharmony_ci// cuts the region from it when allocation is requested. If the 532c593315Sopenharmony_ci// requested size is larger than given threshold (plus small internal 542c593315Sopenharmony_ci// overhead), it will be allocated in a distinct buffer on demand. 552c593315Sopenharmony_ci// The |isolation_threshold| must be less than or equal to 562c593315Sopenharmony_ci// |block_size|. 572c593315Sopenharmony_cistruct BlockAllocator { 582c593315Sopenharmony_ci BlockAllocator(size_t block_size, size_t isolation_threshold) 592c593315Sopenharmony_ci : retain(nullptr), 602c593315Sopenharmony_ci head(nullptr), 612c593315Sopenharmony_ci block_size(block_size), 622c593315Sopenharmony_ci isolation_threshold(std::min(block_size, isolation_threshold)) { 632c593315Sopenharmony_ci assert(isolation_threshold <= block_size); 642c593315Sopenharmony_ci } 652c593315Sopenharmony_ci 662c593315Sopenharmony_ci ~BlockAllocator() { reset(); } 672c593315Sopenharmony_ci 682c593315Sopenharmony_ci BlockAllocator(BlockAllocator &&other) noexcept 692c593315Sopenharmony_ci : retain{std::exchange(other.retain, nullptr)}, 702c593315Sopenharmony_ci head{std::exchange(other.head, nullptr)}, 712c593315Sopenharmony_ci block_size(other.block_size), 722c593315Sopenharmony_ci isolation_threshold(other.isolation_threshold) {} 732c593315Sopenharmony_ci 742c593315Sopenharmony_ci BlockAllocator &operator=(BlockAllocator &&other) noexcept { 752c593315Sopenharmony_ci reset(); 762c593315Sopenharmony_ci 772c593315Sopenharmony_ci retain = std::exchange(other.retain, nullptr); 782c593315Sopenharmony_ci head = std::exchange(other.head, nullptr); 792c593315Sopenharmony_ci block_size = other.block_size; 802c593315Sopenharmony_ci isolation_threshold = other.isolation_threshold; 812c593315Sopenharmony_ci 822c593315Sopenharmony_ci return *this; 832c593315Sopenharmony_ci } 842c593315Sopenharmony_ci 852c593315Sopenharmony_ci BlockAllocator(const BlockAllocator &) = delete; 862c593315Sopenharmony_ci BlockAllocator &operator=(const BlockAllocator &) = delete; 872c593315Sopenharmony_ci 882c593315Sopenharmony_ci void reset() { 892c593315Sopenharmony_ci for (auto mb = retain; mb;) { 902c593315Sopenharmony_ci auto next = mb->next; 912c593315Sopenharmony_ci delete[] reinterpret_cast<uint8_t *>(mb); 922c593315Sopenharmony_ci mb = next; 932c593315Sopenharmony_ci } 942c593315Sopenharmony_ci 952c593315Sopenharmony_ci retain = nullptr; 962c593315Sopenharmony_ci head = nullptr; 972c593315Sopenharmony_ci } 982c593315Sopenharmony_ci 992c593315Sopenharmony_ci MemBlock *alloc_mem_block(size_t size) { 1002c593315Sopenharmony_ci auto block = new uint8_t[sizeof(MemBlock) + size]; 1012c593315Sopenharmony_ci auto mb = reinterpret_cast<MemBlock *>(block); 1022c593315Sopenharmony_ci 1032c593315Sopenharmony_ci mb->next = retain; 1042c593315Sopenharmony_ci mb->begin = mb->last = block + sizeof(MemBlock); 1052c593315Sopenharmony_ci mb->end = mb->begin + size; 1062c593315Sopenharmony_ci retain = mb; 1072c593315Sopenharmony_ci return mb; 1082c593315Sopenharmony_ci } 1092c593315Sopenharmony_ci 1102c593315Sopenharmony_ci void *alloc(size_t size) { 1112c593315Sopenharmony_ci if (size + sizeof(size_t) >= isolation_threshold) { 1122c593315Sopenharmony_ci auto len = std::max(static_cast<size_t>(16), size); 1132c593315Sopenharmony_ci // We will store the allocated size in size_t field. 1142c593315Sopenharmony_ci auto mb = alloc_mem_block(len + sizeof(size_t)); 1152c593315Sopenharmony_ci auto sp = reinterpret_cast<size_t *>(mb->begin); 1162c593315Sopenharmony_ci *sp = len; 1172c593315Sopenharmony_ci mb->last = mb->end; 1182c593315Sopenharmony_ci return mb->begin + sizeof(size_t); 1192c593315Sopenharmony_ci } 1202c593315Sopenharmony_ci 1212c593315Sopenharmony_ci if (!head || 1222c593315Sopenharmony_ci head->end - head->last < static_cast<ssize_t>(size + sizeof(size_t))) { 1232c593315Sopenharmony_ci head = alloc_mem_block(block_size); 1242c593315Sopenharmony_ci } 1252c593315Sopenharmony_ci 1262c593315Sopenharmony_ci // We will store the allocated size in size_t field. 1272c593315Sopenharmony_ci auto res = head->last + sizeof(size_t); 1282c593315Sopenharmony_ci auto sp = reinterpret_cast<size_t *>(head->last); 1292c593315Sopenharmony_ci *sp = size; 1302c593315Sopenharmony_ci 1312c593315Sopenharmony_ci head->last = reinterpret_cast<uint8_t *>( 1322c593315Sopenharmony_ci (reinterpret_cast<intptr_t>(res + size) + 0xf) & ~0xf); 1332c593315Sopenharmony_ci 1342c593315Sopenharmony_ci return res; 1352c593315Sopenharmony_ci } 1362c593315Sopenharmony_ci 1372c593315Sopenharmony_ci // Returns allocated size for memory pointed by |ptr|. We assume 1382c593315Sopenharmony_ci // that |ptr| was returned from alloc() or realloc(). 1392c593315Sopenharmony_ci size_t get_alloc_length(void *ptr) { 1402c593315Sopenharmony_ci return *reinterpret_cast<size_t *>(static_cast<uint8_t *>(ptr) - 1412c593315Sopenharmony_ci sizeof(size_t)); 1422c593315Sopenharmony_ci } 1432c593315Sopenharmony_ci 1442c593315Sopenharmony_ci // Allocates memory of at least |size| bytes. If |ptr| is nullptr, 1452c593315Sopenharmony_ci // this is equivalent to alloc(size). If |ptr| is not nullptr, 1462c593315Sopenharmony_ci // obtain the allocated size for |ptr|, assuming that |ptr| was 1472c593315Sopenharmony_ci // returned from alloc() or realloc(). If the allocated size is 1482c593315Sopenharmony_ci // greater than or equal to size, |ptr| is returned. Otherwise, 1492c593315Sopenharmony_ci // allocates at least |size| bytes of memory, and the original 1502c593315Sopenharmony_ci // content pointed by |ptr| is copied to the newly allocated memory. 1512c593315Sopenharmony_ci void *realloc(void *ptr, size_t size) { 1522c593315Sopenharmony_ci if (!ptr) { 1532c593315Sopenharmony_ci return alloc(size); 1542c593315Sopenharmony_ci } 1552c593315Sopenharmony_ci auto alloclen = get_alloc_length(ptr); 1562c593315Sopenharmony_ci auto p = reinterpret_cast<uint8_t *>(ptr); 1572c593315Sopenharmony_ci if (size <= alloclen) { 1582c593315Sopenharmony_ci return ptr; 1592c593315Sopenharmony_ci } 1602c593315Sopenharmony_ci 1612c593315Sopenharmony_ci auto nalloclen = std::max(size + 1, alloclen * 2); 1622c593315Sopenharmony_ci 1632c593315Sopenharmony_ci auto res = alloc(nalloclen); 1642c593315Sopenharmony_ci std::copy_n(p, alloclen, static_cast<uint8_t *>(res)); 1652c593315Sopenharmony_ci 1662c593315Sopenharmony_ci return res; 1672c593315Sopenharmony_ci } 1682c593315Sopenharmony_ci 1692c593315Sopenharmony_ci // This holds live memory block to free them in dtor. 1702c593315Sopenharmony_ci MemBlock *retain; 1712c593315Sopenharmony_ci // Current memory block to use. 1722c593315Sopenharmony_ci MemBlock *head; 1732c593315Sopenharmony_ci // size of single memory block 1742c593315Sopenharmony_ci size_t block_size; 1752c593315Sopenharmony_ci // if allocation greater or equal to isolation_threshold bytes is 1762c593315Sopenharmony_ci // requested, allocate dedicated block. 1772c593315Sopenharmony_ci size_t isolation_threshold; 1782c593315Sopenharmony_ci}; 1792c593315Sopenharmony_ci 1802c593315Sopenharmony_ci// Makes a copy of |src|. The resulting string will be 1812c593315Sopenharmony_ci// NULL-terminated. 1822c593315Sopenharmony_citemplate <typename BlockAllocator> 1832c593315Sopenharmony_ciStringRef make_string_ref(BlockAllocator &alloc, const StringRef &src) { 1842c593315Sopenharmony_ci auto dst = static_cast<uint8_t *>(alloc.alloc(src.size() + 1)); 1852c593315Sopenharmony_ci auto p = dst; 1862c593315Sopenharmony_ci p = std::copy(std::begin(src), std::end(src), p); 1872c593315Sopenharmony_ci *p = '\0'; 1882c593315Sopenharmony_ci return StringRef{dst, src.size()}; 1892c593315Sopenharmony_ci} 1902c593315Sopenharmony_ci 1912c593315Sopenharmony_ci// private function used in concat_string_ref. this is the base 1922c593315Sopenharmony_ci// function of concat_string_ref_count(). 1932c593315Sopenharmony_ciinline constexpr size_t concat_string_ref_count(size_t acc) { return acc; } 1942c593315Sopenharmony_ci 1952c593315Sopenharmony_ci// private function used in concat_string_ref. This function counts 1962c593315Sopenharmony_ci// the sum of length of given arguments. The calculated length is 1972c593315Sopenharmony_ci// accumulated, and passed to the next function. 1982c593315Sopenharmony_citemplate <typename... Args> 1992c593315Sopenharmony_ciconstexpr size_t concat_string_ref_count(size_t acc, const StringRef &value, 2002c593315Sopenharmony_ci Args &&...args) { 2012c593315Sopenharmony_ci return concat_string_ref_count(acc + value.size(), 2022c593315Sopenharmony_ci std::forward<Args>(args)...); 2032c593315Sopenharmony_ci} 2042c593315Sopenharmony_ci 2052c593315Sopenharmony_ci// private function used in concat_string_ref. this is the base 2062c593315Sopenharmony_ci// function of concat_string_ref_copy(). 2072c593315Sopenharmony_ciinline uint8_t *concat_string_ref_copy(uint8_t *p) { return p; } 2082c593315Sopenharmony_ci 2092c593315Sopenharmony_ci// private function used in concat_string_ref. This function copies 2102c593315Sopenharmony_ci// given strings into |p|. |p| is incremented by the copied length, 2112c593315Sopenharmony_ci// and returned. In the end, return value points to the location one 2122c593315Sopenharmony_ci// beyond the last byte written. 2132c593315Sopenharmony_citemplate <typename... Args> 2142c593315Sopenharmony_ciuint8_t *concat_string_ref_copy(uint8_t *p, const StringRef &value, 2152c593315Sopenharmony_ci Args &&...args) { 2162c593315Sopenharmony_ci p = std::copy(std::begin(value), std::end(value), p); 2172c593315Sopenharmony_ci return concat_string_ref_copy(p, std::forward<Args>(args)...); 2182c593315Sopenharmony_ci} 2192c593315Sopenharmony_ci 2202c593315Sopenharmony_ci// Returns the string which is the concatenation of |args| in the 2212c593315Sopenharmony_ci// given order. The resulting string will be NULL-terminated. 2222c593315Sopenharmony_citemplate <typename BlockAllocator, typename... Args> 2232c593315Sopenharmony_ciStringRef concat_string_ref(BlockAllocator &alloc, Args &&...args) { 2242c593315Sopenharmony_ci size_t len = concat_string_ref_count(0, std::forward<Args>(args)...); 2252c593315Sopenharmony_ci auto dst = static_cast<uint8_t *>(alloc.alloc(len + 1)); 2262c593315Sopenharmony_ci auto p = dst; 2272c593315Sopenharmony_ci p = concat_string_ref_copy(p, std::forward<Args>(args)...); 2282c593315Sopenharmony_ci *p = '\0'; 2292c593315Sopenharmony_ci return StringRef{dst, len}; 2302c593315Sopenharmony_ci} 2312c593315Sopenharmony_ci 2322c593315Sopenharmony_ci// Returns the string which is the concatenation of |value| and |args| 2332c593315Sopenharmony_ci// in the given order. The resulting string will be NULL-terminated. 2342c593315Sopenharmony_ci// This function assumes that the pointer value value.c_str() was 2352c593315Sopenharmony_ci// obtained from alloc.alloc() or alloc.realloc(), and attempts to use 2362c593315Sopenharmony_ci// unused memory region by using alloc.realloc(). If value is empty, 2372c593315Sopenharmony_ci// then just call concat_string_ref(). 2382c593315Sopenharmony_citemplate <typename BlockAllocator, typename... Args> 2392c593315Sopenharmony_ciStringRef realloc_concat_string_ref(BlockAllocator &alloc, 2402c593315Sopenharmony_ci const StringRef &value, Args &&...args) { 2412c593315Sopenharmony_ci if (value.empty()) { 2422c593315Sopenharmony_ci return concat_string_ref(alloc, std::forward<Args>(args)...); 2432c593315Sopenharmony_ci } 2442c593315Sopenharmony_ci 2452c593315Sopenharmony_ci auto len = 2462c593315Sopenharmony_ci value.size() + concat_string_ref_count(0, std::forward<Args>(args)...); 2472c593315Sopenharmony_ci auto dst = static_cast<uint8_t *>( 2482c593315Sopenharmony_ci alloc.realloc(const_cast<uint8_t *>(value.byte()), len + 1)); 2492c593315Sopenharmony_ci auto p = dst + value.size(); 2502c593315Sopenharmony_ci p = concat_string_ref_copy(p, std::forward<Args>(args)...); 2512c593315Sopenharmony_ci *p = '\0'; 2522c593315Sopenharmony_ci 2532c593315Sopenharmony_ci return StringRef{dst, len}; 2542c593315Sopenharmony_ci} 2552c593315Sopenharmony_ci 2562c593315Sopenharmony_cistruct ByteRef { 2572c593315Sopenharmony_ci // The pointer to the beginning of the buffer. 2582c593315Sopenharmony_ci uint8_t *base; 2592c593315Sopenharmony_ci // The length of the buffer. 2602c593315Sopenharmony_ci size_t len; 2612c593315Sopenharmony_ci}; 2622c593315Sopenharmony_ci 2632c593315Sopenharmony_ci// Makes a buffer with given size. The resulting byte string might 2642c593315Sopenharmony_ci// not be NULL-terminated. 2652c593315Sopenharmony_citemplate <typename BlockAllocator> 2662c593315Sopenharmony_ciByteRef make_byte_ref(BlockAllocator &alloc, size_t size) { 2672c593315Sopenharmony_ci auto dst = static_cast<uint8_t *>(alloc.alloc(size)); 2682c593315Sopenharmony_ci return {dst, size}; 2692c593315Sopenharmony_ci} 2702c593315Sopenharmony_ci 2712c593315Sopenharmony_ci} // namespace nghttp2 2722c593315Sopenharmony_ci 2732c593315Sopenharmony_ci#endif // ALLOCATOR_H 274