mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	added initial kernel/thread modules
This commit is contained in:
		
							parent
							
								
									daf7a7880a
								
							
						
					
					
						commit
						6b264518a5
					
				
					 7 changed files with 548 additions and 0 deletions
				
			
		
							
								
								
									
										142
									
								
								src/core/hle/kernel/kernel.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								src/core/hle/kernel/kernel.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,142 @@ | |||
| // Copyright 2014 Citra Emulator Project / PPSSPP Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Refer to the license.txt file included.  
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <string.h> | ||||
| 
 | ||||
| #include "common/common.h" | ||||
| 
 | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
| 
 | ||||
| KernelObjectPool g_kernel_objects; | ||||
| 
 | ||||
| void __KernelInit() { | ||||
|     __KernelThreadingInit(); | ||||
| } | ||||
| 
 | ||||
| void __KernelShutdown() { | ||||
|     __KernelThreadingShutdown(); | ||||
| } | ||||
| 
 | ||||
| KernelObjectPool::KernelObjectPool() { | ||||
|     memset(occupied, 0, sizeof(bool) * MAX_COUNT); | ||||
|     next_id = INITIAL_NEXT_ID; | ||||
| } | ||||
| 
 | ||||
| UID KernelObjectPool::Create(KernelObject *obj, int range_bottom, int range_top) { | ||||
|     if (range_top > MAX_COUNT) { | ||||
|         range_top = MAX_COUNT; | ||||
|     } | ||||
|     if (next_id >= range_bottom && next_id < range_top) { | ||||
|         range_bottom = next_id++; | ||||
|     } | ||||
|     for (int i = range_bottom; i < range_top; i++) { | ||||
|         if (!occupied[i]) { | ||||
|             occupied[i] = true; | ||||
|             pool[i] = obj; | ||||
|             pool[i]->uid = i + HANDLE_OFFSET; | ||||
|             return i + HANDLE_OFFSET; | ||||
|         } | ||||
|     } | ||||
|     ERROR_LOG(HLE, "Unable to allocate kernel object, too many objects slots in use."); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| bool KernelObjectPool::IsValid(UID handle) | ||||
| { | ||||
|     int index = handle - HANDLE_OFFSET; | ||||
|     if (index < 0) | ||||
|         return false; | ||||
|     if (index >= MAX_COUNT) | ||||
|         return false; | ||||
| 
 | ||||
|     return occupied[index]; | ||||
| } | ||||
| 
 | ||||
| void KernelObjectPool::Clear() | ||||
| { | ||||
|     for (int i = 0; i < MAX_COUNT; i++) | ||||
|     { | ||||
|         //brutally clear everything, no validation
 | ||||
|         if (occupied[i]) | ||||
|             delete pool[i]; | ||||
|         occupied[i] = false; | ||||
|     } | ||||
|     memset(pool, 0, sizeof(KernelObject*)*MAX_COUNT); | ||||
|     next_id = INITIAL_NEXT_ID; | ||||
| } | ||||
| 
 | ||||
| KernelObject *&KernelObjectPool::operator [](UID handle) | ||||
| { | ||||
|     _dbg_assert_msg_(KERNEL, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ"); | ||||
|     return pool[handle - HANDLE_OFFSET]; | ||||
| } | ||||
| 
 | ||||
| void KernelObjectPool::List() { | ||||
|     for (int i = 0; i < MAX_COUNT; i++) { | ||||
|         if (occupied[i]) { | ||||
|             if (pool[i]) { | ||||
|                 INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName(),  | ||||
|                     pool[i]->GetName()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int KernelObjectPool::GetCount() | ||||
| { | ||||
|     int count = 0; | ||||
|     for (int i = 0; i < MAX_COUNT; i++) | ||||
|     { | ||||
|         if (occupied[i]) | ||||
|             count++; | ||||
|     } | ||||
|     return count; | ||||
| } | ||||
| 
 | ||||
| KernelObject *KernelObjectPool::CreateByIDType(int type) { | ||||
|     // Used for save states.  This is ugly, but what other way is there?
 | ||||
|     switch (type) { | ||||
|     //case SCE_KERNEL_TMID_Alarm:
 | ||||
|     //    return __KernelAlarmObject();
 | ||||
|     //case SCE_KERNEL_TMID_EventFlag:
 | ||||
|     //    return __KernelEventFlagObject();
 | ||||
|     //case SCE_KERNEL_TMID_Mbox:
 | ||||
|     //    return __KernelMbxObject();
 | ||||
|     //case SCE_KERNEL_TMID_Fpl:
 | ||||
|     //    return __KernelMemoryFPLObject();
 | ||||
|     //case SCE_KERNEL_TMID_Vpl:
 | ||||
|     //    return __KernelMemoryVPLObject();
 | ||||
|     //case PPSSPP_KERNEL_TMID_PMB:
 | ||||
|     //    return __KernelMemoryPMBObject();
 | ||||
|     //case PPSSPP_KERNEL_TMID_Module:
 | ||||
|     //    return __KernelModuleObject();
 | ||||
|     //case SCE_KERNEL_TMID_Mpipe:
 | ||||
|     //    return __KernelMsgPipeObject();
 | ||||
|     //case SCE_KERNEL_TMID_Mutex:
 | ||||
|     //    return __KernelMutexObject();
 | ||||
|     //case SCE_KERNEL_TMID_LwMutex:
 | ||||
|     //    return __KernelLwMutexObject();
 | ||||
|     //case SCE_KERNEL_TMID_Semaphore:
 | ||||
|     //    return __KernelSemaphoreObject();
 | ||||
|     //case SCE_KERNEL_TMID_Callback:
 | ||||
|     //    return __KernelCallbackObject();
 | ||||
|     //case SCE_KERNEL_TMID_Thread:
 | ||||
|     //    return __KernelThreadObject();
 | ||||
|     //case SCE_KERNEL_TMID_VTimer:
 | ||||
|     //    return __KernelVTimerObject();
 | ||||
|     //case SCE_KERNEL_TMID_Tlspl:
 | ||||
|     //    return __KernelTlsplObject();
 | ||||
|     //case PPSSPP_KERNEL_TMID_File:
 | ||||
|     //    return __KernelFileNodeObject();
 | ||||
|     //case PPSSPP_KERNEL_TMID_DirList:
 | ||||
|     //    return __KernelDirListingObject();
 | ||||
| 
 | ||||
|     default: | ||||
|         ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type); | ||||
|         return NULL; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										121
									
								
								src/core/hle/kernel/kernel.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/core/hle/kernel/kernel.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,121 @@ | |||
| // Copyright 2014 Citra Emulator Project / PPSSPP Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Refer to the license.txt file included.  
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| typedef u32 UID; | ||||
| 
 | ||||
| class KernelObjectPool; | ||||
| 
 | ||||
| class KernelObject { | ||||
|     friend class KernelObjectPool; | ||||
|     u32 uid; | ||||
| public: | ||||
|     virtual ~KernelObject() {} | ||||
|     UID GetUID() const { return uid; } | ||||
|     virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; } | ||||
|     virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; } | ||||
|     virtual int GetIDType() const = 0; | ||||
|     //virtual void GetQuickInfo(char *ptr, int size);
 | ||||
| }; | ||||
| 
 | ||||
| class KernelObjectPool { | ||||
| public: | ||||
|     KernelObjectPool(); | ||||
|     ~KernelObjectPool() {} | ||||
| 
 | ||||
|     // Allocates a UID within the range and inserts the object into the map.
 | ||||
|     UID Create(KernelObject *obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF); | ||||
| 
 | ||||
|     static KernelObject *CreateByIDType(int type); | ||||
| 
 | ||||
|     template <class T> | ||||
|     u32 Destroy(UID handle) { | ||||
|         u32 error; | ||||
|         if (Get<T>(handle, error)) { | ||||
|             occupied[handle - handleOffset] = false; | ||||
|             delete pool[handle - handleOffset]; | ||||
|         } | ||||
|         return error; | ||||
|     }; | ||||
| 
 | ||||
|     bool IsValid(UID handle); | ||||
| 
 | ||||
|     template <class T> | ||||
|     T* Get(UID handle, u32& outError) { | ||||
|         if (handle < handleOffset || handle >= handleOffset + maxCount || !occupied[handle - handleOffset]) { | ||||
|             // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP
 | ||||
|             if (handle != 0 && (u32)handle != 0x80020001) { | ||||
|                 WARN_LOG(SCEKERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); | ||||
|             } | ||||
|             outError = T::GetMissingErrorCode(); | ||||
|             return 0; | ||||
|         } else { | ||||
|             // Previously we had a dynamic_cast here, but since RTTI was disabled traditionally,
 | ||||
|             // it just acted as a static case and everything worked. This means that we will never
 | ||||
|             // see the Wrong type object error below, but we'll just have to live with that danger.
 | ||||
|             T* t = static_cast<T*>(pool[handle - handleOffset]); | ||||
|             if (t == 0 || t->GetIDType() != T::GetStaticIDType()) { | ||||
|                 WARN_LOG(SCEKERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle); | ||||
|                 outError = T::GetMissingErrorCode(); | ||||
|                 return 0; | ||||
|             } | ||||
|             outError = SCE_KERNEL_ERROR_OK; | ||||
|             return t; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // ONLY use this when you know the handle is valid.
 | ||||
|     template <class T> | ||||
|     T *GetFast(UID handle) { | ||||
|         const UID realHandle = handle - handleOffset; | ||||
|         _dbg_assert_(SCEKERNEL, realHandle >= 0 && realHandle < maxCount && occupied[realHandle]); | ||||
|         return static_cast<T *>(pool[realHandle]); | ||||
|     } | ||||
| 
 | ||||
|     template <class T, typename ArgT> | ||||
|     void Iterate(bool func(T *, ArgT), ArgT arg) { | ||||
|         int type = T::GetStaticIDType(); | ||||
|         for (int i = 0; i < maxCount; i++) | ||||
|         { | ||||
|             if (!occupied[i]) | ||||
|                 continue; | ||||
|             T *t = static_cast<T *>(pool[i]); | ||||
|             if (t->GetIDType() == type) { | ||||
|                 if (!func(t, arg)) | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     bool GetIDType(UID handle, int *type) const { | ||||
|         if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) ||  | ||||
|             !occupied[handle - HANDLE_OFFSET]) { | ||||
|             ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); | ||||
|             return false; | ||||
|         } | ||||
|         KernelObject *t = pool[handle - HANDLE_OFFSET]; | ||||
|         *type = t->GetIDType(); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     KernelObject *&operator [](UID handle); | ||||
|     void List(); | ||||
|     void Clear(); | ||||
|     int GetCount(); | ||||
| 
 | ||||
| private: | ||||
|     enum { | ||||
|         MAX_COUNT       = 0x1000, | ||||
|         HANDLE_OFFSET   = 0x100, | ||||
|         INITIAL_NEXT_ID = 0x10, | ||||
|     }; | ||||
|     KernelObject *pool[MAX_COUNT]; | ||||
|     bool occupied[MAX_COUNT]; | ||||
|     int next_id; | ||||
| }; | ||||
| 
 | ||||
| extern KernelObjectPool g_kernel_objects; | ||||
							
								
								
									
										228
									
								
								src/core/hle/kernel/thread.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								src/core/hle/kernel/thread.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,228 @@ | |||
| // Copyright 2014 Citra Emulator Project / PPSSPP Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Refer to the license.txt file included.  
 | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| #include <list> | ||||
| #include <vector> | ||||
| #include <map> | ||||
| #include <string> | ||||
| 
 | ||||
| #include "common/common.h" | ||||
| 
 | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
| 
 | ||||
| // Real CTR struct, don't change the fields.
 | ||||
| struct NativeThread { | ||||
|     //u32         Pointer to vtable
 | ||||
|     //u32         Reference count
 | ||||
|     //KProcess*   Process the thread belongs to (virtual address)
 | ||||
|     //u32         Thread id
 | ||||
|     //u32*        ptr = *(KThread+0x8C) - 0xB0
 | ||||
|     //u32*        End-address of the page for this thread allocated in the 0xFF4XX000 region. Thus, 
 | ||||
|     //      if the beginning of this mapped page is 0xFF401000, this ptr would be 0xFF402000.
 | ||||
|     //KThread*    Previous ? (virtual address)
 | ||||
|     //KThread*    Next ? (virtual address)
 | ||||
| }; | ||||
| 
 | ||||
| struct ThreadWaitInfo { | ||||
|     u32 wait_value; | ||||
|     u32 timeout_ptr; | ||||
| }; | ||||
| 
 | ||||
| class Thread : public KernelObject { | ||||
| public: | ||||
|     /*const char *GetName() { return nt.name; }*/ | ||||
|     const char *GetTypeName() { return "Thread"; } | ||||
|     //void GetQuickInfo(char *ptr, int size)
 | ||||
|     //{
 | ||||
|     //    sprintf(ptr, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )",
 | ||||
|     //        context.pc, context.r[13], // 13 is stack pointer
 | ||||
|     //        (nt.status & THREADSTATUS_RUNNING) ? "RUN" : "",
 | ||||
|     //        (nt.status & THREADSTATUS_READY) ? "READY" : "",
 | ||||
|     //        (nt.status & THREADSTATUS_WAIT) ? "WAIT" : "",
 | ||||
|     //        (nt.status & THREADSTATUS_SUSPEND) ? "SUSPEND" : "",
 | ||||
|     //        (nt.status & THREADSTATUS_DORMANT) ? "DORMANT" : "",
 | ||||
|     //        (nt.status & THREADSTATUS_DEAD) ? "DEAD" : "",
 | ||||
|     //        nt.waitType,
 | ||||
|     //        nt.waitID,
 | ||||
|     //        waitInfo.waitValue);
 | ||||
|     //}
 | ||||
| 
 | ||||
|     //static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; }
 | ||||
|     //static int GetStaticIDType() { return SCE_KERNEL_TMID_Thread; }
 | ||||
|     //int GetIDType() const { return SCE_KERNEL_TMID_Thread; }
 | ||||
| 
 | ||||
|     //bool AllocateStack(u32 &stack_size) {
 | ||||
|     //    FreeStack();
 | ||||
| 
 | ||||
|     //    bool fromTop = (nt.attr & PSP_THREAD_ATTR_LOW_STACK) == 0;
 | ||||
|     //    if (nt.attr & PSP_THREAD_ATTR_KERNEL)
 | ||||
|     //    {
 | ||||
|     //        // Allocate stacks for kernel threads (idle) in kernel RAM
 | ||||
|     //        currentStack.start = kernelMemory.Alloc(stack_size, fromTop, (std::string("stack/") + nt.name).c_str());
 | ||||
|     //    }
 | ||||
|     //    else
 | ||||
|     //    {
 | ||||
|     //        currentStack.start = userMemory.Alloc(stack_size, fromTop, (std::string("stack/") + nt.name).c_str());
 | ||||
|     //    }
 | ||||
|     //    if (currentStack.start == (u32)-1)
 | ||||
|     //    {
 | ||||
|     //        currentStack.start = 0;
 | ||||
|     //        nt.initialStack = 0;
 | ||||
|     //        ERROR_LOG(KERNEL, "Failed to allocate stack for thread");
 | ||||
|     //        return false;
 | ||||
|     //    }
 | ||||
| 
 | ||||
|     //    nt.initialStack = currentStack.start;
 | ||||
|     //    nt.stack_size = stack_size;
 | ||||
|     //    return true;
 | ||||
|     //}
 | ||||
| 
 | ||||
|     //bool FillStack() {
 | ||||
|     //    // Fill the stack.
 | ||||
|     //    if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) {
 | ||||
|     //        Memory::Memset(currentStack.start, 0xFF, nt.stack_size);
 | ||||
|     //    }
 | ||||
|     //    context.r[MIPS_REG_SP] = currentStack.start + nt.stack_size;
 | ||||
|     //    currentStack.end = context.r[MIPS_REG_SP];
 | ||||
|     //    // The k0 section is 256 bytes at the top of the stack.
 | ||||
|     //    context.r[MIPS_REG_SP] -= 256;
 | ||||
|     //    context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP];
 | ||||
|     //    u32 k0 = context.r[MIPS_REG_K0];
 | ||||
|     //    Memory::Memset(k0, 0, 0x100);
 | ||||
|     //    Memory::Write_U32(GetUID(), k0 + 0xc0);
 | ||||
|     //    Memory::Write_U32(nt.initialStack, k0 + 0xc8);
 | ||||
|     //    Memory::Write_U32(0xffffffff, k0 + 0xf8);
 | ||||
|     //    Memory::Write_U32(0xffffffff, k0 + 0xfc);
 | ||||
|     //    // After k0 comes the arguments, which is done by sceKernelStartThread().
 | ||||
| 
 | ||||
|     //    Memory::Write_U32(GetUID(), nt.initialStack);
 | ||||
|     //    return true;
 | ||||
|     //}
 | ||||
| 
 | ||||
|     //void FreeStack() {
 | ||||
|     //    if (currentStack.start != 0) {
 | ||||
|     //        DEBUG_LOG(KERNEL, "Freeing thread stack %s", nt.name);
 | ||||
| 
 | ||||
|     //        if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) {
 | ||||
|     //            Memory::Memset(nt.initialStack, 0, nt.stack_size);
 | ||||
|     //        }
 | ||||
| 
 | ||||
|     //        if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
 | ||||
|     //            kernelMemory.Free(currentStack.start);
 | ||||
|     //        }
 | ||||
|     //        else {
 | ||||
|     //            userMemory.Free(currentStack.start);
 | ||||
|     //        }
 | ||||
|     //        currentStack.start = 0;
 | ||||
|     //    }
 | ||||
|     //}
 | ||||
| 
 | ||||
|     //bool PushExtendedStack(u32 size) {
 | ||||
|     //    u32 stack = userMemory.Alloc(size, true, (std::string("extended/") + nt.name).c_str());
 | ||||
|     //    if (stack == (u32)-1)
 | ||||
|     //        return false;
 | ||||
| 
 | ||||
|     //    pushed_stacks.push_back(currentStack);
 | ||||
|     //    currentStack.start = stack;
 | ||||
|     //    currentStack.end = stack + size;
 | ||||
|     //    nt.initialStack = currentStack.start;
 | ||||
|     //    nt.stack_size = currentStack.end - currentStack.start;
 | ||||
| 
 | ||||
|     //    // We still drop the threadID at the bottom and fill it, but there's no k0.
 | ||||
|     //    Memory::Memset(currentStack.start, 0xFF, nt.stack_size);
 | ||||
|     //    Memory::Write_U32(GetUID(), nt.initialStack);
 | ||||
|     //    return true;
 | ||||
|     //}
 | ||||
| 
 | ||||
|     //bool PopExtendedStack() {
 | ||||
|     //    if (pushed_stacks.size() == 0) {
 | ||||
|     //        return false;
 | ||||
|     //    }
 | ||||
|     //    userMemory.Free(currentStack.start);
 | ||||
|     //    currentStack = pushed_stacks.back();
 | ||||
|     //    pushed_stacks.pop_back();
 | ||||
|     //    nt.initialStack = currentStack.start;
 | ||||
|     //    nt.stack_size = currentStack.end - currentStack.start;
 | ||||
|     //    return true;
 | ||||
|     //}
 | ||||
| 
 | ||||
|     Thread() { | ||||
|         currentStack.start = 0; | ||||
|     } | ||||
| 
 | ||||
|     // Can't use a destructor since savestates will call that too.
 | ||||
|     //void Cleanup() {
 | ||||
|     //    // Callbacks are automatically deleted when their owning thread is deleted.
 | ||||
|     //    for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it)
 | ||||
|     //        kernelObjects.Destroy<Callback>(*it);
 | ||||
| 
 | ||||
|     //    if (pushed_stacks.size() != 0)
 | ||||
|     //    {
 | ||||
|     //        WARN_LOG(KERNEL, "Thread ended within an extended stack");
 | ||||
|     //        for (size_t i = 0; i < pushed_stacks.size(); ++i)
 | ||||
|     //            userMemory.Free(pushed_stacks[i].start);
 | ||||
|     //    }
 | ||||
|     //    FreeStack();
 | ||||
|     //}
 | ||||
| 
 | ||||
|     void setReturnValue(u32 retval); | ||||
|     void setReturnValue(u64 retval); | ||||
|     void resumeFromWait(); | ||||
|     //bool isWaitingFor(WaitType type, int id);
 | ||||
|     //int getWaitID(WaitType type);
 | ||||
|     ThreadWaitInfo getWaitInfo(); | ||||
| 
 | ||||
|     // Utils
 | ||||
|     //inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
 | ||||
|     //inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
 | ||||
|     //inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
 | ||||
|     //inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
 | ||||
|     //inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
 | ||||
| 
 | ||||
|     NativeThread nt; | ||||
| 
 | ||||
|     ThreadWaitInfo waitInfo; | ||||
|     UID moduleId; | ||||
| 
 | ||||
|     bool isProcessingCallbacks; | ||||
|     u32 currentMipscallId; | ||||
|     UID currentCallbackId; | ||||
| 
 | ||||
|     ThreadContext context; | ||||
| 
 | ||||
|     std::vector<UID> callbacks; | ||||
| 
 | ||||
|     std::list<u32> pending_calls; | ||||
| 
 | ||||
|     struct StackInfo { | ||||
|         u32 start; | ||||
|         u32 end; | ||||
|     }; | ||||
|     // This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse.
 | ||||
|     // These are stacks that aren't "active" right now, but will pop off once the func returns.
 | ||||
|     std::vector<StackInfo> pushed_stacks; | ||||
| 
 | ||||
|     StackInfo currentStack; | ||||
| 
 | ||||
|     // For thread end.
 | ||||
|     std::vector<UID> waiting_threads; | ||||
|     // Key is the callback id it was for, or if no callback, the thread id.
 | ||||
|     std::map<UID, u64> paused_waits; | ||||
| }; | ||||
| 
 | ||||
| void __KernelThreadingInit() { | ||||
| } | ||||
| 
 | ||||
| void __KernelThreadingShutdown() { | ||||
| } | ||||
| 
 | ||||
| //const char *__KernelGetThreadName(UID threadID);
 | ||||
| //
 | ||||
| //void __KernelSaveContext(ThreadContext *ctx);
 | ||||
| //void __KernelLoadContext(ThreadContext *ctx);
 | ||||
| 
 | ||||
| //void __KernelSwitchContext(Thread *target, const char *reason);
 | ||||
							
								
								
									
										36
									
								
								src/core/hle/kernel/thread.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/core/hle/kernel/thread.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| // Copyright 2014 Citra Emulator Project / PPSSPP Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Refer to the license.txt file included.  
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| enum ThreadStatus { | ||||
|     THREADSTATUS_RUNNING = 1, | ||||
|     THREADSTATUS_READY = 2, | ||||
|     THREADSTATUS_WAIT = 4, | ||||
|     THREADSTATUS_SUSPEND = 8, | ||||
|     THREADSTATUS_DORMANT = 16, | ||||
|     THREADSTATUS_DEAD = 32, | ||||
| 
 | ||||
|     THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND | ||||
| }; | ||||
| 
 | ||||
| struct ThreadContext { | ||||
|     void reset(); | ||||
| 
 | ||||
|     u32 reg[16]; | ||||
|     u32 cpsr; | ||||
|     u32 pc; | ||||
| }; | ||||
| 
 | ||||
| void __KernelThreadingInit(); | ||||
| void __KernelThreadingShutdown(); | ||||
| 
 | ||||
| //const char *__KernelGetThreadName(SceUID threadID);
 | ||||
| //
 | ||||
| //void __KernelSaveContext(ThreadContext *ctx);
 | ||||
| //void __KernelLoadContext(ThreadContext *ctx);
 | ||||
| 
 | ||||
| //void __KernelSwitchContext(Thread *target, const char *reason);
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue