diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index 730801ee17..31fc7c6e40 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -775,6 +775,91 @@ _ce_loom_pure_south(c3_w pgs_w) u3P.dit_w[bas_w - 1] &= 0xffffffff >> bit_w; } +/* _ce_loom_track_north(): [pgs_w] clean, followed by [dif_w] dirty. +*/ +void +_ce_loom_track_north(c3_w pgs_w, c3_w dif_w) +{ + c3_w blk_w = pgs_w >> 5; + c3_w bit_w = pgs_w & 31; + c3_w off_w; + + memset((void*)u3P.dit_w, 0, blk_w << 2); + + if ( bit_w ) { + c3_w tib_w = 32 - bit_w; + c3_w dat_w = u3P.dit_w[blk_w]; + + dat_w &= 0xffffffff << bit_w; + + if ( dif_w <= tib_w ) { + dat_w |= ((1 << dif_w) - 1) << bit_w; + dif_w = 0; + } + else { + dat_w |= 0xffffffff << bit_w; + dif_w -= tib_w; + } + + u3P.dit_w[blk_w] = dat_w; + blk_w += 1; + } + + off_w = blk_w; + blk_w = dif_w >> 5; + bit_w = dif_w & 31; + + memset((void*)(u3P.dit_w + off_w), 0xff, blk_w << 2); + + if ( bit_w ) { + u3P.dit_w[off_w + blk_w] |= (1 << bit_w) - 1; + } +} + +/* _ce_loom_track_south(): [pgs_w] clean, preceded by [dif_w] dirty. +*/ +void +_ce_loom_track_south(c3_w pgs_w, c3_w dif_w) +{ + c3_w blk_w = pgs_w >> 5; + c3_w bit_w = pgs_w & 31; + c3_w bas_w = ((u3P.pag_w - pgs_w) + 31) >> 5; + c3_w off_w; + + memset((void*)(u3P.dit_w + bas_w), 0, blk_w << 2); + + // the following index subtractions (bas_w, off) are safe, + // so long as the south segment never includes all pages + // + if ( bit_w ) { + c3_w tib_w = 32 - bit_w; + c3_w dat_w = u3P.dit_w[--bas_w]; + + dat_w &= 0xffffffff >> bit_w; + + if ( dif_w <= tib_w ) { + dat_w |= ((1 << dif_w) - 1) << (tib_w - dif_w); + dif_w = 0; + } + else { + dat_w |= 0xffffffff >> bit_w; + dif_w -= tib_w; + } + + u3P.dit_w[bas_w] = dat_w; + } + + blk_w = dif_w >> 5; + bit_w = dif_w & 31; + off_w = bas_w - blk_w; + + memset((void*)(u3P.dit_w + off_w), 0xff, blk_w << 2); + + if ( bit_w ) { + u3P.dit_w[off_w - 1] |= ((1 << bit_w) - 1) << (32 - bit_w); + } +} + /* _ce_loom_protect_north(): protect/track pages from the bottom of memory. */ static void diff --git a/pkg/urbit/tests/events_tests.c b/pkg/urbit/tests/events_tests.c new file mode 100644 index 0000000000..f8615efcbf --- /dev/null +++ b/pkg/urbit/tests/events_tests.c @@ -0,0 +1,238 @@ +#include "all.h" + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + // NB: no loom + // + u3P.pag_w = u3a_pages; +} + +static c3_w +_check_north_clean(void) +{ + c3_w i_w, pag_w, blk_w, bit_w; + + for ( i_w = 0; i_w < u3P.pag_w; i_w++ ) { + pag_w = i_w; + blk_w = pag_w >> 5; + bit_w = pag_w & 31; + + if ( u3P.dit_w[blk_w] & (1 << bit_w) ) { + break; + } + } + + return i_w; +} + +static c3_w +_check_north_dirty(c3_w pgs_w, c3_w max_w) +{ + c3_w i_w, pag_w, blk_w, bit_w; + + for ( i_w = 0; i_w < max_w; i_w++ ) { + pag_w = i_w + pgs_w; + blk_w = pag_w >> 5; + bit_w = pag_w & 31; + + if ( !(u3P.dit_w[blk_w] & (1 << bit_w)) ) { + break; + } + } + + return i_w; +} + +static c3_w +_check_south_clean(void) +{ + c3_w i_w, pag_w, blk_w, bit_w; + + for ( i_w = 0; i_w < u3P.pag_w; i_w++ ) { + pag_w = u3P.pag_w - (i_w + 1); + blk_w = pag_w >> 5; + bit_w = pag_w & 31; + + if ( u3P.dit_w[blk_w] & (1 << bit_w) ) { + break; + } + } + + return i_w; +} + +static c3_w +_check_south_dirty(c3_w pgs_w, c3_w max_w) +{ + c3_w i_w, pag_w, blk_w, bit_w; + + for ( i_w = 0; i_w < max_w; i_w++ ) { + pag_w = u3P.pag_w - (i_w + pgs_w + 1); + blk_w = pag_w >> 5; + bit_w = pag_w & 31; + + if ( !(u3P.dit_w[blk_w] & (1 << bit_w)) ) { + break; + } + } + + return i_w; +} + +void +_ce_loom_track_north(c3_w pgs_w, c3_w dif_w); +void +_ce_loom_track_south(c3_w pgs_w, c3_w dif_w); + +static c3_i +_test_tracking(void) +{ + c3_w ret_w; + + u3e_foul(); + + if ( 0 != (ret_w = _check_north_clean()) ) { + fprintf(stderr, "test events track north init %u\r\n", ret_w); + return 0; + } + + if ( 0 != (ret_w = _check_south_clean()) ) { + fprintf(stderr, "test events track south init %u\r\n", ret_w); + return 0; + } + + _ce_loom_track_north(100, 0); + _ce_loom_track_south(1, 0); + + if ( 100 != (ret_w = _check_north_clean()) ) { + fprintf(stderr, "test events track north clean a %u\r\n", ret_w); + return 0; + } + + if ( 1 != (ret_w = _check_south_clean()) ) { + fprintf(stderr, "test events track south clean a %u\r\n", ret_w); + return 0; + } + + _ce_loom_track_north(75, 25); + _ce_loom_track_south(2, 0); + + if ( 75 != (ret_w = _check_north_clean()) ) { + fprintf(stderr, "test events track north clean b %u\r\n", ret_w); + return 0; + } + + if ( 25 != (ret_w = _check_north_dirty(75, 25)) ) { + fprintf(stderr, "test events track north dirty b %u\r\n", ret_w); + return 0; + } + + if ( 2 != (ret_w = _check_south_clean()) ) { + fprintf(stderr, "test events track south clean b %u\r\n", ret_w); + return 0; + } + + _ce_loom_track_north(55, 20); + _ce_loom_track_south(1, 1); + + if ( 55 != (ret_w = _check_north_clean()) ) { + fprintf(stderr, "test events track north clean c %u\r\n", ret_w); + return 0; + } + + if ( 20 != (ret_w = _check_north_dirty(55, 20)) ) { + fprintf(stderr, "test events track north dirty c %u\r\n", ret_w); + return 0; + } + + if ( 1 != (ret_w = _check_south_clean()) ) { + fprintf(stderr, "test events track south clean c %u\r\n", ret_w); + return 0; + } + + if ( 1 != (ret_w = _check_south_dirty(1, 1)) ) { + fprintf(stderr, "test events track north dirty c %u\r\n", ret_w); + return 0; + } + + _ce_loom_track_north(255, 0); + _ce_loom_track_south(48, 0); + + if ( 255 != (ret_w = _check_north_clean()) ) { + fprintf(stderr, "test events track north clean d %u\r\n", ret_w); + return 0; + } + + if ( 48 != (ret_w = _check_south_clean()) ) { + fprintf(stderr, "test events track south clean d %u\r\n", ret_w); + return 0; + } + + _ce_loom_track_north(213, 42); + _ce_loom_track_south(15, 33); + + if ( 213 != (ret_w = _check_north_clean()) ) { + fprintf(stderr, "test events track north clean e %u\r\n", ret_w); + return 0; + } + + if ( 42 != (ret_w = _check_north_dirty(213, 42)) ) { + fprintf(stderr, "test events track north dirty e %u\r\n", ret_w); + return 0; + } + + if ( 15 != (ret_w = _check_south_clean()) ) { + fprintf(stderr, "test events track south clean e %u\r\n", ret_w); + return 0; + } + + if ( 33 != (ret_w = _check_south_dirty(15, 33)) ) { + fprintf(stderr, "test events track north dirty e %u\r\n", ret_w); + return 0; + } + + _ce_loom_track_north(200, 13); + _ce_loom_track_south(10, 5); + + if ( 200 != (ret_w = _check_north_clean()) ) { + fprintf(stderr, "test events track north clean f %u\r\n", ret_w); + return 0; + } + + if ( 13 != (ret_w = _check_north_dirty(200, 13)) ) { + fprintf(stderr, "test events track north dirty f %u\r\n", ret_w); + return 0; + } + + if ( 10 != (ret_w = _check_south_clean()) ) { + fprintf(stderr, "test events track south clean f %u\r\n", ret_w); + return 0; + } + + if ( 5 != (ret_w = _check_south_dirty(10, 5)) ) { + fprintf(stderr, "test events track north dirty f %u\r\n", ret_w); + return 0; + } + + return 1; +} + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + if ( !_test_tracking() ) { + fprintf(stderr, "test_events: tracking: failed\r\n"); + exit(1); + } + + fprintf(stderr, "test_events: ok\n"); + + return 0; +}