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
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 #elif MT_PLATFORM_OSX
56 
57 inline void ThrowException()
58 {
59 	__builtin_trap();
60 }
61 
62 #else
63 
64 #error Platform is not supported!
65 
66 #endif
67 
68 
69 
70 namespace MT
71 {
72 
73 	void* Memory::Alloc(size_t size, size_t align)
74 	{
75 		void* p = nullptr;
76 #if MT_SSE_INTRINSICS_SUPPORTED
77 		p = _mm_malloc(size, align);
78 #else
79 		p = memalign(size, align);
80 #endif
81 		MT_ASSERT(p, "Can't allocate memory");
82 		return p;
83 	}
84 
85 	void Memory::Free(void* p)
86 	{
87 #if MT_SSE_INTRINSICS_SUPPORTED
88 		_mm_free(p);
89 #else
90 		free(p);
91 #endif
92 	}
93 
94 	Memory::StackDesc Memory::AllocStack(size_t size)
95 	{
96 		StackDesc desc;
97 
98 #if MT_PLATFORM_WINDOWS
99 
100 		MW_SYSTEM_INFO systemInfo;
101 		GetSystemInfo(&systemInfo);
102 
103 		int pageSize = (int)systemInfo.dwPageSize;
104 		int pagesCount = (int)size / pageSize;
105 
106 		//need additional page for stack guard
107 		if ((size % pageSize) > 0)
108 		{
109 			pagesCount++;
110 		}
111 
112 		//protected guard page
113 		pagesCount++;
114 
115 		desc.stackMemoryBytesCount = pagesCount * pageSize;
116 		desc.stackMemory = (char*)VirtualAlloc(NULL, desc.stackMemoryBytesCount, MW_MEM_COMMIT, MW_PAGE_READWRITE);
117 		MT_ASSERT(desc.stackMemory != NULL, "Can't allocate memory");
118 
119 		desc.stackBottom = desc.stackMemory + pageSize;
120 		desc.stackTop = desc.stackMemory + desc.stackMemoryBytesCount;
121 
122 		MW_DWORD oldProtect = 0;
123 		MW_BOOL res = VirtualProtect(desc.stackMemory, pageSize, MW_PAGE_NOACCESS, &oldProtect);
124 		MT_USED_IN_ASSERT(res);
125 		MT_ASSERT(res != 0, "Can't protect memory");
126 
127 #elif MT_PLATFORM_POSIX || MT_PLATFORM_OSX
128 
129 		int pageSize = sysconf(_SC_PAGE_SIZE);
130 		int pagesCount = size / pageSize;
131 
132 		//need additional page for stack tail
133 		if ((size % pageSize) > 0)
134 		{
135 			pagesCount++;
136 		}
137 
138 		//protected guard page
139 		pagesCount++;
140 
141 		desc.stackMemoryBytesCount = pagesCount * pageSize;
142 		desc.stackMemory = (char*)mmap(NULL, desc.stackMemoryBytesCount, PROT_READ | PROT_WRITE,  MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
143 
144 		MT_ASSERT((void *)desc.stackMemory != (void *)-1, "Can't allocate memory");
145 
146 		desc.stackBottom = desc.stackMemory + pageSize;
147 		desc.stackTop = desc.stackMemory + desc.stackMemoryBytesCount;
148 
149 		int res = mprotect(desc.stackMemory, pageSize, PROT_NONE);
150 		MT_USED_IN_ASSERT(res);
151 		MT_ASSERT(res == 0, "Can't protect memory");
152 #else
153 		#error Platform is not supported!
154 #endif
155 
156 		return desc;
157 	}
158 
159 	void Memory::FreeStack(const Memory::StackDesc & desc)
160 	{
161 #if MT_PLATFORM_WINDOWS
162 
163 		int res = VirtualFree(desc.stackMemory, 0, MW_MEM_RELEASE);
164 		MT_USED_IN_ASSERT(res);
165 		MT_ASSERT(res != 0, "Can't free memory");
166 
167 #elif MT_PLATFORM_POSIX || MT_PLATFORM_OSX
168 
169 		int res = munmap(desc.stackMemory, desc.stackMemoryBytesCount);
170 		MT_USED_IN_ASSERT(res);
171 		MT_ASSERT(res == 0, "Can't free memory");
172 #else
173 		#error Platform is not supported!
174 #endif
175 	}
176 
177 	void Diagnostic::ReportAssert(const char* condition, const char* description, const char* sourceFile, int sourceLine)
178 	{
179 		printf("Assertion failed : %s. File %s, line %d. Condition %s\n", description, sourceFile, sourceLine, condition);
180 		ThrowException();
181 	}
182 
183 
184 
185 
186 }
187