Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/lib/ra.c

    rfeeac0d r02667d9  
    4343 */
    4444
     45#include <assert.h>
    4546#include <lib/ra.h>
    4647#include <typedefs.h>
    4748#include <mm/slab.h>
    4849#include <bitops.h>
    49 #include <debug.h>
    5050#include <panic.h>
    5151#include <adt/list.h>
     52#include <adt/hash.h>
    5253#include <adt/hash_table.h>
    5354#include <align.h>
     
    5758static slab_cache_t *ra_segment_cache;
    5859
    59 #define USED_BUCKETS    1024
    60 
    61 static size_t used_hash(sysarg_t *key)
    62 {
    63         return ((*key >> 2) & (USED_BUCKETS - 1));
    64 }
    65 
    66 static bool used_compare(sysarg_t *key, size_t keys, link_t *item)
    67 {
    68         ra_segment_t *seg;
    69 
    70         seg = hash_table_get_instance(item, ra_segment_t, fu_link);
    71         return seg->base == *key;
    72 }
    73 
    74 static hash_table_operations_t used_ops = {
     60/** Return the hash of the key stored in the item */
     61static size_t used_hash(const ht_link_t *item)
     62{
     63        ra_segment_t *seg = hash_table_get_inst(item, ra_segment_t, uh_link);
     64        return hash_mix(seg->base);
     65}
     66
     67/** Return the hash of the key */
     68static size_t used_key_hash(void *key)
     69{
     70        uintptr_t *base = (uintptr_t *) key;
     71        return hash_mix(*base);
     72}
     73
     74/** Return true if the key is equal to the item's lookup key */
     75static bool used_key_equal(void *key, const ht_link_t *item)
     76{
     77        uintptr_t *base = (uintptr_t *) key;
     78        ra_segment_t *seg = hash_table_get_inst(item, ra_segment_t, uh_link);
     79        return seg->base == *base;
     80}
     81
     82static hash_table_ops_t used_ops = {
    7583        .hash = used_hash,
    76         .compare = used_compare,
    77         .remove_callback = NULL,
     84        .key_hash = used_key_hash,
     85        .key_equal = used_key_equal
    7886};
    7987
     
    97105
    98106        link_initialize(&seg->segment_link);
    99         link_initialize(&seg->fu_link);
     107        link_initialize(&seg->fl_link);
    100108
    101109        seg->base = base;
     
    160168        list_initialize(&span->segments);
    161169
    162         hash_table_create(&span->used, USED_BUCKETS, 1, &used_ops);
     170        hash_table_create(&span->used, 0, 0, &used_ops);
    163171
    164172        for (i = 0; i <= span->max_order; i++)
     
    171179
    172180        /* Insert the first segment into the respective free list. */
    173         list_append(&seg->fu_link, &span->free[span->max_order]);
     181        list_append(&seg->fl_link, &span->free[span->max_order]);
    174182
    175183        return span;
     184}
     185
     186static void ra_span_destroy(ra_span_t *span)
     187{
     188        hash_table_destroy(&span->used);
     189
     190        list_foreach_safe(span->segments, cur, next) {
     191                ra_segment_t *seg = list_get_instance(cur, ra_segment_t,
     192                    segment_link);
     193                list_remove(&seg->segment_link);
     194                if (seg->flags & RA_SEGMENT_FREE)
     195                        list_remove(&seg->fl_link);
     196                ra_segment_destroy(seg);
     197        }
     198
     199        free(span);
    176200}
    177201
     
    191215}
    192216
     217void ra_arena_destroy(ra_arena_t *arena)
     218{
     219        /*
     220         * No locking necessary as this is the cleanup and all users should have
     221         * stopped using the arena already.
     222         */
     223        list_foreach_safe(arena->spans, cur, next) {
     224                ra_span_t *span = list_get_instance(cur, ra_span_t, span_link);
     225                list_remove(&span->span_link);
     226                ra_span_destroy(span);
     227        }
     228
     229        free(arena);
     230}
     231
    193232/** Add a span to arena. */
    194233bool ra_span_add(ra_arena_t *arena, uintptr_t base, size_t size)
    195234{
    196235        ra_span_t *span;
    197 
    198         /*
    199          * At the moment, we can only create resources that don't include 0.
    200          * If 0 needs to be considered as a valid resource, we would need to
    201          * slightly change the API of the resource allocator.
    202          */
    203         if (base == 0)
    204                 return false;
    205236
    206237        span = ra_span_create(base, size);
     
    215246}
    216247
    217 static uintptr_t ra_span_alloc(ra_span_t *span, size_t size, size_t align)
     248static bool
     249ra_span_alloc(ra_span_t *span, size_t size, size_t align, uintptr_t *base)
    218250{
    219251        /*
     
    239271                /* Take the first segment from the free list. */
    240272                seg = list_get_instance(list_first(&span->free[order]),
    241                     ra_segment_t, fu_link);
    242 
    243                 ASSERT(seg->flags & RA_SEGMENT_FREE);
     273                    ra_segment_t, fl_link);
     274
     275                assert(seg->flags & RA_SEGMENT_FREE);
    244276
    245277                /*
     
    259291                newbase = ALIGN_UP(seg->base, align);
    260292                if (newbase + size != seg->base + ra_segment_size_get(seg)) {
    261                         ASSERT(newbase + (size - 1) < seg->base +
     293                        assert(newbase + (size - 1) < seg->base +
    262294                            (ra_segment_size_get(seg) - 1));
    263295                        succ = ra_segment_create(newbase + size);
     
    281313                            &seg->segment_link);
    282314                        pred_order = fnzb(ra_segment_size_get(pred));
    283                         list_append(&pred->fu_link, &span->free[pred_order]);
     315                        list_append(&pred->fl_link, &span->free[pred_order]);
    284316                }
    285317                if (succ) {
     
    289321                            &seg->segment_link);
    290322                        succ_order = fnzb(ra_segment_size_get(succ));
    291                         list_append(&succ->fu_link, &span->free[succ_order]);
     323                        list_append(&succ->fl_link, &span->free[succ_order]);
    292324                }
    293325
    294326                /* Now remove the found segment from the free list. */
    295                 list_remove(&seg->fu_link);
     327                list_remove(&seg->fl_link);
    296328                seg->base = newbase;
    297329                seg->flags &= ~RA_SEGMENT_FREE;
    298330
    299331                /* Hash-in the segment into the used hash. */
    300                 sysarg_t key = seg->base;
    301                 hash_table_insert(&span->used, &key, &seg->fu_link);
    302 
    303                 return newbase;
    304         }
    305 
    306         return 0;
     332                hash_table_insert(&span->used, &seg->uh_link);
     333
     334                *base = newbase;
     335                return true;
     336        }
     337
     338        return false;
    307339}
    308340
     
    310342{
    311343        sysarg_t key = base;
    312         link_t *link;
     344        ht_link_t *link;
    313345        ra_segment_t *seg;
    314346        ra_segment_t *pred;
     
    324356                    PRIxn ", size=%" PRIdn ").", base, size);
    325357        }
    326         seg = hash_table_get_instance(link, ra_segment_t, fu_link);
     358        seg = hash_table_get_inst(link, ra_segment_t, uh_link);
    327359
    328360        /*
    329361         * Hash out the segment.
    330362         */
    331         hash_table_remove(&span->used, &key, 1);
    332 
    333         ASSERT(!(seg->flags & RA_SEGMENT_FREE));
    334         ASSERT(seg->base == base);
    335         ASSERT(ra_segment_size_get(seg) == size);
     363        hash_table_remove_item(&span->used, link);
     364
     365        assert(!(seg->flags & RA_SEGMENT_FREE));
     366        assert(seg->base == base);
     367        assert(ra_segment_size_get(seg) == size);
    336368
    337369        /*
     
    339371         */
    340372        if (list_first(&span->segments) != &seg->segment_link) {
    341                 pred = hash_table_get_instance(seg->segment_link.prev,
     373                pred = hash_table_get_inst(seg->segment_link.prev,
    342374                    ra_segment_t, segment_link);
    343375
    344                 ASSERT(pred->base < seg->base);
     376                assert(pred->base < seg->base);
    345377
    346378                if (pred->flags & RA_SEGMENT_FREE) {
     
    351383                         * away.
    352384                         */
    353                         list_remove(&pred->fu_link);
     385                        list_remove(&pred->fl_link);
    354386                        list_remove(&pred->segment_link);
    355387                        seg->base = pred->base;
     
    361393         * Check whether the segment can be coalesced with its right neighbor.
    362394         */
    363         succ = hash_table_get_instance(seg->segment_link.next, ra_segment_t,
     395        succ = hash_table_get_inst(seg->segment_link.next, ra_segment_t,
    364396            segment_link);
    365         ASSERT(succ->base > seg->base);
     397        assert(succ->base > seg->base);
    366398        if (succ->flags & RA_SEGMENT_FREE) {
    367399                /*
     
    370402                 * and throw it away.
    371403                 */
    372                 list_remove(&succ->fu_link);
     404                list_remove(&succ->fl_link);
    373405                list_remove(&succ->segment_link);
    374406                ra_segment_destroy(succ);
     
    378410        seg->flags |= RA_SEGMENT_FREE;
    379411        order = fnzb(ra_segment_size_get(seg));
    380         list_append(&seg->fu_link, &span->free[order]);
     412        list_append(&seg->fl_link, &span->free[order]);
    381413}
    382414
    383415/** Allocate resources from arena. */
    384 uintptr_t ra_alloc(ra_arena_t *arena, size_t size, size_t alignment)
    385 {
    386         uintptr_t base = 0;
    387 
    388         ASSERT(size >= 1);
    389         ASSERT(alignment >= 1);
    390         ASSERT(ispwr2(alignment));
     416bool
     417ra_alloc(ra_arena_t *arena, size_t size, size_t alignment, uintptr_t *base)
     418{
     419        bool success = false;
     420
     421        assert(size >= 1);
     422        assert(alignment >= 1);
     423        assert(ispwr2(alignment));
    391424
    392425        irq_spinlock_lock(&arena->lock, true);
    393426        list_foreach(arena->spans, span_link, ra_span_t, span) {
    394                 base = ra_span_alloc(span, size, alignment);
    395                 if (base)
     427                success = ra_span_alloc(span, size, alignment, base);
     428                if (success)
    396429                        break;
    397430        }
    398431        irq_spinlock_unlock(&arena->lock, true);
    399432
    400         return base;
     433        return success;
    401434}
    402435
Note: See TracChangeset for help on using the changeset viewer.