summaryrefslogtreecommitdiff
path: root/src/KingSystem/ActorSystem/actBaseProcHandle.h
blob: 68964e78a079142d9cc32465e3fe02830d1afdc6 (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
#pragma once

#include <basis/seadTypes.h>
#include <container/seadSafeArray.h>
#include <thread/seadAtomic.h>
#include <thread/seadCriticalSection.h>
#include "KingSystem/ActorSystem/actBaseProcCreateTask.h"
#include "KingSystem/Utils/Types.h"

namespace ksys::act {

class BaseProc;
class BaseProcCreateTask;
class BaseProcUnit;

class BaseProcHandle {
public:
    BaseProcHandle();
    ~BaseProcHandle() { deleteProc(); }

    BaseProcHandle(const BaseProcHandle&) = delete;
    BaseProcHandle(BaseProcHandle&&) = delete;
    auto operator=(const BaseProcHandle&) = delete;
    auto operator=(BaseProcHandle&&) = delete;

    bool isProcReady() const;
    bool hasProcCreationFailed() const;
    bool isProcCreationCancelled() const;
    bool isAllocatedOrFailed() const { return mUnit || mFailed; }

    void deleteProcIfFailed();
    void deleteProc();

    BaseProc* getProc() const;
    BaseProc* releaseProc();
    BaseProc* releaseAndWakeProc();
    BaseProcCreateTask* getCreateTask() const;
    BaseProcUnit* getUnit() const { return mUnit; }
    bool allocUnit();

    bool hasFailed() const { return mFailed; }
    void setFailed(bool failed) { mFailed = failed; }

private:
    BaseProcUnit* mUnit = nullptr;
    bool mFailed = false;
};
KSYS_CHECK_SIZE_NX150(BaseProcHandle, 0x10);

/// Glue code between a BaseProcHandle and its associated BaseProc.
/// Used while a BaseProc is being created.
class BaseProcUnit {
public:
    enum class Status : u32 {
        Unused = 0,
        Initializing = 1,
        Ready = 2,
        NoProc = 3,
        _4 = 4,
        Cancelled = 5,
    };

    BaseProcUnit() = default;
    ~BaseProcUnit();

    BaseProcUnit(const BaseProcUnit&) = delete;
    BaseProcUnit(BaseProcUnit&&) = delete;
    auto operator=(const BaseProcUnit&) = delete;
    auto operator=(BaseProcUnit&&) = delete;

    bool deleteProc(u32, BaseProcHandle* handle);
    bool setProc(BaseProc* proc);
    void unlinkProc(BaseProc* proc);
    void cleanUp(BaseProc* proc, bool is_cancellation);
    bool isParentHandleDefault() const;

    Status getStatus() const { return mStatus; }
    BaseProc* getProc() const { return mProc; }
    BaseProcCreateTask& getCreateTask() { return mCreateTask; }
    const BaseProcCreateTask& getCreateTask() const { return mCreateTask; }
    sead::CriticalSection& getCS() { return mCS; }

    bool isReady() const { return mStatus == Status::Ready; }

    bool compareExchangeHandle(BaseProcHandle* expected, BaseProcHandle* desired) {
        return mHandle.compareExchange(expected, desired);
    }

    void setInitializingStatus() { mStatus = Status::Initializing; }

private:
    void reset();

    BaseProcHandle* getHandle() const { return mHandle.load(); }

    sead::Atomic<Status> mStatus = Status::Unused;
    sead::Atomic<BaseProcHandle*> mHandle;
    BaseProc* mProc{};
    BaseProcCreateTask mCreateTask{nullptr};
    sead::CriticalSection mCS;
};
KSYS_CHECK_SIZE_NX150(BaseProcUnit, 0x2f0);

struct BaseProcUnitPool {
    struct Impl {
        sead::SafeArray<BaseProcUnit, 256> array;
    } units{};
    int next = 0;

    BaseProcUnit* alloc(BaseProcHandle* handle);
};

extern BaseProcUnitPool gUnitPool;
extern BaseProcHandle gDummyProcHandle;

}  // namespace ksys::act