diff options
Diffstat (limited to 'console/pager.c')
-rw-r--r-- | console/pager.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/console/pager.c b/console/pager.c new file mode 100644 index 00000000..092a8820 --- /dev/null +++ b/console/pager.c @@ -0,0 +1,221 @@ +/* pager.c - The pager for the display component of a virtual console. + Copyright (C) 2002 Free Software Foundation, Inc. + Written by Marcus Brinkmann. + + This file is part of the GNU Hurd. + + The GNU Hurd 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. + + The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include <errno.h> +#include <assert.h> +#include <error.h> + +#include <sys/mman.h> +#include <cthreads.h> + +#include <hurd.h> +#include <hurd/pager.h> +#include <hurd/console.h> + +#include "pager.h" + + +struct user_pager_info +{ + size_t memobj_npages; + vm_address_t memobj_pages[0]; +}; + + +/* We need a separate bucket for the pager ports. */ +static struct port_bucket *pager_bucket; + + +/* Implement the pager_clear_user_data callback from the pager library. */ +void +pager_clear_user_data (struct user_pager_info *upi) +{ + int idx; + + for (idx = 0; idx < upi->memobj_npages; idx++) + if (upi->memobj_pages[idx]) + vm_deallocate (mach_task_self (), upi->memobj_pages[idx], vm_page_size); + free (upi); +} + + +error_t +pager_read_page (struct user_pager_info *upi, vm_offset_t page, + vm_address_t *buf, int *writelock) +{ + /* XXX clients should get a read only object. */ + *writelock = 0; + + if (upi->memobj_pages[page / vm_page_size] != (vm_address_t) NULL) + { + *buf = upi->memobj_pages[page / vm_page_size]; + upi->memobj_pages[page / vm_page_size] = (vm_address_t) NULL; + } + else + *buf = (vm_address_t) mmap (0, vm_page_size, PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + return 0; +} + + +error_t +pager_write_page (struct user_pager_info *upi, vm_offset_t page, + vm_address_t buf) +{ + assert (upi->memobj_pages[page / vm_page_size] == (vm_address_t) NULL); + upi->memobj_pages[page / vm_page_size] = buf; + return 0; +} + + +error_t +pager_unlock_page (struct user_pager_info *pager, + vm_offset_t address) +{ + assert (!"unlocking requested on unlocked page"); + return 0; +} + + +/* Tell how big the file is. */ +error_t +pager_report_extent (struct user_pager_info *upi, + vm_address_t *offset, + vm_size_t *size) +{ + *offset = 0; + *size = upi->memobj_npages * vm_page_size; + return 0; +} + + +void +pager_dropweak (struct user_pager_info *upi) +{ +} + + +/* A top-level function for the paging thread that just services paging + requests. */ +static void +service_paging_requests (any_t arg) +{ + struct port_bucket *pager_bucket = arg; + for (;;) + ports_manage_port_operations_multithread (pager_bucket, + pager_demuxer, + 1000 * 60 * 2, + 1000 * 60 * 10, 0); +} + + +/* Initialize the pager for the display component. */ +void +user_pager_init (void) +{ + /* Create the pager bucket, and start to serve paging requests. */ + pager_bucket = ports_create_bucket (); + if (! pager_bucket) + error (5, errno, "Cannot create pager bucket"); + + /* Make a thread to service paging requests. */ + cthread_detach (cthread_fork ((cthread_fn_t) service_paging_requests, + (any_t) pager_bucket)); +} + + +/* Create a new pager in USER_PAGER with NPAGES pages, and return a + mapping to the memory in *USER. */ +error_t +user_pager_create (struct user_pager *user_pager, unsigned int npages, + struct cons_display **user) +{ + error_t err; + struct user_pager_info *upi; + + upi = calloc (1, sizeof (struct user_pager_info) + + sizeof (vm_address_t) * npages); + if (!upi) + return errno; + + upi->memobj_npages = npages; + + /* XXX Are the values 1 and MEMORY_OBJECT_COPY_DELAY correct? */ + user_pager->pager = pager_create (upi, pager_bucket, + 1, MEMORY_OBJECT_COPY_DELAY); + if (!user_pager->pager) + { + free (upi); + return errno; + } + user_pager->memobj = pager_get_port (user_pager->pager); + ports_port_deref (user_pager->pager); + + mach_port_insert_right (mach_task_self (), user_pager->memobj, + user_pager->memobj, MACH_MSG_TYPE_MAKE_SEND); + + err = vm_map (mach_task_self (), + (vm_address_t *) user, + (vm_size_t) npages * vm_page_size, + (vm_address_t) 0, + 1 /* ! (flags & MAP_FIXED) */, + user_pager->memobj, 0 /* (vm_offset_t) offset */, + 0 /* ! (flags & MAP_SHARED) */, + VM_PROT_READ | VM_PROT_WRITE, + VM_PROT_READ | VM_PROT_WRITE, + VM_INHERIT_NONE); + if (err) + { + /* UPI will be cleaned up by libpager. */ + mach_port_deallocate (mach_task_self (), user_pager->memobj); + return err; + } + + return 0; +} + + +/* Destroy the pager USER_PAGER and the mapping at USER. */ +void +user_pager_destroy (struct user_pager *user_pager, struct cons_display *user) +{ + /* The pager will be deallocated by libpager. */ + vm_deallocate (mach_task_self (), (vm_offset_t) user, + pager_get_upi (user_pager->pager)->memobj_npages + * vm_page_size); + mach_port_deallocate (mach_task_self (), user_pager->memobj); +} + + +/* Allocate a reference for the memory object backing the pager + USER_PAGER with protection PROT and return it. */ +mach_port_t +user_pager_get_filemap (struct user_pager *user_pager, vm_prot_t prot) +{ + error_t err; + + /* Add a reference for each call, the caller will deallocate it. */ + err = mach_port_mod_refs (mach_task_self (), user_pager->memobj, + MACH_PORT_RIGHT_SEND, +1); + assert_perror (err); + + return user_pager->memobj; +} + |