ClangFormat: apply to source, most of intern
[blender.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 <windows.h>
27 #  include <errno.h>
28 #  include <io.h>
29 #  include <sys/types.h>
30 #  include <stdio.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   /* note len is passed to a 32 bit DWORD, so can't be > 4 GB */
129   maphandle = CreateFileMapping(fhandle, NULL, prot_flags, 0, len, NULL);
130   if (maphandle == 0) {
131     errno = EBADF;
132     return MAP_FAILED;
133   }
134
135   ptr = MapViewOfFile(maphandle, access_flags, 0, offset, 0);
136   if (ptr == NULL) {
137     DWORD dwLastErr = GetLastError();
138     if (dwLastErr == ERROR_MAPPED_ALIGNMENT)
139       errno = EINVAL;
140     else
141       errno = EACCES;
142     CloseHandle(maphandle);
143     return MAP_FAILED;
144   }
145
146   mm = (MemMap *)malloc(sizeof(MemMap));
147   if (!mm) {
148     errno = ENOMEM;
149   }
150   mm->fhandle = fhandle;
151   mm->maphandle = maphandle;
152   mm->mmap = ptr;
153   mmap_addtail(mmapbase, mm);
154
155   return ptr;
156 }
157
158 /* munmap for windows */
159 intptr_t munmap(void *ptr, size_t UNUSED(size))
160 {
161   MemMap *mm = mmap_findlink(mmapbase, ptr);
162   if (!mm) {
163     errno = EINVAL;
164     return -1;
165   }
166   UnmapViewOfFile(mm->mmap);
167   CloseHandle(mm->maphandle);
168   CloseHandle(mm->fhandle);
169   mmap_remlink(mmapbase, mm);
170   free(mm);
171   return 0;
172 }
173
174 /* --------------------------------------------------------------------- */
175 /* local functions                                                       */
176 /* --------------------------------------------------------------------- */
177
178 static void mmap_addtail(volatile mmapListBase *listbase, void *vlink)
179 {
180   struct mmapLink *link = vlink;
181
182   if (link == NULL)
183     return;
184   if (listbase == NULL)
185     return;
186
187   link->next = 0;
188   link->prev = listbase->last;
189
190   if (listbase->last)
191     ((struct mmapLink *)listbase->last)->next = link;
192   if (listbase->first == NULL)
193     listbase->first = link;
194   listbase->last = link;
195 }
196
197 static void mmap_remlink(volatile mmapListBase *listbase, void *vlink)
198 {
199   struct mmapLink *link = vlink;
200
201   if (link == NULL)
202     return;
203   if (listbase == NULL)
204     return;
205
206   if (link->next)
207     link->next->prev = link->prev;
208   if (link->prev)
209     link->prev->next = link->next;
210
211   if (listbase->last == link)
212     listbase->last = link->prev;
213   if (listbase->first == link)
214     listbase->first = link->next;
215 }
216
217 static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr)
218 {
219   MemMap *mm;
220
221   if (ptr == NULL)
222     return NULL;
223   if (listbase == NULL)
224     return NULL;
225
226   mm = (MemMap *)listbase->first;
227   while (mm) {
228     if (mm->mmap == ptr) {
229       return mm;
230     }
231     mm = mm->next;
232   }
233   return NULL;
234 }
235
236 static int mmap_get_prot_flags(int flags)
237 {
238   int prot = PAGE_NOACCESS;
239
240   if ((flags & PROT_READ) == PROT_READ) {
241     if ((flags & PROT_WRITE) == PROT_WRITE) {
242       prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
243     }
244     else {
245       prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_READONLY;
246     }
247   }
248   else if ((flags & PROT_WRITE) == PROT_WRITE) {
249     prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_WRITECOPY;
250   }
251   else if ((flags & PROT_EXEC) == PROT_EXEC) {
252     prot = PAGE_EXECUTE_READ;
253   }
254   return prot;
255 }
256
257 static int mmap_get_access_flags(int flags)
258 {
259   int access = 0;
260
261   if ((flags & PROT_READ) == PROT_READ) {
262     if ((flags & PROT_WRITE) == PROT_WRITE) {
263       access = FILE_MAP_WRITE;
264     }
265     else {
266       access = (flags & PROT_EXEC) ? FILE_MAP_EXECUTE : FILE_MAP_READ;
267     }
268   }
269   else if ((flags & PROT_WRITE) == PROT_WRITE) {
270     access = FILE_MAP_COPY;
271   }
272   else if ((flags & PROT_EXEC) == PROT_EXEC) {
273     access = FILE_MAP_EXECUTE;
274   }
275   return access;
276 }
277
278 #endif  // WIN32