buf_writer.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #include "test/jemalloc_test.h"
  2. #include "jemalloc/internal/buf_writer.h"
  3. #define TEST_BUF_SIZE 16
  4. #define UNIT_MAX (TEST_BUF_SIZE * 3)
  5. static size_t test_write_len;
  6. static char test_buf[TEST_BUF_SIZE];
  7. static uint64_t arg;
  8. static uint64_t arg_store;
  9. static void
  10. test_write_cb(void *cbopaque, const char *s) {
  11. size_t prev_test_write_len = test_write_len;
  12. test_write_len += strlen(s); /* only increase the length */
  13. arg_store = *(uint64_t *)cbopaque; /* only pass along the argument */
  14. assert_zu_le(prev_test_write_len, test_write_len,
  15. "Test write overflowed");
  16. }
  17. static void
  18. test_buf_writer_body(tsdn_t *tsdn, buf_writer_t *buf_writer) {
  19. char s[UNIT_MAX + 1];
  20. size_t n_unit, remain, i;
  21. ssize_t unit;
  22. assert(buf_writer->buf != NULL);
  23. memset(s, 'a', UNIT_MAX);
  24. arg = 4; /* Starting value of random argument. */
  25. arg_store = arg;
  26. for (unit = UNIT_MAX; unit >= 0; --unit) {
  27. /* unit keeps decreasing, so strlen(s) is always unit. */
  28. s[unit] = '\0';
  29. for (n_unit = 1; n_unit <= 3; ++n_unit) {
  30. test_write_len = 0;
  31. remain = 0;
  32. for (i = 1; i <= n_unit; ++i) {
  33. arg = prng_lg_range_u64(&arg, 64);
  34. buf_writer_cb(buf_writer, s);
  35. remain += unit;
  36. if (remain > buf_writer->buf_size) {
  37. /* Flushes should have happened. */
  38. assert_u64_eq(arg_store, arg, "Call "
  39. "back argument didn't get through");
  40. remain %= buf_writer->buf_size;
  41. if (remain == 0) {
  42. /* Last flush should be lazy. */
  43. remain += buf_writer->buf_size;
  44. }
  45. }
  46. assert_zu_eq(test_write_len + remain, i * unit,
  47. "Incorrect length after writing %zu strings"
  48. " of length %zu", i, unit);
  49. }
  50. buf_writer_flush(buf_writer);
  51. expect_zu_eq(test_write_len, n_unit * unit,
  52. "Incorrect length after flushing at the end of"
  53. " writing %zu strings of length %zu", n_unit, unit);
  54. }
  55. }
  56. buf_writer_terminate(tsdn, buf_writer);
  57. }
  58. TEST_BEGIN(test_buf_write_static) {
  59. buf_writer_t buf_writer;
  60. tsdn_t *tsdn = tsdn_fetch();
  61. assert_false(buf_writer_init(tsdn, &buf_writer, test_write_cb, &arg,
  62. test_buf, TEST_BUF_SIZE),
  63. "buf_writer_init() should not encounter error on static buffer");
  64. test_buf_writer_body(tsdn, &buf_writer);
  65. }
  66. TEST_END
  67. TEST_BEGIN(test_buf_write_dynamic) {
  68. buf_writer_t buf_writer;
  69. tsdn_t *tsdn = tsdn_fetch();
  70. assert_false(buf_writer_init(tsdn, &buf_writer, test_write_cb, &arg,
  71. NULL, TEST_BUF_SIZE), "buf_writer_init() should not OOM");
  72. test_buf_writer_body(tsdn, &buf_writer);
  73. }
  74. TEST_END
  75. TEST_BEGIN(test_buf_write_oom) {
  76. buf_writer_t buf_writer;
  77. tsdn_t *tsdn = tsdn_fetch();
  78. assert_true(buf_writer_init(tsdn, &buf_writer, test_write_cb, &arg,
  79. NULL, SC_LARGE_MAXCLASS + 1), "buf_writer_init() should OOM");
  80. assert(buf_writer.buf == NULL);
  81. char s[UNIT_MAX + 1];
  82. size_t n_unit, i;
  83. ssize_t unit;
  84. memset(s, 'a', UNIT_MAX);
  85. arg = 4; /* Starting value of random argument. */
  86. arg_store = arg;
  87. for (unit = UNIT_MAX; unit >= 0; unit -= UNIT_MAX / 4) {
  88. /* unit keeps decreasing, so strlen(s) is always unit. */
  89. s[unit] = '\0';
  90. for (n_unit = 1; n_unit <= 3; ++n_unit) {
  91. test_write_len = 0;
  92. for (i = 1; i <= n_unit; ++i) {
  93. arg = prng_lg_range_u64(&arg, 64);
  94. buf_writer_cb(&buf_writer, s);
  95. assert_u64_eq(arg_store, arg,
  96. "Call back argument didn't get through");
  97. assert_zu_eq(test_write_len, i * unit,
  98. "Incorrect length after writing %zu strings"
  99. " of length %zu", i, unit);
  100. }
  101. buf_writer_flush(&buf_writer);
  102. expect_zu_eq(test_write_len, n_unit * unit,
  103. "Incorrect length after flushing at the end of"
  104. " writing %zu strings of length %zu", n_unit, unit);
  105. }
  106. }
  107. buf_writer_terminate(tsdn, &buf_writer);
  108. }
  109. TEST_END
  110. static int test_read_count;
  111. static size_t test_read_len;
  112. static uint64_t arg_sum;
  113. ssize_t
  114. test_read_cb(void *cbopaque, void *buf, size_t limit) {
  115. static uint64_t rand = 4;
  116. arg_sum += *(uint64_t *)cbopaque;
  117. assert_zu_gt(limit, 0, "Limit for read_cb must be positive");
  118. --test_read_count;
  119. if (test_read_count == 0) {
  120. return -1;
  121. } else {
  122. size_t read_len = limit;
  123. if (limit > 1) {
  124. rand = prng_range_u64(&rand, (uint64_t)limit);
  125. read_len -= (size_t)rand;
  126. }
  127. assert(read_len > 0);
  128. memset(buf, 'a', read_len);
  129. size_t prev_test_read_len = test_read_len;
  130. test_read_len += read_len;
  131. assert_zu_le(prev_test_read_len, test_read_len,
  132. "Test read overflowed");
  133. return read_len;
  134. }
  135. }
  136. static void
  137. test_buf_writer_pipe_body(tsdn_t *tsdn, buf_writer_t *buf_writer) {
  138. arg = 4; /* Starting value of random argument. */
  139. for (int count = 5; count > 0; --count) {
  140. arg = prng_lg_range_u64(&arg, 64);
  141. arg_sum = 0;
  142. test_read_count = count;
  143. test_read_len = 0;
  144. test_write_len = 0;
  145. buf_writer_pipe(buf_writer, test_read_cb, &arg);
  146. assert(test_read_count == 0);
  147. expect_u64_eq(arg_sum, arg * count, "");
  148. expect_zu_eq(test_write_len, test_read_len,
  149. "Write length should be equal to read length");
  150. }
  151. buf_writer_terminate(tsdn, buf_writer);
  152. }
  153. TEST_BEGIN(test_buf_write_pipe) {
  154. buf_writer_t buf_writer;
  155. tsdn_t *tsdn = tsdn_fetch();
  156. assert_false(buf_writer_init(tsdn, &buf_writer, test_write_cb, &arg,
  157. test_buf, TEST_BUF_SIZE),
  158. "buf_writer_init() should not encounter error on static buffer");
  159. test_buf_writer_pipe_body(tsdn, &buf_writer);
  160. }
  161. TEST_END
  162. TEST_BEGIN(test_buf_write_pipe_oom) {
  163. buf_writer_t buf_writer;
  164. tsdn_t *tsdn = tsdn_fetch();
  165. assert_true(buf_writer_init(tsdn, &buf_writer, test_write_cb, &arg,
  166. NULL, SC_LARGE_MAXCLASS + 1), "buf_writer_init() should OOM");
  167. test_buf_writer_pipe_body(tsdn, &buf_writer);
  168. }
  169. TEST_END
  170. int
  171. main(void) {
  172. return test(
  173. test_buf_write_static,
  174. test_buf_write_dynamic,
  175. test_buf_write_oom,
  176. test_buf_write_pipe,
  177. test_buf_write_pipe_oom);
  178. }