summaryrefslogtreecommitdiff
path: root/libhurd-mm/anonymous.c
diff options
context:
space:
mode:
authorneal <neal>2007-11-19 22:59:04 +0000
committerneal <neal>2007-11-19 22:59:04 +0000
commit755d9a8988a5ae6e70fe5dbf6a980bad0c54821d (patch)
treeec578a1f082f218884a48c0b6bb5a0a84da96f01 /libhurd-mm/anonymous.c
parent5c2c982ba3cfbe34c79cb2096018567ca6cd8fb6 (diff)
hurd/
2007-11-19 Neal H. Walfield <neal@gnu.org> * Makefile.am (includehurd_HEADERS): Add exceptions.h. * headers.m4: Link $(BUILDIR)/include/hurd/exceptions.h to exceptions.h. * exceptions.h: New file. viengoos/ 2007-11-19 Neal H. Walfield <neal@gnu.org> * thread.h (struct thread): Add fields have_exception and exception. (UTCB_AREA_SIZE): Provide space for two UTCBs. * thread.c: Include <hurd/exceptions.h>. (thread_create_in): For each thread that we allocate, allocate two consecutive l4 thread ids. (thread_commission): Initialize the main thread and the exception thread. (thread_decommission): Destroy both the main thread and the exception thread. * rm.h: Add RM_exception_collect. (rm_method_id_string): Handle RM_exception_collect. (exception_collect): New RPC method. * server.c: Include <hurd/exceptions.h>. (server_loop): If FROM is the exception thread, look up the thread object using the main thread id. Propagate any fault to the exception thread. If not immediately successful, save the message in THREAD->EXCEPTION and set THREAD->HAVE_EXCEPTION. Implement the exception_collect method. (DEBUG): Also print the method number. libhurd-mm/ 2007-11-19 Neal H. Walfield <neal@gnu.org> * Makefile.am (libhurd_mm_a_SOURCES): Add exceptions.h, exceptions.c, pager.h, pager.c, anonymous.h and anonymous.c. * headers.m4: Link $(BUILDDIR)/include/hurd/pager.h to pager.h. Link $(BUILDDIR)/include/hurd/anonymous.h to anonymous.h. * mm-init.c: Include "exceptions.h". (mm_init): Call exception_handler_init. * pager.h: Completely rewrite. * pager.c: Likewise. * anonymous.h: Likewise. * anonymous.c: Likewise. * exceptions.h: New file. * exceptions.c: Likewise. * mmap.c: Include <hurd/anonymous.h>. (mmap): Rewrite to use an anonymous pager.
Diffstat (limited to 'libhurd-mm/anonymous.c')
-rw-r--r--libhurd-mm/anonymous.c240
1 files changed, 201 insertions, 39 deletions
diff --git a/libhurd-mm/anonymous.c b/libhurd-mm/anonymous.c
index 62a831e..933b562 100644
--- a/libhurd-mm/anonymous.c
+++ b/libhurd-mm/anonymous.c
@@ -1,5 +1,5 @@
-/* anonymous.c - Anonymous memory management.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+/* anonymous.h - Anonymous memory pager interface.
+ Copyright (C) 2007 Free Software Foundation, Inc.
Written by Neal H. Walfield <neal@gnu.org>.
This file is part of the GNU Hurd.
@@ -23,58 +23,220 @@
#include <config.h>
#endif
-#include <stdint.h>
-#include "priv.h"
+#include <hurd/stddef.h>
+#include <hurd/btree.h>
+#include <hurd/slab.h>
-static struct hurd_store anonymous_store;
+#include "anonymous.h"
+#include "pager.h"
+#include "storage.h"
+#include "as.h"
-error_t
-hurd_anonymous_allocate (uintptr_t *address, size_t size,
- uintptr_t flags, int map_now)
+#define DISCARDABLE(a) ((a)->flags & ANONYMOUS_DISCARDABLE)
+
+struct storage_desc
{
- /* This is a bit frustrating. The store cache is indexed by the
- store offset thus even though anonymous memory does not initially
- have a location on backing store, we need to fabricate one.
- Right now we just use a static variable. The 64-bits should give
- us a fair amount of time before we need to come up with a better
- solution. */
- static off64_t offset;
- error_t err;
-
- err = hurd_store_bind_to_vm (&anonymous_store, offset,
- address ? *address : 0, size,
- flags, 1, address);
- if (err)
- return err;
+ hurd_btree_node_t node;
+
+ /* The virtual address. */
+ addr_t addr;
+ /* The allocated storage. */
+ addr_t storage;
+};
+
+static int
+addr_compare (const addr_t *a, const addr_t *b)
+{
+ if (a->raw < b->raw)
+ return -1;
+ return a->raw != b->raw;
+}
+
+BTREE_CLASS (storage_desc, struct storage_desc,
+ addr_t, addr, node, addr_compare)
+
+static error_t
+slab_alloc (void *hook, size_t size, void **ptr)
+{
+ addr_t storage = storage_alloc (meta_data_activity,
+ cap_page, STORAGE_LONG_LIVED, ADDR_VOID);
+
+ *ptr = ADDR_TO_PTR (addr_extend (storage, 0, PAGESIZE_LOG2));
- offset += size;
return 0;
}
+static error_t
+slab_dealloc (void *hook, void *buffer, size_t size)
+{
+ assert (size == PAGESIZE);
+
+ addr_t addr = addr_chop (PTR_TO_ADDR (buffer), PAGESIZE_LOG2);
+ storage_free (addr, false);
+
+ return 0;
+}
+
+/* Storage descriptors are alloced from a slab. */
+static struct hurd_slab_space storage_desc_slab
+ = HURD_SLAB_SPACE_INITIALIZER (struct storage_desc,
+ slab_alloc, slab_dealloc, NULL, NULL, NULL);
+
+static struct storage_desc *
+storage_desc_alloc (void)
+{
+ void *buffer;
+ error_t err = hurd_slab_alloc (&storage_desc_slab, &buffer);
+ if (err)
+ panic ("Out of memory!");
+
+ return buffer;
+}
+
static void
-handle_fault (hurd_store_t *store, void *hook, l4_thread_id_t thread,
- struct region vm_region, off64_t store_offset,
- uintptr_t addr, l4_word_t access)
+storage_desc_free (struct storage_desc *storage)
{
- /* XXX: Until we have a real swap server we (correctly) assume that
- if there is no memory then memory has just not yet been allocated
- (i.e. it is not just paged out). */
- struct hurd_memory *memory = hurd_memory_alloc (vm_region.size);
- if (! memory)
- panic ("hurd_memory_alloc failed.");
+ hurd_slab_dealloc (&storage_desc_slab, storage);
+}
+
+/* Anonymous pagers are allocated from a slab. */
+static struct hurd_slab_space anonymous_pager_slab
+ = HURD_SLAB_SPACE_INITIALIZER (struct anonymous_pager,
+ slab_alloc, slab_dealloc, NULL, NULL, NULL);
+
+#if 0
+void
+anonymous_pager_ensure (struct anonymous_pager *anon,
+ uintptr_t addr, size_t count)
+{
+ assert ((addr & (PAGESIZE - 1)) == 0);
+ assert ((count & (PAGESIZE - 1)) == 0);
- store_offset -= addr - vm_region.start;
+ assert (addr_prefix (anon->pager.region.start) <= addr);
+ // assert (addr + count * PAGESIZE < addr_prefix (anon->pager.region.start) <= addr);
- hurd_store_cache (store, store_offset, memory);
+ addr_t page = addr_chop (PTR_TO_ADDR (addr), PAGESIZE_LOG2);
+
+ struct storage_desc *storage_desc = NULL;
+ storage_desc = hurd_btree_pager_find (&anon->storage, &page);
+
+ while (count > 0)
+ {
+ }
+}
+#endif
+
+static bool
+fault (struct pager *pager,
+ addr_t addr, uintptr_t ip, struct exception_info info)
+{
+ struct anonymous_pager *anon = (struct anonymous_pager *) pager;
+
+ addr_t page;
+ if (addr_depth (addr) == ADDR_BITS)
+ page = addr_chop (addr, PAGESIZE_LOG2);
+ else
+ {
+ assert (addr_depth (addr) == ADDR_BITS - PAGESIZE_LOG2);
+ page = addr;
+ }
+
+ hurd_btree_storage_desc_t *storage_descs;
+ storage_descs = (hurd_btree_storage_desc_t *) &anon->storage;
+
+ struct storage_desc *storage_desc = NULL;
+ if (DISCARDABLE (anon))
+ /* We can only fault on a page that we already have a descriptor
+ for if the page was discardable. Thus, if the pager is not an
+ anonymous pager, we know that there is no descriptor for the
+ page. */
+ storage_desc = hurd_btree_storage_desc_find (storage_descs, &page);
+
+ if (! storage_desc)
+ {
+ storage_desc = storage_desc_alloc ();
+ storage_desc->addr = page;
+
+ bool r = as_slot_ensure (page);
+ if (! r)
+ panic ("Failed to ensure slot at " ADDR_FMT, ADDR_PRINTF (page));
+
+ storage_desc->storage = storage_alloc (anon->activity,
+ cap_page, STORAGE_UNKNOWN, page);
+ if (ADDR_IS_VOID (storage_desc->storage))
+ panic ("Out of memory.");
+
+ struct storage_desc *conflict;
+ conflict = hurd_btree_storage_desc_insert (storage_descs, storage_desc);
+ assert (! conflict);
+ }
+
+ if (anon->fill)
+ /* XXX: There is a slight problem here. */
+ anon->fill (anon, anon->cookie,
+ (uintptr_t) ADDR_TO_PTR (addr_extend (page, 0, PAGESIZE_LOG2)),
+ 1);
+
+ return true;
+}
+
+struct anonymous_pager *
+anonymous_pager_alloc (addr_t activity,
+ uintptr_t addr, size_t size,
+ uintptr_t flags, int map_now)
+{
+ assert ((addr & (PAGESIZE - 1)) == 0);
+ assert ((size & (PAGESIZE - 1)) == 0);
+
+ void *buffer;
+ error_t err = hurd_slab_alloc (&anonymous_pager_slab, &buffer);
+ if (err)
+ panic ("Out of memory!");
+ struct anonymous_pager *anon = buffer;
+
+ memset (anon, 0, sizeof (*anon));
+ anon->pager.fault = fault;
+
+ anon->activity = activity;
+ anon->flags = flags;
+ if (map_now)
+ /* Allocate the required storage right now. */
+ ;
+
+ /* Install the pager. */
+ anon->pager.region.start = addr_chop (PTR_TO_ADDR (addr), PAGESIZE_LOG2);
+ anon->pager.region.count = size >> PAGESIZE_LOG2;
+
+ bool r = pager_install (&anon->pager);
+ if (! r)
+ /* Ooops! There is a region conflict. */
+ {
+ hurd_slab_dealloc (&anonymous_pager_slab, anon);
+ return NULL;
+ }
+
+ return anon;
}
void
-hurd_anonymous_system_init (void)
+anonymous_pager_destroy (struct anonymous_pager *anon)
{
- static bool init_done;
+ /* Deinstall the pager. */
+ pager_deinstall (&anon->pager);
+
+ /* Free the allocated storage. */
+ hurd_btree_storage_desc_t *storage_descs;
+ storage_descs = (hurd_btree_storage_desc_t *) &anon->storage;
+
+ struct storage_desc *node, *next;
+ for (node = hurd_btree_storage_desc_first (storage_descs); node; node = next)
+ {
+ next = hurd_btree_storage_desc_next (node);
- assert (! init_done);
- init_done = true;
+ storage_free (node->storage, false);
+ storage_desc_free (node);
+ }
- hurd_store_init (&anonymous_store, NULL, handle_fault);
+ /* And free its storage. */
+ hurd_slab_dealloc (&anonymous_pager_slab, anon);
}