summaryrefslogtreecommitdiff
path: root/libhurd-slab
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2015-11-29 13:13:39 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2015-11-29 13:13:39 +0100
commit8b21a60d8cf2916e4dbc3019d39d0b380abe7a88 (patch)
tree20b5f8130a81d67d3716f4ae0284d0965350243a /libhurd-slab
parent87bc93725aea306e8bd4e4171622e4418869fc2f (diff)
Add libhurd-slab
* libhurd-slab: New directory * Makefile (lib-subdirs): Add libhurd-slab.
Diffstat (limited to 'libhurd-slab')
-rw-r--r--libhurd-slab/Makefile33
-rw-r--r--libhurd-slab/slab.c518
-rw-r--r--libhurd-slab/slab.h338
3 files changed, 889 insertions, 0 deletions
diff --git a/libhurd-slab/Makefile b/libhurd-slab/Makefile
new file mode 100644
index 00000000..925f70c1
--- /dev/null
+++ b/libhurd-slab/Makefile
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 1994,95,96,97,98,99,2000,01,02,2005 Free Software Foundation, Inc.
+#
+# 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.
+
+dir := libhurd-slab
+makemode := library
+
+libname = libhurd-slab
+SRCS= slab.c
+LCLHDRS = slab.h
+installhdrs = slab.h
+
+MIGSTUBS =
+OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS))
+
+OTHERLIBS = -lpthread
+
+MIGCOMSFLAGS =
+
+include ../Makeconf
diff --git a/libhurd-slab/slab.c b/libhurd-slab/slab.c
new file mode 100644
index 00000000..5a12a43a
--- /dev/null
+++ b/libhurd-slab/slab.c
@@ -0,0 +1,518 @@
+/* Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+ Written by Johan Rydberg.
+
+ This file is part of the GNU Hurd.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <stdint.h>
+
+#include "slab.h"
+
+#define SLAB_PAGES 4
+
+
+/* Number of pages the slab allocator has allocated. */
+static int __hurd_slab_nr_pages;
+
+
+/* Buffer control structure. Lives at the end of an object. If the
+ buffer is allocated, SLAB points to the slab to which it belongs.
+ If the buffer is free, NEXT points to next buffer on free list. */
+union hurd_bufctl
+{
+ union hurd_bufctl *next;
+ struct hurd_slab *slab;
+};
+
+
+/* When the allocator needs to grow a cache, it allocates a slab. A
+ slab consists of one or more pages of memory, split up into equally
+ sized chunks. */
+struct hurd_slab
+{
+ struct hurd_slab *next;
+ struct hurd_slab *prev;
+
+ /* The reference counter holds the number of allocated chunks in
+ the slab. When the counter is zero, all chunks are free and
+ the slab can be relinquished. */
+ int refcount;
+
+ /* Single linked list of free buffers in the slab. */
+ union hurd_bufctl *free_list;
+};
+
+/* Allocate a buffer in *PTR of size SIZE which must be a power of 2
+ and self aligned (i.e. aligned on a SIZE byte boundary) for slab
+ space SPACE. Return 0 on success, an error code on failure. */
+static error_t
+allocate_buffer (struct hurd_slab_space *space, size_t size, void **ptr)
+{
+ if (space->allocate_buffer)
+ return space->allocate_buffer (space->hook, size, ptr);
+ else
+ {
+ *ptr = mmap (NULL, size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
+ if (*ptr == MAP_FAILED)
+ return errno;
+ else
+ return 0;
+ }
+}
+
+/* Deallocate buffer BUFFER of size SIZE which was allocated for slab
+ space SPACE. Return 0 on success, an error code on failure. */
+static error_t
+deallocate_buffer (struct hurd_slab_space *space, void *buffer, size_t size)
+{
+ if (space->deallocate_buffer)
+ return space->deallocate_buffer (space->hook, buffer, size);
+ else
+ {
+ if (munmap (buffer, size) == -1)
+ return errno;
+ else
+ return 0;
+ }
+}
+
+/* Insert SLAB into the list of slabs in SPACE. SLAB is expected to
+ be complete (so it will be inserted at the end). */
+static void
+insert_slab (struct hurd_slab_space *space, struct hurd_slab *slab)
+{
+ assert (slab->refcount == 0);
+ if (space->slab_first == 0)
+ space->slab_first = space->slab_last = slab;
+ else
+ {
+ space->slab_last->next = slab;
+ slab->prev = space->slab_last;
+ space->slab_last = slab;
+ }
+}
+
+
+/* Remove SLAB from list of slabs in SPACE. */
+static void
+remove_slab (struct hurd_slab_space *space, struct hurd_slab *slab)
+{
+ if (slab != space->slab_first
+ && slab != space->slab_last)
+ {
+ slab->next->prev = slab->prev;
+ slab->prev->next = slab->next;
+ return;
+ }
+ if (slab == space->slab_first)
+ {
+ space->slab_first = slab->next;
+ if (space->slab_first)
+ space->slab_first->prev = NULL;
+ }
+ if (slab == space->slab_last)
+ {
+ if (slab->prev)
+ slab->prev->next = NULL;
+ space->slab_last = slab->prev;
+ }
+}
+
+
+/* Iterate through slabs in SPACE and release memory for slabs that
+ are complete (no allocated buffers). */
+static error_t
+reap (struct hurd_slab_space *space)
+{
+ struct hurd_slab *s, *next, *new_first;
+ error_t err = 0;
+
+ for (s = space->slab_first; s; s = next)
+ {
+ next = s->next;
+
+ /* If the reference counter is zero there is no allocated
+ buffers, so it can be freed. */
+ if (!s->refcount)
+ {
+ remove_slab (space, s);
+
+ /* If there is a destructor it must be invoked for every
+ buffer in the slab. */
+ if (space->destructor)
+ {
+ union hurd_bufctl *bufctl;
+ for (bufctl = s->free_list; bufctl; bufctl = bufctl->next)
+ {
+ void *buffer = (((void *) bufctl)
+ - (space->size - sizeof *bufctl));
+ (*space->destructor) (space->hook, buffer);
+ }
+ }
+ /* The slab is located at the end of the page (with the buffers
+ in front of it), get address by masking with page size.
+ This frees the slab and all its buffers, since they live on
+ the same page. */
+ err = deallocate_buffer (space, (void *) (((uintptr_t) s)
+ + sizeof (struct hurd_slab)
+ - space->slab_size),
+ space->slab_size);
+ if (err)
+ break;
+ __hurd_slab_nr_pages--;
+ }
+ }
+
+ /* Even in the case of an error, first_free must be updated since
+ that slab may have been deallocated. */
+ new_first = space->slab_first;
+ while (new_first)
+ {
+ if (new_first->refcount != space->full_refcount)
+ break;
+ new_first = new_first->next;
+ }
+ space->first_free = new_first;
+
+ return err;
+}
+
+
+/* Initialize slab space SPACE. */
+static void
+init_space (hurd_slab_space_t space)
+{
+ size_t size = space->requested_size + sizeof (union hurd_bufctl);
+ size_t alignment = space->requested_align;
+
+ /* If SIZE is so big that one object can not fit into a page
+ something gotta be really wrong. */
+ size = (size + alignment - 1) & ~(alignment - 1);
+ assert (size <= (space->slab_size
+ - sizeof (struct hurd_slab)
+ - sizeof (union hurd_bufctl)));
+
+ space->size = size;
+
+ /* Number of objects that fit into one page. Used to detect when
+ there are no free objects left in a slab. */
+ space->full_refcount
+ = ((space->slab_size - sizeof (struct hurd_slab)) / size);
+
+ /* FIXME: Notify pager's reap functionality about this slab
+ space. */
+
+ space->initialized = true;
+}
+
+
+/* SPACE has no more memory. Allocate new slab and insert it into the
+ list, repoint free_list and return possible error. */
+static error_t
+grow (struct hurd_slab_space *space)
+{
+ error_t err;
+ struct hurd_slab *new_slab;
+ union hurd_bufctl *bufctl;
+ int nr_objs, i;
+ void *p;
+
+ /* If the space has not yet been initialized this is the place to do
+ so. It is okay to test some fields such as first_free prior to
+ initialization since they will be a null pointer in any case. */
+ if (!space->initialized)
+ init_space (space);
+
+ err = allocate_buffer (space, space->slab_size, &p);
+ if (err)
+ return err;
+
+ __hurd_slab_nr_pages++;
+
+ new_slab = (p + space->slab_size - sizeof (struct hurd_slab));
+ memset (new_slab, 0, sizeof (*new_slab));
+
+ /* Calculate the number of objects that the page can hold.
+ SPACE->size should be adjusted to handle alignment. */
+ nr_objs = ((space->slab_size - sizeof (struct hurd_slab))
+ / space->size);
+
+ for (i = 0; i < nr_objs; i++, p += space->size)
+ {
+ /* Invoke constructor at object creation time, not when it is
+ really allocated (for faster allocation). */
+ if (space->constructor)
+ {
+ error_t err = (*space->constructor) (space->hook, p);
+ if (err)
+ {
+ /* The allocated page holds both slab and memory
+ objects. Call the destructor for objects that has
+ been initialized. */
+ for (bufctl = new_slab->free_list; bufctl;
+ bufctl = bufctl->next)
+ {
+ void *buffer = (((void *) bufctl)
+ - (space->size - sizeof *bufctl));
+ (*space->destructor) (space->hook, buffer);
+ }
+
+ deallocate_buffer (space, p, space->slab_size);
+ return err;
+ }
+ }
+
+ /* The most activity is in front of the object, so it is most
+ likely to be overwritten if a freed buffer gets accessed.
+ Therefor, put the bufctl structure at the end of the
+ object. */
+ bufctl = (p + space->size - sizeof *bufctl);
+ bufctl->next = new_slab->free_list;
+ new_slab->free_list = bufctl;
+ }
+
+ /* Insert slab into the list of available slabs for this cache. The
+ only time a slab should be allocated is when there is no more
+ buffers, so it is safe to repoint first_free. */
+ insert_slab (space, new_slab);
+ space->first_free = new_slab;
+ return 0;
+}
+
+
+/* Initialize the slab space SPACE. */
+error_t
+hurd_slab_init (hurd_slab_space_t space, size_t size, size_t alignment,
+ hurd_slab_allocate_buffer_t allocate_buffer,
+ hurd_slab_deallocate_buffer_t deallocate_buffer,
+ hurd_slab_constructor_t constructor,
+ hurd_slab_destructor_t destructor,
+ void *hook)
+{
+ error_t err;
+
+ /* Initialize all members to zero by default. */
+ memset (space, 0, sizeof (struct hurd_slab_space));
+
+ if (!alignment)
+ /* FIXME: Is this a good default? Maybe eight (8) is better,
+ since several architectures require that double and friends are
+ eight byte aligned. */
+ alignment = __alignof__ (void *);
+
+ space->requested_size = size;
+ space->requested_align = alignment;
+ space->slab_size = getpagesize () * SLAB_PAGES;
+
+ /* Testing the size here avoids an assertion in init_space. */
+ size = size + sizeof (union hurd_bufctl);
+ size = (size + alignment - 1) & ~(alignment - 1);
+ if (size > (space->slab_size - sizeof (struct hurd_slab)
+ - sizeof (union hurd_bufctl)))
+ return EINVAL;
+
+ err = pthread_mutex_init (&space->lock, NULL);
+ if (err)
+ return err;
+
+ space->allocate_buffer = allocate_buffer;
+ space->deallocate_buffer = deallocate_buffer;
+ space->constructor = constructor;
+ space->destructor = destructor;
+ space->hook = hook;
+
+ /* The remaining fields will be initialized by init_space. */
+ return 0;
+}
+
+
+/* Create a new slab space with the given object size, alignment,
+ constructor and destructor. ALIGNMENT can be zero. */
+error_t
+hurd_slab_create (size_t size, size_t alignment,
+ hurd_slab_allocate_buffer_t allocate_buffer,
+ hurd_slab_deallocate_buffer_t deallocate_buffer,
+ hurd_slab_constructor_t constructor,
+ hurd_slab_destructor_t destructor,
+ void *hook,
+ hurd_slab_space_t *r_space)
+{
+ hurd_slab_space_t space;
+ error_t err;
+
+ space = malloc (sizeof (struct hurd_slab_space));
+ if (!space)
+ return ENOMEM;
+
+ err = hurd_slab_init (space, size, alignment,
+ allocate_buffer, deallocate_buffer,
+ constructor, destructor, hook);
+ if (err)
+ {
+ free (space);
+ return err;
+ }
+
+ *r_space = space;
+ return 0;
+}
+
+
+/* Destroy all objects and the slab space SPACE. Returns EBUSY if
+ there are still allocated objects in the slab. */
+error_t
+hurd_slab_destroy (hurd_slab_space_t space)
+{
+ error_t err;
+
+ /* The caller wants to destroy the slab. It can not be destroyed if
+ there are any outstanding memory allocations. */
+ pthread_mutex_lock (&space->lock);
+ err = reap (space);
+ if (err)
+ {
+ pthread_mutex_unlock (&space->lock);
+ return err;
+ }
+
+ if (space->slab_first)
+ {
+ /* There are still slabs, i.e. there is outstanding allocations.
+ Return EBUSY. */
+ pthread_mutex_unlock (&space->lock);
+ return EBUSY;
+ }
+
+ /* FIXME: Remove slab space from pager's reap functionality. */
+
+ return 0;
+}
+
+
+/* Destroy all objects and the slab space SPACE. If there were no
+ outstanding allocations free the slab space. Returns EBUSY if
+ there are still allocated objects in the slab space. */
+error_t
+hurd_slab_free (hurd_slab_space_t space)
+{
+ error_t err = hurd_slab_destroy (space);
+ if (err)
+ return err;
+ free (space);
+ return 0;
+}
+
+
+/* Allocate a new object from the slab space SPACE. */
+error_t
+hurd_slab_alloc (hurd_slab_space_t space, void **buffer)
+{
+ error_t err;
+ union hurd_bufctl *bufctl;
+
+ pthread_mutex_lock (&space->lock);
+
+ /* If there is no slabs with free buffer, the cache has to be
+ expanded with another slab. If the slab space has not yet been
+ initialized this is always true. */
+ if (!space->first_free)
+ {
+ err = grow (space);
+ if (err)
+ {
+ pthread_mutex_unlock (&space->lock);
+ return err;
+ }
+ }
+
+ /* Remove buffer from the free list and update the reference
+ counter. If the reference counter will hit the top, it is
+ handled at the time of the next allocation. */
+ bufctl = space->first_free->free_list;
+ space->first_free->free_list = bufctl->next;
+ space->first_free->refcount++;
+ bufctl->slab = space->first_free;
+
+ /* If the reference counter hits the top it means that there has
+ been an allocation boost, otherwise dealloc would have updated
+ the first_free pointer. Find a slab with free objects. */
+ if (space->first_free->refcount == space->full_refcount)
+ {
+ struct hurd_slab *new_first = space->slab_first;
+ while (new_first)
+ {
+ if (new_first->refcount != space->full_refcount)
+ break;
+ new_first = new_first->next;
+ }
+ /* If first_free is set to NULL here it means that there are
+ only empty slabs. The next call to alloc will allocate a new
+ slab if there was no call to dealloc in the meantime. */
+ space->first_free = new_first;
+ }
+ *buffer = ((void *) bufctl) - (space->size - sizeof *bufctl);
+ pthread_mutex_unlock (&space->lock);
+ return 0;
+}
+
+
+static inline void
+put_on_slab_list (struct hurd_slab *slab, union hurd_bufctl *bufctl)
+{
+ bufctl->next = slab->free_list;
+ slab->free_list = bufctl;
+ slab->refcount--;
+ assert (slab->refcount >= 0);
+}
+
+
+/* Deallocate the object BUFFER from the slab space SPACE. */
+void
+hurd_slab_dealloc (hurd_slab_space_t space, void *buffer)
+{
+ struct hurd_slab *slab;
+ union hurd_bufctl *bufctl;
+
+ assert (space->initialized);
+
+ pthread_mutex_lock (&space->lock);
+
+ bufctl = (buffer + (space->size - sizeof *bufctl));
+ put_on_slab_list (slab = bufctl->slab, bufctl);
+
+ /* Try to have first_free always pointing at the slab that has the
+ most number of free objects. So after this deallocation, update
+ the first_free pointer if reference counter drops below the
+ current reference counter of first_free. */
+ if (!space->first_free
+ || slab->refcount < space->first_free->refcount)
+ space->first_free = slab;
+
+ pthread_mutex_unlock (&space->lock);
+}
diff --git a/libhurd-slab/slab.h b/libhurd-slab/slab.h
new file mode 100644
index 00000000..6eeb8e48
--- /dev/null
+++ b/libhurd-slab/slab.h
@@ -0,0 +1,338 @@
+/* slab.h - The GNU Hurd slab allocator interface.
+ Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann <marcus@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _HURD_SLAB_H
+#define _HURD_SLAB_H 1
+
+#include <errno.h>
+#include <stdbool.h>
+#include <pthread.h>
+
+
+/* Allocate a buffer in *PTR of size SIZE which must be a power of 2
+ and self aligned (i.e. aligned on a SIZE byte boundary). HOOK is
+ as provided to hurd_slab_create. Return 0 on success, an error
+ code on failure. */
+typedef error_t (*hurd_slab_allocate_buffer_t) (void *hook, size_t size,
+ void **ptr);
+
+/* Deallocate buffer BUFFER of size SIZE. HOOK is as provided to
+ hurd_slab_create. */
+typedef error_t (*hurd_slab_deallocate_buffer_t) (void *hook, void *buffer,
+ size_t size);
+
+/* Initialize the slab object pointed to by OBJECT. HOOK is as
+ provided to hurd_slab_create. */
+typedef error_t (*hurd_slab_constructor_t) (void *hook, void *object);
+
+/* Destroy the slab object pointed to by OBJECT. HOOK is as provided
+ to hurd_slab_create. */
+typedef void (*hurd_slab_destructor_t) (void *hook, void *object);
+
+
+/* The type of a slab space.
+
+ The structure is divided into two parts: the first is only used
+ while the slab space is constructed. Its fields are either
+ initialized by a static initializer (HURD_SLAB_SPACE_INITIALIZER)
+ or by the hurd_slab_create function. The initialization of the
+ space is delayed until the first allocation. After that only the
+ second part is used. */
+
+typedef struct hurd_slab_space *hurd_slab_space_t;
+struct hurd_slab_space
+{
+ /* First part. Used when initializing slab space object. */
+
+ /* True if slab space has been initialized. */
+ bool initialized;
+
+ /* Protects this structure, along with all the slabs. No need to
+ delay initialization of this field. */
+ pthread_mutex_t lock;
+
+ /* The size and alignment of objects allocated using this slab
+ space. These to fields are used to calculate the final object
+ size, which is put in SIZE (defined below). */
+ size_t requested_size;
+ size_t requested_align;
+
+ /* The size of each slab. */
+ size_t slab_size;
+
+ /* The buffer allocator. */
+ hurd_slab_allocate_buffer_t allocate_buffer;
+
+ /* The buffer deallocator. */
+ hurd_slab_deallocate_buffer_t deallocate_buffer;
+
+ /* The constructor. */
+ hurd_slab_constructor_t constructor;
+
+ /* The destructor. */
+ hurd_slab_destructor_t destructor;
+
+ /* The user's private data. */
+ void *hook;
+
+ /* Second part. Runtime information for the slab space. */
+
+ struct hurd_slab *slab_first;
+ struct hurd_slab *slab_last;
+
+ /* In the doubly-linked list of slabs, empty slabs come first, after
+ that the slabs that have some buffers allocated, and finally the
+ complete slabs (refcount == 0). FIRST_FREE points to the first
+ non-empty slab. */
+ struct hurd_slab *first_free;
+
+ /* For easy checking, this holds the value the reference counter
+ should have for an empty slab. */
+ int full_refcount;
+
+ /* The size of one object. Should include possible alignment as
+ well as the size of the bufctl structure. */
+ size_t size;
+};
+
+
+/* Static initializer. TYPE is used to get size and alignment of
+ objects the slab space will be used to allocate. ALLOCATE_BUFFER
+ may be NULL in which case mmap is called. DEALLOCATE_BUFFER may be
+ NULL in which case munmap is called. CTOR and DTOR are the slab's
+ object constructor and destructor, respectivly and may be NULL if
+ not required. HOOK is passed as user data to the constructor and
+ destructor. */
+#define HURD_SLAB_SPACE_INITIALIZER(TYPE, ALLOC, DEALLOC, CTOR, \
+ DTOR, HOOK) \
+ { \
+ false, \
+ PTHREAD_MUTEX_INITIALIZER, \
+ sizeof (TYPE), \
+ __alignof__ (TYPE), \
+ ALLOC, \
+ DEALLOC, \
+ CTOR, \
+ DTOR, \
+ HOOK \
+ /* The rest of the structure will be filled with zeros, \
+ which is good for us. */ \
+ }
+
+
+/* Create a new slab space with the given object size, alignment,
+ constructor and destructor. ALIGNMENT can be zero.
+ ALLOCATE_BUFFER may be NULL in which case mmap is called.
+ DEALLOCATE_BUFFER may be NULL in which case munmap is called. CTOR
+ and DTOR are the slabs object constructor and destructor,
+ respectivly and may be NULL if not required. HOOK is passed as the
+ first argument to the constructor and destructor. */
+error_t hurd_slab_create (size_t size, size_t alignment,
+ hurd_slab_allocate_buffer_t allocate_buffer,
+ hurd_slab_deallocate_buffer_t deallocate_buffer,
+ hurd_slab_constructor_t constructor,
+ hurd_slab_destructor_t destructor,
+ void *hook,
+ hurd_slab_space_t *space);
+
+/* Destroy all objects and the slab space SPACE. If there were no
+ outstanding allocations free the slab space. Returns EBUSY if
+ there are still allocated objects in the slab space. The dual of
+ hurd_slab_create. */
+error_t hurd_slab_free (hurd_slab_space_t space);
+
+/* Like hurd_slab_create, but does not allocate storage for the slab. */
+error_t hurd_slab_init (hurd_slab_space_t space, size_t size, size_t alignment,
+ hurd_slab_allocate_buffer_t allocate_buffer,
+ hurd_slab_deallocate_buffer_t deallocate_buffer,
+ hurd_slab_constructor_t constructor,
+ hurd_slab_destructor_t destructor,
+ void *hook);
+
+/* Destroy all objects and the slab space SPACE. Returns EBUSY if
+ there are still allocated objects in the slab. The dual of
+ hurd_slab_init. */
+error_t hurd_slab_destroy (hurd_slab_space_t space);
+
+/* Allocate a new object from the slab space SPACE. */
+error_t hurd_slab_alloc (hurd_slab_space_t space, void **buffer);
+
+/* Deallocate the object BUFFER from the slab space SPACE. */
+void hurd_slab_dealloc (hurd_slab_space_t space, void *buffer);
+
+/* Create a more strongly typed slab interface a la a C++ template.
+
+ NAME is the name of the new slab class. NAME is used to synthesize
+ names for the class types and methods using the following rule: the
+ hurd_ namespace will prefix all method names followed by NAME
+ followed by an underscore and finally the method name. The
+ following are thus exposed:
+
+ Types:
+ struct hurd_NAME_slab_space
+ hurd_NAME_slab_space_t
+
+ error_t (*hurd_NAME_slab_constructor_t) (void *hook, element_type *buffer)
+ void (*hurd_NAME_slab_destructor_t) (void *hook, element_type *buffer)
+
+ Functions:
+ error_t hurd_NAME_slab_create (hurd_slab_allocate_buffer_t
+ allocate_buffer,
+ hurd_slab_deallocate_buffer_t
+ deallocate_buffer,
+ hurd_NAME_slab_constructor_t constructor,
+ hurd_NAME_slab_destructor_t destructor,
+ void *hook,
+ hurd_NAME_slab_space_t *space);
+ error_t hurd_NAME_slab_free (hurd_NAME_slab_space_t space);
+
+ error_t hurd_NAME_slab_init (hurd_NAME_slab_space_t space,
+ hurd_slab_allocate_buffer_t allocate_buffer,
+ hurd_slab_deallocate_buffer_t
+ deallocate_buffer,
+ hurd_NAME_slab_constructor_t constructor,
+ hurd_NAME_slab_destructor_t destructor,
+ void *hook);
+ error_t hurd_NAME_slab_destroy (hurd_NAME_slab_space_t space);
+
+ error_t hurd_NAME_slab_alloc (hurd_NAME_slab_space_t space,
+ element_type **buffer);
+ void hurd_NAME_slab_dealloc (hurd_NAME_slab_space_t space,
+ element_type *buffer);
+
+ ELEMENT_TYPE is the type of elements to store in the slab. If you
+ want the slab to contain struct foo, pass `struct foo' as the
+ ELEMENT_TYPE (not `struct foo *'!!!).
+
+*/
+#define SLAB_CLASS(name, element_type) \
+struct hurd_##name##_slab_space \
+{ \
+ struct hurd_slab_space space; \
+}; \
+typedef struct hurd_##name##_slab_space *hurd_##name##_slab_space_t; \
+ \
+typedef error_t (*hurd_##name##_slab_constructor_t) (void *hook, \
+ element_type *buffer); \
+ \
+typedef void (*hurd_##name##_slab_destructor_t) (void *hook, \
+ element_type *buffer); \
+ \
+static inline error_t \
+hurd_##name##_slab_create (hurd_slab_allocate_buffer_t allocate_buffer, \
+ hurd_slab_deallocate_buffer_t deallocate_buffer, \
+ hurd_##name##_slab_constructor_t constructor, \
+ hurd_##name##_slab_destructor_t destructor, \
+ void *hook, \
+ hurd_##name##_slab_space_t *space) \
+{ \
+ union \
+ { \
+ hurd_##name##_slab_constructor_t t; \
+ hurd_slab_constructor_t u; \
+ } con; \
+ union \
+ { \
+ hurd_##name##_slab_destructor_t t; \
+ hurd_slab_destructor_t u; \
+ } des; \
+ union \
+ { \
+ hurd_##name##_slab_space_t *t; \
+ hurd_slab_space_t *u; \
+ } foo; \
+ con.t = constructor; \
+ des.t = destructor; \
+ foo.t = space; \
+ \
+ return hurd_slab_create(sizeof (element_type), __alignof__ (element_type), \
+ allocate_buffer, deallocate_buffer, \
+ con.u, des.u, hook, foo.u); \
+} \
+ \
+static inline error_t \
+hurd_##name##_slab_free (hurd_##name##_slab_space_t space) \
+{ \
+ return hurd_slab_free (&space->space); \
+} \
+ \
+static inline error_t \
+hurd_##name##_slab_init (hurd_##name##_slab_space_t space, \
+ hurd_slab_allocate_buffer_t allocate_buffer, \
+ hurd_slab_deallocate_buffer_t deallocate_buffer, \
+ hurd_##name##_slab_constructor_t constructor, \
+ hurd_##name##_slab_destructor_t destructor, \
+ void *hook) \
+{ \
+ union \
+ { \
+ hurd_##name##_slab_constructor_t t; \
+ hurd_slab_constructor_t u; \
+ } con; \
+ union \
+ { \
+ hurd_##name##_slab_destructor_t t; \
+ hurd_slab_destructor_t u; \
+ } des; \
+ con.t = constructor; \
+ des.t = destructor; \
+ \
+ return hurd_slab_init (&space->space, \
+ sizeof (element_type), __alignof__ (element_type), \
+ allocate_buffer, deallocate_buffer, \
+ con.u, des.u, hook); \
+} \
+ \
+static inline error_t \
+hurd_##name##_slab_destroy (hurd_##name##_slab_space_t space) \
+{ \
+ return hurd_slab_destroy (&space->space); \
+} \
+ \
+static inline error_t \
+hurd_##name##_slab_alloc (hurd_##name##_slab_space_t space, \
+ element_type **buffer) \
+{ \
+ union \
+ { \
+ element_type **e; \
+ void **v; \
+ } foo; \
+ foo.e = buffer; \
+ \
+ return hurd_slab_alloc (&space->space, foo.v); \
+} \
+ \
+static inline void \
+hurd_##name##_slab_dealloc (hurd_##name##_slab_space_t space, \
+ element_type *buffer) \
+{ \
+ union \
+ { \
+ element_type *e; \
+ void *v; \
+ } foo; \
+ foo.e = buffer; \
+ \
+ hurd_slab_dealloc (&space->space, foo.v); \
+}
+
+#endif /* _HURD_SLAB_H */