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