iobuffer.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. #include "precompile.h"
  2. #include "iobuffer.h"
  3. #include "refcnt.h"
  4. #include "memutil.h"
  5. #include "list.h"
  6. #include <assert.h>
  7. struct iobuffer_t
  8. {
  9. struct list_head sp_entry;
  10. char *sp_data;
  11. int sp_capacity;
  12. int sp_hdr_capacity;
  13. int sp_wpos;
  14. int sp_rpos;
  15. void *sp_user_data;
  16. DECLARE_REF_COUNT_MEMBER(sp_ref_cnt);
  17. };
  18. #define DEFAULT_CAPACITY 256
  19. #define DEFAULT_HEADER_CAPACITY 128
  20. static void expand(iobuffer_t *iobuf, int head_capacity, int newcapacity)
  21. {
  22. if (head_capacity == -1) {
  23. int t = iobuf->sp_capacity;
  24. while (newcapacity > t)
  25. t = t*2;
  26. if (t > iobuf->sp_capacity) {
  27. iobuf->sp_data = (char*)realloc(iobuf->sp_data, t);
  28. iobuf->sp_capacity = t;
  29. }
  30. } else if (newcapacity == -1) {
  31. int t = iobuf->sp_hdr_capacity;
  32. while (head_capacity > t)
  33. t = t*2;
  34. if (t > iobuf->sp_rpos) {
  35. char *new_data;
  36. int new_rpos;
  37. int new_wpos;
  38. newcapacity = iobuf->sp_capacity + (t - iobuf->sp_hdr_capacity);
  39. new_data = malloc(newcapacity);
  40. new_rpos = t;
  41. new_wpos = new_rpos + (iobuf->sp_wpos - iobuf->sp_rpos);
  42. memcpy(new_data+new_rpos, iobuf->sp_data+iobuf->sp_rpos, iobuf->sp_wpos - iobuf->sp_rpos);
  43. free(iobuf->sp_data);
  44. iobuf->sp_data = new_data;
  45. iobuf->sp_rpos = new_rpos;
  46. iobuf->sp_wpos = new_wpos;
  47. iobuf->sp_hdr_capacity = t;
  48. iobuf->sp_capacity = newcapacity;
  49. }
  50. } else {
  51. int t = iobuf->sp_capacity;
  52. char *new_data = (char*)malloc(t);
  53. int new_rpos = head_capacity;
  54. int new_wpos = new_rpos + (iobuf->sp_wpos - iobuf->sp_rpos);
  55. while (newcapacity > t)
  56. t = t*2;
  57. memcpy(new_data+new_rpos, iobuf->sp_data+iobuf->sp_rpos, iobuf->sp_wpos - iobuf->sp_rpos);
  58. free(iobuf->sp_data);
  59. iobuf->sp_data = new_data;
  60. iobuf->sp_rpos = new_rpos;
  61. iobuf->sp_wpos = new_wpos;
  62. iobuf->sp_capacity = t;
  63. }
  64. }
  65. static __inline int empty_size(iobuffer_t *iobuf)
  66. {
  67. return iobuf->sp_capacity - iobuf->sp_wpos;
  68. }
  69. static __inline int content_size(iobuffer_t *iobuf)
  70. {
  71. return iobuf->sp_wpos - iobuf->sp_rpos;
  72. }
  73. static void destroy(iobuffer_t *iobuf)
  74. {
  75. iobuffer_set_capacity(iobuf, 0);
  76. //memset(iobuf, 0, sizeof(*iobuf));
  77. free(iobuf);
  78. }
  79. static void iobuffer_write_buf(iobuffer_t *iobuf, const char *buf, int n)
  80. {
  81. if (n+iobuf->sp_wpos > iobuf->sp_capacity)
  82. expand(iobuf, -1, n + iobuf->sp_wpos);
  83. memcpy(iobuf->sp_data+iobuf->sp_wpos, buf, n);
  84. iobuf->sp_wpos += n;
  85. }
  86. static void iobuffer_write_head_buf(iobuffer_t *iobuf, const char *buf, int n)
  87. {
  88. if (iobuf->sp_rpos < n)
  89. expand(iobuf, iobuf->sp_hdr_capacity-iobuf->sp_rpos+n, -1);
  90. iobuf->sp_rpos -= n;
  91. memcpy(iobuf->sp_data+iobuf->sp_rpos, buf, n);
  92. }
  93. static int write_7bit_int(unsigned char buf[8], unsigned int v)
  94. {
  95. int i = 0;
  96. while (v >= 0x80) {
  97. buf[i++] = (unsigned char)(v | 0x80); // set most left bit == 1
  98. v >>= 7;
  99. }
  100. buf[i++] = (unsigned char)v;
  101. return i;
  102. }
  103. static void iobuffer_write_7bit_int(iobuffer_t *iobuf, unsigned int v)
  104. {
  105. char buf[8];
  106. int n = write_7bit_int(buf, v);
  107. iobuffer_write_buf(iobuf, buf, n);
  108. }
  109. static void iobuffer_write_head_7bit_int(iobuffer_t *iobuf, unsigned int v)
  110. {
  111. char buf[8];
  112. int n = write_7bit_int(buf, v);
  113. iobuffer_write_head_buf(iobuf, buf, n);
  114. }
  115. static void iobuffer_read_buf(iobuffer_t *iobuf, char *buf, int n)
  116. {
  117. assert(content_size(iobuf) >= n);
  118. memcpy(buf, iobuf->sp_data+iobuf->sp_rpos, n);
  119. iobuf->sp_rpos += n;
  120. }
  121. static void iobuffer_read_7bit_int(iobuffer_t *iobuf, int *v)
  122. {
  123. int count = 0;
  124. int shift = 0;
  125. unsigned char b;
  126. do {
  127. if (shift == 5*7) // corrupted stream
  128. assert(0);
  129. b = iobuf->sp_data[iobuf->sp_rpos ++];
  130. count |= (b & 0x7F) << shift;
  131. shift += 7;
  132. } while (b & 0x80); // most left bit is flag
  133. *v = count;
  134. }
  135. TOOLKIT_API iobuffer_t *iobuffer_create(int head_capacity, int capacity)
  136. {
  137. iobuffer_t *iobuf;
  138. if (head_capacity <= 0)
  139. head_capacity = DEFAULT_HEADER_CAPACITY;
  140. if (capacity <= 0) {
  141. capacity = head_capacity + DEFAULT_CAPACITY;
  142. } else {
  143. capacity += head_capacity;
  144. }
  145. iobuf = MALLOC_T(iobuffer_t);
  146. iobuf->sp_hdr_capacity = head_capacity;
  147. iobuf->sp_capacity = capacity;
  148. iobuf->sp_data = malloc(capacity);
  149. iobuf->sp_user_data = NULL;
  150. iobuf->sp_entry.next = iobuf->sp_entry.prev = NULL;
  151. iobuffer_reset(iobuf);
  152. REF_COUNT_INIT(&iobuf->sp_ref_cnt);
  153. return iobuf;
  154. }
  155. TOOLKIT_API void iobuffer_destroy(iobuffer_t *iobuf)
  156. {
  157. iobuffer_dec_ref(iobuf);
  158. }
  159. TOOLKIT_API iobuffer_t *iobuffer_clone(iobuffer_t *iobuf)
  160. {
  161. iobuffer_t *newiobuf;
  162. newiobuf = iobuffer_create(iobuf->sp_hdr_capacity, iobuf->sp_capacity);
  163. memcpy(newiobuf->sp_data+iobuf->sp_rpos, iobuf->sp_data+iobuf->sp_rpos, iobuf->sp_wpos-iobuf->sp_rpos);
  164. newiobuf->sp_rpos = iobuf->sp_rpos;
  165. newiobuf->sp_wpos = iobuf->sp_wpos;
  166. newiobuf->sp_user_data = iobuf->sp_user_data;
  167. return newiobuf;
  168. }
  169. TOOLKIT_API void iobuffer_reset(iobuffer_t *iobuf)
  170. {
  171. iobuf->sp_rpos = iobuf->sp_hdr_capacity;
  172. iobuf->sp_wpos = iobuf->sp_hdr_capacity;
  173. }
  174. TOOLKIT_API int iobuffer_get_capacity(iobuffer_t *iobuf)
  175. {
  176. return iobuf->sp_capacity;
  177. }
  178. TOOLKIT_API void iobuffer_set_capacity(iobuffer_t *iobuf, int capacity)
  179. {
  180. iobuf->sp_data = (char*)realloc(iobuf->sp_data, capacity);
  181. if (iobuf->sp_wpos > capacity)
  182. iobuf->sp_wpos = capacity;
  183. if (iobuf->sp_rpos > capacity)
  184. iobuf->sp_rpos = capacity;
  185. iobuf->sp_capacity = capacity;
  186. }
  187. TOOLKIT_API char *iobuffer_data(iobuffer_t *iobuf, int offset)
  188. {
  189. if (offset != -1) {
  190. return iobuf->sp_data + iobuf->sp_rpos + offset;
  191. } else {
  192. return iobuf->sp_data + iobuf->sp_wpos;
  193. }
  194. }
  195. TOOLKIT_API int iobuffer_get_length(iobuffer_t *iobuf)
  196. {
  197. return iobuf->sp_wpos - iobuf->sp_rpos;
  198. }
  199. TOOLKIT_API void iobuffer_set_length(iobuffer_t *iobuf, int length)
  200. {
  201. iobuf->sp_wpos = iobuf->sp_rpos + length;
  202. if (iobuf->sp_wpos > iobuf->sp_capacity)
  203. iobuf->sp_wpos = iobuf->sp_capacity;
  204. }
  205. TOOLKIT_API void iobuffer_push_count(iobuffer_t *iobuf, int n)
  206. {
  207. assert(empty_size(iobuf) >= n);
  208. iobuf->sp_wpos += n;
  209. }
  210. TOOLKIT_API void iobuffer_pop_count(iobuffer_t *iobuf, int n)
  211. {
  212. assert(content_size(iobuf) >= n);
  213. iobuf->sp_rpos += n;
  214. }
  215. TOOLKIT_API void iobuffer_write(iobuffer_t *iobuf, int t, const void *v, int n)
  216. {
  217. int len = 0;
  218. switch (t) {
  219. case IOBUF_T_I8:
  220. len += 4;
  221. case IOBUF_T_I4:
  222. len += 2;
  223. case IOBUF_T_I2:
  224. len += 1;
  225. case IOBUF_T_I1:
  226. len += 1;
  227. iobuffer_write_buf(iobuf, v, len);
  228. break;
  229. case IOBUF_T_STR:
  230. if (!v) {
  231. n = 0;
  232. } else {
  233. if (n == -1)
  234. n = strlen(v);
  235. }
  236. iobuffer_write_7bit_int(iobuf, (unsigned int)n);
  237. if (n > 0)
  238. iobuffer_write_buf(iobuf, v, n);
  239. break;
  240. case IOBUF_T_WSTR:
  241. if (!v) {
  242. n = 0;
  243. } else {
  244. if (n == -1)
  245. n = wcslen(v)<<1;
  246. }
  247. iobuffer_write_7bit_int(iobuf, n);
  248. if (n > 0)
  249. iobuffer_write_buf(iobuf, v, n);
  250. break;
  251. case IOBUF_T_BUF:
  252. if (n > 0)
  253. iobuffer_write_buf(iobuf, v, n);
  254. break;
  255. case IOBUF_T_7BIT:
  256. iobuffer_write_7bit_int(iobuf, *(unsigned int*)v);
  257. break;
  258. }
  259. }
  260. TOOLKIT_API void iobuffer_write_head(iobuffer_t *iobuf, int t, const void *v, int n)
  261. {
  262. int len = 0;
  263. switch (t) {
  264. case IOBUF_T_I8:
  265. len += 4;
  266. case IOBUF_T_I4:
  267. len += 2;
  268. case IOBUF_T_I2:
  269. len += 1;
  270. case IOBUF_T_I1:
  271. len += 1;
  272. iobuffer_write_head_buf(iobuf, v, len);
  273. break;
  274. case IOBUF_T_STR:
  275. if (!v) {
  276. n = 0;
  277. } else {
  278. if (n == -1) {
  279. n = strlen(v);
  280. }
  281. }
  282. if (n > 0)
  283. iobuffer_write_head_buf(iobuf, v, n);
  284. iobuffer_write_head_7bit_int(iobuf, n);
  285. break;
  286. case IOBUF_T_WSTR:
  287. if (!v) {
  288. n = 0;
  289. } else {
  290. if (n == -1) {
  291. n = wcslen(v)<<1;
  292. }
  293. }
  294. if (n > 0)
  295. iobuffer_write_head_buf(iobuf, v, n);
  296. iobuffer_write_head_7bit_int(iobuf, n);
  297. break;
  298. case IOBUF_T_BUF:
  299. if (n > 0)
  300. iobuffer_write_head_buf(iobuf, v, n);
  301. break;
  302. case IOBUF_T_7BIT:
  303. iobuffer_write_head_7bit_int(iobuf, *(unsigned int*)v);
  304. break;
  305. default:
  306. assert(0);
  307. }
  308. }
  309. TOOLKIT_API void iobuffer_read(iobuffer_t *iobuf, int t, void *v, int *n)
  310. {
  311. int len = 0;
  312. switch (t) {
  313. case IOBUF_T_I8:
  314. len += 4;
  315. case IOBUF_T_I4:
  316. len += 2;
  317. case IOBUF_T_I2:
  318. len += 1;
  319. case IOBUF_T_I1:
  320. len += 1;
  321. iobuffer_read_buf(iobuf, v, len);
  322. break;
  323. case IOBUF_T_STR:
  324. if (v) {
  325. int old_rpos = iobuf->sp_rpos;
  326. iobuffer_read_7bit_int(iobuf, &len);
  327. if (!n || len < *n) {
  328. iobuffer_read_buf(iobuf, v, len);
  329. *((char*)v + len) = 0;
  330. if (n)
  331. *n = len;
  332. } else {
  333. iobuf->sp_rpos = old_rpos;
  334. *n = len;
  335. }
  336. } else {
  337. if (n) {
  338. int old_rpos = iobuf->sp_rpos;
  339. iobuffer_read_7bit_int(iobuf, &len);
  340. iobuf->sp_rpos = old_rpos;
  341. *n = len;
  342. } else {
  343. assert(0);
  344. }
  345. }
  346. break;
  347. case IOBUF_T_WSTR:
  348. if (v) {
  349. int old_rpos = iobuf->sp_rpos;
  350. iobuffer_read_7bit_int(iobuf, &len);
  351. if (!n || len < *n) {
  352. iobuffer_read_buf(iobuf, v, len); /* wchar_t */
  353. *((char*)v + len) = 0; // wchar termination char is 2 byte
  354. *((char*)v + len+1) = 0;
  355. if (n)
  356. *n = len;
  357. } else {
  358. iobuf->sp_rpos = old_rpos;
  359. *n = len;
  360. }
  361. } else {
  362. if (n) {
  363. int old_rpos = iobuf->sp_rpos;
  364. iobuffer_read_7bit_int(iobuf, &len);
  365. iobuf->sp_rpos = old_rpos;
  366. *n = len;
  367. } else {
  368. assert(0);
  369. }
  370. }
  371. break;
  372. case IOBUF_T_BUF:
  373. if (*n > 0)
  374. iobuffer_read_buf(iobuf, v, *n);
  375. break;
  376. case IOBUF_T_7BIT:
  377. iobuffer_read_7bit_int(iobuf, v);
  378. break;
  379. default:
  380. assert(0);
  381. }
  382. }
  383. TOOLKIT_API int iobuffer_get_read_state(iobuffer_t *iobuf)
  384. {
  385. return iobuf->sp_rpos;
  386. }
  387. TOOLKIT_API void iobuffer_restore_read_state(iobuffer_t *iobuf, int state)
  388. {
  389. iobuf->sp_rpos = state;
  390. }
  391. TOOLKIT_API int iobuffer_get_write_state(iobuffer_t *iobuf)
  392. {
  393. return iobuf->sp_wpos;
  394. }
  395. TOOLKIT_API void iobuffer_restore_write_state(iobuffer_t *iobuf, int state)
  396. {
  397. iobuf->sp_wpos = state;
  398. }
  399. TOOLKIT_API void iobuffer_set_user_data(iobuffer_t *iobuf, void *user_data)
  400. {
  401. iobuf->sp_user_data = user_data;
  402. }
  403. TOOLKIT_API void *iobuffer_get_user_data(iobuffer_t *iobuf)
  404. {
  405. return iobuf->sp_user_data;
  406. }
  407. IMPLEMENT_REF_COUNT_MT(iobuffer, iobuffer_t, sp_ref_cnt, destroy)
  408. TOOLKIT_API void iobuffer_format_readv(iobuffer_t *iobuf, const char *fmt, va_list arg)
  409. {
  410. if (fmt) {
  411. const char *p = fmt;
  412. while (*p) {
  413. switch (*p) {
  414. case '8':
  415. iobuffer_read(iobuf, IOBUF_T_I8, va_arg(arg, void*), NULL);
  416. break;
  417. case '7': // 7bit int code
  418. iobuffer_read(iobuf, IOBUF_T_7BIT, va_arg(arg, void*), NULL);
  419. break;
  420. case '4':
  421. iobuffer_read(iobuf, IOBUF_T_I4, va_arg(arg, void*), 0);
  422. break;
  423. case '2':
  424. iobuffer_read(iobuf, IOBUF_T_I2, va_arg(arg, void*), 0);
  425. break;
  426. case '1':
  427. iobuffer_read(iobuf, IOBUF_T_I1, va_arg(arg, void*), 0);
  428. break;
  429. case 's':case 'S':
  430. {
  431. char **pstr = va_arg(arg, char**);
  432. int slen;
  433. iobuffer_read(iobuf, IOBUF_T_STR, NULL, &slen);
  434. *pstr = (char*)malloc(slen+1);
  435. iobuffer_read(iobuf, IOBUF_T_STR, *pstr, 0);
  436. }
  437. break;
  438. case 'w': case 'W':
  439. {
  440. wchar_t **pstr = va_arg(arg, wchar_t**);
  441. int slen;
  442. iobuffer_read(iobuf, IOBUF_T_WSTR, NULL, &slen);
  443. *pstr = (wchar_t*)malloc(slen+2); // null terminated is two bytes
  444. iobuffer_read(iobuf, IOBUF_T_WSTR, *pstr, 0);
  445. }
  446. break;
  447. case 'b':case 'B':
  448. {
  449. void *buf = va_arg(arg, void*);
  450. int size = va_arg(arg, int);
  451. iobuffer_read(iobuf, IOBUF_T_BUF, buf, &size);
  452. }
  453. break;
  454. default:
  455. assert(0);
  456. break;
  457. }
  458. p++;
  459. }
  460. }
  461. }
  462. TOOLKIT_API void iobuffer_format_writev(iobuffer_t *iobuf, const char *fmt, va_list arg)
  463. {
  464. if (fmt) {
  465. const char *p = fmt;
  466. while (*p) {
  467. switch (*p) {
  468. case '8':
  469. iobuffer_write(iobuf, IOBUF_T_I8, va_arg(arg, void*), 0);
  470. break;
  471. case '7':
  472. iobuffer_write(iobuf, IOBUF_T_7BIT, va_arg(arg, void*), 0);
  473. break;
  474. case '4':
  475. iobuffer_write(iobuf, IOBUF_T_I4, va_arg(arg, void*), 0);
  476. break;
  477. case '2':
  478. iobuffer_write(iobuf, IOBUF_T_I2, va_arg(arg, void*), 0);
  479. break;
  480. case '1':
  481. iobuffer_write(iobuf, IOBUF_T_I1, va_arg(arg, void*), 0);
  482. break;
  483. case 's':case 'S':
  484. iobuffer_write(iobuf, IOBUF_T_STR, va_arg(arg, void*), -1);
  485. break;
  486. case 'w':case 'W':
  487. iobuffer_write(iobuf, IOBUF_T_WSTR, va_arg(arg, void*), -1);
  488. break;
  489. case 'b':case 'B':
  490. {
  491. void *buf = va_arg(arg, void*);
  492. int size = va_arg(arg, int);
  493. iobuffer_write(iobuf, IOBUF_T_BUF, buf, size);
  494. }
  495. break;
  496. default:
  497. assert(0);
  498. break;
  499. }
  500. p++;
  501. }
  502. }
  503. }
  504. TOOLKIT_API void iobuffer_format_read(iobuffer_t *iobuf, const char *fmt, ...)
  505. {
  506. va_list arg;
  507. va_start(arg, fmt);
  508. iobuffer_format_readv(iobuf, fmt, arg);
  509. va_end(arg);
  510. }
  511. TOOLKIT_API void iobuffer_format_write(iobuffer_t *iobuf, const char *fmt, ...)
  512. {
  513. va_list arg;
  514. va_start(arg, fmt);
  515. iobuffer_format_writev(iobuf, fmt, arg);
  516. va_end(arg);
  517. }
  518. TOOLKIT_API void iobuffer_format_writev_head(iobuffer_t *iobuf, const char *fmt, va_list arg)
  519. {
  520. if (fmt) {
  521. const char *p = fmt;
  522. while (*p) {
  523. switch (*p) {
  524. case '8':
  525. iobuffer_write_head(iobuf, IOBUF_T_I8, va_arg(arg, void*), 0);
  526. break;
  527. case '7':
  528. iobuffer_write_head(iobuf, IOBUF_T_7BIT, va_arg(arg, void*), 0);
  529. break;
  530. case '4':
  531. iobuffer_write_head(iobuf, IOBUF_T_I4, va_arg(arg, void*), 0);
  532. break;
  533. case '2':
  534. iobuffer_write_head(iobuf, IOBUF_T_I2, va_arg(arg, void*), 0);
  535. break;
  536. case '1':
  537. iobuffer_write_head(iobuf, IOBUF_T_I1, va_arg(arg, void*), 0);
  538. break;
  539. case 's':case 'S':
  540. iobuffer_write_head(iobuf, IOBUF_T_STR, va_arg(arg, void*), -1);
  541. break;
  542. case 'w':case 'W':
  543. iobuffer_write_head(iobuf, IOBUF_T_WSTR, va_arg(arg, void*), -1);
  544. break;
  545. case 'b':case 'B':
  546. {
  547. void *buf = va_arg(arg, void*);
  548. int size = va_arg(arg, int);
  549. iobuffer_write_head(iobuf, IOBUF_T_BUF, buf, size);
  550. }
  551. break;
  552. default:
  553. assert(0);
  554. break;
  555. }
  556. p++;
  557. }
  558. }
  559. }
  560. TOOLKIT_API void iobuffer_format_write_head(iobuffer_t *iobuf, const char *fmt, ...)
  561. {
  562. va_list arg;
  563. va_start(arg, fmt);
  564. iobuffer_format_writev_head(iobuf, fmt, arg);
  565. va_end(arg);
  566. }
  567. struct iobuffer_queue_t
  568. {
  569. struct list_head iobuf_list;
  570. int cnt;
  571. };
  572. TOOLKIT_API iobuffer_queue_t *iobuffer_queue_create()
  573. {
  574. iobuffer_queue_t *queue = MALLOC_T(iobuffer_queue_t);
  575. queue->cnt = 0;
  576. INIT_LIST_HEAD(&queue->iobuf_list);
  577. return queue;
  578. }
  579. TOOLKIT_API void iobuffer_queue_destroy(iobuffer_queue_t *queue)
  580. {
  581. while (!list_empty(&queue->iobuf_list)) {
  582. iobuffer_t *iobuf = iobuffer_queue_deque(queue);
  583. iobuffer_destroy(iobuf);
  584. }
  585. free(queue);
  586. }
  587. TOOLKIT_API void iobuffer_queue_enqueue(iobuffer_queue_t *queue, iobuffer_t *iobuf)
  588. {
  589. list_add_tail(&iobuf->sp_entry, &queue->iobuf_list);
  590. queue->cnt++;
  591. }
  592. TOOLKIT_API iobuffer_t *iobuffer_queue_deque(iobuffer_queue_t *queue)
  593. {
  594. iobuffer_t *iob = list_first_entry(&queue->iobuf_list, iobuffer_t, sp_entry);
  595. list_del(&iob->sp_entry);
  596. queue->cnt--;
  597. return iob;
  598. }
  599. TOOLKIT_API int iobuffer_queue_count(iobuffer_queue_t *queue)
  600. {
  601. return queue->cnt;
  602. }
  603. TOOLKIT_API iobuffer_t *iobuffer_queue_head(iobuffer_queue_t *queue)
  604. {
  605. return list_first_entry(&queue->iobuf_list, iobuffer_t, sp_entry);
  606. }
  607. TOOLKIT_API iobuffer_t *iobuffer_queue_tail(iobuffer_queue_t *queue)
  608. {
  609. return list_last_entry(&queue->iobuf_list, iobuffer_t, sp_entry);
  610. }