message_pool.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/io/message_pool.h>
  6. #include <aws/common/thread.h>
  7. int aws_memory_pool_init(
  8. struct aws_memory_pool *mempool,
  9. struct aws_allocator *alloc,
  10. uint16_t ideal_segment_count,
  11. size_t segment_size) {
  12. mempool->alloc = alloc;
  13. mempool->ideal_segment_count = ideal_segment_count;
  14. mempool->segment_size = segment_size;
  15. mempool->data_ptr = aws_mem_calloc(alloc, ideal_segment_count, sizeof(void *));
  16. if (!mempool->data_ptr) {
  17. return AWS_OP_ERR;
  18. }
  19. aws_array_list_init_static(&mempool->stack, mempool->data_ptr, ideal_segment_count, sizeof(void *));
  20. for (uint16_t i = 0; i < ideal_segment_count; ++i) {
  21. void *memory = aws_mem_acquire(alloc, segment_size);
  22. if (memory) {
  23. aws_array_list_push_back(&mempool->stack, &memory);
  24. } else {
  25. goto clean_up;
  26. }
  27. }
  28. return AWS_OP_SUCCESS;
  29. clean_up:
  30. aws_memory_pool_clean_up(mempool);
  31. return AWS_OP_ERR;
  32. }
  33. void aws_memory_pool_clean_up(struct aws_memory_pool *mempool) {
  34. void *cur = NULL;
  35. while (aws_array_list_length(&mempool->stack) > 0) {
  36. /* the only way this fails is not possible since I already checked the length. */
  37. aws_array_list_back(&mempool->stack, &cur);
  38. aws_array_list_pop_back(&mempool->stack);
  39. aws_mem_release(mempool->alloc, cur);
  40. }
  41. aws_array_list_clean_up(&mempool->stack);
  42. aws_mem_release(mempool->alloc, mempool->data_ptr);
  43. }
  44. void *aws_memory_pool_acquire(struct aws_memory_pool *mempool) {
  45. void *back = NULL;
  46. if (aws_array_list_length(&mempool->stack) > 0) {
  47. aws_array_list_back(&mempool->stack, &back);
  48. aws_array_list_pop_back(&mempool->stack);
  49. return back;
  50. }
  51. void *mem = aws_mem_acquire(mempool->alloc, mempool->segment_size);
  52. return mem;
  53. }
  54. void aws_memory_pool_release(struct aws_memory_pool *mempool, void *to_release) {
  55. size_t pool_size = aws_array_list_length(&mempool->stack);
  56. if (pool_size >= mempool->ideal_segment_count) {
  57. aws_mem_release(mempool->alloc, to_release);
  58. return;
  59. }
  60. aws_array_list_push_back(&mempool->stack, &to_release);
  61. }
  62. struct message_pool_allocator {
  63. struct aws_allocator base_allocator;
  64. struct aws_message_pool *msg_pool;
  65. };
  66. void *s_message_pool_mem_acquire(struct aws_allocator *allocator, size_t size) {
  67. (void)allocator;
  68. (void)size;
  69. /* no one should ever call this ever. */
  70. AWS_ASSERT(0);
  71. return NULL;
  72. }
  73. void s_message_pool_mem_release(struct aws_allocator *allocator, void *ptr) {
  74. struct message_pool_allocator *msg_pool_alloc = allocator->impl;
  75. aws_message_pool_release(msg_pool_alloc->msg_pool, (struct aws_io_message *)ptr);
  76. }
  77. static size_t MSG_OVERHEAD = sizeof(struct aws_io_message) + sizeof(struct message_pool_allocator);
  78. int aws_message_pool_init(
  79. struct aws_message_pool *msg_pool,
  80. struct aws_allocator *alloc,
  81. struct aws_message_pool_creation_args *args) {
  82. msg_pool->alloc = alloc;
  83. size_t msg_data_size = args->application_data_msg_data_size + MSG_OVERHEAD;
  84. if (aws_memory_pool_init(
  85. &msg_pool->application_data_pool, alloc, args->application_data_msg_count, msg_data_size)) {
  86. return AWS_OP_ERR;
  87. }
  88. size_t small_blk_data_size = args->small_block_msg_data_size + MSG_OVERHEAD;
  89. if (aws_memory_pool_init(&msg_pool->small_block_pool, alloc, args->small_block_msg_count, small_blk_data_size)) {
  90. aws_memory_pool_clean_up(&msg_pool->application_data_pool);
  91. return AWS_OP_ERR;
  92. }
  93. return AWS_OP_SUCCESS;
  94. }
  95. void aws_message_pool_clean_up(struct aws_message_pool *msg_pool) {
  96. aws_memory_pool_clean_up(&msg_pool->application_data_pool);
  97. aws_memory_pool_clean_up(&msg_pool->small_block_pool);
  98. AWS_ZERO_STRUCT(*msg_pool);
  99. }
  100. struct message_wrapper {
  101. struct aws_io_message message;
  102. struct message_pool_allocator msg_allocator;
  103. uint8_t buffer_start[1];
  104. };
  105. struct aws_io_message *aws_message_pool_acquire(
  106. struct aws_message_pool *msg_pool,
  107. enum aws_io_message_type message_type,
  108. size_t size_hint) {
  109. struct message_wrapper *message_wrapper = NULL;
  110. size_t max_size = 0;
  111. switch (message_type) {
  112. case AWS_IO_MESSAGE_APPLICATION_DATA:
  113. if (size_hint > msg_pool->small_block_pool.segment_size - MSG_OVERHEAD) {
  114. message_wrapper = aws_memory_pool_acquire(&msg_pool->application_data_pool);
  115. max_size = msg_pool->application_data_pool.segment_size - MSG_OVERHEAD;
  116. } else {
  117. message_wrapper = aws_memory_pool_acquire(&msg_pool->small_block_pool);
  118. max_size = msg_pool->small_block_pool.segment_size - MSG_OVERHEAD;
  119. }
  120. break;
  121. default:
  122. AWS_ASSERT(0);
  123. aws_raise_error(AWS_IO_CHANNEL_UNKNOWN_MESSAGE_TYPE);
  124. return NULL;
  125. }
  126. if (!message_wrapper) {
  127. return NULL;
  128. }
  129. message_wrapper->message.message_type = message_type;
  130. message_wrapper->message.message_tag = 0;
  131. message_wrapper->message.user_data = NULL;
  132. message_wrapper->message.copy_mark = 0;
  133. message_wrapper->message.on_completion = NULL;
  134. /* the buffer shares the allocation with the message. It's the bit at the end. */
  135. message_wrapper->message.message_data.buffer = message_wrapper->buffer_start;
  136. message_wrapper->message.message_data.len = 0;
  137. message_wrapper->message.message_data.capacity = size_hint <= max_size ? size_hint : max_size;
  138. /* set the allocator ptr */
  139. message_wrapper->msg_allocator.base_allocator.impl = &message_wrapper->msg_allocator;
  140. message_wrapper->msg_allocator.base_allocator.mem_acquire = s_message_pool_mem_acquire;
  141. message_wrapper->msg_allocator.base_allocator.mem_realloc = NULL;
  142. message_wrapper->msg_allocator.base_allocator.mem_release = s_message_pool_mem_release;
  143. message_wrapper->msg_allocator.msg_pool = msg_pool;
  144. message_wrapper->message.allocator = &message_wrapper->msg_allocator.base_allocator;
  145. return &message_wrapper->message;
  146. }
  147. void aws_message_pool_release(struct aws_message_pool *msg_pool, struct aws_io_message *message) {
  148. memset(message->message_data.buffer, 0, message->message_data.len);
  149. message->allocator = NULL;
  150. struct message_wrapper *wrapper = AWS_CONTAINER_OF(message, struct message_wrapper, message);
  151. switch (message->message_type) {
  152. case AWS_IO_MESSAGE_APPLICATION_DATA:
  153. if (message->message_data.capacity > msg_pool->small_block_pool.segment_size - MSG_OVERHEAD) {
  154. aws_memory_pool_release(&msg_pool->application_data_pool, wrapper);
  155. } else {
  156. aws_memory_pool_release(&msg_pool->small_block_pool, wrapper);
  157. }
  158. break;
  159. default:
  160. AWS_ASSERT(0);
  161. aws_raise_error(AWS_IO_CHANNEL_UNKNOWN_MESSAGE_TYPE);
  162. }
  163. }