Fix #34121: OSL + persistent images option was not freeing shader memory properly,
[blender.git] / intern / guardedalloc / intern / mmap_win.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Andrea Weikert.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file guardedalloc/intern/mmap_win.c
29  *  \ingroup MEM
30  */
31
32 #ifdef WIN32
33
34 #include <windows.h>
35 #include <errno.h>
36 #include <io.h>
37 #include <sys/types.h>
38 #include <stdio.h>
39
40 #include "mmap_win.h"
41
42 #ifndef FILE_MAP_EXECUTE
43 //not defined in earlier versions of the Platform  SDK (before February 2003)
44 #define FILE_MAP_EXECUTE 0x0020
45 #endif
46
47 /* copied from BLI_utildefines.h, ugh */
48 #ifdef __GNUC__
49 #  define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
50 #else
51 #  define UNUSED(x) x
52 #endif
53
54 /* --------------------------------------------------------------------- */
55 /* local storage definitions                                             */
56 /* --------------------------------------------------------------------- */
57 /* all memory mapped chunks are put in linked lists */
58 typedef struct mmapLink {
59         struct mmapLink *next, *prev;
60 } mmapLink;
61
62 typedef struct mmapListBase {
63         void *first, *last;
64 } mmapListBase;
65
66 typedef struct MemMap {
67         struct MemMap *next, *prev;
68         void *mmap;
69         HANDLE fhandle;
70         HANDLE maphandle;
71 } MemMap;
72
73 /* --------------------------------------------------------------------- */
74 /* local functions                                                       */
75 /* --------------------------------------------------------------------- */
76
77 static void mmap_addtail(volatile mmapListBase *listbase, void *vlink);
78 static void mmap_remlink(volatile mmapListBase *listbase, void *vlink);
79 static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr);
80
81 static int mmap_get_prot_flags(int flags);
82 static int mmap_get_access_flags(int flags);
83
84 /* --------------------------------------------------------------------- */
85 /* vars                                                                  */
86 /* --------------------------------------------------------------------- */
87 volatile static struct mmapListBase _mmapbase;
88 volatile static struct mmapListBase *mmapbase = &_mmapbase;
89
90
91 /* --------------------------------------------------------------------- */
92 /* implementation                                                        */
93 /* --------------------------------------------------------------------- */
94
95 /* mmap for windows */
96 void *mmap(void *UNUSED(start), size_t len, int prot, int flags, int fd, off_t offset)
97 {
98         HANDLE fhandle = INVALID_HANDLE_VALUE;
99         HANDLE maphandle;
100         int prot_flags = mmap_get_prot_flags(prot);
101         int access_flags = mmap_get_access_flags(prot);
102         MemMap *mm = NULL;
103         void *ptr = NULL;
104
105         if (flags & MAP_FIXED) {
106                 return MAP_FAILED;
107         }
108
109 #if 0
110         if ( fd == -1 ) {
111                 _set_errno( EBADF );
112                 return MAP_FAILED;
113         }
114 #endif
115
116         if (fd != -1) {
117                 fhandle = (HANDLE) _get_osfhandle(fd);
118         }
119         if (fhandle == INVALID_HANDLE_VALUE) {
120                 if (!(flags & MAP_ANONYMOUS)) {
121                         errno = EBADF;
122                         return MAP_FAILED;
123                 }
124         }
125         else {
126                 if (!DuplicateHandle(GetCurrentProcess(), fhandle, GetCurrentProcess(),
127                                      &fhandle, 0, FALSE, DUPLICATE_SAME_ACCESS) ) {
128                         return MAP_FAILED;
129                 }
130         }
131
132         maphandle = CreateFileMapping(fhandle, NULL, prot_flags, 0, len, 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, intptr_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 == 0) return;
186         if (listbase == 0) return;
187
188         link->next = 0;
189         link->prev = listbase->last;
190
191         if (listbase->last) ((struct mmapLink *)listbase->last)->next = link;
192         if (listbase->first == 0) listbase->first = link;
193         listbase->last = link;
194 }
195
196 static void mmap_remlink(volatile mmapListBase *listbase, void *vlink)
197 {
198         struct mmapLink *link = vlink;
199
200         if (link == 0) return;
201         if (listbase == 0) return;
202
203         if (link->next) link->next->prev = link->prev;
204         if (link->prev) link->prev->next = link->next;
205
206         if (listbase->last == link) listbase->last = link->prev;
207         if (listbase->first == link) listbase->first = link->next;
208 }
209
210 static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr)
211 {
212         MemMap *mm;
213
214         if (ptr == 0) return NULL;
215         if (listbase == 0) return NULL;
216         
217         mm = (MemMap *)listbase->first;
218         while (mm) {
219                 if (mm->mmap == ptr) {
220                         return mm;
221                 }
222                 mm = mm->next;
223         }
224         return NULL;
225 }
226
227 static int mmap_get_prot_flags(int flags)
228 {
229         int prot = PAGE_NOACCESS;
230
231         if ( (flags & PROT_READ) == PROT_READ) {
232                 if ( (flags & PROT_WRITE) == PROT_WRITE) {
233                         prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
234                 }
235                 else {
236                         prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_READONLY;
237                 }
238         }
239         else if ( (flags & PROT_WRITE) == PROT_WRITE) {
240                 prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_WRITECOPY;
241         }
242         else if ( (flags & PROT_EXEC) == PROT_EXEC) {
243                 prot = PAGE_EXECUTE_READ;
244         }
245         return prot;
246 }
247
248 static int mmap_get_access_flags(int flags)
249 {
250         int access = 0;
251
252         if ( (flags & PROT_READ) == PROT_READ) {
253                 if ( (flags & PROT_WRITE) == PROT_WRITE) {
254                         access = FILE_MAP_WRITE;
255                 }
256                 else {
257                         access = (flags & PROT_EXEC) ? FILE_MAP_EXECUTE : FILE_MAP_READ;
258                 }
259         }
260         else if ( (flags & PROT_WRITE) == PROT_WRITE) {
261                 access = FILE_MAP_COPY;
262         }
263         else if ( (flags & PROT_EXEC) == PROT_EXEC) {
264                 access = FILE_MAP_EXECUTE;
265         }
266         return access;
267 }
268
269 #endif // WIN32