connlist.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #include "connlist.h"
  2. conn_list_t conn_list = { NULL, NULL, 0, 0, PTHREAD_MUTEX_INITIALIZER };
  3. static h2o_stream_conn_t **conn_list_get_null_element_unsafe(conn_list_t *list)
  4. {
  5. struct conn_list_leaf *leaf = list->head;
  6. while (leaf != NULL) {
  7. for (int i = 0; i < CONN_LIST_MEMPOOL_SIZE; i++) {
  8. if (leaf->conn[i] == NULL)
  9. return &leaf->conn[i];
  10. }
  11. leaf = leaf->next;
  12. }
  13. return NULL;
  14. }
  15. void conn_list_insert(conn_list_t *list, h2o_stream_conn_t *conn)
  16. {
  17. pthread_mutex_lock(&list->lock);
  18. // in case the allocated capacity is not used up
  19. // we can reuse the null element
  20. if (list->capacity != list->size) {
  21. h2o_stream_conn_t **null_element = conn_list_get_null_element_unsafe(list);
  22. if (unlikely(null_element == NULL)) {
  23. pthread_mutex_unlock(&list->lock);
  24. error_report("conn_list_insert: capacity != size but no null element found");
  25. return;
  26. }
  27. *null_element = conn;
  28. list->size++;
  29. pthread_mutex_unlock(&list->lock);
  30. return;
  31. }
  32. // if not, we need to allocate a new leaf
  33. struct conn_list_leaf *old_tail = list->tail;
  34. list->tail = callocz(1, sizeof(struct conn_list_leaf));
  35. if (unlikely(old_tail == NULL))
  36. list->head = list->tail;
  37. else
  38. old_tail->next = list->tail;
  39. list->tail->conn[0] = conn;
  40. list->size++;
  41. list->capacity += CONN_LIST_MEMPOOL_SIZE;
  42. pthread_mutex_unlock(&list->lock);
  43. }
  44. typedef struct {
  45. conn_list_t *list;
  46. struct conn_list_leaf *leaf;
  47. int idx;
  48. } conn_list_iter_t;
  49. static inline void conn_list_iter_create_unsafe(conn_list_iter_t *iter, conn_list_t *list)
  50. {
  51. iter->list = list;
  52. iter->leaf = list->head;
  53. iter->idx = 0;
  54. }
  55. static inline int conn_list_iter_next_unsafe(conn_list_iter_t *iter, h2o_stream_conn_t **conn)
  56. {
  57. if (unlikely(iter->idx == iter->list->capacity))
  58. return 0;
  59. if (iter->idx && iter->idx % CONN_LIST_MEMPOOL_SIZE == 0) {
  60. iter->leaf = iter->leaf->next;
  61. }
  62. *conn = iter->leaf->conn[iter->idx++ % CONN_LIST_MEMPOOL_SIZE];
  63. return 1;
  64. }
  65. void conn_list_iter_all(conn_list_t *list, void (*cb)(h2o_stream_conn_t *conn))
  66. {
  67. pthread_mutex_lock(&list->lock);
  68. conn_list_iter_t iter;
  69. conn_list_iter_create_unsafe(&iter, list);
  70. h2o_stream_conn_t *conn;
  71. while (conn_list_iter_next_unsafe(&iter, &conn)) {
  72. if (conn == NULL)
  73. continue;
  74. cb(conn);
  75. }
  76. pthread_mutex_unlock(&list->lock);
  77. }
  78. static void conn_list_garbage_collect_unsafe(conn_list_t *list)
  79. {
  80. if (list->capacity - list->size > CONN_LIST_MEMPOOL_SIZE) {
  81. struct conn_list_leaf *new_tail = list->head;
  82. while (new_tail->next != list->tail)
  83. new_tail = new_tail->next;
  84. // check if the tail leaf is empty and move the data if not
  85. for (int i = 0; i < CONN_LIST_MEMPOOL_SIZE; i++) {
  86. if (list->tail->conn[i] != NULL) {
  87. h2o_stream_conn_t **null_element = conn_list_get_null_element_unsafe(list);
  88. if (unlikely(null_element == NULL)) {
  89. error_report("conn_list_garbage_collect_unsafe: list->capacity - list->size > CONN_LIST_MEMPOOL_SIZE but no null element found?");
  90. return;
  91. }
  92. *null_element = list->tail->conn[i];
  93. list->tail->conn[i] = NULL;
  94. }
  95. }
  96. freez(list->tail);
  97. new_tail->next = NULL;
  98. list->tail = new_tail;
  99. list->capacity -= CONN_LIST_MEMPOOL_SIZE;
  100. }
  101. }
  102. static inline int conn_list_iter_remove(conn_list_iter_t *iter, h2o_stream_conn_t *conn)
  103. {
  104. if (unlikely(iter->idx == iter->list->capacity))
  105. return -1;
  106. if (iter->idx && iter->idx % CONN_LIST_MEMPOOL_SIZE == 0) {
  107. iter->leaf = iter->leaf->next;
  108. }
  109. if(conn == iter->leaf->conn[iter->idx % CONN_LIST_MEMPOOL_SIZE]) {
  110. iter->leaf->conn[iter->idx % CONN_LIST_MEMPOOL_SIZE] = NULL;
  111. iter->idx++;
  112. return 1;
  113. }
  114. iter->idx++;
  115. return 0;
  116. }
  117. int conn_list_remove_conn(conn_list_t *list, h2o_stream_conn_t *conn)
  118. {
  119. pthread_mutex_lock(&list->lock);
  120. conn_list_iter_t iter;
  121. conn_list_iter_create_unsafe(&iter, list);
  122. int rc;
  123. while (!(rc = conn_list_iter_remove(&iter, conn)));
  124. if (rc == -1) {
  125. pthread_mutex_unlock(&list->lock);
  126. error_report("conn_list_remove_conn: conn not found");
  127. return 0;
  128. }
  129. list->size--;
  130. conn_list_garbage_collect_unsafe(list);
  131. pthread_mutex_unlock(&list->lock);
  132. return 1;
  133. }