Rev 780 | Rev 782 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 780 | Rev 781 | ||
---|---|---|---|
Line 305... | Line 305... | ||
305 | 305 | ||
306 | /**************************************/ |
306 | /**************************************/ |
307 | /* CPU-Cache slab functions */ |
307 | /* CPU-Cache slab functions */ |
308 | 308 | ||
309 | /** |
309 | /** |
- | 310 | * Finds a full magazine in cache, takes it from list |
|
- | 311 | * and returns it |
|
- | 312 | * |
|
- | 313 | * @param first If true, return first, else last mag |
|
- | 314 | */ |
|
- | 315 | static slab_magazine_t * get_mag_from_cache(slab_cache_t *cache, |
|
- | 316 | int first) |
|
- | 317 | { |
|
- | 318 | slab_magazine_t *mag = NULL; |
|
- | 319 | link_t *cur; |
|
- | 320 | ||
- | 321 | spinlock_lock(&cache->maglock); |
|
- | 322 | if (!list_empty(&cache->magazines)) { |
|
- | 323 | if (first) |
|
- | 324 | cur = cache->magazines.next; |
|
- | 325 | else |
|
- | 326 | cur = cache->magazines.prev; |
|
- | 327 | mag = list_get_instance(cur, slab_magazine_t, link); |
|
- | 328 | list_remove(&mag->link); |
|
- | 329 | atomic_dec(&cache->magazine_counter); |
|
- | 330 | } |
|
- | 331 | spinlock_unlock(&cache->maglock); |
|
- | 332 | return mag; |
|
- | 333 | } |
|
- | 334 | ||
- | 335 | /** Prepend magazine to magazine list in cache */ |
|
- | 336 | static void put_mag_to_cache(slab_cache_t *cache, slab_magazine_t *mag) |
|
- | 337 | { |
|
- | 338 | spinlock_lock(&cache->maglock); |
|
- | 339 | ||
- | 340 | list_prepend(&mag->link, &cache->magazines); |
|
- | 341 | atomic_inc(&cache->magazine_counter); |
|
- | 342 | ||
- | 343 | spinlock_unlock(&cache->maglock); |
|
- | 344 | } |
|
- | 345 | ||
- | 346 | /** |
|
310 | * Free all objects in magazine and free memory associated with magazine |
347 | * Free all objects in magazine and free memory associated with magazine |
311 | * |
348 | * |
312 | * @return Number of freed pages |
349 | * @return Number of freed pages |
313 | */ |
350 | */ |
314 | static count_t magazine_destroy(slab_cache_t *cache, |
351 | static count_t magazine_destroy(slab_cache_t *cache, |
Line 347... | Line 384... | ||
347 | cache->mag_cache[CPU->id].last = cmag; |
384 | cache->mag_cache[CPU->id].last = cmag; |
348 | return lastmag; |
385 | return lastmag; |
349 | } |
386 | } |
350 | } |
387 | } |
351 | /* Local magazines are empty, import one from magazine list */ |
388 | /* Local magazines are empty, import one from magazine list */ |
352 | spinlock_lock(&cache->maglock); |
389 | newmag = get_mag_from_cache(cache, 1); |
353 | if (list_empty(&cache->magazines)) { |
390 | if (!newmag) |
354 | spinlock_unlock(&cache->maglock); |
- | |
355 | return NULL; |
391 | return NULL; |
356 | } |
- | |
357 | newmag = list_get_instance(cache->magazines.next, |
- | |
358 | slab_magazine_t, |
- | |
359 | link); |
- | |
360 | list_remove(&newmag->link); |
- | |
361 | spinlock_unlock(&cache->maglock); |
- | |
362 | 392 | ||
363 | if (lastmag) |
393 | if (lastmag) |
364 | slab_free(&mag_cache, lastmag); |
394 | magazine_destroy(cache, lastmag); |
- | 395 | ||
365 | cache->mag_cache[CPU->id].last = cmag; |
396 | cache->mag_cache[CPU->id].last = cmag; |
366 | cache->mag_cache[CPU->id].current = newmag; |
397 | cache->mag_cache[CPU->id].current = newmag; |
367 | return newmag; |
398 | return newmag; |
368 | } |
399 | } |
369 | 400 | ||
Line 432... | Line 463... | ||
432 | return NULL; |
463 | return NULL; |
433 | newmag->size = SLAB_MAG_SIZE; |
464 | newmag->size = SLAB_MAG_SIZE; |
434 | newmag->busy = 0; |
465 | newmag->busy = 0; |
435 | 466 | ||
436 | /* Flush last to magazine list */ |
467 | /* Flush last to magazine list */ |
437 | if (lastmag) { |
468 | if (lastmag) |
438 | spinlock_lock(&cache->maglock); |
469 | put_mag_to_cache(cache, lastmag); |
439 | list_prepend(&lastmag->link, &cache->magazines); |
- | |
440 | spinlock_unlock(&cache->maglock); |
- | |
441 | } |
470 | |
442 | /* Move current as last, save new as current */ |
471 | /* Move current as last, save new as current */ |
443 | cache->mag_cache[CPU->id].last = cmag; |
472 | cache->mag_cache[CPU->id].last = cmag; |
444 | cache->mag_cache[CPU->id].current = newmag; |
473 | cache->mag_cache[CPU->id].current = newmag; |
445 | 474 | ||
446 | return newmag; |
475 | return newmag; |
Line 586... | Line 615... | ||
586 | */ |
615 | */ |
587 | static count_t _slab_reclaim(slab_cache_t *cache, int flags) |
616 | static count_t _slab_reclaim(slab_cache_t *cache, int flags) |
588 | { |
617 | { |
589 | int i; |
618 | int i; |
590 | slab_magazine_t *mag; |
619 | slab_magazine_t *mag; |
591 | link_t *cur; |
- | |
592 | count_t frames = 0; |
620 | count_t frames = 0; |
- | 621 | int magcount; |
|
593 | 622 | ||
594 | if (cache->flags & SLAB_CACHE_NOMAGAZINE) |
623 | if (cache->flags & SLAB_CACHE_NOMAGAZINE) |
595 | return 0; /* Nothing to do */ |
624 | return 0; /* Nothing to do */ |
596 | 625 | ||
597 | /* First lock all cpu caches, then the complete cache lock */ |
626 | /* We count up to original magazine count to avoid |
598 | if (flags & SLAB_RECLAIM_ALL) { |
627 | * endless loop |
- | 628 | */ |
|
599 | for (i=0; i < config.cpu_count; i++) |
629 | magcount = atomic_get(&cache->magazine_counter); |
- | 630 | while (magcount-- && (mag=get_mag_from_cache(cache,0))) { |
|
600 | spinlock_lock(&cache->mag_cache[i].lock); |
631 | frames += magazine_destroy(cache,mag); |
- | 632 | if (!(flags & SLAB_RECLAIM_ALL) && frames) |
|
- | 633 | break; |
|
601 | } |
634 | } |
602 | spinlock_lock(&cache->maglock); |
- | |
603 | 635 | ||
604 | if (flags & SLAB_RECLAIM_ALL) { |
636 | if (flags & SLAB_RECLAIM_ALL) { |
605 | /* Aggressive memfree */ |
637 | /* Free cpu-bound magazines */ |
606 | /* Destroy CPU magazines */ |
638 | /* Destroy CPU magazines */ |
607 | for (i=0; i<config.cpu_count; i++) { |
639 | for (i=0; i<config.cpu_count; i++) { |
- | 640 | spinlock_lock(&cache->mag_cache[i].lock); |
|
- | 641 | ||
608 | mag = cache->mag_cache[i].current; |
642 | mag = cache->mag_cache[i].current; |
609 | if (mag) |
643 | if (mag) |
610 | frames += magazine_destroy(cache, mag); |
644 | frames += magazine_destroy(cache, mag); |
611 | cache->mag_cache[i].current = NULL; |
645 | cache->mag_cache[i].current = NULL; |
612 | 646 | ||
613 | mag = cache->mag_cache[i].last; |
647 | mag = cache->mag_cache[i].last; |
614 | if (mag) |
648 | if (mag) |
615 | frames += magazine_destroy(cache, mag); |
649 | frames += magazine_destroy(cache, mag); |
616 | cache->mag_cache[i].last = NULL; |
650 | cache->mag_cache[i].last = NULL; |
617 | } |
- | |
618 | } |
651 | |
619 | /* We can release the cache locks now */ |
- | |
620 | if (flags & SLAB_RECLAIM_ALL) { |
- | |
621 | for (i=0; i < config.cpu_count; i++) |
- | |
622 | spinlock_unlock(&cache->mag_cache[i].lock); |
652 | spinlock_unlock(&cache->mag_cache[i].lock); |
- | 653 | } |
|
623 | } |
654 | } |
624 | /* Destroy full magazines */ |
- | |
625 | cur=cache->magazines.prev; |
- | |
626 | 655 | ||
627 | while (cur != &cache->magazines) { |
- | |
628 | mag = list_get_instance(cur, slab_magazine_t, link); |
- | |
629 | - | ||
630 | cur = cur->prev; |
- | |
631 | list_remove(&mag->link); |
- | |
632 | frames += magazine_destroy(cache,mag); |
- | |
633 | /* If we do not do full reclaim, break |
- | |
634 | * as soon as something is freed */ |
- | |
635 | if (!(flags & SLAB_RECLAIM_ALL) && frames) |
- | |
636 | break; |
- | |
637 | } |
- | |
638 | - | ||
639 | spinlock_unlock(&cache->maglock); |
- | |
640 | - | ||
641 | return frames; |
656 | return frames; |
642 | } |
657 | } |
643 | 658 | ||
644 | /** Check that there are no slabs and remove cache from system */ |
659 | /** Check that there are no slabs and remove cache from system */ |
645 | void slab_cache_destroy(slab_cache_t *cache) |
660 | void slab_cache_destroy(slab_cache_t *cache) |
646 | { |
661 | { |
- | 662 | ipl_t ipl; |
|
- | 663 | ||
- | 664 | /* First remove cache from link, so that we don't need |
|
- | 665 | * to disable interrupts later |
|
- | 666 | */ |
|
- | 667 | ||
- | 668 | ipl = interrupts_disable(); |
|
- | 669 | spinlock_lock(&slab_cache_lock); |
|
- | 670 | ||
- | 671 | list_remove(&cache->link); |
|
- | 672 | ||
- | 673 | spinlock_unlock(&slab_cache_lock); |
|
- | 674 | interrupts_restore(ipl); |
|
- | 675 | ||
647 | /* Do not lock anything, we assume the software is correct and |
676 | /* Do not lock anything, we assume the software is correct and |
648 | * does not touch the cache when it decides to destroy it */ |
677 | * does not touch the cache when it decides to destroy it */ |
649 | 678 | ||
650 | /* Destroy all magazines */ |
679 | /* Destroy all magazines */ |
651 | _slab_reclaim(cache, SLAB_RECLAIM_ALL); |
680 | _slab_reclaim(cache, SLAB_RECLAIM_ALL); |
Line 653... | Line 682... | ||
653 | /* All slabs must be empty */ |
682 | /* All slabs must be empty */ |
654 | if (!list_empty(&cache->full_slabs) \ |
683 | if (!list_empty(&cache->full_slabs) \ |
655 | || !list_empty(&cache->partial_slabs)) |
684 | || !list_empty(&cache->partial_slabs)) |
656 | panic("Destroying cache that is not empty."); |
685 | panic("Destroying cache that is not empty."); |
657 | 686 | ||
658 | spinlock_lock(&slab_cache_lock); |
- | |
659 | list_remove(&cache->link); |
- | |
660 | spinlock_unlock(&slab_cache_lock); |
- | |
661 | - | ||
662 | slab_free(&slab_cache_cache, cache); |
687 | slab_free(&slab_cache_cache, cache); |
663 | } |
688 | } |
664 | 689 | ||
665 | /** Allocate new object from cache - if no flags given, always returns |
690 | /** Allocate new object from cache - if no flags given, always returns |
666 | memory */ |
691 | memory */ |
Line 672... | Line 697... | ||
672 | /* Disable interrupts to avoid deadlocks with interrupt handlers */ |
697 | /* Disable interrupts to avoid deadlocks with interrupt handlers */ |
673 | ipl = interrupts_disable(); |
698 | ipl = interrupts_disable(); |
674 | 699 | ||
675 | if (!(cache->flags & SLAB_CACHE_NOMAGAZINE)) |
700 | if (!(cache->flags & SLAB_CACHE_NOMAGAZINE)) |
676 | result = magazine_obj_get(cache); |
701 | result = magazine_obj_get(cache); |
677 | - | ||
678 | if (!result) |
702 | if (!result) |
679 | result = slab_obj_create(cache, flags); |
703 | result = slab_obj_create(cache, flags); |
680 | 704 | ||
681 | interrupts_restore(ipl); |
705 | interrupts_restore(ipl); |
682 | 706 | ||
Line 718... | Line 742... | ||
718 | 742 | ||
719 | spinlock_lock(&slab_cache_lock); |
743 | spinlock_lock(&slab_cache_lock); |
720 | 744 | ||
721 | /* TODO: Add assert, that interrupts are disabled, otherwise |
745 | /* TODO: Add assert, that interrupts are disabled, otherwise |
722 | * memory allocation from interrupts can deadlock. |
746 | * memory allocation from interrupts can deadlock. |
- | 747 | * - cache_destroy can call this with interrupts enabled :-/ |
|
723 | */ |
748 | */ |
724 | 749 | ||
725 | for (cur = slab_cache_list.next;cur!=&slab_cache_list; cur=cur->next) { |
750 | for (cur = slab_cache_list.next;cur!=&slab_cache_list; cur=cur->next) { |
726 | cache = list_get_instance(cur, slab_cache_t, link); |
751 | cache = list_get_instance(cur, slab_cache_t, link); |
727 | frames += _slab_reclaim(cache, flags); |
752 | frames += _slab_reclaim(cache, flags); |
Line 812... | Line 837... | ||
812 | } |
837 | } |
813 | 838 | ||
814 | 839 | ||
815 | void kfree(void *obj) |
840 | void kfree(void *obj) |
816 | { |
841 | { |
817 | slab_t *slab = obj2slab(obj); |
842 | slab_t *slab; |
818 | 843 | ||
- | 844 | if (!obj) return; |
|
- | 845 | ||
- | 846 | slab = obj2slab(obj); |
|
819 | _slab_free(slab->cache, obj, slab); |
847 | _slab_free(slab->cache, obj, slab); |
820 | } |
848 | } |