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