mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	CoreTiming: Reworked CoreTiming (#3119)
* CoreTiming: New CoreTiming; Add Test for CoreTiming
This commit is contained in:
		
							parent
							
								
									b7cf793814
								
							
						
					
					
						commit
						e9a95b2e7d
					
				
					 18 changed files with 678 additions and 593 deletions
				
			
		|  | @ -76,6 +76,7 @@ set(HEADERS | |||
|             telemetry.h | ||||
|             thread.h | ||||
|             thread_queue_list.h | ||||
|             threadsafe_queue.h | ||||
|             timer.h | ||||
|             vector_math.h | ||||
|             ) | ||||
|  |  | |||
							
								
								
									
										122
									
								
								src/common/threadsafe_queue.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								src/common/threadsafe_queue.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,122 @@ | |||
| // Copyright 2010 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2+
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| // a simple lockless thread-safe,
 | ||||
| // single reader, single writer queue
 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <atomic> | ||||
| #include <cstddef> | ||||
| #include <mutex> | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| namespace Common { | ||||
| template <typename T, bool NeedSize = true> | ||||
| class SPSCQueue { | ||||
| public: | ||||
|     SPSCQueue() : size(0) { | ||||
|         write_ptr = read_ptr = new ElementPtr(); | ||||
|     } | ||||
|     ~SPSCQueue() { | ||||
|         // this will empty out the whole queue
 | ||||
|         delete read_ptr; | ||||
|     } | ||||
| 
 | ||||
|     u32 Size() const { | ||||
|         static_assert(NeedSize, "using Size() on FifoQueue without NeedSize"); | ||||
|         return size.load(); | ||||
|     } | ||||
| 
 | ||||
|     bool Empty() const { | ||||
|         return !read_ptr->next.load(); | ||||
|     } | ||||
|     T& Front() const { | ||||
|         return read_ptr->current; | ||||
|     } | ||||
|     template <typename Arg> | ||||
|     void Push(Arg&& t) { | ||||
|         // create the element, add it to the queue
 | ||||
|         write_ptr->current = std::forward<Arg>(t); | ||||
|         // set the next pointer to a new element ptr
 | ||||
|         // then advance the write pointer
 | ||||
|         ElementPtr* new_ptr = new ElementPtr(); | ||||
|         write_ptr->next.store(new_ptr, std::memory_order_release); | ||||
|         write_ptr = new_ptr; | ||||
|         if (NeedSize) | ||||
|             size++; | ||||
|     } | ||||
| 
 | ||||
|     void Pop() { | ||||
|         if (NeedSize) | ||||
|             size--; | ||||
|         ElementPtr* tmpptr = read_ptr; | ||||
|         // advance the read pointer
 | ||||
|         read_ptr = tmpptr->next.load(); | ||||
|         // set the next element to nullptr to stop the recursive deletion
 | ||||
|         tmpptr->next.store(nullptr); | ||||
|         delete tmpptr; // this also deletes the element
 | ||||
|     } | ||||
| 
 | ||||
|     bool Pop(T& t) { | ||||
|         if (Empty()) | ||||
|             return false; | ||||
| 
 | ||||
|         if (NeedSize) | ||||
|             size--; | ||||
| 
 | ||||
|         ElementPtr* tmpptr = read_ptr; | ||||
|         read_ptr = tmpptr->next.load(std::memory_order_acquire); | ||||
|         t = std::move(tmpptr->current); | ||||
|         tmpptr->next.store(nullptr); | ||||
|         delete tmpptr; | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     // not thread-safe
 | ||||
|     void Clear() { | ||||
|         size.store(0); | ||||
|         delete read_ptr; | ||||
|         write_ptr = read_ptr = new ElementPtr(); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     // stores a pointer to element
 | ||||
|     // and a pointer to the next ElementPtr
 | ||||
|     class ElementPtr { | ||||
|     public: | ||||
|         ElementPtr() : next(nullptr) {} | ||||
|         ~ElementPtr() { | ||||
|             ElementPtr* next_ptr = next.load(); | ||||
| 
 | ||||
|             if (next_ptr) | ||||
|                 delete next_ptr; | ||||
|         } | ||||
| 
 | ||||
|         T current; | ||||
|         std::atomic<ElementPtr*> next; | ||||
|     }; | ||||
| 
 | ||||
|     ElementPtr* write_ptr; | ||||
|     ElementPtr* read_ptr; | ||||
|     std::atomic<u32> size; | ||||
| }; | ||||
| 
 | ||||
| // a simple thread-safe,
 | ||||
| // single reader, multiple writer queue
 | ||||
| 
 | ||||
| template <typename T, bool NeedSize = true> | ||||
| class MPSCQueue : public SPSCQueue<T, NeedSize> { | ||||
| public: | ||||
|     template <typename Arg> | ||||
|     void Push(Arg&& t) { | ||||
|         std::lock_guard<std::mutex> lock(write_lock); | ||||
|         SPSCQueue<T, NeedSize>::Push(t); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::mutex write_lock; | ||||
| }; | ||||
| } // namespace Common
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue