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