1 | #ifndef SEAD_HEAPMGR_H_ |
---|---|
2 | #define SEAD_HEAPMGR_H_ |
3 | |
4 | #include <container/seadPtrArray.h> |
5 | #include <heap/seadArena.h> |
6 | #include <heap/seadHeap.h> |
7 | #include <hostio/seadHostIONode.h> |
8 | #include <prim/seadDelegate.h> |
9 | #include <prim/seadSafeString.h> |
10 | #include <thread/seadAtomic.h> |
11 | #include <thread/seadCriticalSection.h> |
12 | #include <time/seadTickSpan.h> |
13 | |
14 | namespace sead |
15 | { |
16 | class HeapMgr : hostio::Node |
17 | { |
18 | struct AllocCallbackArg; |
19 | struct CreateCallbackArg; |
20 | struct DestroyCallbackArg; |
21 | struct FreeCallbackArg; |
22 | using IAllocCallback = IDelegate1<const AllocCallbackArg*>; |
23 | using ICreateCallback = IDelegate1<const CreateCallbackArg*>; |
24 | using IDestroyCallback = IDelegate1<const DestroyCallbackArg*>; |
25 | using IFreeCallback = IDelegate1<const FreeCallbackArg*>; |
26 | |
27 | public: |
28 | struct AllocFailedCallbackArg; |
29 | using IAllocFailedCallback = IDelegate1<const AllocFailedCallbackArg*>; |
30 | |
31 | HeapMgr(); |
32 | virtual ~HeapMgr() {} |
33 | |
34 | static void initialize(size_t size); |
35 | static void initializeImpl_(); |
36 | static void initialize(Arena* arena); |
37 | static void createRootHeap_(); |
38 | static void destroy(); |
39 | void initHostIO(); |
40 | |
41 | Heap* findContainHeap(const void* ptr) const; |
42 | static bool isContainedInAnyHeap(const void* ptr); |
43 | static void dumpTreeYAML(WriteStream& stream); |
44 | void setAllocFromNotSeadThreadHeap(Heap* heap); |
45 | static void removeFromFindContainHeapCache_(Heap* heap); |
46 | |
47 | Heap* findHeapByName(const SafeString& name, int index) const; |
48 | static Heap* findHeapByName_(Heap*, const SafeString&, int* index); |
49 | Heap* getCurrentHeap() const; |
50 | |
51 | static void removeRootHeap(Heap*); |
52 | |
53 | IAllocFailedCallback* setAllocFailedCallback(IAllocFailedCallback* callback); |
54 | IAllocFailedCallback* getAllocFailedCallback() { return mAllocFailedCallback; } |
55 | |
56 | static HeapMgr* instance() { return sInstancePtr; } |
57 | static s32 getRootHeapNum() { return sRootHeaps.size(); } |
58 | |
59 | static Heap* getRootHeap(s32 index) { return sRootHeaps[index]; } |
60 | |
61 | // TODO: these should be private |
62 | static Arena* sArena; |
63 | static HeapMgr sInstance; |
64 | static HeapMgr* sInstancePtr; |
65 | |
66 | using RootHeaps = FixedPtrArray<Heap, 4>; |
67 | using IndependentHeaps = FixedPtrArray<Heap, 4>; |
68 | |
69 | private: |
70 | friend class ScopedCurrentHeapSetter; |
71 | |
72 | /// Set the current heap to the specified heap and returns the previous "current heap". |
73 | Heap* setCurrentHeap_(Heap* heap); |
74 | |
75 | static Arena sDefaultArena; |
76 | static RootHeaps sRootHeaps; |
77 | static IndependentHeaps sIndependentHeaps; |
78 | static CriticalSection sHeapTreeLockCS; |
79 | static TickSpan sSleepSpanAtRemoveCacheFailure; |
80 | |
81 | /// fallback heap that is returned when getting the current heap outside of an sead::Thread |
82 | Heap* mAllocFromNotSeadThreadHeap = nullptr; |
83 | IAllocFailedCallback* mAllocFailedCallback = nullptr; |
84 | }; |
85 | |
86 | /// Sets the "current heap" to the specified heap and restores the previous "current heap" |
87 | /// when this goes out of scope. |
88 | class ScopedCurrentHeapSetter |
89 | { |
90 | public: |
91 | explicit ScopedCurrentHeapSetter(sead::Heap* heap) |
92 | { |
93 | if (heap) |
94 | setPreviousHeap_(HeapMgr::instance()->setCurrentHeap_(heap)); |
95 | else |
96 | setPreviousHeapToNone_(); |
97 | } |
98 | |
99 | ~ScopedCurrentHeapSetter() |
100 | { |
101 | if (hasPreviousHeap_()) |
102 | HeapMgr::instance()->setCurrentHeap_(getPreviousHeap_()); |
103 | } |
104 | |
105 | protected: |
106 | /// @warning Only call this if hasPreviousHeap returns true. |
107 | Heap* getPreviousHeap_() const { return reinterpret_cast<Heap*>(mPreviousHeap); } |
108 | void setPreviousHeap_(Heap* heap) { mPreviousHeap = reinterpret_cast<uintptr_t>(heap); } |
109 | void setPreviousHeapToNone_() { mPreviousHeap = 1; } |
110 | bool hasPreviousHeap_() const |
111 | { |
112 | // XXX: We cannot just do `mPreviousHeap != 1` because that results in different codegen. |
113 | // The cast smells like implementation defined behavior, but 1 should not be a valid |
114 | // pointer on any platform that we support. In practice, this will work correctly. |
115 | return reinterpret_cast<Heap*>(mPreviousHeap) != reinterpret_cast<Heap*>(1); |
116 | } |
117 | |
118 | uintptr_t mPreviousHeap; |
119 | }; |
120 | |
121 | class FindContainHeapCache |
122 | { |
123 | public: |
124 | FindContainHeapCache(); |
125 | |
126 | bool tryRemoveHeap(Heap* heap); |
127 | Heap* tryAddHeap() |
128 | { |
129 | mHeap |= 1; |
130 | return reinterpret_cast<Heap*>(mHeap.load()); |
131 | } |
132 | Heap* getHeap() const { return reinterpret_cast<Heap*>(mHeap.load()); } |
133 | void setHeap(Heap* heap) { mHeap.storeNonAtomic(uintptr_t(heap)); } |
134 | void resetHeap() { mHeap.fetchAnd(~1LL); } |
135 | |
136 | Atomic<uintptr_t> mHeap; |
137 | }; |
138 | |
139 | } // namespace sead |
140 | |
141 | #endif // SEAD_HEAPMGR_H_ |
142 |