1 // The MIT License (MIT)
2 //
3 // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
4 //
5 // 	Permission is hereby granted, free of charge, to any person obtaining a copy
6 // 	of this software and associated documentation files (the "Software"), to deal
7 // 	in the Software without restriction, including without limitation the rights
8 // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // 	copies of the Software, and to permit persons to whom the Software is
10 // 	furnished to do so, subject to the following conditions:
11 //
12 //  The above copyright notice and this permission notice shall be included in
13 // 	all copies or substantial portions of the Software.
14 //
15 // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // 	THE SOFTWARE.
22 #include <MTConfig.h>
23 #include <MTAppInterop.h>
24 #include <MTTools.h>
25 
26 #include <stdio.h>
27 
28 #if MT_SSE_INTRINSICS_SUPPORTED
29 #include <xmmintrin.h>
30 #else
31 #include <malloc.h>
32 #endif
33 
34 
35 
36 
37 #if MT_PLATFORM_WINDOWS
38 
39 inline void ThrowException()
40 {
41 	__debugbreak();
42 }
43 
44 #elif MT_PLATFORM_POSIX || MT_PLATFORM_OSX
45 
46 #include<signal.h>
47 inline void ThrowException()
48 {
49 	raise(SIGTRAP);
50 	// force access violation error
51 	char* pBadAddr = (char*)0x0;
52 	*pBadAddr = 0;
53 }
54 
55 #else
56 
57 #error Platform is not supported!
58 
59 #endif
60 
61 
62 
63 namespace MT
64 {
65 
66 	void* Memory::Alloc(size_t size, size_t align)
67 	{
68 		void* p = nullptr;
69 #if MT_SSE_INTRINSICS_SUPPORTED
70 		p = _mm_malloc(size, align);
71 #else
72 		p = memalign(size, align);
73 #endif
74 		MT_ASSERT(p, "Can't allocate memory");
75 		return p;
76 	}
77 
78 	void Memory::Free(void* p)
79 	{
80 #if MT_SSE_INTRINSICS_SUPPORTED
81 		_mm_free(p);
82 #else
83 		free(p);
84 #endif
85 	}
86 
87 	Memory::StackDesc Memory::AllocStack(size_t size)
88 	{
89 		StackDesc desc;
90 
91 #if MT_PLATFORM_WINDOWS
92 
93 		MW_SYSTEM_INFO systemInfo;
94 		GetSystemInfo(&systemInfo);
95 
96 		int pageSize = (int)systemInfo.dwPageSize;
97 		int pagesCount = (int)size / pageSize;
98 
99 		//need additional page for stack guard
100 		if ((size % pageSize) > 0)
101 		{
102 			pagesCount++;
103 		}
104 
105 		//protected guard page
106 		pagesCount++;
107 
108 		desc.stackMemoryBytesCount = pagesCount * pageSize;
109 		desc.stackMemory = (char*)VirtualAlloc(NULL, desc.stackMemoryBytesCount, MW_MEM_COMMIT, MW_PAGE_READWRITE);
110 		MT_ASSERT(desc.stackMemory != NULL, "Can't allocate memory");
111 
112 		desc.stackBottom = desc.stackMemory + pageSize;
113 		desc.stackTop = desc.stackMemory + desc.stackMemoryBytesCount;
114 
115 		MW_DWORD oldProtect = 0;
116 		MW_BOOL res = VirtualProtect(desc.stackMemory, pageSize, MW_PAGE_NOACCESS, &oldProtect);
117 		MT_USED_IN_ASSERT(res);
118 		MT_ASSERT(res != 0, "Can't protect memory");
119 
120 #elif MT_PLATFORM_POSIX || MT_PLATFORM_OSX
121 
122 		int pageSize = sysconf(_SC_PAGE_SIZE);
123 		int pagesCount = size / pageSize;
124 
125 		//need additional page for stack tail
126 		if ((size % pageSize) > 0)
127 		{
128 			pagesCount++;
129 		}
130 
131 		//protected guard page
132 		pagesCount++;
133 
134 		desc.stackMemoryBytesCount = pagesCount * pageSize;
135 		desc.stackMemory = (char*)mmap(NULL, desc.stackMemoryBytesCount, PROT_READ | PROT_WRITE,  MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
136 
137 		MT_ASSERT((void *)desc.stackMemory != (void *)-1, "Can't allocate memory");
138 
139 		desc.stackBottom = desc.stackMemory + pageSize;
140 		desc.stackTop = desc.stackMemory + desc.stackMemoryBytesCount;
141 
142 		int res = mprotect(desc.stackMemory, pageSize, PROT_NONE);
143 		MT_USED_IN_ASSERT(res);
144 		MT_ASSERT(res == 0, "Can't protect memory");
145 #else
146 		#error Platform is not supported!
147 #endif
148 
149 		return desc;
150 	}
151 
152 	void Memory::FreeStack(const Memory::StackDesc & desc)
153 	{
154 #if MT_PLATFORM_WINDOWS
155 
156 		int res = VirtualFree(desc.stackMemory, 0, MW_MEM_RELEASE);
157 		MT_USED_IN_ASSERT(res);
158 		MT_ASSERT(res != 0, "Can't free memory");
159 
160 #elif MT_PLATFORM_POSIX || MT_PLATFORM_OSX
161 
162 		int res = munmap(desc.stackMemory, desc.stackMemoryBytesCount);
163 		MT_USED_IN_ASSERT(res);
164 		MT_ASSERT(res == 0, "Can't free memory");
165 #else
166 		#error Platform is not supported!
167 #endif
168 	}
169 
170 	void Diagnostic::ReportAssert(const char* condition, const char* description, const char* sourceFile, int sourceLine)
171 	{
172 		printf("Assertion failed : %s. File %s, line %d. Condition %s\n", description, sourceFile, sourceLine, condition);
173 		ThrowException();
174 	}
175 
176 
177 
178 
179 }
180