1 // Copyright 2009 Sony Online Entertainment, all rights reserved.
2 // Original author: Jeff Petersen
3 #ifndef SOEUTIL_MEMORY_H
4 #define SOEUTIL_MEMORY_H
6 #include "ThreadLocal.h"
10 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
11 // The basic idea is to allow hooking of the SoeUtil memory allocations that occur. The application call
12 // SoeUtil::SetMemoryHandler to point SoeUtil to use the specified MemoryHandler derived class. All allocations
13 // by SoeUtil that occur then get routed to the handler.
15 // Normally SetMemoryHandler only changes the handler for the current thread-context. Applications can use
16 // SetGlobalMemoryHandler to change the MemoryHandler used for all thread contexts. Thread-specific handlers take
17 // precedence over the global handler, which takes precedence over going directly to the built-in heap. By default
18 // there are no handlers installed and everything goes directly to the built-in heap.
20 // Not all memory activity inside of SoeUtil routes through the MemoryHandler. In particular, the DeleteAll
21 // convenience function on embedded containers, the algorithm ListDeleteAll, and the RefCounted::RefDestroySelf
22 // function do not go through the handler to free things, but instead always simply call 'delete' since most of the
23 // time these are allocations that were done by the application directly. Serialization and Unserialization of
24 // embedded containers also do not go through the memory handler, for similar reasons.
26 // The application is free to also hook through the SoeUtil memory handler by doing allocations via the
27 // SoeUtil::Alloc and SoeUtil::Free functions.
29 // Warning: It is not safe to delete an object via its base-class pointer by explicitly calling the destructor and
30 // then calling SoeUtil::Free on the pointer to free the memory. The base-class pointer is not guaranteed to point
31 // to the beginning of the originally allocated memory-block in situations where multiple-inheritance has been used.
32 // This is partly the reason why SoeUtil makes no attempt to have DeleteAll and Release functionality go through its
33 // custom allocator. The only safe way to destruct an object via a pointer to it base class is via the 'delete'
34 // operator. If these things must be routed to a custom allocator, then overloading the new/delete operator on a
35 // per class basis (or the global new/delete operator) would be required.
36 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
46 // if this handler is set as the global handler for all thread contexts, then these functions need to be thread-safe.
47 virtual void *OnAlloc(int bytes
) = 0;
48 virtual void OnFree(void *p
) = 0;
51 // These two calls set/get the memory handler for the global-context
52 // It is not safe to change the global handler if other threads are currently using the heap/SoeUtil, since they may get mismatched alloc/free calls
53 void SetGlobalMemoryHandler(MemoryHandler
*handler
);
54 MemoryHandler
*GetGlobalMemoryHandler();
56 // These two calls set/get the memory handler for this thread-context
57 void SetMemoryHandler(MemoryHandler
*handler
);
58 MemoryHandler
*GetMemoryHandler();
60 void *Alloc(int bytes
); // returns NULL on failure
64 class MemoryHandlerGuard
67 MemoryHandlerGuard(MemoryHandler
*handler
)
69 m_oldHandler
= GetMemoryHandler();
70 SetMemoryHandler(handler
);
75 SetMemoryHandler(m_oldHandler
);
79 MemoryHandler
*m_oldHandler
;
82 // deriving from this base class will cause derived classes to route through the SoeUtil::Alloc and SoeUtil::Free functions
86 static void *operator new(size_t size
) { void *p
= Alloc((int)size
); if (p
== NULL
) { throw std::bad_alloc(); } return p
; }
87 static void *operator new[](size_t size
) { void *p
= Alloc((int)size
); if (p
== NULL
) { throw std::bad_alloc(); } return p
; }
88 static void *operator new(size_t size
, const std::nothrow_t
&) throw() { return Alloc((int)size
); }
89 static void *operator new(size_t /*size*/, void *p
) throw() { return p
; }
90 static void *operator new[](size_t size
, const std::nothrow_t
&) throw() { return Alloc((int)size
); }
91 static void *operator new[](size_t /*size*/, void *p
) throw() { return p
; }
93 static void operator delete(void *p
) throw() { Free(p
); }
94 static void operator delete[](void *p
) throw() { Free(p
); }
95 static void operator delete(void *p
, const std::nothrow_t
&) throw() { Free(p
); }
96 static void operator delete(void * /*p*/, void *) throw() {}
97 static void operator delete[] (void *p
, const std::nothrow_t
&) throw() { Free(p
); }
98 static void operator delete[] (void * /*p*/, void *) throw() {}
102 ////////////////////////////////////////////////////////////////////////////////////////////////////////
103 // inline implementation
104 ////////////////////////////////////////////////////////////////////////////////////////////////////////
106 namespace SystemInternal
108 inline MemoryHandler
*&GlobalMemoryHandler()
110 static MemoryHandler
*s_memoryHandler
= NULL
;
111 return s_memoryHandler
;
114 inline SoeUtil::ThreadLocalPointer
<MemoryHandler
> &GlobalTlsMemoryHandler()
116 static SoeUtil::ThreadLocalPointer
<MemoryHandler
> s_tls_memoryHandler
;
117 return s_tls_memoryHandler
;
121 inline void *Alloc(int bytes
)
123 if (SystemInternal::GlobalTlsMemoryHandler().Get() != NULL
)
125 return SystemInternal::GlobalTlsMemoryHandler().Get()->OnAlloc(bytes
);
127 else if (SystemInternal::GlobalMemoryHandler() != NULL
)
129 return SystemInternal::GlobalMemoryHandler()->OnAlloc(bytes
);
133 return new(std::nothrow
) byte
[bytes
];
137 inline void Free(void *p
)
141 if (SystemInternal::GlobalTlsMemoryHandler().Get() != NULL
)
143 SystemInternal::GlobalTlsMemoryHandler().Get()->OnFree(p
);
145 else if (SystemInternal::GlobalMemoryHandler() != NULL
)
147 SystemInternal::GlobalMemoryHandler()->OnFree(p
);
156 inline void SetGlobalMemoryHandler(MemoryHandler
*handler
)
158 SystemInternal::GlobalMemoryHandler() = handler
;
161 inline MemoryHandler
*GetGlobalMemoryHandler()
163 return SystemInternal::GlobalMemoryHandler();
166 inline void SetMemoryHandler(MemoryHandler
*handler
)
168 SystemInternal::GlobalTlsMemoryHandler().Set(handler
);
171 inline MemoryHandler
*GetMemoryHandler()
173 return SystemInternal::GlobalTlsMemoryHandler().Get();