aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/hle/kernel/thread.h
blob: 51290975e387ea748a547c5190afb49154cc94ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright 2014 Citra Emulator Project / PPSSPP Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <string>
#include <vector>

#include "common/common_types.h"

#include "core/core.h"
#include "core/mem_map.h"

#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"

enum ThreadPriority {
    THREADPRIO_HIGHEST      = 0,    ///< Highest thread priority
    THREADPRIO_DEFAULT      = 16,   ///< Default thread priority for userland apps
    THREADPRIO_LOW          = 31,   ///< Low range of thread priority for userland apps
    THREADPRIO_LOWEST       = 63,   ///< Thread priority max checked by svcCreateThread
};

enum ThreadProcessorId {
    THREADPROCESSORID_0     = 0xFFFFFFFE,   ///< Enables core appcode
    THREADPROCESSORID_1     = 0xFFFFFFFD,   ///< Enables core syscore
    THREADPROCESSORID_ALL   = 0xFFFFFFFC,   ///< Enables both cores
};

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
};

enum WaitType {
    WAITTYPE_NONE,
    WAITTYPE_SLEEP,
    WAITTYPE_SEMA,
    WAITTYPE_EVENT,
    WAITTYPE_THREADEND,
    WAITTYPE_MUTEX,
    WAITTYPE_SYNCH,
    WAITTYPE_ARB,
    WAITTYPE_TIMER,
};

namespace Kernel {

class Thread : public Kernel::Object {
public:
    std::string GetName() const override { return name; }
    std::string GetTypeName() const override { return "Thread"; }

    static const HandleType HANDLE_TYPE = HandleType::Thread;
    HandleType GetHandleType() const override { return HANDLE_TYPE; }

    inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; }
    inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; }
    inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; }
    inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
    inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
    inline bool IsIdle() const { return idle; }

    ResultVal<bool> WaitSynchronization() override;

    Core::ThreadContext context;

    u32 thread_id;

    u32 status;
    u32 entry_point;
    u32 stack_top;
    u32 stack_size;

    s32 initial_priority;
    s32 current_priority;

    s32 processor_id;

    WaitType wait_type;
    Handle wait_handle;
    VAddr wait_address;

    std::vector<Handle> waiting_threads;

    std::string name;

    /// Whether this thread is intended to never actually be executed, i.e. always idle
    bool idle = false;

private:
    // TODO(yuriks) Temporary until the creation logic can be moved into a static function
    friend Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority,
            s32 processor_id, u32 stack_top, int stack_size);

    Thread() = default;
};

/// Creates a new thread - wrapper for external user
Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id,
    u32 stack_top, int stack_size=Kernel::DEFAULT_STACK_SIZE);

/// Sets up the primary application thread
Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);

/// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule();

/// Stops the current thread
ResultCode StopThread(Handle thread, const char* reason);

/**
 * Retrieves the ID of the specified thread handle
 * @param thread_id Will contain the output thread id
 * @param handle Handle to the thread we want
 * @return Whether the function was successful or not
 */
ResultCode GetThreadId(u32* thread_id, Handle handle);

/// Resumes a thread from waiting by marking it as "ready"
void ResumeThreadFromWait(Handle handle);

/// Arbitrate the highest priority thread that is waiting
Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address);

/// Arbitrate all threads currently waiting...
void ArbitrateAllThreads(u32 arbiter, u32 address);

/// Gets the current thread
Thread* GetCurrentThread();

/// Gets the current thread handle
Handle GetCurrentThreadHandle();

/**
 * Puts the current thread in the wait state for the given type
 * @param wait_type Type of wait
 * @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread
 */
void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle());

/**
 * Schedules an event to wake up the specified thread after the specified delay.
 * @param handle The thread handle.
 * @param nanoseconds The time this thread will be allowed to sleep for.
 */
void WakeThreadAfterDelay(Handle handle, s64 nanoseconds);

/**
 * Puts the current thread in the wait state for the given type
 * @param wait_type Type of wait
 * @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread
 * @param wait_address Arbitration address used to resume from wait
 */
void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_address);

/// Put current thread in a wait state - on WaitSynchronization
void WaitThread_Synchronization();

/// Get the priority of the thread specified by handle
ResultVal<u32> GetThreadPriority(const Handle handle);

/// Set the priority of the thread specified by handle
ResultCode SetThreadPriority(Handle handle, s32 priority);

/**
 * Sets up the idle thread, this is a thread that is intended to never execute instructions,
 * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue
 * and will try to yield on every call.
 * @returns The handle of the idle thread
 */
Handle SetupIdleThread();

/// Whether the current thread is an idle thread
bool IsIdleThread(Handle thread);

/// Initialize threading
void ThreadingInit();

/// Shutdown threading
void ThreadingShutdown();

} // namespace