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); } }
void nghttp2_stream_reschedule(nghttp2_stream *stream) { nghttp2_stream *dep_stream; assert(stream->queued); dep_stream = stream->dep_prev; for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) { if (nghttp2_pq_size(&dep_stream->obq) == 1) { dep_stream->descendant_last_cycle = 0; stream->cycle = 0; } else { dep_stream->descendant_last_cycle = nghttp2_max(dep_stream->descendant_last_cycle, stream->cycle); stream->cycle = stream_next_cycle(stream, dep_stream->descendant_last_cycle); nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); } DEBUGF(fprintf(stderr, "stream: stream=%d obq resched cycle=%ld\n", stream->stream_id, stream->cycle)); dep_stream->last_writelen = stream->last_writelen; } }
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); } } }
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); }
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); }