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
14namespace sead
15{
16class 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
27public:
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
69private:
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.
88class ScopedCurrentHeapSetter
89{
90public:
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
105protected:
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
121class FindContainHeapCache
122{
123public:
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