connlist.c 4.5 KB

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