bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

mlock for the Hurd


From: James A Morrison
Subject: mlock for the Hurd
Date: Tue, 25 Mar 2003 23:38:57 -0500 (EST)

 Hey,

  I figured I'd post this patch because it seems to work and I've toasted
another filesystem.  Which means I'll have some more work to do to get a 
decent build environment up again.

  I've only done limiting testing on this.  That is, I mmaped a few pages,
then mlocked them, the program did not return any errors.  I tried to mmap
a gig of anonymous memory and mlock return invalid argument, so I assume the
mmap failed, thus causing mlock to fail.  I then malloc'd a gig and tried to
mlock it.  This didn't freeze my system, but did cause a kernel panic after
a minute or so.  The error was something like panic: alloc pt zone exhausted",
which I assume means the kernel was wiring the memory and ran out.  

 I'm posting this here because I haven't had a chance to try the read loop.
If the read loop works properly then we can probably only use it.


Anyway, have fun.

James A. Morrison

2003-03-25  James A Morrison  <ja2morri@uwaterloo.ca>

        * mlock.c (mlock): Check the memory protections for the regions to
        be locked and ensure each page is in memory before it is wired by
        the kernel.

Index: mlock.c
===================================================================
RCS file: /cvs/glibc/libc/sysdeps/mach/hurd/mlock.c,v
retrieving revision 1.2
diff -u -r1.2 mlock.c
--- mlock.c     6 Jul 2001 04:55:57 -0000       1.2
+++ mlock.c     24 Mar 2003 00:44:41 -0000
@@ -1,5 +1,5 @@
 /* mlock -- guarantee pages are resident in memory.  Mach/Hurd version.
-   Copyright (C) 2001 Free Software Foundation, Inc.
+   Copyright (C) 2001, 03 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -30,17 +30,90 @@
 mlock (const void *addr, size_t len)
 {
   mach_port_t hostpriv;
-  vm_address_t page;
+  vm_address_t page, working;
   error_t err;
+  size_t remaining, wiring, size;
+  boolean_t shared;
+  vm_prot_t cur_prot, max_prot;
+  mach_port_t obj_name;
+  vm_offset_t offset;
+  vm_inherit_t inherit;
+  volatile char *poke;
+  volatile char ch;
+
+  static size_t touches = 1;
 
   err = __get_privileged_ports (&hostpriv, NULL);
   if (err)
     return __hurd_fail (EPERM);
 
-  page = trunc_page ((vm_address_t) addr);
-  len = round_page ((vm_address_t) addr + len) - page;
-  err = __vm_wire (hostpriv, __mach_task_self (), page, len,
-                  VM_PROT_ALL); /* XXX ? */
+  working = page = trunc_page ((vm_address_t) addr);
+  remaining = len = round_page ((vm_address_t) addr + len) - page;
+
+  do
+    {
+      size_t do_touch;
+      err = __vm_region (__mach_task_self (), &page, &size, &cur_prot,
+                         &max_prot, &inherit, &shared, &obj_name, &offset);
+      if (err) 
+        goto err_state;
+      else if (page != working)
+        {
+          err = ENOMEM;
+          goto err_state;
+        }
+
+      /* Prune size if it is larger than we need. */
+      size = size > remaining ? remaining : size;
+
+      for (working = page; working < (page + size);
+          working += (size_t)wiring)
+        {
+          do_touch = remaining / vm_page_size;
+          do_touch = do_touch > touches ? touches : do_touch;
+          wiring = do_touch * vm_page_size;
+
+          /* write to the page if we can. */
+          if (cur_prot & VM_PROT_WRITE)
+            for (poke = page; poke < working + wiring; poke += vm_page_size)
+              *poke = *poke;
+          else
+            for (poke = page; poke < working + wiring; poke += vm_page_size)
+              ch = *poke;
+    
+          /* Use the current protection because the programmer should have the
+             correct protections in place before trying to do anything.  It 
+             looks safer this way as well. */
+          err = __vm_wire (hostpriv, __mach_task_self (), working, wiring,
+                           cur_prot); 
+          if (err)
+            goto err_state;
+
+          remaining -= wiring;
+        }
+
+    }
+  while (remaining);
+
+err_state:
+  if (err)
+    {
+      /* Assume the memory wasn't locked before, so we unlock it all to restore
+         the state it was in. */
+     working = page;
+     remaining = len - remaining;
+     while (remaining)
+       {
+         err = __vm_region (__mach_task_self (), &working, &size, &cur_prot,
+                            &max_prot, &inherit, &shared, &obj_name, &offset);
+         size = size > remaining ? remaining : size;
+         err = __vm_wire (hostpriv, __mach_task_self (), working, wiring,
+                         VM_PROT_NONE); 
+     
+         remaining -= size;
+       }
+    }
+
   __mach_port_deallocate (__mach_task_self (), hostpriv);
 
   return err ? __hurd_fail (err) : 0;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]