lws-dsh.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /*
  2. * libwebsockets - small server side websockets and web server implementation
  3. *
  4. * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to
  8. * deal in the Software without restriction, including without limitation the
  9. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10. * sell copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  22. * IN THE SOFTWARE.
  23. */
  24. #include "private-lib-core.h"
  25. struct lws_dsh_search {
  26. size_t required;
  27. int kind;
  28. lws_dsh_obj_t *best;
  29. lws_dsh_t *dsh;
  30. lws_dsh_t *already_checked;
  31. lws_dsh_t *this_dsh;
  32. };
  33. static int
  34. _lws_dsh_alloc_tail(lws_dsh_t *dsh, int kind, const void *src1, size_t size1,
  35. const void *src2, size_t size2, lws_dll2_t *replace);
  36. static size_t
  37. lws_dsh_align(size_t length)
  38. {
  39. size_t align = sizeof(int *);
  40. if (length & (align - 1))
  41. length += align - (length & (align - 1));
  42. return length;
  43. }
  44. lws_dsh_t *
  45. lws_dsh_create(lws_dll2_owner_t *owner, size_t buf_len, int count_kinds)
  46. {
  47. size_t oha_len = sizeof(lws_dsh_obj_head_t) * ++count_kinds;
  48. lws_dsh_obj_t *obj;
  49. lws_dsh_t *dsh;
  50. int n;
  51. assert(buf_len);
  52. assert(count_kinds > 1);
  53. dsh = lws_malloc(sizeof(lws_dsh_t) + buf_len + oha_len, __func__);
  54. if (!dsh)
  55. return NULL;
  56. /* set convenience pointers to the overallocated parts */
  57. dsh->oha = (lws_dsh_obj_head_t *)&dsh[1];
  58. dsh->buf = ((uint8_t *)dsh->oha) + oha_len;
  59. dsh->count_kinds = count_kinds;
  60. dsh->buffer_size = buf_len;
  61. dsh->being_destroyed = 0;
  62. /* clear down the obj heads array */
  63. memset(dsh->oha, 0, oha_len);
  64. for (n = 0; n < count_kinds; n++)
  65. dsh->oha[n].kind = n;
  66. /* initially the whole buffer is on the free kind (0) list */
  67. obj = (lws_dsh_obj_t *)dsh->buf;
  68. memset(obj, 0, sizeof(*obj));
  69. obj->asize = buf_len - sizeof(*obj);
  70. lws_dll2_add_head(&obj->list, &dsh->oha[0].owner);
  71. dsh->locally_free = obj->asize;
  72. dsh->locally_in_use = 0;
  73. lws_dll2_clear(&dsh->list);
  74. if (owner)
  75. lws_dll2_add_head(&dsh->list, owner);
  76. // lws_dsh_describe(dsh, "post-init");
  77. return dsh;
  78. }
  79. static int
  80. search_best_free(struct lws_dll2 *d, void *user)
  81. {
  82. struct lws_dsh_search *s = (struct lws_dsh_search *)user;
  83. lws_dsh_obj_t *obj = lws_container_of(d, lws_dsh_obj_t, list);
  84. lwsl_debug("%s: obj %p, asize %zu (req %zu)\n", __func__, obj,
  85. obj->asize, s->required);
  86. if (obj->asize >= s->required &&
  87. (!s->best || obj->asize < s->best->asize)) {
  88. s->best = obj;
  89. s->dsh = s->this_dsh;
  90. }
  91. return 0;
  92. }
  93. static int
  94. try_foreign(struct lws_dll2 *d, void *user)
  95. {
  96. struct lws_dsh_search *s = (struct lws_dsh_search *)user;
  97. lws_dsh_t *dsh1 = lws_container_of(d, lws_dsh_t, list);
  98. if (dsh1 == s->already_checked)
  99. return 0;
  100. if (dsh1->being_destroyed)
  101. return 0;
  102. if (dsh1->count_kinds < s->kind + 1)
  103. return 0;
  104. lwsl_debug("%s: actual try_foreign: dsh %p (free list size %d)\n",
  105. __func__, dsh1, dsh1->oha[0].owner.count);
  106. s->this_dsh = dsh1;
  107. if (lws_dll2_foreach_safe(&dsh1->oha[0].owner, s, search_best_free))
  108. return 1;
  109. return 0;
  110. }
  111. static int
  112. free_foreign(struct lws_dll2 *d, void *user)
  113. {
  114. lws_dsh_obj_t *obj = lws_container_of(d, lws_dsh_obj_t, list);
  115. lws_dsh_t *dsh = (lws_dsh_t *)user;
  116. void *p = (void *)&obj[1];
  117. if (obj->dsh != dsh)
  118. lws_dsh_free(&p);
  119. return 0;
  120. }
  121. static int
  122. evict2(struct lws_dll2 *d, void *user)
  123. {
  124. lws_dsh_obj_t *obj = lws_container_of(d, lws_dsh_obj_t, list);
  125. lws_dsh_t *dsh = (lws_dsh_t *)user;
  126. void *p;
  127. if (obj->dsh != dsh)
  128. return 0;
  129. /*
  130. * If we are here, it means obj is a live object that is allocated on
  131. * the dsh being destroyed, from a different dsh. We need to migrate
  132. * the object to a dsh that isn't being destroyed.
  133. */
  134. lwsl_debug("%s: migrating object size %zu\n", __func__, obj->size);
  135. if (_lws_dsh_alloc_tail(dsh, 0, (void *)&obj[1], obj->size, NULL, 0, &obj->list)) {
  136. lwsl_notice("%s: failed to migrate object\n", __func__);
  137. /*
  138. * only thing we can do is drop the logical object
  139. */
  140. p = (uint8_t *)&obj[1];
  141. lws_dsh_free(&p);
  142. }
  143. return 0;
  144. }
  145. static int
  146. evict1(struct lws_dll2 *d, void *user)
  147. {
  148. lws_dsh_t *dsh1 = lws_container_of(d, lws_dsh_t, list);
  149. lws_dsh_t *dsh = (lws_dsh_t *)user;
  150. int n;
  151. if (dsh1->being_destroyed)
  152. return 0;
  153. /*
  154. * For every dsh that's not being destroyed, send every object to
  155. * evict2 for checking.
  156. */
  157. lwsl_debug("%s: checking dsh %p\n", __func__, dsh1);
  158. for (n = 1; n < dsh1->count_kinds; n++) {
  159. lws_dll2_describe(&dsh1->oha[n].owner, "check dsh1");
  160. lws_dll2_foreach_safe(&dsh1->oha[n].owner, dsh, evict2);
  161. }
  162. return 0;
  163. }
  164. void
  165. lws_dsh_destroy(lws_dsh_t **pdsh)
  166. {
  167. lws_dsh_t *dsh = *pdsh;
  168. int n;
  169. if (!dsh)
  170. return;
  171. lwsl_debug("%s: destroying dsh %p\n", __func__, dsh);
  172. dsh->being_destroyed = 1;
  173. /* we need to explicitly free any of our allocations in foreign dsh */
  174. for (n = 1; n < dsh->count_kinds; n++)
  175. lws_dll2_foreach_safe(&dsh->oha[n].owner, dsh, free_foreign);
  176. /*
  177. * We need to have anybody else with allocations in us evict them
  178. * and make a copy in a buffer that isn't being destroyed
  179. */
  180. if (dsh->list.owner)
  181. lws_dll2_foreach_safe(dsh->list.owner, dsh, evict1);
  182. lws_dll2_remove(&dsh->list);
  183. /* everything else is in one heap allocation */
  184. lws_free_set_NULL(*pdsh);
  185. }
  186. static int
  187. _lws_dsh_alloc_tail(lws_dsh_t *dsh, int kind, const void *src1, size_t size1,
  188. const void *src2, size_t size2, lws_dll2_t *replace)
  189. {
  190. size_t asize = sizeof(lws_dsh_obj_t) + lws_dsh_align(size1 + size2);
  191. struct lws_dsh_search s;
  192. assert(kind >= 0);
  193. kind++;
  194. assert(!dsh || kind < dsh->count_kinds);
  195. /*
  196. * Search our free list looking for the smallest guy who will fit
  197. * what we want to allocate
  198. */
  199. s.required = asize;
  200. s.kind = kind;
  201. s.best = NULL;
  202. s.already_checked = NULL;
  203. s.this_dsh = dsh;
  204. if (dsh && !dsh->being_destroyed)
  205. lws_dll2_foreach_safe(&dsh->oha[0].owner, &s, search_best_free);
  206. if (!s.best) {
  207. /*
  208. * Let's see if any other buffer has room
  209. */
  210. s.already_checked = dsh;
  211. if (dsh && dsh->list.owner)
  212. lws_dll2_foreach_safe(dsh->list.owner, &s, try_foreign);
  213. if (!s.best) {
  214. lwsl_notice("%s: no buffer has space\n", __func__);
  215. return 1;
  216. }
  217. }
  218. /* anything coming out of here must be aligned */
  219. assert(!(((unsigned long)s.best) & (sizeof(int *) - 1)));
  220. if (s.best->asize < asize + (2 * sizeof(*s.best))) {
  221. /*
  222. * Exact fit, or close enough we can't / don't want to have to
  223. * track the little bit of free area that would be left.
  224. *
  225. * Move the object from the free list to the oha of the
  226. * desired kind
  227. */
  228. lws_dll2_remove(&s.best->list);
  229. s.best->dsh = s.dsh;
  230. s.best->size = size1 + size2;
  231. memcpy(&s.best[1], src1, size1);
  232. if (src2)
  233. memcpy((uint8_t *)&s.best[1] + size1, src2, size2);
  234. if (replace) {
  235. s.best->list.prev = replace->prev;
  236. s.best->list.next = replace->next;
  237. s.best->list.owner = replace->owner;
  238. if (replace->prev)
  239. replace->prev->next = &s.best->list;
  240. if (replace->next)
  241. replace->next->prev = &s.best->list;
  242. } else
  243. if (dsh)
  244. lws_dll2_add_tail(&s.best->list, &dsh->oha[kind].owner);
  245. assert(s.dsh->locally_free >= s.best->asize);
  246. s.dsh->locally_free -= s.best->asize;
  247. s.dsh->locally_in_use += s.best->asize;
  248. assert(s.dsh->locally_in_use <= s.dsh->buffer_size);
  249. } else {
  250. lws_dsh_obj_t *obj;
  251. /*
  252. * Free area was oversize enough that we need to split it.
  253. *
  254. * Leave the first part of the free area where it is and
  255. * reduce its extent by our asize. Use the latter part of
  256. * the original free area as the allocation.
  257. */
  258. lwsl_debug("%s: splitting... free reduce %zu -> %zu\n",
  259. __func__, s.best->asize, s.best->asize - asize);
  260. s.best->asize -= asize;
  261. /* latter part becomes new object */
  262. obj = (lws_dsh_obj_t *)(((uint8_t *)s.best) + s.best->asize);
  263. lws_dll2_clear(&obj->list);
  264. obj->dsh = s.dsh;
  265. obj->size = size1 + size2;
  266. obj->asize = asize;
  267. memcpy(&obj[1], src1, size1);
  268. if (src2)
  269. memcpy((uint8_t *)&obj[1] + size1, src2, size2);
  270. if (replace) {
  271. s.best->list.prev = replace->prev;
  272. s.best->list.next = replace->next;
  273. s.best->list.owner = replace->owner;
  274. if (replace->prev)
  275. replace->prev->next = &s.best->list;
  276. if (replace->next)
  277. replace->next->prev = &s.best->list;
  278. } else
  279. if (dsh)
  280. lws_dll2_add_tail(&obj->list, &dsh->oha[kind].owner);
  281. assert(s.dsh->locally_free >= asize);
  282. s.dsh->locally_free -= asize;
  283. s.dsh->locally_in_use += asize;
  284. assert(s.dsh->locally_in_use <= s.dsh->buffer_size);
  285. }
  286. // lws_dsh_describe(dsh, "post-alloc");
  287. return 0;
  288. }
  289. int
  290. lws_dsh_alloc_tail(lws_dsh_t *dsh, int kind, const void *src1, size_t size1,
  291. const void *src2, size_t size2)
  292. {
  293. return _lws_dsh_alloc_tail(dsh, kind, src1, size1, src2, size2, NULL);
  294. }
  295. static int
  296. buf_compare(const lws_dll2_t *d, const lws_dll2_t *i)
  297. {
  298. return (int)lws_ptr_diff(d, i);
  299. }
  300. void
  301. lws_dsh_free(void **pobj)
  302. {
  303. lws_dsh_obj_t *_o = (lws_dsh_obj_t *)((uint8_t *)(*pobj) - sizeof(*_o)),
  304. *_o2;
  305. lws_dsh_t *dsh = _o->dsh;
  306. /* anything coming out of here must be aligned */
  307. assert(!(((unsigned long)_o) & (sizeof(int *) - 1)));
  308. /*
  309. * Remove the object from its list and place on the free list of the
  310. * dsh the buffer space belongs to
  311. */
  312. lws_dll2_remove(&_o->list);
  313. *pobj = NULL;
  314. assert(dsh->locally_in_use >= _o->asize);
  315. dsh->locally_free += _o->asize;
  316. dsh->locally_in_use -= _o->asize;
  317. assert(dsh->locally_in_use <= dsh->buffer_size);
  318. /*
  319. * The free space list is sorted in buffer address order, so detecting
  320. * coalescing opportunities is cheap. Because the free list should be
  321. * continuously tending to reduce by coalescing, the sorting should not
  322. * be expensive to maintain.
  323. */
  324. _o->size = 0; /* not meaningful when on free list */
  325. lws_dll2_add_sorted(&_o->list, &_o->dsh->oha[0].owner, buf_compare);
  326. /* First check for already-free block at the end we can subsume.
  327. * Because the free list is sorted, if there is such a guy he is
  328. * already our list.next */
  329. _o2 = (lws_dsh_obj_t *)_o->list.next;
  330. if (_o2 && (uint8_t *)_o + _o->asize == (uint8_t *)_o2) {
  331. /*
  332. * since we are freeing _obj, we can coalesce with a
  333. * free area immediately ahead of it
  334. *
  335. * [ _o (being freed) ][ _o2 (free) ] -> [ larger _o ]
  336. */
  337. _o->asize += _o2->asize;
  338. /* guy next to us was absorbed into us */
  339. lws_dll2_remove(&_o2->list);
  340. }
  341. /* Then check if we can be subsumed by a free block behind us.
  342. * Because the free list is sorted, if there is such a guy he is
  343. * already our list.prev */
  344. _o2 = (lws_dsh_obj_t *)_o->list.prev;
  345. if (_o2 && (uint8_t *)_o2 + _o2->asize == (uint8_t *)_o) {
  346. /*
  347. * since we are freeing obj, we can coalesce it with
  348. * the previous free area that abuts it
  349. *
  350. * [ _o2 (free) ][ _o (being freed) ] -> [ larger _o2 ]
  351. */
  352. _o2->asize += _o->asize;
  353. /* we were absorbed! */
  354. lws_dll2_remove(&_o->list);
  355. }
  356. // lws_dsh_describe(dsh, "post-alloc");
  357. }
  358. int
  359. lws_dsh_get_head(lws_dsh_t *dsh, int kind, void **obj, size_t *size)
  360. {
  361. lws_dsh_obj_t *_obj = (lws_dsh_obj_t *)
  362. lws_dll2_get_head(&dsh->oha[kind + 1].owner);
  363. if (!_obj) {
  364. *obj = 0;
  365. *size = 0;
  366. return 1; /* there is no head */
  367. }
  368. *obj = (void *)(&_obj[1]);
  369. *size = _obj->size;
  370. /* anything coming out of here must be aligned */
  371. assert(!(((unsigned long)(*obj)) & (sizeof(int *) - 1)));
  372. return 0; /* we returned the head */
  373. }
  374. #if defined(_DEBUG)
  375. static int
  376. describe_kind(struct lws_dll2 *d, void *user)
  377. {
  378. lws_dsh_obj_t *obj = lws_container_of(d, lws_dsh_obj_t, list);
  379. lwsl_info(" _obj %p - %p, dsh %p, size %zu, asize %zu\n",
  380. obj, (uint8_t *)obj + obj->asize,
  381. obj->dsh, obj->size, obj->asize);
  382. return 0;
  383. }
  384. void
  385. lws_dsh_describe(lws_dsh_t *dsh, const char *desc)
  386. {
  387. int n = 0;
  388. lwsl_info("%s: dsh %p, bufsize %zu, kinds %d, lf: %zu, liu: %zu, %s\n",
  389. __func__, dsh, dsh->buffer_size, dsh->count_kinds,
  390. dsh->locally_free, dsh->locally_in_use, desc);
  391. for (n = 0; n < dsh->count_kinds; n++) {
  392. lwsl_info(" Kind %d:\n", n);
  393. lws_dll2_foreach_safe(&dsh->oha[n].owner, dsh, describe_kind);
  394. }
  395. }
  396. #endif