diff options
| author | 2014-05-15 18:19:34 -0400 | |
|---|---|---|
| committer | 2014-05-15 18:19:34 -0400 | |
| commit | cf2eb8e3d3876d5866bdcb5dfe2ae9deceea2cb4 (patch) | |
| tree | 54f5df772f7c0726c82f8041cff8d3e01b3b332e | |
| parent | - added helper function for __KernelCreateThread (diff) | |
| download | yuzu-cf2eb8e3d3876d5866bdcb5dfe2ae9deceea2cb4.tar.gz yuzu-cf2eb8e3d3876d5866bdcb5dfe2ae9deceea2cb4.tar.xz yuzu-cf2eb8e3d3876d5866bdcb5dfe2ae9deceea2cb4.zip | |
added ThreadQueueList class to common (taken from PPSSPP)
| -rw-r--r-- | src/common/common.vcxproj | 1 | ||||
| -rw-r--r-- | src/common/common.vcxproj.filters | 1 | ||||
| -rw-r--r-- | src/common/thread_queue_list.h | 216 |
3 files changed, 218 insertions, 0 deletions
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 5dc6ff790..86295a480 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj | |||
| @@ -190,6 +190,7 @@ | |||
| 190 | <ClInclude Include="swap.h" /> | 190 | <ClInclude Include="swap.h" /> |
| 191 | <ClInclude Include="symbols.h" /> | 191 | <ClInclude Include="symbols.h" /> |
| 192 | <ClInclude Include="thread.h" /> | 192 | <ClInclude Include="thread.h" /> |
| 193 | <ClInclude Include="thread_queue_list.h" /> | ||
| 193 | <ClInclude Include="thunk.h" /> | 194 | <ClInclude Include="thunk.h" /> |
| 194 | <ClInclude Include="timer.h" /> | 195 | <ClInclude Include="timer.h" /> |
| 195 | <ClInclude Include="utf8.h" /> | 196 | <ClInclude Include="utf8.h" /> |
diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 268730228..84cfa8837 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | <ClInclude Include="symbols.h" /> | 40 | <ClInclude Include="symbols.h" /> |
| 41 | <ClInclude Include="scm_rev.h" /> | 41 | <ClInclude Include="scm_rev.h" /> |
| 42 | <ClInclude Include="bit_field.h" /> | 42 | <ClInclude Include="bit_field.h" /> |
| 43 | <ClInclude Include="thread_queue_list.h" /> | ||
| 43 | </ItemGroup> | 44 | </ItemGroup> |
| 44 | <ItemGroup> | 45 | <ItemGroup> |
| 45 | <ClCompile Include="break_points.cpp" /> | 46 | <ClCompile Include="break_points.cpp" /> |
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h new file mode 100644 index 000000000..4a89572f6 --- /dev/null +++ b/src/common/thread_queue_list.h | |||
| @@ -0,0 +1,216 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project / PPSSPP Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common.h" | ||
| 8 | |||
| 9 | namespace Common { | ||
| 10 | |||
| 11 | template<class IdType> | ||
| 12 | struct ThreadQueueList { | ||
| 13 | // Number of queues (number of priority levels starting at 0.) | ||
| 14 | static const int NUM_QUEUES = 128; | ||
| 15 | |||
| 16 | // Initial number of threads a single queue can handle. | ||
| 17 | static const int INITIAL_CAPACITY = 32; | ||
| 18 | |||
| 19 | struct Queue { | ||
| 20 | // Next ever-been-used queue (worse priority.) | ||
| 21 | Queue *next; | ||
| 22 | // First valid item in data. | ||
| 23 | int first; | ||
| 24 | // One after last valid item in data. | ||
| 25 | int end; | ||
| 26 | // A too-large array with room on the front and end. | ||
| 27 | IdType *data; | ||
| 28 | // Size of data array. | ||
| 29 | int capacity; | ||
| 30 | }; | ||
| 31 | |||
| 32 | ThreadQueueList() { | ||
| 33 | memset(queues, 0, sizeof(queues)); | ||
| 34 | first = invalid(); | ||
| 35 | } | ||
| 36 | |||
| 37 | ~ThreadQueueList() { | ||
| 38 | for (int i = 0; i < NUM_QUEUES; ++i) | ||
| 39 | { | ||
| 40 | if (queues[i].data != NULL) | ||
| 41 | free(queues[i].data); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | // Only for debugging, returns priority level. | ||
| 46 | int contains(const IdType uid) { | ||
| 47 | for (int i = 0; i < NUM_QUEUES; ++i) | ||
| 48 | { | ||
| 49 | if (queues[i].data == NULL) | ||
| 50 | continue; | ||
| 51 | |||
| 52 | Queue *cur = &queues[i]; | ||
| 53 | for (int j = cur->first; j < cur->end; ++j) | ||
| 54 | { | ||
| 55 | if (cur->data[j] == uid) | ||
| 56 | return i; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | return -1; | ||
| 61 | } | ||
| 62 | |||
| 63 | inline IdType pop_first() { | ||
| 64 | Queue *cur = first; | ||
| 65 | while (cur != invalid()) | ||
| 66 | { | ||
| 67 | if (cur->end - cur->first > 0) | ||
| 68 | return cur->data[cur->first++]; | ||
| 69 | cur = cur->next; | ||
| 70 | } | ||
| 71 | |||
| 72 | //_dbg_assert_msg_(SCEKERNEL, false, "ThreadQueueList should not be empty."); | ||
| 73 | return 0; | ||
| 74 | } | ||
| 75 | |||
| 76 | inline IdType pop_first_better(u32 priority) { | ||
| 77 | Queue *cur = first; | ||
| 78 | Queue *stop = &queues[priority]; | ||
| 79 | while (cur < stop) | ||
| 80 | { | ||
| 81 | if (cur->end - cur->first > 0) | ||
| 82 | return cur->data[cur->first++]; | ||
| 83 | cur = cur->next; | ||
| 84 | } | ||
| 85 | |||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | inline void push_front(u32 priority, const IdType threadID) { | ||
| 90 | Queue *cur = &queues[priority]; | ||
| 91 | cur->data[--cur->first] = threadID; | ||
| 92 | if (cur->first == 0) | ||
| 93 | rebalance(priority); | ||
| 94 | } | ||
| 95 | |||
| 96 | inline void push_back(u32 priority, const IdType threadID) { | ||
| 97 | Queue *cur = &queues[priority]; | ||
| 98 | cur->data[cur->end++] = threadID; | ||
| 99 | if (cur->end == cur->capacity) | ||
| 100 | rebalance(priority); | ||
| 101 | } | ||
| 102 | |||
| 103 | inline void remove(u32 priority, const IdType threadID) { | ||
| 104 | Queue *cur = &queues[priority]; | ||
| 105 | //_dbg_assert_msg_(SCEKERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up."); | ||
| 106 | |||
| 107 | for (int i = cur->first; i < cur->end; ++i) | ||
| 108 | { | ||
| 109 | if (cur->data[i] == threadID) | ||
| 110 | { | ||
| 111 | int remaining = --cur->end - i; | ||
| 112 | if (remaining > 0) | ||
| 113 | memmove(&cur->data[i], &cur->data[i + 1], remaining * sizeof(IdType)); | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | // Wasn't there. | ||
| 119 | } | ||
| 120 | |||
| 121 | inline void rotate(u32 priority) { | ||
| 122 | Queue *cur = &queues[priority]; | ||
| 123 | //_dbg_assert_msg_(SCEKERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up."); | ||
| 124 | |||
| 125 | if (cur->end - cur->first > 1) | ||
| 126 | { | ||
| 127 | cur->data[cur->end++] = cur->data[cur->first++]; | ||
| 128 | if (cur->end == cur->capacity) | ||
| 129 | rebalance(priority); | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | inline void clear() { | ||
| 134 | for (int i = 0; i < NUM_QUEUES; ++i) | ||
| 135 | { | ||
| 136 | if (queues[i].data != NULL) | ||
| 137 | free(queues[i].data); | ||
| 138 | } | ||
| 139 | memset(queues, 0, sizeof(queues)); | ||
| 140 | first = invalid(); | ||
| 141 | } | ||
| 142 | |||
| 143 | inline bool empty(u32 priority) const { | ||
| 144 | const Queue *cur = &queues[priority]; | ||
| 145 | return cur->first == cur->end; | ||
| 146 | } | ||
| 147 | |||
| 148 | inline void prepare(u32 priority) { | ||
| 149 | Queue *cur = &queues[priority]; | ||
| 150 | if (cur->next == NULL) | ||
| 151 | link(priority, INITIAL_CAPACITY); | ||
| 152 | } | ||
| 153 | |||
| 154 | private: | ||
| 155 | Queue *invalid() const { | ||
| 156 | return (Queue *) -1; | ||
| 157 | } | ||
| 158 | |||
| 159 | void link(u32 priority, int size) { | ||
| 160 | //_dbg_assert_msg_(SCEKERNEL, queues[priority].data == NULL, "ThreadQueueList::Queue should only be initialized once."); | ||
| 161 | |||
| 162 | if (size <= INITIAL_CAPACITY) | ||
| 163 | size = INITIAL_CAPACITY; | ||
| 164 | else | ||
| 165 | { | ||
| 166 | int goal = size; | ||
| 167 | size = INITIAL_CAPACITY; | ||
| 168 | while (size < goal) | ||
| 169 | size *= 2; | ||
| 170 | } | ||
| 171 | Queue *cur = &queues[priority]; | ||
| 172 | cur->data = (IdType *) malloc(sizeof(IdType) * size); | ||
| 173 | cur->capacity = size; | ||
| 174 | cur->first = size / 2; | ||
| 175 | cur->end = size / 2; | ||
| 176 | |||
| 177 | for (int i = (int) priority - 1; i >= 0; --i) | ||
| 178 | { | ||
| 179 | if (queues[i].next != NULL) | ||
| 180 | { | ||
| 181 | cur->next = queues[i].next; | ||
| 182 | queues[i].next = cur; | ||
| 183 | return; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | cur->next = first; | ||
| 188 | first = cur; | ||
| 189 | } | ||
| 190 | |||
| 191 | void rebalance(u32 priority) { | ||
| 192 | Queue *cur = &queues[priority]; | ||
| 193 | int size = cur->end - cur->first; | ||
| 194 | if (size >= cur->capacity - 2) { | ||
| 195 | IdType *new_data = (IdType *)realloc(cur->data, cur->capacity * 2 * sizeof(IdType)); | ||
| 196 | if (new_data != NULL) { | ||
| 197 | cur->capacity *= 2; | ||
| 198 | cur->data = new_data; | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | int newFirst = (cur->capacity - size) / 2; | ||
| 203 | if (newFirst != cur->first) { | ||
| 204 | memmove(&cur->data[newFirst], &cur->data[cur->first], size * sizeof(IdType)); | ||
| 205 | cur->first = newFirst; | ||
| 206 | cur->end = newFirst + size; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | // The first queue that's ever been used. | ||
| 211 | Queue *first; | ||
| 212 | // The priority level queues of thread ids. | ||
| 213 | Queue queues[NUM_QUEUES]; | ||
| 214 | }; | ||
| 215 | |||
| 216 | } // namespace | ||