~ chicken-core (chicken-5) 9eea204cb79bdd300cabdcf3ae229ad4102276e1


commit 9eea204cb79bdd300cabdcf3ae229ad4102276e1
Author:     felix <felix@call-with-current-continuation.org>
AuthorDate: Tue Apr 9 23:16:43 2013 +0200
Commit:     Christian Kellermann <ckeen@pestilenz.org>
CommitDate: Wed Apr 10 19:40:09 2013 +0200

    added initial support for memory-mapped files on Windows (contributed by rivo)
    
    Signed-off-by: felix <felix@call-with-current-continuation.org>
    Signed-off-by: Christian Kellermann <ckeen@pestilenz.org>

diff --git a/NEWS b/NEWS
index 018d57ad..b013a84f 100644
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,7 @@
   - read-line no longer returns trailing CRs in rare cases on TCP ports (#568)
   - write and pp now correctly use escape sequences for control characters
      (thanks to Florian Zumbiehl)
+  - posix: memory-mapped file support for Windows (thanks to "rivo")
 
 - Runtime system
   - Special events in poll() are now handled, avoiding hangs in threaded apps.
diff --git a/manual/Unit posix b/manual/Unit posix
index 441f811a..2606e86c 100644
--- a/manual/Unit posix	
+++ b/manual/Unit posix	
@@ -1460,9 +1460,6 @@ Microsoft tools or with MinGW):
  file-truncate
  file-lock  file-lock/blocking  file-unlock  file-test-lock
  create-fifo  fifo?
- prot/...
- map/...
- map-file-to-memory  unmap-file-from-memory  memory-mapped-file-pointer  memory-mapped-file?
  set-alarm!
  terminal-port?  terminal-name
  process-fork  process-signal
diff --git a/posixwin.scm b/posixwin.scm
index d2cc9273..3d28e642 100644
--- a/posixwin.scm
+++ b/posixwin.scm
@@ -1686,6 +1686,165 @@ EOF
 	(##sys#error 'current-user-name "cannot retrieve current user-name") ) ) )
 
 
+;;; memory mapped files
+
+#>
+#define PROT_NONE       0
+#define PROT_READ       1
+#define PROT_WRITE      2
+#define PROT_EXEC       4
+#define MAP_FILE        0
+#define MAP_SHARED      1
+#define MAP_PRIVATE     2
+#define MAP_FIXED       0x10
+#define MAP_ANONYMOUS   0x20
+
+// This value is available starting with Windows XP with SP2 
+// and Windows Server 2003 with SP1.
+#ifndef FILE_MAP_EXECUTE
+#define FILE_MAP_EXECUTE 0x20
+#endif//FILE_MAP_EXECUTE
+
+static int page_flags[] =
+{
+    0,
+    PAGE_READONLY,
+    PAGE_READWRITE,
+    PAGE_READWRITE,
+    PAGE_EXECUTE_READ,
+    PAGE_EXECUTE_READ,
+    PAGE_EXECUTE_READWRITE
+};
+
+static int file_flags[] =
+{
+    0,
+    FILE_MAP_READ,
+    FILE_MAP_READ|FILE_MAP_WRITE,
+    FILE_MAP_READ|FILE_MAP_WRITE,
+    FILE_MAP_READ|FILE_MAP_EXECUTE,
+    FILE_MAP_READ|FILE_MAP_EXECUTE,
+    FILE_MAP_READ|FILE_MAP_WRITE|FILE_MAP_EXECUTE
+};
+
+void* mmap(void* addr,int len,int prot,int flags,int fd,int off)
+{
+    HANDLE hMap;
+    HANDLE hFile;
+
+    void* ptr;
+
+    if ((flags & MAP_FIXED) || (flags & MAP_PRIVATE) || (flags & MAP_ANONYMOUS))
+    {
+        errno = EINVAL;
+        return (void*)-1;
+    }
+
+    hFile = _get_osfhandle(fd);
+    if (hFile == INVALID_HANDLE_VALUE)
+    {
+        return (void*)-1;
+    }
+
+    hMap = CreateFileMapping(
+            hFile,
+            NULL,
+            page_flags[prot & (PROT_READ|PROT_WRITE|PROT_EXEC)],
+            0,
+            0,
+            NULL);
+
+    if (hMap == INVALID_HANDLE_VALUE)
+    {
+        set_last_errno();
+        return (void*)-1;
+    }
+
+    ptr = MapViewOfFile(
+            hMap,
+            file_flags[prot & (PROT_READ|PROT_WRITE|PROT_EXEC)],
+            0,
+            off,
+            len);
+
+    if (ptr == NULL)
+    {
+        set_last_errno();
+        ptr = (void*)-1;
+    }
+
+    CloseHandle(hMap);
+
+    return ptr;
+}
+
+int munmap(void* addr,int len)
+{
+    if (UnmapViewOfFile(addr))
+    {
+        errno = 0;
+        return 0;
+    }
+    set_last_errno();
+    return -1;
+}
+
+int is_bad_mmap(void* p)
+{
+    void* bad_ptr;
+    bad_ptr = (void*)-1;
+    return p == bad_ptr;
+}
+<#
+
+(define-foreign-variable _prot_none int "PROT_NONE")
+(define-foreign-variable _prot_read int "PROT_READ")
+(define-foreign-variable _prot_write int "PROT_WRITE")
+(define-foreign-variable _prot_exec int "PROT_EXEC")
+(define-foreign-variable _map_file int "MAP_FILE")
+(define-foreign-variable _map_shared int "MAP_SHARED")
+(define-foreign-variable _map_fixed int "MAP_FIXED")
+(define-foreign-variable _map_private int "MAP_PRIVATE")
+(define-foreign-variable _map_anonymous int "MAP_ANONYMOUS")
+
+(define prot/none _prot_none)
+(define prot/read _prot_read)
+(define prot/write _prot_write)
+(define prot/exec _prot_exec)
+(define map/file _map_file)
+(define map/shared _map_shared)
+(define map/private _map_private)
+(define map/fixed _map_fixed)
+(define map/anonymous _map_anonymous)
+
+(define map-file-to-memory
+  (let ([mmap (foreign-lambda c-pointer "mmap" c-pointer integer int int int integer)]
+        [bad-mmap? (foreign-lambda bool "is_bad_mmap" c-pointer)] )
+    (lambda (addr len prot flag fd . off)
+      (let ([addr (if (not addr) (##sys#null-pointer) addr)]
+            [off (if (pair? off) (car off) 0)] )
+        (unless (and (##core#inline "C_blockp" addr) (##core#inline "C_specialp" addr))
+          (##sys#signal-hook #:type-error 'map-file-to-memory "bad argument type - not a foreign pointer" addr) )
+        (let ([addr2 (mmap addr len prot flag fd off)])
+          (when (bad-mmap? addr2)
+            (posix-error #:file-error 'map-file-to-memory "cannot map file to memory" addr len prot flag fd off) )
+          (##sys#make-structure 'mmap addr2 len) ) ) ) ) )
+
+(define unmap-file-from-memory
+  (let ([munmap (foreign-lambda int "munmap" c-pointer integer)] )
+    (lambda (mmap . len)
+      (##sys#check-structure mmap 'mmap 'unmap-file-from-memory)
+      (let ([len (if (pair? len) (car len) (##sys#slot mmap 2))])
+        (unless (eq? 0 (munmap (##sys#slot mmap 1) len))
+      (posix-error #:file-error 'unmap-file-from-memory "cannot unmap file from memory" mmap len) ) ) ) ) )
+
+(define (memory-mapped-file-pointer mmap)
+  (##sys#check-structure mmap 'mmap 'memory-mapped-file-pointer)
+  (##sys#slot mmap 1) )
+
+(define (memory-mapped-file? x)
+  (##sys#structure? x 'mmap) )
+
 ;;; unimplemented stuff:
 
 (define-syntax define-unimplemented
@@ -1704,7 +1863,6 @@ EOF
 (define-unimplemented current-effective-user-name)
 (define-unimplemented current-group-id)
 (define-unimplemented current-user-id)
-(define-unimplemented map-file-to-memory)
 (define-unimplemented file-link)
 (define-unimplemented file-lock)
 (define-unimplemented file-lock/blocking)
@@ -1715,7 +1873,6 @@ EOF
 (define-unimplemented get-groups)
 (define-unimplemented group-information)
 (define-unimplemented initialize-groups)
-(define-unimplemented memory-mapped-file-pointer)
 (define-unimplemented parent-process-id)
 (define-unimplemented process-fork)
 (define-unimplemented process-group-id)
@@ -1733,7 +1890,6 @@ EOF
 (define-unimplemented signal-masked?)
 (define-unimplemented signal-unmask!)
 (define-unimplemented terminal-name)
-(define-unimplemented unmap-file-from-memory)
 (define-unimplemented user-information)
 (define-unimplemented utc-time->seconds)
 (define-unimplemented string->time)
@@ -1741,13 +1897,7 @@ EOF
 (define errno/wouldblock 0)
 
 (define (fifo? _) #f)
-(define (memory-mapped-file? _) #f)
 
-(define map/anonymous 0)
-(define map/file 0)
-(define map/fixed 0)
-(define map/private 0)
-(define map/shared 0)
 (define open/fsync 0)
 (define open/noctty 0)
 (define open/nonblock 0)
@@ -1755,7 +1905,3 @@ EOF
 (define perm/isgid 0)
 (define perm/isuid 0)
 (define perm/isvtx 0)
-(define prot/exec 0)
-(define prot/none 0)
-(define prot/read 0)
-(define prot/write 0)
diff --git a/tests/posix-tests.scm b/tests/posix-tests.scm
index e0d35ee2..1f934d9b 100644
--- a/tests/posix-tests.scm
+++ b/tests/posix-tests.scm
@@ -1,4 +1,4 @@
-(use files posix)
+(use files posix lolevel)
 
 (define-syntax assert-error
   (syntax-rules ()
@@ -31,3 +31,15 @@
 (assert-error (process-execute "false\x00123"))
 (assert-error (process-execute "false" '("1" "123\x00456")))
 (assert-error (process-execute "false" '("123\x00456") '("foo\x00bar" "blabla") '("lalala" "qux\x00mooh")))
+
+(let ((tnpfilpn (create-temporary-file)))
+  (let ((tmpfilno (file-open tnpfilpn (+ open/rdwr open/creat)))
+        (data "abcde")
+        (size 5))
+    (file-write tmpfilno data)
+    (let ((mmap (map-file-to-memory #f size prot/read map/file tmpfilno))
+          (str (make-string size)))
+      (assert (memory-mapped-file? mmap))
+      (move-memory! (memory-mapped-file-pointer mmap) str size)
+      (assert (blob=? (string->blob data) (string->blob str)))
+      (unmap-file-from-memory mmap))))
Trap