/[hurd]/hurd-l4/libhurd-slab/slab.c
ViewVC logotype

Diff of /hurd-l4/libhurd-slab/slab.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.5 by marcus, Wed Sep 17 15:12:22 2003 UTC revision 1.6 by marcus, Mon Sep 22 14:36:03 2003 UTC
# Line 18  Line 18 
18     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19     02111-1307 USA.  */     02111-1307 USA.  */
20    
 /* Known limitation: No memory is returned to the system.  As a  
    side-effect, the destructor will never be called.  */  
   
21  #if HAVE_CONFIG_H  #if HAVE_CONFIG_H
22  #include <config.h>  #include <config.h>
23  #endif  #endif
# Line 32  Line 29 
29  #include <string.h>  #include <string.h>
30  #include <unistd.h>  #include <unistd.h>
31  #include <pthread.h>  #include <pthread.h>
32    #include <stdint.h>
33    
34  #include "slab.h"  #include "slab.h"
35    
36    
 /* We do just want to initialize the allocator once.  */  
 static pthread_once_t __hurd_slab_init = PTHREAD_ONCE_INIT;  
   
37  /* Number of pages the slab allocator has allocated.  */  /* Number of pages the slab allocator has allocated.  */
38  static int __hurd_slab_nr_pages;  static int __hurd_slab_nr_pages;
39    
40  /* Internal slab used to allocate hurd_slab_space structures.  */  /* List of created slab spaces.  */
41  static hurd_slab_space_t __hurd_slab_space;  static hurd_slab_space_t space_list;
42    
43    /* Protect __hurd_space_list.  */
44    static pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;
45    
46  /* Buffer control structure.  Lives at the end of an object.  If the  /* Buffer control structure.  Lives at the end of an object.  If the
47     buffer is allocated, SLAB points to the slab to which it belongs.     buffer is allocated, SLAB points to the slab to which it belongs.
# Line 80  struct hurd_slab_space Line 77  struct hurd_slab_space
77    struct hurd_slab *slab_first;    struct hurd_slab *slab_first;
78    struct hurd_slab *slab_last;    struct hurd_slab *slab_last;
79    
80      /* Link in the list of created slab spaces.  */
81      struct hurd_slab_space *space_next;
82    
83    /* In the double linked list of slabs, empty slabs come first,    /* In the double linked list of slabs, empty slabs come first,
84       after that there is the slabs that have some buffers allocated,       after that there is the slabs that have some buffers allocated,
85       and finally the complete slabs (refcount == 0).  FIRST_FREE       and finally the complete slabs (refcount == 0).  FIRST_FREE
# Line 121  insert_slab (struct hurd_slab_space *spa Line 121  insert_slab (struct hurd_slab_space *spa
121      }      }
122  }  }
123    
124    /* Remove SLAB from list of slabs in SPACE.  */
125    static void
126    remove_slab (struct hurd_slab_space *space, struct hurd_slab *slab)
127    {
128      if (slab != space->slab_first
129          && slab != space->slab_last)
130        {
131          slab->next->prev = slab->prev;
132          slab->prev->next = slab->next;
133          return;
134        }
135      if (slab == space->slab_first)
136        {
137          space->slab_first = slab->next;
138          if (space->slab_first)
139            space->slab_first->prev = NULL;
140        }
141      if (slab == space->slab_last)
142        {
143          if (slab->prev)
144            slab->prev->next = NULL;
145          space->slab_last = slab->prev;
146        }
147    }
148    
149    /* Iterate through slabs in SPACE and release memory for slabs that
150       are complete (no allocated buffers).  */
151    error_t
152    reap (struct hurd_slab_space *space)
153    {
154      struct hurd_slab *s, *next, *new_first;
155      error_t err = 0;
156    
157      pthread_mutex_lock (&space->lock);
158    
159      for (s = space->slab_first; s; s = next)
160        {
161          next = s->next;
162    
163          /* If the reference counter is zero there is no allocated
164             buffers, so it can be freed.  */
165          if (!s->refcount)
166            {
167              remove_slab (space, s);
168              
169              /* If there is a destructor it must be invoked for every
170                 buffer in the slab.  */
171              if (space->destructor)
172                {
173                  union hurd_bufctl *bufctl;
174                  for (bufctl = s->free_list; bufctl; bufctl = bufctl->next)
175                    {
176                      void *buffer = (((void *) bufctl)
177                                      - (space->size - sizeof *bufctl));
178                      (*space->destructor) (buffer);
179                    }
180                }
181              /* The slab is located at the end of the page (with the buffers
182                 in front of it), get address by masking with page size.  
183                 This frees the slab and all its buffers, since they live on
184                 the same page.  */
185              err = munmap
186                ((void *) (((uintptr_t) s) & ~(getpagesize () - 1)),
187                 getpagesize ());
188              if (err)
189                break;
190              __hurd_slab_nr_pages--;
191            }
192        }
193    
194      /* Even in the case of an error, first_free must be updated since
195         that slab may have been deallocated.  */
196      new_first = space->slab_first;
197      while (new_first)
198        {
199          if (new_first->refcount != space->full_refcount)
200            break;
201          new_first = new_first->next;
202        }
203      space->first_free = new_first;
204    
205      pthread_mutex_unlock (&space->lock);
206      return err;
207    }
208    
209    /* Release unused memory.  */
210    error_t
211    hurd_slab_reap (void)
212    {
213      struct hurd_slab_space *space;
214      error_t err = 0;
215    
216      pthread_mutex_lock (&list_lock);
217      for (space = space_list; space; space = space->space_next)
218        {
219          if ((err = reap (space)))
220            break;
221        }
222      pthread_mutex_unlock (&list_lock);
223      return err;
224    }
225    
226  /* SPACE has no more memory.  Allocate new slab and insert it into the  /* SPACE has no more memory.  Allocate new slab and insert it into the
227     list, repoint free_list and return possible error.  */     list, repoint free_list and return possible error.  */
# Line 170  grow (struct hurd_slab_space *space) Line 271  grow (struct hurd_slab_space *space)
271    return 0;    return 0;
272  }  }
273    
274    /* Insert SPACE into list of created slab spaces.  */
 /* Initialize the internal slab space used for allocating other slab  
    spaces.  The usual chicken and the egg problem.  */  
275  static void  static void
276  init_allocator (void)  insert_space (struct hurd_slab_space *space)
277  {  {
278    __hurd_slab_space = malloc (sizeof (struct hurd_slab_space));    pthread_mutex_lock (&list_lock);
279    __hurd_slab_space->size = (sizeof (struct hurd_slab_space)    if (!space_list)
280                               + sizeof (union hurd_bufctl));      space_list = space;
281    __hurd_slab_space->full_refcount = ((getpagesize ()    else
282                                         - sizeof (struct hurd_slab))      {
283                                        / __hurd_slab_space->size);        space->space_next = space_list;
284    pthread_mutex_init (&__hurd_slab_space->lock, NULL);        space_list = space;
285        }
286      pthread_mutex_unlock (&list_lock);
287  }  }
288    
289    
# Line 202  hurd_slab_create (size_t size, size_t al Line 303  hurd_slab_create (size_t size, size_t al
303                - sizeof (union hurd_bufctl)))                - sizeof (union hurd_bufctl)))
304      return EINVAL;      return EINVAL;
305    
306    pthread_once (&__hurd_slab_init, init_allocator);    *space = malloc (sizeof (struct hurd_slab_space));
307      if (!*space)
308    if ((err = hurd_slab_alloc (__hurd_slab_space, (void **) space)))      return ENOMEM;
     return err;  
309    memset (*space, 0, sizeof (struct hurd_slab_space));    memset (*space, 0, sizeof (struct hurd_slab_space));
310    
311    err = pthread_mutex_init (&(*space)->lock, NULL);    err = pthread_mutex_init (&(*space)->lock, NULL);
312    if (err)    if (err)
313      {      {
314        hurd_slab_dealloc (__hurd_slab_space, *space);        free (*space);
315        return err;        return err;
316      }      }
317    
# Line 230  hurd_slab_create (size_t size, size_t al Line 330  hurd_slab_create (size_t size, size_t al
330    /* Calculate the number of objects that fit in a slab.  */    /* Calculate the number of objects that fit in a slab.  */
331    (*space)->full_refcount    (*space)->full_refcount
332      = ((getpagesize () - sizeof (struct hurd_slab)) / (*space)->size);      = ((getpagesize () - sizeof (struct hurd_slab)) / (*space)->size);
333    
334      insert_space (*space);
335    return 0;    return 0;
336  }  }
337    

Legend:
Removed from v.1.5  
changed lines
  Added in v.1.6

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26