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