diff --git a/src/Makefile.am b/src/Makefile.am index e894c0c2..3c167b8c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -144,7 +144,8 @@ nghttpx_unittest_SOURCES = shrpx-unittest.cc \ util_test.cc util_test.h \ nghttp2_gzip_test.c nghttp2_gzip_test.h \ nghttp2_gzip.c nghttp2_gzip.h \ - ringbuf_test.cc ringbuf_test.h + ringbuf_test.cc ringbuf_test.h \ + memchunk_test.cc memchunk_test.h nghttpx_unittest_CPPFLAGS = ${AM_CPPFLAGS}\ -DNGHTTP2_TESTS_DIR=\"$(top_srcdir)/tests\" nghttpx_unittest_LDFLAGS = ${AM_LDFLAGS} \ diff --git a/src/memchunk.h b/src/memchunk.h index 43e4bfa9..c00c1e60 100644 --- a/src/memchunk.h +++ b/src/memchunk.h @@ -27,6 +27,8 @@ #include "nghttp2_config.h" +#include + #include #include @@ -100,6 +102,7 @@ template struct Pool { } freelist = m; } + using value_type = T; std::unique_ptr pool; T *freelist; size_t poolsize; @@ -226,9 +229,9 @@ template struct Memchunks { size_t len; }; -typedef Memchunk<4096> Memchunk4K; -typedef Pool MemchunkPool4K; -typedef Memchunks Memchunks4K; +using Memchunk4K = Memchunk<4096>; +using MemchunkPool4K = Pool; +using Memchunks4K = Memchunks; } // namespace nghttp2 diff --git a/src/memchunk_test.cc b/src/memchunk_test.cc new file mode 100644 index 00000000..7cba39ed --- /dev/null +++ b/src/memchunk_test.cc @@ -0,0 +1,198 @@ +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2015 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "memchunk_test.h" + +#include + +#include + +#include "memchunk.h" + +namespace nghttp2 { + +void test_pool_recycle(void) { + MemchunkPool4K pool; + + CU_ASSERT(!pool.pool); + CU_ASSERT(0 == pool.poolsize); + CU_ASSERT(nullptr == pool.freelist); + + auto m1 = pool.get(); + + CU_ASSERT(m1 == pool.pool.get()); + CU_ASSERT(MemchunkPool4K::value_type::size == pool.poolsize); + CU_ASSERT(nullptr == pool.freelist); + + auto m2 = pool.get(); + + CU_ASSERT(m2 == pool.pool.get()); + CU_ASSERT(2 * MemchunkPool4K::value_type::size == pool.poolsize); + CU_ASSERT(nullptr == pool.freelist); + CU_ASSERT(m1 == m2->knext.get()); + CU_ASSERT(nullptr == m1->knext.get()); + + auto m3 = pool.get(); + + CU_ASSERT(m3 == pool.pool.get()); + CU_ASSERT(3 * MemchunkPool4K::value_type::size == pool.poolsize); + CU_ASSERT(nullptr == pool.freelist); + + pool.recycle(m3); + + CU_ASSERT(m3 == pool.pool.get()); + CU_ASSERT(3 * MemchunkPool4K::value_type::size == pool.poolsize); + CU_ASSERT(m3 == pool.freelist); + + auto m4 = pool.get(); + + CU_ASSERT(m3 == m4); + CU_ASSERT(m4 == pool.pool.get()); + CU_ASSERT(3 * MemchunkPool4K::value_type::size == pool.poolsize); + CU_ASSERT(nullptr == pool.freelist); + + pool.recycle(m2); + pool.recycle(m1); + + CU_ASSERT(m1 == pool.freelist); + CU_ASSERT(m2 == m1->next); + CU_ASSERT(nullptr == m2->next); +} + +using Memchunk16 = Memchunk<16>; +using MemchunkPool16 = Pool; +using Memchunks16 = Memchunks; + +void test_memchunks_append(void) { + MemchunkPool16 pool; + Memchunks16 chunks(&pool); + + chunks.append_cstr("012"); + + auto m = chunks.tail; + + CU_ASSERT(3 == m->len()); + CU_ASSERT(13 == m->left()); + + chunks.append_cstr("3456789abcdef@"); + + CU_ASSERT(16 == m->len()); + CU_ASSERT(0 == m->left()); + + m = chunks.tail; + + CU_ASSERT(1 == m->len()); + CU_ASSERT(15 == m->left()); + CU_ASSERT(17 == chunks.rleft()); + + char buf[16]; + size_t nread; + + nread = chunks.remove(buf, 8); + + CU_ASSERT(8 == nread); + CU_ASSERT(0 == memcmp("01234567", buf, nread)); + CU_ASSERT(9 == chunks.rleft()); + + nread = chunks.remove(buf, sizeof(buf)); + + CU_ASSERT(9 == nread); + CU_ASSERT(0 == memcmp("89abcdef@", buf, nread)); + CU_ASSERT(0 == chunks.rleft()); + CU_ASSERT(nullptr == chunks.head); + CU_ASSERT(nullptr == chunks.tail); + CU_ASSERT(32 == pool.poolsize); +} + +void test_memchunks_drain(void) { + MemchunkPool16 pool; + Memchunks16 chunks(&pool); + + chunks.append_cstr("0123456789"); + + size_t nread; + + nread = chunks.drain(3); + + CU_ASSERT(3 == nread); + + char buf[16]; + + nread = chunks.remove(buf, sizeof(buf)); + + CU_ASSERT(7 == nread); + CU_ASSERT(0 == memcmp("3456789", buf, nread)); +} + +void test_memchunks_riovec(void) { + MemchunkPool16 pool; + Memchunks16 chunks(&pool); + + char buf[3 * 16]; + + chunks.append(buf, sizeof(buf)); + + struct iovec iov[2]; + auto iovcnt = chunks.riovec(iov, util::array_size(iov)); + + auto m = chunks.head; + + CU_ASSERT(2 == iovcnt); + CU_ASSERT(m->begin == iov[0].iov_base); + CU_ASSERT(m->len() == iov[0].iov_len); + + m = m->next; + + CU_ASSERT(m->begin == iov[1].iov_base); + CU_ASSERT(m->len() == iov[1].iov_len); + + chunks.drain(2 * 16); + + iovcnt = chunks.riovec(iov, util::array_size(iov)); + + CU_ASSERT(1 == iovcnt); + + m = chunks.head; + CU_ASSERT(m->begin == iov[0].iov_base); + CU_ASSERT(m->len() == iov[0].iov_len); +} + +void test_memchunks_recycle(void) { + MemchunkPool16 pool; + { + Memchunks16 chunks(&pool); + char buf[32]; + chunks.append(buf, sizeof(buf)); + } + CU_ASSERT(32 == pool.poolsize); + CU_ASSERT(nullptr != pool.freelist); + + auto m = pool.freelist; + m = m->next; + + CU_ASSERT(nullptr != m); + CU_ASSERT(nullptr == m->next); +} + +} // namespace nghttp2 diff --git a/src/memchunk_test.h b/src/memchunk_test.h new file mode 100644 index 00000000..31e2665c --- /dev/null +++ b/src/memchunk_test.h @@ -0,0 +1,38 @@ +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2015 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef MEMCHUNK_TEST_H +#define MEMCHUNK_TEST_H + +namespace nghttp2 { + +void test_pool_recycle(void); +void test_memchunks_append(void); +void test_memchunks_drain(void); +void test_memchunks_riovec(void); +void test_memchunks_recycle(void); + +} // namespace nghttp2 + +#endif // MEMCHUNK_TEST_H diff --git a/src/shrpx-unittest.cc b/src/shrpx-unittest.cc index 1e9cda83..2859f425 100644 --- a/src/shrpx-unittest.cc +++ b/src/shrpx-unittest.cc @@ -39,6 +39,7 @@ #include "util_test.h" #include "nghttp2_gzip_test.h" #include "ringbuf_test.h" +#include "memchunk_test.h" #include "shrpx_config.h" static int init_suite1(void) { return 0; } @@ -130,7 +131,13 @@ int main(int argc, char *argv[]) { shrpx::test_util_ipv6_numeric_addr) || !CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) || !CU_add_test(pSuite, "ringbuf_write", nghttp2::test_ringbuf_write) || - !CU_add_test(pSuite, "ringbuf_iovec", nghttp2::test_ringbuf_iovec)) { + !CU_add_test(pSuite, "ringbuf_iovec", nghttp2::test_ringbuf_iovec) || + !CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) || + !CU_add_test(pSuite, "memchunk_append", nghttp2::test_memchunks_append) || + !CU_add_test(pSuite, "memchunk_drain", nghttp2::test_memchunks_drain) || + !CU_add_test(pSuite, "memchunk_riovec", nghttp2::test_memchunks_riovec) || + !CU_add_test(pSuite, "memchunk_recycle", + nghttp2::test_memchunks_recycle)) { CU_cleanup_registry(); return CU_get_error(); }