thread_queue_list.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright 2014 Citra Emulator Project / PPSSPP Project
  2. // Licensed under GPLv2
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include "common/common.h"
  6. namespace Common {
  7. template<class IdType>
  8. struct ThreadQueueList {
  9. // Number of queues (number of priority levels starting at 0.)
  10. static const int NUM_QUEUES = 128;
  11. // Initial number of threads a single queue can handle.
  12. static const int INITIAL_CAPACITY = 32;
  13. struct Queue {
  14. // Next ever-been-used queue (worse priority.)
  15. Queue *next;
  16. // First valid item in data.
  17. int first;
  18. // One after last valid item in data.
  19. int end;
  20. // A too-large array with room on the front and end.
  21. IdType *data;
  22. // Size of data array.
  23. int capacity;
  24. };
  25. ThreadQueueList() {
  26. memset(queues, 0, sizeof(queues));
  27. first = invalid();
  28. }
  29. ~ThreadQueueList() {
  30. for (int i = 0; i < NUM_QUEUES; ++i)
  31. {
  32. if (queues[i].data != NULL)
  33. free(queues[i].data);
  34. }
  35. }
  36. // Only for debugging, returns priority level.
  37. int contains(const IdType uid) {
  38. for (int i = 0; i < NUM_QUEUES; ++i)
  39. {
  40. if (queues[i].data == NULL)
  41. continue;
  42. Queue *cur = &queues[i];
  43. for (int j = cur->first; j < cur->end; ++j)
  44. {
  45. if (cur->data[j] == uid)
  46. return i;
  47. }
  48. }
  49. return -1;
  50. }
  51. inline IdType pop_first() {
  52. Queue *cur = first;
  53. while (cur != invalid())
  54. {
  55. if (cur->end - cur->first > 0)
  56. return cur->data[cur->first++];
  57. cur = cur->next;
  58. }
  59. //_dbg_assert_msg_(SCEKERNEL, false, "ThreadQueueList should not be empty.");
  60. return 0;
  61. }
  62. inline IdType pop_first_better(u32 priority) {
  63. Queue *cur = first;
  64. Queue *stop = &queues[priority];
  65. while (cur < stop)
  66. {
  67. if (cur->end - cur->first > 0)
  68. return cur->data[cur->first++];
  69. cur = cur->next;
  70. }
  71. return 0;
  72. }
  73. inline void push_front(u32 priority, const IdType threadID) {
  74. Queue *cur = &queues[priority];
  75. cur->data[--cur->first] = threadID;
  76. if (cur->first == 0)
  77. rebalance(priority);
  78. }
  79. inline void push_back(u32 priority, const IdType threadID) {
  80. Queue *cur = &queues[priority];
  81. cur->data[cur->end++] = threadID;
  82. if (cur->end == cur->capacity)
  83. rebalance(priority);
  84. }
  85. inline void remove(u32 priority, const IdType threadID) {
  86. Queue *cur = &queues[priority];
  87. //_dbg_assert_msg_(SCEKERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
  88. for (int i = cur->first; i < cur->end; ++i)
  89. {
  90. if (cur->data[i] == threadID)
  91. {
  92. int remaining = --cur->end - i;
  93. if (remaining > 0)
  94. memmove(&cur->data[i], &cur->data[i + 1], remaining * sizeof(IdType));
  95. return;
  96. }
  97. }
  98. // Wasn't there.
  99. }
  100. inline void rotate(u32 priority) {
  101. Queue *cur = &queues[priority];
  102. //_dbg_assert_msg_(SCEKERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
  103. if (cur->end - cur->first > 1)
  104. {
  105. cur->data[cur->end++] = cur->data[cur->first++];
  106. if (cur->end == cur->capacity)
  107. rebalance(priority);
  108. }
  109. }
  110. inline void clear() {
  111. for (int i = 0; i < NUM_QUEUES; ++i)
  112. {
  113. if (queues[i].data != NULL)
  114. free(queues[i].data);
  115. }
  116. memset(queues, 0, sizeof(queues));
  117. first = invalid();
  118. }
  119. inline bool empty(u32 priority) const {
  120. const Queue *cur = &queues[priority];
  121. return cur->first == cur->end;
  122. }
  123. inline void prepare(u32 priority) {
  124. Queue *cur = &queues[priority];
  125. if (cur->next == NULL)
  126. link(priority, INITIAL_CAPACITY);
  127. }
  128. private:
  129. Queue *invalid() const {
  130. return (Queue *) -1;
  131. }
  132. void link(u32 priority, int size) {
  133. //_dbg_assert_msg_(SCEKERNEL, queues[priority].data == NULL, "ThreadQueueList::Queue should only be initialized once.");
  134. if (size <= INITIAL_CAPACITY)
  135. size = INITIAL_CAPACITY;
  136. else
  137. {
  138. int goal = size;
  139. size = INITIAL_CAPACITY;
  140. while (size < goal)
  141. size *= 2;
  142. }
  143. Queue *cur = &queues[priority];
  144. cur->data = (IdType *) malloc(sizeof(IdType) * size);
  145. cur->capacity = size;
  146. cur->first = size / 2;
  147. cur->end = size / 2;
  148. for (int i = (int) priority - 1; i >= 0; --i)
  149. {
  150. if (queues[i].next != NULL)
  151. {
  152. cur->next = queues[i].next;
  153. queues[i].next = cur;
  154. return;
  155. }
  156. }
  157. cur->next = first;
  158. first = cur;
  159. }
  160. void rebalance(u32 priority) {
  161. Queue *cur = &queues[priority];
  162. int size = cur->end - cur->first;
  163. if (size >= cur->capacity - 2) {
  164. IdType *new_data = (IdType *)realloc(cur->data, cur->capacity * 2 * sizeof(IdType));
  165. if (new_data != NULL) {
  166. cur->capacity *= 2;
  167. cur->data = new_data;
  168. }
  169. }
  170. int newFirst = (cur->capacity - size) / 2;
  171. if (newFirst != cur->first) {
  172. memmove(&cur->data[newFirst], &cur->data[cur->first], size * sizeof(IdType));
  173. cur->first = newFirst;
  174. cur->end = newFirst + size;
  175. }
  176. }
  177. // The first queue that's ever been used.
  178. Queue *first;
  179. // The priority level queues of thread ids.
  180. Queue queues[NUM_QUEUES];
  181. };
  182. } // namespace