Changeset da1bafb in mainline for kernel/generic/src/mm/slab.c


Ignore:
Timestamp:
2010-05-24T18:57:31Z (14 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
0095368
Parents:
666f492
Message:

major code revision

  • replace spinlocks taken with interrupts disabled with irq_spinlocks
  • change spacing (not indendation) to be tab-size independent
  • use unsigned integer types where appropriate (especially bit flags)
  • visual separation
  • remove argument names in function prototypes
  • string changes
  • correct some formating directives
  • replace various cryptic single-character variables (t, a, m, c, b, etc.) with proper identifiers (thread, task, timeout, as, itm, itc, etc.)
  • unify some assembler constructs
  • unused page table levels are now optimized out in compile time
  • replace several ints (with boolean semantics) with bools
  • use specifically sized types instead of generic types where appropriate (size_t, uint32_t, btree_key_t)
  • improve comments
  • split asserts with conjuction into multiple independent asserts
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/mm/slab.c

    r666f492 rda1bafb  
    3333/**
    3434 * @file
    35  * @brief       Slab allocator.
     35 * @brief Slab allocator.
    3636 *
    3737 * The slab allocator is closely modelled after OpenSolaris slab allocator.
     
    5050 *
    5151 * The slab allocator supports per-CPU caches ('magazines') to facilitate
    52  * good SMP scaling. 
     52 * good SMP scaling.
    5353 *
    5454 * When a new object is being allocated, it is first checked, if it is
     
    6565 * thrashing when somebody is allocating/deallocating 1 item at the magazine
    6666 * size boundary. LIFO order is enforced, which should avoid fragmentation
    67  * as much as possible. 
    68  * 
     67 * as much as possible.
     68 *
    6969 * Every cache contains list of full slabs and list of partially full slabs.
    7070 * Empty slabs are immediately freed (thrashing will be avoided because
    71  * of magazines). 
     71 * of magazines).
    7272 *
    7373 * The slab information structure is kept inside the data area, if possible.
     
    9595 *
    9696 * @todo
    97  * it might be good to add granularity of locks even to slab level,
     97 * It might be good to add granularity of locks even to slab level,
    9898 * we could then try_spinlock over all partial slabs and thus improve
    99  * scalability even on slab level
     99 * scalability even on slab level.
     100 *
    100101 */
    101102
     
    114115#include <macros.h>
    115116
    116 SPINLOCK_INITIALIZE(slab_cache_lock);
     117IRQ_SPINLOCK_STATIC_INITIALIZE(slab_cache_lock);
    117118static LIST_INITIALIZE(slab_cache_list);
    118119
    119120/** Magazine cache */
    120121static slab_cache_t mag_cache;
     122
    121123/** Cache for cache descriptors */
    122124static slab_cache_t slab_cache_cache;
     125
    123126/** Cache for external slab descriptors
    124127 * This time we want per-cpu cache, so do not make it static
     
    128131 */
    129132static slab_cache_t *slab_extern_cache;
     133
    130134/** Caches for malloc */
    131135static slab_cache_t *malloc_caches[SLAB_MAX_MALLOC_W - SLAB_MIN_MALLOC_W + 1];
     136
    132137static const char *malloc_names[] =  {
    133138        "malloc-16",
     
    154159/** Slab descriptor */
    155160typedef struct {
    156         slab_cache_t *cache;    /**< Pointer to parent cache. */
    157         link_t link;            /**< List of full/partial slabs. */
    158         void *start;            /**< Start address of first available item. */
    159         size_t available;       /**< Count of available items in this slab. */
    160         size_t nextavail;       /**< The index of next available item. */
     161        slab_cache_t *cache;  /**< Pointer to parent cache. */
     162        link_t link;          /**< List of full/partial slabs. */
     163        void *start;          /**< Start address of first available item. */
     164        size_t available;     /**< Count of available items in this slab. */
     165        size_t nextavail;     /**< The index of next available item. */
    161166} slab_t;
    162167
    163168#ifdef CONFIG_DEBUG
    164 static int _slab_initialized = 0;
     169static unsigned int _slab_initialized = 0;
    165170#endif
    166171
    167172/**************************************/
    168173/* Slab allocation functions          */
    169 
    170 /**
    171  * Allocate frames for slab space and initialize
    172  *
    173  */
    174 static slab_t *slab_space_alloc(slab_cache_t *cache, int flags)
    175 {
    176         void *data;
     174/**************************************/
     175
     176/** Allocate frames for slab space and initialize
     177 *
     178 */
     179static slab_t *slab_space_alloc(slab_cache_t *cache, unsigned int flags)
     180{
     181       
     182       
     183        size_t zone = 0;
     184       
     185        void *data = frame_alloc_generic(cache->order, FRAME_KA | flags, &zone);
     186        if (!data) {
     187                return NULL;
     188        }
     189       
    177190        slab_t *slab;
    178191        size_t fsize;
    179         unsigned int i;
    180         size_t zone = 0;
    181        
    182         data = frame_alloc_generic(cache->order, FRAME_KA | flags, &zone);
    183         if (!data) {
    184                 return NULL;
    185         }
     192       
    186193        if (!(cache->flags & SLAB_CACHE_SLINSIDE)) {
    187194                slab = slab_alloc(slab_extern_cache, flags);
     
    196203       
    197204        /* Fill in slab structures */
    198         for (i = 0; i < ((unsigned int) 1 << cache->order); i++)
     205        size_t i;
     206        for (i = 0; i < ((size_t) 1 << cache->order); i++)
    199207                frame_set_parent(ADDR2PFN(KA2PA(data)) + i, slab, zone);
    200 
     208       
    201209        slab->start = data;
    202210        slab->available = cache->objects;
    203211        slab->nextavail = 0;
    204212        slab->cache = cache;
    205 
     213       
    206214        for (i = 0; i < cache->objects; i++)
    207                 *((int *) (slab->start + i*cache->size)) = i + 1;
    208 
     215                *((size_t *) (slab->start + i * cache->size)) = i + 1;
     216       
    209217        atomic_inc(&cache->allocated_slabs);
    210218        return slab;
    211219}
    212220
    213 /**
    214  * Deallocate space associated with slab
     221/** Deallocate space associated with slab
    215222 *
    216223 * @return number of freed frames
     224 *
    217225 */
    218226static size_t slab_space_free(slab_cache_t *cache, slab_t *slab)
    219227{
    220228        frame_free(KA2PA(slab->start));
    221         if (! (cache->flags & SLAB_CACHE_SLINSIDE))
     229        if (!(cache->flags & SLAB_CACHE_SLINSIDE))
    222230                slab_free(slab_extern_cache, slab);
    223 
     231       
    224232        atomic_dec(&cache->allocated_slabs);
    225233       
    226         return 1 << cache->order;
     234        return (1 << cache->order);
    227235}
    228236
    229237/** Map object to slab structure */
    230 static slab_t * obj2slab(void *obj)
     238static slab_t *obj2slab(void *obj)
    231239{
    232240        return (slab_t *) frame_get_parent(ADDR2PFN(KA2PA(obj)), 0);
    233241}
    234242
    235 /**************************************/
     243/******************/
    236244/* Slab functions */
    237 
    238 
    239 /**
    240  * Return object to slab and call a destructor
     245/******************/
     246
     247/** Return object to slab and call a destructor
    241248 *
    242249 * @param slab If the caller knows directly slab of the object, otherwise NULL
    243250 *
    244251 * @return Number of freed pages
     252 *
    245253 */
    246254static size_t slab_obj_destroy(slab_cache_t *cache, void *obj, slab_t *slab)
    247255{
    248         int freed = 0;
    249 
    250256        if (!slab)
    251257                slab = obj2slab(obj);
    252 
     258       
    253259        ASSERT(slab->cache == cache);
    254 
     260       
     261        size_t freed = 0;
     262       
    255263        if (cache->destructor)
    256264                freed = cache->destructor(obj);
     
    258266        spinlock_lock(&cache->slablock);
    259267        ASSERT(slab->available < cache->objects);
    260 
    261         *((int *)obj) = slab->nextavail;
     268       
     269        *((size_t *) obj) = slab->nextavail;
    262270        slab->nextavail = (obj - slab->start) / cache->size;
    263271        slab->available++;
    264 
     272       
    265273        /* Move it to correct list */
    266274        if (slab->available == cache->objects) {
     
    268276                list_remove(&slab->link);
    269277                spinlock_unlock(&cache->slablock);
    270 
     278               
    271279                return freed + slab_space_free(cache, slab);
    272 
    273280        } else if (slab->available == 1) {
    274281                /* It was in full, move to partial */
     
    276283                list_prepend(&slab->link, &cache->partial_slabs);
    277284        }
     285       
    278286        spinlock_unlock(&cache->slablock);
    279287        return freed;
    280288}
    281289
    282 /**
    283  * Take new object from slab or create new if needed
     290/** Take new object from slab or create new if needed
    284291 *
    285292 * @return Object address or null
     293 *
    286294 */
    287295static void *slab_obj_create(slab_cache_t *cache, int flags)
    288296{
     297        spinlock_lock(&cache->slablock);
     298       
    289299        slab_t *slab;
    290         void *obj;
    291 
    292         spinlock_lock(&cache->slablock);
    293 
     300       
    294301        if (list_empty(&cache->partial_slabs)) {
    295                 /* Allow recursion and reclaiming
     302                /*
     303                 * Allow recursion and reclaiming
    296304                 * - this should work, as the slab control structures
    297305                 *   are small and do not need to allocate with anything
    298306                 *   other than frame_alloc when they are allocating,
    299307                 *   that's why we should get recursion at most 1-level deep
     308                 *
    300309                 */
    301310                spinlock_unlock(&cache->slablock);
     
    303312                if (!slab)
    304313                        return NULL;
     314               
    305315                spinlock_lock(&cache->slablock);
    306316        } else {
     
    309319                list_remove(&slab->link);
    310320        }
    311         obj = slab->start + slab->nextavail * cache->size;
    312         slab->nextavail = *((int *)obj);
     321       
     322        void *obj = slab->start + slab->nextavail * cache->size;
     323        slab->nextavail = *((size_t *) obj);
    313324        slab->available--;
    314 
     325       
    315326        if (!slab->available)
    316327                list_prepend(&slab->link, &cache->full_slabs);
    317328        else
    318329                list_prepend(&slab->link, &cache->partial_slabs);
    319 
     330       
    320331        spinlock_unlock(&cache->slablock);
    321 
    322         if (cache->constructor && cache->constructor(obj, flags)) {
     332       
     333        if ((cache->constructor) && (cache->constructor(obj, flags))) {
    323334                /* Bad, bad, construction failed */
    324335                slab_obj_destroy(cache, obj, slab);
    325336                return NULL;
    326337        }
     338       
    327339        return obj;
    328340}
    329341
    330 /**************************************/
     342/****************************/
    331343/* CPU-Cache slab functions */
    332 
    333 /**
    334  * Finds a full magazine in cache, takes it from list
    335  * and returns it
    336  *
    337  * @param first If true, return first, else last mag
    338  */
    339 static slab_magazine_t *get_mag_from_cache(slab_cache_t *cache, int first)
     344/****************************/
     345
     346/** Find a full magazine in cache, take it from list and return it
     347 *
     348 * @param first If true, return first, else last mag.
     349 *
     350 */
     351static slab_magazine_t *get_mag_from_cache(slab_cache_t *cache, bool first)
    340352{
    341353        slab_magazine_t *mag = NULL;
    342354        link_t *cur;
    343 
     355       
    344356        spinlock_lock(&cache->maglock);
    345357        if (!list_empty(&cache->magazines)) {
     
    348360                else
    349361                        cur = cache->magazines.prev;
     362               
    350363                mag = list_get_instance(cur, slab_magazine_t, link);
    351364                list_remove(&mag->link);
    352365                atomic_dec(&cache->magazine_counter);
    353366        }
     367       
    354368        spinlock_unlock(&cache->maglock);
    355369        return mag;
    356370}
    357371
    358 /** Prepend magazine to magazine list in cache */
     372/** Prepend magazine to magazine list in cache
     373 *
     374 */
    359375static void put_mag_to_cache(slab_cache_t *cache, slab_magazine_t *mag)
    360376{
    361377        spinlock_lock(&cache->maglock);
    362 
     378       
    363379        list_prepend(&mag->link, &cache->magazines);
    364380        atomic_inc(&cache->magazine_counter);
     
    367383}
    368384
    369 /**
    370  * Free all objects in magazine and free memory associated with magazine
     385/** Free all objects in magazine and free memory associated with magazine
    371386 *
    372387 * @return Number of freed pages
     388 *
    373389 */
    374390static size_t magazine_destroy(slab_cache_t *cache, slab_magazine_t *mag)
    375391{
    376         unsigned int i;
     392        size_t i;
    377393        size_t frames = 0;
    378 
     394       
    379395        for (i = 0; i < mag->busy; i++) {
    380396                frames += slab_obj_destroy(cache, mag->objs[i], NULL);
     
    383399       
    384400        slab_free(&mag_cache, mag);
    385 
     401       
    386402        return frames;
    387403}
    388404
    389 /**
    390  * Find full magazine, set it as current and return it
     405/** Find full magazine, set it as current and return it
    391406 *
    392407 * Assume cpu_magazine lock is held
     408 *
    393409 */
    394410static slab_magazine_t *get_full_current_mag(slab_cache_t *cache)
    395411{
    396         slab_magazine_t *cmag, *lastmag, *newmag;
    397 
    398         cmag = cache->mag_cache[CPU->id].current;
    399         lastmag = cache->mag_cache[CPU->id].last;
     412        slab_magazine_t *cmag = cache->mag_cache[CPU->id].current;
     413        slab_magazine_t *lastmag = cache->mag_cache[CPU->id].last;
     414       
    400415        if (cmag) { /* First try local CPU magazines */
    401416                if (cmag->busy)
    402417                        return cmag;
    403 
    404                 if (lastmag && lastmag->busy) {
     418               
     419                if ((lastmag) && (lastmag->busy)) {
    405420                        cache->mag_cache[CPU->id].current = lastmag;
    406421                        cache->mag_cache[CPU->id].last = cmag;
     
    408423                }
    409424        }
     425       
    410426        /* Local magazines are empty, import one from magazine list */
    411         newmag = get_mag_from_cache(cache, 1);
     427        slab_magazine_t *newmag = get_mag_from_cache(cache, 1);
    412428        if (!newmag)
    413429                return NULL;
    414 
     430       
    415431        if (lastmag)
    416432                magazine_destroy(cache, lastmag);
    417 
     433       
    418434        cache->mag_cache[CPU->id].last = cmag;
    419435        cache->mag_cache[CPU->id].current = newmag;
     436       
    420437        return newmag;
    421438}
    422439
    423 /**
    424  * Try to find object in CPU-cache magazines
     440/** Try to find object in CPU-cache magazines
    425441 *
    426442 * @return Pointer to object or NULL if not available
     443 *
    427444 */
    428445static void *magazine_obj_get(slab_cache_t *cache)
    429446{
    430         slab_magazine_t *mag;
    431         void *obj;
    432 
    433447        if (!CPU)
    434448                return NULL;
    435 
     449       
    436450        spinlock_lock(&cache->mag_cache[CPU->id].lock);
    437 
    438         mag = get_full_current_mag(cache);
     451       
     452        slab_magazine_t *mag = get_full_current_mag(cache);
    439453        if (!mag) {
    440454                spinlock_unlock(&cache->mag_cache[CPU->id].lock);
    441455                return NULL;
    442456        }
    443         obj = mag->objs[--mag->busy];
     457       
     458        void *obj = mag->objs[--mag->busy];
    444459        spinlock_unlock(&cache->mag_cache[CPU->id].lock);
     460       
    445461        atomic_dec(&cache->cached_objs);
    446462       
     
    448464}
    449465
    450 /**
    451  * Assure that the current magazine is empty, return pointer to it, or NULL if
    452  * no empty magazine is available and cannot be allocated
     466/** Assure that the current magazine is empty, return pointer to it,
     467 * or NULL if no empty magazine is available and cannot be allocated
    453468 *
    454469 * Assume mag_cache[CPU->id].lock is held
    455470 *
    456  * We have 2 magazines bound to processor.
    457  * First try the current.
    458  *  If full, try the last.
    459  *   If full, put to magazines list.
    460  *   allocate new, exchange last & current
     471 * We have 2 magazines bound to processor.
     472 * First try the current.
     473 * If full, try the last.
     474 * If full, put to magazines list.
    461475 *
    462476 */
    463477static slab_magazine_t *make_empty_current_mag(slab_cache_t *cache)
    464478{
    465         slab_magazine_t *cmag,*lastmag,*newmag;
    466 
    467         cmag = cache->mag_cache[CPU->id].current;
    468         lastmag = cache->mag_cache[CPU->id].last;
    469 
     479        slab_magazine_t *cmag = cache->mag_cache[CPU->id].current;
     480        slab_magazine_t *lastmag = cache->mag_cache[CPU->id].last;
     481       
    470482        if (cmag) {
    471483                if (cmag->busy < cmag->size)
    472484                        return cmag;
    473                 if (lastmag && lastmag->busy < lastmag->size) {
     485               
     486                if ((lastmag) && (lastmag->busy < lastmag->size)) {
    474487                        cache->mag_cache[CPU->id].last = cmag;
    475488                        cache->mag_cache[CPU->id].current = lastmag;
     
    477490                }
    478491        }
     492       
    479493        /* current | last are full | nonexistent, allocate new */
    480         /* We do not want to sleep just because of caching */
    481         /* Especially we do not want reclaiming to start, as
    482          * this would deadlock */
    483         newmag = slab_alloc(&mag_cache, FRAME_ATOMIC | FRAME_NO_RECLAIM);
     494       
     495        /*
     496         * We do not want to sleep just because of caching,
     497         * especially we do not want reclaiming to start, as
     498         * this would deadlock.
     499         *
     500         */
     501        slab_magazine_t *newmag = slab_alloc(&mag_cache,
     502            FRAME_ATOMIC | FRAME_NO_RECLAIM);
    484503        if (!newmag)
    485504                return NULL;
     505       
    486506        newmag->size = SLAB_MAG_SIZE;
    487507        newmag->busy = 0;
    488 
     508       
    489509        /* Flush last to magazine list */
    490510        if (lastmag)
    491511                put_mag_to_cache(cache, lastmag);
    492 
     512       
    493513        /* Move current as last, save new as current */
    494         cache->mag_cache[CPU->id].last = cmag; 
    495         cache->mag_cache[CPU->id].current = newmag;     
    496 
     514        cache->mag_cache[CPU->id].last = cmag;
     515        cache->mag_cache[CPU->id].current = newmag;
     516       
    497517        return newmag;
    498518}
    499519
    500 /**
    501  * Put object into CPU-cache magazine
    502  *
    503  * @return 0 - success, -1 - could not get memory
     520/** Put object into CPU-cache magazine
     521 *
     522 * @return 0 on success, -1 on no memory
     523 *
    504524 */
    505525static int magazine_obj_put(slab_cache_t *cache, void *obj)
    506526{
    507         slab_magazine_t *mag;
    508 
    509527        if (!CPU)
    510528                return -1;
    511 
     529       
    512530        spinlock_lock(&cache->mag_cache[CPU->id].lock);
    513 
    514         mag = make_empty_current_mag(cache);
     531       
     532        slab_magazine_t *mag = make_empty_current_mag(cache);
    515533        if (!mag) {
    516534                spinlock_unlock(&cache->mag_cache[CPU->id].lock);
     
    519537       
    520538        mag->objs[mag->busy++] = obj;
    521 
     539       
    522540        spinlock_unlock(&cache->mag_cache[CPU->id].lock);
     541       
    523542        atomic_inc(&cache->cached_objs);
     543       
    524544        return 0;
    525545}
    526546
    527 
    528 /**************************************/
     547/************************/
    529548/* Slab cache functions */
    530 
    531 /** Return number of objects that fit in certain cache size */
    532 static unsigned int comp_objects(slab_cache_t *cache)
     549/************************/
     550
     551/** Return number of objects that fit in certain cache size
     552 *
     553 */
     554static size_t comp_objects(slab_cache_t *cache)
    533555{
    534556        if (cache->flags & SLAB_CACHE_SLINSIDE)
    535                 return ((PAGE_SIZE << cache->order) - sizeof(slab_t)) /
    536                     cache->size;
    537         else 
     557                return ((PAGE_SIZE << cache->order)
     558                    - sizeof(slab_t)) / cache->size;
     559        else
    538560                return (PAGE_SIZE << cache->order) / cache->size;
    539561}
    540562
    541 /** Return wasted space in slab */
    542 static unsigned int badness(slab_cache_t *cache)
    543 {
    544         unsigned int objects;
    545         unsigned int ssize;
    546 
    547         objects = comp_objects(cache);
    548         ssize = PAGE_SIZE << cache->order;
     563/** Return wasted space in slab
     564 *
     565 */
     566static size_t badness(slab_cache_t *cache)
     567{
     568        size_t objects = comp_objects(cache);
     569        size_t ssize = PAGE_SIZE << cache->order;
     570       
    549571        if (cache->flags & SLAB_CACHE_SLINSIDE)
    550572                ssize -= sizeof(slab_t);
     573       
    551574        return ssize - objects * cache->size;
    552575}
    553576
    554 /**
    555  * Initialize mag_cache structure in slab cache
     577/** Initialize mag_cache structure in slab cache
     578 *
    556579 */
    557580static bool make_magcache(slab_cache_t *cache)
    558581{
    559         unsigned int i;
    560        
    561582        ASSERT(_slab_initialized >= 2);
    562 
     583       
    563584        cache->mag_cache = malloc(sizeof(slab_mag_cache_t) * config.cpu_count,
    564585            FRAME_ATOMIC);
    565586        if (!cache->mag_cache)
    566587                return false;
    567 
     588       
     589        size_t i;
    568590        for (i = 0; i < config.cpu_count; i++) {
    569591                memsetb(&cache->mag_cache[i], sizeof(cache->mag_cache[i]), 0);
    570592                spinlock_initialize(&cache->mag_cache[i].lock,
    571                     "slab_maglock_cpu");
    572         }
     593                    "slab.cache.mag_cache[].lock");
     594        }
     595       
    573596        return true;
    574597}
    575598
    576 /** Initialize allocated memory as a slab cache */
     599/** Initialize allocated memory as a slab cache
     600 *
     601 */
    577602static void _slab_cache_create(slab_cache_t *cache, const char *name,
    578     size_t size, size_t align, int (*constructor)(void *obj, int kmflag),
    579     int (*destructor)(void *obj), int flags)
    580 {
    581         int pages;
    582         ipl_t ipl;
    583 
     603    size_t size, size_t align, int (*constructor)(void *obj,
     604    unsigned int kmflag), size_t (*destructor)(void *obj), unsigned int flags)
     605{
    584606        memsetb(cache, sizeof(*cache), 0);
    585607        cache->name = name;
    586 
     608       
    587609        if (align < sizeof(unative_t))
    588610                align = sizeof(unative_t);
     611       
    589612        size = ALIGN_UP(size, align);
    590                
     613       
    591614        cache->size = size;
    592 
    593615        cache->constructor = constructor;
    594616        cache->destructor = destructor;
    595617        cache->flags = flags;
    596 
     618       
    597619        list_initialize(&cache->full_slabs);
    598620        list_initialize(&cache->partial_slabs);
    599621        list_initialize(&cache->magazines);
    600         spinlock_initialize(&cache->slablock, "slab_lock");
    601         spinlock_initialize(&cache->maglock, "slab_maglock");
     622       
     623        spinlock_initialize(&cache->slablock, "slab.cache.slablock");
     624        spinlock_initialize(&cache->maglock, "slab.cache.maglock");
     625       
    602626        if (!(cache->flags & SLAB_CACHE_NOMAGAZINE))
    603627                (void) make_magcache(cache);
    604 
     628       
    605629        /* Compute slab sizes, object counts in slabs etc. */
    606630        if (cache->size < SLAB_INSIDE_SIZE)
    607631                cache->flags |= SLAB_CACHE_SLINSIDE;
    608 
     632       
    609633        /* Minimum slab order */
    610         pages = SIZE2FRAMES(cache->size);
     634        size_t pages = SIZE2FRAMES(cache->size);
     635       
    611636        /* We need the 2^order >= pages */
    612637        if (pages == 1)
     
    614639        else
    615640                cache->order = fnzb(pages - 1) + 1;
    616 
    617         while (badness(cache) > SLAB_MAX_BADNESS(cache)) {
     641       
     642        while (badness(cache) > SLAB_MAX_BADNESS(cache))
    618643                cache->order += 1;
    619         }
     644       
    620645        cache->objects = comp_objects(cache);
     646       
    621647        /* If info fits in, put it inside */
    622648        if (badness(cache) > sizeof(slab_t))
    623649                cache->flags |= SLAB_CACHE_SLINSIDE;
    624 
     650       
    625651        /* Add cache to cache list */
    626         ipl = interrupts_disable();
    627         spinlock_lock(&slab_cache_lock);
    628 
     652        irq_spinlock_lock(&slab_cache_lock, true);
    629653        list_append(&cache->link, &slab_cache_list);
    630 
    631         spinlock_unlock(&slab_cache_lock);
    632         interrupts_restore(ipl);
    633 }
    634 
    635 /** Create slab cache */
     654        irq_spinlock_unlock(&slab_cache_lock, true);
     655}
     656
     657/** Create slab cache
     658 *
     659 */
    636660slab_cache_t *slab_cache_create(const char *name, size_t size, size_t align,
    637     int (*constructor)(void *obj, int kmflag), int (*destructor)(void *obj),
    638     int flags)
    639 {
    640         slab_cache_t *cache;
    641 
    642         cache = slab_alloc(&slab_cache_cache, 0);
     661    int (*constructor)(void *obj, unsigned int kmflag),
     662    size_t (*destructor)(void *obj), unsigned int flags)
     663{
     664        slab_cache_t *cache = slab_alloc(&slab_cache_cache, 0);
    643665        _slab_cache_create(cache, name, size, align, constructor, destructor,
    644666            flags);
     667       
    645668        return cache;
    646669}
    647670
    648 /**
    649  * Reclaim space occupied by objects that are already free
     671/** Reclaim space occupied by objects that are already free
    650672 *
    651673 * @param flags If contains SLAB_RECLAIM_ALL, do aggressive freeing
     674 *
    652675 * @return Number of freed pages
    653  */
    654 static size_t _slab_reclaim(slab_cache_t *cache, int flags)
    655 {
    656         unsigned int i;
     676 *
     677 */
     678static size_t _slab_reclaim(slab_cache_t *cache, unsigned int flags)
     679{
     680        if (cache->flags & SLAB_CACHE_NOMAGAZINE)
     681                return 0; /* Nothing to do */
     682       
     683        /*
     684         * We count up to original magazine count to avoid
     685         * endless loop
     686         */
     687        atomic_count_t magcount = atomic_get(&cache->magazine_counter);
     688       
    657689        slab_magazine_t *mag;
    658690        size_t frames = 0;
    659         int magcount;
    660        
    661         if (cache->flags & SLAB_CACHE_NOMAGAZINE)
    662                 return 0; /* Nothing to do */
    663 
    664         /* We count up to original magazine count to avoid
    665          * endless loop
    666          */
    667         magcount = atomic_get(&cache->magazine_counter);
    668         while (magcount-- && (mag=get_mag_from_cache(cache, 0))) {
    669                 frames += magazine_destroy(cache,mag);
    670                 if (!(flags & SLAB_RECLAIM_ALL) && frames)
     691       
     692        while ((magcount--) && (mag = get_mag_from_cache(cache, 0))) {
     693                frames += magazine_destroy(cache, mag);
     694                if ((!(flags & SLAB_RECLAIM_ALL)) && (frames))
    671695                        break;
    672696        }
     
    675699                /* Free cpu-bound magazines */
    676700                /* Destroy CPU magazines */
     701                size_t i;
    677702                for (i = 0; i < config.cpu_count; i++) {
    678703                        spinlock_lock(&cache->mag_cache[i].lock);
    679 
     704                       
    680705                        mag = cache->mag_cache[i].current;
    681706                        if (mag)
     
    687712                                frames += magazine_destroy(cache, mag);
    688713                        cache->mag_cache[i].last = NULL;
    689 
     714                       
    690715                        spinlock_unlock(&cache->mag_cache[i].lock);
    691716                }
    692717        }
    693 
     718       
    694719        return frames;
    695720}
    696721
    697 /** Check that there are no slabs and remove cache from system  */
     722/** Check that there are no slabs and remove cache from system
     723 *
     724 */
    698725void slab_cache_destroy(slab_cache_t *cache)
    699726{
    700         ipl_t ipl;
    701 
    702         /* First remove cache from link, so that we don't need
     727        /*
     728         * First remove cache from link, so that we don't need
    703729         * to disable interrupts later
     730         *
    704731         */
    705 
    706         ipl = interrupts_disable();
    707         spinlock_lock(&slab_cache_lock);
    708 
     732        irq_spinlock_lock(&slab_cache_lock, true);
    709733        list_remove(&cache->link);
    710 
    711         spinlock_unlock(&slab_cache_lock);
    712         interrupts_restore(ipl);
    713 
    714         /* Do not lock anything, we assume the software is correct and
    715          * does not touch the cache when it decides to destroy it */
     734        irq_spinlock_unlock(&slab_cache_lock, true);
     735       
     736        /*
     737         * Do not lock anything, we assume the software is correct and
     738         * does not touch the cache when it decides to destroy it
     739         *
     740         */
    716741       
    717742        /* Destroy all magazines */
    718743        _slab_reclaim(cache, SLAB_RECLAIM_ALL);
    719 
     744       
    720745        /* All slabs must be empty */
    721         if (!list_empty(&cache->full_slabs) ||
    722             !list_empty(&cache->partial_slabs))
     746        if ((!list_empty(&cache->full_slabs)) ||
     747            (!list_empty(&cache->partial_slabs)))
    723748                panic("Destroying cache that is not empty.");
    724 
     749       
    725750        if (!(cache->flags & SLAB_CACHE_NOMAGAZINE))
    726751                free(cache->mag_cache);
     752       
    727753        slab_free(&slab_cache_cache, cache);
    728754}
    729755
    730 /** Allocate new object from cache - if no flags given, always returns memory */
    731 void *slab_alloc(slab_cache_t *cache, int flags)
    732 {
    733         ipl_t ipl;
     756/** Allocate new object from cache - if no flags given, always returns memory
     757 *
     758 */
     759void *slab_alloc(slab_cache_t *cache, unsigned int flags)
     760{
     761        /* Disable interrupts to avoid deadlocks with interrupt handlers */
     762        ipl_t ipl = interrupts_disable();
     763       
    734764        void *result = NULL;
    735765       
    736         /* Disable interrupts to avoid deadlocks with interrupt handlers */
    737         ipl = interrupts_disable();
    738 
    739         if (!(cache->flags & SLAB_CACHE_NOMAGAZINE)) {
     766        if (!(cache->flags & SLAB_CACHE_NOMAGAZINE))
    740767                result = magazine_obj_get(cache);
    741         }
     768       
    742769        if (!result)
    743770                result = slab_obj_create(cache, flags);
    744 
     771       
    745772        interrupts_restore(ipl);
    746 
     773       
    747774        if (result)
    748775                atomic_inc(&cache->allocated_objs);
    749 
     776       
    750777        return result;
    751778}
    752779
    753 /** Return object to cache, use slab if known  */
     780/** Return object to cache, use slab if known
     781 *
     782 */
    754783static void _slab_free(slab_cache_t *cache, void *obj, slab_t *slab)
    755784{
    756         ipl_t ipl;
    757 
    758         ipl = interrupts_disable();
    759 
     785        ipl_t ipl = interrupts_disable();
     786       
    760787        if ((cache->flags & SLAB_CACHE_NOMAGAZINE) ||
    761             magazine_obj_put(cache, obj)) {
     788            (magazine_obj_put(cache, obj)))
    762789                slab_obj_destroy(cache, obj, slab);
    763 
    764         }
     790       
    765791        interrupts_restore(ipl);
    766792        atomic_dec(&cache->allocated_objs);
    767793}
    768794
    769 /** Return slab object to cache */
     795/** Return slab object to cache
     796 *
     797 */
    770798void slab_free(slab_cache_t *cache, void *obj)
    771799{
     
    773801}
    774802
    775 /* Go through all caches and reclaim what is possible */
    776 size_t slab_reclaim(int flags)
    777 {
    778         slab_cache_t *cache;
     803/** Go through all caches and reclaim what is possible
     804 *
     805 * Interrupts must be disabled before calling this function,
     806 * otherwise  memory allocation from interrupts can deadlock.
     807 *
     808 */
     809size_t slab_reclaim(unsigned int flags)
     810{
     811        irq_spinlock_lock(&slab_cache_lock, false);
     812       
     813        size_t frames = 0;
    779814        link_t *cur;
    780         size_t frames = 0;
    781 
    782         spinlock_lock(&slab_cache_lock);
    783 
    784         /* TODO: Add assert, that interrupts are disabled, otherwise
    785          * memory allocation from interrupts can deadlock.
    786          */
    787 
    788815        for (cur = slab_cache_list.next; cur != &slab_cache_list;
    789816            cur = cur->next) {
    790                 cache = list_get_instance(cur, slab_cache_t, link);
     817                slab_cache_t *cache = list_get_instance(cur, slab_cache_t, link);
    791818                frames += _slab_reclaim(cache, flags);
    792819        }
    793 
    794         spinlock_unlock(&slab_cache_lock);
    795 
     820       
     821        irq_spinlock_unlock(&slab_cache_lock, false);
     822       
    796823        return frames;
    797824}
    798825
    799 
    800 /* Print list of slabs */
     826/* Print list of slabs
     827 *
     828 */
    801829void slab_print_list(void)
    802830{
    803         int skip = 0;
    804 
    805         printf("slab name        size     pages  obj/pg slabs  cached allocated"
     831        printf("slab name        size     pages  obj/pg   slabs  cached allocated"
    806832            " ctl\n");
    807         printf("---------------- -------- ------ ------ ------ ------ ---------"
     833        printf("---------------- -------- ------ -------- ------ ------ ---------"
    808834            " ---\n");
    809 
     835       
     836        size_t skip = 0;
    810837        while (true) {
    811                 slab_cache_t *cache;
    812                 link_t *cur;
    813                 ipl_t ipl;
    814                 int i;
    815 
    816838                /*
    817839                 * We must not hold the slab_cache_lock spinlock when printing
     
    836858                 * statistics.
    837859                 */
    838 
    839                 ipl = interrupts_disable();
    840                 spinlock_lock(&slab_cache_lock);
    841 
     860               
     861                irq_spinlock_lock(&slab_cache_lock, true);
     862               
     863                link_t *cur;
     864                size_t i;
    842865                for (i = 0, cur = slab_cache_list.next;
    843                     i < skip && cur != &slab_cache_list;
    844                     i++, cur = cur->next)
    845                         ;
    846 
     866                    (i < skip) && (cur != &slab_cache_list);
     867                    i++, cur = cur->next);
     868               
    847869                if (cur == &slab_cache_list) {
    848                         spinlock_unlock(&slab_cache_lock);
    849                         interrupts_restore(ipl);
     870                        irq_spinlock_unlock(&slab_cache_lock, true);
    850871                        break;
    851872                }
    852 
     873               
    853874                skip++;
    854 
    855                 cache = list_get_instance(cur, slab_cache_t, link);
    856 
     875               
     876                slab_cache_t *cache = list_get_instance(cur, slab_cache_t, link);
     877               
    857878                const char *name = cache->name;
    858879                uint8_t order = cache->order;
    859880                size_t size = cache->size;
    860                 unsigned int objects = cache->objects;
     881                size_t objects = cache->objects;
    861882                long allocated_slabs = atomic_get(&cache->allocated_slabs);
    862883                long cached_objs = atomic_get(&cache->cached_objs);
    863884                long allocated_objs = atomic_get(&cache->allocated_objs);
    864                 int flags = cache->flags;
    865                
    866                 spinlock_unlock(&slab_cache_lock);
    867                 interrupts_restore(ipl);
    868                
    869                 printf("%-16s %8" PRIs " %6d %6u %6ld %6ld %9ld %-3s\n",
     885                unsigned int flags = cache->flags;
     886               
     887                irq_spinlock_unlock(&slab_cache_lock, true);
     888               
     889                printf("%-16s %8" PRIs " %6u %8" PRIs " %6ld %6ld %9ld %-3s\n",
    870890                    name, size, (1 << order), objects, allocated_slabs,
    871891                    cached_objs, allocated_objs,
     
    876896void slab_cache_init(void)
    877897{
    878         int i, size;
    879 
    880898        /* Initialize magazine cache */
    881899        _slab_cache_create(&mag_cache, "slab_magazine",
     
    883901            sizeof(uintptr_t), NULL, NULL, SLAB_CACHE_NOMAGAZINE |
    884902            SLAB_CACHE_SLINSIDE);
     903       
    885904        /* Initialize slab_cache cache */
    886905        _slab_cache_create(&slab_cache_cache, "slab_cache",
    887906            sizeof(slab_cache_cache), sizeof(uintptr_t), NULL, NULL,
    888907            SLAB_CACHE_NOMAGAZINE | SLAB_CACHE_SLINSIDE);
     908       
    889909        /* Initialize external slab cache */
    890910        slab_extern_cache = slab_cache_create("slab_extern", sizeof(slab_t), 0,
    891911            NULL, NULL, SLAB_CACHE_SLINSIDE | SLAB_CACHE_MAGDEFERRED);
    892 
     912       
    893913        /* Initialize structures for malloc */
     914        size_t i;
     915        size_t size;
     916       
    894917        for (i = 0, size = (1 << SLAB_MIN_MALLOC_W);
    895918            i < (SLAB_MAX_MALLOC_W - SLAB_MIN_MALLOC_W + 1);
     
    898921                    NULL, NULL, SLAB_CACHE_MAGDEFERRED);
    899922        }
     923       
    900924#ifdef CONFIG_DEBUG
    901925        _slab_initialized = 1;
     
    906930 *
    907931 * Kernel calls this function, when it knows the real number of
    908  * processors.
    909  * Allocate slab for cpucache and enable it on all existing
    910  * slabs that are SLAB_CACHE_MAGDEFERRED
     932 * processors. Allocate slab for cpucache and enable it on all
     933 * existing slabs that are SLAB_CACHE_MAGDEFERRED
     934 *
    911935 */
    912936void slab_enable_cpucache(void)
    913937{
    914         link_t *cur;
    915         slab_cache_t *s;
    916 
    917938#ifdef CONFIG_DEBUG
    918939        _slab_initialized = 2;
    919940#endif
    920 
    921         spinlock_lock(&slab_cache_lock);
    922        
     941       
     942        irq_spinlock_lock(&slab_cache_lock, false);
     943       
     944        link_t *cur;
    923945        for (cur = slab_cache_list.next; cur != &slab_cache_list;
    924             cur = cur->next){
    925                 s = list_get_instance(cur, slab_cache_t, link);
    926                 if ((s->flags & SLAB_CACHE_MAGDEFERRED) !=
     946            cur = cur->next) {
     947                slab_cache_t *slab = list_get_instance(cur, slab_cache_t, link);
     948                if ((slab->flags & SLAB_CACHE_MAGDEFERRED) !=
    927949                    SLAB_CACHE_MAGDEFERRED)
    928950                        continue;
    929                 (void) make_magcache(s);
    930                 s->flags &= ~SLAB_CACHE_MAGDEFERRED;
    931         }
    932 
    933         spinlock_unlock(&slab_cache_lock);
    934 }
    935 
    936 /**************************************/
    937 /* kalloc/kfree functions             */
    938 void *malloc(unsigned int size, int flags)
     951               
     952                (void) make_magcache(slab);
     953                slab->flags &= ~SLAB_CACHE_MAGDEFERRED;
     954        }
     955       
     956        irq_spinlock_unlock(&slab_cache_lock, false);
     957}
     958
     959void *malloc(size_t size, unsigned int flags)
    939960{
    940961        ASSERT(_slab_initialized);
     
    943964        if (size < (1 << SLAB_MIN_MALLOC_W))
    944965                size = (1 << SLAB_MIN_MALLOC_W);
    945 
    946         int idx = fnzb(size - 1) - SLAB_MIN_MALLOC_W + 1;
    947 
     966       
     967        uint8_t idx = fnzb(size - 1) - SLAB_MIN_MALLOC_W + 1;
     968       
    948969        return slab_alloc(malloc_caches[idx], flags);
    949970}
    950971
    951 void *realloc(void *ptr, unsigned int size, int flags)
     972void *realloc(void *ptr, size_t size, unsigned int flags)
    952973{
    953974        ASSERT(_slab_initialized);
     
    959980                if (size < (1 << SLAB_MIN_MALLOC_W))
    960981                        size = (1 << SLAB_MIN_MALLOC_W);
    961                 int idx = fnzb(size - 1) - SLAB_MIN_MALLOC_W + 1;
     982                uint8_t idx = fnzb(size - 1) - SLAB_MIN_MALLOC_W + 1;
    962983               
    963984                new_ptr = slab_alloc(malloc_caches[idx], flags);
     
    9801001        if (!ptr)
    9811002                return;
    982 
     1003       
    9831004        slab_t *slab = obj2slab(ptr);
    9841005        _slab_free(slab->cache, ptr, slab);
Note: See TracChangeset for help on using the changeset viewer.