summaryrefslogtreecommitdiff
path: root/src/KingSystem/Utils/Thread/TaskThread.h
blob: 8d2cb559612913f452ceb52195ee5218dd8b4398 (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
#pragma once

#include <prim/seadRuntimeTypeInfo.h>
#include <prim/seadTypedBitFlag.h>
#include <thread/seadAtomic.h>
#include <thread/seadThread.h>
#include "KingSystem/Utils/Thread/Event.h"
#include "KingSystem/Utils/Types.h"

namespace ksys::util {

class Task;
class TaskQueueBase;
class TaskQueueLock;

class TaskThread : public sead::Thread {
    SEAD_RTTI_BASE(TaskThread)
public:
    enum Message {
        cMessage_QueueUpdated = 1,
        cMessage_Pause = 2,
        cMessage_Resume = 3,
    };

    struct InitArg {
        /// Number of lanes if a new queue is to be created.
        /// Only used if queue is nullptr.
        u16 num_lanes;
        /// Number of tasks to process in a row before yielding. Can be zero to disable the limit.
        u32 batch_size;
        /// Heap that will be used to allocate a new queue if necessary.
        /// Only used if queue is nullptr.
        sead::Heap* heap;
        /// Task queue. If null, a new queue will be created and owned by this thread.
        TaskQueueBase* queue;
    };
    KSYS_CHECK_SIZE_NX150(InitArg, 0x18);

    TaskThread(const sead::SafeString& name, sead::Heap* heap, s32 priority,
               sead::MessageQueue::BlockType block_type, sead::MessageQueue::Element quit_msg,
               s32 stack_size, s32 message_queue_size);
    ~TaskThread() override;

    bool init(const InitArg& arg);

    s32 getNumActiveTasks() const;

    void waitForQueueToEmpty();
    void cancelTasks(u8 id);
    void clearQueue();
    void lock(TaskQueueLock* lock);

    bool isActiveAndReceivedQueueUpdateMsg() const;
    bool isPaused() const;
    bool receivedQueueUpdatedMsg() const;

    void pause();
    void pauseAndWaitForAck();
    void resume();
    void resumeAndWaitForAck();

    bool isBusyProcessingTask() const;
    bool isLookingForTask() const;

    bool receivedPauseMsg() const;
    bool receivedResumeMsg() const;
    bool receivedQuitMsg() const;

    void cancelCurrentTask();

    TaskQueueBase* getTaskQueue() const { return mTaskQueue; }

protected:
    friend class TaskQueueBase;

    enum class Flag {
        _1 = 0x1,
        _2 = 0x2,
        _4 = 0x4,
        Paused = 0x8,
        /// The task queue is *not* owned by this TaskThread.
        DoesNotOwnTaskQueue = 0x10,
        /// A batch is being processed.
        IsActive = 0x20,
        /// This thread is looking for a task to process.
        IsLookingForTask = 0x40,
        /// A task is being processed.
        IsBusyProcessingTask = 0x80,
    };

    void calc_(sead::MessageQueue::Element msg) override;

    sead::TypedBitFlag<Flag, u8> mFlags = [] {
        decltype(mFlags) flags;
        flags.set(Flag::_2);
        flags.set(Flag::_4);
        return flags;
    }();
    Task* mTask = nullptr;
    s32 mBatchSize = 0;
    s32 mNumRemainingTasksInBatch = 0;
    sead::Atomic<Message> mPauseResumeMsg = cMessage_Resume;
    Event mPauseResumeEvent;
    Event mTaskProcessedEvent;
    TaskQueueBase* mTaskQueue = nullptr;
};
KSYS_CHECK_SIZE_NX150(TaskThread, 0x1a0);

}  // namespace ksys::util