mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge branch 'threading'
This commit is contained in:
		
						commit
						32c314c992
					
				
					 44 changed files with 1559 additions and 193 deletions
				
			
		|  | @ -190,6 +190,7 @@ | |||
|     <ClInclude Include="swap.h" /> | ||||
|     <ClInclude Include="symbols.h" /> | ||||
|     <ClInclude Include="thread.h" /> | ||||
|     <ClInclude Include="thread_queue_list.h" /> | ||||
|     <ClInclude Include="thunk.h" /> | ||||
|     <ClInclude Include="timer.h" /> | ||||
|     <ClInclude Include="utf8.h" /> | ||||
|  |  | |||
|  | @ -40,6 +40,7 @@ | |||
|     <ClInclude Include="symbols.h" /> | ||||
|     <ClInclude Include="scm_rev.h" /> | ||||
|     <ClInclude Include="bit_field.h" /> | ||||
|     <ClInclude Include="thread_queue_list.h" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClCompile Include="break_points.cpp" /> | ||||
|  |  | |||
|  | @ -22,6 +22,11 @@ template<> struct CompileTimeAssert<true> {}; | |||
| #define b32(x)  (b16(x) | (b16(x) >>16) ) | ||||
| #define ROUND_UP_POW2(x)    (b32(x - 1) + 1) | ||||
| 
 | ||||
| #define MIN(a, b)   ((a)<(b)?(a):(b)) | ||||
| #define MAX(a, b)   ((a)>(b)?(a):(b)) | ||||
| 
 | ||||
| #define CLAMP(x, min, max)  (((x) > max) ? max : (((x) < min) ? min : (x))) | ||||
| 
 | ||||
| #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) | ||||
| 
 | ||||
| #ifndef _WIN32 | ||||
|  |  | |||
|  | @ -5,6 +5,8 @@ | |||
| #ifndef _LOG_H_ | ||||
| #define _LOG_H_ | ||||
| 
 | ||||
| #define LOGGING | ||||
| 
 | ||||
| #define    NOTICE_LEVEL  1  // VERY important information that is NOT errors. Like startup and OSReports.
 | ||||
| #define    ERROR_LEVEL   2  // Critical errors 
 | ||||
| #define    WARNING_LEVEL 3  // Something is suspicious.
 | ||||
|  | @ -53,7 +55,7 @@ enum LOG_TYPE { | |||
|     WII_IPC_ES, | ||||
|     WII_IPC_FILEIO, | ||||
|     WII_IPC_HID, | ||||
|     WII_IPC_HLE, | ||||
|     KERNEL, | ||||
|     SVC, | ||||
|     NDMA, | ||||
|     HLE, | ||||
|  |  | |||
|  | @ -60,13 +60,13 @@ LogManager::LogManager() | |||
|     m_Log[LogTypes::LOADER]             = new LogContainer("Loader",            "Loader"); | ||||
|     m_Log[LogTypes::FILESYS]            = new LogContainer("FileSys",           "File System"); | ||||
|     m_Log[LogTypes::WII_IPC_HID]        = new LogContainer("WII_IPC_HID",       "WII IPC HID"); | ||||
|     m_Log[LogTypes::WII_IPC_HLE]        = new LogContainer("WII_IPC_HLE",       "WII IPC HLE"); | ||||
|     m_Log[LogTypes::KERNEL]             = new LogContainer("KERNEL",            "KERNEL HLE"); | ||||
|     m_Log[LogTypes::WII_IPC_DVD]        = new LogContainer("WII_IPC_DVD",       "WII IPC DVD"); | ||||
|     m_Log[LogTypes::WII_IPC_ES]         = new LogContainer("WII_IPC_ES",        "WII IPC ES"); | ||||
|     m_Log[LogTypes::WII_IPC_FILEIO]     = new LogContainer("WII_IPC_FILEIO",    "WII IPC FILEIO"); | ||||
|     m_Log[LogTypes::RENDER]             = new LogContainer("RENDER",            "RENDER"); | ||||
|     m_Log[LogTypes::LCD]                = new LogContainer("LCD",               "LCD"); | ||||
|     m_Log[LogTypes::SVC]                = new LogContainer("SVC",               "Supervisor Call"); | ||||
|     m_Log[LogTypes::SVC]                = new LogContainer("SVC",               "Supervisor Call HLE"); | ||||
|     m_Log[LogTypes::NDMA]               = new LogContainer("NDMA",              "NDMA"); | ||||
|     m_Log[LogTypes::HLE]                = new LogContainer("HLE",               "High Level Emulation"); | ||||
|     m_Log[LogTypes::HW]                 = new LogContainer("HW",                "Hardware"); | ||||
|  |  | |||
							
								
								
									
										216
									
								
								src/common/thread_queue_list.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								src/common/thread_queue_list.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,216 @@ | |||
| // Copyright 2014 Citra Emulator Project / PPSSPP Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Refer to the license.txt file included.  
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "common/common.h" | ||||
| 
 | ||||
| namespace Common { | ||||
| 
 | ||||
| template<class IdType> | ||||
| struct ThreadQueueList { | ||||
|     // Number of queues (number of priority levels starting at 0.)
 | ||||
|     static const int NUM_QUEUES = 128; | ||||
|      | ||||
|     // Initial number of threads a single queue can handle.
 | ||||
|     static const int INITIAL_CAPACITY = 32; | ||||
| 
 | ||||
|     struct Queue { | ||||
|         // Next ever-been-used queue (worse priority.)
 | ||||
|         Queue *next; | ||||
|         // First valid item in data.
 | ||||
|         int first; | ||||
|         // One after last valid item in data.
 | ||||
|         int end; | ||||
|         // A too-large array with room on the front and end.
 | ||||
|         IdType *data; | ||||
|         // Size of data array.
 | ||||
|         int capacity; | ||||
|     }; | ||||
| 
 | ||||
|     ThreadQueueList() { | ||||
|         memset(queues, 0, sizeof(queues)); | ||||
|         first = invalid(); | ||||
|     } | ||||
| 
 | ||||
|     ~ThreadQueueList() { | ||||
|         for (int i = 0; i < NUM_QUEUES; ++i) | ||||
|         { | ||||
|             if (queues[i].data != NULL) | ||||
|                 free(queues[i].data); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Only for debugging, returns priority level.
 | ||||
|     int contains(const IdType uid) { | ||||
|         for (int i = 0; i < NUM_QUEUES; ++i) | ||||
|         { | ||||
|             if (queues[i].data == NULL) | ||||
|                 continue; | ||||
| 
 | ||||
|             Queue *cur = &queues[i]; | ||||
|             for (int j = cur->first; j < cur->end; ++j) | ||||
|             { | ||||
|                 if (cur->data[j] == uid) | ||||
|                     return i; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     inline IdType pop_first() { | ||||
|         Queue *cur = first; | ||||
|         while (cur != invalid()) | ||||
|         { | ||||
|             if (cur->end - cur->first > 0) | ||||
|                 return cur->data[cur->first++]; | ||||
|             cur = cur->next; | ||||
|         } | ||||
| 
 | ||||
|         //_dbg_assert_msg_(SCEKERNEL, false, "ThreadQueueList should not be empty.");
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     inline IdType pop_first_better(u32 priority) { | ||||
|         Queue *cur = first; | ||||
|         Queue *stop = &queues[priority]; | ||||
|         while (cur < stop) | ||||
|         { | ||||
|             if (cur->end - cur->first > 0) | ||||
|                 return cur->data[cur->first++]; | ||||
|             cur = cur->next; | ||||
|         } | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     inline void push_front(u32 priority, const IdType threadID) { | ||||
|         Queue *cur = &queues[priority]; | ||||
|         cur->data[--cur->first] = threadID; | ||||
|         if (cur->first == 0) | ||||
|             rebalance(priority); | ||||
|     } | ||||
| 
 | ||||
|     inline void push_back(u32 priority, const IdType threadID) { | ||||
|         Queue *cur = &queues[priority]; | ||||
|         cur->data[cur->end++] = threadID; | ||||
|         if (cur->end == cur->capacity) | ||||
|             rebalance(priority); | ||||
|     } | ||||
| 
 | ||||
|     inline void remove(u32 priority, const IdType threadID) { | ||||
|         Queue *cur = &queues[priority]; | ||||
|         //_dbg_assert_msg_(SCEKERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
 | ||||
| 
 | ||||
|         for (int i = cur->first; i < cur->end; ++i) | ||||
|         { | ||||
|             if (cur->data[i] == threadID) | ||||
|             { | ||||
|                 int remaining = --cur->end - i; | ||||
|                 if (remaining > 0) | ||||
|                     memmove(&cur->data[i], &cur->data[i + 1], remaining * sizeof(IdType)); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Wasn't there.
 | ||||
|     } | ||||
| 
 | ||||
|     inline void rotate(u32 priority) { | ||||
|         Queue *cur = &queues[priority]; | ||||
|         //_dbg_assert_msg_(SCEKERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
 | ||||
| 
 | ||||
|         if (cur->end - cur->first > 1) | ||||
|         { | ||||
|             cur->data[cur->end++] = cur->data[cur->first++]; | ||||
|             if (cur->end == cur->capacity) | ||||
|                 rebalance(priority); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     inline void clear() { | ||||
|         for (int i = 0; i < NUM_QUEUES; ++i) | ||||
|         { | ||||
|             if (queues[i].data != NULL) | ||||
|                 free(queues[i].data); | ||||
|         } | ||||
|         memset(queues, 0, sizeof(queues)); | ||||
|         first = invalid(); | ||||
|     } | ||||
| 
 | ||||
|     inline bool empty(u32 priority) const { | ||||
|         const Queue *cur = &queues[priority]; | ||||
|         return cur->first == cur->end; | ||||
|     } | ||||
| 
 | ||||
|     inline void prepare(u32 priority) { | ||||
|         Queue *cur = &queues[priority]; | ||||
|         if (cur->next == NULL) | ||||
|             link(priority, INITIAL_CAPACITY); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     Queue *invalid() const { | ||||
|         return (Queue *) -1; | ||||
|     } | ||||
| 
 | ||||
|     void link(u32 priority, int size) { | ||||
|         //_dbg_assert_msg_(SCEKERNEL, queues[priority].data == NULL, "ThreadQueueList::Queue should only be initialized once.");
 | ||||
| 
 | ||||
|         if (size <= INITIAL_CAPACITY) | ||||
|             size = INITIAL_CAPACITY; | ||||
|         else | ||||
|         { | ||||
|             int goal = size; | ||||
|             size = INITIAL_CAPACITY; | ||||
|             while (size < goal) | ||||
|                 size *= 2; | ||||
|         } | ||||
|         Queue *cur = &queues[priority]; | ||||
|         cur->data = (IdType *) malloc(sizeof(IdType) * size); | ||||
|         cur->capacity = size; | ||||
|         cur->first = size / 2; | ||||
|         cur->end = size / 2; | ||||
| 
 | ||||
|         for (int i = (int) priority - 1; i >= 0; --i) | ||||
|         { | ||||
|             if (queues[i].next != NULL) | ||||
|             { | ||||
|                 cur->next = queues[i].next; | ||||
|                 queues[i].next = cur; | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         cur->next = first; | ||||
|         first = cur; | ||||
|     } | ||||
| 
 | ||||
|     void rebalance(u32 priority) { | ||||
|         Queue *cur = &queues[priority]; | ||||
|         int size = cur->end - cur->first; | ||||
|         if (size >= cur->capacity - 2)  { | ||||
|             IdType *new_data = (IdType *)realloc(cur->data, cur->capacity * 2 * sizeof(IdType)); | ||||
|             if (new_data != NULL)  { | ||||
|                 cur->capacity *= 2; | ||||
|                 cur->data = new_data; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         int newFirst = (cur->capacity - size) / 2; | ||||
|         if (newFirst != cur->first) { | ||||
|             memmove(&cur->data[newFirst], &cur->data[cur->first], size * sizeof(IdType)); | ||||
|             cur->first = newFirst; | ||||
|             cur->end = newFirst + size; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // The first queue that's ever been used.
 | ||||
|     Queue *first; | ||||
|     // The priority level queues of thread ids.
 | ||||
|     Queue queues[NUM_QUEUES]; | ||||
| }; | ||||
| 
 | ||||
| } // namespace
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue