[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: memory_object_lock_request and memory_object_data_return fnord
From: |
Neal H Walfield |
Subject: |
Re: memory_object_lock_request and memory_object_data_return fnord |
Date: |
27 Mar 2002 00:35:07 -0500 |
User-agent: |
Gnus/5.0808 (Gnus v5.8.8) Emacs/21.1 |
> I think we should certainly use vm_copy for whole-page copies in
> pager_memcpy because of the badly suboptimal behavior you've described.
I have cooked up the attached implementation. I checked everything
but a few border cases -- I need to write a few more tests. Perhaps,
I will get to it this weekend. However, I am interested in some
feedback.
Thanks.
/* Fault-safe copy into or out of pager-backed memory.
Copyright (C) 1996,97,99,2000,01,02 Free Software Foundation, Inc.
Written by Roland McGrath.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pager.h"
#include <sys/mman.h>
#include <hurd/sigpreempt.h>
#include <assert.h>
#include <string.h>
/* Try to copy *SIZE bytes between the region OTHER points to
and the region at OFFSET in the pager indicated by PAGER and MEMOBJ.
If PROT is VM_PROT_READ, copying is from the pager to OTHER;
if PROT contains VM_PROT_WRITE, copying is from OTHER into the pager.
*SIZE is always filled in the actual number of bytes successfully copied.
Returns an error code if the pager-backed memory faults;
if there is no fault, returns 0 and *SIZE will be unchanged. */
error_t
pager_memcpy (struct pager *pager, memory_object_t memobj,
vm_offset_t offset, void *other, size_t *size,
vm_prot_t prot)
{
error_t err;
size_t n = *size;
#define VMCOPY_WINDOW_DEFAULT_SIZE (16 * vm_page_size)
#define MEMCPY_WINDOW_DEFAULT_SIZE (8 * vm_page_size)
vm_address_t window;
vm_size_t window_size;
error_t do_vm_copy (void)
{
assert ((offset & (vm_page_size - 1)) == 0);
assert (((vm_address_t) other & (vm_page_size - 1)) == 0);
do
{
window_size = VMCOPY_WINDOW_DEFAULT_SIZE > n
? n : VMCOPY_WINDOW_DEFAULT_SIZE;
err = vm_map (mach_task_self (), &window, window_size, 0, 1,
memobj, offset, 0, prot, prot, VM_INHERIT_NONE);
if (err)
return err;
if (prot == VM_PROT_READ)
err = vm_copy (mach_task_self (), window, window_size,
(vm_address_t) other);
else
err = vm_copy (mach_task_self (), (vm_address_t) other,
window_size, window);
vm_deallocate (mach_task_self (), window, window_size);
if (err)
return err;
other += window_size;
offset += window_size;
n -= window_size;
}
while (n >= vm_page_size);
return 0;
}
error_t do_copy (struct hurd_signal_preemptor *preemptor)
{
error_t do_memcpy (size_t to_copy)
{
window_size = MEMCPY_WINDOW_DEFAULT_SIZE;
do
{
size_t pageoff = offset & (vm_page_size - 1);
if (window)
/* Deallocate the old window. */
{
vm_deallocate (mach_task_self (), window, window_size);
window = 0;
}
/* Map in and copy a standard-sized window, unless that is
more than the total left to be copied. */
if (window_size > pageoff + n)
window_size = pageoff + n;
err = vm_map (mach_task_self (), &window, window_size, 0, 1,
memobj, n - pageoff, 0,
prot, prot, VM_INHERIT_NONE);
if (err)
return err;
/* Realign the fault preemptor for the new mapping window. */
preemptor->first = window;
preemptor->last = window + window_size;
if (prot == VM_PROT_READ)
memcpy (other, (const void *) window + pageoff,
window_size - pageoff);
else
memcpy ((void *) window + pageoff, other,
window_size - pageoff);
offset += window_size - pageoff;
other += window_size - pageoff;
to_copy -= window_size - pageoff;
n -= window_size - pageoff;
}
while (to_copy > 0);
return 0;
}
/* Can we use vm_copy? */
if ((((vm_address_t) other & (vm_page_size - 1))
== (offset & (vm_page_size - 1)))
&& (n - vm_page_size
>= vm_page_size - ((vm_address_t) other & (vm_page_size - 1))))
/* 1) other and offset are aligned with repect to each other;
and 2) we have at least one fully aligned page. */
{
err = do_memcpy (vm_page_size
- ((vm_address_t) other & (vm_page_size - 1)));
if (err)
return err;
assert (n > vm_page_size);
err = do_vm_copy ();
if (err || n == 0)
/* We failed or we finished. */
return err;
}
return do_memcpy (n);
}
jmp_buf buf;
void fault (int signo, long int sigcode, struct sigcontext *scp)
{
assert (scp->sc_error == EKERN_MEMORY_ERROR);
err = pager_get_error (pager, sigcode - window + offset);
n -= sigcode - window;
longjmp (buf, 1);
}
if (n == 0)
/* Nothing to do. */
return 0;
if (((vm_address_t) other & (vm_page_size - 1)) == 0
&& n >= vm_page_size
&& (((vm_address_t) other & (vm_page_size - 1))
== (offset & (vm_page_size -1))))
/* 1) the start address is page aligned; 2) we have more than a
page; and 3) the source and destination are aligned with
repect to each other. */
{
err = do_vm_copy ();
if (err || n == 0)
/* We failed or we finished. */
{
*size -= n;
return err;
}
}
/* Need to do it the hard way. */
window = 0;
window_size = 0;
if (setjmp (buf) == 0)
hurd_catch_signal (sigmask (SIGSEGV) | sigmask (SIGBUS),
window, window + window_size,
&do_copy, (sighandler_t) &fault);
if (window)
vm_deallocate (mach_task_self (), window, window_size);
if (! err)
assert (n == 0);
*size -= n;
return err;
}
- Re: GNU/Linux binary compatibility (Was: Re: memory_object_lock_request and memory_object_data_return fnord), (continued)
- Re: GNU/Linux binary compatibility (Was: Re: memory_object_lock_request and memory_object_data_return fnord), Oystein Viggen, 2002/03/25
- Re: GNU/Linux binary compatibility (Was: Re: memory_object_lock_request and memory_object_data_return fnord), Jeroen Dekkers, 2002/03/25
- Re: GNU/Linux binary compatibility (Was: Re: memory_object_lock_request and memory_object_data_return fnord), Farid Hajji, 2002/03/25
- Re: GNU/Linux binary compatibility (Was: Re: memory_object_lock_request and memory_object_data_return fnord), Jeroen Dekkers, 2002/03/25
- Re: GNU/Linux binary compatibility (Was: Re: memory_object_lock_request and memory_object_data_return fnord), Oystein Viggen, 2002/03/26
- Re: GNU/Linux binary compatibility (Was: Re: memory_object_lock_request and memory_object_data_return fnord), Jeroen Dekkers, 2002/03/26
- Re: memory_object_lock_request and memory_object_data_return fnord, Roland McGrath, 2002/03/25
- Re: memory_object_lock_request and memory_object_data_return fnord,
Neal H Walfield <=
- Re: memory_object_lock_request and memory_object_data_return fnord, Thomas Bushnell, BSG, 2002/03/27
- Re: memory_object_lock_request and memory_object_data_return fnord, Thomas Bushnell, BSG, 2002/03/14