1 // Copyright (C) 2003 Dolphin Project. 2 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, version 2.0 or later versions. 6 7 // This program is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 // GNU General Public License 2.0 for more details. 11 12 // A copy of the GPL 2.0 should have been included with the program. 13 // If not, see http://www.gnu.org/licenses/ 14 15 // Official SVN repository and contact information can be found at 16 // http://code.google.com/p/dolphin-emu/ 17 18 #pragma once 19 20 #include <cstring> 21 #include "Common/MemoryUtil.h" 22 #include "Common/Serialize/Serializer.h" 23 24 // STL-look-a-like interface, but name is mixed case to distinguish it clearly from the 25 // real STL classes. 26 27 // Not fully featured, no safety checking yet. Add features as needed. 28 29 template <class T, int N> 30 class FixedSizeQueue { 31 public: FixedSizeQueue()32 FixedSizeQueue() { 33 // Allocate aligned memory, just because. 34 //int sizeInBytes = N * sizeof(T); 35 //storage_ = (T *)AllocateMemoryPages(sizeInBytes); 36 storage_ = new T[N]; 37 clear(); 38 } 39 ~FixedSizeQueue()40 ~FixedSizeQueue() { 41 // FreeMemoryPages((void *)storage_, N * sizeof(T)); 42 delete [] storage_; 43 } 44 clear()45 void clear() { 46 head_ = 0; 47 tail_ = 0; 48 count_ = 0; 49 // Not entirely necessary, but keeps things clean. 50 memset(storage_, 0, sizeof(T) * N); 51 } 52 push(T t)53 void push(T t) { 54 storage_[tail_] = t; 55 tail_++; 56 if (tail_ == N) 57 tail_ = 0; 58 count_++; 59 } 60 61 // Gets pointers to write to directly. pushPointers(size_t size,T ** dest1,size_t * sz1,T ** dest2,size_t * sz2)62 void pushPointers(size_t size, T **dest1, size_t *sz1, T **dest2, size_t *sz2) { 63 if (tail_ + (int)size < N) { 64 *dest1 = &storage_[tail_]; 65 *sz1 = size; 66 tail_ += (int)size; 67 if (tail_ == N) tail_ = 0; 68 *dest2 = 0; 69 *sz2 = 0; 70 } else { 71 *dest1 = &storage_[tail_]; 72 *sz1 = N - tail_; 73 tail_ = (int)(size - *sz1); 74 *dest2 = &storage_[0]; 75 *sz2 = tail_; 76 } 77 count_ += (int)size; 78 } 79 popPointers(size_t size,const T ** src1,size_t * sz1,const T ** src2,size_t * sz2)80 void popPointers(size_t size, const T **src1, size_t *sz1, const T **src2, size_t *sz2) { 81 if ((int)size > count_) size = count_; 82 83 if (head_ + size < N) { 84 *src1 = &storage_[head_]; 85 *sz1 = size; 86 head_ += (int)size; 87 if (head_ == N) head_ = 0; 88 *src2 = 0; 89 *sz2 = 0; 90 } else { 91 *src1 = &storage_[head_]; 92 *sz1 = N - head_; 93 head_ = (int)(size - *sz1); 94 *src2 = &storage_[0]; 95 *sz2 = head_; 96 } 97 count_ -= (int)size; 98 } 99 pop()100 void pop() { 101 head_++; 102 if (head_ == N) 103 head_ = 0; 104 count_--; 105 } 106 107 /* 108 void push_array(const T *ptr, size_t num) { 109 // TODO: memcpy 110 for (size_t i = 0; i < num; i++) { 111 push(ptr[i]); 112 } 113 } 114 115 void pop_array(T *outptr, size_t num) { 116 for (size_t i = 0; i < num; i++) { 117 outptr[i] = front(); 118 pop(); 119 } 120 }*/ 121 pop_front()122 T pop_front() { 123 const T &temp = storage_[head_]; 124 pop(); 125 return temp; 126 } 127 front()128 T &front() { return storage_[head_]; } 129 front()130 const T &front() const { return storage_[head_]; } 131 size()132 size_t size() const { 133 return count_; 134 } 135 capacity()136 size_t capacity() const { 137 return N; 138 } 139 room()140 int room() const { 141 return N - count_; 142 } 143 empty()144 bool empty() { 145 return count_ == 0; 146 } 147 DoState(PointerWrap & p)148 void DoState(PointerWrap &p) { 149 int size = N; 150 Do(p, size); 151 if (size != N) 152 { 153 ERROR_LOG(COMMON, "Savestate failure: Incompatible queue size."); 154 return; 155 } 156 DoArray<T>(p, storage_, N); 157 Do(p, head_); 158 Do(p, tail_); 159 Do(p, count_); 160 p.DoMarker("FixedSizeQueue"); 161 } 162 163 private: 164 T *storage_; 165 int head_; 166 int tail_; 167 int count_; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future. 168 169 // Make copy constructor private for now. 170 FixedSizeQueue(FixedSizeQueue &other); 171 FixedSizeQueue& operator=(const FixedSizeQueue &other); 172 }; 173 174 175 // I'm not sure this is 100% safe but it might be "Good Enough" :) 176 // TODO: Use this, maybe make it safer first by using proper atomics 177 // instead of volatile 178 template<class T, int blockSize, int numBlocks> 179 class LockFreeBlockQueue { 180 public: LockFreeBlockQueue()181 LockFreeBlockQueue() { 182 curReadBlock = 0; 183 curWriteBlock = 0; 184 for (size_t i = 0; i < numBlocks; i++) { 185 blocks[i] = new T[blockSize]; 186 } 187 } ~LockFreeBlockQueue()188 ~LockFreeBlockQueue() { 189 for (size_t i = 0; i < numBlocks; i++) { 190 delete [] blocks[i]; 191 } 192 } 193 194 // Write to the returned pointer then call EndPush to finish the push. BeginPush()195 T *BeginPush() { 196 return blocks[curWriteBlock]; 197 } EndPush()198 void EndPush() { 199 curWriteBlock++; 200 if (curWriteBlock == NUM_BLOCKS) 201 curWriteBlock = 0; 202 } 203 CanPush()204 bool CanPush() { 205 int nextBlock = curWriteBlock + 1; 206 if (nextBlock == NUM_BLOCKS) nextBlock = 0; 207 return nextBlock != curReadBlock; 208 } 209 CanPop()210 bool CanPop() { return curReadBlock != curWriteBlock; } 211 212 // Read from the returned pointer then call EndPush to finish the pop. BeginPop()213 T *BeginPop() { 214 return blocks[curReadBlock]; 215 } EndPop()216 void EndPop() { 217 curReadBlock++; 218 if (curReadBlock == NUM_BLOCKS) 219 curReadBlock = 0; 220 } 221 222 private: 223 enum { NUM_BLOCKS = 16 }; 224 T **blocks[NUM_BLOCKS]; 225 226 volatile int curReadBlock; 227 volatile int curWriteBlock; 228 }; 229 230