OSDN Git Service

Initial checkin of text Corinna sent to cygwin-announce.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / mmap.cc
1 /* mmap.cc
2
3    Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005,
4    2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include "miscfuncs.h"
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <sys/mman.h>
17 #include <sys/param.h>
18 #include "cygerrno.h"
19 #include "security.h"
20 #include "path.h"
21 #include "fhandler.h"
22 #include "dtable.h"
23 #include "cygheap.h"
24 #include "ntdll.h"
25 #include <sys/queue.h>
26
27 /* __PROT_ATTACH indicates an anonymous mapping which is supposed to be
28    attached to a file mapping for pages beyond the file's EOF.  The idea
29    is to support mappings longer than the file, without the file growing
30    to mapping length (POSIX semantics). */
31 #define __PROT_ATTACH   0x8000000
32 /* Filler pages are the pages from the last file backed page to the next
33    64K boundary.  These pages are created as anonymous pages, but with
34    the same page protection as the file's pages, since POSIX applications
35    expect to be able to access this part the same way as the file pages. */
36 #define __PROT_FILLER   0x4000000
37
38 /* Stick with 4K pages for bookkeeping, otherwise we just get confused
39    when trying to do file mappings with trailing filler pages correctly. */
40 #define PAGE_CNT(bytes) howmany((bytes), wincap.page_size())
41
42 #define PGBITS          (sizeof (DWORD)*8)
43 #define MAPSIZE(pages)  howmany ((pages), PGBITS)
44
45 #define MAP_SET(n)      (page_map[(n)/PGBITS] |= (1L << ((n) % PGBITS)))
46 #define MAP_CLR(n)      (page_map[(n)/PGBITS] &= ~(1L << ((n) % PGBITS)))
47 #define MAP_ISSET(n)    (page_map[(n)/PGBITS] & (1L << ((n) % PGBITS)))
48
49 /* Used for anonymous mappings. */
50 static fhandler_dev_zero fh_anonymous;
51
52 /* Used for thread synchronization while accessing mmap bookkeeping lists. */
53 static NO_COPY muto mmap_guard;
54 #define LIST_LOCK()    (mmap_guard.init ("mmap_guard")->acquire ())
55 #define LIST_UNLOCK()  (mmap_guard.release ())
56
57 /* Small helpers to avoid having lots of flag bit tests in the code. */
58 static inline bool
59 priv (int flags)
60 {
61   return (flags & MAP_PRIVATE) == MAP_PRIVATE;
62 }
63
64 static inline bool
65 fixed (int flags)
66 {
67   return (flags & MAP_FIXED) == MAP_FIXED;
68 }
69
70 static inline bool
71 anonymous (int flags)
72 {
73   return (flags & MAP_ANONYMOUS) == MAP_ANONYMOUS;
74 }
75
76 static inline bool
77 noreserve (int flags)
78 {
79   return (flags & MAP_NORESERVE) == MAP_NORESERVE;
80 }
81
82 static inline bool
83 autogrow (int flags)
84 {
85   return (flags & MAP_AUTOGROW) == MAP_AUTOGROW;
86 }
87
88 static inline bool
89 attached (int prot)
90 {
91   return (prot & __PROT_ATTACH) == __PROT_ATTACH;
92 }
93
94 static inline bool
95 filler (int prot)
96 {
97   return (prot & __PROT_FILLER) == __PROT_FILLER;
98 }
99
100 static inline DWORD
101 gen_create_protect (DWORD openflags, int flags)
102 {
103   DWORD ret = PAGE_READONLY;
104
105   if (priv (flags))
106     ret = PAGE_WRITECOPY;
107   else if (openflags & GENERIC_WRITE)
108     ret = PAGE_READWRITE;
109
110   if (openflags & GENERIC_EXECUTE)
111     ret <<= 4;
112
113   return ret;
114 }
115
116 /* Generate Windows protection flags from mmap prot and flag values. */
117 static inline DWORD
118 gen_protect (int prot, int flags)
119 {
120   DWORD ret = PAGE_NOACCESS;
121
122   /* Attached pages are only reserved, but the protection must be a
123      valid value, so we just return PAGE_READWRITE. */
124   if (attached (prot))
125     return PAGE_EXECUTE_READWRITE;
126
127   if (prot & PROT_WRITE)
128     ret = (priv (flags) && (!anonymous (flags) || filler (prot)))
129           ? PAGE_WRITECOPY : PAGE_READWRITE;
130   else if (prot & PROT_READ)
131     ret = PAGE_READONLY;
132
133   if (prot & PROT_EXEC)
134     ret <<= 4;
135
136   return ret;
137 }
138
139 static HANDLE
140 CreateMapping (HANDLE fhdl, size_t len, _off64_t off, DWORD openflags,
141                int prot, int flags)
142 {
143   HANDLE h;
144   NTSTATUS status;
145
146   LARGE_INTEGER sectionsize = { QuadPart: len };
147   ULONG protect = gen_create_protect (openflags, flags);
148   ULONG attributes = attached (prot) ? SEC_RESERVE : SEC_COMMIT;
149
150   OBJECT_ATTRIBUTES oa;
151   InitializeObjectAttributes (&oa, NULL, OBJ_INHERIT, NULL,
152                               sec_none.lpSecurityDescriptor);
153
154   if (fhdl == INVALID_HANDLE_VALUE)
155     {
156       /* Standard anonymous mapping needs non-zero len. */
157       status = NtCreateSection (&h, SECTION_ALL_ACCESS, &oa, &sectionsize,
158                                 protect, attributes, NULL);
159     }
160   else if (autogrow (flags))
161     {
162       /* Auto-grow only works if the protection is PAGE_READWRITE.  So,
163          first we call NtCreateSection with PAGE_READWRITE, then, if the
164          requested protection is different, we close the mapping and
165          reopen it again with the correct protection, if auto-grow worked. */
166       sectionsize.QuadPart += off;
167       status = NtCreateSection (&h, SECTION_ALL_ACCESS, &oa, &sectionsize,
168                                 PAGE_READWRITE, attributes, fhdl);
169       if (NT_SUCCESS (status) && protect != PAGE_READWRITE)
170         {
171           NtClose (h);
172           status = NtCreateSection (&h, SECTION_ALL_ACCESS, &oa, &sectionsize,
173                                     protect, attributes, fhdl);
174         }
175     }
176   else
177     {
178       /* Zero len creates mapping for whole file and allows
179          AT_EXTENDABLE_FILE mapping, if we ever use it... */
180       sectionsize.QuadPart = 0;
181       status = NtCreateSection (&h, SECTION_ALL_ACCESS, &oa, &sectionsize,
182                                 protect, attributes, fhdl);
183     }
184   if (!NT_SUCCESS (status))
185     {
186       h = NULL;
187       SetLastError (RtlNtStatusToDosError (status));
188     }
189   return h;
190 }
191
192 static void *
193 MapView (HANDLE h, void *addr, size_t len, DWORD openflags,
194          int prot, int flags, _off64_t off)
195 {
196   NTSTATUS status;
197   LARGE_INTEGER offset = { QuadPart:off };
198   DWORD protect = gen_create_protect (openflags, flags);
199   void *base = addr;
200   ULONG commitsize = attached (prot) ? 0 : len;
201   ULONG viewsize = len;
202   ULONG alloc_type = (base && !wincap.is_wow64 () ? AT_ROUND_TO_PAGE : 0)
203                      | MEM_TOP_DOWN;
204
205   /* Try mapping using the given address first, even if it's NULL.
206      If it failed, and addr was not NULL and flags is not MAP_FIXED,
207      try again with NULL address.
208
209      Note: Retrying the mapping might be unnecessary, now that mmap64 checks
210            for a valid memory area first. */
211   status = NtMapViewOfSection (h, NtCurrentProcess (), &base, 0, commitsize,
212                                &offset, &viewsize, ViewShare, alloc_type,
213                                protect);
214   if (!NT_SUCCESS (status) && addr && !fixed (flags))
215     {
216       base = NULL;
217       status = NtMapViewOfSection (h, NtCurrentProcess (), &base, 0, commitsize,
218                                    &offset, &viewsize, ViewShare, 0, protect);
219     }
220   if (!NT_SUCCESS (status))
221     {
222       base = NULL;
223       SetLastError (RtlNtStatusToDosError (status));
224     }
225   debug_printf ("%p (status %p) = NtMapViewOfSection (h:%x, addr:%x, len:%u,"
226                 " off:%X, protect:%x, type:%x)",
227                 base, status, h, addr, len, off, protect, 0);
228   return base;
229 }
230
231 /* Class structure used to keep a record of all current mmap areas
232    in a process.  Needed for bookkeeping all mmaps in a process and
233    for duplicating all mmaps after fork() since mmaps are not propagated
234    to child processes by Windows.  All information must be duplicated
235    by hand, see fixup_mmaps_after_fork().
236
237    The class structure:
238
239    One member of class map per process, global variable mmapped_areas.
240    Contains a singly-linked list of type class mmap_list.  Each mmap_list
241    entry represents all mapping to a file, keyed by file descriptor and
242    file name hash.
243    Each list entry contains a singly-linked list of type class mmap_record.
244    Each mmap_record represents exactly one mapping.  For each mapping, there's
245    an additional so called `page_map'.  It's an array of bits, one bit
246    per mapped memory page.  The bit is set if the page is accessible,
247    unset otherwise. */
248
249 #pragma pack(push, 4)
250 class mmap_record
251 {
252   public:
253     LIST_ENTRY (mmap_record) mr_next;
254
255   private:
256     int fd;
257     HANDLE mapping_hdl;
258     DWORD openflags;
259     int prot;
260     int flags;
261     _off64_t offset;
262     DWORD len;
263     caddr_t base_address;
264     int dev;
265     DWORD page_map[0];
266
267   public:
268     mmap_record (int nfd, HANDLE h, DWORD of, int p, int f, _off64_t o, DWORD l,
269                  caddr_t b) :
270        fd (nfd),
271        mapping_hdl (h),
272        openflags (of),
273        prot (p),
274        flags (f),
275        offset (o),
276        len (l),
277        base_address (b)
278       {
279         dev = 0;
280         if (fd >= 0 && !cygheap->fdtab.not_open (fd))
281           dev = cygheap->fdtab[fd]->dev ();
282         else if (fd == -1)
283           dev = FH_ZERO;
284       }
285
286     int get_fd () const { return fd; }
287     HANDLE get_handle () const { return mapping_hdl; }
288     int get_device () { return dev; }
289     int get_prot () const { return prot; }
290     int get_openflags () const { return openflags; }
291     int get_flags () const { return flags; }
292     bool priv () const { return ::priv (flags); }
293     bool fixed () const { return ::fixed (flags); }
294     bool anonymous () const { return ::anonymous (flags); }
295     bool noreserve () const { return ::noreserve (flags); }
296     bool autogrow () const { return ::autogrow (flags); }
297     bool attached () const { return ::attached (prot); }
298     bool filler () const { return ::filler (prot); }
299     _off64_t get_offset () const { return offset; }
300     DWORD get_len () const { return len; }
301     caddr_t get_address () const { return base_address; }
302
303     void init_page_map (mmap_record &r);
304
305     DWORD find_unused_pages (DWORD pages) const;
306     bool match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len);
307     _off64_t map_pages (_off64_t off, DWORD len);
308     bool map_pages (caddr_t addr, DWORD len);
309     bool unmap_pages (caddr_t addr, DWORD len);
310     int access (caddr_t address);
311
312     fhandler_base *alloc_fh ();
313     void free_fh (fhandler_base *fh);
314
315     DWORD gen_create_protect () const
316       { return ::gen_create_protect (get_openflags (), get_flags ()); }
317     DWORD gen_protect () const
318       { return ::gen_protect (get_prot (), get_flags ()); }
319     bool compatible_flags (int fl) const;
320 };
321 #pragma pack(pop)
322
323 class mmap_list
324 {
325   public:
326     LIST_ENTRY (mmap_list) ml_next;
327     LIST_HEAD (, mmap_record) recs;
328
329   private:
330     int fd;
331     __ino64_t hash;
332
333   public:
334     int get_fd () const { return fd; }
335     __ino64_t get_hash () const { return hash; }
336
337     bool anonymous () const { return fd == -1; }
338     void set (int nfd, struct __stat64 *st);
339     mmap_record *add_record (mmap_record &r);
340     bool del_record (mmap_record *rec);
341     caddr_t try_map (void *addr, size_t len, int flags, _off64_t off);
342 };
343
344 class mmap_areas
345 {
346   public:
347     LIST_HEAD (, mmap_list) lists;
348
349     mmap_list *get_list_by_fd (int fd, struct __stat64 *st);
350     mmap_list *add_list (int fd, struct __stat64 *st);
351     void del_list (mmap_list *ml);
352 };
353
354 /* This is the global map structure pointer. */
355 static mmap_areas mmapped_areas;
356
357 bool
358 mmap_record::compatible_flags (int fl) const
359 {
360 #define MAP_COMPATMASK  (MAP_TYPE | MAP_NORESERVE)
361   return (get_flags () & MAP_COMPATMASK) == (fl & MAP_COMPATMASK);
362 }
363
364 DWORD
365 mmap_record::find_unused_pages (DWORD pages) const
366 {
367   DWORD mapped_pages = PAGE_CNT (get_len ());
368   DWORD start;
369
370   if (pages > mapped_pages)
371     return (DWORD)-1;
372   for (start = 0; start <= mapped_pages - pages; ++start)
373     if (!MAP_ISSET (start))
374       {
375         DWORD cnt;
376         for (cnt = 0; cnt < pages; ++cnt)
377           if (MAP_ISSET (start + cnt))
378             break;
379         if (cnt >= pages)
380           return start;
381       }
382   return (DWORD)-1;
383 }
384
385 bool
386 mmap_record::match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len)
387 {
388   caddr_t low = (addr >= get_address ()) ? addr : get_address ();
389   caddr_t high = get_address ();
390   if (filler ())
391     high += get_len ();
392   else
393     high += (PAGE_CNT (get_len ()) * wincap.page_size ());
394   high = (addr + len < high) ? addr + len : high;
395   if (low < high)
396     {
397       m_addr = low;
398       m_len = high - low;
399       return true;
400     }
401   return false;
402 }
403
404 void
405 mmap_record::init_page_map (mmap_record &r)
406 {
407   *this = r;
408   DWORD start_protect = gen_create_protect ();
409   DWORD real_protect = gen_protect ();
410   if (real_protect != start_protect && !noreserve ()
411       && !VirtualProtect (get_address (), get_len (),
412                           real_protect, &start_protect))
413     system_printf ("Warning: VirtualProtect (addr: %p, len: 0x%x, "
414                    "new_prot: 0x%x, old_prot: 0x%x), %E",
415                    get_address (), get_len (),
416                    real_protect, start_protect);
417   DWORD len = PAGE_CNT (get_len ());
418   while (len-- > 0)
419     MAP_SET (len);
420 }
421
422 _off64_t
423 mmap_record::map_pages (_off64_t off, DWORD len)
424 {
425   /* Used ONLY if this mapping matches into the chunk of another already
426      performed mapping in a special case of MAP_ANON|MAP_PRIVATE.
427
428      Otherwise it's job is now done by init_page_map(). */
429   DWORD old_prot;
430   debug_printf ("map_pages (fd=%d, off=%D, len=%u)", get_fd (), off, len);
431   len = PAGE_CNT (len);
432
433   if ((off = find_unused_pages (len)) == (DWORD)-1)
434     return 0L;
435   if (!noreserve ()
436       && !VirtualProtect (get_address () + off * wincap.page_size (),
437                           len * wincap.page_size (), gen_protect (),
438                           &old_prot))
439     {
440       __seterrno ();
441       return (_off64_t)-1;
442     }
443
444   while (len-- > 0)
445     MAP_SET (off + len);
446   return off * wincap.page_size ();
447 }
448
449 bool
450 mmap_record::map_pages (caddr_t addr, DWORD len)
451 {
452   debug_printf ("map_pages (addr=%x, len=%u)", addr, len);
453   DWORD old_prot;
454   DWORD off = addr - get_address ();
455   off /= wincap.page_size ();
456   len = PAGE_CNT (len);
457   /* First check if the area is unused right now. */
458   for (DWORD l = 0; l < len; ++l)
459     if (MAP_ISSET (off + l))
460       {
461         set_errno (EINVAL);
462         return false;
463       }
464   if (!noreserve ()
465       && !VirtualProtect (get_address () + off * wincap.page_size (),
466                           len * wincap.page_size (), gen_protect (),
467                           &old_prot))
468     {
469       __seterrno ();
470       return false;
471     }
472   for (; len-- > 0; ++off)
473     MAP_SET (off);
474   return true;
475 }
476
477 bool
478 mmap_record::unmap_pages (caddr_t addr, DWORD len)
479 {
480   DWORD old_prot;
481   DWORD off = addr - get_address ();
482   if (noreserve ()
483       && !VirtualFree (get_address () + off, len, MEM_DECOMMIT))
484     debug_printf ("VirtualFree in unmap_pages () failed, %E");
485   else if (!VirtualProtect (get_address () + off, len, PAGE_NOACCESS,
486                             &old_prot))
487     debug_printf ("VirtualProtect in unmap_pages () failed, %E");
488
489   off /= wincap.page_size ();
490   len = PAGE_CNT (len);
491   for (; len-- > 0; ++off)
492     MAP_CLR (off);
493   /* Return TRUE if all pages are free'd which may result in unmapping
494      the whole chunk. */
495   for (len = MAPSIZE (PAGE_CNT (get_len ())); len > 0; )
496     if (page_map[--len])
497       return false;
498   return true;
499 }
500
501 int
502 mmap_record::access (caddr_t address)
503 {
504   if (address < get_address () || address >= get_address () + get_len ())
505     return 0;
506   DWORD off = (address - get_address ()) / wincap.page_size ();
507   return MAP_ISSET (off);
508 }
509
510 fhandler_base *
511 mmap_record::alloc_fh ()
512 {
513   if (anonymous ())
514     {
515       fh_anonymous.set_io_handle (INVALID_HANDLE_VALUE);
516       fh_anonymous.set_access (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE);
517       return &fh_anonymous;
518     }
519
520   /* The file descriptor could have been closed or, even
521      worse, could have been reused for another file before
522      the call to fork(). This requires creating a fhandler
523      of the correct type to be sure to call the method of the
524      correct class. */
525   device fdev;
526   fdev.name = fdev.native = "";
527   fdev.parse (get_device ());
528   fhandler_base *fh = build_fh_dev (fdev);
529   fh->set_access (get_openflags ());
530   return fh;
531 }
532
533 void
534 mmap_record::free_fh (fhandler_base *fh)
535 {
536   if (!anonymous ())
537     delete fh;
538 }
539
540 mmap_record *
541 mmap_list::add_record (mmap_record &r)
542 {
543   mmap_record *rec = (mmap_record *) ccalloc (HEAP_MMAP,
544                       sizeof (mmap_record)
545                       + MAPSIZE (PAGE_CNT (r.get_len ())) * sizeof (DWORD), 1);
546   if (!rec)
547     return NULL;
548   rec->init_page_map (r);
549
550   LIST_INSERT_HEAD (&recs, rec, mr_next);
551   return rec;
552 }
553
554 void
555 mmap_list::set (int nfd, struct __stat64 *st)
556 {
557   fd = nfd;
558   if (!anonymous ())
559     {
560       /* The fd isn't sufficient since it could already be the fd of another
561          file.  So we use the inode number as evaluated by fstat to identify
562          the file. */
563       hash = st ? st->st_ino : (__ino64_t) 0;
564     }
565   LIST_INIT (&recs);
566 }
567
568 bool
569 mmap_list::del_record (mmap_record *rec)
570 {
571   LIST_REMOVE (rec, mr_next);
572   cfree (rec);
573   /* Return true if the list is empty which allows the caller to remove
574      this list from the list of lists. */
575   return !LIST_FIRST(&recs);
576 }
577
578 caddr_t
579 mmap_list::try_map (void *addr, size_t len, int flags, _off64_t off)
580 {
581   mmap_record *rec;
582
583   if (off == 0 && !fixed (flags))
584     {
585       /* If MAP_FIXED isn't given, check if this mapping matches into the
586          chunk of another already performed mapping. */
587       DWORD plen = PAGE_CNT (len);
588       LIST_FOREACH (rec, &recs, mr_next)
589         if (rec->find_unused_pages (plen) != (DWORD) -1)
590           break;
591       if (rec && rec->compatible_flags (flags))
592         {
593           if ((off = rec->map_pages (off, len)) == (_off64_t) -1)
594             return (caddr_t) MAP_FAILED;
595           return (caddr_t) rec->get_address () + off;
596         }
597     }
598   else if (fixed (flags))
599     {
600       /* If MAP_FIXED is given, test if the requested area is in an
601          unmapped part of an still active mapping.  This can happen
602          if a memory region is unmapped and remapped with MAP_FIXED. */
603       caddr_t u_addr;
604       DWORD u_len;
605
606       LIST_FOREACH (rec, &recs, mr_next)
607         if (rec->match ((caddr_t) addr, len, u_addr, u_len))
608           break;
609       if (rec)
610         {
611           if (u_addr > (caddr_t) addr || u_addr + len < (caddr_t) addr + len
612               || !rec->compatible_flags (flags))
613             {
614               /* Partial match only, or access mode doesn't match. */
615               /* FIXME: Handle partial mappings gracefully if adjacent
616                  memory is available. */
617               set_errno (EINVAL);
618               return (caddr_t) MAP_FAILED;
619             }
620           if (!rec->map_pages ((caddr_t) addr, len))
621             return (caddr_t) MAP_FAILED;
622           return (caddr_t) addr;
623         }
624     }
625   return NULL;
626 }
627
628 mmap_list *
629 mmap_areas::get_list_by_fd (int fd, struct __stat64 *st)
630 {
631   mmap_list *ml;
632   LIST_FOREACH (ml, &lists, ml_next)
633     {
634       if (fd == -1 && ml->anonymous ())
635         return ml;
636       /* The fd isn't sufficient since it could already be the fd of another
637          file.  So we use the inode number as evaluated by fstat to identify
638          the file. */
639       if (fd != -1 && st && ml->get_hash () == st->st_ino)
640         return ml;
641     }
642   return 0;
643 }
644
645 mmap_list *
646 mmap_areas::add_list (int fd, struct __stat64 *st)
647 {
648   mmap_list *ml = (mmap_list *) cmalloc (HEAP_MMAP, sizeof (mmap_list));
649   if (!ml)
650     return NULL;
651   ml->set (fd, st);
652   LIST_INSERT_HEAD (&lists, ml, ml_next);
653   return ml;
654 }
655
656 void
657 mmap_areas::del_list (mmap_list *ml)
658 {
659   LIST_REMOVE (ml, ml_next);
660   cfree (ml);
661 }
662
663 /* This function allows an external function to test if a given memory
664    region is part of an mmapped memory region. */
665 bool
666 is_mmapped_region (caddr_t start_addr, caddr_t end_address)
667 {
668   size_t len = end_address - start_addr;
669
670   LIST_LOCK ();
671   mmap_list *map_list = mmapped_areas.get_list_by_fd (-1, NULL);
672
673   if (!map_list)
674     return false;
675
676   mmap_record *rec;
677   caddr_t u_addr;
678   DWORD u_len;
679   bool ret = false;
680
681   LIST_FOREACH (rec, &map_list->recs, mr_next)
682     {
683       if (rec->match (start_addr, len, u_addr, u_len))
684         {
685           ret = true;
686           break;
687         }
688     }
689   LIST_UNLOCK ();
690   return ret;
691 }
692
693 /* This function is called from exception_handler when a segmentation
694    violation has occurred.  It should also be called from all Cygwin
695    functions that want to support passing noreserve mmap page addresses
696    to Windows system calls.  In that case, it should be called only after
697    a system call indicates that the application buffer passed had an
698    invalid virtual address to avoid any performance impact in non-noreserve
699    cases.
700
701    Check if the address range is all within noreserve mmap regions.  If so,
702    call VirtualAlloc to commit the pages and return MMAP_NORESERVE_COMMITED
703    on success.  If the page has __PROT_ATTACH (SUSv3 memory protection
704    extension), or if VirutalAlloc fails, return MMAP_RAISE_SIGBUS.
705    Otherwise, return MMAP_NONE if the address range is not covered by an
706    attached or noreserve map.
707
708    On MAP_NORESERVE_COMMITED, the exeception handler should return 0 to
709    allow the application to retry the memory access, or the calling Cygwin
710    function should retry the Windows system call. */
711
712 mmap_region_status
713 mmap_is_attached_or_noreserve (void *addr, size_t len)
714 {
715   mmap_region_status ret = MMAP_NONE;
716
717   LIST_LOCK ();
718   mmap_list *map_list = mmapped_areas.get_list_by_fd (-1, NULL);
719
720   size_t pagesize = wincap.allocation_granularity ();
721   caddr_t start_addr = (caddr_t) rounddown ((uintptr_t) addr, pagesize);
722   len += ((caddr_t) addr - start_addr);
723   len = roundup2 (len, pagesize);
724
725   if (map_list == NULL)
726     goto out;
727
728   mmap_record *rec;
729   caddr_t u_addr;
730   DWORD u_len;
731
732   LIST_FOREACH (rec, &map_list->recs, mr_next)
733     {
734       if (!rec->match (start_addr, len, u_addr, u_len))
735         continue;
736       if (rec->attached ())
737         {
738           ret = MMAP_RAISE_SIGBUS;
739           break;
740         }
741       if (!rec->noreserve ())
742         break;
743
744       size_t commit_len = u_len - (start_addr - u_addr);
745       if (commit_len > len)
746         commit_len = len;
747
748       if (!VirtualAlloc (start_addr, commit_len, MEM_COMMIT,
749                          rec->gen_protect ()))
750         {
751           ret = MMAP_RAISE_SIGBUS;
752           break;
753         }
754
755       start_addr += commit_len;
756       len -= commit_len;
757       if (!len)
758         {
759           ret = MMAP_NORESERVE_COMMITED;
760           break;
761         }
762     }
763 out:
764   LIST_UNLOCK ();
765   return ret;
766 }
767
768 static caddr_t
769 mmap_worker (mmap_list *map_list, fhandler_base *fh, caddr_t base, size_t len,
770              int prot, int flags, int fd, _off64_t off, struct __stat64 *st)
771 {
772   HANDLE h = fh->mmap (&base, len, prot, flags, off);
773   if (h == INVALID_HANDLE_VALUE)
774     return NULL;
775   if (!map_list
776       && !(map_list = mmapped_areas.get_list_by_fd (fd, st))
777       && !(map_list = mmapped_areas.add_list (fd, st)))
778     {
779       fh->munmap (h, base, len);
780       return NULL;
781     }
782   mmap_record mmap_rec (fd, h, fh->get_access (), prot, flags, off, len, base);
783   mmap_record *rec = map_list->add_record (mmap_rec);
784   if (!rec)
785     {
786       fh->munmap (h, base, len);
787       return NULL;
788     }
789   return base;
790 }
791
792 extern "C" void *
793 mmap64 (void *addr, size_t len, int prot, int flags, int fd, _off64_t off)
794 {
795   syscall_printf ("addr %x, len %u, prot %x, flags %x, fd %d, off %D",
796                   addr, len, prot, flags, fd, off);
797
798   caddr_t ret = (caddr_t) MAP_FAILED;
799   fhandler_base *fh = NULL;
800   fhandler_disk_file *fh_disk_file = NULL; /* Used for reopening a disk file
801                                               when necessary. */
802   mmap_list *map_list = NULL;
803   size_t orig_len = 0;
804   caddr_t base = NULL;
805   struct __stat64 st;
806
807   DWORD pagesize = wincap.allocation_granularity ();
808
809   fh_anonymous.set_io_handle (INVALID_HANDLE_VALUE);
810   fh_anonymous.set_access (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE);
811
812   /* EINVAL error conditions. */
813   if (off % pagesize
814       || ((prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)))
815       || ((flags & MAP_TYPE) != MAP_SHARED
816           && (flags & MAP_TYPE) != MAP_PRIVATE)
817       || (fixed (flags) && ((uintptr_t) addr % pagesize))
818       || !len)
819     {
820       set_errno (EINVAL);
821       goto out;
822     }
823
824   if (!anonymous (flags) && fd != -1)
825     {
826       /* Ensure that fd is open */
827       cygheap_fdget cfd (fd);
828       if (cfd < 0)
829         goto out;
830
831       fh = cfd;
832
833       /* mmap /dev/zero is like MAP_ANONYMOUS. */
834       if (fh->get_device () == FH_ZERO)
835         flags |= MAP_ANONYMOUS;
836
837       /* The autoconf mmap test maps a file of size 1 byte.  It then tests
838          every byte of the entire mapped page of 64K for 0-bytes since that's
839          what POSIX requires.  The problem is, we can't create that mapping on
840          64 bit systems.  The file mapping will be only a single page, 4K, and
841          since 64 bit systems don't support the AT_ROUND_TO_PAGE flag, the
842          remainder of the 64K slot will result in a SEGV when accessed.
843
844          So, what we do here is cheating for the sake of the autoconf test
845          on 64 bit systems.  The justification is that there's very likely
846          no application actually utilizing the map beyond EOF, and we know that
847          all bytes beyond EOF are set to 0 anyway.  If this test doesn't work
848          on 64 bit systems, it will result in not using mmap at all in a
849          package.  But we want that mmap is treated as usable by autoconf,
850          regardless whether the autoconf test runs on a 32 bit or a 64 bit
851          system.
852
853          Ok, so we know exactly what autoconf is doing.  The file is called
854          "conftest.txt", it has a size of 1 byte, the mapping size is the
855          pagesize, the requested protection is PROT_READ | PROT_WRITE, the
856          mapping is MAP_SHARED, the offset is 0.
857
858          If all these requirements are given, we just return an anonymous map.
859          This will help to get over the autoconf test even on 64 bit systems.
860          The tests are ordered for speed. */
861       if (wincap.is_wow64 ())
862         {
863           UNICODE_STRING fname;
864           IO_STATUS_BLOCK io;
865           FILE_STANDARD_INFORMATION fsi;
866
867           if (len == pagesize
868               && prot == (PROT_READ | PROT_WRITE)
869               && flags == MAP_SHARED
870               && off == 0
871               && (RtlSplitUnicodePath (fh->pc.get_nt_native_path (), NULL,
872                                        &fname),
873                   wcscmp (fname.Buffer, L"conftest.txt") == 0)
874               && NT_SUCCESS (NtQueryInformationFile (fh->get_handle (), &io,
875                                                      &fsi, sizeof fsi,
876                                                      FileStandardInformation))
877               && fsi.EndOfFile.QuadPart == 1LL)
878             flags |= MAP_ANONYMOUS;
879         }
880     }
881
882   if (anonymous (flags) || fd == -1)
883     {
884       fh = &fh_anonymous;
885       fd = -1;
886       flags |= MAP_ANONYMOUS;
887       /* Anonymous mappings are always forced to pagesize length with
888          no offset. */
889       len = roundup2 (len, pagesize);
890       off = 0;
891     }
892   else if (fh->get_device () == FH_FS)
893     {
894       /* EACCES error conditions according to SUSv3.  File must be opened
895          for reading, regardless of the requested protection, and file must
896          be opened for writing when PROT_WRITE together with MAP_SHARED
897          is requested. */
898       if (!(fh->get_access () & GENERIC_READ)
899           || (!(fh->get_access () & GENERIC_WRITE)
900               && (prot & PROT_WRITE) && !priv (flags)))
901         {
902           set_errno (EACCES);
903           goto out;
904         }
905
906       /* You can't create mappings with PAGE_EXECUTE protection if
907          the file isn't explicitely opened with EXECUTE access. */
908       OBJECT_ATTRIBUTES attr;
909       NTSTATUS status;
910       HANDLE h;
911       IO_STATUS_BLOCK io;
912
913       InitializeObjectAttributes (&attr, &ro_u_empty, fh->pc.objcaseinsensitive (),
914                                   fh->get_handle (), NULL);
915       status = NtOpenFile (&h,
916                            fh->get_access () | GENERIC_EXECUTE | SYNCHRONIZE,
917                            &attr, &io, FILE_SHARE_VALID_FLAGS,
918                            FILE_SYNCHRONOUS_IO_NONALERT
919                            | FILE_OPEN_FOR_BACKUP_INTENT);
920       if (NT_SUCCESS (status))
921         {
922           fh_disk_file = new (ccalloc (HEAP_FHANDLER, 1, sizeof *fh_disk_file))
923                              fhandler_disk_file;
924           fh_disk_file->set_name (fh->pc);
925           fh_disk_file->set_io_handle (h);
926           fh_disk_file->set_access (fh->get_access () | GENERIC_EXECUTE);
927           fh = fh_disk_file;
928         }
929       else if (prot & PROT_EXEC)
930         {
931           /* TODO: To be or not to be... I'm opting for refusing this
932              mmap request rather than faking it, but that might break
933              some non-portable code. */
934           set_errno (EACCES);
935           goto out;
936         }
937
938       if (fh->fstat_fs (&st))
939         {
940           __seterrno ();
941           goto out;
942         }
943       _off64_t fsiz = st.st_size;
944
945       /* Don't allow file mappings beginning beyond EOF since Windows can't
946          handle that POSIX like, unless MAP_AUTOGROW flag is set, which
947          mimics Windows behaviour. */
948       if (off >= fsiz && !autogrow (flags))
949         {
950           /* Instead, it seems suitable to return an anonymous mapping of
951              the given size instead.  Mapped addresses beyond EOF aren't
952              written back to the file anyway, so the handling is identical
953              to other pages beyond EOF. */
954           fh = &fh_anonymous;
955           len = roundup2 (len, pagesize);
956           prot = PROT_READ | PROT_WRITE | __PROT_ATTACH;
957           flags &= MAP_FIXED;
958           flags |= MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
959           fd = -1;
960           off = 0;
961           goto go_ahead;
962         }
963       fsiz -= off;
964       /* We're creating the pages beyond EOF as reserved, anonymous pages.
965          Note that this isn't done in WOW64 environments since apparently
966          WOW64 does not support the AT_ROUND_TO_PAGE flag which is required
967          to get this right.  Too bad. */
968       if (!wincap.is_wow64 ()
969           && ((len > fsiz && !autogrow (flags))
970               || roundup2 (len, wincap.page_size ())
971                  < roundup2 (len, pagesize)))
972         orig_len = len;
973       if (len > fsiz)
974         {
975           if (autogrow (flags))
976             {
977               /* Allow mapping beyond EOF if MAP_AUTOGROW flag is set.
978                  Check if file has been opened for writing, otherwise
979                  MAP_AUTOGROW is invalid. */
980               if (!(fh->get_access () & GENERIC_WRITE))
981                 {
982                   set_errno (EINVAL);
983                   goto out;
984                 }
985             }
986           else
987             /* Otherwise, don't map beyond EOF, since Windows would change
988                the file to the new length, in contrast to POSIX. */
989             len = fsiz;
990         }
991
992       /* If the requested offset + len is <= file size, drop MAP_AUTOGROW.
993          This simplifes fhandler::mmap's job. */
994       if (autogrow (flags) && (off + len) <= fsiz)
995         flags &= ~MAP_AUTOGROW;
996     }
997
998 go_ahead:
999
1000   /* MAP_NORESERVE is only supported on private anonymous mappings.
1001      Remove that bit from flags so that later code doesn't have to
1002      test all bits. */
1003   if (noreserve (flags) && (!anonymous (flags) || !priv (flags)))
1004     flags &= ~MAP_NORESERVE;
1005
1006   LIST_LOCK ();
1007   map_list = mmapped_areas.get_list_by_fd (fd, &st);
1008
1009   /* Test if an existing anonymous mapping can be recycled. */
1010   if (map_list && anonymous (flags))
1011     {
1012       caddr_t tried = map_list->try_map (addr, len, flags, off);
1013       /* try_map returns NULL if no map matched, otherwise it returns
1014          a valid address, or MAP_FAILED in case of a fatal error. */
1015       if (tried)
1016         {
1017           ret = tried;
1018           goto out_with_unlock;
1019         }
1020     }
1021
1022   if (orig_len)
1023     {
1024       /* If the requested length is bigger than the file size, we try to
1025          allocate an area of the full size first.  This area is immediately
1026          deallocated and the address we got is used as base address for the
1027          subsequent real mappings.  This ensures that we have enough space
1028          for the whole thing. */
1029       orig_len = roundup2 (orig_len, pagesize);
1030       PVOID newaddr = VirtualAlloc (addr, orig_len, MEM_TOP_DOWN | MEM_RESERVE,
1031                                     PAGE_READWRITE);
1032       if (!newaddr)
1033         {
1034           /* If addr is not NULL, but MAP_FIXED isn't given, allow the OS
1035              to choose. */
1036           if (addr && !fixed (flags))
1037             newaddr = VirtualAlloc (NULL, orig_len, MEM_TOP_DOWN | MEM_RESERVE,
1038                                     PAGE_READWRITE);
1039           if (!newaddr)
1040             {
1041               __seterrno ();
1042               goto out_with_unlock;
1043             }
1044         }
1045       if (!VirtualFree (newaddr, 0, MEM_RELEASE))
1046         {
1047           __seterrno ();
1048           goto out_with_unlock;
1049         }
1050       addr = newaddr;
1051     }
1052
1053   base = mmap_worker (map_list, fh, (caddr_t) addr, len, prot, flags, fd, off,
1054                       &st);
1055   if (!base)
1056     goto out_with_unlock;
1057
1058   if (orig_len)
1059     {
1060       /* If the requested length is bigger than the file size, the
1061          remainder is created as anonymous mapping.  Actually two
1062          mappings are created, first the remainder from the file end to
1063          the next 64K boundary as accessible pages with the same
1064          protection as the file's pages, then as much pages as necessary
1065          to accomodate the requested length, but as reserved pages which
1066          raise a SIGBUS when trying to access them.  AT_ROUND_TO_PAGE
1067          and page protection on shared pages is only supported by 32 bit NT,
1068          so don't even try on WOW64.  This is accomplished by not setting
1069          orig_len on WOW64 above. */
1070 #if 0
1071       orig_len = roundup2 (orig_len, pagesize);
1072 #endif
1073       len = roundup2 (len, wincap.page_size ());
1074       if (orig_len - len)
1075         {
1076           orig_len -= len;
1077           size_t valid_page_len = orig_len % pagesize;
1078           size_t sigbus_page_len = orig_len - valid_page_len;
1079
1080           caddr_t at_base = base + len;
1081           if (valid_page_len)
1082             {
1083               prot |= __PROT_FILLER;
1084               flags &= MAP_SHARED | MAP_PRIVATE;
1085               flags |= MAP_ANONYMOUS | MAP_FIXED;
1086               at_base = mmap_worker (NULL, &fh_anonymous, at_base,
1087                                      valid_page_len, prot, flags, -1, 0, NULL);
1088               if (!at_base)
1089                 {
1090                   fh->munmap (fh->get_handle (), base, len);
1091                   set_errno (ENOMEM);
1092                   goto out_with_unlock;
1093                 }
1094               at_base += valid_page_len;
1095             }
1096           if (sigbus_page_len)
1097             {
1098               prot = PROT_READ | PROT_WRITE | __PROT_ATTACH;
1099               flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED;
1100               at_base = mmap_worker (NULL, &fh_anonymous, at_base,
1101                                      sigbus_page_len, prot, flags, -1, 0, NULL);
1102               if (!at_base)
1103                 debug_printf ("Warning: Mapping beyond EOF failed, %E");
1104             }
1105         }
1106     }
1107
1108   ret = base;
1109
1110 out_with_unlock:
1111   LIST_UNLOCK ();
1112
1113 out:
1114
1115   if (fh_disk_file)
1116     {
1117       NtClose (fh_disk_file->get_handle ());
1118       delete fh;
1119     }
1120
1121   syscall_printf ("%p = mmap() ", ret);
1122   return ret;
1123 }
1124
1125 extern "C" void *
1126 mmap (void *addr, size_t len, int prot, int flags, int fd, _off_t off)
1127 {
1128   return mmap64 (addr, len, prot, flags, fd, (_off64_t)off);
1129 }
1130
1131 /* munmap () removes all mmapped pages between addr and addr+len. */
1132
1133 extern "C" int
1134 munmap (void *addr, size_t len)
1135 {
1136   syscall_printf ("munmap (addr %x, len %u)", addr, len);
1137
1138   /* Error conditions according to SUSv3 */
1139   if (!addr || !len || check_invalid_virtual_addr (addr, len))
1140     {
1141       set_errno (EINVAL);
1142       return -1;
1143     }
1144   size_t pagesize = wincap.allocation_granularity ();
1145   if (((uintptr_t) addr % pagesize) || !len)
1146     {
1147       set_errno (EINVAL);
1148       return -1;
1149     }
1150   len = roundup2 (len, pagesize);
1151
1152   LIST_LOCK ();
1153
1154   /* Iterate through the map, unmap pages between addr and addr+len
1155      in all maps. */
1156   mmap_list *map_list, *next_map_list;
1157   LIST_FOREACH_SAFE (map_list, &mmapped_areas.lists, ml_next, next_map_list)
1158     {
1159       mmap_record *rec, *next_rec;
1160       caddr_t u_addr;
1161       DWORD u_len;
1162
1163       LIST_FOREACH_SAFE (rec, &map_list->recs, mr_next, next_rec)
1164         {
1165           if (!rec->match ((caddr_t) addr, len, u_addr, u_len))
1166             continue;
1167           if (rec->unmap_pages (u_addr, u_len))
1168             {
1169               /* The whole record has been unmapped, so we now actually
1170                  unmap it from the system in full length... */
1171               fhandler_base *fh = rec->alloc_fh ();
1172               fh->munmap (rec->get_handle (),
1173                           rec->get_address (),
1174                           rec->get_len ());
1175               rec->free_fh (fh);
1176
1177               /* ...and delete the record. */
1178               if (map_list->del_record (rec))
1179                 {
1180                   /* Yay, the last record has been removed from the list,
1181                      we can remove the list now, too. */
1182                   mmapped_areas.del_list (map_list);
1183                   break;
1184                 }
1185             }
1186         }
1187     }
1188
1189   LIST_UNLOCK ();
1190   syscall_printf ("0 = munmap(): %x", addr);
1191   return 0;
1192 }
1193
1194 /* Sync file with memory. Ignore flags for now. */
1195
1196 extern "C" int
1197 msync (void *addr, size_t len, int flags)
1198 {
1199   int ret = -1;
1200   mmap_list *map_list;
1201
1202   syscall_printf ("msync (addr: %p, len %u, flags %x)", addr, len, flags);
1203
1204   pthread_testcancel ();
1205
1206   LIST_LOCK ();
1207
1208   if (((uintptr_t) addr % wincap.allocation_granularity ())
1209       || (flags & ~(MS_ASYNC | MS_SYNC | MS_INVALIDATE))
1210       || ((flags & (MS_ASYNC | MS_SYNC)) == (MS_ASYNC | MS_SYNC)))
1211     {
1212       set_errno (EINVAL);
1213       goto out;
1214     }
1215 #if 0 /* If I only knew why I did that... */
1216   len = roundup2 (len, wincap.allocation_granularity ());
1217 #endif
1218
1219   /* Iterate through the map, looking for the mmapped area.
1220      Error if not found. */
1221   LIST_FOREACH (map_list, &mmapped_areas.lists, ml_next)
1222     {
1223       mmap_record *rec;
1224       LIST_FOREACH (rec, &map_list->recs, mr_next)
1225         {
1226           if (rec->access ((caddr_t) addr))
1227             {
1228               /* Check whole area given by len. */
1229               for (DWORD i = wincap.allocation_granularity ();
1230                    i < len;
1231                    i += wincap.allocation_granularity ())
1232                 if (!rec->access ((caddr_t) addr + i))
1233                   {
1234                     set_errno (ENOMEM);
1235                     goto out;
1236                   }
1237               fhandler_base *fh = rec->alloc_fh ();
1238               ret = fh->msync (rec->get_handle (), (caddr_t) addr, len, flags);
1239               rec->free_fh (fh);
1240               goto out;
1241             }
1242         }
1243     }
1244
1245   /* No matching mapping exists. */
1246   set_errno (ENOMEM);
1247
1248 out:
1249   LIST_UNLOCK ();
1250   syscall_printf ("%R = msync()", ret);
1251   return ret;
1252 }
1253
1254 /* Set memory protection */
1255
1256 extern "C" int
1257 mprotect (void *addr, size_t len, int prot)
1258 {
1259   bool in_mapped = false;
1260   bool ret = false;
1261   DWORD old_prot;
1262   DWORD new_prot = 0;
1263
1264   syscall_printf ("mprotect (addr: %p, len %u, prot %x)", addr, len, prot);
1265
1266   /* See comment in mmap64 for a description. */
1267   size_t pagesize = wincap.allocation_granularity ();
1268   if ((uintptr_t) addr % pagesize)
1269     {
1270       set_errno (EINVAL);
1271       goto out;
1272     }
1273   len = roundup2 (len, pagesize);
1274
1275   LIST_LOCK ();
1276
1277   /* Iterate through the map, protect pages between addr and addr+len
1278      in all maps. */
1279   mmap_list *map_list;
1280   LIST_FOREACH (map_list, &mmapped_areas.lists, ml_next)
1281     {
1282       mmap_record *rec;
1283       caddr_t u_addr;
1284       DWORD u_len;
1285
1286       LIST_FOREACH (rec, &map_list->recs, mr_next)
1287         {
1288           if (!rec->match ((caddr_t) addr, len, u_addr, u_len))
1289             continue;
1290           in_mapped = true;
1291           if (rec->attached ())
1292             continue;
1293           new_prot = gen_protect (prot, rec->get_flags ());
1294           if (rec->noreserve ())
1295             {
1296               if (new_prot == PAGE_NOACCESS)
1297                 ret = VirtualFree (u_addr, u_len, MEM_DECOMMIT);
1298               else
1299                 ret = !!VirtualAlloc (u_addr, u_len, MEM_COMMIT, new_prot);
1300             }
1301           else
1302             ret = VirtualProtect (u_addr, u_len, new_prot, &old_prot);
1303           if (!ret)
1304             {
1305               __seterrno ();
1306               break;
1307             }
1308         }
1309     }
1310
1311   LIST_UNLOCK ();
1312
1313   if (!in_mapped)
1314     {
1315       int flags = 0;
1316       MEMORY_BASIC_INFORMATION mbi;
1317
1318       ret = VirtualQuery (addr, &mbi, sizeof mbi);
1319       if (ret)
1320         {
1321           /* If write protection is requested, check if the page was
1322              originally protected writecopy.  In this case call VirtualProtect
1323              requesting PAGE_WRITECOPY, otherwise the VirtualProtect will fail
1324              on NT version >= 5.0 */
1325           if (prot & PROT_WRITE)
1326             {
1327               if (mbi.AllocationProtect == PAGE_WRITECOPY
1328                   || mbi.AllocationProtect == PAGE_EXECUTE_WRITECOPY)
1329                 flags = MAP_PRIVATE;
1330             }
1331           new_prot = gen_protect (prot, flags);
1332           if (new_prot != PAGE_NOACCESS && mbi.State == MEM_RESERVE)
1333             ret = VirtualAlloc (addr, len, MEM_COMMIT, new_prot);
1334           else
1335             ret = VirtualProtect (addr, len, new_prot, &old_prot);
1336         }
1337       if (!ret)
1338         __seterrno ();
1339     }
1340
1341 out:
1342
1343   syscall_printf ("%R = mprotect ()", ret ? 0 : -1);
1344   return ret ? 0 : -1;
1345 }
1346
1347 extern "C" int
1348 mlock (const void *addr, size_t len)
1349 {
1350   int ret = -1;
1351
1352   /* Align address and length values to page size. */
1353   size_t pagesize = wincap.allocation_granularity ();
1354   PVOID base = (PVOID) rounddown((uintptr_t) addr, pagesize);
1355   ULONG size = roundup2 (((uintptr_t) addr - (uintptr_t) base) + len, pagesize);
1356   NTSTATUS status = 0;
1357   do
1358     {
1359       status = NtLockVirtualMemory (NtCurrentProcess (), &base, &size,
1360                                     MAP_PROCESS);
1361       if (status == STATUS_WORKING_SET_QUOTA)
1362         {
1363           /* The working set is too small, try to increase it so that the
1364              requested locking region fits in.  Unfortunately I don't know
1365              any function which would return the currently locked pages of
1366              a process (no go with NtQueryVirtualMemory).
1367
1368              So, except for the border cases, what we do here is something
1369              really embarrassing.  We raise the working set by 64K at a time
1370              and retry, until either we fail to raise the working set size
1371              further, or until NtLockVirtualMemory returns successfully (or
1372              with another error).  */
1373           ULONG min, max;
1374           if (!GetProcessWorkingSetSize (GetCurrentProcess (), &min, &max))
1375             {
1376               set_errno (ENOMEM);
1377               break;
1378             }
1379           if (min < size)
1380             min = size + pagesize;
1381           else if (size < pagesize)
1382             min += size;
1383           else
1384             min += pagesize;
1385           if (max < min)
1386             max = min;
1387           if (!SetProcessWorkingSetSize (GetCurrentProcess (), min, max))
1388             {
1389               set_errno (ENOMEM);
1390               break;
1391             }
1392         }
1393       else if (!NT_SUCCESS (status))
1394         __seterrno_from_nt_status (status);
1395       else
1396         ret = 0;
1397     }
1398   while (status == STATUS_WORKING_SET_QUOTA);
1399
1400   syscall_printf ("%R = mlock(%p, %u)", ret, addr, len);
1401   return ret;
1402 }
1403
1404 extern "C" int
1405 munlock (const void *addr, size_t len)
1406 {
1407   int ret = -1;
1408
1409   /* Align address and length values to page size. */
1410   size_t pagesize = wincap.allocation_granularity ();
1411   PVOID base = (PVOID) rounddown((uintptr_t) addr, pagesize);
1412   ULONG size = roundup2 (((uintptr_t) addr - (uintptr_t) base) + len, pagesize);
1413   NTSTATUS status = NtUnlockVirtualMemory (NtCurrentProcess (), &base, &size,
1414                                            MAP_PROCESS);
1415   if (!NT_SUCCESS (status))
1416     __seterrno_from_nt_status (status);
1417   else
1418     ret = 0;
1419
1420   syscall_printf ("%R = munlock(%p, %u)", ret, addr, len);
1421   return ret;
1422 }
1423
1424 extern "C" int
1425 posix_madvise (void *addr, size_t len, int advice)
1426 {
1427   int ret;
1428   /* Check parameters. */
1429   if (advice < POSIX_MADV_NORMAL || advice > POSIX_MADV_DONTNEED
1430       || !len)
1431     ret = EINVAL;
1432   else
1433     {
1434       /* Check requested memory area. */
1435       MEMORY_BASIC_INFORMATION m;
1436       char *p = (char *) addr;
1437       char *endp = p + len;
1438       while (p < endp)
1439         {
1440           if (!VirtualQuery (p, &m, sizeof m) || m.State == MEM_FREE)
1441             {
1442               ret = ENOMEM;
1443               break;
1444             }
1445           p = (char *) m.BaseAddress + m.RegionSize;
1446         }
1447       ret = 0;
1448     }
1449
1450   syscall_printf ("%d = posix_madvise(%p, %u, %d)", ret, addr, len, advice);
1451   /* Eventually do nothing. */
1452   return 0;
1453 }
1454
1455 /*
1456  * Base implementation:
1457  *
1458  * `mmap' returns ENODEV as documented in SUSv2.
1459  * In contrast to the global function implementation, the member function
1460  * `mmap' has to return the mapped base address in `addr' and the handle to
1461  * the mapping object as return value. In case of failure, the fhandler
1462  * mmap has to close that handle by itself and return INVALID_HANDLE_VALUE.
1463  *
1464  * `munmap' and `msync' get the handle to the mapping object as first parameter
1465  * additionally.
1466 */
1467 HANDLE
1468 fhandler_base::mmap (caddr_t *addr, size_t len, int prot,
1469                      int flags, _off64_t off)
1470 {
1471   set_errno (ENODEV);
1472   return INVALID_HANDLE_VALUE;
1473 }
1474
1475 int
1476 fhandler_base::munmap (HANDLE h, caddr_t addr, size_t len)
1477 {
1478   set_errno (ENODEV);
1479   return -1;
1480 }
1481
1482 int
1483 fhandler_base::msync (HANDLE h, caddr_t addr, size_t len, int flags)
1484 {
1485   set_errno (ENODEV);
1486   return -1;
1487 }
1488
1489 bool
1490 fhandler_base::fixup_mmap_after_fork (HANDLE h, int prot, int flags,
1491                                       _off64_t offset, DWORD size,
1492                                       void *address)
1493 {
1494   set_errno (ENODEV);
1495   return -1;
1496 }
1497
1498 /* Implementation for anonymous maps.  Using fhandler_dev_zero looks
1499    quite the natural way. */
1500 HANDLE
1501 fhandler_dev_zero::mmap (caddr_t *addr, size_t len, int prot,
1502                          int flags, _off64_t off)
1503 {
1504   HANDLE h;
1505   void *base;
1506
1507   if (priv (flags) && !filler (prot))
1508     {
1509       /* Private anonymous maps are now implemented using VirtualAlloc.
1510          This has two advantages:
1511
1512          - VirtualAlloc has a smaller footprint than a copy-on-write
1513            anonymous map.
1514
1515          - It supports decommitting using VirtualFree, in contrast to
1516            section maps.  This allows minimum footprint private maps,
1517            when using the (non-POSIX, yay-Linux) MAP_NORESERVE flag.
1518       */
1519       DWORD protect = gen_protect (prot, flags);
1520       DWORD alloc_type = MEM_TOP_DOWN | MEM_RESERVE
1521                          | (noreserve (flags) ? 0 : MEM_COMMIT);
1522       base = VirtualAlloc (*addr, len, alloc_type, protect);
1523       if (!base && addr && !fixed (flags))
1524         base = VirtualAlloc (NULL, len, alloc_type, protect);
1525       if (!base || (fixed (flags) && base != *addr))
1526         {
1527           if (!base)
1528             __seterrno ();
1529           else
1530             {
1531               VirtualFree (base, 0, MEM_RELEASE);
1532               set_errno (EINVAL);
1533               debug_printf ("VirtualAlloc: address shift with MAP_FIXED given");
1534             }
1535           return INVALID_HANDLE_VALUE;
1536         }
1537       h = (HANDLE) 1; /* Fake handle to indicate success. */
1538     }
1539   else
1540     {
1541       h = CreateMapping (get_handle (), len, off, get_access (), prot, flags);
1542       if (!h)
1543         {
1544           __seterrno ();
1545           debug_printf ("CreateMapping failed with %E");
1546           return INVALID_HANDLE_VALUE;
1547         }
1548
1549       base = MapView (h, *addr, len, get_access(), prot, flags, off);
1550       if (!base || (fixed (flags) && base != *addr))
1551         {
1552           if (!base)
1553             __seterrno ();
1554           else
1555             {
1556               NtUnmapViewOfSection (NtCurrentProcess (), base);
1557               set_errno (EINVAL);
1558               debug_printf ("MapView: address shift with MAP_FIXED given");
1559             }
1560           NtClose (h);
1561           return INVALID_HANDLE_VALUE;
1562         }
1563     }
1564   *addr = (caddr_t) base;
1565   return h;
1566 }
1567
1568 int
1569 fhandler_dev_zero::munmap (HANDLE h, caddr_t addr, size_t len)
1570 {
1571   if (h == (HANDLE) 1)  /* See fhandler_dev_zero::mmap. */
1572     VirtualFree (addr, 0, MEM_RELEASE);
1573   else
1574     {
1575       NtUnmapViewOfSection (NtCurrentProcess (), addr);
1576       NtClose (h);
1577     }
1578   return 0;
1579 }
1580
1581 int
1582 fhandler_dev_zero::msync (HANDLE h, caddr_t addr, size_t len, int flags)
1583 {
1584   return 0;
1585 }
1586
1587 bool
1588 fhandler_dev_zero::fixup_mmap_after_fork (HANDLE h, int prot, int flags,
1589                                       _off64_t offset, DWORD size,
1590                                       void *address)
1591 {
1592   /* Re-create the map */
1593   void *base;
1594   if (priv (flags) && !filler (prot))
1595     {
1596       DWORD alloc_type = MEM_RESERVE | (noreserve (flags) ? 0 : MEM_COMMIT);
1597       /* Always allocate R/W so that ReadProcessMemory doesn't fail
1598          due to a non-writable target address.  The protection is
1599          set to the correct one anyway in the fixup loop. */
1600       base = VirtualAlloc (address, size, alloc_type, PAGE_READWRITE);
1601     }
1602   else
1603     base = MapView (h, address, size, get_access (), prot, flags, offset);
1604   if (base != address)
1605     {
1606       MEMORY_BASIC_INFORMATION m;
1607       VirtualQuery (address, &m, sizeof (m));
1608       system_printf ("requested %p != %p mem alloc base %p, state %p, "
1609                      "size %d, %E", address, base, m.AllocationBase, m.State,
1610                      m.RegionSize);
1611     }
1612   return base == address;
1613 }
1614
1615 /* Implementation for disk files and anonymous mappings. */
1616 HANDLE
1617 fhandler_disk_file::mmap (caddr_t *addr, size_t len, int prot,
1618                           int flags, _off64_t off)
1619 {
1620   HANDLE h = CreateMapping (get_handle (), len, off, get_access (),
1621                             prot, flags);
1622   if (!h)
1623     {
1624       __seterrno ();
1625       debug_printf ("CreateMapping failed with %E");
1626       return INVALID_HANDLE_VALUE;
1627     }
1628
1629   void *base = MapView (h, *addr, len, get_access (), prot, flags, off);
1630   if (!base || (fixed (flags) && base != *addr))
1631     {
1632       if (!base)
1633         __seterrno ();
1634       else
1635         {
1636           NtUnmapViewOfSection (NtCurrentProcess (), base);
1637           set_errno (EINVAL);
1638           debug_printf ("MapView: address shift with MAP_FIXED given");
1639         }
1640       NtClose (h);
1641       return INVALID_HANDLE_VALUE;
1642     }
1643
1644   *addr = (caddr_t) base;
1645   return h;
1646 }
1647
1648 int
1649 fhandler_disk_file::munmap (HANDLE h, caddr_t addr, size_t len)
1650 {
1651   NtUnmapViewOfSection (NtCurrentProcess (), addr);
1652   NtClose (h);
1653   return 0;
1654 }
1655
1656 int
1657 fhandler_disk_file::msync (HANDLE h, caddr_t addr, size_t len, int flags)
1658 {
1659   if (FlushViewOfFile (addr, len) == 0)
1660     {
1661       __seterrno ();
1662       return -1;
1663     }
1664   return 0;
1665 }
1666
1667 bool
1668 fhandler_disk_file::fixup_mmap_after_fork (HANDLE h, int prot, int flags,
1669                                            _off64_t offset, DWORD size,
1670                                            void *address)
1671 {
1672   /* Re-create the map */
1673   void *base = MapView (h, address, size, get_access (), prot, flags, offset);
1674   if (base != address)
1675     {
1676       MEMORY_BASIC_INFORMATION m;
1677       VirtualQuery (address, &m, sizeof (m));
1678       system_printf ("requested %p != %p mem alloc base %p, state %p, "
1679                      "size %d, %E", address, base, m.AllocationBase, m.State,
1680                      m.RegionSize);
1681     }
1682   return base == address;
1683 }
1684
1685 HANDLE
1686 fhandler_dev_mem::mmap (caddr_t *addr, size_t len, int prot,
1687                         int flags, _off64_t off)
1688 {
1689   if (off >= mem_size
1690       || (DWORD) len >= mem_size
1691       || off + len >= mem_size)
1692     {
1693       set_errno (EINVAL);
1694       debug_printf ("-1 = mmap(): illegal parameter, set EINVAL");
1695       return INVALID_HANDLE_VALUE;
1696     }
1697
1698   OBJECT_ATTRIBUTES attr;
1699   InitializeObjectAttributes (&attr, &ro_u_pmem,
1700                               OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
1701                               NULL, NULL);
1702
1703   /* Section access is bit-wise ored, while on the Win32 level access
1704      is only one of the values.  It's not quite clear if the section
1705      access has to be defined this way, or if SECTION_ALL_ACCESS would
1706      be sufficient but this worked fine so far, so why change? */
1707   ACCESS_MASK section_access;
1708   if (prot & PROT_WRITE)
1709     section_access = SECTION_MAP_READ | SECTION_MAP_WRITE;
1710   else
1711     section_access = SECTION_MAP_READ;
1712
1713   HANDLE h;
1714   NTSTATUS status = NtOpenSection (&h, section_access, &attr);
1715   if (!NT_SUCCESS (status))
1716     {
1717       __seterrno_from_nt_status (status);
1718       debug_printf ("-1 = mmap(): NtOpenSection failed with %E");
1719       return INVALID_HANDLE_VALUE;
1720     }
1721
1722   void *base = MapView (h, *addr, len, get_access (), prot,
1723                         flags | MAP_ANONYMOUS, off);
1724   if (!base || (fixed (flags) && base != *addr))
1725     {
1726       if (!base)
1727         __seterrno ();
1728       else
1729         {
1730           NtUnmapViewOfSection (NtCurrentProcess (), base);
1731           set_errno (EINVAL);
1732           debug_printf ("MapView: address shift with MAP_FIXED given");
1733         }
1734       NtClose (h);
1735       return INVALID_HANDLE_VALUE;
1736     }
1737
1738   *addr = (caddr_t) base;
1739   return h;
1740 }
1741
1742 int
1743 fhandler_dev_mem::munmap (HANDLE h, caddr_t addr, size_t len)
1744 {
1745   NTSTATUS status;
1746   if (!NT_SUCCESS (status = NtUnmapViewOfSection (NtCurrentProcess (), addr)))
1747     {
1748       __seterrno_from_nt_status (status);
1749       return -1;
1750     }
1751   NtClose (h);
1752   return 0;
1753 }
1754
1755 int
1756 fhandler_dev_mem::msync (HANDLE h, caddr_t addr, size_t len, int flags)
1757 {
1758   return 0;
1759 }
1760
1761 bool
1762 fhandler_dev_mem::fixup_mmap_after_fork (HANDLE h, int prot, int flags,
1763                                          _off64_t offset, DWORD size,
1764                                          void *address)
1765 {
1766   void *base = MapView (h, address, size, get_access (), prot,
1767                         flags | MAP_ANONYMOUS, offset);
1768   if (base != address)
1769     {
1770       MEMORY_BASIC_INFORMATION m;
1771       VirtualQuery (address, &m, sizeof (m));
1772       system_printf ("requested %p != %p mem alloc base %p, state %p, "
1773                      "size %d, %E", address, base, m.AllocationBase, m.State,
1774                      m.RegionSize);
1775     }
1776   return base == address;
1777 }
1778
1779 /* Call to re-create all the file mappings in a forked child. Called from
1780    the child in initialization. At this point we are passed a valid
1781    mmapped_areas map, and all the HANDLE's are valid for the child, but
1782    none of the mapped areas are in our address space. We need to iterate
1783    through the map, doing the MapViewOfFile calls.  */
1784
1785 int __stdcall
1786 fixup_mmaps_after_fork (HANDLE parent)
1787 {
1788   /* Iterate through the map */
1789   mmap_list *map_list;
1790   LIST_FOREACH (map_list, &mmapped_areas.lists, ml_next)
1791     {
1792       mmap_record *rec;
1793       LIST_FOREACH (rec, &map_list->recs, mr_next)
1794         {
1795           debug_printf ("fd %d, h 0x%x, address %p, len 0x%x, prot: 0x%x, "
1796                         "flags: 0x%x, offset %X",
1797                         rec->get_fd (), rec->get_handle (), rec->get_address (),
1798                         rec->get_len (), rec->get_prot (), rec->get_flags (),
1799                         rec->get_offset ());
1800
1801           fhandler_base *fh = rec->alloc_fh ();
1802           bool ret = fh->fixup_mmap_after_fork (rec->get_handle (),
1803                                                 rec->get_prot (),
1804                                                 rec->get_flags () | MAP_FIXED,
1805                                                 rec->get_offset (),
1806                                                 rec->get_len (),
1807                                                 rec->get_address ());
1808           rec->free_fh (fh);
1809
1810           if (!ret)
1811             {
1812               if (rec->attached ())
1813                 {
1814                   system_printf ("Warning: Fixup mapping beyond EOF failed");
1815                   continue;
1816                 }
1817               return -1;
1818             }
1819
1820           MEMORY_BASIC_INFORMATION mbi;
1821           DWORD old_prot;
1822
1823           for (char *address = rec->get_address ();
1824                address < rec->get_address () + rec->get_len ();
1825                address += mbi.RegionSize)
1826             {
1827               if (!VirtualQueryEx (parent, address, &mbi, sizeof mbi))
1828                 {
1829                   system_printf ("VirtualQueryEx failed for MAP_PRIVATE "
1830                                  "address %p, %E", address);
1831                   return -1;
1832                 }
1833               /* Just skip reserved pages. */
1834               if (mbi.State == MEM_RESERVE)
1835                 continue;
1836               /* Copy-on-write pages must be copied to the child to circumvent
1837                  a strange notion how copy-on-write is supposed to work. */
1838               if (rec->priv ())
1839                 {
1840                   if (rec->noreserve ()
1841                       && !VirtualAlloc (address, mbi.RegionSize,
1842                                         MEM_COMMIT, PAGE_READWRITE))
1843                     {
1844                       system_printf ("VirtualAlloc failed for MAP_PRIVATE "
1845                                      "address %p, %E", address);
1846                       return -1;
1847                     }
1848                   if (mbi.Protect == PAGE_NOACCESS
1849                       && !VirtualProtectEx (parent, address, mbi.RegionSize,
1850                                             PAGE_READONLY, &old_prot))
1851                     {
1852                       system_printf ("VirtualProtectEx failed for MAP_PRIVATE "
1853                                      "address %p, %E", address);
1854                       return -1;
1855                     }
1856                   else if ((mbi.AllocationProtect == PAGE_WRITECOPY
1857                             || mbi.AllocationProtect == PAGE_EXECUTE_WRITECOPY)
1858                            && (mbi.Protect == PAGE_READWRITE
1859                                || mbi.Protect == PAGE_EXECUTE_READWRITE))
1860                     /* A WRITECOPY page which has been written to is set to
1861                        READWRITE, but that's an incompatible protection to
1862                        set the page to.  Convert the protection to WRITECOPY
1863                        so that the below VirtualProtect doesn't fail. */
1864                     mbi.Protect <<= 1;
1865
1866                   if (!ReadProcessMemory (parent, address, address,
1867                                           mbi.RegionSize, NULL))
1868                     {
1869                       system_printf ("ReadProcessMemory failed for MAP_PRIVATE "
1870                                      "address %p, %E", address);
1871                       return -1;
1872                     }
1873                   if (mbi.Protect == PAGE_NOACCESS
1874                       && !VirtualProtectEx (parent, address, mbi.RegionSize,
1875                                             PAGE_NOACCESS, &old_prot))
1876                     {
1877                       system_printf ("WARNING: VirtualProtectEx to return to "
1878                                      "PAGE_NOACCESS state in parent failed for "
1879                                      "MAP_PRIVATE address %p, %E", address);
1880                       return -1;
1881                     }
1882                 }
1883               /* Set child page protection to parent protection */
1884               if (!VirtualProtect (address, mbi.RegionSize,
1885                                    mbi.Protect, &old_prot))
1886                 {
1887                   MEMORY_BASIC_INFORMATION m;
1888                   VirtualQuery (address, &m, sizeof m);
1889                   system_printf ("VirtualProtect failed for "
1890                                  "address %p, "
1891                                  "parentstate: 0x%x, "
1892                                  "state: 0x%x, "
1893                                  "parentprot: 0x%x, "
1894                                  "prot: 0x%x, %E",
1895                                  address, mbi.State, m.State,
1896                                  mbi.Protect, m.Protect);
1897                   return -1;
1898                 }
1899             }
1900         }
1901     }
1902
1903   debug_printf ("succeeded");
1904   return 0;
1905 }