/[hurd]/hurd/libpager/pager-memcpy.c
ViewVC logotype

Diff of /hurd/libpager/pager-memcpy.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.7 by roland, Mon Feb 26 04:15:07 2001 UTC revision 1.8 by neal, Wed Apr 10 04:09:58 2002 UTC
# Line 1  Line 1 
1  /* Fault-safe copy into or out of pager-backed memory.  /* Fault-safe copy into or out of pager-backed memory.
2     Copyright (C) 1996,97,99,2000,2001 Free Software Foundation, Inc.     Copyright (C) 1996,97,99, 2000,01,02 Free Software Foundation, Inc.
3     Written by Roland McGrath.     Written by Roland McGrath.
4    
5     This program is free software; you can redistribute it and/or     This program is free software; you can redistribute it and/or
# Line 16  Line 16 
16     along with this program; if not, write to the Free Software     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18    
19    #include "priv.h"
20  #include "pager.h"  #include "pager.h"
21  #include <sys/mman.h>  #include <sys/mman.h>
22  #include <hurd/sigpreempt.h>  #include <hurd/sigpreempt.h>
23  #include <assert.h>  #include <assert.h>
24  #include <string.h>  #include <string.h>
25    
26    /* Start using vm_copy over memcpy when we have at a page.  (This
27       value *cannot* be less than vm_page_size.)  */
28    #define VMCOPY_BETTER_THAN_MEMCPY (vm_page_size)
29    
30  /* Try to copy *SIZE bytes between the region OTHER points to  /* Try to copy *SIZE bytes between the region OTHER points to
31     and the region at OFFSET in the pager indicated by PAGER and MEMOBJ.     and the region at OFFSET in the pager indicated by PAGER and MEMOBJ.
32     If PROT is VM_PROT_READ, copying is from the pager to OTHER;     If PROT is VM_PROT_READ, copying is from the pager to OTHER;
# Line 29  Line 34 
34     *SIZE is always filled in the actual number of bytes successfully copied.     *SIZE is always filled in the actual number of bytes successfully copied.
35     Returns an error code if the pager-backed memory faults;     Returns an error code if the pager-backed memory faults;
36     if there is no fault, returns 0 and *SIZE will be unchanged.  */     if there is no fault, returns 0 and *SIZE will be unchanged.  */
   
37  error_t  error_t
38  pager_memcpy (struct pager *pager, memory_object_t memobj,  pager_memcpy (struct pager *pager, memory_object_t memobj,
39                vm_offset_t offset, void *other, size_t *size,                vm_offset_t offset, void *other, size_t *size,
40                vm_prot_t prot)                vm_prot_t prot)
41  {  {
   vm_address_t window = 0;  
   vm_size_t windowsize = 8 * vm_page_size;  
   size_t to_copy = *size;  
42    error_t err;    error_t err;
43      size_t n = *size;
44    
45    error_t copy (struct hurd_signal_preemptor *preemptor)  #define VMCOPY_WINDOW_DEFAULT_SIZE (16 * vm_page_size)
46    #define MEMCPY_WINDOW_DEFAULT_SIZE (8 * vm_page_size)
47      vm_address_t window;
48      vm_size_t window_size;
49    
50      error_t do_vm_copy (void)
51      {      {
52        while (to_copy > 0)        assert ((offset & (vm_page_size - 1)) == 0);
53          {        assert (((vm_address_t) other & (vm_page_size - 1)) == 0);
54            size_t pageoff = offset & (vm_page_size - 1);        assert (n >= vm_page_size);
55    
56            if (window)        do
57              /* Deallocate the old window.  */          {
58              munmap ((caddr_t) window, windowsize);            window_size =
59                VMCOPY_WINDOW_DEFAULT_SIZE > n
60            /* Map in and copy a standard-sized window, unless that is              ? (n - (n & (vm_page_size - 1)))
61               more than the total left to be copied.  */              : VMCOPY_WINDOW_DEFAULT_SIZE;
62    
63            if (windowsize > pageoff + to_copy)            assert (window_size >= VMCOPY_BETTER_THAN_MEMCPY);
64              windowsize = pageoff + to_copy;            assert ((window_size & (vm_page_size - 1)) == 0);
65              
66            window = 0;            err = vm_map (mach_task_self (), &window, window_size, 0, 1,
67            err = vm_map (mach_task_self (), &window, windowsize, 0, 1,                          memobj, offset, 0, prot, prot, VM_INHERIT_NONE);
                         memobj, offset - pageoff, 0,  
                         prot, prot, VM_INHERIT_NONE);  
68            if (err)            if (err)
69              return 0;              return err;
   
           /* Realign the fault preemptor for the new mapping window.  */  
           preemptor->first = window;  
           preemptor->last = window + windowsize;  
70    
71            if (prot == VM_PROT_READ)            if (prot == VM_PROT_READ)
72              memcpy (other, (const void *) window + pageoff,              err = vm_copy (mach_task_self (), window, window_size,
73                      windowsize - pageoff);                             (vm_address_t) other);
74            else            else
75              memcpy ((void *) window + pageoff, other, windowsize - pageoff);              err = vm_copy (mach_task_self (), (vm_address_t) other,
76                               window_size, window);
77    
78            offset += windowsize - pageoff;            vm_deallocate (mach_task_self (), window, window_size);
79            other += windowsize - pageoff;  
80            to_copy -= windowsize - pageoff;            if (err)
81                return err;
82    
83              other += window_size;
84              offset += window_size;
85              n -= window_size;
86          }          }
87          while (n >= VMCOPY_BETTER_THAN_MEMCPY);
88    
89        return 0;        return 0;
90      }      }
91    
92      error_t do_copy (struct hurd_signal_preemptor *preemptor)
93        {
94          error_t do_memcpy (size_t to_copy)
95            {
96              window_size = MEMCPY_WINDOW_DEFAULT_SIZE;
97    
98              do
99                {
100                  size_t pageoff = offset & (vm_page_size - 1);
101                  size_t copy_count = window_size - pageoff;
102    
103                  /* Map in and copy a standard-sized window, unless that is
104                     more than the total left to be copied.  */
105    
106                  if (window_size >= round_page (pageoff + to_copy))
107                    {
108                      copy_count = to_copy;
109                      window_size = round_page (pageoff + to_copy);
110                    }
111    
112                  err = vm_map (mach_task_self (), &window, window_size, 0, 1,
113                                memobj, offset - pageoff, 0,
114                                prot, prot, VM_INHERIT_NONE);
115                  if (err)
116                    return err;
117    
118                  /* Realign the fault preemptor for the new mapping window.  */
119                  preemptor->first = window;
120                  preemptor->last = window + window_size;
121    
122                  if (prot == VM_PROT_READ)
123                    memcpy (other, (const void *) window + pageoff, copy_count);
124                  else
125                    memcpy ((void *) window + pageoff, other, copy_count);
126                  
127                  vm_deallocate (mach_task_self (), window, window_size);
128    
129                  offset += copy_count;
130                  other += copy_count;
131                  to_copy -= copy_count;
132                  n -= copy_count;
133    
134                  assert (n >= 0);
135                  assert (to_copy >= 0);
136                }
137              while (to_copy > 0);
138              
139              return 0;
140            }
141    
142          /* Can we use vm_copy?  */
143          if ((((vm_address_t) other & (vm_page_size - 1))
144               == (offset & (vm_page_size - 1)))
145              && (n >= (VMCOPY_BETTER_THAN_MEMCPY + vm_page_size
146                        - ((vm_address_t) other & (vm_page_size - 1)))))
147            /* 1) other and offset are aligned with repect to each other;
148               and 2) we have at least VMCOPY_BETTER_THAN_MEMCPY fully
149               aligned pages.  */
150            {
151              err = do_memcpy (vm_page_size
152                               - ((vm_address_t) other & (vm_page_size - 1)));
153              if (err)
154                return err;
155      
156              assert (n >= VMCOPY_BETTER_THAN_MEMCPY);
157    
158              err = do_vm_copy ();
159              if (err || n == 0)
160                /* We failed or we finished.  */
161                return err;
162    
163              assert (n < VMCOPY_BETTER_THAN_MEMCPY);
164            }
165    
166          return do_memcpy (n);
167        }
168    
169    jmp_buf buf;    jmp_buf buf;
170    void fault (int signo, long int sigcode, struct sigcontext *scp)    void fault (int signo, long int sigcode, struct sigcontext *scp)
171      {      {
172        assert (scp->sc_error == EKERN_MEMORY_ERROR);        assert (scp->sc_error == EKERN_MEMORY_ERROR);
173        err = pager_get_error (pager, sigcode - window + offset);        err = pager_get_error (pager,
174        to_copy -= sigcode - window;                               (sigcode - window + offset) / vm_page_size);
175          n -= sigcode - window;
176          vm_deallocate (mach_task_self (), window, window_size);
177        longjmp (buf, 1);        longjmp (buf, 1);
178      }      }
179    
180    if (to_copy == 0)    if (n == 0)
181      /* Short-circuit return if nothing to do.      /* Nothing to do.  */
        ERR would not be initialized by the copy loop in this case.  */  
182      return 0;      return 0;
183    
184      if (((vm_address_t) other & (vm_page_size - 1)) == 0
185          && (offset & (vm_page_size - 1)) == 0
186          && n >= VMCOPY_BETTER_THAN_MEMCPY)
187        /* 1) the start address is page aligned; 2) the offset is page
188           aligned; and 3) we have more than VMCOPY_BETTER_THAN_MEMCPY
189           pages. */
190        {
191          err = do_vm_copy ();
192          if (err || n == 0)
193            /* We failed or we finished.  */
194            {
195              *size -= n;
196              return err;
197            }
198    
199          assert (n < VMCOPY_BETTER_THAN_MEMCPY);
200        }
201    
202      /* Need to do it the hard way.  */
203    
204      window = 0;
205      window_size = 0;
206    
207    if (setjmp (buf) == 0)    if (setjmp (buf) == 0)
208      hurd_catch_signal (sigmask (SIGSEGV) | sigmask (SIGBUS),      hurd_catch_signal (sigmask (SIGSEGV) | sigmask (SIGBUS),
209                         window, window + windowsize,                         window, window + window_size,
210                         &copy, (sighandler_t) &fault);                         &do_copy, (sighandler_t) &fault);
211    
212    if (window)    if (! err)
213      munmap ((caddr_t) window, windowsize);      assert (n == 0);
214    
215    *size -= to_copy;    *size -= n;
216    
217    return err;    return err;
218  }  }

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.8

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26