nghttp2_stream.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. /*
  2. * Copyright (C) 2015-2018 Alibaba Group Holding Limited
  3. */
  4. #include "nghttp2_stream.h"
  5. #include <assert.h>
  6. #include <stdio.h>
  7. #include "nghttp2_session.h"
  8. #include "nghttp2_helper.h"
  9. #include "nghttp2_debug.h"
  10. /* Maximum distance between any two stream's cycle in the same
  11. prirority queue. Imagine stream A's cycle is A, and stream B's
  12. cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
  13. may get overflow. Because of how we calculate the next cycle
  14. value, if B - A is less than or equals to
  15. NGHTTP2_MAX_CYCLE_DISTANCE, A and B are in the same scale, in other
  16. words, B is really greater than or equal to A. Otherwise, A is a
  17. result of overflow, and it is actually A > B if we consider that
  18. fact. */
  19. #define NGHTTP2_MAX_CYCLE_DISTANCE (16384 * 256 + 255)
  20. static int stream_less(const void *lhsx, const void *rhsx) {
  21. const nghttp2_stream *lhs, *rhs;
  22. lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
  23. rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
  24. if (lhs->cycle == rhs->cycle) {
  25. return lhs->seq < rhs->seq;
  26. }
  27. if (lhs->cycle < rhs->cycle) {
  28. return rhs->cycle - lhs->cycle <= NGHTTP2_MAX_CYCLE_DISTANCE;
  29. }
  30. return lhs->cycle - rhs->cycle > NGHTTP2_MAX_CYCLE_DISTANCE;
  31. }
  32. void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
  33. uint8_t flags, nghttp2_stream_state initial_state,
  34. int32_t weight, int32_t remote_initial_window_size,
  35. int32_t local_initial_window_size,
  36. void *stream_user_data, nghttp2_mem *mem) {
  37. nghttp2_map_entry_init(&stream->map_entry, (key_type)stream_id);
  38. nghttp2_pq_init(&stream->obq, stream_less, mem);
  39. stream->stream_id = stream_id;
  40. stream->flags = flags;
  41. stream->state = initial_state;
  42. stream->shut_flags = NGHTTP2_SHUT_NONE;
  43. stream->stream_user_data = stream_user_data;
  44. stream->item = NULL;
  45. stream->remote_window_size = remote_initial_window_size;
  46. stream->local_window_size = local_initial_window_size;
  47. stream->recv_window_size = 0;
  48. stream->consumed_size = 0;
  49. stream->recv_reduction = 0;
  50. stream->window_update_queued = 0;
  51. stream->dep_prev = NULL;
  52. stream->dep_next = NULL;
  53. stream->sib_prev = NULL;
  54. stream->sib_next = NULL;
  55. stream->closed_prev = NULL;
  56. stream->closed_next = NULL;
  57. stream->weight = weight;
  58. stream->sum_dep_weight = 0;
  59. stream->http_flags = NGHTTP2_HTTP_FLAG_NONE;
  60. stream->content_length = -1;
  61. stream->recv_content_length = 0;
  62. stream->status_code = -1;
  63. stream->queued = 0;
  64. stream->descendant_last_cycle = 0;
  65. stream->cycle = 0;
  66. stream->pending_penalty = 0;
  67. stream->descendant_next_seq = 0;
  68. stream->seq = 0;
  69. stream->last_writelen = 0;
  70. }
  71. void nghttp2_stream_free(nghttp2_stream *stream) {
  72. nghttp2_pq_free(&stream->obq);
  73. /* We don't free stream->item. If it is assigned to aob, then
  74. active_outbound_item_reset() will delete it. Otherwise,
  75. nghttp2_stream_close() or session_del() will delete it. */
  76. }
  77. void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) {
  78. stream->shut_flags = (uint8_t)(stream->shut_flags | flag);
  79. }
  80. /*
  81. * Returns nonzero if |stream| is active. This function does not take
  82. * into account its descendants.
  83. */
  84. static int stream_active(nghttp2_stream *stream) {
  85. return stream->item &&
  86. (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0;
  87. }
  88. /*
  89. * Returns nonzero if |stream| or one of its descendants is active
  90. */
  91. static int stream_subtree_active(nghttp2_stream *stream) {
  92. return stream_active(stream) || !nghttp2_pq_empty(&stream->obq);
  93. }
  94. /*
  95. * Returns next cycle for |stream|.
  96. */
  97. static void stream_next_cycle(nghttp2_stream *stream, uint32_t last_cycle) {
  98. uint32_t penalty;
  99. penalty = (uint32_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT +
  100. stream->pending_penalty;
  101. stream->cycle = last_cycle + penalty / (uint32_t)stream->weight;
  102. stream->pending_penalty = penalty % (uint32_t)stream->weight;
  103. }
  104. static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
  105. int rv;
  106. for (; dep_stream && !stream->queued;
  107. stream = dep_stream, dep_stream = dep_stream->dep_prev) {
  108. stream_next_cycle(stream, dep_stream->descendant_last_cycle);
  109. stream->seq = dep_stream->descendant_next_seq++;
  110. DEBUGF("stream: stream=%d obq push cycle=%d\n", stream->stream_id,
  111. stream->cycle);
  112. DEBUGF("stream: push stream %d to stream %d\n", stream->stream_id,
  113. dep_stream->stream_id);
  114. rv = nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
  115. if (rv != 0) {
  116. return rv;
  117. }
  118. stream->queued = 1;
  119. }
  120. return 0;
  121. }
  122. /*
  123. * Removes |stream| from parent's obq. If removal of |stream| makes
  124. * parent's obq empty, and parent is not active, then parent is also
  125. * removed. This process is repeated recursively.
  126. */
  127. static void stream_obq_remove(nghttp2_stream *stream) {
  128. nghttp2_stream *dep_stream;
  129. dep_stream = stream->dep_prev;
  130. if (!stream->queued) {
  131. return;
  132. }
  133. for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
  134. DEBUGF("stream: remove stream %d from stream %d\n", stream->stream_id,
  135. dep_stream->stream_id);
  136. nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
  137. assert(stream->queued);
  138. stream->queued = 0;
  139. stream->cycle = 0;
  140. stream->pending_penalty = 0;
  141. stream->descendant_last_cycle = 0;
  142. stream->last_writelen = 0;
  143. if (stream_subtree_active(dep_stream)) {
  144. return;
  145. }
  146. }
  147. }
  148. /*
  149. * Moves |stream| from |src|'s obq to |dest|'s obq. Removal from
  150. * |src|'s obq is just done calling nghttp2_pq_remove(), so it does
  151. * not recursively remove |src| and ancestors, like
  152. * stream_obq_remove().
  153. */
  154. static int stream_obq_move(nghttp2_stream *dest, nghttp2_stream *src,
  155. nghttp2_stream *stream) {
  156. if (!stream->queued) {
  157. return 0;
  158. }
  159. DEBUGF("stream: remove stream %d from stream %d (move)\n", stream->stream_id,
  160. src->stream_id);
  161. nghttp2_pq_remove(&src->obq, &stream->pq_entry);
  162. stream->queued = 0;
  163. return stream_obq_push(dest, stream);
  164. }
  165. void nghttp2_stream_reschedule(nghttp2_stream *stream) {
  166. nghttp2_stream *dep_stream;
  167. assert(stream->queued);
  168. dep_stream = stream->dep_prev;
  169. for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
  170. nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
  171. stream_next_cycle(stream, dep_stream->descendant_last_cycle);
  172. stream->seq = dep_stream->descendant_next_seq++;
  173. nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
  174. DEBUGF("stream: stream=%d obq resched cycle=%d\n", stream->stream_id,
  175. stream->cycle);
  176. dep_stream->last_writelen = stream->last_writelen;
  177. }
  178. }
  179. void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
  180. nghttp2_stream *dep_stream;
  181. uint32_t last_cycle;
  182. int32_t old_weight;
  183. uint32_t wlen_penalty;
  184. if (stream->weight == weight) {
  185. return;
  186. }
  187. old_weight = stream->weight;
  188. stream->weight = weight;
  189. dep_stream = stream->dep_prev;
  190. if (!dep_stream) {
  191. return;
  192. }
  193. dep_stream->sum_dep_weight += weight - old_weight;
  194. if (!stream->queued) {
  195. return;
  196. }
  197. nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
  198. wlen_penalty = (uint32_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT;
  199. /* Compute old stream->pending_penalty we used to calculate
  200. stream->cycle */
  201. stream->pending_penalty =
  202. (uint32_t)((stream->pending_penalty + (uint32_t)old_weight -
  203. (wlen_penalty % (uint32_t)old_weight)) %
  204. (uint32_t)old_weight);
  205. last_cycle = stream->cycle -
  206. (wlen_penalty + stream->pending_penalty) / (uint32_t)old_weight;
  207. /* Now we have old stream->pending_penalty and new stream->weight in
  208. place */
  209. stream_next_cycle(stream, last_cycle);
  210. if (stream->cycle < dep_stream->descendant_last_cycle &&
  211. (dep_stream->descendant_last_cycle - stream->cycle) <=
  212. NGHTTP2_MAX_CYCLE_DISTANCE) {
  213. stream->cycle = dep_stream->descendant_last_cycle;
  214. }
  215. /* Continue to use same stream->seq */
  216. nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
  217. DEBUGF("stream: stream=%d obq resched cycle=%d\n", stream->stream_id,
  218. stream->cycle);
  219. }
  220. static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
  221. for (; stream->sib_next; stream = stream->sib_next)
  222. ;
  223. return stream;
  224. }
  225. int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
  226. int32_t weight) {
  227. weight = stream->weight * weight / stream->sum_dep_weight;
  228. return nghttp2_max(1, weight);
  229. }
  230. #ifdef STREAM_DEP_DEBUG
  231. static void ensure_inactive(nghttp2_stream *stream) {
  232. nghttp2_stream *si;
  233. if (stream->queued) {
  234. fprintf(stderr, "stream(%p)=%d, stream->queued = 1; want 0\n", stream,
  235. stream->stream_id);
  236. assert(0);
  237. }
  238. if (stream_active(stream)) {
  239. fprintf(stderr, "stream(%p)=%d, stream_active(stream) = 1; want 0\n",
  240. stream, stream->stream_id);
  241. assert(0);
  242. }
  243. if (!nghttp2_pq_empty(&stream->obq)) {
  244. fprintf(stderr, "stream(%p)=%d, nghttp2_pq_size() = %zu; want 0\n", stream,
  245. stream->stream_id, nghttp2_pq_size(&stream->obq));
  246. assert(0);
  247. }
  248. for (si = stream->dep_next; si; si = si->sib_next) {
  249. ensure_inactive(si);
  250. }
  251. }
  252. static void check_queued(nghttp2_stream *stream) {
  253. nghttp2_stream *si;
  254. int queued;
  255. if (stream->queued) {
  256. if (!stream_subtree_active(stream)) {
  257. fprintf(stderr,
  258. "stream(%p)=%d, stream->queued == 1, but "
  259. "stream_active() == %d and nghttp2_pq_size(&stream->obq) = %zu\n",
  260. stream, stream->stream_id, stream_active(stream),
  261. nghttp2_pq_size(&stream->obq));
  262. assert(0);
  263. }
  264. if (!stream_active(stream)) {
  265. queued = 0;
  266. for (si = stream->dep_next; si; si = si->sib_next) {
  267. if (si->queued) {
  268. ++queued;
  269. }
  270. }
  271. if (queued == 0) {
  272. fprintf(stderr,
  273. "stream(%p)=%d, stream->queued == 1, and "
  274. "!stream_active(), but no descendants is queued\n",
  275. stream, stream->stream_id);
  276. assert(0);
  277. }
  278. }
  279. for (si = stream->dep_next; si; si = si->sib_next) {
  280. check_queued(si);
  281. }
  282. } else {
  283. if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) {
  284. fprintf(stderr,
  285. "stream(%p) = %d, stream->queued == 0, but "
  286. "stream_active(stream) == %d and "
  287. "nghttp2_pq_size(&stream->obq) = %zu\n",
  288. stream, stream->stream_id, stream_active(stream),
  289. nghttp2_pq_size(&stream->obq));
  290. assert(0);
  291. }
  292. for (si = stream->dep_next; si; si = si->sib_next) {
  293. ensure_inactive(si);
  294. }
  295. }
  296. }
  297. static void check_sum_dep(nghttp2_stream *stream) {
  298. nghttp2_stream *si;
  299. int32_t n = 0;
  300. for (si = stream->dep_next; si; si = si->sib_next) {
  301. n += si->weight;
  302. }
  303. if (n != stream->sum_dep_weight) {
  304. fprintf(stderr, "stream(%p)=%d, sum_dep_weight = %d; want %d\n", stream,
  305. stream->stream_id, n, stream->sum_dep_weight);
  306. assert(0);
  307. }
  308. for (si = stream->dep_next; si; si = si->sib_next) {
  309. check_sum_dep(si);
  310. }
  311. }
  312. static void check_dep_prev(nghttp2_stream *stream) {
  313. nghttp2_stream *si;
  314. for (si = stream->dep_next; si; si = si->sib_next) {
  315. if (si->dep_prev != stream) {
  316. fprintf(stderr, "si->dep_prev = %p; want %p\n", si->dep_prev, stream);
  317. assert(0);
  318. }
  319. check_dep_prev(si);
  320. }
  321. }
  322. #endif /* STREAM_DEP_DEBUG */
  323. #ifdef STREAM_DEP_DEBUG
  324. static void validate_tree(nghttp2_stream *stream) {
  325. nghttp2_stream *si;
  326. if (!stream) {
  327. return;
  328. }
  329. for (; stream->dep_prev; stream = stream->dep_prev)
  330. ;
  331. assert(stream->stream_id == 0);
  332. assert(!stream->queued);
  333. fprintf(stderr, "checking...\n");
  334. if (nghttp2_pq_empty(&stream->obq)) {
  335. fprintf(stderr, "root obq empty\n");
  336. for (si = stream->dep_next; si; si = si->sib_next) {
  337. ensure_inactive(si);
  338. }
  339. } else {
  340. for (si = stream->dep_next; si; si = si->sib_next) {
  341. check_queued(si);
  342. }
  343. }
  344. check_sum_dep(stream);
  345. check_dep_prev(stream);
  346. }
  347. #else /* !STREAM_DEP_DEBUG */
  348. static void validate_tree(nghttp2_stream *stream) { (void)stream; }
  349. #endif /* !STREAM_DEP_DEBUG*/
  350. static int stream_update_dep_on_attach_item(nghttp2_stream *stream) {
  351. int rv;
  352. rv = stream_obq_push(stream->dep_prev, stream);
  353. if (rv != 0) {
  354. return rv;
  355. }
  356. validate_tree(stream);
  357. return 0;
  358. }
  359. static int stream_update_dep_on_detach_item(nghttp2_stream *stream) {
  360. if (nghttp2_pq_empty(&stream->obq)) {
  361. stream_obq_remove(stream);
  362. }
  363. validate_tree(stream);
  364. return 0;
  365. }
  366. int nghttp2_stream_attach_item(nghttp2_stream *stream,
  367. nghttp2_outbound_item *item) {
  368. int rv;
  369. assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0);
  370. assert(stream->item == NULL);
  371. DEBUGF("stream: stream=%d attach item=%p\n", stream->stream_id, item);
  372. stream->item = item;
  373. rv = stream_update_dep_on_attach_item(stream);
  374. if (rv != 0) {
  375. /* This may relave stream->queued == 1, but stream->item == NULL.
  376. But only consequence of this error is fatal one, and session
  377. destruction. In that execution path, these inconsistency does
  378. not matter. */
  379. stream->item = NULL;
  380. return rv;
  381. }
  382. return 0;
  383. }
  384. int nghttp2_stream_detach_item(nghttp2_stream *stream) {
  385. DEBUGF("stream: stream=%d detach item=%p\n", stream->stream_id, stream->item);
  386. stream->item = NULL;
  387. stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
  388. return stream_update_dep_on_detach_item(stream);
  389. }
  390. int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
  391. assert(stream->item);
  392. DEBUGF("stream: stream=%d defer item=%p cause=%02x\n", stream->stream_id,
  393. stream->item, flags);
  394. stream->flags |= flags;
  395. return stream_update_dep_on_detach_item(stream);
  396. }
  397. int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) {
  398. assert(stream->item);
  399. DEBUGF("stream: stream=%d resume item=%p flags=%02x\n", stream->stream_id,
  400. stream->item, flags);
  401. stream->flags = (uint8_t)(stream->flags & ~flags);
  402. if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) {
  403. return 0;
  404. }
  405. return stream_update_dep_on_attach_item(stream);
  406. }
  407. int nghttp2_stream_check_deferred_item(nghttp2_stream *stream) {
  408. return stream->item && (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
  409. }
  410. int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream) {
  411. return stream->item &&
  412. (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
  413. }
  414. static int update_initial_window_size(int32_t *window_size_ptr,
  415. int32_t new_initial_window_size,
  416. int32_t old_initial_window_size) {
  417. int64_t new_window_size = (int64_t)(*window_size_ptr) +
  418. new_initial_window_size - old_initial_window_size;
  419. if (INT32_MIN > new_window_size ||
  420. new_window_size > NGHTTP2_MAX_WINDOW_SIZE) {
  421. return -1;
  422. }
  423. *window_size_ptr = (int32_t)new_window_size;
  424. return 0;
  425. }
  426. int nghttp2_stream_update_remote_initial_window_size(
  427. nghttp2_stream *stream, int32_t new_initial_window_size,
  428. int32_t old_initial_window_size) {
  429. return update_initial_window_size(&stream->remote_window_size,
  430. new_initial_window_size,
  431. old_initial_window_size);
  432. }
  433. int nghttp2_stream_update_local_initial_window_size(
  434. nghttp2_stream *stream, int32_t new_initial_window_size,
  435. int32_t old_initial_window_size) {
  436. return update_initial_window_size(&stream->local_window_size,
  437. new_initial_window_size,
  438. old_initial_window_size);
  439. }
  440. void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) {
  441. stream->state = NGHTTP2_STREAM_OPENED;
  442. stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH);
  443. }
  444. int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream,
  445. nghttp2_stream *target) {
  446. for (; stream; stream = stream->dep_prev) {
  447. if (stream == target) {
  448. return 1;
  449. }
  450. }
  451. return 0;
  452. }
  453. int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
  454. nghttp2_stream *stream) {
  455. nghttp2_stream *si;
  456. int rv;
  457. DEBUGF("stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream,
  458. dep_stream->stream_id, stream, stream->stream_id);
  459. stream->sum_dep_weight = dep_stream->sum_dep_weight;
  460. dep_stream->sum_dep_weight = stream->weight;
  461. if (dep_stream->dep_next) {
  462. for (si = dep_stream->dep_next; si; si = si->sib_next) {
  463. si->dep_prev = stream;
  464. if (si->queued) {
  465. rv = stream_obq_move(stream, dep_stream, si);
  466. if (rv != 0) {
  467. return rv;
  468. }
  469. }
  470. }
  471. if (stream_subtree_active(stream)) {
  472. rv = stream_obq_push(dep_stream, stream);
  473. if (rv != 0) {
  474. return rv;
  475. }
  476. }
  477. stream->dep_next = dep_stream->dep_next;
  478. }
  479. dep_stream->dep_next = stream;
  480. stream->dep_prev = dep_stream;
  481. validate_tree(stream);
  482. return 0;
  483. }
  484. static void set_dep_prev(nghttp2_stream *stream, nghttp2_stream *dep) {
  485. for (; stream; stream = stream->sib_next) {
  486. stream->dep_prev = dep;
  487. }
  488. }
  489. static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
  490. dep_stream->dep_next = stream;
  491. if (stream) {
  492. stream->dep_prev = dep_stream;
  493. }
  494. }
  495. static void link_sib(nghttp2_stream *a, nghttp2_stream *b) {
  496. a->sib_next = b;
  497. if (b) {
  498. b->sib_prev = a;
  499. }
  500. }
  501. static void insert_link_dep(nghttp2_stream *dep_stream,
  502. nghttp2_stream *stream) {
  503. nghttp2_stream *sib_next;
  504. assert(stream->sib_prev == NULL);
  505. sib_next = dep_stream->dep_next;
  506. link_sib(stream, sib_next);
  507. link_dep(dep_stream, stream);
  508. }
  509. static void unlink_sib(nghttp2_stream *stream) {
  510. nghttp2_stream *prev, *next, *dep_next;
  511. prev = stream->sib_prev;
  512. dep_next = stream->dep_next;
  513. assert(prev);
  514. if (dep_next) {
  515. /*
  516. * prev--stream(--sib_next--...)
  517. * |
  518. * dep_next
  519. */
  520. link_sib(prev, dep_next);
  521. set_dep_prev(dep_next, stream->dep_prev);
  522. if (stream->sib_next) {
  523. link_sib(stream_last_sib(dep_next), stream->sib_next);
  524. }
  525. } else {
  526. /*
  527. * prev--stream(--sib_next--...)
  528. */
  529. next = stream->sib_next;
  530. prev->sib_next = next;
  531. if (next) {
  532. next->sib_prev = prev;
  533. }
  534. }
  535. }
  536. static void unlink_dep(nghttp2_stream *stream) {
  537. nghttp2_stream *prev, *next, *dep_next;
  538. prev = stream->dep_prev;
  539. dep_next = stream->dep_next;
  540. assert(prev);
  541. if (dep_next) {
  542. /*
  543. * prev
  544. * |
  545. * stream(--sib_next--...)
  546. * |
  547. * dep_next
  548. */
  549. link_dep(prev, dep_next);
  550. set_dep_prev(dep_next, stream->dep_prev);
  551. if (stream->sib_next) {
  552. link_sib(stream_last_sib(dep_next), stream->sib_next);
  553. }
  554. } else if (stream->sib_next) {
  555. /*
  556. * prev
  557. * |
  558. * stream--sib_next
  559. */
  560. next = stream->sib_next;
  561. next->sib_prev = NULL;
  562. link_dep(prev, next);
  563. } else {
  564. prev->dep_next = NULL;
  565. }
  566. }
  567. void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
  568. nghttp2_stream *stream) {
  569. DEBUGF("stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream,
  570. dep_stream->stream_id, stream, stream->stream_id);
  571. dep_stream->sum_dep_weight += stream->weight;
  572. if (dep_stream->dep_next == NULL) {
  573. link_dep(dep_stream, stream);
  574. } else {
  575. insert_link_dep(dep_stream, stream);
  576. }
  577. validate_tree(stream);
  578. }
  579. int nghttp2_stream_dep_remove(nghttp2_stream *stream) {
  580. nghttp2_stream *dep_prev, *si;
  581. int32_t sum_dep_weight_delta;
  582. int rv;
  583. DEBUGF("stream: dep_remove stream(%p)=%d\n", stream, stream->stream_id);
  584. /* Distribute weight of |stream| to direct descendants */
  585. sum_dep_weight_delta = -stream->weight;
  586. for (si = stream->dep_next; si; si = si->sib_next) {
  587. si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight);
  588. sum_dep_weight_delta += si->weight;
  589. if (si->queued) {
  590. rv = stream_obq_move(stream->dep_prev, stream, si);
  591. if (rv != 0) {
  592. return rv;
  593. }
  594. }
  595. }
  596. assert(stream->dep_prev);
  597. dep_prev = stream->dep_prev;
  598. dep_prev->sum_dep_weight += sum_dep_weight_delta;
  599. if (stream->queued) {
  600. stream_obq_remove(stream);
  601. }
  602. if (stream->sib_prev) {
  603. unlink_sib(stream);
  604. } else {
  605. unlink_dep(stream);
  606. }
  607. stream->sum_dep_weight = 0;
  608. stream->dep_prev = NULL;
  609. stream->dep_next = NULL;
  610. stream->sib_prev = NULL;
  611. stream->sib_next = NULL;
  612. validate_tree(dep_prev);
  613. return 0;
  614. }
  615. int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
  616. nghttp2_stream *stream) {
  617. nghttp2_stream *last_sib;
  618. nghttp2_stream *dep_next;
  619. nghttp2_stream *si;
  620. int rv;
  621. DEBUGF("stream: dep_insert_subtree dep_stream(%p)=%d stream(%p)=%d\n",
  622. dep_stream, dep_stream->stream_id, stream, stream->stream_id);
  623. stream->sum_dep_weight += dep_stream->sum_dep_weight;
  624. dep_stream->sum_dep_weight = stream->weight;
  625. if (dep_stream->dep_next) {
  626. dep_next = dep_stream->dep_next;
  627. link_dep(dep_stream, stream);
  628. if (stream->dep_next) {
  629. last_sib = stream_last_sib(stream->dep_next);
  630. link_sib(last_sib, dep_next);
  631. } else {
  632. link_dep(stream, dep_next);
  633. }
  634. for (si = dep_next; si; si = si->sib_next) {
  635. si->dep_prev = stream;
  636. if (si->queued) {
  637. rv = stream_obq_move(stream, dep_stream, si);
  638. if (rv != 0) {
  639. return rv;
  640. }
  641. }
  642. }
  643. } else {
  644. link_dep(dep_stream, stream);
  645. }
  646. if (stream_subtree_active(stream)) {
  647. rv = stream_obq_push(dep_stream, stream);
  648. if (rv != 0) {
  649. return rv;
  650. }
  651. }
  652. validate_tree(dep_stream);
  653. return 0;
  654. }
  655. int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
  656. nghttp2_stream *stream) {
  657. int rv;
  658. DEBUGF("stream: dep_add_subtree dep_stream(%p)=%d stream(%p)=%d\n",
  659. dep_stream, dep_stream->stream_id, stream, stream->stream_id);
  660. dep_stream->sum_dep_weight += stream->weight;
  661. if (dep_stream->dep_next) {
  662. insert_link_dep(dep_stream, stream);
  663. } else {
  664. link_dep(dep_stream, stream);
  665. }
  666. if (stream_subtree_active(stream)) {
  667. rv = stream_obq_push(dep_stream, stream);
  668. if (rv != 0) {
  669. return rv;
  670. }
  671. }
  672. validate_tree(dep_stream);
  673. return 0;
  674. }
  675. void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
  676. nghttp2_stream *next, *dep_prev;
  677. DEBUGF("stream: dep_remove_subtree stream(%p)=%d\n", stream,
  678. stream->stream_id);
  679. assert(stream->dep_prev);
  680. dep_prev = stream->dep_prev;
  681. if (stream->sib_prev) {
  682. link_sib(stream->sib_prev, stream->sib_next);
  683. } else {
  684. next = stream->sib_next;
  685. link_dep(dep_prev, next);
  686. if (next) {
  687. next->sib_prev = NULL;
  688. }
  689. }
  690. dep_prev->sum_dep_weight -= stream->weight;
  691. if (stream->queued) {
  692. stream_obq_remove(stream);
  693. }
  694. validate_tree(dep_prev);
  695. stream->sib_prev = NULL;
  696. stream->sib_next = NULL;
  697. stream->dep_prev = NULL;
  698. }
  699. int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) {
  700. return stream->dep_prev || stream->dep_next || stream->sib_prev ||
  701. stream->sib_next;
  702. }
  703. nghttp2_outbound_item *
  704. nghttp2_stream_next_outbound_item(nghttp2_stream *stream) {
  705. nghttp2_pq_entry *ent;
  706. nghttp2_stream *si;
  707. for (;;) {
  708. if (stream_active(stream)) {
  709. /* Update ascendant's descendant_last_cycle here, so that we can
  710. assure that new stream is scheduled based on it. */
  711. for (si = stream; si->dep_prev; si = si->dep_prev) {
  712. si->dep_prev->descendant_last_cycle = si->cycle;
  713. }
  714. return stream->item;
  715. }
  716. ent = nghttp2_pq_top(&stream->obq);
  717. if (!ent) {
  718. return NULL;
  719. }
  720. stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
  721. }
  722. }
  723. nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) {
  724. if (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) {
  725. return NGHTTP2_STREAM_STATE_CLOSED;
  726. }
  727. if (stream->flags & NGHTTP2_STREAM_FLAG_PUSH) {
  728. if (stream->shut_flags & NGHTTP2_SHUT_RD) {
  729. return NGHTTP2_STREAM_STATE_RESERVED_LOCAL;
  730. }
  731. if (stream->shut_flags & NGHTTP2_SHUT_WR) {
  732. return NGHTTP2_STREAM_STATE_RESERVED_REMOTE;
  733. }
  734. }
  735. if (stream->shut_flags & NGHTTP2_SHUT_RD) {
  736. return NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE;
  737. }
  738. if (stream->shut_flags & NGHTTP2_SHUT_WR) {
  739. return NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL;
  740. }
  741. if (stream->state == NGHTTP2_STREAM_IDLE) {
  742. return NGHTTP2_STREAM_STATE_IDLE;
  743. }
  744. return NGHTTP2_STREAM_STATE_OPEN;
  745. }
  746. nghttp2_stream *nghttp2_stream_get_parent(nghttp2_stream *stream) {
  747. return stream->dep_prev;
  748. }
  749. nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream) {
  750. return stream->sib_next;
  751. }
  752. nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream) {
  753. return stream->sib_prev;
  754. }
  755. nghttp2_stream *nghttp2_stream_get_first_child(nghttp2_stream *stream) {
  756. return stream->dep_next;
  757. }
  758. int32_t nghttp2_stream_get_weight(nghttp2_stream *stream) {
  759. return stream->weight;
  760. }
  761. int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream) {
  762. return stream->sum_dep_weight;
  763. }
  764. int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream) {
  765. return stream->stream_id;
  766. }