CMake: add WITH_LINKER_LLD option for unix platforms
[blender-staging.git] / intern / guardedalloc / intern / mmap_win.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup MEM
22  */
23
24 #ifdef WIN32
25
26 #  include <errno.h>
27 #  include <io.h>
28 #  include <stdio.h>
29 #  include <sys/types.h>
30 #  include <windows.h>
31
32 #  include "mmap_win.h"
33
34 #  ifndef FILE_MAP_EXECUTE
35 // not defined in earlier versions of the Platform  SDK (before February 2003)
36 #    define FILE_MAP_EXECUTE 0x0020
37 #  endif
38
39 /* copied from BLI_utildefines.h, ugh */
40 #  ifdef __GNUC__
41 #    define UNUSED(x) UNUSED_##x __attribute__((__unused__))
42 #  else
43 #    define UNUSED(x) x
44 #  endif
45
46 /* --------------------------------------------------------------------- */
47 /* local storage definitions                                             */
48 /* --------------------------------------------------------------------- */
49 /* all memory mapped chunks are put in linked lists */
50 typedef struct mmapLink {
51   struct mmapLink *next, *prev;
52 } mmapLink;
53
54 typedef struct mmapListBase {
55   void *first, *last;
56 } mmapListBase;
57
58 typedef struct MemMap {
59   struct MemMap *next, *prev;
60   void *mmap;
61   HANDLE fhandle;
62   HANDLE maphandle;
63 } MemMap;
64
65 /* --------------------------------------------------------------------- */
66 /* local functions                                                       */
67 /* --------------------------------------------------------------------- */
68
69 static void mmap_addtail(volatile mmapListBase *listbase, void *vlink);
70 static void mmap_remlink(volatile mmapListBase *listbase, void *vlink);
71 static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr);
72
73 static int mmap_get_prot_flags(int flags);
74 static int mmap_get_access_flags(int flags);
75
76 /* --------------------------------------------------------------------- */
77 /* vars                                                                  */
78 /* --------------------------------------------------------------------- */
79 volatile static struct mmapListBase _mmapbase;
80 volatile static struct mmapListBase *mmapbase = &_mmapbase;
81
82 /* --------------------------------------------------------------------- */
83 /* implementation                                                        */
84 /* --------------------------------------------------------------------- */
85
86 /* mmap for windows */
87 void *mmap(void *UNUSED(start), size_t len, int prot, int flags, int fd, off_t offset)
88 {
89   HANDLE fhandle = INVALID_HANDLE_VALUE;
90   HANDLE maphandle;
91   int prot_flags = mmap_get_prot_flags(prot);
92   int access_flags = mmap_get_access_flags(prot);
93   MemMap *mm = NULL;
94   void *ptr = NULL;
95
96   if (flags & MAP_FIXED) {
97     return MAP_FAILED;
98   }
99
100 #  if 0
101   if (fd == -1) {
102     _set_errno(EBADF);
103     return MAP_FAILED;
104   }
105 #  endif
106
107   if (fd != -1) {
108     fhandle = (HANDLE)_get_osfhandle(fd);
109   }
110   if (fhandle == INVALID_HANDLE_VALUE) {
111     if (!(flags & MAP_ANONYMOUS)) {
112       errno = EBADF;
113       return MAP_FAILED;
114     }
115   }
116   else {
117     if (!DuplicateHandle(GetCurrentProcess(),
118                          fhandle,
119                          GetCurrentProcess(),
120                          &fhandle,
121                          0,
122                          FALSE,
123                          DUPLICATE_SAME_ACCESS)) {
124       return MAP_FAILED;
125     }
126   }
127
128   /* Split 64 bit size into low and high bits. */
129   DWORD len_bits_high = len >> 32;
130   DWORD len_bits_low = len & 0xFFFFFFFF;
131
132   maphandle = CreateFileMapping(fhandle, NULL, prot_flags, len_bits_high, len_bits_low, NULL);
133   if (maphandle == 0) {
134     errno = EBADF;
135     return MAP_FAILED;
136   }
137
138   ptr = MapViewOfFile(maphandle, access_flags, 0, offset, 0);
139   if (ptr == NULL) {
140     DWORD dwLastErr = GetLastError();
141     if (dwLastErr == ERROR_MAPPED_ALIGNMENT)
142       errno = EINVAL;
143     else
144       errno = EACCES;
145     CloseHandle(maphandle);
146     return MAP_FAILED;
147   }
148
149   mm = (MemMap *)malloc(sizeof(MemMap));
150   if (!mm) {
151     errno = ENOMEM;
152   }
153   mm->fhandle = fhandle;
154   mm->maphandle = maphandle;
155   mm->mmap = ptr;
156   mmap_addtail(mmapbase, mm);
157
158   return ptr;
159 }
160
161 /* munmap for windows */
162 intptr_t munmap(void *ptr, size_t UNUSED(size))
163 {
164   MemMap *mm = mmap_findlink(mmapbase, ptr);
165   if (!mm) {
166     errno = EINVAL;
167     return -1;
168   }
169   UnmapViewOfFile(mm->mmap);
170   CloseHandle(mm->maphandle);
171   CloseHandle(mm->fhandle);
172   mmap_remlink(mmapbase, mm);
173   free(mm);
174   return 0;
175 }
176
177 /* --------------------------------------------------------------------- */
178 /* local functions                                                       */
179 /* --------------------------------------------------------------------- */
180
181 static void mmap_addtail(volatile mmapListBase *listbase, void *vlink)
182 {
183   struct mmapLink *link = vlink;
184
185   if (link == NULL)
186     return;
187   if (listbase == NULL)
188     return;
189
190   link->next = 0;
191   link->prev = listbase->last;
192
193   if (listbase->last)
194     ((struct mmapLink *)listbase->last)->next = link;
195   if (listbase->first == NULL)
196     listbase->first = link;
197   listbase->last = link;
198 }
199
200 static void mmap_remlink(volatile mmapListBase *listbase, void *vlink)
201 {
202   struct mmapLink *link = vlink;
203
204   if (link == NULL)
205     return;
206   if (listbase == NULL)
207     return;
208
209   if (link->next)
210     link->next->prev = link->prev;
211   if (link->prev)
212     link->prev->next = link->next;
213
214   if (listbase->last == link)
215     listbase->last = link->prev;
216   if (listbase->first == link)
217     listbase->first = link->next;
218 }
219
220 static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr)
221 {
222   MemMap *mm;
223
224   if (ptr == NULL)
225     return NULL;
226   if (listbase == NULL)
227     return NULL;
228
229   mm = (MemMap *)listbase->first;
230   while (mm) {
231     if (mm->mmap == ptr) {
232       return mm;
233     }
234     mm = mm->next;
235   }
236   return NULL;
237 }
238
239 static int mmap_get_prot_flags(int flags)
240 {
241   int prot = PAGE_NOACCESS;
242
243   if ((flags & PROT_READ) == PROT_READ) {
244     if ((flags & PROT_WRITE) == PROT_WRITE) {
245       prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
246     }
247     else {
248       prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_READONLY;
249     }
250   }
251   else if ((flags & PROT_WRITE) == PROT_WRITE) {
252     prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_WRITECOPY;
253   }
254   else if ((flags & PROT_EXEC) == PROT_EXEC) {
255     prot = PAGE_EXECUTE_READ;
256   }
257   return prot;
258 }
259
260 static int mmap_get_access_flags(int flags)
261 {
262   int access = 0;
263
264   if ((flags & PROT_READ) == PROT_READ) {
265     if ((flags & PROT_WRITE) == PROT_WRITE) {
266       access = FILE_MAP_WRITE;
267     }
268     else {
269       access = (flags & PROT_EXEC) ? FILE_MAP_EXECUTE : FILE_MAP_READ;
270     }
271   }
272   else if ((flags & PROT_WRITE) == PROT_WRITE) {
273     access = FILE_MAP_COPY;
274   }
275   else if ((flags & PROT_EXEC) == PROT_EXEC) {
276     access = FILE_MAP_EXECUTE;
277   }
278   return access;
279 }
280
281 #endif  // WIN32