commit-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[hurd] 16/75: Add libhurd-slab


From: Samuel Thibault
Subject: [hurd] 16/75: Add libhurd-slab
Date: Thu, 14 Jan 2016 01:04:05 +0000

This is an automated email from the git hooks/post-receive script.

sthibault pushed a commit to branch dde
in repository hurd.

commit 8b21a60d8cf2916e4dbc3019d39d0b380abe7a88
Author: Samuel Thibault <address@hidden>
Date:   Sun Nov 29 13:13:39 2015 +0100

    Add libhurd-slab
    
    * libhurd-slab: New directory
    * Makefile (lib-subdirs): Add libhurd-slab.
---
 Makefile              |   3 +-
 libhurd-slab/Makefile |  33 ++++
 libhurd-slab/slab.c   | 518 ++++++++++++++++++++++++++++++++++++++++++++++++++
 libhurd-slab/slab.h   | 338 ++++++++++++++++++++++++++++++++
 4 files changed, 891 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index ebda8aa..d48baaa 100644
--- a/Makefile
+++ b/Makefile
@@ -28,7 +28,8 @@ include ./Makeconf
 # Hurd libraries
 lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \
              libpager libfshelp libdiskfs libtrivfs libps \
-             libnetfs libpipe libstore libhurdbugaddr libftpconn libcons
+             libnetfs libpipe libstore libhurdbugaddr libftpconn libcons \
+             libhurd-slab
 
 # Hurd programs
 prog-subdirs = auth proc exec term \
diff --git a/libhurd-slab/Makefile b/libhurd-slab/Makefile
new file mode 100644
index 0000000..925f70c
--- /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 0000000..5a12a43
--- /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 0000000..6eeb8e4
--- /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 <address@hidden>
+
+   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 */

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/pkg-hurd/hurd.git



reply via email to

[Prev in Thread] Current Thread [Next in Thread]