static void validate_tree(nghttp2_stream *stream) { nghttp2_stream *si; if (!stream) { return; } for (; stream->dep_prev; stream = stream->dep_prev) ; assert(stream->stream_id == 0); assert(!stream->queued); fprintf(stderr, "checking...\n"); if (nghttp2_pq_empty(&stream->obq)) { fprintf(stderr, "root obq empty\n"); for (si = stream->dep_next; si; si = si->sib_next) { ensure_inactive(si); } } else { for (si = stream->dep_next; si; si = si->sib_next) { check_queued(si); } } check_sum_dep(stream); check_dep_prev(stream); }
static void ensure_inactive(nghttp2_stream *stream) { nghttp2_stream *si; if (stream->queued) { fprintf(stderr, "stream(%p)=%d, stream->queued = 1; want 0\n", stream, stream->stream_id); assert(0); } if (stream_active(stream)) { fprintf(stderr, "stream(%p)=%d, stream_active(stream) = 1; want 0\n", stream, stream->stream_id); assert(0); } if (!nghttp2_pq_empty(&stream->obq)) { fprintf(stderr, "stream(%p)=%d, nghttp2_pq_size() = %zu; want 0\n", stream, stream->stream_id, nghttp2_pq_size(&stream->obq)); assert(0); } for (si = stream->dep_next; si; si = si->sib_next) { ensure_inactive(si); } }
static int stream_update_dep_on_detach_item(nghttp2_stream *stream) { if (nghttp2_pq_empty(&stream->obq)) { stream_obq_remove(stream); } validate_tree(stream); return 0; }
void test_nghttp2_pq(void) { int i; nghttp2_pq pq; nghttp2_pq_init(&pq, pq_compar); CU_ASSERT(nghttp2_pq_empty(&pq)); CU_ASSERT(0 == nghttp2_pq_size(&pq)); CU_ASSERT(0 == nghttp2_pq_push(&pq, (void *)"foo")); CU_ASSERT(0 == nghttp2_pq_empty(&pq)); CU_ASSERT(1 == nghttp2_pq_size(&pq)); CU_ASSERT(strcmp("foo", nghttp2_pq_top(&pq)) == 0); CU_ASSERT(0 == nghttp2_pq_push(&pq, (void *)"bar")); CU_ASSERT(strcmp("bar", nghttp2_pq_top(&pq)) == 0); CU_ASSERT(0 == nghttp2_pq_push(&pq, (void *)"baz")); CU_ASSERT(strcmp("bar", nghttp2_pq_top(&pq)) == 0); CU_ASSERT(0 == nghttp2_pq_push(&pq, (void *)"C")); CU_ASSERT(4 == nghttp2_pq_size(&pq)); CU_ASSERT(strcmp("C", nghttp2_pq_top(&pq)) == 0); nghttp2_pq_pop(&pq); CU_ASSERT(3 == nghttp2_pq_size(&pq)); CU_ASSERT(strcmp("bar", nghttp2_pq_top(&pq)) == 0); nghttp2_pq_pop(&pq); CU_ASSERT(strcmp("baz", nghttp2_pq_top(&pq)) == 0); nghttp2_pq_pop(&pq); CU_ASSERT(strcmp("foo", nghttp2_pq_top(&pq)) == 0); nghttp2_pq_pop(&pq); CU_ASSERT(nghttp2_pq_empty(&pq)); CU_ASSERT(0 == nghttp2_pq_size(&pq)); CU_ASSERT(NULL == nghttp2_pq_top(&pq)); /* Add bunch of entry to see realloc works */ for (i = 0; i < 10000; ++i) { CU_ASSERT(0 == nghttp2_pq_push(&pq, (void *)"foo")); CU_ASSERT((size_t)(i + 1) == nghttp2_pq_size(&pq)); } for (i = 10000; i > 0; --i) { CU_ASSERT(NULL != nghttp2_pq_top(&pq)); nghttp2_pq_pop(&pq); CU_ASSERT((size_t)(i - 1) == nghttp2_pq_size(&pq)); } nghttp2_pq_free(&pq); }
static void check_queued(nghttp2_stream *stream) { nghttp2_stream *si; int queued; if (stream->queued) { if (!stream_subtree_active(stream)) { fprintf(stderr, "stream(%p)=%d, stream->queued == 1, but " "stream_active() == %d and nghttp2_pq_size(&stream->obq) = %zu\n", stream, stream->stream_id, stream_active(stream), nghttp2_pq_size(&stream->obq)); assert(0); } if (!stream_active(stream)) { queued = 0; for (si = stream->dep_next; si; si = si->sib_next) { if (si->queued) { ++queued; } } if (queued == 0) { fprintf(stderr, "stream(%p)=%d, stream->queued == 1, and " "!stream_active(), but no descendants is queued\n", stream, stream->stream_id); assert(0); } } for (si = stream->dep_next; si; si = si->sib_next) { check_queued(si); } } else { if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) { fprintf(stderr, "stream(%p) = %d, stream->queued == 0, but " "stream_active(stream) == %d and " "nghttp2_pq_size(&stream->obq) = %zu\n", stream, stream->stream_id, stream_active(stream), nghttp2_pq_size(&stream->obq)); assert(0); } for (si = stream->dep_next; si; si = si->sib_next) { ensure_inactive(si); } } }
/* * Returns nonzero if |stream| or one of its descendants is active */ static int stream_subtree_active(nghttp2_stream *stream) { return stream_active(stream) || !nghttp2_pq_empty(&stream->obq); }
void test_nghttp2_pq(void) { int i; nghttp2_pq pq; string_entry *top; nghttp2_pq_init(&pq, pq_less, nghttp2_mem_default()); CU_ASSERT(nghttp2_pq_empty(&pq)); CU_ASSERT(0 == nghttp2_pq_size(&pq)); CU_ASSERT(0 == nghttp2_pq_push(&pq, &string_entry_new("foo")->ent)); CU_ASSERT(0 == nghttp2_pq_empty(&pq)); CU_ASSERT(1 == nghttp2_pq_size(&pq)); top = (string_entry *)nghttp2_pq_top(&pq); CU_ASSERT(strcmp("foo", top->s) == 0); CU_ASSERT(0 == nghttp2_pq_push(&pq, &string_entry_new("bar")->ent)); top = (string_entry *)nghttp2_pq_top(&pq); CU_ASSERT(strcmp("bar", top->s) == 0); CU_ASSERT(0 == nghttp2_pq_push(&pq, &string_entry_new("baz")->ent)); top = (string_entry *)nghttp2_pq_top(&pq); CU_ASSERT(strcmp("bar", top->s) == 0); CU_ASSERT(0 == nghttp2_pq_push(&pq, &string_entry_new("C")->ent)); CU_ASSERT(4 == nghttp2_pq_size(&pq)); top = (string_entry *)nghttp2_pq_top(&pq); CU_ASSERT(strcmp("C", top->s) == 0); string_entry_del(top); nghttp2_pq_pop(&pq); CU_ASSERT(3 == nghttp2_pq_size(&pq)); top = (string_entry *)nghttp2_pq_top(&pq); CU_ASSERT(strcmp("bar", top->s) == 0); nghttp2_pq_pop(&pq); string_entry_del(top); top = (string_entry *)nghttp2_pq_top(&pq); CU_ASSERT(strcmp("baz", top->s) == 0); nghttp2_pq_pop(&pq); string_entry_del(top); top = (string_entry *)nghttp2_pq_top(&pq); CU_ASSERT(strcmp("foo", top->s) == 0); nghttp2_pq_pop(&pq); string_entry_del(top); CU_ASSERT(nghttp2_pq_empty(&pq)); CU_ASSERT(0 == nghttp2_pq_size(&pq)); CU_ASSERT(NULL == nghttp2_pq_top(&pq)); /* Add bunch of entry to see realloc works */ for (i = 0; i < 10000; ++i) { CU_ASSERT(0 == nghttp2_pq_push(&pq, &string_entry_new("foo")->ent)); CU_ASSERT((size_t)(i + 1) == nghttp2_pq_size(&pq)); } for (i = 10000; i > 0; --i) { top = (string_entry *)nghttp2_pq_top(&pq); CU_ASSERT(NULL != top); nghttp2_pq_pop(&pq); string_entry_del(top); CU_ASSERT((size_t)(i - 1) == nghttp2_pq_size(&pq)); } nghttp2_pq_free(&pq); }